Skip to content

feat: embedding param override && internal params - #2276

Merged
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
seefs001:feature/internal_params
Nov 23, 2025
Merged

feat: embedding param override && internal params#2276
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
seefs001:feature/internal_params

Conversation

@seefs001

@seefs001 seefs001 commented Nov 22, 2025

Copy link
Copy Markdown
Collaborator

fix #2275 #2054 #1796

// 目前内置以下字段:
// - model:上游模型名
// - upstream_model:始终为通道映射后的上游模型名。
// - original_model:请求最初指定的模型名。

对于OpenAI兼容接口,这个为了保证兼容,model的用法和之前没有变化,之所以弄original_model就是为了解决这种问题。
把model提出来的原因是Gemini的请求没有模型名称,这个内置model在这里用的。

Summary by CodeRabbit

  • New Features

    • Parameter overrides now support context-aware conditional evaluation based on model type and request context information.
  • Refactor

    • Enhanced parameter override processing to propagate context across handler components for improved condition-based override application.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Nov 22, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Extends ApplyParamOverride across the codebase to accept and propagate a context parameter built from RelayInfo, enabling condition-based parameter overrides to evaluate fields (like model) stored outside the JSON body. Core implementation in relay/common/override.go adds context support, a new BuildParamOverrideContext function, and integrates common package marshalling for consistency.

Changes

Cohort / File(s) Summary
Core override logic
relay/common/override.go
Refactored ApplyParamOverride to accept conditionContext map[string]interface{}, updated applyOperations and checkConditions to propagate context, added BuildParamOverrideContext(info *RelayInfo) function returning model/upstream_model/original_model context, replaced JSON marshalling with common package methods.
Handler function updates
relay/claude_handler.go, relay/compatible_handler.go, relay/gemini_handler.go, relay/image_handler.go, relay/rerank_handler.go, relay/responses_handler.go
Updated calls to ApplyParamOverride to pass context via relaycommon.BuildParamOverrideContext(info) as third parameter.
Embedding handler
relay/embedding_handler.go
Added post-serialization parameter override handling in EmbeddingHelper with context support and error handling for ChannelParamOverrideInvalid.

Sequence Diagram

sequenceDiagram
    participant Handler as Handler Function
    participant BuildCtx as BuildParamOverrideContext
    participant ApplyOverride as ApplyParamOverride
    participant CheckCond as checkConditions
    participant ApplyOps as applyOperations

    Handler->>BuildCtx: BuildParamOverrideContext(info)
    BuildCtx-->>Handler: context map {model, upstream_model, ...}
    Handler->>ApplyOverride: ApplyParamOverride(jsonData, overrides, context)
    ApplyOverride->>ApplyOps: applyOperations(jsonData, operations, context)
    loop For each operation
        ApplyOps->>CheckCond: checkConditions(operation.conditions, jsonData, context)
        alt Conditions satisfied
            CheckCond-->>ApplyOps: true
            ApplyOps->>ApplyOps: Apply operation to jsonData
        else Conditions not satisfied
            CheckCond-->>ApplyOps: false
            ApplyOps->>ApplyOps: Skip operation
        end
    end
    ApplyOps-->>ApplyOverride: modified jsonData
    ApplyOverride-->>Handler: result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Core logic review: relay/common/override.go introduces new context propagation through condition evaluation and operation application; requires careful verification of how context flows through checkConditionscheckSingleCondition and how it interacts with JSON marshalling transitions.
  • Call site consistency: Six handler files updated with identical pattern changes; verify all callers correctly pass BuildParamOverrideContext(info).
  • Context type handling: Ensure interface{} context parameter is properly typed and handled in condition checking logic, especially in checkSingleCondition where context fallback occurs.

Possibly related PRs

  • PR #1603: Main PR that modifies the ApplyParamOverride API to accept and propagate a context parameter; directly related as this PR applies the same pattern across all handler call sites.

Suggested reviewers

  • creamlike1024

Poem

