Skip to content

Fix/aws header override - #3066

Merged
Calcium-Ion merged 8 commits into
QuantumNous:mainfrom
seefs001:fix/aws-header-override
Mar 2, 2026
Merged

Fix/aws header override#3066
Calcium-Ion merged 8 commits into
QuantumNous:mainfrom
seefs001:fix/aws-header-override

Conversation

@seefs001

@seefs001 seefs001 commented Feb 28, 2026

Copy link
Copy Markdown
Collaborator

fix #2944 #3041

Summary by CodeRabbit

  • New Features

    • Runtime header override applied to AWS Bedrock requests
    • Public header-override resolver exposed
    • Optional metadata field added to AWS and Vertex AI request payloads
  • Tests

    • AWS Bedrock header-override test added
    • New tests for mixed legacy + operation-based parameter overrides
    • Channel affinity operations merge test added
  • Improvements

    • Two-stage legacy + operations parameter override handling
    • Operations merge/concatenation behavior for channel templates
    • Improved request body unmarshalling and cleaner JSON output
  • Chores

    • Updated AWS SDK and related dependencies

seefs001 and others added 2 commits March 1, 2026 01:13
Co-authored-by: G2-star <G2-star@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Feb 28, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Runtime header override resolution was exposed via a new public function and integrated into the AWS relay request flow; request DTOs for AWS and Vertex channels gained optional metadata passthrough fields; Claude request unmarshalling switched to a reusable helper; Thinking.Type JSON tag made omitempty. Legacy param overrides are applied before operation-based overrides; tests for mixed overrides and an AWS header-override test were added. AWS SDK dependencies were bumped.

Changes

Cohort / File(s) Summary
Header override API & integration
relay/channel/api_request.go, relay/channel/aws/relay-aws.go
Added public ResolveHeaderOverride(info *common.RelayInfo, c *gin.Context) wrapper and applied resolved runtime header overrides to AWS request headers in doAwsClientRequest.
Request DTOs (metadata passthrough & Claude tweak)
relay/channel/aws/dto.go, relay/channel/vertex/dto.go, dto/claude.go
Added Metadata json.RawMessage (json:"metadata,omitempty") to AWS and Vertex Claude request DTOs; changed Thinking.Type tag to json:"type,omitempty".
Request unmarshalling
relay/helper/valid_request.go
Replaced Gin's ShouldBindJSON with common.UnmarshalBodyReusable for Claude request parsing to tolerate unknown/additional fields.
Legacy + operations param override
relay/common/override.go, service/channel_affinity.go
Added buildLegacyParamOverride and extractParamOperations; ApplyParamOverride now applies legacy overrides via applyOperationsLegacy first (if present), then operation-based overrides; channel-affinity merge concatenates operations lists.
Tests (override + AWS)
relay/common/override_test.go, service/channel_affinity_template_test.go, relay/channel/aws/relay_aws_test.go
Added tests covering mixed legacy+operations overrides, channel-affinity operations merging, and AWS Bedrock payload receiving runtime header override (anthropic_beta) in request body.
Dependencies
go.mod
Bumped AWS SDK v2 and related module versions (several transitive updates).

Sequence Diagram(s)

sequenceDiagram
    participant Client as Incoming Request
    participant Handler as AWS Relay Handler
    participant Resolver as ResolveHeaderOverride
    participant Processor as processHeaderOverride
    participant AWS as AWS Bedrock

    Client->>Handler: HTTP request with runtime header overrides
    Handler->>Resolver: ResolveHeaderOverride(relayInfo, ctx)
    Resolver->>Processor: processHeaderOverride(...)
    Processor-->>Resolver: resolved header map
    Resolver-->>Handler: return resolved overrides
    Handler->>Handler: apply overrides to headers/body (e.g., anthropic_beta)
    Handler->>AWS: send InvokeModelInput with applied overrides
    AWS-->>Handler: response
    Handler-->>Client: proxied response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Calcium-Ion

Poem

