fix: align claude codex translation

This commit is contained in:
sususu98
2026-04-29 18:47:03 +08:00
parent 2ea8f77efb
commit 1c0c426b85
4 changed files with 454 additions and 36 deletions
@@ -68,7 +68,7 @@ func ConvertCodexResponseToClaude(_ context.Context, _ string, originalRequestRa
params := (*param).(*ConvertCodexResponseToClaudeParams)
if params.ThinkingBlockOpen && params.ThinkingStopPending {
switch rootResult.Get("type").String() {
case "response.content_part.added", "response.completed":
case "response.content_part.added", "response.completed", "response.incomplete":
output = append(output, finalizeCodexThinkingBlock(params)...)
}
}
@@ -117,18 +117,12 @@ func ConvertCodexResponseToClaude(_ context.Context, _ string, originalRequestRa
params.BlockIndex++
output = translatorcommon.AppendSSEEventBytes(output, "content_block_stop", template, 2)
} else if typeStr == "response.completed" {
} else if typeStr == "response.completed" || typeStr == "response.incomplete" {
template = []byte(`{"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`)
p := params.HasToolCall
stopReason := rootResult.Get("response.stop_reason").String()
if p {
template, _ = sjson.SetBytes(template, "delta.stop_reason", "tool_use")
} else if stopReason == "max_tokens" || stopReason == "stop" {
template, _ = sjson.SetBytes(template, "delta.stop_reason", stopReason)
} else {
template, _ = sjson.SetBytes(template, "delta.stop_reason", "end_turn")
}
inputTokens, outputTokens, cachedTokens := extractResponsesUsage(rootResult.Get("response.usage"))
responseData := rootResult.Get("response")
template, _ = sjson.SetBytes(template, "delta.stop_reason", mapCodexStopReasonToClaude(codexStopReason(responseData), params.HasToolCall))
template = setClaudeStopSequence(template, "delta.stop_sequence", responseData)
inputTokens, outputTokens, cachedTokens := extractResponsesUsage(responseData.Get("usage"))
template, _ = sjson.SetBytes(template, "usage.input_tokens", inputTokens)
template, _ = sjson.SetBytes(template, "usage.output_tokens", outputTokens)
if cachedTokens > 0 {
@@ -259,7 +253,8 @@ func ConvertCodexResponseToClaudeNonStream(_ context.Context, _ string, original
revNames := buildReverseMapFromClaudeOriginalShortToOriginal(originalRequestRawJSON)
rootResult := gjson.ParseBytes(rawJSON)
if rootResult.Get("type").String() != "response.completed" {
typeStr := rootResult.Get("type").String()
if typeStr != "response.completed" && typeStr != "response.incomplete" {
return []byte{}
}
@@ -371,18 +366,57 @@ func ConvertCodexResponseToClaudeNonStream(_ context.Context, _ string, original
})
}
out, _ = sjson.SetBytes(out, "stop_reason", mapCodexStopReasonToClaude(codexStopReason(responseData), hasToolCall))
out = setClaudeStopSequence(out, "stop_sequence", responseData)
return out
}
func codexStopReason(responseData gjson.Result) string {
if stopReason := responseData.Get("stop_reason"); stopReason.Exists() && stopReason.String() != "" {
out, _ = sjson.SetBytes(out, "stop_reason", stopReason.String())
} else if hasToolCall {
out, _ = sjson.SetBytes(out, "stop_reason", "tool_use")
} else {
out, _ = sjson.SetBytes(out, "stop_reason", "end_turn")
if stopReason.String() == "stop" && codexStopSequence(responseData).String() != "" {
return "stop_sequence"
}
return stopReason.String()
}
if reason := responseData.Get("incomplete_details.reason"); reason.Exists() && reason.String() != "" {
return reason.String()
}
if codexStopSequence(responseData).String() != "" {
return "stop_sequence"
}
return ""
}
func mapCodexStopReasonToClaude(stopReason string, hasToolCall bool) string {
if hasToolCall {
return "tool_use"
}
if stopSequence := responseData.Get("stop_sequence"); stopSequence.Exists() && stopSequence.String() != "" {
out, _ = sjson.SetRawBytes(out, "stop_sequence", []byte(stopSequence.Raw))
switch stopReason {
case "", "stop", "completed":
return "end_turn"
case "max_tokens", "max_output_tokens":
return "max_tokens"
case "tool_use", "tool_calls", "function_call":
return "tool_use"
case "end_turn", "stop_sequence", "pause_turn", "refusal", "model_context_window_exceeded":
return stopReason
case "content_filter":
return "refusal"
default:
return "end_turn"
}
}
func codexStopSequence(responseData gjson.Result) gjson.Result {
return responseData.Get("stop_sequence")
}
func setClaudeStopSequence(out []byte, path string, responseData gjson.Result) []byte {
if stopSequence := codexStopSequence(responseData); stopSequence.Exists() && stopSequence.String() != "" {
out, _ = sjson.SetRawBytes(out, path, []byte(stopSequence.Raw))
}
return out
}