🐰 A context flows through handlers swift and bright,
Where models hide in URLs, out of sight,
Conditions now can peek at hidden state,
Parameter overrides no longer wait!
Gemini's secrets now reveal their fate! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'feat: embedding param override && internal params' is vague and uses non-descriptive phrasing ('&&' notation, 'internal params'). It does not clearly communicate the specific main change—implementing context-aware parameter overrides to fix Gemini model condition evaluation. Revise title to be more specific and descriptive, such as: 'feat: add context-aware param overrides for model conditions' or similar phrasing that explains the actual implementation.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR implements context-aware parameter overrides through BuildParamOverrideContext and applies them across all handlers, directly addressing the core issue (#2275) where Gemini model conditions failed due to missing model field in converted JSON.
Out of Scope Changes check ✅ Passed All changes are focused on implementing context-aware parameter overrides and propagating context through handlers. No unrelated modifications detected outside the scope of fixing Gemini parameter override conditions.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • 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

Comment @coderabbitai help to get the list of available commands and usage tips.

@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: 2

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)

258-268: Inconsistent parameter override implementation - update to use ApplyParamOverride.

The GeminiEmbeddingHandler uses the legacy direct map manipulation approach for parameter overrides, while GeminiHelper and other handlers now use relaycommon.ApplyParamOverride with context. This inconsistency means:

  • Condition-based overrides don't work for Gemini embeddings
  • Users cannot leverage the new override format introduced in this PR

Apply this diff to align with the updated approach:

 	// 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)
+		jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info))
 		if err != nil {
 			return types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid, types.ErrOptionWithSkipRetry())
 		}
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between efb8f1f and 0885597.

📒 Files selected for processing (8)
  • relay/claude_handler.go (1 hunks)
  • relay/common/override.go (9 hunks)
  • relay/compatible_handler.go (1 hunks)
  • relay/embedding_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
🧠 Learnings (1)
📚 Learning: 2025-08-08T17:12:43.157Z
Learnt from: RedwindA
Repo: QuantumNous/new-api PR: 1537
File: relay/gemini_handler.go:330-342
Timestamp: 2025-08-08T17:12:43.157Z
Learning: In the new-api repository, the `GeminiEmbeddingHandler` function in `relay/gemini_handler.go` is designed specifically for native Gemini embedding requests and therefore does not require the `ConvertGeminiRequest` step that is used in the chat handler. The embedding requests are already in the native Gemini format and don't need conversion.

Applied to files:

  • relay/embedding_handler.go
  • relay/gemini_handler.go
🧬 Code graph analysis (8)
relay/claude_handler.go (1)
relay/common/override.go (2)
  • ApplyParamOverride (33-47)
  • BuildParamOverrideContext (460-481)
relay/embedding_handler.go (2)
relay/common/override.go (2)
  • ApplyParamOverride (33-47)
  • BuildParamOverrideContext (460-481)
types/error.go (3)
  • NewError (204-224)
  • ErrorCodeChannelParamOverrideInvalid (53-53)
  • ErrOptionWithSkipRetry (334-338)
relay/image_handler.go (1)
relay/common/override.go (2)
  • ApplyParamOverride (33-47)
  • BuildParamOverrideContext (460-481)
relay/responses_handler.go (1)
relay/common/override.go (2)
  • ApplyParamOverride (33-47)
  • BuildParamOverrideContext (460-481)
relay/gemini_handler.go (1)
relay/common/override.go (2)
  • ApplyParamOverride (33-47)
  • BuildParamOverrideContext (460-481)
relay/common/override.go (2)
common/json.go (2)
  • Marshal (21-23)
  • Unmarshal (9-11)
relay/common/relay_info.go (2)
  • RelayInfo (76-123)
  • ChannelMeta (56-74)
relay/compatible_handler.go (1)
relay/common/override.go (2)
  • ApplyParamOverride (33-47)
  • BuildParamOverrideContext (460-481)
relay/rerank_handler.go (1)
relay/common/override.go (2)
  • ApplyParamOverride (33-47)
  • BuildParamOverrideContext (460-481)
🔇 Additional comments (8)
relay/common/override.go (1)

33-47: Context-aware condition evaluation looks correct and backwards compatible

The new conditionContext plumbed through ApplyParamOverrideapplyOperationscheckConditions/checkSingleCondition only kicks in when the primary JSON lookup fails, so existing overrides that match on fields inside the body keep their behavior, while channels like Gemini (where model is not in the body) can now rely on context. The fallback to contextJSON plus the reuse of the existing comparison helpers looks solid.

Also applies to: 126-186, 310-319

relay/embedding_handler.go (1)