🐰 I hopped through headers, a tiny dev sprite,
I nudged metadata gently into the light,
Omitted empty types with a soft little cheer,
Applied legacy then ops so the payload is clear,
Tests nibbled carrots — the relay is right! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Fix/aws header override' is vague and does not clearly describe the specific changes. While it references AWS header overrides, it lacks clarity about what is being fixed or improved. Revise the title to be more descriptive, such as 'Add header override support for AWS Bedrock requests' or 'Support parameter overrides with legacy and operations-based precedence' to better reflect the changeset.
Out of Scope Changes check ❓ Inconclusive The PR includes changes beyond issue #2944's scope: header override functionality in relay-aws.go, enhanced parameter override logic with legacy/operations precedence in override.go, channel affinity template merging, and related test cases. These extend the PR's scope to include broader override infrastructure improvements. Clarify whether the header override infrastructure, parameter override precedence changes, and channel affinity enhancements are intentional extensions of the original issue or should be separated into a distinct PR for better change isolation.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR addresses the core requirements from issue #2944: tolerating unknown JSON fields via UnmarshalBodyReusable, adding Metadata and OutputConfig fields, updating Thinking.Type tag with omitempty, and passing these through to AWS Bedrock. Additional enhancements include header override support and operation precedence handling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dto/claude.go`:
- Around line 429-432: The Thinking struct currently marks the Type field with
`omitempty`, which allows omission but the Anthropic Claude API requires the
`type` field; remove the `omitempty` tag from Thinking.Type in the Thinking
struct definition (or ensure callers always set a valid "enabled"/"disabled"
value before JSON serialization) so the serialized payload always includes the
required `type` field; update any constructors or code paths that build Thinking
to set a default if necessary.

In `@relay/channel/vertex/dto.go`:
- Line 23: The copyRequest function fails to copy the new Metadata field from
dto.ClaudeRequest into the VertexAIClaudeRequest, so include req.Metadata =
src.Metadata (or equivalent) when building the VertexAIClaudeRequest in
copyRequest; update the copyRequest logic to read src.Metadata (from
dto.ClaudeRequest) and assign it to the target VertexAIClaudeRequest.Metadata so
Vertex AI requests carry over the metadata field.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21cfc1c and 5afa5d2.

📒 Files selected for processing (7)
  • dto/claude.go
  • relay/channel/api_request.go
  • relay/channel/aws/dto.go
  • relay/channel/aws/relay-aws.go
  • relay/channel/aws/relay_aws_test.go
  • relay/channel/vertex/dto.go
  • relay/helper/valid_request.go

Comment thread dto/claude.go
Comment on lines 429 to 432
type Thinking struct {
Type string `json:"type"`
Type string `json:"type,omitempty"`
BudgetTokens *int `json:"budget_tokens,omitempty"`
}

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

🧩 Analysis chain

🌐 Web query:

Anthropic Claude API thinking type field specification documentation

💡 Result:

thinking field (request) — Claude Messages API

To enable extended thinking, include a top-level thinking object in your Messages API request with:

"thinking": { "type": "enabled", "budget_tokens": 2048 }
  • type: "enabled" (to turn on extended thinking)
  • budget_tokens: maximum token budget for thinking; must be at least 1024 and (in the normal/non-interleaved case) less than max_tokens; the thinking budget counts toward your max_tokens limit. [1][2]

To disable:

"thinking": { "type": "disabled" }
``` [2]

### `thinking` content blocks (response)

When enabled, the assistant response `content` will include one or more blocks with:

* `type`: `"thinking"`
* `thinking`: the model’s thinking text (what you can display, depending on model/version)
* `signature`: an opaque verification value; Anthropic notes full thinking may be encrypted and returned via `signature` (not meant to be parsed). [1][3]

### Streaming events for thinking

In streaming mode, thinking arrives via:

* `thinking_delta` events (incremental thinking text)
* a `signature_delta` event **just before** `content_block_stop` for that thinking block. [3]

---

**Sources:** Anthropic “Building with extended thinking” docs [1], Anthropic API token counting docs (request schema notes for `thinking`) [2], Anthropic “Streaming Messages” docs (thinking/signature deltas) [3], Anthropic API release notes (signature behavior) [4].

---



</details>

**Do not add `omitempty` to `Thinking.Type` — the `type` field is required by the Anthropic API.**

The Anthropic Claude API documentation explicitly requires the `type` field in thinking objects, with values of either `"enabled"` or `"disabled"`. Using `omitempty` allows this field to be omitted when empty, which violates the API specification and could cause requests to fail. Either ensure `Type` is always set to a valid value before serialization, or remove the `omitempty` tag.

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @dto/claude.go around lines 429 - 432, The Thinking struct currently marks
the Type field with omitempty, which allows omission but the Anthropic Claude
API requires the type field; remove the omitempty tag from Thinking.Type in
the Thinking struct definition (or ensure callers always set a valid
"enabled"/"disabled" value before JSON serialization) so the serialized payload
always includes the required type field; update any constructors or code paths
that build Thinking to set a default if necessary.


</details>

<!-- This is an auto-generated comment by CodeRabbit -->

Comment thread relay/channel/vertex/dto.go Outdated
ToolChoice any `json:"tool_choice,omitempty"`
Thinking *dto.Thinking `json:"thinking,omitempty"`
OutputConfig json.RawMessage `json:"output_config,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"`

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

Metadata field is not copied in copyRequest.

The new Metadata field was added to VertexAIClaudeRequest, but copyRequest (lines 26-41) does not copy req.Metadata from the source dto.ClaudeRequest. This means Vertex AI requests will never include the metadata even when the original request contains it.

🐛 Proposed fix to include Metadata in copyRequest
 func copyRequest(req *dto.ClaudeRequest, version string) *VertexAIClaudeRequest {
 	return &VertexAIClaudeRequest{
 		AnthropicVersion: version,
 		System:           req.System,
 		Messages:         req.Messages,
 		MaxTokens:        req.MaxTokens,
 		Stream:           req.Stream,
 		Temperature:      req.Temperature,
 		TopP:             req.TopP,
 		TopK:             req.TopK,
 		StopSequences:    req.StopSequences,
 		Tools:            req.Tools,
 		ToolChoice:       req.ToolChoice,
 		Thinking:         req.Thinking,
 		OutputConfig:     req.OutputConfig,
+		Metadata:         req.Metadata,
 	}
 }
📝 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
Metadata json.RawMessage `json:"metadata,omitempty"`
func copyRequest(req *dto.ClaudeRequest, version string) *VertexAIClaudeRequest {
return &VertexAIClaudeRequest{
AnthropicVersion: version,
System: req.System,
Messages: req.Messages,
MaxTokens: req.MaxTokens,
Stream: req.Stream,
Temperature: req.Temperature,
TopP: req.TopP,
TopK: req.TopK,
StopSequences: req.StopSequences,
Tools: req.Tools,
ToolChoice: req.ToolChoice,
Thinking: req.Thinking,
OutputConfig: req.OutputConfig,
Metadata: req.Metadata,
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/vertex/dto.go` at line 23, The copyRequest function fails to
copy the new Metadata field from dto.ClaudeRequest into the
VertexAIClaudeRequest, so include req.Metadata = src.Metadata (or equivalent)
when building the VertexAIClaudeRequest in copyRequest; update the copyRequest
logic to read src.Metadata (from dto.ClaudeRequest) and assign it to the target
VertexAIClaudeRequest.Metadata so Vertex AI requests carry over the metadata
field.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@service/channel_affinity.go`:
- Around line 439-450: The merge logic for the "operations" key uses the raw
template key k, so differently-cased/whitespace keys (e.g., " Operations ")
won't match existing base entries; normalize the key before reading/writing by
computing normKey := strings.ToLower(strings.TrimSpace(k)) (or constant
"operations") and use normKey when calling extractParamOperations and when
reading/writing out (e.g., check out[normKey], assign out[normKey] = ...); if
the original raw key differs from normKey, remove or replace out[k] to avoid
duplicate keys. Ensure you still call extractParamOperations(v) for the template
value v and preserve the existing append order (tplOps before baseOps).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02608b1 and 493e568.

📒 Files selected for processing (2)
  • service/channel_affinity.go
  • service/channel_affinity_template_test.go

Comment on lines +439 to +450
if strings.EqualFold(strings.TrimSpace(k), "operations") {
baseOps, hasBaseOps := extractParamOperations(out[k])
tplOps, hasTplOps := extractParamOperations(v)
if hasTplOps {
if hasBaseOps {
out[k] = append(tplOps, baseOps...)
} else {
out[k] = tplOps
}
continue
}
}

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

Normalize the target operations key before reading/writing.

Line 440 reads out[k] using the raw template key. If template uses " Operations " and base uses "operations", base ops won’t merge and you can end up with duplicate operation keys.

🔧 Proposed fix
 	for k, v := range tpl {
 		if strings.EqualFold(strings.TrimSpace(k), "operations") {
-			baseOps, hasBaseOps := extractParamOperations(out[k])
+			opsKey := "operations"
+			for existingKey := range out {
+				if strings.EqualFold(strings.TrimSpace(existingKey), "operations") {
+					opsKey = existingKey
+					break
+				}
+			}
+			baseOps, hasBaseOps := extractParamOperations(out[opsKey])
 			tplOps, hasTplOps := extractParamOperations(v)
 			if hasTplOps {
-				if hasBaseOps {
-					out[k] = append(tplOps, baseOps...)
-				} else {
-					out[k] = tplOps
-				}
+				mergedOps := tplOps
+				if hasBaseOps {
+					mergedOps = append(tplOps, baseOps...)
+				}
+				out[opsKey] = mergedOps
+				if opsKey != k {
+					delete(out, k)
+				}
 				continue
 			}
 		}
 		out[k] = v
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@service/channel_affinity.go` around lines 439 - 450, The merge logic for the
"operations" key uses the raw template key k, so differently-cased/whitespace
keys (e.g., " Operations ") won't match existing base entries; normalize the key
before reading/writing by computing normKey :=
strings.ToLower(strings.TrimSpace(k)) (or constant "operations") and use normKey
when calling extractParamOperations and when reading/writing out (e.g., check
out[normKey], assign out[normKey] = ...); if the original raw key differs from
normKey, remove or replace out[k] to avoid duplicate keys. Ensure you still call
extractParamOperations(v) for the template value v and preserve the existing
append order (tplOps before baseOps).

