Skip to content

Support Claude Code web search when transforming to OpenAI-format providers #3

Description

@guo

Description

Claude Code's web search tool does not work when ccrouter transforms Anthropic requests to OpenAI-format endpoints (e.g. GPT/Codex). The transformer currently has no explicit handling for web_search / search_result / search-specific content or tool types, and unknown content blocks are silently dropped.

Context

Current transform behavior (src/transform.rs, src/stream.rs, src/handler.rs):

Works

  • text + image content
  • standard Anthropic tools → OpenAI function tools
  • assistant tool_use ↔ OpenAI tool_calls
  • user tool_result ↔ OpenAI role: "tool"
  • streamed tool-call assembly back into Anthropic SSE

Missing / likely breakpoints for web search

  • convert_content_parts() only preserves text and image; any other block type is dropped
  • all Anthropic tools are forced into OpenAI {type: "function", ...} shape
  • non-stream response conversion only understands string message.content and tool_calls
  • stream conversion only understands text deltas and tool-call deltas
  • transformed profiles hard-coded to POST {base_url}/chat/completions
  • no tests covering any of this

Assessment

  • Research difficulty: medium/high — mostly because protocol evidence is missing, not because the code is hard
  • Generic translation across OpenAI-compatible providers: not realistic yet. Web search is one of the least standardized areas; support likely needs to be provider-specific
  • Pass-through Anthropic profiles are unaffected (feature already works end-to-end with any Anthropic-compatible upstream)

Proposed approach

Two phases.

Phase 1 — fail fast (small, safe)

  • detect search-related Anthropic constructs in the request
  • if active profile is format = \"openai\" and no search adapter exists, return a clear error instead of silently stripping fields
  • document the limitation in README

Phase 2 — provider-specific adapters (after capturing real traffic)

  • extend Profile in src/config.rs with capability fields (endpoint family, search support mode)
  • split to_openai_request into a generic base + capability-specific post-processing
  • extend non-stream + stream response conversion to carry search/citation output back to Claude Code
  • make endpoint selection per-profile in src/handler.rs so providers that only expose search on a non-chat endpoint (e.g. /responses) can be supported

Evidence needed before Phase 2

Protocol captures on both sides:

  • real Claude Code /v1/messages request with web search enabled (non-stream)
  • full SSE transcript of the same request streaming
  • exact request/response shape on the target GPT/Codex endpoint (does search live on /chat/completions, /responses, or provider-specific?)
  • failure payload when search is unsupported on the chosen model/endpoint

Acceptance criteria

  • Phase 1: OpenAI-format profiles return an explicit error (not silent stripping) when a Claude Code request includes search-related fields
  • Phase 1: README documents current web-search support (pass-through only)
  • Phase 2: at least one OpenAI-compatible provider adapter supports web search end-to-end
  • Phase 2: fixture-based request/response/SSE tests cover the adapter
  • Phase 2: manual verification passes against Claude Code (control: Anthropic pass-through; transformed: supported adapter)

Critical files (for reference)

  • src/transform.rs
  • src/stream.rs
  • src/handler.rs
  • src/config.rs
  • README.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions