fix(anthropicapi): carry top_p/user in typed fields + architecture-review quick wins#472
Conversation
/v1/messages ingress wrote top_p and metadata.user_id into ExtraFields even though core.ChatRequest has typed TopP and User fields. Wire output was identical, but internal consumers of the typed fields (Responses lowering, compatible-provider user copy) saw zero values for Anthropic-dialect traffic, and the split armed the duplicate-JSON-key hazard in the extras merge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- providers.IsValidClientRequestID replaces three verbatim copies in the openai, openrouter, and azure packages; its table test moves next to it. - Remove dead responsecache.CacheTypeBoth (possible-refactoring #1) and the unreferenced circuitBreaker.Allow(). - Rename gateway/refactor_findings_test.go to edge_cases_test.go so the file is named for its content, not the review session that produced it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed files - docs/dev/2026-07-04_architecture-review.md: full findings with file:line evidence, blast-radius analysis, and a sequenced refactoring roadmap. - CLAUDE.md: guardrail definitions are persisted in the guardrail_definitions store with admin CRUD; config.yaml only seeds it (was described as config-only). - .gitattributes: mark checked-in swagger artifacts linguist-generated so the 8k-line docs.go collapses in review diffs. - possible-refactoring.md: mark item 1 (CacheTypeBoth) done. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
Warning Review limit reached
Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR consolidates client request-ID validation into a shared providers.IsValidClientRequestID helper used by azure, openai, and openrouter, propagates top_p/user into typed core.ChatRequest fields in Anthropic request translation, removes dead code (circuitBreaker.Allow, CacheTypeBoth), and adds documentation. ChangesProvider Request-ID Validation
Anthropic Request Typed Fields
Dead Code Removal
Documentation
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Provider as "azure/openai/openrouter setHeaders"
participant Shared as "providers.IsValidClientRequestID"
Provider->>Shared: ValidateRequestID(requestID)
Shared-->>Provider: valid bool
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/dev/2026-07-04_architecture-review.md`:
- Around line 142-149: The architecture review note still presents the Anthropic
typed-field gap as unresolved, but this branch already fixes it, so update the
affected finding around the Anthropic request handling and any related follow-up
sections to reflect current branch state. Either remove the stale issue or
rewrite it as historical context, and make sure references to
`anthropicapi/request.go`, `core.ChatRequest.TopP`, `core.ChatRequest.User`,
`providers/responses_adapter.go`, and `providers/openai/compatible_provider.go`
no longer imply an open bug.
In `@internal/providers/auth_headers_test.go`:
- Line 6: Add table-driven test coverage for embedded control characters in the
auth header value handling, since the current cases only verify length and
multi-byte/emoji rejection. Update the relevant tests in the auth header test
suite to include inputs such as a CRLF-injection string and a NUL-byte string,
and assert they are rejected by the validation logic used in auth_headers.go.
Keep the new cases alongside the existing boundary tests so the mismatch between
the doc comment and implementation is covered.
In `@internal/providers/auth_headers.go`:
- Around line 29-42: The IsValidClientRequestID helper currently only excludes
bytes above 127, so it still accepts control characters and DEL instead of
matching the printable ASCII contract. Update the validation in
IsValidClientRequestID to allow only the printable range used for forwarded
request IDs (0x20 through 0x7E), while keeping the existing length check and
using the same loop over id bytes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 67d8d133-8847-40aa-ab48-c14988240e5e
📒 Files selected for processing (15)
.gitattributesCLAUDE.mddocs/dev/2026-07-04_architecture-review.mddocs/dev/possible-refactoring.mdinternal/anthropicapi/request.gointernal/anthropicapi/request_test.gointernal/gateway/edge_cases_test.gointernal/llmclient/circuit_breaker.gointernal/providers/auth_headers.gointernal/providers/auth_headers_test.gointernal/providers/azure/azure.gointernal/providers/openai/openai.gointernal/providers/openai/openai_test.gointernal/providers/openrouter/openrouter.gointernal/responsecache/semantic.go
💤 Files with no reviewable changes (3)
- internal/responsecache/semantic.go
- internal/providers/openai/openai_test.go
- internal/llmclient/circuit_breaker.go
| **[BUG] `/v1/messages` ingress bypasses typed IR fields.** | ||
| `anthropicapi/request.go:443–460` writes `top_p` and `user` into `ExtraFields` | ||
| even though `core.ChatRequest` has typed `TopP` (`types.go:26`) and `User` | ||
| (`types.go:37`). Wire output is correct (merged at marshal), but internal readers | ||
| of the typed fields see zero values — `providers/responses_adapter.go:46` and | ||
| `providers/openai/compatible_provider.go:330` copy `req.User`, and any future | ||
| consumer of `req.TopP` silently misses Anthropic-dialect traffic. One field, two | ||
| channels, chosen per-ingress. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Refresh findings that this branch already resolves.
These sections still describe the Anthropic typed-field gap and the CacheTypeBoth / circuitBreaker.Allow() removals as open work, but the PR stack already lands those fixes. Please convert them to historical notes or remove them so the document matches current branch state.
Also applies to: 501-507, 520-522
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/dev/2026-07-04_architecture-review.md` around lines 142 - 149, The
architecture review note still presents the Anthropic typed-field gap as
unresolved, but this branch already fixes it, so update the affected finding
around the Anthropic request handling and any related follow-up sections to
reflect current branch state. Either remove the stale issue or rewrite it as
historical context, and make sure references to `anthropicapi/request.go`,
`core.ChatRequest.TopP`, `core.ChatRequest.User`,
`providers/responses_adapter.go`, and `providers/openai/compatible_provider.go`
no longer imply an open bug.
…tion IsValidClientRequestID documented a printable-ASCII contract but accepted any byte <= 127, letting control characters and DEL through; a control byte in a header value makes Go's transport reject the whole outbound request. Restrict to 0x20-0x7E and cover control/NUL/tab/DEL cases in the table test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
First batch of fixes from a full architecture review (the review itself is included at
docs/dev/2026-07-04_architecture-review.md).Bug fix
/v1/messagesingress wrotetop_pandmetadata.user_idintoExtraFieldseven thoughcore.ChatRequesthas typedTopP/Userfields. Wire output was identical, but internal consumers of the typed fields (Responses-via-chat lowering, the compatible provider'susercopy) saw zero values for Anthropic-dialect traffic, and the two-channel split armed the duplicate-JSON-key hazard in the extras merge. They now land in the typed fields;stopstays inExtraFields(no typed equivalent).User-visible impact
top_p/userkeys for OpenAI-family providers, and the Anthropic egress adapter already preferred the typedTopP(it ignores auserextra either way). Requests that lower/v1/messagesinto the Responses path now correctly carryuser.Cleanups
providers.IsValidClientRequestIDreplaces three verbatim copies (openai/openrouter/azure); its table test moved next to it.responsecache.CacheTypeBoth(possible-refactoring Basic project scaffold with: chat completion, streaming and models endpoints from OpenAI #1) and unreferencedcircuitBreaker.Allow().gateway/refactor_findings_test.go→edge_cases_test.go(name the content, not the session).Docs
guardrail_definitionsstore with admin CRUD;config.yamlonly seeds it..gitattributesmarks the checked-in swagger artifactslinguist-generatedso the 8k-linedocs.gocollapses in review diffs.Testing
go build ./..., fullgo test ./..., andgolangci-lint(0 issues) pass; pre-commitmake test-raceran on each commit.TestToChatRequestExtraFieldsupdated to pin the typed-field behavior and asserttop_p/userno longer ride inExtraFields.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation