Skip to content

Commit 9875565

Browse files
committed
**fix(claude translator): ensure default token counts when usage data is missing**
1 parent faa483b commit 9875565

File tree

1 file changed

+35
-21
lines changed

1 file changed

+35
-21
lines changed

internal/translator/openai/claude/openai_claude_response.go

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -284,29 +284,36 @@ func convertOpenAIStreamingChunkToAnthropic(rawJSON []byte, param *ConvertOpenAI
284284

285285
// Handle usage information separately (this comes in a later chunk)
286286
// Only process if usage has actual values (not null)
287-
if usage := root.Get("usage"); usage.Exists() && usage.Type != gjson.Null && param.FinishReason != "" {
288-
// Check if usage has actual token counts
289-
promptTokens := usage.Get("prompt_tokens")
290-
completionTokens := usage.Get("completion_tokens")
291-
292-
if promptTokens.Exists() && completionTokens.Exists() {
293-
// Send message_delta with usage
294-
messageDelta := map[string]interface{}{
295-
"type": "message_delta",
296-
"delta": map[string]interface{}{
297-
"stop_reason": mapOpenAIFinishReasonToAnthropic(param.FinishReason),
298-
"stop_sequence": nil,
299-
},
300-
"usage": map[string]interface{}{
301-
"input_tokens": promptTokens.Int(),
302-
"output_tokens": completionTokens.Int(),
303-
},
287+
if param.FinishReason != "" {
288+
usage := root.Get("usage")
289+
var inputTokens, outputTokens int64
290+
if usage.Exists() && usage.Type != gjson.Null {
291+
// Check if usage has actual token counts
292+
promptTokens := usage.Get("prompt_tokens")
293+
completionTokens := usage.Get("completion_tokens")
294+
295+
if promptTokens.Exists() && completionTokens.Exists() {
296+
inputTokens = promptTokens.Int()
297+
outputTokens = completionTokens.Int()
304298
}
305-
306-
messageDeltaJSON, _ := json.Marshal(messageDelta)
307-
results = append(results, "event: message_delta\ndata: "+string(messageDeltaJSON)+"\n\n")
308-
param.MessageDeltaSent = true
309299
}
300+
// Send message_delta with usage
301+
messageDelta := map[string]interface{}{
302+
"type": "message_delta",
303+
"delta": map[string]interface{}{
304+
"stop_reason": mapOpenAIFinishReasonToAnthropic(param.FinishReason),
305+
"stop_sequence": nil,
306+
},
307+
"usage": map[string]interface{}{
308+
"input_tokens": inputTokens,
309+
"output_tokens": outputTokens,
310+
},
311+
}
312+
313+
messageDeltaJSON, _ := json.Marshal(messageDelta)
314+
results = append(results, "event: message_delta\ndata: "+string(messageDeltaJSON)+"\n\n")
315+
param.MessageDeltaSent = true
316+
310317
}
311318

312319
return results
@@ -413,6 +420,11 @@ func convertOpenAINonStreamingToAnthropic(rawJSON []byte) []string {
413420
"input_tokens": usage.Get("prompt_tokens").Int(),
414421
"output_tokens": usage.Get("completion_tokens").Int(),
415422
}
423+
} else {
424+
response["usage"] = map[string]interface{}{
425+
"input_tokens": 0,
426+
"output_tokens": 0,
427+
}
416428
}
417429

418430
responseJSON, _ := json.Marshal(response)
@@ -601,6 +613,8 @@ func ConvertOpenAIResponseToClaudeNonStream(_ context.Context, _ string, origina
601613
usageJSON, _ = sjson.Set(usageJSON, "output_tokens", respUsage.Get("completion_tokens").Int())
602614
parsedUsage := gjson.Parse(usageJSON).Value().(map[string]interface{})
603615
response["usage"] = parsedUsage
616+
} else {
617+
response["usage"] = `{"input_tokens":0,"output_tokens":0}`
604618
}
605619

606620
if response["stop_reason"] == nil {

0 commit comments

Comments
 (0)