Skip to content

fix(xai): stop stripping web_search fields xAI accepts - #2422

Merged
Ingwannu merged 2 commits into
lidge-jun:devfrom
olddonkey:fix/xai-web-search-overstrip
Aug 23, 2026
Merged

fix(xai): stop stripping web_search fields xAI accepts#2422
Ingwannu merged 2 commits into
lidge-jun:devfrom
olddonkey:fix/xai-web-search-overstrip

Conversation

@olddonkey

@olddonkey olddonkey commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

What

normalizeXaiResponsesWebSearch deleted user_location and search_content_types from every xAI web_search declaration. Both are accepted by the upstream, so this was a silent capability loss on the API-key path — a caller's location hint and content-type selection never reached the model.

It also contradicted the sibling layer. stripOpenAiOnlyWebSearchFields removes exactly the two fields xAI refuses and deliberately keeps user_location/filters, with a probe note in tests/responses-routed-web-search-fields.test.ts recording them as accepted. The two layers disagreed about the same field, and the normalizer runs first, so it won.

Evidence

Probed 2026-08-22, one field per request, against both xAI destinations — api.x.ai and cli-chat-proxy.grok.com — which behave identically:

field verdict
external_web_access 400 Argument not supported — on every value, including true
search_context_size 400 Argument not supported
user_location 200
search_content_types 200
filters 200
enable_image_search 200

So only the two refused fields are removed now.

The search_content_types:["image"] -> enable_image_search mapping is kept. It compensated for a deletion that no longer happens, so it is arguably redundant, but removing it would be a separate behavior change and is out of scope here.

Tests

Two assertions in tests/responses-routed-web-search-fields.test.ts over-specified the result as a bare {type:"web_search"} while that same file's probe note says user_location is accepted. They now assert it is preserved. tests/xai-web-search-compat.test.ts is updated for the same reason and its test renamed to say what it actually checks.

Gate

bun test --isolate --parallel ./tests/14246 pass / 5 fail. All five also fail on untouched upstream/dev (baseline run: 6 fail, a superset of mine). Zero regressions.

The suite is flaky — three runs of identical code gave 18, 5 and 6 failures — so this is reported as a set difference against a baseline rather than an absolute count. The failing families (CL-07 task effectiveness, Codex autostart shim, release helper, shellStreamExec) are timing/filesystem sensitive and unrelated to this change.

🤖 Generated with Claude Code

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • Bug Fixes
    • Improved xAI web-search compatibility by preserving supported location, content-type, filter, and image-search settings.
    • Continued removing only unsupported search configuration fields during tool conversion.
    • Ensured consistent behavior for routed and registry-based web-search configurations.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Aug 22, 2026
@github-actions

github-actions Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request has been marked Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently.
Maintainers notified: @lidge-jun @Ingwannu

@github-actions
github-actions Bot marked this pull request as draft August 22, 2026 23:53
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7bf55320-386f-45b0-9d43-0508d8b137ac

📥 Commits

Reviewing files that changed from the base of the PR and between ddaf497 and 415aec6.

📒 Files selected for processing (1)
  • tests/responses-routed-web-search-fields.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The xAI web-search adapter now removes only external_web_access and search_context_size. Compatibility and routing tests verify that user_location, search_content_types, filters, and enable_image_search remain preserved.

Changes

xAI web-search normalization

Layer / File(s) Summary
Preserve supported xAI fields
src/adapters/xai-web-search.ts, tests/xai-web-search-compat.test.ts
The adapter removes only external_web_access and search_context_size. Compatibility expectations retain user_location, search_content_types, and enable_image_search.
Validate routed Responses behavior
tests/responses-routed-web-search-fields.test.ts
Routing tests cover official OpenAI expectations, registry-classified xAI transport, and unclassified transport. They verify that accepted fields remain preserved and that unsupported fields are removed only for registry-classified xAI transport.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: 🟡 Moderate · up to 415ae

The change is narrowly scoped to preserve xAI-supported web-search fields and has no supplied regression signal, but the PR remains draft with all readiness gates unchecked and the reported local suite has five failures; merge readiness therefore remains unconfirmed until those checks are resolved or explicitly accepted.

Suggested reviewers: ingwannu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: preserving web_search fields accepted by xAI.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

`normalizeXaiResponsesWebSearch` deleted `user_location` and
`search_content_types` from every xAI web_search declaration. Both are
accepted by the upstream, so this was a silent capability loss on the
API-key path — a caller's location hint and content-type selection never
reached the model.

