From 6d8609e45758505e83095787b91c6058a68f6318 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Sun, 1 Feb 2026 05:25:14 +0800 Subject: [PATCH] feat(config): add payload filter rules to remove JSON paths Introduce `Filter` rules in the payload configuration to remove specified JSON paths from the payload. Update related helper functions and add examples to `config.example.yaml`. --- config.example.yaml | 15 +++-- internal/config/config.go | 10 +++ internal/runtime/executor/payload_helpers.go | 67 +++++++++++--------- sdk/config/config.go | 1 + 4 files changed, 58 insertions(+), 35 deletions(-) diff --git a/config.example.yaml b/config.example.yaml index 83e92627..75a175af 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -285,24 +285,31 @@ oauth-model-alias: # default: # Default rules only set parameters when they are missing in the payload. # - models: # - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*") -# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex +# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity # params: # JSON path (gjson/sjson syntax) -> value # "generationConfig.thinkingConfig.thinkingBudget": 32768 # default-raw: # Default raw rules set parameters using raw JSON when missing (must be valid JSON). # - models: # - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*") -# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex +# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity # params: # JSON path (gjson/sjson syntax) -> raw JSON value (strings are used as-is, must be valid JSON) # "generationConfig.responseJsonSchema": "{\"type\":\"object\",\"properties\":{\"answer\":{\"type\":\"string\"}}}" # override: # Override rules always set parameters, overwriting any existing values. # - models: # - name: "gpt-*" # Supports wildcards (e.g., "gpt-*") -# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex +# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity # params: # JSON path (gjson/sjson syntax) -> value # "reasoning.effort": "high" # override-raw: # Override raw rules always set parameters using raw JSON (must be valid JSON). # - models: # - name: "gpt-*" # Supports wildcards (e.g., "gpt-*") -# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex +# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity # params: # JSON path (gjson/sjson syntax) -> raw JSON value (strings are used as-is, must be valid JSON) # "response_format": "{\"type\":\"json_schema\",\"json_schema\":{\"name\":\"answer\",\"schema\":{\"type\":\"object\"}}}" +# filter: # Filter rules remove specified parameters from the payload. +# - models: +# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*") +# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity +# params: # JSON paths (gjson/sjson syntax) to remove from the payload +# - "generationConfig.thinkingConfig.thinkingBudget" +# - "generationConfig.responseJsonSchema" diff --git a/internal/config/config.go b/internal/config/config.go index 63d04aa4..87847517 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -229,6 +229,16 @@ type PayloadConfig struct { Override []PayloadRule `yaml:"override" json:"override"` // OverrideRaw defines rules that always set raw JSON values, overwriting any existing values. OverrideRaw []PayloadRule `yaml:"override-raw" json:"override-raw"` + // Filter defines rules that remove parameters from the payload by JSON path. + Filter []PayloadFilterRule `yaml:"filter" json:"filter"` +} + +// PayloadFilterRule describes a rule to remove specific JSON paths from matching model payloads. +type PayloadFilterRule struct { + // Models lists model entries with name pattern and protocol constraint. + Models []PayloadModelRule `yaml:"models" json:"models"` + // Params lists JSON paths (gjson/sjson syntax) to remove from the payload. + Params []string `yaml:"params" json:"params"` } // PayloadRule describes a single rule targeting a list of models with parameter updates. diff --git a/internal/runtime/executor/payload_helpers.go b/internal/runtime/executor/payload_helpers.go index ebae858a..271e2c5b 100644 --- a/internal/runtime/executor/payload_helpers.go +++ b/internal/runtime/executor/payload_helpers.go @@ -21,7 +21,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string return payload } rules := cfg.Payload - if len(rules.Default) == 0 && len(rules.DefaultRaw) == 0 && len(rules.Override) == 0 && len(rules.OverrideRaw) == 0 { + if len(rules.Default) == 0 && len(rules.DefaultRaw) == 0 && len(rules.Override) == 0 && len(rules.OverrideRaw) == 0 && len(rules.Filter) == 0 { return payload } model = strings.TrimSpace(model) @@ -39,7 +39,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string // Apply default rules: first write wins per field across all matching rules. for i := range rules.Default { rule := &rules.Default[i] - if !payloadRuleMatchesModels(rule, protocol, candidates) { + if !payloadModelRulesMatch(rule.Models, protocol, candidates) { continue } for path, value := range rule.Params { @@ -64,7 +64,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string // Apply default raw rules: first write wins per field across all matching rules. for i := range rules.DefaultRaw { rule := &rules.DefaultRaw[i] - if !payloadRuleMatchesModels(rule, protocol, candidates) { + if !payloadModelRulesMatch(rule.Models, protocol, candidates) { continue } for path, value := range rule.Params { @@ -93,7 +93,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string // Apply override rules: last write wins per field across all matching rules. for i := range rules.Override { rule := &rules.Override[i] - if !payloadRuleMatchesModels(rule, protocol, candidates) { + if !payloadModelRulesMatch(rule.Models, protocol, candidates) { continue } for path, value := range rule.Params { @@ -111,7 +111,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string // Apply override raw rules: last write wins per field across all matching rules. for i := range rules.OverrideRaw { rule := &rules.OverrideRaw[i] - if !payloadRuleMatchesModels(rule, protocol, candidates) { + if !payloadModelRulesMatch(rule.Models, protocol, candidates) { continue } for path, value := range rule.Params { @@ -130,38 +130,43 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string out = updated } } + // Apply filter rules: remove matching paths from payload. + for i := range rules.Filter { + rule := &rules.Filter[i] + if !payloadModelRulesMatch(rule.Models, protocol, candidates) { + continue + } + for _, path := range rule.Params { + fullPath := buildPayloadPath(root, path) + if fullPath == "" { + continue + } + updated, errDel := sjson.DeleteBytes(out, fullPath) + if errDel != nil { + continue + } + out = updated + } + } return out } -func payloadRuleMatchesModels(rule *config.PayloadRule, protocol string, models []string) bool { - if rule == nil || len(models) == 0 { +func payloadModelRulesMatch(rules []config.PayloadModelRule, protocol string, models []string) bool { + if len(rules) == 0 || len(models) == 0 { return false } for _, model := range models { - if payloadRuleMatchesModel(rule, model, protocol) { - return true - } - } - return false -} - -func payloadRuleMatchesModel(rule *config.PayloadRule, model, protocol string) bool { - if rule == nil { - return false - } - if len(rule.Models) == 0 { - return false - } - for _, entry := range rule.Models { - name := strings.TrimSpace(entry.Name) - if name == "" { - continue - } - if ep := strings.TrimSpace(entry.Protocol); ep != "" && protocol != "" && !strings.EqualFold(ep, protocol) { - continue - } - if matchModelPattern(name, model) { - return true + for _, entry := range rules { + name := strings.TrimSpace(entry.Name) + if name == "" { + continue + } + if ep := strings.TrimSpace(entry.Protocol); ep != "" && protocol != "" && !strings.EqualFold(ep, protocol) { + continue + } + if matchModelPattern(name, model) { + return true + } } } return false diff --git a/sdk/config/config.go b/sdk/config/config.go index 304ccdd8..a9b5c2c3 100644 --- a/sdk/config/config.go +++ b/sdk/config/config.go @@ -19,6 +19,7 @@ type AmpCode = internalconfig.AmpCode type OAuthModelAlias = internalconfig.OAuthModelAlias type PayloadConfig = internalconfig.PayloadConfig type PayloadRule = internalconfig.PayloadRule +type PayloadFilterRule = internalconfig.PayloadFilterRule type PayloadModelRule = internalconfig.PayloadModelRule type GeminiKey = internalconfig.GeminiKey