Skip to content

Comments

fix: allow output_config, metadata and unknown fields in Claude/Bedrock requests#2944

Open
G2-star wants to merge 4 commits intoQuantumNous:mainfrom
G2-star:feature/bedrock-output-config
Open

fix: allow output_config, metadata and unknown fields in Claude/Bedrock requests#2944
G2-star wants to merge 4 commits intoQuantumNous:mainfrom
G2-star:feature/bedrock-output-config

Conversation

@G2-star
Copy link

@G2-star G2-star commented Feb 13, 2026

Summary

  • Replaced ShouldBindJSON with UnmarshalBodyReusable in GetAndValidateClaudeRequest to tolerate unknown JSON fields
  • Added OutputConfig and Metadata fields (json.RawMessage) to AwsClaudeRequest for transparent passthrough to Bedrock
  • Added omitempty to Thinking.Type JSON tag to avoid sending empty "type":""
  • Fixed FileMeta construction to pass MediaType to NewBase64FileSource

Why

Claude's API evolves with new fields (output_config for effort control, metadata, etc.). Strict validation via ShouldBindJSON rejects requests containing these fields with 400 errors, breaking forward compatibility. AWS Bedrock needs these fields forwarded as-is for features like adaptive thinking.

Changed files

File Change
relay/helper/valid_request.go Use common.UnmarshalBodyReusable instead of ShouldBindJSON
dto/claude.go Thinking.Type add omitempty; fix FileMeta base64 source with MediaType
relay/channel/aws/dto.go Add OutputConfig and Metadata fields to AwsClaudeRequest
relay/helper/valid_request_test.go New: tests for output_config, thinking, unknown fields
relay/channel/aws/dto_test.go New: tests for output_config passthrough to Bedrock

Test plan

  • relay/helper/valid_request_test.go — output_config, thinking, unknown fields accepted
  • relay/channel/aws/dto_test.go — output_config passes through to Bedrock request body
  • Manual: send Claude API request with output_config and metadata via both Claude and AWS Bedrock channels

Summary by CodeRabbit

  • New Features

    • Added optional Metadata support for AWS Claude API requests to extend payloads.
  • Bug Fixes

    • Improved request parsing to tolerate unknown fields and handle empty output_config/thinking payloads.
    • Adjusted Thinking serialization so empty type values are omitted.
  • Tests

    • Added tests covering request parsing, output_config handling, unknown fields, and thinking behavior.

G2-star added 3 commits February 6, 2026 13:25
Allow `output_config`, `thinking` and other new fields, tolerate unknown fields, and avoid 400 errors due to extra fields.

Changes:
1. relay/helper/valid_request.go
   - `GetAndValidateClaudeRequest` now uses `common.UnmarshalBodyReusable` for JSON parsing
   - Purpose: Use fault-tolerant parsing for Claude/Bedrock endpoints to avoid failures from unknown fields

2. dto/claude.go
   - `Thinking.Type` now includes `omitempty`
   - Purpose: Avoid serializing empty strings when `type` is not provided

3. relay/channel/aws/dto.go
   - Added `OutputConfig json.RawMessage` and `Metadata json.RawMessage` to `AwsClaudeRequest`
   - Purpose: Pass through `output_config` (including `effort` or future extension fields) and `metadata` without strict validation

4. New Tests
   - relay/helper/valid_request_test.go: Tests for `output_config` (low/high/empty), `thinking`, unknown field `foo`
   - relay/channel/aws/dto_test.go: Tests for `output_config` pass-through, `thinking`, unknown field filtering
上游代码将 FileMeta.OriginData 重构为 FileMeta.Source (*FileSource)
使用 NewURLFileSource 和 NewBase64FileSource 创建对应的文件来源
- Merged latest changes from upstream/main (68 commits)
- Resolved conflict in relay/channel/aws/dto.go (kept Metadata field)
- Fixed FileMeta compatibility issue with new FileSource API
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Walkthrough