It also contradicted the sibling layer: `stripOpenAiOnlyWebSearchFields`
removes exactly the two fields xAI refuses and deliberately KEEPS
user_location/filters, with a probe note recording them as accepted
(tests/responses-routed-web-search-fields.test.ts). The two layers
disagreed about the same field, and the normalizer ran first, so it won.

Probed 2026-08-22, one field per request, against BOTH xAI destinations
(api.x.ai and cli-chat-proxy.grok.com), which behave identically:

  external_web_access   400 on EVERY value, including `true`
  search_context_size   400
  user_location         200
  search_content_types  200
  filters               200
  enable_image_search   200

So only the two refused fields are removed now. The image-search mapping
is kept: it compensates for nothing being deleted anymore, but dropping
it would be a separate behavior change.

Two assertions in responses-routed-web-search-fields.test.ts over-specified
the result as a bare `{type:"web_search"}` while that file's own probe note
says user_location is accepted; they now assert it is preserved.

Gate: 14246 pass / 5 fail, and all five also fail on untouched upstream/dev
(baseline: 6 fail, a superset). Zero regressions. The failing families
(CL-07, autostart shim, release helper, shellStreamExec) are flaky and
unrelated.
@olddonkey
olddonkey force-pushed the fix/xai-web-search-overstrip branch from ddaf497 to 4c6582c Compare August 23, 2026 00:00
@github-actions
github-actions Bot marked this pull request as ready for review August 23, 2026 00:03
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 52 / 80

설명: 이 PR 은 엑스아이 웹검색에서 받아 주는 칸을 지워 버리던 것을 그만둔다. 지금 CURRENT dev HEAD 는 4f41a8e93 이다. 이번 시간에 origin/dev 는 그대로다. 새 머지는 없다. 착지는 여전히 2396 사용량 CLI 오늘 비용이다. package.json 은 2.27.0 이다. src/config.ts 는 3975줄이다. src/runtime 폴더는 지금 HEAD 에 없다. 이 PR 의 베이스는 지금 HEAD 와 같다. 위에 올라간 커밋은 하나다.

지금 HEAD 의 src/adapters/xai-web-search.ts 63줄부터 68줄까지는 웹검색 도구에서 네 칸을 지운다. 바깥 웹 접근, 검색 맥락 크기, 검색 내용 종류, 사용자 위치다. 69줄은 내용 종류에 그림이 있으면 그림검색 켜기를 붙인다. 그래서 호출자가 위치를 넣어도, 글과 그림만 고르라고 해도, 그 값이 모델까지 가지 않는다. 옆 레이어 src/adapters/openai-responses.ts 1506줄 OPENAI_ONLY_WEB_SEARCH_FIELDS 는 바깥 웹 접근과 검색 맥락 크기 두 칸만 지운다. 1496줄 주석은 2026-08-21 조사에서 사용자 위치와 필터는 받아 준다고 적어 두었다. 같은 파일 시험 tests/responses-routed-web-search-fields.test.ts 32줄도 그 조사를 반복한다. 그런데 엑스아이 전용 정규화기가 먼저 돌아가서, 받아 주는 칸까지 지워 버린다. 두 레이어가 같은 칸을 다르게 본다.

이 PR 은 거절하는 두 칸만 지운다. 작성자가 2026-08-22 에 칸마다 하나씩, api.x.ai 와 cli-chat-proxy.grok.com 둘 다에 찔러 보았다. 둘의 답이 같다. 바깥 웹 접근은 참이어도 400 이다. 검색 맥락 크기도 400 이다. 사용자 위치, 검색 내용 종류, 필터, 그림검색 켜기는 200 이다. 그림검색 켜기 매핑은 남긴다. 이제 내용 종류를 안 지우니 겹칠 수 있지만, 빼는 것은 이번 범위가 아니다. 시험 두 파일은 맨몸 웹검색이 아니라 위치를 남긴다고 잠근다. 호환 시험 이름도 거절 칸만 지운다고 바꿨다.

