-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
feat(payload): support persisted disable toggles #2741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -301,19 +301,27 @@ type PayloadConfig struct { | |
|
|
||
| // PayloadFilterRule describes a rule to remove specific JSON paths from matching model payloads. | ||
| type PayloadFilterRule struct { | ||
| // Disabled skips this rule entirely when true. | ||
| Disabled bool `yaml:"disabled,omitempty" json:"disabled,omitempty"` | ||
| // 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"` | ||
| // DisabledParams lists JSON paths that should remain visible in config but not be applied. | ||
| DisabledParams []string `yaml:"disabled-params,omitempty" json:"disabled-params,omitempty"` | ||
| } | ||
|
|
||
| // PayloadRule describes a single rule targeting a list of models with parameter updates. | ||
| type PayloadRule struct { | ||
| // Disabled skips this rule entirely when true. | ||
| Disabled bool `yaml:"disabled,omitempty" json:"disabled,omitempty"` | ||
| // Models lists model entries with name pattern and protocol constraint. | ||
| Models []PayloadModelRule `yaml:"models" json:"models"` | ||
| // Params maps JSON paths (gjson/sjson syntax) to values written into the payload. | ||
| // For *-raw rules, values are treated as raw JSON fragments (strings are used as-is). | ||
| Params map[string]any `yaml:"params" json:"params"` | ||
| // DisabledParams lists JSON paths that should remain visible in config but not be applied. | ||
| DisabledParams []string `yaml:"disabled-params,omitempty" json:"disabled-params,omitempty"` | ||
|
Comment on lines
+323
to
+324
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Adding Useful? React with 👍 / 👎.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in d9d5c4e. |
||
| } | ||
|
|
||
| // PayloadModelRule ties a model name pattern to a specific translator protocol. | ||
|
|
@@ -720,8 +728,16 @@ func sanitizePayloadRawRules(rules []PayloadRule, section string) []PayloadRule | |
| if len(rule.Params) == 0 { | ||
| continue | ||
| } | ||
| if rule.Disabled { | ||
| out = append(out, rule) | ||
| continue | ||
| } | ||
| disabledParams := payloadDisabledParamSet(rule.DisabledParams) | ||
| invalid := false | ||
| for path, value := range rule.Params { | ||
| if payloadParamDisabled(disabledParams, path) { | ||
|
Comment on lines
+735
to
+738
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in a44447a. |
||
| continue | ||
| } | ||
| raw, ok := payloadRawString(value) | ||
| if !ok { | ||
| continue | ||
|
|
@@ -745,6 +761,32 @@ func sanitizePayloadRawRules(rules []PayloadRule, section string) []PayloadRule | |
| return out | ||
| } | ||
|
|
||
| func payloadDisabledParamSet(paths []string) map[string]struct{} { | ||
| if len(paths) == 0 { | ||
| return nil | ||
| } | ||
| out := make(map[string]struct{}, len(paths)) | ||
| for _, path := range paths { | ||
| trimmed := strings.TrimSpace(path) | ||
| if trimmed == "" { | ||
| continue | ||
| } | ||
| out[trimmed] = struct{}{} | ||
| } | ||
| if len(out) == 0 { | ||
| return nil | ||
| } | ||
| return out | ||
| } | ||
|
|
||
| func payloadParamDisabled(disabled map[string]struct{}, path string) bool { | ||
| if len(disabled) == 0 { | ||
| return false | ||
| } | ||
| _, ok := disabled[strings.TrimSpace(path)] | ||
| return ok | ||
| } | ||
|
|
||
| func payloadRawString(value any) ([]byte, bool) { | ||
| switch typed := value.(type) { | ||
| case string: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package config | ||
|
|
||
| import "testing" | ||
|
|
||
| func TestSanitizePayloadRules_KeepsDisabledRawRuleWithInvalidJSON(t *testing.T) { | ||
| cfg := &Config{ | ||
| Payload: PayloadConfig{ | ||
| DefaultRaw: []PayloadRule{ | ||
| { | ||
| Disabled: true, | ||
| Models: []PayloadModelRule{{Name: "gpt-*"}}, | ||
| Params: map[string]any{ | ||
| "metadata": `{"enabled":`, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| cfg.SanitizePayloadRules() | ||
|
|
||
| if len(cfg.Payload.DefaultRaw) != 1 { | ||
| t.Fatalf("disabled raw rule should be preserved during sanitize, got %d rules", len(cfg.Payload.DefaultRaw)) | ||
| } | ||
| if !cfg.Payload.DefaultRaw[0].Disabled { | ||
| t.Fatalf("disabled raw rule should remain disabled after sanitize") | ||
| } | ||
| } | ||
|
|
||
| func TestSanitizePayloadRules_DropsEnabledRawRuleWithInvalidJSON(t *testing.T) { | ||
| cfg := &Config{ | ||
| Payload: PayloadConfig{ | ||
| DefaultRaw: []PayloadRule{ | ||
| { | ||
| Models: []PayloadModelRule{{Name: "gpt-*"}}, | ||
| Params: map[string]any{ | ||
| "metadata": `{"enabled":`, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| cfg.SanitizePayloadRules() | ||
|
|
||
| if len(cfg.Payload.DefaultRaw) != 0 { | ||
| t.Fatalf("enabled raw rule with invalid JSON should be dropped, got %d rules", len(cfg.Payload.DefaultRaw)) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,10 +39,14 @@ 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 !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| if rule.Disabled || !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| continue | ||
| } | ||
| disabledParams := payloadDisabledParamSet(rule.DisabledParams) | ||
| for path, value := range rule.Params { | ||
| if payloadParamDisabled(disabledParams, path) { | ||
| continue | ||
| } | ||
| fullPath := buildPayloadPath(root, path) | ||
| if fullPath == "" { | ||
| continue | ||
|
|
@@ -64,10 +68,14 @@ 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 !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| if rule.Disabled || !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| continue | ||
| } | ||
| disabledParams := payloadDisabledParamSet(rule.DisabledParams) | ||
| for path, value := range rule.Params { | ||
| if payloadParamDisabled(disabledParams, path) { | ||
| continue | ||
| } | ||
| fullPath := buildPayloadPath(root, path) | ||
| if fullPath == "" { | ||
| continue | ||
|
|
@@ -93,10 +101,14 @@ 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 !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| if rule.Disabled || !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| continue | ||
| } | ||
| disabledParams := payloadDisabledParamSet(rule.DisabledParams) | ||
| for path, value := range rule.Params { | ||
| if payloadParamDisabled(disabledParams, path) { | ||
| continue | ||
| } | ||
| fullPath := buildPayloadPath(root, path) | ||
| if fullPath == "" { | ||
| continue | ||
|
|
@@ -111,10 +123,14 @@ 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 !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| if rule.Disabled || !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| continue | ||
| } | ||
| disabledParams := payloadDisabledParamSet(rule.DisabledParams) | ||
| for path, value := range rule.Params { | ||
| if payloadParamDisabled(disabledParams, path) { | ||
| continue | ||
| } | ||
| fullPath := buildPayloadPath(root, path) | ||
| if fullPath == "" { | ||
| continue | ||
|
|
@@ -133,10 +149,14 @@ func ApplyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string | |
| // Apply filter rules: remove matching paths from payload. | ||
| for i := range rules.Filter { | ||
| rule := &rules.Filter[i] | ||
| if !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| if rule.Disabled || !payloadModelRulesMatch(rule.Models, protocol, candidates) { | ||
| continue | ||
| } | ||
| disabledParams := payloadDisabledParamSet(rule.DisabledParams) | ||
| for _, path := range rule.Params { | ||
| if payloadParamDisabled(disabledParams, path) { | ||
| continue | ||
| } | ||
| fullPath := buildPayloadPath(root, path) | ||
| if fullPath == "" { | ||
| continue | ||
|
|
@@ -151,6 +171,32 @@ func ApplyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string | |
| return out | ||
| } | ||
|
|
||
| func payloadDisabledParamSet(paths []string) map[string]struct{} { | ||
| if len(paths) == 0 { | ||
| return nil | ||
| } | ||
| out := make(map[string]struct{}, len(paths)) | ||
| for _, path := range paths { | ||
| trimmed := strings.TrimSpace(path) | ||
| if trimmed == "" { | ||
| continue | ||
| } | ||
| out[trimmed] = struct{}{} | ||
| } | ||
| if len(out) == 0 { | ||
| return nil | ||
| } | ||
| return out | ||
| } | ||
|
Comment on lines
+174
to
+190
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
|
||
| func payloadParamDisabled(disabled map[string]struct{}, path string) bool { | ||
| if len(disabled) == 0 { | ||
| return false | ||
| } | ||
| _, ok := disabled[strings.TrimSpace(path)] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| return ok | ||
| } | ||
|
Comment on lines
+192
to
+198
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
|
||
| func payloadModelRulesMatch(rules []config.PayloadModelRule, protocol string, models []string) bool { | ||
| if len(rules) == 0 || len(models) == 0 { | ||
| return false | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
DisabledParamsfield (and the keys inParams) should be sanitized during configuration loading. The currentSanitizePayloadRulesimplementation in this file (around line 713) appears to skip these new fields and the standardDefault/Overriderules. Trimming these strings at load time would eliminate the need for expensivestrings.TrimSpacecalls and map allocations during request processing in the executor.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I addressed the correctness issue in d9d5c4e by teaching
SanitizePayloadRulesto skip validation for disabled raw params. I am intentionally deferring the broader load-time normalization and precomputation optimization for this PR to keep the fix scoped and avoid introducing unrelated behavior changes.