feat(xai): enable hosted web search for Grok OAuth#71
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request introduces support for the Grok CLI subscription proxy (the Grok flavor) to enable end-to-end hosted web search tool capabilities, translating Grok's search calls, results, and citations into Anthropic-compatible formats. It updates documentation, configuration, request translation, and adds corresponding integration tests. The code review feedback suggests improving annotation_added in src/model/responses.rs by ensuring a text block is active before appending citations to prevent potential protocol errors.
There was a problem hiding this comment.
All reported issues were addressed across 6 files
Architecture diagram
sequenceDiagram
participant Client as Anthropic Client
participant GW as shunt Gateway
participant Cfg as Config (flavor detection)
participant Req as Request Translator
participant SSE as SSE State Machine
participant Grok as Grok CLI Proxy (grok.com)
participant Xai as xAI API (api.x.ai)
Note over Client,Xai: Hosted web_search flow for Grok OAuth subscription
Client->>GW: POST /responses (tools: [web_search], tool_choice: forced web_search)
GW->>Cfg: responses_flavor(auth=xai_oauth)
Cfg-->>GW: ResponsesFlavor::Grok
alt Grok flavor (OAuth subscription)
GW->>Req: translate_request (flavor=Grok, include web_search)
Req->>Req: Keep web_search tool, map tool_choice to {"type": "web_search"}
Req->>Req: Skip OpenAi-Beta header
Req-->>GW: Shaped request with hosted web_search tool
GW->>Grok: Forward request (with x-grok-cli identity headers)
Grok-->>GW: SSE events: web_search_call, url_citation, text...
GW->>SSE: apply events
SSE->>SSE: web_search_call -> server_tool_use + web_search_tool_result blocks
SSE->>SSE: url_citation -> citations_delta with encrypted_index mapping
SSE-->>GW: Translated Anthropic SSE events
GW-->>Client: Anthropic-formatted response
else Xai flavor (api.x.ai, API key)
GW->>Req: translate_request (flavor=Xai, drop web_search)
Req->>Req: Remove web_search tool from tools array
Req->>Req: Downgrade forced web_search tool_choice to "auto"
Req->>Req: Skip OpenAi-Beta header
Req-->>GW: Shaped request without hosted tools
GW->>Xai: Forward request
Xai-->>GW: SSE events (no web_search_call)
GW->>SSE: apply events
SSE-->>GW: Standard text/reasoning events only
GW-->>Client: Anthropic response (no search tool)
end
Note over SSE: Encrypted index mapping from web_search results to url_citation annotations
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Greptile SummaryThis PR introduces a dedicated
Confidence Score: 5/5Safe to merge — the flavor split is table-driven and narrowly scoped to grok.com OAuth hosts, leaving all other providers untouched. The No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant CC as Claude Code
participant SH as shunt (Grok flavor)
participant GK as Grok CLI Proxy
CC->>SH: POST /v1/messages (with web_search tool)
SH->>GK: POST /responses (web_search tool forwarded)
GK-->>SH: response.output_item.added (web_search_call)
Note over SH: ignored (processing deferred to done)
GK-->>SH: response.output_item.done (web_search_call + results)
SH->>SH: close_any(), build web_search_indexes map
SH-->>CC: content_block_start (server_tool_use)
SH-->>CC: content_block_stop
SH-->>CC: content_block_start (web_search_tool_result)
SH-->>CC: content_block_stop
GK-->>SH: response.output_item.added (message)
SH-->>CC: content_block_start (text)
GK-->>SH: response.output_text.delta
SH-->>CC: content_block_delta (text_delta)
GK-->>SH: response.output_text.annotation.added (url_citation)
SH->>SH: lookup encrypted_index from web_search_indexes
SH-->>CC: content_block_delta (citations_delta)
GK-->>SH: response.output_text.done
SH-->>CC: content_block_stop
GK-->>SH: response.completed (usage)
SH-->>CC: message_delta (stop_reason: end_turn)
SH-->>CC: message_stop
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant CC as Claude Code
participant SH as shunt (Grok flavor)
participant GK as Grok CLI Proxy
CC->>SH: POST /v1/messages (with web_search tool)
SH->>GK: POST /responses (web_search tool forwarded)
GK-->>SH: response.output_item.added (web_search_call)
Note over SH: ignored (processing deferred to done)
GK-->>SH: response.output_item.done (web_search_call + results)
SH->>SH: close_any(), build web_search_indexes map
SH-->>CC: content_block_start (server_tool_use)
SH-->>CC: content_block_stop
SH-->>CC: content_block_start (web_search_tool_result)
SH-->>CC: content_block_stop
GK-->>SH: response.output_item.added (message)
SH-->>CC: content_block_start (text)
GK-->>SH: response.output_text.delta
SH-->>CC: content_block_delta (text_delta)
GK-->>SH: response.output_text.annotation.added (url_citation)
SH->>SH: lookup encrypted_index from web_search_indexes
SH-->>CC: content_block_delta (citations_delta)
GK-->>SH: response.output_text.done
SH-->>CC: content_block_stop
GK-->>SH: response.completed (usage)
SH-->>CC: message_delta (stop_reason: end_turn)
SH-->>CC: message_stop
Reviews (2): Last reviewed commit: "fix(xai): harden web search response blo..." | Re-trigger Greptile |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for the Grok CLI subscription proxy (ResponsesFlavor::Grok), enabling end-to-end translation of the hosted web_search tool and its associated citations into Anthropic-compatible blocks (server_tool_use, web_search_tool_result, and citation blocks). The review feedback highlights two robustness issues in src/model/responses.rs: first, removing null title or cited_text fields from citations could violate the Anthropic API spec, so defaulting them to empty strings is recommended; second, the content field in web_search_tool_result could receive a null value if the search results are null, so a fallback to an empty array should be enforced.
|
/gemini review |
|
There was a problem hiding this comment.
Code Review
이 풀 리퀘스트는 Grok CLI 구독 프록시를 지원하기 위해 새로운 Grok ResponsesFlavor를 도입하고, 호스팅된 web_search 도구 및 URL 인용(citation) 데이터를 Anthropic 규격(server_tool_use, web_search_tool_result, 인용 블록)으로 변환하는 기능을 구현합니다. 이를 위해 AnthropicSseMachine에 인용 및 웹 검색 인덱싱 상태 관리 로직을 추가하고, 요청 변환 시 Grok flavor에 대해 웹 검색 도구를 유지하도록 처리했습니다. 관련 문서와 통합 테스트도 충실히 추가되었습니다. 제공된 리뷰 댓글이 없으므로 코드 변경 사항에 대한 추가 피드백은 없습니다.