Refactors FileSource creation in Claude DTOs, makes Thinking.Type omit when empty, adds a Metadata field to AwsClaudeRequest, removes response compaction handling, switches Claude request body parsing to UnmarshalBodyReusable, and adds tests for output_config, unknown fields, and Thinking parsing.

Changes

Cohort / File(s) Summary
Claude DTO
dto/claude.go
Removed internal FileSource helper and inlined conditional construction (URL vs base64) for media; changed Thinking.Type JSON tag to json:"type,omitempty".
AWS DTO & Tests
relay/channel/aws/dto.go, relay/channel/aws/dto_test.go
Added Metadata json.RawMessage to AwsClaudeRequest; added tests validating preservation of output_config, handling of unknown fields, and empty output_config behavior.
Request Validation & Tests
relay/helper/valid_request.go, relay/helper/valid_request_test.go
Removed compaction handling and orphaned helper; switched binding from ShouldBindJSON to common.UnmarshalBodyReusable for Claude requests; added unit tests covering parsing of output_config, unknown fields, and Thinking contents.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • seefs001

Poem

🐇 I nibble through fields both new and old,

Metadata tucked in JSON fold,
Thinking hides when empty, shy—
Tests hop in to verify,
Claude's requests now neat and bold.

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (65 files):

⚔️ .cursor/rules/project.mdc (content)
⚔️ AGENTS.md (content)
⚔️ CLAUDE.md (content)
⚔️ README.fr.md (content)
⚔️ README.ja.md (content)
⚔️ README.md (content)
⚔️ common/body_storage.go (content)
⚔️ common/endpoint_type.go (content)
⚔️ common/gin.go (content)
⚔️ controller/channel-test.go (content)
⚔️ controller/model_sync.go (content)
⚔️ controller/pricing.go (content)
⚔️ controller/ratio_sync.go (content)
⚔️ controller/relay.go (content)
⚔️ dto/claude.go (content)
⚔️ dto/ratio_sync.go (content)
⚔️ i18n/i18n.go (content)
⚔️ i18n/keys.go (content)
⚔️ i18n/locales/en.yaml (content)
⚔️ middleware/auth.go (content)
⚔️ middleware/cache.go (content)
⚔️ middleware/distributor.go (content)
⚔️ model/pricing.go (content)
⚔️ model/task.go (content)
⚔️ model/token.go (content)
⚔️ relay/channel/api_request.go (content)
⚔️ relay/channel/aws/dto.go (content)
⚔️ relay/channel/aws/relay-aws.go (content)
⚔️ relay/channel/gemini/relay-gemini.go (content)
⚔️ relay/channel/task/sora/adaptor.go (content)
⚔️ relay/channel/xai/adaptor.go (content)
⚔️ relay/channel/xai/constants.go (content)
⚔️ relay/channel/xai/text.go (content)
⚔️ relay/claude_handler.go (content)
⚔️ relay/common/relay_info.go (content)
⚔️ relay/compatible_handler.go (content)
⚔️ relay/gemini_handler.go (content)
⚔️ relay/helper/valid_request.go (content)
⚔️ relay/image_handler.go (content)
⚔️ relay/rerank_handler.go (content)
⚔️ relay/responses_handler.go (content)
⚔️ service/channel_affinity.go (content)
⚔️ service/error.go (content)
⚔️ web/bun.lock (content)
⚔️ web/package.json (content)
⚔️ web/src/components/layout/headerbar/LanguageSelector.jsx (content)
⚔️ web/src/components/settings/ChannelSelectorModal.jsx (content)
⚔️ web/src/components/settings/personal/cards/PreferencesSettings.jsx (content)
⚔️ web/src/components/table/channels/ChannelsActions.jsx (content)
⚔️ web/src/components/table/models/modals/SyncWizardModal.jsx (content)
⚔️ web/src/components/table/task-logs/TaskLogsColumnDefs.jsx (content)
⚔️ web/src/components/table/task-logs/TaskLogsTable.jsx (content)
⚔️ web/src/components/table/task-logs/index.jsx (content)
⚔️ web/src/components/table/tokens/TokensFilters.jsx (content)
⚔️ web/src/components/table/usage-logs/UsageLogsColumnDefs.jsx (content)
⚔️ web/src/components/table/users/modals/EditUserModal.jsx (content)
⚔️ web/src/hooks/task-logs/useTaskLogsData.js (content)
⚔️ web/src/hooks/tokens/useTokensData.jsx (content)
⚔️ web/src/i18n/i18n.js (content)
⚔️ web/src/i18n/locales/en.json (content)
⚔️ web/src/i18n/locales/fr.json (content)
⚔️ web/src/i18n/locales/ja.json (content)
⚔️ web/src/i18n/locales/ru.json (content)
⚔️ web/src/i18n/locales/vi.json (content)
⚔️ web/src/pages/Setting/Ratio/UpstreamRatioSync.jsx (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: allowing output_config, metadata, and unknown fields in Claude/Bedrock requests, which matches the core purpose of switching to tolerant JSON parsing and adding passthrough fields.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch feature/bedrock-output-config
  • Post resolved changes as copyable diffs in a comment

No actionable comments were generated in the recent review. 🎉


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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🤖 Fix all issues with AI agents
In `@relay/channel/aws/dto_test.go`:
- Around line 13-36: This test relies on implicit defaults causing
buildAwsRequestBody(nil, ...) to avoid calling common.GetRequestBody(c); make
the behavior explicit by populating the
RelayInfo.ChannelMeta.ChannelSetting.PassThroughBodyEnabled field in the
RelayInfo passed to buildAwsRequestBody (set it to false if you intend to
exercise the non-passthrough path), or if you want to test the passthrough
branch set PassThroughBodyEnabled to true and pass a mocked/non-nil gin.Context
and stub common.GetRequestBody; update the test to set
relaycommon.RelayInfo.ChannelMeta.ChannelSetting.PassThroughBodyEnabled
accordingly to avoid nil gin.Context panics when buildAwsRequestBody or
common.GetRequestBody are invoked.
🧹 Nitpick comments (1)
dto/claude.go (1)

246-252: Consider extracting the duplicated FileSource construction into a helper.

The same URL-vs-base64 branching logic appears identically in both the system-media block (lines 246-252) and the message-media block (lines 284-290). A small helper (e.g., newFileSourceFromClaudeSource(data string, mediaType string) *types.FileSource) would reduce duplication and make future changes less error-prone.

The actual fix — passing media.Source.MediaType to NewBase64FileSource — looks correct.

♻️ Proposed helper extraction
// Add near the top of the file or in a shared util
func newImageFileMeta(data, mediaType string) *types.FileMeta {
	var src *types.FileSource
	if strings.HasPrefix(data, "http://") || strings.HasPrefix(data, "https://") {
		src = types.NewURLFileSource(data)
	} else {
		src = types.NewBase64FileSource(data, mediaType)
	}
	return &types.FileMeta{FileType: types.FileTypeImage, Source: src}
}

Then both call sites simplify to:

 if data != "" {
-    var fileSource *types.FileSource
-    if strings.HasPrefix(data, "http://") || strings.HasPrefix(data, "https://") {
-        fileSource = types.NewURLFileSource(data)
-    } else {
-        fileSource = types.NewBase64FileSource(data, media.Source.MediaType)
-    }
-    fileMeta = append(fileMeta, &types.FileMeta{FileType: types.FileTypeImage, Source: fileSource})
+    fileMeta = append(fileMeta, newImageFileMeta(data, media.Source.MediaType))
 }

Also applies to: 284-290

Address CodeRabbit review: make test intent explicit by setting
PassThroughBodyEnabled: false instead of relying on zero-value default.
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.

1 participant