mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
fix(openai): set tool_choice auto for Codex image bridge
This commit is contained in:
@@ -754,6 +754,20 @@ func ensureOpenAIResponsesImageGenerationTool(reqBody map[string]any) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func ensureOpenAIResponsesImageGenerationToolChoiceAuto(reqBody map[string]any) bool {
|
||||
if len(reqBody) == 0 || !hasOpenAIImageGenerationTool(reqBody) {
|
||||
return false
|
||||
}
|
||||
if isCodexSparkModel(firstNonEmptyString(reqBody["model"])) {
|
||||
return false
|
||||
}
|
||||
if _, ok := reqBody["tool_choice"]; ok {
|
||||
return false
|
||||
}
|
||||
reqBody["tool_choice"] = "auto"
|
||||
return true
|
||||
}
|
||||
|
||||
func applyCodexImageGenerationBridgeInstructions(reqBody map[string]any) bool {
|
||||
if len(reqBody) == 0 || !hasOpenAIImageGenerationTool(reqBody) {
|
||||
return false
|
||||
|
||||
@@ -2696,6 +2696,10 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco
|
||||
markDecodedModified()
|
||||
logger.LegacyPrintf("service.openai_gateway", "[OpenAI] Injected /responses image_generation tool for Codex client")
|
||||
}
|
||||
if codexImageGenerationBridgeEnabled && ensureOpenAIResponsesImageGenerationToolChoiceAuto(decoded) {
|
||||
markDecodedModified()
|
||||
logger.LegacyPrintf("service.openai_gateway", "[OpenAI] Set /responses image_generation tool_choice=auto for Codex client")
|
||||
}
|
||||
if normalizeOpenAIResponsesImageGenerationTools(decoded) {
|
||||
markDecodedModified()
|
||||
logger.LegacyPrintf("service.openai_gateway", "[OpenAI] Normalized /responses image_generation tool payload")
|
||||
|
||||
@@ -116,6 +116,11 @@ func TestOpenAIGatewayServiceForward_CodexImageInjectionRespectsGroupCapability(
|
||||
require.Equal(t, tt.wantInjected, hasImageTool)
|
||||
instructions := gjson.GetBytes(upstream.lastBody, "instructions").String()
|
||||
require.Equal(t, tt.wantInjected, strings.Contains(instructions, "image_generation"))
|
||||
toolChoice := gjson.GetBytes(upstream.lastBody, "tool_choice")
|
||||
require.Equal(t, tt.wantInjected, toolChoice.Exists())
|
||||
if tt.wantInjected {
|
||||
require.Equal(t, "auto", toolChoice.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -175,10 +180,34 @@ func TestOpenAIGatewayServiceForward_ChannelBridgeOverrideEnablesCodexInjection(
|
||||
require.NotNil(t, result)
|
||||
require.NotNil(t, upstream.lastReq)
|
||||
require.True(t, gjson.GetBytes(upstream.lastBody, `tools.#(type=="image_generation")`).Exists())
|
||||
require.Equal(t, "auto", gjson.GetBytes(upstream.lastBody, "tool_choice").String())
|
||||
instructions := gjson.GetBytes(upstream.lastBody, "instructions").String()
|
||||
require.Contains(t, instructions, "image_generation")
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayServiceForward_CodexBridgePreservesExistingToolChoice(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_codex_tool_choice","model":"gpt-5.4","usage":{"input_tokens":1,"output_tokens":1}}`)),
|
||||
},
|
||||
}
|
||||
svc := newOpenAIImageGenerationControlTestService(upstream)
|
||||
svc.cfg.Gateway.CodexImageGenerationBridgeEnabled = true
|
||||
c, _ := newOpenAIImageGenerationControlTestContext(true, "codex_cli_rs/0.98.0")
|
||||
account := newOpenAIImageGenerationControlTestAccount()
|
||||
|
||||
result, err := svc.Forward(context.Background(), c, account, []byte(`{"model":"gpt-5.4","input":"draw","stream":false,"tools":[{"type":"image_generation"}],"tool_choice":{"type":"image_generation"}}`))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, result)
|
||||
require.NotNil(t, upstream.lastReq)
|
||||
require.Equal(t, "image_generation", gjson.GetBytes(upstream.lastBody, "tool_choice.type").String())
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayService_CodexImageGenerationBridgeOverridePrecedence(t *testing.T) {
|
||||
groupID := int64(4242)
|
||||
|
||||
|
||||
@@ -2666,6 +2666,10 @@ func (s *OpenAIGatewayService) ProxyResponsesWebSocketFromClient(
|
||||
bridgeModified = true
|
||||
logOpenAIWSModeInfo("ingress_ws_codex_image_tool_injected account_id=%d", account.ID)
|
||||
}
|
||||
if ensureOpenAIResponsesImageGenerationToolChoiceAuto(payloadMap) {
|
||||
bridgeModified = true
|
||||
logOpenAIWSModeInfo("ingress_ws_codex_image_tool_choice_auto account_id=%d", account.ID)
|
||||
}
|
||||
if normalizeOpenAIResponsesImageGenerationTools(payloadMap) {
|
||||
bridgeModified = true
|
||||
}
|
||||
|
||||
@@ -431,6 +431,7 @@ func TestOpenAIGatewayService_ProxyResponsesWebSocketFromClient_InjectsCodexImag
|
||||
upstreamPayload := requestToJSONString(captureConn.writes[0])
|
||||
require.True(t, gjson.Get(upstreamPayload, `tools.#(type=="image_generation")`).Exists())
|
||||
require.Equal(t, "png", gjson.Get(upstreamPayload, `tools.#(type=="image_generation").output_format`).String())
|
||||
require.Equal(t, "auto", gjson.Get(upstreamPayload, "tool_choice").String())
|
||||
require.Contains(t, gjson.Get(upstreamPayload, "instructions").String(), "image_generation")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user