-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feats:independent condition judgement file and interface, add more conditions #1756
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: alpha
Are you sure you want to change the base?
Conversation
…ock,NewAPIInternalPromptToken condition
WalkthroughRefactors param-override to accept full Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Handler as Relay Handler
participant Override as ApplyParamOverride
participant Cond as ConditionChecker
note over Handler,Override: Handler now passes full RelayInfo and receives isBlock flag
Client->>Handler: Request (jsonData, info)
Handler->>Override: ApplyParamOverride(jsonData, info)
Override->>Override: inject NewAPIInternal (prompt tokens)
Override->>Cond: CheckConditions (for ops with Conditions)
Cond-->>Override: condition result / error
Override->>Override: applyOperations (set/move/append/prepend/to/block/pass)
alt block triggered
Override-->>Handler: jsonData, isBlock=true, err
Handler-->>Client: Error channel:condition_trigger_block
else non-block error
Override-->>Handler: jsonData, isBlock=false, err
Handler-->>Client: Error channel:param_override_invalid
else success
Override-->>Handler: jsonData, isBlock=false, nil
Handler-->>Client: Proceed with provider request
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (7)
🚧 Files skipped from review as they are similar to previous changes (2)
🧰 Additional context used🧬 Code graph analysis (5)relay/claude_handler.go (2)
relay/responses_handler.go (2)
relay/gemini_handler.go (2)
relay/compatible_handler.go (2)
relay/image_handler.go (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
relay/gemini_handler.go (1)
231-242
: Unify embeddings override path with ApplyParamOverride and handle block.Embeddings still use the legacy merge; switch to the new flow and return 403 on block.
// apply param override if len(info.ParamOverride) > 0 { - reqMap := make(map[string]interface{}) - _ = common.Unmarshal(jsonData, &reqMap) - for key, value := range info.ParamOverride { - reqMap[key] = value - } - jsonData, err = common.Marshal(reqMap) - if err != nil { - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) - } + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) + if err != nil { + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + } + return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + } }
♻️ Duplicate comments (3)
relay/image_handler.go (2)
72-77
: Return proper 4xx HTTP codes for block/invalid overridesAlign status codes with semantics (Forbidden/Bad Request) instead of default 500.
- return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + return types.NewErrorWithStatusCode(err, types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) ... - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + return types.NewErrorWithStatusCode(err, types.ErrorCodeChannelParamOverrideInvalid, http.StatusBadRequest, types.ErrOptionWithSkipRetry())
70-77
: Also block when isBlock is true and err is nilMirror the defensive check to avoid proceeding on a silent block.
- jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) - if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) - } + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) + if isBlock && err == nil { + return types.NewError(fmt.Errorf("blocked by condition"), types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + } + if err != nil { + if isBlock { + return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + } + return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + }relay/responses_handler.go (1)
62-69
: Guard against isBlock without error; use 4xx codesSame concerns as other handlers: explicitly short-circuit on isBlock even if err is nil; prefer 403/400 for block/invalid override.
- jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) - if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) - } + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) + if isBlock && err == nil { + return types.NewErrorWithStatusCode(fmt.Errorf("blocked by condition"), types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + } + if err != nil { + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + } + return types.NewErrorWithStatusCode(err, types.ErrorCodeChannelParamOverrideInvalid, http.StatusBadRequest, types.ErrOptionWithSkipRetry()) + }
🧹 Nitpick comments (16)
relay/common/condition.go (3)
26-33
: Constrain Mode to known values (enum-like) to prevent config typos.Using a dedicated type or constants reduces runtime errors from misspelled modes and improves IDE help.
Example additions (outside the shown range):
type ConditionMode string const ( ModeFull ConditionMode = "full" ModePrefix ConditionMode = "prefix" ModeSuffix ConditionMode = "suffix" ModeContains ConditionMode = "contains" ModeGT ConditionMode = "gt" ModeGTE ConditionMode = "gte" ModeLT ConditionMode = "lt" ModeLTE ConditionMode = "lte" )Within this struct:
- Mode string `json:"mode"` // full, prefix, suffix, contains, gt, gte, lt, lte + Mode ConditionMode `json:"mode"` // see ConditionMode constantsAnd where used:
// adjust call site compareGjsonValues(value, targetValue, strings.ToLower(string(condition.Mode)))
54-82
: Short-circuit evaluation and validate logic operand.Avoid building a results slice; fail fast and error on unknown logic instead of silently defaulting to OR.
func checkConditions(jsonStr string, conditions []ConditionOperation, logic string) (bool, error) { if len(conditions) == 0 { return true, nil // 没有条件,直接通过 } - results := make([]bool, len(conditions)) - for i, condition := range conditions { - result, err := checkSingleCondition(jsonStr, condition) - if err != nil { - return false, err - } - results[i] = result - } - - if strings.ToUpper(logic) == "AND" { - for _, result := range results { - if !result { - return false, nil - } - } - return true, nil - } else { - for _, result := range results { - if result { - return true, nil - } - } - return false, nil - } + upper := strings.ToUpper(strings.TrimSpace(logic)) + switch upper { + case "AND": + for _, cond := range conditions { + ok, err := checkSingleCondition(jsonStr, cond) + if err != nil { + return false, err + } + if !ok { + return false, nil + } + } + return true, nil + case "OR", "": + for _, cond := range conditions { + ok, err := checkSingleCondition(jsonStr, cond) + if err != nil { + return false, err + } + if ok { + return true, nil + } + } + return false, nil + default: + return false, fmt.Errorf("unsupported logic: %s (expected AND/OR)", logic) + } }
168-190
: Use epsilon for float equality to avoid false negatives.Direct float equality can be brittle; a tiny tolerance is safer.
case gjson.Number: - return jsonValue.Num == targetValue.Num, nil + return math.Abs(jsonValue.Num-targetValue.Num) < 1e-9, nilAdd import (outside this range):
import "math"relay/gemini_handler.go (1)
141-144
: Avoid logging internal token metadata.ApplyParamOverride may inject an internal key; scrub it before logging to prevent leaking internals in logs.
- logger.LogDebug(c, "Gemini request body: "+string(jsonData)) + // redact internal keys before logging + var sanitized map[string]interface{} + if err := common.Unmarshal(jsonData, &sanitized); err == nil { + delete(sanitized, relaycommon.InternalPromptTokensKey) + if b, _ := common.Marshal(sanitized); b != nil { + logger.LogDebug(c, "Gemini request body: "+string(b)) + } else { + logger.LogDebug(c, "Gemini request body: "+string(jsonData)) + } + } else { + logger.LogDebug(c, "Gemini request body: "+string(jsonData)) + }relay/compatible_handler.go (3)
140-145
: Return 4xx instead of default 500 for client/actionable errorsBoth “block by condition” and “invalid param override” are client/actionable states; using NewError defaults to 500. Prefer explicit 4xx to reflect semantics and avoid noisy alerts.
Proposed tweak:
- return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + return types.NewErrorWithStatusCode(err, types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) ... - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + return types.NewErrorWithStatusCode(err, types.ErrorCodeChannelParamOverrideInvalid, http.StatusBadRequest, types.ErrOptionWithSkipRetry())
141-144
: Typo in constant identifier “Contidion”The exported identifier types.ErrorCodeContidionTriggerBlock contains a typo. The string value is correct, but the symbol name is error-prone.
Outside this file, consider in types/error.go:
// Preferred const ErrorCodeConditionTriggerBlock ErrorCode = "channel:condition_trigger_block" // Back-compat alias (deprecate later) const ErrorCodeContidionTriggerBlock = ErrorCodeConditionTriggerBlockThen update call sites gradually.
136-146
: De-duplicate override-and-branch pattern across handlersThe same try-override/branch logic now appears in multiple handlers. A small helper will reduce drift and future bugs.
Example (outside this file):
// relay/common/override_helper.go func ApplyOverrideOrBlock(jsonData []byte, info *relaycommon.RelayInfo) ([]byte, *types.NewAPIError) { if len(info.ParamOverride) == 0 { return jsonData, nil } jd, isBlock, err := relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) if isBlock && err == nil { return nil, types.NewErrorWithStatusCode(fmt.Errorf("blocked by condition"), types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) } if err != nil { if isBlock { return nil, types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) } return nil, types.NewErrorWithStatusCode(err, types.ErrorCodeChannelParamOverrideInvalid, http.StatusBadRequest, types.ErrOptionWithSkipRetry()) } return jd, nil }Then call it from handlers.
relay/claude_handler.go (2)
91-97
: Return a 4xx for condition-triggered blocks (avoid 500).Condition-driven blocks are client/actionable states, not server faults. Set an explicit 403 (or 400) to prevent misclassification and retries.
- if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } + if isBlock { + // 403 Forbidden better communicates condition-based denial + return types.NewErrorWithStatusCode(err, types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + }
91-97
: Fix spelling in error code constant name ("Contidion" → "Condition").The exported identifier has a typo, which propagates across call sites. Rename the constant and update references; the underlying string value can remain unchanged.
-// types/error.go -ErrorCodeContidionTriggerBlock ErrorCode = "channel:condition_trigger_block" +// types/error.go +ErrorCodeConditionTriggerBlock ErrorCode = "channel:condition_trigger_block"- return types.NewErrorWithStatusCode(err, types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry())relay/rerank_handler.go (2)
62-67
: Surface a 4xx for condition-blocks and keep retries skipped.Mirror the Claude handler suggestion: send 403 (or 400) instead of falling back to default 500 semantics.
- if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + }
62-67
: Align with corrected constant name if you accept the rename.- return types.NewErrorWithStatusCode(err, types.ErrorCodeContidionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry())relay/common/override.go (5)
10-10
: Internal key: consider a harder-to-collide name and document non-contract status.To minimize accidental collisions with user fields, consider a more obviously reserved key (e.g., "__newapi_internal_prompt_tokens"). At minimum, add a comment stating it’s an internal, non-stable key.
-const InternalPromptTokensKey = "NewAPIInternalPromptTokens" +// Internal implementation detail; not a public/contracted field. +const InternalPromptTokensKey = "NewAPIInternalPromptTokens"
150-159
: Clarify pass semantics (short-circuit) with a comment.It currently returns immediately after deleting the internal key. Add a note so users don’t expect subsequent ops to run.
- if op.Mode == "pass" { + if op.Mode == "pass" { + // Short-circuit: conditions satisfied → bypass remaining operations. // 移除添加的内部字段 result, _ = sjson.Delete(result, InternalPromptTokensKey) return result, false, nil // 直接通过 }
166-186
: Improve error context to aid troubleshooting.Include normalized paths in error messages.
- default: - return "", false, fmt.Errorf("unknown operation: %s", op.Mode) + default: + return "", false, fmt.Errorf("unknown operation %q at path=%q from=%q to=%q", op.Mode, opPath, opFrom, opTo) } if err != nil { - return "", false, fmt.Errorf("operation %s failed: %v", op.Mode, err) + return "", false, fmt.Errorf("operation %s failed at path=%q from=%q to=%q: %v", op.Mode, opPath, opFrom, opTo, err) }
132-191
: Add basic counters for observability (blocks/passes).Expose metrics for block/pass events to ease debugging and alerting.
- Track: condition_trigger_block_total, condition_trigger_pass_total
- Labels: channel, model, operation, condition_logic
23-26
: ApplyParamOverride signature update verified across all call sites
- All handlers now pass
info.PromptTokens
and unpack the three‐value return (jsonData, isBlock, err
).- Block error constant
ErrorCodeContidionTriggerBlock
is consistently referenced but its name contains a typo—rename it toErrorCodeConditionTriggerBlock
in types/error.go and update all usages.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (9)
relay/claude_handler.go
(1 hunks)relay/common/condition.go
(1 hunks)relay/common/override.go
(3 hunks)relay/compatible_handler.go
(1 hunks)relay/gemini_handler.go
(1 hunks)relay/image_handler.go
(1 hunks)relay/rerank_handler.go
(1 hunks)relay/responses_handler.go
(1 hunks)types/error.go
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
relay/claude_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(23-38)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/gemini_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(23-38)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/image_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(23-38)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/rerank_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(23-38)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/responses_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(23-38)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/compatible_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(23-38)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/common/override.go (1)
relay/common/condition.go (1)
CheckConditions
(35-38)
🔇 Additional comments (4)
relay/common/condition.go (1)
84-111
: Core evaluation flow looks solid.Handling of missing keys with PassMissingKey and post-compare inversion is clear.
relay/compatible_handler.go (1)
138-145
: Remove redundant block-without-error check applyOperations’s “block” path always returns a non-nil error alongside isBlock=true, so there is no scenario where isBlock==true and err==nil.Likely an incorrect or invalid review comment.
relay/common/override.go (2)
35-38
: Backward-compatibility fallback looks good.Legacy map-based overrides continue to work and return isBlock=false, preserving prior behavior.
188-191
: Cleanup after operations is correct.The internal token field is removed at the end of normal processing.
func processNegativeIndex(jsonStr string, path string) string { | ||
re := regexp.MustCompile(`\.(-\d+)`) | ||
matches := re.FindAllStringSubmatch(path, -1) | ||
|
||
if len(matches) == 0 { | ||
return path | ||
} | ||
|
||
result := path | ||
for _, match := range matches { | ||
negIndex := match[1] | ||
index, _ := strconv.Atoi(negIndex) | ||
|
||
arrayPath := strings.Split(path, negIndex)[0] | ||
if strings.HasSuffix(arrayPath, ".") { | ||
arrayPath = arrayPath[:len(arrayPath)-1] | ||
} | ||
|
||
array := gjson.Get(jsonStr, arrayPath) | ||
if array.IsArray() { | ||
length := len(array.Array()) | ||
actualIndex := length + index | ||
if actualIndex >= 0 && actualIndex < length { | ||
result = strings.Replace(result, match[0], "."+strconv.Itoa(actualIndex), 1) | ||
} | ||
} | ||
} | ||
|
||
return result | ||
} |
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.
Incorrect array path resolution for multiple negative indices (nested arrays).
arrayPath is derived from the original path for every match, so the second/next negative index may compute length from the wrong array. This mis-evaluates paths like a.-1.b.-1.
Apply a left-to-right replacement that recalculates arrayPath against the progressively updated path:
func processNegativeIndex(jsonStr string, path string) string {
- re := regexp.MustCompile(`\.(-\d+)`)
- matches := re.FindAllStringSubmatch(path, -1)
-
- if len(matches) == 0 {
- return path
- }
-
- result := path
- for _, match := range matches {
- negIndex := match[1]
- index, _ := strconv.Atoi(negIndex)
-
- arrayPath := strings.Split(path, negIndex)[0]
- if strings.HasSuffix(arrayPath, ".") {
- arrayPath = arrayPath[:len(arrayPath)-1]
- }
-
- array := gjson.Get(jsonStr, arrayPath)
- if array.IsArray() {
- length := len(array.Array())
- actualIndex := length + index
- if actualIndex >= 0 && actualIndex < length {
- result = strings.Replace(result, match[0], "."+strconv.Itoa(actualIndex), 1)
- }
- }
- }
-
- return result
+ re := regexp.MustCompile(`\.(-\d+)`)
+ result := path
+ for {
+ loc := re.FindStringSubmatchIndex(result)
+ if loc == nil {
+ break
+ }
+ negIndex := result[loc[2]:loc[3]] // e.g. "-1"
+ idx, _ := strconv.Atoi(negIndex) // negative
+
+ arrayPath := result[:loc[0]]
+ if strings.HasSuffix(arrayPath, ".") {
+ arrayPath = arrayPath[:len(arrayPath)-1]
+ }
+ arr := gjson.Get(jsonStr, arrayPath)
+ if !arr.IsArray() {
+ // Not an array; stop to avoid infinite loop and let lookup fail naturally.
+ break
+ }
+ length := len(arr.Array())
+ actualIndex := length + idx
+ if actualIndex < 0 || actualIndex >= length {
+ // Out of range; leave as-is so gjson returns missing.
+ break
+ }
+ replacement := "." + strconv.Itoa(actualIndex)
+ // Replace this occurrence and continue scanning the updated path.
+ result = result[:loc[0]] + replacement + result[loc[1]:]
+ }
+ return result
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func processNegativeIndex(jsonStr string, path string) string { | |
re := regexp.MustCompile(`\.(-\d+)`) | |
matches := re.FindAllStringSubmatch(path, -1) | |
if len(matches) == 0 { | |
return path | |
} | |
result := path | |
for _, match := range matches { | |
negIndex := match[1] | |
index, _ := strconv.Atoi(negIndex) | |
arrayPath := strings.Split(path, negIndex)[0] | |
if strings.HasSuffix(arrayPath, ".") { | |
arrayPath = arrayPath[:len(arrayPath)-1] | |
} | |
array := gjson.Get(jsonStr, arrayPath) | |
if array.IsArray() { | |
length := len(array.Array()) | |
actualIndex := length + index | |
if actualIndex >= 0 && actualIndex < length { | |
result = strings.Replace(result, match[0], "."+strconv.Itoa(actualIndex), 1) | |
} | |
} | |
} | |
return result | |
} | |
func processNegativeIndex(jsonStr string, path string) string { | |
re := regexp.MustCompile(`\.(-\d+)`) | |
result := path | |
for { | |
loc := re.FindStringSubmatchIndex(result) | |
if loc == nil { | |
break | |
} | |
negIndex := result[loc[2]:loc[3]] // e.g. "-1" | |
idx, _ := strconv.Atoi(negIndex) // negative | |
arrayPath := result[:loc[0]] | |
if strings.HasSuffix(arrayPath, ".") { | |
arrayPath = arrayPath[:len(arrayPath)-1] | |
} | |
arr := gjson.Get(jsonStr, arrayPath) | |
if !arr.IsArray() { | |
// Not an array; stop to avoid infinite loop and let lookup fail naturally. | |
break | |
} | |
length := len(arr.Array()) | |
actualIndex := length + idx | |
if actualIndex < 0 || actualIndex >= length { | |
// Out of range; leave as-is so gjson returns missing. | |
break | |
} | |
replacement := "." + strconv.Itoa(actualIndex) | |
// Replace this occurrence and continue scanning the updated path. | |
result = result[:loc[0]] + replacement + result[loc[1]:] | |
} | |
return result | |
} |
🤖 Prompt for AI Agents
In relay/common/condition.go around lines 113 to 142, the function
processNegativeIndex computes arrayPath from the original path for every
negative-index match which breaks nested/multiple negative indices (e.g.,
a.-1.b.-1); change the loop to perform left-to-right replacements by deriving
arrayPath from the progressively updated result (use strings.Split(result,
negIndex)[0] instead of strings.Split(path, negIndex)[0]), update result
immediately after a successful replacement, and continue using the updated
result for subsequent matches (keeping the existing dot-trim and bounds checks).
relay/common/override.go
Outdated
func applyOperations(jsonStr string, operations []ParamOperation, promptTokens int) (string, bool, error) { | ||
// 添加PromptTokens到JSON中以便条件判断,强制覆盖 | ||
jsonStrWithTokens, err := sjson.Set(jsonStr, InternalPromptTokensKey, promptTokens) | ||
if err != nil { | ||
return "", false, fmt.Errorf("failed to add %s: %v", InternalPromptTokensKey, err) | ||
} | ||
|
||
result := jsonStrWithTokens | ||
for _, op := range operations { | ||
// 检查条件是否满足 | ||
ok, err := checkConditions(result, op.Conditions, op.Logic) | ||
ok, err := CheckConditions(result, op.Conditions, op.Logic) | ||
if err != nil { | ||
return "", err | ||
return "", false, err | ||
} | ||
if !ok { | ||
continue // 条件不满足,跳过当前操作 | ||
} | ||
|
||
// 处理block和pass操作 | ||
if op.Mode == "block" { | ||
blockMessage := fmt.Sprintf("request blocked by conditions: %+v", op.Conditions) | ||
return result, true, fmt.Errorf(blockMessage) | ||
} | ||
if op.Mode == "pass" { | ||
// 移除添加的内部字段 | ||
result, _ = sjson.Delete(result, InternalPromptTokensKey) | ||
return result, false, nil // 直接通过 | ||
} |
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.
🛠️ Refactor suggestion
Ensure internal token field is removed on the block path to prevent leaks.
If a future caller inspects the returned JSON on error, the internal field could leak. Delete it before returning on block.
- if op.Mode == "block" {
- blockMessage := fmt.Sprintf("request blocked by conditions: %+v", op.Conditions)
- return result, true, fmt.Errorf(blockMessage)
- }
+ if op.Mode == "block" {
+ blockMessage := fmt.Sprintf("request blocked by conditions: %+v", op.Conditions)
+ cleaned, _ := sjson.Delete(result, InternalPromptTokensKey)
+ return cleaned, true, fmt.Errorf(blockMessage)
+ }
🤖 Prompt for AI Agents
In relay/common/override.go around lines 132 to 159, the block path returns the
JSON containing the internal prompt-tokens field which may leak sensitive
internals to callers on error; before returning on op.Mode == "block" delete the
InternalPromptTokensKey from result (use sjson.Delete or equivalent), handle any
deletion error if needed, and then return the cleaned result with the same block
error and boolean flag so the internal field is not exposed.
var isBlock bool | ||
jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) | ||
if err != nil { | ||
if isBlock { | ||
return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) | ||
} | ||
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) |
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.
💡 Verification agent
🧩 Analysis chain
Return 403 and fix constant name when a block condition triggers.
Currently this returns a generic 500 via NewError and uses a misspelled constant. Treat blocks as a client/policy error.
- var isBlock bool
- jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens)
+ var isBlock bool
+ jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens)
if err != nil {
- if isBlock {
- return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry())
- }
+ if isBlock {
+ return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry())
+ }
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
}
🏁 Script executed:
#!/bin/bash
# Verify all handlers use the corrected constant and set explicit status codes for block responses.
rg -nP 'ErrorCodeContidionTriggerBlock|ErrorCodeConditionTriggerBlock' -C2
rg -nP 'NewError\([^)]*ConditionTriggerBlock' -C2
rg -nP 'NewErrorWithStatusCode\([^)]*ConditionTriggerBlock' -C2
Length of output: 3075
Fix block condition error constant and return 403 status
- Rename in types/error.go:
- ErrorCodeContidionTriggerBlock ErrorCode = "channel:condition_trigger_block" + ErrorCodeConditionTriggerBlock ErrorCode = "channel:condition_trigger_block"
- In each handler (relay/gemini_handler.go, responses_handler.go, rerank_handler.go, image_handler.go, compatible_handler.go, claude_handler.go), replace:
- if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + }
- Add
import "net/http"
to handlers that use NewErrorWithStatusCode.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
var isBlock bool | |
jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) | |
if err != nil { | |
if isBlock { | |
return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) | |
} | |
return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) | |
// In relay/gemini_handler.go, add to your import block: | |
import ( | |
// ... other imports ... | |
"net/http" | |
) | |
// … | |
var isBlock bool | |
jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, info.PromptTokens) | |
if err != nil { | |
if isBlock { | |
return types.NewErrorWithStatusCode( | |
err, | |
types.ErrorCodeConditionTriggerBlock, | |
http.StatusForbidden, | |
types.ErrOptionWithSkipRetry(), | |
) | |
} | |
return types.NewError( | |
err, | |
types.ErrorCodeChannelParamOverrideInvalid, | |
types.ErrOptionWithSkipRetry(), | |
) | |
} |
🤖 Prompt for AI Agents
In relay/gemini_handler.go around lines 131 to 137, the code uses the misspelled
constant ErrorCodeContidionTriggerBlock and returns a generic NewError; rename
the constant to ErrorCodeConditionTriggerBlock and change the error return to
use types.NewErrorWithStatusCode(..., types.ErrorCodeConditionTriggerBlock,
http.StatusForbidden, types.ErrOptionWithSkipRetry()), and add import "net/http"
at the top of the file.
// channel error | ||
ErrorCodeChannelNoAvailableKey ErrorCode = "channel:no_available_key" | ||
ErrorCodeChannelParamOverrideInvalid ErrorCode = "channel:param_override_invalid" | ||
ErrorCodeContidionTriggerBlock ErrorCode = "channel:condition_trigger_block" |
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.
💡 Verification agent
🧩 Analysis chain
Fix typo in new error code constant (Condition).
Rename the exported identifier to avoid propagating a misspelling across the codebase and SDKs.
- ErrorCodeContidionTriggerBlock ErrorCode = "channel:condition_trigger_block"
+ ErrorCodeConditionTriggerBlock ErrorCode = "channel:condition_trigger_block"
Run to locate/update all call sites:
🏁 Script executed:
#!/bin/bash
rg -nP 'ErrorCodeContidionTriggerBlock|condition_trigger_block' -C2
Length of output: 2950
Rename ErrorCodeContidionTriggerBlock
to ErrorCodeConditionTriggerBlock
across the codebase
--- types/error.go
@@ 53
- ErrorCodeContidionTriggerBlock ErrorCode = "channel:condition_trigger_block"
+ ErrorCodeConditionTriggerBlock ErrorCode = "channel:condition_trigger_block"
Update every usage of the misspelled constant in these files (and any others):
- relay/responses_handler.go
- relay/rerank_handler.go
- relay/image_handler.go
- relay/gemini_handler.go
- relay/claude_handler.go
- relay/compatible_handler.go
Replace ErrorCodeContidionTriggerBlock
with ErrorCodeConditionTriggerBlock
, then rerun tests and regenerate any affected SDKs.
🤖 Prompt for AI Agents
In types/error.go around line 53, the constant name is misspelled as
ErrorCodeContidionTriggerBlock; rename it to ErrorCodeConditionTriggerBlock and
update every import-site usage across the codebase (specifically
relay/responses_handler.go, relay/rerank_handler.go, relay/image_handler.go,
relay/gemini_handler.go, relay/claude_handler.go, relay/compatible_handler.go)
to the new identifier, run the test suite to catch any remaining references, and
regenerate any affected SDKs or generated artifacts so symbols stay in sync.
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.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
relay/common/override.go (1)
150-153
: Add tests for negative-index handling
processNegativeIndex is implemented in relay/common/condition.go (line 113) but isn’t covered by any tests. Add unit tests validating that op.Path, op.From and op.To correctly handle negative indices.
♻️ Duplicate comments (1)
relay/common/override.go (1)
154-158
: Fix: internal tokens leak on block path; delete before returning.
Block currently returns result with NewAPIInternalPromptTokens. Clean it first to avoid leaking internals in error surfaces.- if op.Mode == "block" { - blockMessage := fmt.Sprintf("request blocked by conditions: %+v", op.Conditions) - return result, true, fmt.Errorf(blockMessage) - } + if op.Mode == "block" { + blockMessage := fmt.Sprintf("request blocked by conditions: %+v", op.Conditions) + cleaned, _ := sjson.Delete(result, InternalPromptTokensKey) + return cleaned, true, fmt.Errorf(blockMessage) + }
🧹 Nitpick comments (4)
relay/common/override.go (4)
14-14
: Define mode string constants to prevent typos across call sites.
Consider centralizing allowed modes (delete, set, move, prepend, append, block, pass) as string consts to avoid stringly-typed bugs.// Example (place near InternalPromptTokensKey) const ( ModeDelete = "delete" ModeSet = "set" ModeMove = "move" ModePrepend = "prepend" ModeAppend = "append" ModeBlock = "block" ModePass = "pass" )
23-23
: Nit: local parameter should be lowerCamelCase.
Rename PromptTokens -> promptTokens to follow Go naming conventions for locals.-func ApplyParamOverride(jsonData []byte, paramOverride map[string]interface{}, PromptTokens int) ([]byte, bool, error) { +func ApplyParamOverride(jsonData []byte, paramOverride map[string]interface{}, promptTokens int) ([]byte, bool, error) { - result, isBlock, err := applyOperations(string(jsonData), operations, PromptTokens) + result, isBlock, err := applyOperations(string(jsonData), operations, promptTokens)
156-156
: Optional: avoid exposing policy details in public error text.
Consider a generic message (e.g., "request blocked by policy") and log details server-side to reduce information disclosure.- blockMessage := fmt.Sprintf("request blocked by conditions: %+v", op.Conditions) + blockMessage := "request blocked by policy"
192-195
: Nit: handle cleanup error or consistently ignore with a comment.
Currently ignoring sjson.Delete error. Either document intent or handle it to avoid silent failures.- result, _ = sjson.Delete(result, InternalPromptTokensKey) + // Best-effort cleanup; ignore error by design because token is internal-only. + result, _ = sjson.Delete(result, InternalPromptTokensKey)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
relay/common/override.go
(5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
relay/common/override.go (1)
relay/common/condition.go (1)
CheckConditions
(35-38)
🔇 Additional comments (3)
relay/common/override.go (3)
10-10
: LGTM: internal-prompt-tokens key introduction makes sense.
No issues with the exported const; aligns with later usage.
132-137
: LGTM: safe token injection with error handling.
The internal token field is injected upfront with proper error propagation.
23-33
: No action needed: all ApplyParamOverride call sites now pass three arguments and handle isBlock.
…feats-add-more-conditions # Conflicts: # relay/common/override.go
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.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
relay/gemini_handler.go (1)
231-242
: Embedding handler bypasses new conditional block logicThis manual override merge skips ApplyParamOverride, so pass/block conditions won’t run here. Align with other handlers and enforce policy.
- // apply param override - if len(info.ParamOverride) > 0 { - reqMap := make(map[string]interface{}) - _ = common.Unmarshal(jsonData, &reqMap) - for key, value := range info.ParamOverride { - reqMap[key] = value - } - jsonData, err = common.Marshal(reqMap) - if err != nil { - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) - } - } + // apply param override (supports pass/block conditions) + if len(info.ParamOverride) > 0 { + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) + if err != nil { + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + } + return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + } + }relay/responses_handler.go (1)
44-50
: Honor channel-level PassThroughBodyEnabledOther handlers respect both global and channel settings. This endpoint ignores the channel flag, which can break per-channel pass-through.
- if model_setting.GetGlobalSettings().PassThroughRequestEnabled { + if model_setting.GetGlobalSettings().PassThroughRequestEnabled || info.ChannelSetting.PassThroughBodyEnabled {
♻️ Duplicate comments (4)
relay/gemini_handler.go (1)
131-137
: Return 403 and fix misspelled error code for block conditionUse the correct constant and return a 403 to signal a policy/block condition instead of a 500.
- var isBlock bool - jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + } return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) }relay/compatible_handler.go (1)
138-145
: Use 403 and the corrected error code when a block condition triggersMatch the contract used elsewhere: explicit 403 + ErrorCodeConditionTriggerBlock.
- var isBlock bool - jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + } return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) }relay/claude_handler.go (1)
91-98
: Fix constant name and return 403 for block conditionAlign with the new condition system and correct the typo.
- var isBlock bool - jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } + if isBlock { + return types.NewErrorWithStatusCode(err, types.ErrorCodeConditionTriggerBlock, http.StatusForbidden, types.ErrOptionWithSkipRetry()) + } return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) }relay/common/override.go (1)
153-160
: Prevent internal-field leak on block pathRemove NewAPIInternal before returning on block to avoid accidental exposure if callers inspect the returned JSON on error.
- if op.Mode == "block" { - blockMessage := "request blocked by param override conditions" - return result, true, fmt.Errorf(blockMessage) - } + if op.Mode == "block" { + blockMessage := "request blocked by param override conditions" + cleaned, _ := sjson.Delete(result, InternalPromptTokensKey) + return cleaned, true, fmt.Errorf(blockMessage) + }
🧹 Nitpick comments (11)
relay/compatible_handler.go (1)
140-145
: Optional: Param-override invalid should be a 400, not a 500Consider signaling client error explicitly for malformed overrides.
- return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + return types.NewErrorWithStatusCode(err, types.ErrorCodeChannelParamOverrideInvalid, http.StatusBadRequest, types.ErrOptionWithSkipRetry())relay/image_handler.go (3)
55-57
: Mark ConvertImageRequest errors as non-retryableThese are deterministic request-shape errors; align with other sites that use ErrOptionWithSkipRetry.
- return types.NewError(err, types.ErrorCodeConvertRequestFailed) + return types.NewError(err, types.ErrorCodeConvertRequestFailed, types.ErrOptionWithSkipRetry())
68-78
: Unnecessary guard before ApplyParamOverrideApplyParamOverride already no-ops when ParamOverride is empty. Simplify and reduce branching.
- // apply param override - if len(info.ParamOverride) > 0 { - var isBlock bool - jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) - if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) - } - } + // apply param override (no-op when ParamOverride is empty) + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) + if err != nil { + if isBlock { + return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + } + return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + }
73-75
: Typo in error code identifier nameIdentifier “ErrorCodeContidionTriggerBlock” has a typo. Consider renaming to ErrorCodeConditionTriggerBlock for clarity (string value can remain unchanged). Verify downstream references before renaming.
- return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + return types.NewError(err, types.ErrorCodeConditionTriggerBlock, types.ErrOptionWithSkipRetry())relay/rerank_handler.go (3)
28-30
: Fix copy error message typeMessage says ImageRequest but operation is for RerankRequest.
- return types.NewError(fmt.Errorf("failed to copy request to ImageRequest: %w", err), types.ErrorCodeInvalidRequest, types.ErrOptionWithSkipRetry()) + return types.NewError(fmt.Errorf("failed to copy request to RerankRequest: %w", err), types.ErrorCodeInvalidRequest, types.ErrOptionWithSkipRetry())
72-74
: Use structured debug logging instead of printlnFor consistency with other handlers and to include request context.
- println(fmt.Sprintf("Rerank request body: %s", string(jsonData))) + logger.LogDebug(c, fmt.Sprintf("Rerank request body: %s", string(jsonData)))Add missing import:
import ( "bytes" "fmt" "io" "net/http" "one-api/common" "one-api/dto" relaycommon "one-api/relay/common" "one-api/relay/helper" + "one-api/logger" "one-api/service" "one-api/setting/model_setting" "one-api/types"
61-69
: Unnecessary guard before ApplyParamOverrideSame simplification as other handlers.
- // apply param override - if len(info.ParamOverride) > 0 { - var isBlock bool - jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) - if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) - } - } + // apply param override (no-op when ParamOverride is empty) + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) + if err != nil { + if isBlock { + return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + } + return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + }relay/responses_handler.go (2)
72-75
: Use structured debug logging instead of printlnAlign with logger usage elsewhere and include context.
- println("requestBody: ", string(jsonData)) + logger.LogDebug(c, fmt.Sprintf("responses request body: %s", string(jsonData)))Add missing import:
import ( "bytes" "fmt" "io" "net/http" "one-api/common" "one-api/dto" relaycommon "one-api/relay/common" "one-api/relay/helper" + "one-api/logger" "one-api/service" "one-api/setting/model_setting" "one-api/types" "strings"
61-69
: Unnecessary guard before ApplyParamOverrideSame rationale: ApplyParamOverride no-ops if empty.
- if len(info.ParamOverride) > 0 { - var isBlock bool - jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) - if err != nil { - if isBlock { - return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) - } - return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) - } - } + var isBlock bool + jsonData, isBlock, err = relaycommon.ApplyParamOverride(jsonData, info) + if err != nil { + if isBlock { + return types.NewError(err, types.ErrorCodeContidionTriggerBlock, types.ErrOptionWithSkipRetry()) + } + return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry()) + }relay/common/override.go (2)
27-43
: Minor: rename param to idiomatic lowerCamelGo style prefers relayInfo over Relayinfo; improves readability.
-func ApplyParamOverride(jsonData []byte, Relayinfo *RelayInfo) ([]byte, bool, error) { - if len(Relayinfo.ParamOverride) == 0 { +func ApplyParamOverride(jsonData []byte, relayInfo *RelayInfo) ([]byte, bool, error) { + if len(relayInfo.ParamOverride) == 0 { return jsonData, false, nil } - if operations, ok := tryParseOperations(Relayinfo.ParamOverride); ok { - info := &NewAPIInternal{PromptTokens: Relayinfo.PromptTokens} + if operations, ok := tryParseOperations(relayInfo.ParamOverride); ok { + info := &NewAPIInternal{PromptTokens: relayInfo.PromptTokens} result, isBlock, err := applyOperations(string(jsonData), operations, info) return []byte(result), isBlock, err } - result, err := applyOperationsLegacy(jsonData, Relayinfo.ParamOverride) + result, err := applyOperationsLegacy(jsonData, relayInfo.ParamOverride) return result, false, err }
45-121
: Stricter parsing when 'operations' key existsIf 'operations' exists but is malformed, silently falling back to legacy may apply unintended overrides. Consider returning an explicit error instead of fallback in this case.
Example approach:
- tryParseOperations returns (ops, ok, parseErr)
- If operations key present and parseErr != nil, propagate error; only fallback when key is absent.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
relay/claude_handler.go
(1 hunks)relay/common/override.go
(4 hunks)relay/compatible_handler.go
(1 hunks)relay/gemini_handler.go
(1 hunks)relay/image_handler.go
(1 hunks)relay/rerank_handler.go
(1 hunks)relay/responses_handler.go
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
relay/image_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(27-43)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/gemini_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(27-43)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/rerank_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(27-43)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/compatible_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(27-43)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/common/override.go (2)
relay/common/relay_info.go (1)
RelayInfo
(74-120)relay/common/condition.go (1)
CheckConditions
(35-38)
relay/claude_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(27-43)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
relay/responses_handler.go (2)
relay/common/override.go (1)
ApplyParamOverride
(27-43)types/error.go (3)
NewError
(188-200)ErrorCodeContidionTriggerBlock
(53-53)ErrOptionWithSkipRetry
(297-301)
🔇 Additional comments (2)
relay/common/override.go (2)
10-14
: Token injection shape looks goodConstant and struct for internal prompt-tokens are clear and scoped.
162-165
: processNegativeIndex is already defined in relay/common/condition.go; no action required.Likely an incorrect or invalid review comment.
这个改动向下兼容吗 |
independent condition judgement file and interface, add pass,block,NewAPIInternalPromptToken condition.
It is used for the separate models priority for the future (:
Summary by CodeRabbit
New Features
Bug Fixes