feat: apply image_generation filtering before payload rules

- Updated `ApplyPayloadConfigWithRoot` to prioritize `disable-image-generation` filtering before applying payload rules.
- Ensured payload overrides can explicitly re-enable `image_generation` when required.
- Added unit tests to validate `image_generation` restoration through overrides.
This commit is contained in:
Luis Pater
2026-04-30 12:42:08 +08:00
parent f56a19e5b8
commit 6ba7c810a7
2 changed files with 46 additions and 8 deletions

View File

@@ -23,6 +23,15 @@ func ApplyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
}
out := payload
// Apply disable-image-generation filtering before payload rules so config payload
// overrides can explicitly re-enable image_generation when desired.
if cfg.DisableImageGeneration != config.DisableImageGenerationOff {
if cfg.DisableImageGeneration != config.DisableImageGenerationChat || !isImagesEndpointRequestPath(requestPath) {
out = removeToolTypeFromPayloadWithRoot(out, root, "image_generation")
out = removeToolChoiceFromPayloadWithRoot(out, root, "image_generation")
}
}
rules := cfg.Payload
hasPayloadRules := len(rules.Default) != 0 || len(rules.DefaultRaw) != 0 || len(rules.Override) != 0 || len(rules.OverrideRaw) != 0 || len(rules.Filter) != 0
if hasPayloadRules {
@@ -149,14 +158,6 @@ func ApplyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
}
}
}
if cfg.DisableImageGeneration != config.DisableImageGenerationOff {
if cfg.DisableImageGeneration == config.DisableImageGenerationChat && isImagesEndpointRequestPath(requestPath) {
return out
}
out = removeToolTypeFromPayloadWithRoot(out, root, "image_generation")
out = removeToolChoiceFromPayloadWithRoot(out, root, "image_generation")
}
return out
}

View File

@@ -95,3 +95,40 @@ func TestApplyPayloadConfigWithRoot_DisableImageGenerationChat_KeepsImageGenerat
t.Fatalf("expected tool_choice to be kept on images endpoint")
}
}
func TestApplyPayloadConfigWithRoot_DisableImageGeneration_PayloadOverrideCanRestoreImageGeneration(t *testing.T) {
cfg := &config.Config{
SDKConfig: config.SDKConfig{DisableImageGeneration: config.DisableImageGenerationAll},
Payload: config.PayloadConfig{
OverrideRaw: []config.PayloadRule{
{
Models: []config.PayloadModelRule{
{Name: "gpt-5.4", Protocol: "openai-response"},
},
Params: map[string]any{
"tools": `[{"type":"image_generation"},{"type":"function","name":"f1"}]`,
"tool_choice": `{"type":"image_generation"}`,
},
},
},
},
}
payload := []byte(`{"tools":[{"type":"image_generation"},{"type":"function","name":"f1"}],"tool_choice":{"type":"image_generation"}}`)
out := ApplyPayloadConfigWithRoot(cfg, "gpt-5.4", "openai-response", "", payload, nil, "", "")
tools := gjson.GetBytes(out, "tools")
if !tools.Exists() || !tools.IsArray() {
t.Fatalf("expected tools array, got %v", tools.Type)
}
arr := tools.Array()
if len(arr) != 2 {
t.Fatalf("expected 2 tools after payload override, got %d", len(arr))
}
if got := arr[0].Get("type").String(); got != "image_generation" {
t.Fatalf("expected first tool type=image_generation, got %q", got)
}
if !gjson.GetBytes(out, "tool_choice").Exists() {
t.Fatalf("expected tool_choice to be restored by payload override")
}
}