From 54ffb52838f55493e566dc4c109a2e10b3aee186 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Fri, 5 Sep 2025 09:02:24 +0800 Subject: [PATCH] Add `FunctionCallIndex` to `ConvertCliToOpenAIParams` and enhance tool call handling - Introduced `FunctionCallIndex` to track and manage function call indices within `ConvertCliToOpenAIParams`. - Enhanced handling for `response.completed` and `response.output_item.done` data types to support tool call scenarios. - Improved logic for restoring original tool names and setting function arguments during response parsing. --- .../chat-completions/codex_openai_response.go | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/internal/translator/codex/openai/chat-completions/codex_openai_response.go b/internal/translator/codex/openai/chat-completions/codex_openai_response.go index 49ed00ef..9a596426 100644 --- a/internal/translator/codex/openai/chat-completions/codex_openai_response.go +++ b/internal/translator/codex/openai/chat-completions/codex_openai_response.go @@ -21,9 +21,10 @@ var ( // ConvertCliToOpenAIParams holds parameters for response conversion. type ConvertCliToOpenAIParams struct { - ResponseID string - CreatedAt int64 - Model string + ResponseID string + CreatedAt int64 + Model string + FunctionCallIndex int } // ConvertCodexResponseToOpenAI translates a single chunk of a streaming response from the @@ -43,9 +44,10 @@ type ConvertCliToOpenAIParams struct { func ConvertCodexResponseToOpenAI(_ context.Context, modelName string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, param *any) []string { if *param == nil { *param = &ConvertCliToOpenAIParams{ - Model: modelName, - CreatedAt: 0, - ResponseID: "", + Model: modelName, + CreatedAt: 0, + ResponseID: "", + FunctionCallIndex: -1, } } @@ -108,27 +110,36 @@ func ConvertCodexResponseToOpenAI(_ context.Context, modelName string, originalR template, _ = sjson.Set(template, "choices.0.delta.content", deltaResult.String()) } } else if dataType == "response.completed" { - template, _ = sjson.Set(template, "choices.0.finish_reason", "stop") - template, _ = sjson.Set(template, "choices.0.native_finish_reason", "stop") + finishReason := "stop" + if (*param).(*ConvertCliToOpenAIParams).FunctionCallIndex != -1 { + finishReason = "tool_calls" + } + template, _ = sjson.Set(template, "choices.0.finish_reason", finishReason) + template, _ = sjson.Set(template, "choices.0.native_finish_reason", finishReason) } else if dataType == "response.output_item.done" { - functionCallItemTemplate := `{"id": "","type": "function","function": {"name": "","arguments": ""}}` + functionCallItemTemplate := `{"index":0,"id":"","type":"function","function":{"name":"","arguments":""}}` itemResult := rootResult.Get("item") if itemResult.Exists() { if itemResult.Get("type").String() != "function_call" { return []string{} } + + // set the index + (*param).(*ConvertCliToOpenAIParams).FunctionCallIndex++ + functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "index", (*param).(*ConvertCliToOpenAIParams).FunctionCallIndex) + template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls", `[]`) functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "id", itemResult.Get("call_id").String()) - { - // Restore original tool name if it was shortened - name := itemResult.Get("name").String() - // Build reverse map on demand from original request tools - rev := buildReverseMapFromOriginalOpenAI(originalRequestRawJSON) - if orig, ok := rev[name]; ok { - name = orig - } - functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "function.name", name) + + // Restore original tool name if it was shortened + name := itemResult.Get("name").String() + // Build reverse map on demand from original request tools + rev := buildReverseMapFromOriginalOpenAI(originalRequestRawJSON) + if orig, ok := rev[name]; ok { + name = orig } + functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "function.name", name) + functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "function.arguments", itemResult.Get("arguments").String()) template, _ = sjson.Set(template, "choices.0.delta.role", "assistant") template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls.-1", functionCallItemTemplate)