작성자는 olddonkey 이다. 드래프트가 아니다. bug 와 review-ready 라벨이 있다. 체크리스트 네 칸이 채워져 있다. GitHub 위생, 타깃, 라벨, CodeRabbit 은 통과다. 작성자 로컬은 같은 스위트에서 기준선과 비교해 회귀가 없다고 적었다. Closes 가 없다. 이번 시간에 2421 은 머지 없이 닫혔고 2420 도 닫혔다. 사용자 길이로는 위치와 내용 종류가 모델에 안 가는 구멍이라서 52. 카탈로그 팁은 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. Cursor 정적 카탈로그는 opus-4-8-fast / opus-5-fast. 2334 CursorCredentialRouter 는 여전히 src/providers/cursor-pool.ts 모듈+테스트만 있고 어댑터에 연결되지 않았다. 2332 H2 는 discovery 전용. 2320 overflow + 2342 는 이미 dev. 2188 사이드카는 이미 dev. 2382 데스크톱 앱 재시작은 이미 dev. 2292 는 아직 연다.

src/adapters/xai-web-search.ts 라인 63 - 지금 HEAD 는 바깥 웹 접근, 검색 맥락 크기, 검색 내용 종류, 사용자 위치를 같이 지운다
src/adapters/xai-web-search.ts 라인 69 - 내용 종류에 그림이 있으면 그림검색 켜기를 붙인다. 이 PR 은 이 매핑을 남긴다
src/adapters/openai-responses.ts 라인 1506 - 옆 레이어는 거절하는 두 칸만 지운다. 사용자 위치와 필터는 남긴다
tests/responses-routed-web-search-fields.test.ts 라인 105 - 지금 시험은 맨몸 웹검색을 잠근다. 같은 파일 조사 주석과 어긋난다
tests/xai-web-search-compat.test.ts 라인 27 - 지금 시험 이름은 문서 스키마로 낮춘다고 하고, 위치와 내용 종류가 없다고 잠근다
GitHub CI - 위생과 타깃과 라벨은 통과. CodeRabbit 지적 없음. 작성자 로컬은 기준선 대비 회귀 없음

메인테이너의 판단이 필요한 지점

  • GitHub 에 스위트 권위가 없어도 로컬 기준선 비교만으로 머지할지
  • 그림검색 켜기 매핑을 이번에도 남길지. 작성자는 따로 빼는 것은 범위 밖이라고 했다
  • 이 구멍을 이슈로 남길지. 본문에 Closes 가 없다

너의 추천
위생이 초록이니 머지한다. 가드를 더 넓히지 말 것. 거절 칸만 지운 채로 둔다. 그림검색 켜기 매핑은 이번 PR 에서 빼지 않는다. types.ts/config.ts 스플릿과 겹치지 않는다. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.

이 댓글은 grok-bot이 작성했습니다

The two assertions this branch changed both built an api.x.ai provider, where
the xAI normalizer strips the fatal fields before the capability gate runs. They
would have passed with the backfill broken, and never touched the OAuth CLI
destination the Responses opt-in actually targets.

Now the OAuth row resolves through resolveProviderTransport("xai", routed),
asserts it reaches cli-chat-proxy.grok.com, and checks the accepted fields
survive there; an unclassified control asserts the fatal fields are RETAINED
without classification, so a broken backfill fails.
@github-actions
github-actions Bot marked this pull request as draft August 23, 2026 04:47
@olddonkey

Copy link
Copy Markdown
Contributor Author

Updated after review.

The two assertions this PR changed both built an api.x.ai provider, where the xAI normalizer strips the fatal fields before the capability gate runs. They would have passed with the backfill broken, and never exercised the OAuth CLI destination the Responses opt-in actually targets — so they no longer proved what their names claim.

Now the OAuth row resolves through resolveProviderTransport("xai", routed), asserts it reaches cli-chat-proxy.grok.com, and checks the accepted fields survive there. An unclassified control asserts the fatal fields are retained without classification, so a broken backfill fails the test. The existing api.x.ai coverage stays.

Gate: 14433 pass / 2 fail, zero regressions against untouched upstream/dev at the same commit.

@github-actions
github-actions Bot marked this pull request as ready for review August 23, 2026 05:59

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved on exact head 415aec65f77ef92958f755d909ca98f95a2e71a2. The change is narrowly scoped to preserving xAI-accepted user_location and search_content_types while continuing to remove only external_web_access and search_context_size; the existing enable_image_search mapping remains unchanged. I verified the two focused suites (15/15), strict typecheck, and the full repository Cross-platform CI including macOS, all Linux shards, package smokes, hygiene, and CodeRabbit. The updated OAuth control also proves the registry capability backfill is causal rather than accidentally passing through the public-host normalizer.

@Ingwannu
Ingwannu merged commit 43b2e26 into lidge-jun:dev Aug 23, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants