Skip to content

feats: the flexable params override and compatible format - #1603

Merged
Calcium-Ion merged 2 commits into
QuantumNous:alphafrom
nekohy:feats-the-flexable-params-override
Aug 16, 2025
Merged

feats: the flexable params override and compatible format#1603
Calcium-Ion merged 2 commits into
QuantumNous:alphafrom
nekohy:feats-the-flexable-params-override

Conversation

@nekohy

@nekohy nekohy commented Aug 16, 2025

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added an advanced, condition-aware parameter override format (set, delete, move, prepend, append) with AND/OR conditions; legacy format remains supported.
    • Centralized override application so all request types use the same override engine.
  • UI

    • Edit Channel modal now shows clearer placeholder guidance and one-click templates for both old and new override formats.
  • Chores

    • Added JSON parsing/manipulation dependencies to support the new override engine.

@coderabbitai

coderabbitai Bot commented Aug 16, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Centralizes JSON parameter-override handling by adding a new operations-capable override engine and ApplyParamOverride, updates multiple relay handlers to call it, adds Tidwall JSON libs to go.mod, and updates the web UI to document and insert both legacy and new override formats.

Changes

Cohort / File(s) Summary of Changes
Dependencies
go.mod
Added direct deps: github.com/tidwall/gjson v1.18.0, github.com/tidwall/sjson v1.2.5; added indirect deps: github.com/tidwall/match v1.1.1 and github.com/tidwall/pretty v1.2.0.
Override engine
relay/common/override.go
New file: introduces ApplyParamOverride(jsonData []byte, paramOverride map[string]interface{}) ([]byte, error), types ParamOperation and ConditionOperation, operations (set/delete/move/prepend/append), condition evaluation (AND/OR), operation application, and a legacy shallow-merge fallback. Uses gjson/sjson.
Relay handlers (delegation)
relay/claude_handler.go, relay/gemini_handler.go, relay/image_handler.go, relay/relay-text.go, relay/rerank_handler.go, relay/responses_handler.go
Replaced inline manual JSON-unmarshal/merge/remarshal override logic with calls to relaycommon.ApplyParamOverride; preserved existing control flow and existing error handling (ChannelParamOverrideInvalid).
Web UI (templates & placeholder)
web/src/components/table/channels/modals/EditChannelModal.jsx
Expanded param_override placeholder to document legacy and new operations-based formats; added two quick-fill template options for the old and new formats; no behavior changes to onChange/autosize.

Sequence Diagram(s)

sequenceDiagram
  participant Handler
  participant OverrideEngine as relaycommon.ApplyParamOverride
  participant Parser as Operations Parser
  participant Legacy as Legacy Merge

  Handler->>OverrideEngine: ApplyParamOverride(jsonData, paramOverride)
  alt paramOverride empty
    OverrideEngine-->>Handler: original jsonData
  else paramOverride has "operations"
    OverrideEngine->>Parser: tryParseOperations(paramOverride)
    alt parse ok
      Parser-->>OverrideEngine: []ParamOperation
      OverrideEngine->>OverrideEngine: applyOperations sequentially (conditions checked)
      alt apply ok
        OverrideEngine-->>Handler: updated jsonData
      else apply error
        OverrideEngine-->>Handler: error
      end
    else parse fail
      OverrideEngine->>Legacy: applyOperationsLegacy(jsonData, paramOverride)
      Legacy-->>OverrideEngine: merged jsonData or error
      OverrideEngine-->>Handler: result
    end
  else no "operations"
    OverrideEngine->>Legacy: applyOperationsLegacy(jsonData, paramOverride)
    Legacy-->>OverrideEngine: merged jsonData or error
    OverrideEngine-->>Handler: result
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

I hop through JSON with whiskers keen,
Set, move, append — or wipe a scene.
Conditions checked, or fall back kind,
Tidwall tools and carrots help me find.
A rabbit’s tweak — small, neat, and clean. 🥕

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent 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.

📥 Commits

Reviewing files that changed from the base of the PR and between dd497d5 and b591b4e.

📒 Files selected for processing (1)
  • relay/common/override.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • relay/common/override.go
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (7)
web/src/components/table/channels/modals/EditChannelModal.jsx (1)

1656-1700: Add client-side JSON validation for param_override and block stream overrides

Good UX addition. To reduce backend round-trips and align with “不支持覆盖 stream 参数”, add a validator that:

  • Ensures param_override is valid JSON when provided.
  • Blocks top-level "stream" overrides and operations targeting path "stream".