53-58: Embedding param override integration is consistent and safe

Applying ApplyParamOverride after ConvertEmbeddingRequest with a context from BuildParamOverrideContext(info) matches the pattern used in other handlers and correctly surfaces failures as channel:param_override_invalid with skipRetry. This should enable model-based override conditions for embeddings (including Gemini) without changing existing behavior when no overrides are configured.

relay/image_handler.go (1)

70-76: Image param override now correctly receives context

Threading relaycommon.BuildParamOverrideContext(info) into ApplyParamOverride keeps the existing error handling while allowing conditions that depend on fields like model (especially for providers that don’t expose it in the body). This looks consistent with the other handlers.

relay/responses_handler.go (1)

67-73: Responses helper correctly adopts the new context-aware override

Passing relaycommon.BuildParamOverrideContext(info) into ApplyParamOverride after RemoveDisabledFields aligns this path with the others and should unblock model-based override conditions for responses without changing non-context cases.

relay/rerank_handler.go (1)

61-67: Rerank helper’s override call is consistent with the new API

The rerank flow now applies overrides with a context from BuildParamOverrideContext(info), matching the other handlers and allowing conditions that depend on model metadata while preserving prior behavior when overrides are absent.

relay/claude_handler.go (1)

126-126: LGTM - Context parameter correctly propagated.

The updated call to ApplyParamOverride now passes the context built from RelayInfo, enabling condition-based parameter overrides to evaluate fields (like model names) that exist outside the JSON body.

relay/gemini_handler.go (1)

159-159: LGTM - Key fix for Gemini parameter override conditions.

This change addresses issue #2275 by passing context that includes model names from RelayInfo, allowing condition-based parameter overrides to evaluate the model field even though Gemini places model names in the request URL rather than the JSON body.

relay/compatible_handler.go (1)

147-147: LGTM - Context parameter correctly propagated.

The updated call to ApplyParamOverride now passes the context built from RelayInfo, enabling condition-based parameter overrides to evaluate fields (like model names) stored outside the JSON body.

Comment thread relay/common/override.go
Comment on lines +9 to 10
"github.com/QuantumNous/new-api/common"
"github.com/tidwall/gjson"

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Minor: central JSON helpers are good; consider handling marshal error and verify no import cycle

Switching to the root common.Marshal/Unmarshal helpers in applyOperationsLegacy and mergeObjects is a nice consistency improvement.

Two small follow‑ups you might consider:

  1. In mergeObjects, the error from common.Marshal(v) is ignored:
jsonBytes, _ := common.Marshal(v)
if err := common.Unmarshal(jsonBytes, &newMap); err != nil {
    return "", err
}

It would be slightly safer to propagate that error instead of discarding it, even if failure is unlikely for the types you expect.

  1. This file (package relay/common) imports the root github.com/QuantumNous/new-api/common package. That’s fine, but it does mean a new potential for an import cycle if the root common package ever imports relay/common. It’s probably not happening today, but worth quickly checking.

Also applies to: 295-308, 428-441


🏁 Script executed:

#!/bin/bash
# Quick sanity check: look for any imports of relay/common from the root common package.
fd '\.go$' common | xargs -r rg -n '"github.com/QuantumNous/new-api/relay/common"' -C2 || true

Length of output: 0


🏁 Script executed:

#!/bin/bash
# 1. Locate the file and check its structure
echo "=== Finding relay/common/override.go ==="
fd -t f 'override.go' --path '*relay/common*'

# 2. Check what's in root common package
echo -e "\n=== Root common package Go files ==="
fd -t f '\.go$' common/ | head -20

# 3. Check if root common imports relay/common (alternative approach)
echo -e "\n=== Checking root common for relay/common imports ==="
rg 'relay/common|relay\.common' common/ --type go -n -C1 || echo "(no matches found)"

# 4. Verify the actual mergeObjects function around the lines cited
echo -e "\n=== Looking for mergeObjects function ==="
rg 'func.*mergeObjects|jsonBytes.*Marshal' relay/ --type go -n -B2 -A5 || echo "(not found)"

Length of output: 1696


🏁 Script executed:

#!/bin/bash
# Check lines 295-308 area for similar Marshal error handling pattern
echo "=== Checking lines 295-308 in relay/common/override.go ==="
sed -n '290,310p' relay/common/override.go

# Also check if there are other instances of Marshal with error ignored
echo -e "\n=== All instances of 'Marshal' with blank error handling in relay/common/override.go ==="
rg 'Marshal.*_\s*:=' relay/common/override.go -n -B2 -A2

Length of output: 719


Handle error from common.Marshal in mergeObjects function

At line 437 in relay/common/override.go, the error from common.Marshal(v) is discarded:

jsonBytes, _ := common.Marshal(v)
if err := common.Unmarshal(jsonBytes, &newMap); err != nil {
    return "", err
}

Propagate the error instead to avoid silently masking failures:

jsonBytes, err := common.Marshal(v)
if err != nil {
    return "", err
}
if err := common.Unmarshal(jsonBytes, &newMap); err != nil {
    return "", err
}

No import cycle detected. The root common package does not import relay/common, so the new dependency is safe.

🤖 Prompt for AI Agents
In relay/common/override.go around lines 9 and 437, the call to
common.Marshal(v) in mergeObjects ignores the returned error; change the code to
capture and check the error from common.Marshal, returning it if non-nil before
proceeding to common.Unmarshal, so failures from Marshal are propagated instead
of silently discarded.

Comment thread relay/common/override.go
Comment on lines +455 to +481
// BuildParamOverrideContext 提供 ApplyParamOverride 可用的上下文信息。
// 目前内置以下字段:
// - model:优先使用上游模型名(UpstreamModelName),若不存在则回落到原始模型名(OriginModelName)。
// - upstream_model:始终为通道映射后的上游模型名。
// - original_model:请求最初指定的模型名。
func BuildParamOverrideContext(info *RelayInfo) map[string]interface{} {
if info == nil || info.ChannelMeta == nil {
return nil
}

ctx := make(map[string]interface{})
if info.UpstreamModelName != "" {
ctx["model"] = info.UpstreamModelName
ctx["upstream_model"] = info.UpstreamModelName
}
if info.OriginModelName != "" {
ctx["original_model"] = info.OriginModelName
if _, exists := ctx["model"]; !exists {
ctx["model"] = info.OriginModelName
}
}

if len(ctx) == 0 {
return nil
}
return ctx
}

@coderabbitai coderabbitai Bot Nov 22, 2025

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.

⚠️ Potential issue | 🟠 Major

Semantics of model vs original_model / upstream_model may not match #2275’s intent

BuildParamOverrideContext currently sets:

  • model = UpstreamModelName (if non-empty), falling back to OriginModelName
  • upstream_model = UpstreamModelName
  • original_model = OriginModelName

Issue #2275 explicitly called out evaluating conditions “before model redirection takes effect”. With this mapping, a condition on path: "model" for Gemini will see the upstream (mapped) model whenever mapping is configured, not the originally requested model.

If the desired semantics for existing/expected configs are:

  • model → original requested model (pre‑mapping)
  • upstream_model → mapped channel model

then this implementation may surprise users and make it impossible to key overrides off the pre‑mapping name without updating all existing overrides to use original_model.

Consider either:

  • Swapping the meaning so ctx["model"] is OriginModelName and ctx["upstream_model"] remains mapped, or
  • Keeping current behavior but clearly documenting that model here is the upstream model, and requiring configs that care about the original to use original_model.

Please confirm which behavior you want relative to #2275 and adjust accordingly if needed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Because the code is already deployed and running, the meaning of the model cannot be changed.

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.

@seefs001, understood! Backward compatibility with existing deployed configurations is definitely a valid constraint.

In that case, users who need to create conditions based on the pre-mapping model name (the original requested model) should use path: "original_model" in their condition operations, while path: "model" will continue to resolve to the upstream (mapped) model when available.

It might be worth adding a brief note in your documentation or inline comments that:

  • model → upstream model (post-mapping) when available, otherwise original model
  • original_model → always the originally requested model (pre-mapping)
  • upstream_model → always the channel-mapped model

This will help users understand which field to reference in their override conditions based on their specific use case.

@Calcium-Ion
Calcium-Ion merged commit dbfcb44 into QuantumNous:main Nov 23, 2025
1 check passed
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
…rams

feat: embedding param override && internal params
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.

[Bug] Gemini 渠道參數覆蓋無法基於新格式模板的 model 條件生效

2 participants