feat(translator): preserve structured tool_choice in OpenAI response conversions

- Updated `ConvertOpenAIResponsesRequestToOpenAIChatCompletions` to retain `tool_choice` with raw byte handling.
- Added `TestConvertOpenAIResponsesRequestToOpenAIChatCompletions_PreservesStructuredToolChoice` to ensure function and type fields are preserved in transformations.

Closes: #3384
This commit is contained in:
Luis Pater
2026-06-19 05:48:57 +08:00
parent 07c297a51b
commit aed54adbea
2 changed files with 26 additions and 1 deletions
@@ -250,7 +250,7 @@ func ConvertOpenAIResponsesRequestToOpenAIChatCompletions(modelName string, inpu
// Convert tool_choice if present
if toolChoice := root.Get("tool_choice"); toolChoice.Exists() {
out, _ = sjson.SetBytes(out, "tool_choice", toolChoice.String())
out, _ = sjson.SetRawBytes(out, "tool_choice", []byte(toolChoice.Raw))
}
return out
@@ -173,3 +173,28 @@ func TestConvertOpenAIResponsesRequestToOpenAIChatCompletions_FlattensNamespaceT
t.Fatalf("tools.0.function.parameters.required.0 = %q, want a; output=%s", got, out)
}
}
func TestConvertOpenAIResponsesRequestToOpenAIChatCompletions_PreservesStructuredToolChoice(t *testing.T) {
raw := []byte(`{
"input": [
{"role":"user","content":"Run command."}
],
"tool_choice": {
"type": "function",
"function": {
"name": "run_command"
}
}
}`)
t.Logf("input json:\n%s", prettyJSONForTest(raw))
out := ConvertOpenAIResponsesRequestToOpenAIChatCompletions("gpt-5.4", raw, false)
t.Logf("output json:\n%s", prettyJSONForTest(out))
if got := gjson.GetBytes(out, "tool_choice.type").String(); got != "function" {
t.Fatalf("tool_choice.type = %q, want function; output=%s", got, out)
}
if got := gjson.GetBytes(out, "tool_choice.function.name").String(); got != "run_command" {
t.Fatalf("tool_choice.function.name = %q, want run_command; output=%s", got, out)
}
}