Apply this diff within this TextArea to add a custom validation rule:

                   <Form.TextArea
                       field='param_override'
                       label={t('参数覆盖')}
                       placeholder={
                           t('此项可选,用于覆盖请求参数。不支持覆盖 stream 参数') +
                           '\n' + t('旧格式(直接覆盖):') +
                           '\n{\n  "temperature": 0,\n  "max_tokens": 1000\n}' +
                           '\n\n' + t('新格式(支持条件判断与json自定义):') +
                           '\n{\n  "operations": [\n    {\n      "path": "temperature",\n      "mode": "set",\n      "value": 0.7,\n      "conditions": [\n        {\n          "path": "model",\n          "mode": "prefix",\n          "value": "gpt"\n        }\n      ]\n    }\n  ]\n}'
                       }
+                      rules={[
+                        {
+                          validator: (_, value) => {
+                            if (!value || `${value}`.trim() === '') return true;
+                            if (!verifyJSON(value)) return t('参数覆盖必须是合法的 JSON 格式');
+                            try {
+                              const obj = JSON.parse(value);
+                              if (obj && typeof obj === 'object') {
+                                // Block old-format "stream"
+                                if (Object.prototype.hasOwnProperty.call(obj, 'stream')) {
+                                  return t('不支持覆盖 stream 参数');
+                                }
+                                // Block new-format operations that target "stream"
+                                if (Array.isArray(obj.operations)) {
+                                  const violates = obj.operations.some(op => typeof op?.path === 'string' && op.path.trim() === 'stream');
+                                  if (violates) return t('不支持覆盖 stream 参数');
+                                }
+                              }
+                            } catch {}
+                            return true;
+                          }
+                        }
+                      ]}
                       autosize
                       onChange={(value) => handleInputChange('param_override', value)}
                       extraText={
relay/claude_handler.go (1)

86-86: Centralized override application: ensure disallowing 'stream' and add tests

The switch to relaycommon.ApplyParamOverride improves consistency and maintainability. Please verify that:

  • The override engine rejects attempts to change stream, matching the UI guidance.
  • Both legacy and operations formats are covered by tests in this handler path.

If helpful, I can draft unit tests that:

  • Assert legacy { "temperature": 0 } merges.
  • Assert operations-based set/delete/prepend/append with AND/OR conditions.
  • Assert attempts to set "stream" are rejected.
relay/rerank_handler.go (1)

65-65: Good consolidation; confirm parity and stream-protection

Using ApplyParamOverride here aligns the rerank path with other handlers. Please confirm:

  • Behavior parity with previous override semantics (legacy path) for flat keys.
  • Engine-level guard blocks any override of "stream".
  • Add a test that covers both formats for the rerank request structure.

Happy to help author a focused test that feeds representative rerank payloads through ApplyParamOverride and validates the final JSON.

relay/common/override.go (4)

232-242: Prepend/append to non-existent path currently errors

modifyValue returns an error if the path does not exist (type is Null). Many users expect prepend/append to create the field when missing (e.g., set string to value or initialize an array). Consider handling the non-existent case by creating the field based on the type of value.

One approach:

 func modifyValue(jsonStr, path string, value interface{}, keepOrigin, isPrepend bool) (string, error) {
 	current := gjson.Get(jsonStr, path)
+	if !current.Exists() {
+		// Initialize field if missing
+		switch v := value.(type) {
+		case []interface{}:
+			return sjson.Set(jsonStr, path, v)
+		case map[string]interface{}:
+			return sjson.Set(jsonStr, path, v)
+		default:
+			return sjson.Set(jsonStr, path, fmt.Sprintf("%v", v))
+		}
+	}
 	switch {
 		// ...
 	}
 }

58-66: Validate required fields per operation type

tryParseOperations does not enforce that Path is present for set/delete/prepend/append, or that From/To are present for move. These will fall through to runtime errors in applyOperations and, before the previous comment’s fix, could trigger an unsafe legacy fallback. Prefer early validation with a clear error.


168-181: Legacy merge should ignore “operations” key (defensive)

Even with the stricter ApplyParamOverride change, consider excluding the reserved "operations" key from the legacy merge to avoid accidental leakage if applyOperationsLegacy is reused elsewhere.

Example tweak:

 for key, value := range paramOverride {
-	reqMap[key] = value
+	if key != "operations" {
+		reqMap[key] = value
+	}
 }

145-166: Condition matching is string-only; document or extend

checkSingleCondition coerces values to strings and supports full/prefix/suffix/contains. If numeric/boolean matches are expected, extend modes or document the string-only behavior to avoid confusion.

I can add unit tests covering AND/OR logic, number/boolean comparisons, and array/object targets if helpful.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between f6a4843 and dd497d5.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (9)
  • go.mod (2 hunks)
  • relay/claude_handler.go (1 hunks)
  • relay/common/override.go (1 hunks)
  • relay/gemini_handler.go (1 hunks)
  • relay/image_handler.go (1 hunks)
  • relay/relay-text.go (1 hunks)
  • relay/rerank_handler.go (1 hunks)
  • relay/responses_handler.go (1 hunks)
  • web/src/components/table/channels/modals/EditChannelModal.jsx (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
relay/responses_handler.go (1)
relay/common/override.go (1)
  • ApplyParamOverride (28-46)
relay/image_handler.go (1)
relay/common/override.go (1)
  • ApplyParamOverride (28-46)
relay/claude_handler.go (1)
relay/common/override.go (1)
  • ApplyParamOverride (28-46)
relay/rerank_handler.go (1)
relay/common/override.go (1)
  • ApplyParamOverride (28-46)
web/src/components/table/channels/modals/EditChannelModal.jsx (1)
web/src/components/table/channels/modals/EditTagModal.jsx (1)
  • handleInputChange (77-129)
relay/relay-text.go (1)
relay/common/override.go (1)
  • ApplyParamOverride (28-46)
relay/gemini_handler.go (1)
relay/common/override.go (1)
  • ApplyParamOverride (28-46)
🔇 Additional comments (5)
relay/responses_handler.go (1)

56-56: Centralized override: looks good; align pass-through semantics and block 'stream'

This change is correct. Two small follow-ups:

  • Ensure ApplyParamOverride rejects "stream" overrides (consistent with UI).
  • Consider aligning pass-through gating with other handlers (many check both global and channel setting); if intentional, ignore.

Would you like me to scan all handlers and summarize where pass-through gating differs so we can decide whether to unify?

relay/image_handler.go (1)

64-70: Centralized override call: looks good

Switching to relaycommon.ApplyParamOverride trims duplication and unifies behavior. Error mapping to ChannelParamOverrideInvalid and skip-retry is appropriate.

relay/gemini_handler.go (2)

124-130: Centralized override logic: good replacement

Using relaycommon.ApplyParamOverride here aligns this path with the new engine and preserves existing error semantics.


222-233: ParamOverride helper used consistently across relay handlers

All instances of manual shallow merges for info.ParamOverride have been replaced with relaycommon.ApplyParamOverride, including in relay/gemini_handler.go. No residual manual merge logic remains.

relay/relay-text.go (1)

134-141: Param override centralization: LGTM

Good move to delegate to ApplyParamOverride and return ChannelParamOverrideInvalid with skip-retry on error.

Comment thread go.mod
Comment on lines +34 to +35
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

New gjson/sjson deps: verify CI/toolchain alignment and transitive integrity

The additions look correct for path-based JSON ops. Please verify:

  • CI/go toolchain supports go 1.23.x used here.
  • No stale indirects; run a tidy pass to ensure minimal sets.
  • All handler sites rely on the centralized override (no lingering bespoke merges).

You can quickly sanity-check call-sites and look for any remaining manual override logic with:

Also applies to: 87-88


🏁 Script executed:

#!/bin/bash
# Show all references to ApplyParamOverride and ParamOverride across handlers
rg -nP --type=go -C2 'ApplyParamOverride\s*\(|\bParamOverride\b'

# Optional: list direct usages of tidwall libs to confirm they're only in the override engine
rg -nP --type=go -C2 '\btidwall/(gjson|sjson)\b'

Length of output: 5389


🏁 Script executed:

#!/bin/bash
# Check Go version in go.mod
grep -n '^go ' go.mod

# List indirect dependencies in go.mod
grep -n 'indirect' go.mod

Length of output: 3197


New tidwall libs added: verify toolchain, tidy deps, and consolidate override logic

Please address the following before merging:

  • go.mod sets Go version to 1.23.4—confirm your CI/workflow is running Go ≥ 1.23.
  • Run go mod tidy to prune any stale indirect entries.
  • We’ve identified a bespoke merge in relay/gemini_handler.go (lines 221–228). Replace this manual Unmarshal/loop logic with the centralized relaycommon.ApplyParamOverride call for consistency.

Also apply the same checks to the tidwall/match and tidwall/pretty entries at go.mod lines 87–88.

🤖 Prompt for AI Agents
In go.mod around lines 34-35 (and also review lines 87-88 for the tidwall/match
and tidwall/pretty entries), update the module bookkeeping: confirm CI/workflows
use Go >= 1.23 (go 1.23.4 in go.mod requires the toolchain be >= that), run `go
mod tidy` to remove stale indirect deps, and ensure any replace/override logic
is consolidated; additionally, in relay/gemini_handler.go around lines 221-228
replace the bespoke manual Unmarshal + loop merge logic with a call to
relaycommon.ApplyParamOverride (pass the same parameters/contexts used
elsewhere) so the centralized override behavior is used consistently.

Comment thread relay/common/override.go
Comment on lines +33 to +46
// 尝试断言为操作格式
if operations, ok := tryParseOperations(paramOverride); ok {
// 使用新方法
result, err := applyOperations(string(jsonData), operations)
if err != nil {
// 新方法失败,回退到旧方法
return applyOperationsLegacy(jsonData, paramOverride)
}
return []byte(result), nil
}

// 直接使用旧方法
return applyOperationsLegacy(jsonData, paramOverride)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Don’t fall back to legacy when operations are present; return an error instead

If an “operations” block is present but fails (parse or apply), falling back to legacy can silently inject the top-level "operations" key into the outbound request or mask user mistakes. This will likely cause upstream API errors with hard-to-trace behavior. Prefer failing fast when operations are intended but invalid.

Apply this diff:

-	// 尝试断言为操作格式
-	if operations, ok := tryParseOperations(paramOverride); ok {
-		// 使用新方法
-		result, err := applyOperations(string(jsonData), operations)
-		if err != nil {
-			// 新方法失败,回退到旧方法
-			return applyOperationsLegacy(jsonData, paramOverride)
-		}
-		return []byte(result), nil
-	}
-
-	// 直接使用旧方法
-	return applyOperationsLegacy(jsonData, paramOverride)
+	// 尝试断言为操作格式
+	if _, hasOps := paramOverride["operations"]; hasOps {
+		operations, ok := tryParseOperations(paramOverride)
+		if !ok {
+			return nil, fmt.Errorf("invalid param_override operations format")
+		}
+		result, err := applyOperations(string(jsonData), operations)
+		if err != nil {
+			return nil, fmt.Errorf("param_override operations failed: %w", err)
+		}
+		return []byte(result), nil
+	}
+	// 直接使用旧方法(仅在未提供 operations 时)
+	return applyOperationsLegacy(jsonData, paramOverride)
📝 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.

Suggested change
// 尝试断言为操作格式
if operations, ok := tryParseOperations(paramOverride); ok {
// 使用新方法
result, err := applyOperations(string(jsonData), operations)
if err != nil {
// 新方法失败,回退到旧方法
return applyOperationsLegacy(jsonData, paramOverride)
}
return []byte(result), nil
}
// 直接使用旧方法
return applyOperationsLegacy(jsonData, paramOverride)
}
// 尝试断言为操作格式
if _, hasOps := paramOverride["operations"]; hasOps {
operations, ok := tryParseOperations(paramOverride)
if !ok {
return nil, fmt.Errorf("invalid param_override operations format")
}
result, err := applyOperations(string(jsonData), operations)
if err != nil {
return nil, fmt.Errorf("param_override operations failed: %w", err)
}
return []byte(result), nil
}
// 直接使用旧方法(仅在未提供 operations 时)
return applyOperationsLegacy(jsonData, paramOverride)
}
🤖 Prompt for AI Agents
In relay/common/override.go around lines 33 to 46, the current logic falls back
to applyOperationsLegacy when an "operations" block is present but parsing or
new applyOperations fails; change this to fail fast instead: if
tryParseOperations(paramOverride) returns ok then call
applyOperations(string(jsonData), operations) and if it returns an error
propagate that error (wrap or return it) rather than calling
applyOperationsLegacy; return []byte(result) on success. Also ensure parsing
failures (ok == false) still follow the old path, but any parse success with
subsequent errors must not fallback and must return an explicit error with
context about "operations" handling.

Comment thread relay/common/override.go Outdated
@Calcium-Ion
Calcium-Ion merged commit 73a7b33 into QuantumNous:alpha Aug 16, 2025
3 checks passed
x22x22 pushed a commit to x22x22/new-api that referenced this pull request Apr 24, 2026
…rams-override

feats: the flexable params override and compatible format
jiutubaba pushed a commit to jiutubaba/fx-api that referenced this pull request May 17, 2026
…obile-double-render

fix(frontend): reduce account usage request fan-out on pagination
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants