mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 12:20:52 +08:00
fix(translator): normalize and restrict stop_reason/finish_reason usage
- Standardized the handling of `stop_reason` and `finish_reason` across Codex and Gemini responses. - Restricted pass-through of specific reasons (`max_tokens`, `stop`) for consistency. - Enhanced fallback logic for undefined reasons.
This commit is contained in:
@@ -113,10 +113,10 @@ func ConvertCodexResponseToClaude(_ context.Context, _ string, originalRequestRa
|
|||||||
template = `{"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
template = `{"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
||||||
p := (*param).(*ConvertCodexResponseToClaudeParams).HasToolCall
|
p := (*param).(*ConvertCodexResponseToClaudeParams).HasToolCall
|
||||||
stopReason := rootResult.Get("response.stop_reason").String()
|
stopReason := rootResult.Get("response.stop_reason").String()
|
||||||
if stopReason != "" {
|
if p {
|
||||||
template, _ = sjson.Set(template, "delta.stop_reason", stopReason)
|
|
||||||
} else if p {
|
|
||||||
template, _ = sjson.Set(template, "delta.stop_reason", "tool_use")
|
template, _ = sjson.Set(template, "delta.stop_reason", "tool_use")
|
||||||
|
} else if stopReason == "max_tokens" || stopReason == "stop" {
|
||||||
|
template, _ = sjson.Set(template, "delta.stop_reason", stopReason)
|
||||||
} else {
|
} else {
|
||||||
template, _ = sjson.Set(template, "delta.stop_reason", "end_turn")
|
template, _ = sjson.Set(template, "delta.stop_reason", "end_turn")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,11 +78,16 @@ func ConvertCliResponseToOpenAI(_ context.Context, _ string, originalRequestRawJ
|
|||||||
template, _ = sjson.Set(template, "id", responseIDResult.String())
|
template, _ = sjson.Set(template, "id", responseIDResult.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract and set the finish reason.
|
finishReason := ""
|
||||||
if finishReasonResult := gjson.GetBytes(rawJSON, "response.candidates.0.finishReason"); finishReasonResult.Exists() {
|
if stopReasonResult := gjson.GetBytes(rawJSON, "response.stop_reason"); stopReasonResult.Exists() {
|
||||||
template, _ = sjson.Set(template, "choices.0.finish_reason", strings.ToLower(finishReasonResult.String()))
|
finishReason = stopReasonResult.String()
|
||||||
template, _ = sjson.Set(template, "choices.0.native_finish_reason", strings.ToLower(finishReasonResult.String()))
|
|
||||||
}
|
}
|
||||||
|
if finishReason == "" {
|
||||||
|
if finishReasonResult := gjson.GetBytes(rawJSON, "response.candidates.0.finishReason"); finishReasonResult.Exists() {
|
||||||
|
finishReason = finishReasonResult.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finishReason = strings.ToLower(finishReason)
|
||||||
|
|
||||||
// Extract and set usage metadata (token counts).
|
// Extract and set usage metadata (token counts).
|
||||||
if usageResult := gjson.GetBytes(rawJSON, "response.usageMetadata"); usageResult.Exists() {
|
if usageResult := gjson.GetBytes(rawJSON, "response.usageMetadata"); usageResult.Exists() {
|
||||||
@@ -197,6 +202,12 @@ func ConvertCliResponseToOpenAI(_ context.Context, _ string, originalRequestRawJ
|
|||||||
if hasFunctionCall {
|
if hasFunctionCall {
|
||||||
template, _ = sjson.Set(template, "choices.0.finish_reason", "tool_calls")
|
template, _ = sjson.Set(template, "choices.0.finish_reason", "tool_calls")
|
||||||
template, _ = sjson.Set(template, "choices.0.native_finish_reason", "tool_calls")
|
template, _ = sjson.Set(template, "choices.0.native_finish_reason", "tool_calls")
|
||||||
|
} else if finishReason != "" && (*param).(*convertCliResponseToOpenAIChatParams).FunctionIndex == 0 {
|
||||||
|
// Only pass through specific finish reasons
|
||||||
|
if finishReason == "max_tokens" || finishReason == "stop" {
|
||||||
|
template, _ = sjson.Set(template, "choices.0.finish_reason", finishReason)
|
||||||
|
template, _ = sjson.Set(template, "choices.0.native_finish_reason", finishReason)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{template}
|
return []string{template}
|
||||||
|
|||||||
@@ -129,11 +129,16 @@ func ConvertGeminiResponseToOpenAI(_ context.Context, _ string, originalRequestR
|
|||||||
candidateIndex := int(candidate.Get("index").Int())
|
candidateIndex := int(candidate.Get("index").Int())
|
||||||
template, _ = sjson.Set(template, "choices.0.index", candidateIndex)
|
template, _ = sjson.Set(template, "choices.0.index", candidateIndex)
|
||||||
|
|
||||||
// Extract and set the finish reason.
|
finishReason := ""
|
||||||
if finishReasonResult := candidate.Get("finishReason"); finishReasonResult.Exists() {
|
if stopReasonResult := gjson.GetBytes(rawJSON, "stop_reason"); stopReasonResult.Exists() {
|
||||||
template, _ = sjson.Set(template, "choices.0.finish_reason", strings.ToLower(finishReasonResult.String()))
|
finishReason = stopReasonResult.String()
|
||||||
template, _ = sjson.Set(template, "choices.0.native_finish_reason", strings.ToLower(finishReasonResult.String()))
|
|
||||||
}
|
}
|
||||||
|
if finishReason == "" {
|
||||||
|
if finishReasonResult := gjson.GetBytes(rawJSON, "candidates.0.finishReason"); finishReasonResult.Exists() {
|
||||||
|
finishReason = finishReasonResult.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finishReason = strings.ToLower(finishReason)
|
||||||
|
|
||||||
partsResult := candidate.Get("content.parts")
|
partsResult := candidate.Get("content.parts")
|
||||||
hasFunctionCall := false
|
hasFunctionCall := false
|
||||||
@@ -225,6 +230,12 @@ func ConvertGeminiResponseToOpenAI(_ context.Context, _ string, originalRequestR
|
|||||||
if hasFunctionCall {
|
if hasFunctionCall {
|
||||||
template, _ = sjson.Set(template, "choices.0.finish_reason", "tool_calls")
|
template, _ = sjson.Set(template, "choices.0.finish_reason", "tool_calls")
|
||||||
template, _ = sjson.Set(template, "choices.0.native_finish_reason", "tool_calls")
|
template, _ = sjson.Set(template, "choices.0.native_finish_reason", "tool_calls")
|
||||||
|
} else if finishReason != "" {
|
||||||
|
// Only pass through specific finish reasons
|
||||||
|
if finishReason == "max_tokens" || finishReason == "stop" {
|
||||||
|
template, _ = sjson.Set(template, "choices.0.finish_reason", finishReason)
|
||||||
|
template, _ = sjson.Set(template, "choices.0.native_finish_reason", finishReason)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
responseStrings = append(responseStrings, template)
|
responseStrings = append(responseStrings, template)
|
||||||
|
|||||||
Reference in New Issue
Block a user