Summary
web_searchtools and forced choices only for the verified Grok OAuth surfaceweb_search_calloutput, results, and URL annotations into Anthropic server-tool, result, and citation eventsapi.x.aibehaviorTesting
cargo test --all-features --workspacecargo clippy --all-targets --all-features -- -D warningscargo fmt --all --checkgit diff --checkLive validation
A local live probe was not run because neither
XAI_API_KEYnor a Grok OAuth credential is available in this worktree. The request and response wire behavior is covered by focused fixtures based on the live event sequence recorded in the issue.Closes #61
Summary by cubic
Enables hosted
web_searchfor Grok OAuth (Grok CLI proxy) and translates Grok search calls, results, and URL citations into Anthropic tool and citation events. Keeps theapi.x.aideveloper API unchanged and documents separate hosted-search billing; also hardens the streaming mapper for web search edge cases. Addresses #61.New Features
ResponsesFlavor::Grok(detected whenauth = xai_oauthtargetsgrok.com); keptXaiforapi.x.ai.web_searchtool and forced choice only forgrok; drop onxaiand downgrade choice toauto.web_search_callintoserver_tool_useandweb_search_tool_result; mapresponse.output_text.annotation.addedurl_citationto Anthropic citation deltas, propagatingencrypted_indexfrom results and opening a text block if needed.OpenAI-Beta: responses=experimentalfor bothXaiandGrok.Bug Fixes
resultsas[]; supportid/call_idandaction/input.encrypted_content→encrypted_indexmapping per-URL; omitencrypted_indexwhen missing.Written for commit 4bf9df6. Summary will update on new commits.