fix(claude): convert web_search tools for Claude relay - #4771
Conversation
WalkthroughThe PR implements web-search tool detection and conversion in ChangesClaude Web-Search Tool Conversion
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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.
Actionable comments posted: 1
🤖 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 `@dto/openai_request.go`:
- Around line 236-241: Change the optional string scalars Name and
SearchContextSize in the OpenAI request DTO to pointer types (*string) so absent
vs empty values are preserved; update any code that reads or writes these fields
(notably conversion/usage in relay-claude.go such as
webSearchMaxUsesFromContextSize and any places accessing Name) to check for nil
and dereference safely, and adjust marshaling/unmarshaling logic accordingly to
maintain omitempty behavior.
🪄 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: CHILL
Plan: Pro
Run ID: fc868899-9f97-491a-a86d-6f14d7beb427
📒 Files selected for processing (5)
dto/claude.godto/openai_request.gorelay/channel/claude/relay-claude.gorelay/channel/claude/relay_claude_test.gorelay/channel/vertex/dto_test.go
| Name string `json:"name,omitempty"` | ||
| MaxUses *int `json:"max_uses,omitempty"` | ||
| AllowedDomains []string `json:"allowed_domains,omitempty"` | ||
| BlockedDomains []string `json:"blocked_domains,omitempty"` | ||
| SearchContextSize string `json:"search_context_size,omitempty"` | ||
| UserLocation json.RawMessage `json:"user_location,omitempty"` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Consider using pointer types for optional string fields.
The coding guideline states: "Optional scalar fields in request structs parsed from client JSON and re-marshaled to upstream providers MUST use pointer types with omitempty tags to preserve explicit zero values and distinguish between absent and zero-valued fields."
Name and SearchContextSize are string scalars with omitempty, but are not pointer types. If these fields are truly optional (which appears to be the case from the test coverage), they should be *string to comply with the guideline and allow distinguishing between absent fields and empty strings.
As per coding guidelines, optional scalar fields in relay DTO paths must use pointer types to preserve absent vs zero-value distinction.
♻️ Proposed fix
// Claude server-side web search tool 参数。OpenAI 兼容请求里可能直接传
// web_search / web_search_preview / web_search_20250305,转换 Claude 请求时需要保留。
- Name string `json:"name,omitempty"`
+ Name *string `json:"name,omitempty"`
MaxUses *int `json:"max_uses,omitempty"`
AllowedDomains []string `json:"allowed_domains,omitempty"`
BlockedDomains []string `json:"blocked_domains,omitempty"`
- SearchContextSize string `json:"search_context_size,omitempty"`
+ SearchContextSize *string `json:"search_context_size,omitempty"`
UserLocation json.RawMessage `json:"user_location,omitempty"`Note: This change would require updating the conversion logic in relay-claude.go to handle the pointer types, particularly in webSearchMaxUsesFromContextSize and any Name field access.
🤖 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 `@dto/openai_request.go` around lines 236 - 241, Change the optional string
scalars Name and SearchContextSize in the OpenAI request DTO to pointer types
(*string) so absent vs empty values are preserved; update any code that reads or
writes these fields (notably conversion/usage in relay-claude.go such as
webSearchMaxUsesFromContextSize and any places accessing Name) to check for nil
and dereference safely, and adjust marshaling/unmarshaling logic accordingly to
maintain omitempty behavior.
8c5eafb to
86f2708
Compare
Co-authored-by: Talon <talon@users.noreply.github.com>
86f2708 to
5302a34
Compare
|
补充说明一下本 PR 的验证边界,方便 review:
|
Important
📝 变更描述 / Description
修复 OpenAI 兼容 Chat Completions 请求里直接传入 Claude web search tool 时没有被转换的问题。
当前
RequestOpenAI2ClaudeMessage只处理 function tool 和web_search_options。如果客户端传tools: [{"type":"web_search"}]、web_search_preview或web_search_20250305,这些 tool 会被当作非 function tool 跳过,最终没有传给 Claude。这个 PR 只做最小转换:
web_search_20250305server tool。web_search_options注入第二个搜索工具,避免重复。ToolCallRequestDTO 结构。🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
本地 Go 版本:
go version go1.25.1 linux/amd64通过:
git diff --checkgo test ./relay/channel/claude -run 'TestRequestOpenAI2ClaudeMessage_(ConvertsClaudeWebSearchTool|ConvertsWebSearchOptions|DoesNotDuplicateWebSearchTool)' -count=1 -vgo test ./relay/channel/vertex -run TestCopyRequestPreservesClaudeWebSearchTools -count=1 -vgo test ./dto ./service -count=1真实端到端验证:
claude-sonnet-4-6普通/v1/chat/completions:HTTP 200,返回NEW_API_VERTEX_CLAUDE_OK。claude-sonnet-4-6+tools: [{"type":"web_search"}]:HTTP 200;本地 New API 计费日志记录web_search=true、web_search_call_count=1。claude-sonnet-4-6+web_search_options:HTTP 200;本地 New API 计费日志记录web_search_call_count=1。claude-sonnet-4-6同时带tools: [{"type":"web_search_preview"}]和web_search_options:HTTP 200;本地 New API 计费日志记录web_search_call_count=1,确认不会重复注入搜索工具。claude-opus-4-7普通请求:HTTP 200,返回NEW_API_VERTEX_OPUS_OK。claude-opus-4-7+tools: [{"type":"web_search"}]+tool_choice: "required":HTTP 200;本地 New API 计费日志记录web_search=true、web_search_call_count=1。claude-sonnet-4-6+tool_choice: "required"返回正文包含searched=yes; source=GitHub - QuantumNous/new-api...; url=https://github.com/QuantumNous/new-api,同时日志记录web_search_call_count=1。补充说明:
claude-opus-4-7如果传temperature,Vertex Claude 返回temperature is deprecated for this model;去掉temperature后正常。这是模型参数约束,不是本 PR 引入的问题。go test ./...已运行,当前失败项为既有测试状态:relay/channel/claude下 3 条文件内容转换测试,以及relay/helper的TestStreamScannerHandler_StreamStatus_PreInitialized。本 PR 新增和相关测试均已单独通过。Summary by CodeRabbit
Bug Fixes
Tests