@Calcium-Ion
Calcium-Ion merged commit 0689600 into QuantumNous:main Mar 2, 2026
1 check passed
hardingCheng pushed a commit to hardingCheng/new-api that referenced this pull request Mar 3, 2026
* main:
  feat: auto fetch upstream models (QuantumNous#2979)
  feat: add AionUI to chat settings and built-in templates
  Revert "fix: aws text content blocks must be non-empty"
  Revert "Fix/aws non empty text"
  fix: tool responses
  Return error when model price/ratio unset
  Merge pull request QuantumNous#3066 from seefs001/fix/aws-header-override
  fix: handle rate limits and improve error response parsing in video task updates
  fix: default empty input_json_delta arguments to {} for tool call parsing
  fix: preserve tool_use on malformed tool arguments to keep tool_result pairing valid
  fix: aws text content blocks must be non-empty
  feat: add cc-switch integration and modal for token management
  fix: preserve explicit zero values in native relay requests
  fix: enhance migrateTokenModelLimitsToText function to return errors and improve migration checks
  fix: migrate model_limits column from varchar(1024) to text for existing tables
  fix: change token model_limits column from varchar(1024) to text

# Conflicts:
#	web/src/i18n/locales/en.json
#	web/src/i18n/locales/fr.json
#	web/src/i18n/locales/ja.json
#	web/src/i18n/locales/ru.json
#	web/src/i18n/locales/vi.json
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
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.

Claude Code使用非Anthropic渠道出现报错“invalid beta flag”

2 participants