mirror of
https://github.com/alibaba/higress.git
synced 2026-05-27 22:27:29 +08:00
add cached token usage when converting openai to claude (#3766)
Signed-off-by: 钰诚 <yucheng.lxr@alibaba-inc.com>
This commit is contained in:
@@ -788,16 +788,21 @@ func (c *ClaudeToOpenAIConverter) buildClaudeStreamResponse(ctx wrapper.HttpCont
|
|||||||
log.Debugf("[OpenAI->Claude] Processing usage info - input: %d, output: %d",
|
log.Debugf("[OpenAI->Claude] Processing usage info - input: %d, output: %d",
|
||||||
openaiResponse.Usage.PromptTokens, openaiResponse.Usage.CompletionTokens)
|
openaiResponse.Usage.PromptTokens, openaiResponse.Usage.CompletionTokens)
|
||||||
|
|
||||||
|
usage := &claudeTextGenUsage{
|
||||||
|
InputTokens: openaiResponse.Usage.PromptTokens,
|
||||||
|
OutputTokens: openaiResponse.Usage.CompletionTokens,
|
||||||
|
}
|
||||||
|
if openaiResponse.Usage.PromptTokensDetails != nil {
|
||||||
|
usage.CacheReadInputTokens = openaiResponse.Usage.PromptTokensDetails.CachedTokens
|
||||||
|
}
|
||||||
|
|
||||||
// Send message_delta with both stop_reason and usage (Claude protocol requirement)
|
// Send message_delta with both stop_reason and usage (Claude protocol requirement)
|
||||||
messageDelta := &claudeTextGenStreamResponse{
|
messageDelta := &claudeTextGenStreamResponse{
|
||||||
Type: "message_delta",
|
Type: "message_delta",
|
||||||
Delta: &claudeTextGenDelta{
|
Delta: &claudeTextGenDelta{
|
||||||
StopSequence: json.RawMessage("null"), // Explicit null per Claude spec
|
StopSequence: json.RawMessage("null"), // Explicit null per Claude spec
|
||||||
},
|
},
|
||||||
Usage: &claudeTextGenUsage{
|
Usage: usage,
|
||||||
InputTokens: openaiResponse.Usage.PromptTokens,
|
|
||||||
OutputTokens: openaiResponse.Usage.CompletionTokens,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include cached stop_reason if available
|
// Include cached stop_reason if available
|
||||||
|
|||||||
@@ -859,6 +859,22 @@ func TestClaudeToOpenAIConverter_ConvertReasoningResponseToClaude(t *testing.T)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClaudeToOpenAIConverter_ConvertOpenAIStreamResponseToClaude_WithCachedTokens(t *testing.T) {
|
||||||
|
converter := &ClaudeToOpenAIConverter{}
|
||||||
|
|
||||||
|
streamChunk := "data: {\"id\":\"chatcmpl-test\",\"model\":\"gpt-4o\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\"}}]}\n\n" +
|
||||||
|
"data: {\"id\":\"chatcmpl-test\",\"model\":\"gpt-4o\",\"choices\":[{\"index\":0,\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":100,\"completion_tokens\":20,\"total_tokens\":120,\"prompt_tokens_details\":{\"cached_tokens\":60}}}\n\n"
|
||||||
|
|
||||||
|
result, err := converter.ConvertOpenAIStreamResponseToClaude(nil, []byte(streamChunk))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resultStr := string(result)
|
||||||
|
assert.Contains(t, resultStr, "\"type\":\"message_delta\"")
|
||||||
|
assert.Contains(t, resultStr, "\"input_tokens\":100")
|
||||||
|
assert.Contains(t, resultStr, "\"output_tokens\":20")
|
||||||
|
assert.Contains(t, resultStr, "\"cache_read_input_tokens\":60")
|
||||||
|
}
|
||||||
|
|
||||||
func TestClaudeToOpenAIConverter_StripCchFromSystemMessage(t *testing.T) {
|
func TestClaudeToOpenAIConverter_StripCchFromSystemMessage(t *testing.T) {
|
||||||
converter := &ClaudeToOpenAIConverter{}
|
converter := &ClaudeToOpenAIConverter{}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user