feat: Enhance usage tracking across response handlers
This commit is contained in:
@@ -92,9 +92,34 @@ export function claudeToOpenAIResponse(chunk, state) {
|
||||
}
|
||||
|
||||
case "message_delta": {
|
||||
// Extract usage from message_delta event (Claude native format)
|
||||
// Normalize to OpenAI format (prompt_tokens/completion_tokens) for consistent logging
|
||||
if (chunk.usage && typeof chunk.usage === "object") {
|
||||
const inputTokens = typeof chunk.usage.input_tokens === "number" ? chunk.usage.input_tokens : 0;
|
||||
const outputTokens = typeof chunk.usage.output_tokens === "number" ? chunk.usage.output_tokens : 0;
|
||||
const cacheReadTokens = typeof chunk.usage.cache_read_input_tokens === "number" ? chunk.usage.cache_read_input_tokens : 0;
|
||||
const cacheCreationTokens = typeof chunk.usage.cache_creation_input_tokens === "number" ? chunk.usage.cache_creation_input_tokens : 0;
|
||||
|
||||
// Use OpenAI format keys for consistent logging in stream.js
|
||||
state.usage = {
|
||||
prompt_tokens: inputTokens,
|
||||
completion_tokens: outputTokens,
|
||||
input_tokens: inputTokens,
|
||||
output_tokens: outputTokens
|
||||
};
|
||||
|
||||
// Store cache tokens if present
|
||||
if (cacheReadTokens > 0) {
|
||||
state.usage.cache_read_input_tokens = cacheReadTokens;
|
||||
}
|
||||
if (cacheCreationTokens > 0) {
|
||||
state.usage.cache_creation_input_tokens = cacheCreationTokens;
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk.delta?.stop_reason) {
|
||||
state.finishReason = convertStopReason(chunk.delta.stop_reason);
|
||||
results.push({
|
||||
const finalChunk = {
|
||||
id: `chatcmpl-${state.messageId}`,
|
||||
object: "chat.completion.chunk",
|
||||
created: Math.floor(Date.now() / 1000),
|
||||
@@ -104,7 +129,41 @@ export function claudeToOpenAIResponse(chunk, state) {
|
||||
delta: {},
|
||||
finish_reason: state.finishReason
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
// Include usage in final chunk if available
|
||||
if (state.usage && typeof state.usage === "object") {
|
||||
const inputTokens = state.usage.input_tokens || 0;
|
||||
const outputTokens = state.usage.output_tokens || 0;
|
||||
const cachedTokens = state.usage.cache_read_input_tokens || 0;
|
||||
const cacheCreationTokens = state.usage.cache_creation_input_tokens || 0;
|
||||
|
||||
// prompt_tokens = input_tokens + cache_read + cache_creation (all prompt-side tokens)
|
||||
// completion_tokens = output_tokens
|
||||
// total_tokens = prompt_tokens + completion_tokens
|
||||
const promptTokens = inputTokens + cachedTokens + cacheCreationTokens;
|
||||
const completionTokens = outputTokens;
|
||||
const totalTokens = promptTokens + completionTokens;
|
||||
|
||||
finalChunk.usage = {
|
||||
prompt_tokens: promptTokens,
|
||||
completion_tokens: completionTokens,
|
||||
total_tokens: totalTokens
|
||||
};
|
||||
|
||||
// Add prompt_tokens_details if cached tokens exist
|
||||
if (cachedTokens > 0 || cacheCreationTokens > 0) {
|
||||
finalChunk.usage.prompt_tokens_details = {};
|
||||
if (cachedTokens > 0) {
|
||||
finalChunk.usage.prompt_tokens_details.cached_tokens = cachedTokens;
|
||||
}
|
||||
if (cacheCreationTokens > 0) {
|
||||
finalChunk.usage.prompt_tokens_details.cache_creation_tokens = cacheCreationTokens;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results.push(finalChunk);
|
||||
state.finishReasonSent = true;
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user