mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-21 22:31:42 +08:00
Merge pull request #4104 from gebdalaoli-arch/codex/fix-image-gen-hosted-tool-conflict
[codex] avoid duplicate hosted image tool injection
This commit is contained in:
@@ -838,6 +838,9 @@ func ensureOpenAIResponsesImageGenerationTool(reqBody map[string]any) bool {
|
||||
if isCodexSparkModel(firstNonEmptyString(reqBody["model"])) {
|
||||
return false
|
||||
}
|
||||
if hasOpenAIImageGenerationTool(reqBody) {
|
||||
return false
|
||||
}
|
||||
|
||||
tool := map[string]any{
|
||||
"type": "image_generation",
|
||||
@@ -855,16 +858,6 @@ func ensureOpenAIResponsesImageGenerationTool(reqBody map[string]any) bool {
|
||||
reqBody["tools"] = []any{tool}
|
||||
return true
|
||||
}
|
||||
for _, rawTool := range tools {
|
||||
toolMap, ok := rawTool.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if strings.TrimSpace(firstNonEmptyString(toolMap["type"])) == "image_generation" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
reqBody["tools"] = append(tools, tool)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -617,6 +617,65 @@ func TestEnsureOpenAIResponsesImageGenerationTool_PreservesExistingImageTool(t *
|
||||
require.Equal(t, "webp", tool["output_format"])
|
||||
}
|
||||
|
||||
func TestEnsureOpenAIResponsesImageGenerationTool_PreservesImageGenNamespace(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
reqBody map[string]any
|
||||
}{
|
||||
{
|
||||
name: "top-level tools",
|
||||
reqBody: map[string]any{
|
||||
"model": "gpt-5.5",
|
||||
"tools": []any{
|
||||
map[string]any{
|
||||
"type": "namespace",
|
||||
"name": "image_gen",
|
||||
"tools": []any{
|
||||
map[string]any{"type": "function", "name": "imagegen"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "responses lite additional_tools",
|
||||
reqBody: map[string]any{
|
||||
"model": "gpt-5.5",
|
||||
"input": []any{
|
||||
map[string]any{
|
||||
"type": "additional_tools",
|
||||
"tools": []any{
|
||||
map[string]any{
|
||||
"type": "namespace",
|
||||
"name": "image_gen",
|
||||
"tools": []any{
|
||||
map[string]any{"type": "function", "name": "imagegen"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.True(t, hasOpenAIImageGenerationTool(tt.reqBody))
|
||||
|
||||
modified := ensureOpenAIResponsesImageGenerationTool(tt.reqBody)
|
||||
|
||||
require.False(t, modified)
|
||||
tools, _ := tt.reqBody["tools"].([]any)
|
||||
for _, rawTool := range tools {
|
||||
tool, ok := rawTool.(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.NotEqual(t, "image_generation", firstNonEmptyString(tool["type"]))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCodexImageGenerationBridgeInstructions_AppendsBridgeOnce(t *testing.T) {
|
||||
reqBody := map[string]any{
|
||||
"model": "gpt-5.4",
|
||||
|
||||
@@ -283,6 +283,44 @@ func TestOpenAIGatewayServiceForward_ChannelBridgeOverrideEnablesCodexInjection(
|
||||
require.Contains(t, instructions, "image_generation")
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayServiceForward_CodexBridgeDoesNotInjectHostedToolAlongsideImageGenNamespace(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
upstream := &httpUpstreamRecorder{
|
||||
resp: &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Header: http.Header{"Content-Type": []string{"application/json"}},
|
||||
Body: io.NopCloser(strings.NewReader(`{"id":"resp_namespace_image","model":"gpt-5.5","usage":{"input_tokens":1,"output_tokens":1}}`)),
|
||||
},
|
||||
}
|
||||
svc := newOpenAIImageGenerationControlTestService(upstream)
|
||||
svc.cfg.Gateway.CodexImageGenerationBridgeEnabled = true
|
||||
c, _ := newOpenAIImageGenerationControlTestContext(true, "codex_cli_rs/0.144.1")
|
||||
account := newOpenAIImageGenerationControlTestAccount()
|
||||
body := []byte(`{
|
||||
"model":"gpt-5.5",
|
||||
"stream":false,
|
||||
"tools":[
|
||||
{"type":"function","name":"shell","parameters":{"type":"object"}},
|
||||
{"type":"namespace","name":"image_gen","tools":[{"type":"function","name":"imagegen"}]}
|
||||
],
|
||||
"input":[
|
||||
{"type":"message","role":"user","content":[{"type":"input_text","text":"draw a cat"}]},
|
||||
{"type":"additional_tools","tools":[{"type":"namespace","name":"image_gen","tools":[{"type":"function","name":"imagegen"}]}]}
|
||||
],
|
||||
"tool_choice":"auto"
|
||||
}`)
|
||||
|
||||
result, err := svc.Forward(context.Background(), c, account, body)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, result)
|
||||
require.NotNil(t, upstream.lastReq)
|
||||
require.False(t, gjson.GetBytes(upstream.lastBody, `tools.#(type=="image_generation")`).Exists())
|
||||
require.Equal(t, "namespace", gjson.GetBytes(upstream.lastBody, `tools.#(name=="image_gen").type`).String())
|
||||
require.Equal(t, "namespace", gjson.GetBytes(upstream.lastBody, `input.#(type=="additional_tools").tools.#(name=="image_gen").type`).String())
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayServiceForward_CodexBridgePreservesExistingToolChoice(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user