Repository navigation
fix(anthropic): accept server-side tools on /v1/messages - #2702
Conversation
The native Anthropic /v1/messages endpoint validated every tool against a custom-tool schema requiring `description` and `input_schema`, so server-side tools like web_search_20250305 (which carry a versioned `type` and neither field) were rejected with a ZodError before reaching a provider. Accept Anthropic server-side tools via a union schema and translate web_search tools into the internal `web_search` tool the chat completions endpoint already forwards to Anthropic as web_search_20250305. Unsupported server tools are dropped with a warning rather than rejecting the request. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 11 minutes and 11 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
WalkthroughThe PR extends the Anthropic gateway tool pipeline to support server-side tools (e.g., ChangesAnthropic Server-Side Tool Support
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3dd02c4162
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (tool.type.startsWith("web_search")) { | ||
| return { | ||
| type: "web_search", | ||
| ...(tool.max_uses !== undefined ? { max_uses: tool.max_uses } : {}), | ||
| ...(tool.user_location | ||
| ? { user_location: tool.user_location } | ||
| : {}), | ||
| }; |
There was a problem hiding this comment.
Preserve server web_search settings
When a native /v1/messages request includes Anthropic's web search tool with allowed_domains/blocked_domains or the newer web_search_20260209 type, this branch collapses it to the generic chat web_search object. Downstream prepareRequestBody for Anthropic always re-emits web_search_20250305 and only copies max_uses, so accepted requests can silently lose domain constraints and downgrade dynamic filtering before reaching Anthropic.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
apps/gateway/src/api.spec.ts (2)
5163-5168: 💤 Low valueConsider verifying field preservation in the forwarded tool.
The test checks that the forwarded tool has
type: "web_search_20250305", but doesn't verify thatmax_uses(sent at line 5151) is preserved. For more robust coverage, consider adding an assertion like:const webSearchTool = forwardedTools.find( (t: { type?: string }) => t.type === "web_search_20250305", ); expect(webSearchTool).toBeDefined(); expect(webSearchTool.max_uses).toBe(3);🤖 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 `@apps/gateway/src/api.spec.ts` around lines 5163 - 5168, The current test assertion only verifies that a tool with type "web_search_20250305" exists in the forwardedTools array but does not verify that the max_uses field is preserved during forwarding. Enhance the test by finding the specific tool with type "web_search_20250305" using an additional find call, then add assertions to verify both that the tool is defined and that its max_uses property equals 3 (matching the value set at line 5151).
5196-5198: 💤 Low valueConsider verifying the error message content.
The test confirms that a malformed custom tool is rejected with a 400 status, but doesn't verify the error message mentions the missing
input_schema. For more robust coverage, consider adding:expect(res.status).toBe(400); const json = await res.json(); expect(JSON.stringify(json)).toContain("input_schema");🤖 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 `@apps/gateway/src/api.spec.ts` around lines 5196 - 5198, The test for malformed custom tool rejection only verifies the HTTP status code is 400 but doesn't validate that the error message specifically mentions the missing "input_schema" field. Enhance the test by adding assertions that parse the response JSON and confirm the error message contains the string "input_schema" to provide more robust coverage of the validation logic. This ensures the API not only rejects invalid input with the correct status code but also returns meaningful error details to the client.
🤖 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.
Nitpick comments:
In `@apps/gateway/src/api.spec.ts`:
- Around line 5163-5168: The current test assertion only verifies that a tool
with type "web_search_20250305" exists in the forwardedTools array but does not
verify that the max_uses field is preserved during forwarding. Enhance the test
by finding the specific tool with type "web_search_20250305" using an additional
find call, then add assertions to verify both that the tool is defined and that
its max_uses property equals 3 (matching the value set at line 5151).
- Around line 5196-5198: The test for malformed custom tool rejection only
verifies the HTTP status code is 400 but doesn't validate that the error message
specifically mentions the missing "input_schema" field. Enhance the test by
adding assertions that parse the response JSON and confirm the error message
contains the string "input_schema" to provide more robust coverage of the
validation logic. This ensures the API not only rejects invalid input with the
correct status code but also returns meaningful error details to the client.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 930a17e7-a984-4546-9c11-60655dd13d6b
📒 Files selected for processing (2)
apps/gateway/src/anthropic/anthropic.tsapps/gateway/src/api.spec.ts
Addresses Codex PR feedback: server web_search tools sent to /v1/messages with allowed_domains/blocked_domains or user_location were accepted but silently dropped, because the internal WebSearchTool and the Anthropic prepareRequestBody only carried max_uses. Thread allowed_domains, blocked_domains, and user_location through the WebSearchTool type, the chat completions schema, tool extraction, and the Anthropic provider request (re-emitting user_location with the required `type: "approximate"`). Harden the /v1/messages tests to assert max_uses, domain filters, and user_location survive the round-trip, and that a custom tool missing input_schema is rejected with an input_schema error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Addressed the Codex P2 in 4d6ff90: The |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4d6ff90c8f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (tool.type.startsWith("web_search")) { | ||
| return { | ||
| type: "web_search", | ||
| ...(tool.max_uses !== undefined ? { max_uses: tool.max_uses } : {}), |
There was a problem hiding this comment.
Preserve Anthropic web-search response blocks
When a native /v1/messages request reaches this branch and Claude actually performs a web search, Anthropic returns server_tool_use / web_search_tool_result content blocks and text citations in the Messages response (docs). The inner chat path converts those into OpenAI-style text plus message.annotations, but the outer /v1/messages response builder only reconstructs content from message.content and tool_calls, so citations and encrypted search-result content are dropped; Anthropic clients lose the source data needed for display and multi-turn search conversations.
Useful? React with 👍 / 👎.
| // These are executed by Anthropic, carry a versioned `type` instead of an | ||
| // `input_schema`, and must not be validated as custom tools. | ||
| const anthropicServerToolSchema = z.object({ | ||
| type: z.string(), |
There was a problem hiding this comment.
Reject explicit custom tools missing schemas
Because the server-tool schema accepts any string type, a request like tools: [{ type: "custom", name: "get_weather", description: "..." }] no longer fails validation for the missing input_schema: it misses the custom-tool union arm, matches this server-tool arm, and is then silently dropped as an unsupported server tool. This regresses malformed custom-tool validation for clients that include the explicit type: "custom" field that this same schema allows for valid custom tools.
Useful? React with 👍 / 👎.
## Problem
The native Anthropic `/v1/messages` endpoint rejected valid requests
that included Anthropic **server-side tools** (e.g.
`web_search_20250305`). Sending Anthropic's documented web search
request:
```json
{
"model": "claude-sonnet-4-6",
"max_tokens": 4096,
"messages": [{ "role": "user", "content": "Search the web ..." }],
"tools": [{ "type": "web_search_20250305", "name": "web_search", "max_uses": 3 }]
}
```
returned a `ZodError`:
```json
{"success":false,"error":{"issues":[
{"code":"invalid_type","path":["tools",0,"description"],"message":"Required"},
{"code":"invalid_type","path":["tools",0,"input_schema"],"message":"Required"}
],"name":"ZodError"}}
```
The same request works when sent directly to `api.anthropic.com`.
## Root cause
The endpoint's tool schema (`anthropicToolSchema`) required
`description` **and** `input_schema` on **every** tool. Server-side
tools carry a versioned `type` and have neither field, so validation
failed before the request ever reached a provider.
## Fix
- Split the tool schema into a union: standard **custom tools** (`name`
+ `input_schema`) and Anthropic **server-side tools** (`type` + `name` +
optional config like `max_uses`, `user_location`, `allowed_domains`).
- In the Anthropic → OpenAI translation, map `web_search*` server tools
to the internal `web_search` tool that the chat completions endpoint
already forwards to Anthropic as `web_search_20250305` (preserving
`max_uses`/`user_location`).
- Unsupported server tools are dropped with a warning rather than
rejecting the whole request.
## Tests
Added two unit tests in `apps/gateway/src/api.spec.ts`:
- A `web_search_20250305` server tool passes validation and is forwarded
to the Anthropic provider as a native `web_search_20250305` tool.
- A malformed custom tool (missing `input_schema`) is still rejected
with `400`.
`pnpm build`, `pnpm format`, and the new tests all pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **New Features**
* Added support for Anthropic native server-side tools (such as web
search) alongside custom tools
* Enhanced tool configuration with additional parameters including
allowed domains, blocked domains, and user location settings
* **Tests**
* Added comprehensive test coverage for server-side tool handling and
custom tool validation
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem
The native Anthropic
/v1/messagesendpoint rejected valid requests that included Anthropic server-side tools (e.g.web_search_20250305). Sending Anthropic's documented web search request:{ "model": "claude-sonnet-4-6", "max_tokens": 4096, "messages": [{ "role": "user", "content": "Search the web ..." }], "tools": [{ "type": "web_search_20250305", "name": "web_search", "max_uses": 3 }] }returned a
ZodError:{"success":false,"error":{"issues":[ {"code":"invalid_type","path":["tools",0,"description"],"message":"Required"}, {"code":"invalid_type","path":["tools",0,"input_schema"],"message":"Required"} ],"name":"ZodError"}}The same request works when sent directly to
api.anthropic.com.Root cause
The endpoint's tool schema (
anthropicToolSchema) requireddescriptionandinput_schemaon every tool. Server-side tools carry a versionedtypeand have neither field, so validation failed before the request ever reached a provider.Fix
name+input_schema) and Anthropic server-side tools (type+name+ optional config likemax_uses,user_location,allowed_domains).web_search*server tools to the internalweb_searchtool that the chat completions endpoint already forwards to Anthropic asweb_search_20250305(preservingmax_uses/user_location).Tests
Added two unit tests in
apps/gateway/src/api.spec.ts:web_search_20250305server tool passes validation and is forwarded to the Anthropic provider as a nativeweb_search_20250305tool.input_schema) is still rejected with400.pnpm build,pnpm format, and the new tests all pass.🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Tests