Skip to content

feat(web-search): live gemini executor on the Antigravity CCA transport (#2188 L8) - #2243

Merged
lidge-jun merged 4 commits into
devfrom
codex/sidecar-gemini-executor
Aug 21, 2026
Merged

feat(web-search): live gemini executor on the Antigravity CCA transport (#2188 L8)#2243
lidge-jun merged 4 commits into
devfrom
codex/sidecar-gemini-executor

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

Layer 8 of the #2188 follow-up chain (parent: #2242). The Gemini web-search executor goes live on the Antigravity CCA transport:

  • src/web-search/gemini-executor.ts: runGeminiWebSearch sends the CCA envelope — REGISTRY-pinned destination (a config-level baseUrl is never trusted for OAuth transmission, same rule as src/server/images.ts), IDE-fingerprint User-Agent (a plain UA gets 404, probe-verified), discovered projectId, tools: [{google_search:{}}], and the effort-mapped thinkingConfig.thinkingLevel via resolveAntigravityEffortWireModel. redirect: "manual", never-throws, all error branches redacted.
  • mapCcaGroundedResponse maps candidates[0] text + groundingMetadata.groundingChunks[].web to the sidecar outcome, deduped by uri.
  • planWebSearch's gemini arm goes live fail-closed (OAuth or projectId absent → no plan); the loop arm fails closed without a resolved provider (regression-pinned: zero fetches, zero pool recordings); registry activates the backend on the same predicate.
  • Imports stay lean (google-antigravity-wire + antigravity-models only — no google.ts adapter drag, reviewer-verified).

Live E2E through the real executor: grounded answer 433 chars + 2 grounding sources, with automatic OAuth token rotation mid-call.

Design doc: devlog/_plan/260820_sidecar_selection_unification/080_layer8_gemini_executor.md (rev 2) + 002 LIVE PROBE.

Verification

  • Remote full gate at exact head (lidge): 13801 pass / 15 skip / 0 fail across 874 files (493s); typecheck clean.
  • 9 focused tests: request-shape pin (registry destination under a malicious baseUrl, manual redirect, bearer + IDE UA, full envelope, gemini-3.7-flash-tiered + thinkingLevel: "low"), grounding-map fixtures from the live capture, fail-closed matrix, loop-level fail-closed regression.
  • Independent read-only review (terra): 3 P1 (unredacted non-Error branch — fixed in both new executors, missing request-shape test, missing loop regression) + 1 follow-up (thinkingLevel assertion) all fixed — final VERDICT: pass.

Checklist

@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner August 21, 2026 02:08
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@lidge-jun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

Limit details: You’ve used all 10 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f535b300-9cdd-4e05-aea3-f308396a859a

📥 Commits

Reviewing files that changed from the base of the PR and between ef867c9 and ef551e8.

📒 Files selected for processing (7)
  • src/server/responses/core.ts
  • src/web-search/backends.ts
  • src/web-search/gemini-executor.ts
  • src/web-search/index.ts
  • src/web-search/loop.ts
  • src/web-search/xai-executor.ts
  • tests/gemini-web-search.test.ts

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.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 21, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6db16f621b

ℹ️ 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 (!active || active.needsReauth === true) return false;
return !!(active.credential as { projectId?: string } | undefined)?.projectId;
},
eligibleModel: candidate => candidate.provider === "google-antigravity",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Map Gemini picker rows to the Gemini backend

When Antigravity OAuth is active, this descriptor adds its models to the Dashboard picker, but gui/src/pages/dashboard-shared.ts:350-352 maps every non-Anthropic model to openai, and the picker saves that inferred backend in dashboard-overview-sections.tsx:515-519. Selecting a Gemini row therefore persists backend: "openai" and sends the Gemini model ID to the ChatGPT sidecar instead of invoking this executor; return backend metadata with each option and teach the picker to preserve gemini.

Useful? React with 👍 / 👎.

Comment thread src/web-search/gemini-executor.ts Outdated
): Promise<SidecarOutcome> {
let token: string;
try {
token = (await getValidAccessTokenSnapshot(providerName)).accessToken;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Include OAuth refresh in the sidecar deadline

When the active Antigravity token is expired and its refresh request stalls, this await occurs before signalWithTimeout is created, so neither webSearchSidecar.timeoutMs nor a client abort can stop the authentication phase; the whole Responses turn can outlive its advertised hosted-search deadline. Create the linked signal before credential resolution and race or propagate it through the refresh, as the Antigravity image path does, while cleaning it up on early returns.

AGENTS.md reference: src/AGENTS.md:L17-L17

Useful? React with 👍 / 👎.

Comment thread src/web-search/gemini-executor.ts Outdated
Comment thread src/web-search/gemini-executor.ts Outdated
Comment thread src/web-search/index.ts
Comment on lines +24 to +25
// Default Gemini model for the gemini-backed sidecar (CCA grounding probe, devlog 002).
const DEFAULT_GEMINI_SIDECAR_MODEL = "gemini-3.7-flash";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Document that the Gemini backend is now live

This introduces a user-selectable backend and default model without updating the user documentation: docs-site/src/content/docs/guides/sidecars.md:26-28 still describes only OpenAI and Anthropic, while structure/04_transports-and-sidecars.md:898-904 explicitly says Gemini is inert. Update the English configuration/sidecar guidance, scoped translations, and the architecture record so operators can configure the required Antigravity OAuth/project flow without following contradictory instructions.

AGENTS.md reference: AGENTS.md:L279-L280

Useful? React with 👍 / 👎.

@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.

Reviewed exact head 6db16f6. The Gemini direction is valuable, but I found three merge blockers that the current 9/9 focused suite does not cover:

  1. runGeminiWebSearch obtains an OAuthAccessSnapshot, keeps only accessToken, then separately re-reads the current active account for projectId. If the active account changes while token refresh or request setup is in flight, the request can pair account A bearer with account B project. The snapshot already carries the projectId bound to the exact account and generation; use that same snapshot atomically and add an account-switch regression.
  2. After fetchWithResetRetry resolves, neither the error-body read nor the success JSON read attaches cancelBodyOnAbort. This reopens the known abort-before-reader race already documented and fixed in the existing OpenAI and Anthropic sidecars. Attach the guard before either branch reads, and prove an abort immediately after headers cancels and settles the body.
  3. Both res.text and res.json materialize an unbounded upstream body. A CCA response is untrusted network input and this sidecar should retain a strict byte ceiling. Use the shared bounded body/bytes primitive with the linked signal, cancel on overflow, parse only bounded UTF-8 JSON, and add oversized success and error regressions.

The focused tests and typecheck pass locally, but exact-head CI is currently red on macOS, and this stack is based on #2242, which still has unresolved requested changes. Please fix the three boundaries, make the parent clean, rerun exact-head CI, then retarget only after the parent lands.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 60 / 80

#2188 L8임. 베이스가 codex/sidecar-xai-executor (#2242 L7). 지금 dev HEAD 826a1b7a4엔 제미니 암도 backends.ts도 없음. planWebSearch (src/web-search/index.ts:144-204)가 openai/anthropic만. 루프 (src/web-search/loop.ts:659-661)도 그 이분법. L6 유니온이 gemini를 이너트로 넣어 두고, 이 PR이 runGeminiWebSearch를 살림. 부모 #2242 없이 리타깃하면 깨짐.

실행기 핀이 맞음. src/web-search/gemini-executor.ts가 config baseUrl을 안 믿음. getProviderRegistryEntry("google-antigravity") + fallback https://daily-cloudcode-pa.googleapis.com. src/server/images.ts랑 같은 규칙. evil.example로 자격 안 나감. 테스트가 그거 잠금. UA는 ANTIGRAVITY_REQUEST_UA (src/adapters/google-antigravity-wire.ts:12). 플레인 UA면 404. 프로브 맞음. tools: [{google_search:{}}] + resolveAntigravityEffortWireModelthinkingConfig.thinkingLevel 넣음. redirect: "manual". never-throws. import가 google-antigravity-wire + antigravity-models만. google.ts 어댑터 안 끌어옴. ㅇㅇ 그거 맞음.

플랜/루프 fail-closed. findGeminiSidecarProvidergoogle-antigravity OAuth + 발견된 projectId. 없으면 plan 없음. 루프가 geminiSidecar 없으면 포워드 실행기/풀 레코더 안 탐. 테스트가 zero fetch + zero pool. mapCcaGroundedResponse가 래핑 {response} / 플랫 둘 다. groundingChunks uri 디듑. 텍스트 없으면 error. 기본 모델 gemini-3.7-flash.

src/types/config.ts 안 건드림. L6가 유니온을 이미 넓힘. 스플릿이 이 PR을 바로 무효화하진 않음. 그래도 사이드카 스택이 index.ts/loop.ts를 같이 소유하니 L7 먼저. 닫을 중복 아님. #2190 x_search 안 섞음. #2217/#2227 와이어 기본 안 건드림. #2233/#2246 구글 파트 계약이랑도 별 선. 이쪽은 CCA 엔벨로프지 어댑터 파서가 아님.

2.28 블로커 아님. 프리뷰 배포 플랜 아님. 지금 HEAD 위에 바로 머지하지 말 것. L1→L7 순서.

해결방안: #2242 머지 후 리타깃. config baseUrl 신뢰 금지 유지. google.ts 임포트 넣지 말 것. 스플릿이 사이드카 플랜/루프를 옮기면 리베이스하지 말고 닫고 다시 짜라. 지금은 그 정도 아님.

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

@lidge-jun

Copy link
Copy Markdown
Owner Author

All three blockers addressed in 249cc91: (1) runGeminiWebSearch now uses the projectId carried by the SAME OAuthAccessSnapshot atomically — an account switch mid-flight can no longer pair account A bearer with account B project (account-switch regression); (2) cancelBodyOnAbort attaches immediately after fetchWithResetRetry resolves, before either the error-body or success-JSON branch reads (abort-after-headers regression proves the body cancels and settles); (3) both reads go through a bounded 64 KiB UTF-8 JSON path with the linked signal, cancelling on overflow (oversized success + error regressions). All four regressions observed red before the fix. Fresh local: 50/0 across three suites, tsc clean, privacy:scan pass. Parent #2242 blockers were addressed in b2c2054 on its branch; will rerun exact-head CI after the stack settles. Ready for re-review.

@lidge-jun
lidge-jun requested a review from Ingwannu August 21, 2026 03:16

@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.

Reviewed exact head 249cc91a38b742da8e279c885b31dd10490d390f. The three blockers from my previous review are fixed: the token and project now come from one OAuth snapshot, the response body is guarded immediately after headers, and both success/error payloads use the bounded 64 KiB reader. The focused regressions, typecheck, privacy scan, and exact-head CI are green.

Three current-head blockers remain before this stack layer can be approved:

  1. runGeminiWebSearch still creates signalWithTimeout only after getValidAccessTokenSnapshot completes. A stalled Antigravity refresh therefore ignores both the caller abort and webSearchSidecar.timeoutMs. The existing CCA image path creates the deadline before auth and races the non-cancellable refresh against it. Apply the same boundary here and add abort/timeout-during-auth regressions.
  2. The server option DTO still drops backend provenance (WebSearchModelOption has no backend), while the GUI web-search picker still calls sidecarBackendForModel, whose fallback is OpenAI for every non-Anthropic row. Selecting a google-antigravity candidate therefore persists { backend: "openai" } and never reaches this executor. Carry the exact backend in every server option, widen the GUI web-search backend type to include xai | gemini | exa, preserve it through grandfathered/current options, and add a picker/save regression.
  3. The user and architecture docs are now contradictory: guides/sidecars.md documents only OpenAI/Anthropic, and structure/04_transports-and-sidecars.md still says explicit Gemini is inert. Document the live Antigravity OAuth/project requirement, default model, fail-closed behavior, and update directly affected translations.

Please keep this on top of #2242, fix these boundaries, and rerun exact-head CI. The implementation remains a strong stack candidate after that.

@lidge-jun
lidge-jun force-pushed the codex/sidecar-xai-executor branch from 3f574c3 to a03f51a Compare August 21, 2026 03:39
…2188 L8)

runGeminiWebSearch sends the CCA envelope (registry-pinned endpoint,
IDE fingerprint UA, discovered projectId, google_search tool,
effort-mapped thinkingLevel) with the stored Antigravity OAuth and maps
candidates[0] text + groundingMetadata.groundingChunks to the sidecar
outcome. planWebSearch's gemini arm goes live fail-closed on OAuth or
projectId absence; the loop arm fails closed without a resolved
provider; the registry activates the backend on the same predicate.
…t shape

Non-Error throws reached tool results unredacted in both new executors.
Adds the reviewer-demanded request-shape test (registry destination
despite a malicious baseUrl, manual redirect, bearer + IDE UA, full CCA
envelope) and the gemini loop fail-closed regression mirroring xai.
Bind the bearer token and Cloud Code Assist project to one OAuthAccessSnapshot so an active-account switch cannot cross-pair credentials. Guard the response body immediately after headers, then consume success and error payloads through the shared 64 KiB byte bound with linked cancellation and strict UTF-8 JSON parsing. Add regressions for account switching, post-header abort settlement, and oversized success/error cancellation.

Evidence: bun test tests/gemini-web-search.test.ts tests/cancel-body-on-abort.test.ts tests/bounded-body.test.ts (50 pass); bun x tsc --noEmit; bun run privacy:scan.
@lidge-jun
lidge-jun force-pushed the codex/sidecar-gemini-executor branch from 249cc91 to ef551e8 Compare August 21, 2026 03:39
@lidge-jun
lidge-jun changed the base branch from codex/sidecar-xai-executor to dev August 21, 2026 03:39
@lidge-jun
lidge-jun merged commit 738eed7 into dev Aug 21, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants