mirror of
https://github.com/decolua/9router.git
synced 2026-05-08 12:01:28 +00:00
fix: correct token extraction for Claude non-streaming responses (#131)
- Add response logging for non-streaming requests (5_res_provider.json, 7_res_client.json) - Fix extractUsageFromResponse() to check Claude format before OpenAI format - Prevents format misidentification that caused tokens to show as 0 - Claude uses input_tokens/output_tokens vs OpenAI's prompt_tokens/completion_tokens Fixes dashboard Details tab showing 0 tokens for Claude requests
This commit is contained in:
@@ -194,18 +194,8 @@ function translateNonStreamingResponse(responseBody, targetFormat, sourceFormat)
|
||||
function extractUsageFromResponse(responseBody, provider) {
|
||||
if (!responseBody || typeof responseBody !== 'object') return null;
|
||||
|
||||
// OpenAI format
|
||||
if (responseBody.usage && typeof responseBody.usage === 'object') {
|
||||
return {
|
||||
prompt_tokens: responseBody.usage.prompt_tokens || 0,
|
||||
completion_tokens: responseBody.usage.completion_tokens || 0,
|
||||
cached_tokens: responseBody.usage.prompt_tokens_details?.cached_tokens,
|
||||
reasoning_tokens: responseBody.usage.completion_tokens_details?.reasoning_tokens
|
||||
};
|
||||
}
|
||||
|
||||
// Claude format
|
||||
if (responseBody.usage && typeof responseBody.usage === 'object' && (responseBody.usage.input_tokens !== undefined || responseBody.usage.output_tokens !== undefined)) {
|
||||
// Claude format - check first to avoid conflict with OpenAI check
|
||||
if (responseBody.usage && typeof responseBody.usage === 'object' && responseBody.usage.input_tokens !== undefined) {
|
||||
return {
|
||||
prompt_tokens: responseBody.usage.input_tokens || 0,
|
||||
completion_tokens: responseBody.usage.output_tokens || 0,
|
||||
@@ -214,6 +204,16 @@ function extractUsageFromResponse(responseBody, provider) {
|
||||
};
|
||||
}
|
||||
|
||||
// OpenAI format
|
||||
if (responseBody.usage && typeof responseBody.usage === 'object' && responseBody.usage.prompt_tokens !== undefined) {
|
||||
return {
|
||||
prompt_tokens: responseBody.usage.prompt_tokens || 0,
|
||||
completion_tokens: responseBody.usage.completion_tokens || 0,
|
||||
cached_tokens: responseBody.usage.prompt_tokens_details?.cached_tokens,
|
||||
reasoning_tokens: responseBody.usage.completion_tokens_details?.reasoning_tokens
|
||||
};
|
||||
}
|
||||
|
||||
// Gemini format
|
||||
if (responseBody.usageMetadata && typeof responseBody.usageMetadata === 'object') {
|
||||
return {
|
||||
@@ -723,6 +723,14 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
|
||||
}
|
||||
}
|
||||
|
||||
// Log provider response (raw response from provider)
|
||||
reqLogger.logProviderResponse(
|
||||
providerResponse.status,
|
||||
providerResponse.statusText,
|
||||
providerResponse.headers,
|
||||
responseBody
|
||||
);
|
||||
|
||||
// Notify success - caller can clear error status if needed
|
||||
if (onRequestSuccess) {
|
||||
await onRequestSuccess();
|
||||
@@ -758,6 +766,9 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
|
||||
translatedResponse.usage = filterUsageForFormat(buffered, sourceFormat);
|
||||
}
|
||||
|
||||
// Log converted response (final response to client)
|
||||
reqLogger.logConvertedResponse(translatedResponse);
|
||||
|
||||
const totalLatency = Date.now() - requestStartTime;
|
||||
const requestDetail = {
|
||||
provider: provider || "unknown",
|
||||
|
||||
Reference in New Issue
Block a user