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`.
This commit is contained in:
Luis Pater
2026-02-01 05:25:14 +08:00
parent d216adeffc
commit 6d8609e457
4 changed files with 58 additions and 35 deletions

View File

@@ -285,24 +285,31 @@ oauth-model-alias:
# default: # Default rules only set parameters when they are missing in the payload. # default: # Default rules only set parameters when they are missing in the payload.
# - models: # - models:
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*") # - 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 # params: # JSON path (gjson/sjson syntax) -> value
# "generationConfig.thinkingConfig.thinkingBudget": 32768 # "generationConfig.thinkingConfig.thinkingBudget": 32768
# default-raw: # Default raw rules set parameters using raw JSON when missing (must be valid JSON). # default-raw: # Default raw rules set parameters using raw JSON when missing (must be valid JSON).
# - models: # - models:
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*") # - 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) # 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\"}}}" # "generationConfig.responseJsonSchema": "{\"type\":\"object\",\"properties\":{\"answer\":{\"type\":\"string\"}}}"
# override: # Override rules always set parameters, overwriting any existing values. # override: # Override rules always set parameters, overwriting any existing values.
# - models: # - models:
# - name: "gpt-*" # Supports wildcards (e.g., "gpt-*") # - 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 # params: # JSON path (gjson/sjson syntax) -> value
# "reasoning.effort": "high" # "reasoning.effort": "high"
# override-raw: # Override raw rules always set parameters using raw JSON (must be valid JSON). # override-raw: # Override raw rules always set parameters using raw JSON (must be valid JSON).
# - models: # - models:
# - name: "gpt-*" # Supports wildcards (e.g., "gpt-*") # - 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) # 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\"}}}" # "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"

View File

@@ -229,6 +229,16 @@ type PayloadConfig struct {
Override []PayloadRule `yaml:"override" json:"override"` Override []PayloadRule `yaml:"override" json:"override"`
// OverrideRaw defines rules that always set raw JSON values, overwriting any existing values. // OverrideRaw defines rules that always set raw JSON values, overwriting any existing values.
OverrideRaw []PayloadRule `yaml:"override-raw" json:"override-raw"` 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. // PayloadRule describes a single rule targeting a list of models with parameter updates.

View File

@@ -21,7 +21,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
return payload return payload
} }
rules := cfg.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 return payload
} }
model = strings.TrimSpace(model) 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. // Apply default rules: first write wins per field across all matching rules.
for i := range rules.Default { for i := range rules.Default {
rule := &rules.Default[i] rule := &rules.Default[i]
if !payloadRuleMatchesModels(rule, protocol, candidates) { if !payloadModelRulesMatch(rule.Models, protocol, candidates) {
continue continue
} }
for path, value := range rule.Params { 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. // Apply default raw rules: first write wins per field across all matching rules.
for i := range rules.DefaultRaw { for i := range rules.DefaultRaw {
rule := &rules.DefaultRaw[i] rule := &rules.DefaultRaw[i]
if !payloadRuleMatchesModels(rule, protocol, candidates) { if !payloadModelRulesMatch(rule.Models, protocol, candidates) {
continue continue
} }
for path, value := range rule.Params { 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. // Apply override rules: last write wins per field across all matching rules.
for i := range rules.Override { for i := range rules.Override {
rule := &rules.Override[i] rule := &rules.Override[i]
if !payloadRuleMatchesModels(rule, protocol, candidates) { if !payloadModelRulesMatch(rule.Models, protocol, candidates) {
continue continue
} }
for path, value := range rule.Params { 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. // Apply override raw rules: last write wins per field across all matching rules.
for i := range rules.OverrideRaw { for i := range rules.OverrideRaw {
rule := &rules.OverrideRaw[i] rule := &rules.OverrideRaw[i]
if !payloadRuleMatchesModels(rule, protocol, candidates) { if !payloadModelRulesMatch(rule.Models, protocol, candidates) {
continue continue
} }
for path, value := range rule.Params { for path, value := range rule.Params {
@@ -130,29 +130,33 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
out = updated 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 return out
} }
func payloadRuleMatchesModels(rule *config.PayloadRule, protocol string, models []string) bool { func payloadModelRulesMatch(rules []config.PayloadModelRule, protocol string, models []string) bool {
if rule == nil || len(models) == 0 { if len(rules) == 0 || len(models) == 0 {
return false return false
} }
for _, model := range models { for _, model := range models {
if payloadRuleMatchesModel(rule, model, protocol) { for _, entry := range rules {
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) name := strings.TrimSpace(entry.Name)
if name == "" { if name == "" {
continue continue
@@ -164,6 +168,7 @@ func payloadRuleMatchesModel(rule *config.PayloadRule, model, protocol string) b
return true return true
} }
} }
}
return false return false
} }

View File

@@ -19,6 +19,7 @@ type AmpCode = internalconfig.AmpCode
type OAuthModelAlias = internalconfig.OAuthModelAlias type OAuthModelAlias = internalconfig.OAuthModelAlias
type PayloadConfig = internalconfig.PayloadConfig type PayloadConfig = internalconfig.PayloadConfig
type PayloadRule = internalconfig.PayloadRule type PayloadRule = internalconfig.PayloadRule
type PayloadFilterRule = internalconfig.PayloadFilterRule
type PayloadModelRule = internalconfig.PayloadModelRule type PayloadModelRule = internalconfig.PayloadModelRule
type GeminiKey = internalconfig.GeminiKey type GeminiKey = internalconfig.GeminiKey