Skip to content

docs(privacy): align Zoo Code observability retention with website policy#346

Open
JamesRobert20 wants to merge 20 commits into
mainfrom
feat/zoo-gateway-telemetry-policy
Open

docs(privacy): align Zoo Code observability retention with website policy#346
JamesRobert20 wants to merge 20 commits into
mainfrom
feat/zoo-gateway-telemetry-policy

Conversation

@JamesRobert20
Copy link
Copy Markdown
Contributor

@JamesRobert20 JamesRobert20 commented May 27, 2026

Summary

  • Updates extension PRIVACY.md: 90-day metadata retention (matches zoocode.dev legal policy), plan-gated dashboard visibility (7 days Free / 90 days Pro+)
  • Updates zoo-telemetry.ts doc comment to match

Independent of Zoo Gateway provider code (split from #229 per review).

Test plan

Made with Cursor

Summary by CodeRabbit

  • Documentation

    • Privacy policy expanded: telemetry now covers all authenticated users, includes task/model/token counts and estimated cost, links to account, retained up to 90 days, dashboard visibility varies by plan, and user controls to stop collection or request deletion.
  • New Features

    • Zoo Gateway provider added: sign-in, model discovery, default model selection, streaming and completion support, settings UI and i18n.
  • Bug Fixes / Reliability

    • Auth callback, sign-out, and token sync/clear now apply to all active instances; auth-scoped model fetching prevents cross-user cache leaks.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new "zoo-gateway" provider end-to-end (types, provider module, fetchers, handler, API wiring), updates model-cache behavior for auth-scoped models, extends webview/settings UI and validation, propagates Zoo auth tokens to all provider instances, expands telemetry to all authenticated users, updates PRIVACY.md, adds i18n keys and tests, and revises Vite build config.

Changes

Zoo Gateway + Telemetry

Layer / File(s) Summary
Complete integration and cross-cutting updates
packages/types/..., src/api/..., src/core/webview/..., webview-ui/..., src/services/..., PRIVACY.md, webview-ui/vite.config.ts, src/i18n/..., src/api/providers/fetchers/*, src/api/providers/zoo-gateway.ts
All changes required to add zoo-gateway support and broaden telemetry to all authenticated users: new provider types/exports and default model info; ZooGatewayHandler implementation and fetcher (getZooGatewayModels) with Zod validation; model-cache bypass for auth-scoped models; API handler wiring; webview and settings UI wiring and validation updates; ClineProvider multi-instance auth propagation and profile seeding; telemetry gating removed (token-only); privacy doc updated; wide i18n additions; tests for handlers, fetchers, webview, settings, activation flows; Vite config changes.

Estimated code review effort: 🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Zoo-Code-Org/Zoo-Code#32: Prior telemetry sender changes touching src/services/zoo-telemetry.ts and tests; related to telemetry adjustments in this PR.
  • Zoo-Code-Org/Zoo-Code#214: Earlier Vite/build pipeline updates; overlaps with webview-ui/vite.config.ts changes in this PR.

Suggested reviewers

  • hannesrudolph
  • taltas
  • edelauna
  • navedmerchant

"A rabbit in the code, ears up for the gate,
I stitched a new provider—now models await.
Telemetry hums when signed in and true,
Dashboards and settings, i18n too.
Hop, test, and deploy — a small carrot for you 🥕"

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/zoo-gateway-telemetry-policy
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/zoo-gateway-telemetry-policy

@JamesRobert20 JamesRobert20 mentioned this pull request May 27, 2026
1 task
James Mtendamema and others added 4 commits May 27, 2026 07:50
Co-authored-by: Cursor <cursoragent@cursor.com>
… fetch

- Stop reassigning RouterProvider.client; thread Zoo enrichment headers
  through openAiHeaders so a single OpenAI client is used.
- Replace npm_package_version (never populated at extension runtime)
  with Package.version from the shared package shim.
- Default the model list to [] on a structurally broken response so we
  log and recover instead of crashing on response.data.data being
  undefined.
- Bypass inFlightRefresh de-duplication for zoo-gateway: a refresh
  triggered after sign-out/sign-in must not return the previous user's
  in-flight response.
- Add fetcher unit tests covering auth header, timeout, error
  redaction, and bad-response handling.

Co-authored-by: Cursor <cursoragent@cursor.com>
…RouterName stays exhaustive

Co-authored-by: Cursor <cursoragent@cursor.com>
…terName exhaustiveness holds

Co-authored-by: Cursor <cursoragent@cursor.com>
@JamesRobert20 JamesRobert20 force-pushed the feat/zoo-gateway-telemetry-policy branch from f0aa066 to 3251b6e Compare May 27, 2026 14:29
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

James Mtendamema and others added 2 commits May 27, 2026 08:40
Co-authored-by: Cursor <cursoragent@cursor.com>
Cover constructor auth guard, base URL resolution, streaming, task/mode headers, temperature, cache breakpoints, tool calls, and completePrompt.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown
Contributor

@proyectoauraorg proyectoauraorg left a comment

Choose a reason for hiding this comment

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

Review: Privacy/Telemetry Alignment

Verdict: ✅ Approved

Verified

  • zoo-telemetry.test.ts — 5 tests pass (including new 'all authenticated users' test)
  • ✅ Subscription check removal is correct — server-side gating at zoocode.dev
  • ✅ PRIVACY.md matches the code changes (90-day retention, plan-gated dashboard)
  • ✅ Net code reduction (-10 lines) — removes unnecessary complexity

Important

The old code sent telemetry only to users with active subscriptions. This PR removes that client-side gate, so all authenticated users (free and paid) will now send telemetry. This is correct IF the server enforces plan-gated dashboard visibility (7 days Free / 90 days Pro+).

Recommend confirming that zoocode.dev server-side retention and dashboard visibility policies are implemented before merging this PR.

Dependency

Independent of the Zoo Gateway stack. Can merge to main at any time.

@JamesRobert20 JamesRobert20 force-pushed the feat/zoo-gateway-telemetry-policy branch from 3251b6e to 89559d5 Compare May 28, 2026 20:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (11)
webview-ui/src/i18n/locales/es/settings.json-455-455 (1)

455-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix garbled UTF-8 text in Spanish locale strings.

Line 455 and Line 871 contain mojibake, so these messages will display corrupted characters in the UI.

💡 Proposed fix
-		"googleCloudCredentialsPathWarning": "Este campo espera el contenido JSON de un archivo de clave de cuenta de servicio, no una ruta. Si tienes una ruta, pégala en el campo <strong>Ruta del archivo de clave de Google Cloud</strong> a continuación, o borra este campo y utiliza la variable de entorno <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
+		"googleCloudCredentialsPathWarning": "Este campo espera el contenido JSON de un archivo de clave de cuenta de servicio, no una ruta. Si tienes una ruta, pégala en el campo <strong>Ruta del archivo de clave de Google Cloud</strong> a continuación, o borra este campo y utiliza la variable de entorno <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
@@
-		"automaticFetch": "La extensión obtiene automáticamente la lista más reciente de modelos disponibles en <serviceLink>{{serviceName}}</serviceLink>. Si no está seguro de qué modelo elegir, Zoo Code funciona mejor con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. También puede buscar \"free\" para opciones sin costo actualmente disponibles.",
+		"automaticFetch": "La extensión obtiene automáticamente la lista más reciente de modelos disponibles en <serviceLink>{{serviceName}}</serviceLink>. Si no está seguro de qué modelo elegir, Zoo Code funciona mejor con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. También puede buscar \"free\" para opciones sin costo actualmente disponibles.",

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/es/settings.json` at line 455, The Spanish locale
string under the key "googleCloudCredentialsPathWarning" contains mojibake
(e.g., "pégala", "a continuación"); update that value to use proper UTF-8
accented characters (e.g., "pégala", "a continuación") and scan the same file
for the other affected key around line 871 to fix similar garbled sequences so
all Spanish strings are valid UTF-8.
src/api/providers/fetchers/zoo-gateway.ts-68-77 (1)

68-77: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Skip model discovery when there is no session token.

Line 59 states auth is required, but Lines 68-77 still issue a network call without credentials. That creates guaranteed failures and noisy logs for signed-out users.

💡 Proposed fix
-	const sessionToken = options?.zooSessionToken || getCachedZooCodeToken()
-	const headers: Record<string, string> = {}
-	if (sessionToken) {
-		headers["Authorization"] = `Bearer ${sessionToken}`
-	}
+	const sessionToken = options?.zooSessionToken ?? getCachedZooCodeToken()
+	if (!sessionToken) {
+		return models
+	}
+	const headers: Record<string, string> = {
+		Authorization: `Bearer ${sessionToken}`,
+	}
🤖 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 `@src/api/providers/fetchers/zoo-gateway.ts` around lines 68 - 77, The code
issues an axios.get to `${baseURL}/models` even when no session token is
available (sessionToken from options?.zooSessionToken || getCachedZooCodeToken),
causing needless failed requests; update the logic to short-circuit before the
network call when sessionToken is falsy (e.g., return an empty models list or
null from the enclosing function), so do not call axios.get or use
MODEL_DISCOVERY_TIMEOUT_MS without credentials—use the sessionToken variable and
the axios.get call sites as the anchors to implement the early return.
webview-ui/src/i18n/locales/de/settings.json-455-455 (1)

455-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the mojibake in these German strings.

Both translated values are corrupted, so googleCloudCredentialsPathWarning and modelPicker.automaticFetch will render as unreadable text in the settings UI.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/de/settings.json` at line 455, The German strings
contain mojibake where umlauts were corrupted; update the values for the keys
googleCloudCredentialsPathWarning and modelPicker.automaticFetch in the locales
file to use the correct German characters (e.g., "Schlüssel" and
"Schlüsseldateipfad") so the messages read correctly—specifically replace
"Schl├╝ssel" and "Schl├╝sseldateipfad" with "Schlüssel" and "Schlüsseldateipfad"
and ensure the rest of the punctuation/HTML/templating (like <strong> and
<code>) remains unchanged.
webview-ui/src/i18n/locales/tr/settings.json-455-455 (1)

455-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the mojibake in these Turkish strings.

googleCloudCredentialsPathWarning and modelPicker.automaticFetch are corrupted here, so the translated settings copy will render unreadably.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/tr/settings.json` at line 455, The Turkish
strings for keys googleCloudCredentialsPathWarning and
modelPicker.automaticFetch contain mojibake (corrupted characters); open the
localization entries for these keys, replace the corrupted characters with the
correct Turkish characters/words (e.g., restore characters like ı, ş, ç, ğ, ö,
ü) so the sentences read naturally, ensure the file is saved in UTF-8 without
BOM, and also fix the identical corrupted instance noted around the other
occurrence (modelPicker.automaticFetch) so both entries render correctly.
webview-ui/src/i18n/locales/zh-TW/settings.json-465-465 (1)

465-465: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the mojibake in these Traditional Chinese strings.

Both values are corrupted, so googleCloudCredentialsPathWarning and modelPicker.automaticFetch will show unreadable text in the UI.

Also applies to: 881-881

🤖 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 `@webview-ui/src/i18n/locales/zh-TW/settings.json` at line 465, The Traditional
Chinese strings for the keys googleCloudCredentialsPathWarning and
modelPicker.automaticFetch are corrupted (mojibake); locate the JSON entries for
"googleCloudCredentialsPathWarning" and "modelPicker.automaticFetch" and replace
the garbled text with correct Traditional Chinese translations, preserving any
inline HTML tags like <strong> and <code> and ensuring the meaning about setting
GOOGLE_APPLICATION_CREDENTIALS and automatic model fetching remains accurate;
also fix the duplicate occurrence noted (the other affected entry around the
second mention) so both occurrences show readable Traditional Chinese.
webview-ui/src/i18n/locales/pt-BR/settings.json-455-455 (1)

455-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix mojibake in Portuguese translations.

These strings are UTF-8 corrupted and will render broken text in UI.

💡 Suggested fix
-		"googleCloudCredentialsPathWarning": "Este campo espera o conteúdo JSON de um arquivo de chave de conta de serviço, não um caminho. Se você tiver um caminho, cole-o no campo <strong>Caminho do Arquivo de Chave Google Cloud</strong> abaixo, ou limpe este campo e use a variável de ambiente <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
+		"googleCloudCredentialsPathWarning": "Este campo espera o conteúdo JSON de um arquivo de chave de conta de serviço, não um caminho. Se você tiver um caminho, cole-o no campo <strong>Caminho do Arquivo de Chave Google Cloud</strong> abaixo, ou limpe este campo e use a variável de ambiente <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
@@
-		"automaticFetch": "A extensão busca automaticamente a lista mais recente de modelos disponíveis em <serviceLink>{{serviceName}}</serviceLink>. Se você não tem certeza sobre qual modelo escolher, o Zoo Code funciona melhor com <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Você também pode pesquisar por \"free\" para encontrar opções gratuitas atualmente disponíveis.",
+		"automaticFetch": "A extensão busca automaticamente a lista mais recente de modelos disponíveis em <serviceLink>{{serviceName}}</serviceLink>. Se você não tem certeza sobre qual modelo escolher, o Zoo Code funciona melhor com <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Você também pode pesquisar por \"free\" para encontrar opções gratuitas atualmente disponíveis.",

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/pt-BR/settings.json` at line 455, The Portuguese
translation for the key "googleCloudCredentialsPathWarning" (and the other
affected key around the same area) contains mojibake (UTF-8 corruption) and must
be replaced with correctly encoded UTF-8 text; locate the
"googleCloudCredentialsPathWarning" entry in the pt-BR locale and update the
string to use proper Portuguese characters (e.g., "conteúdo", "conta de
serviço", "não", "você", "variável de ambiente", "Caminho do Arquivo de Chave
Google Cloud") so the UI renders correctly; ensure the same corrections are
applied to the other corrupted pt-BR string referenced in the review.
webview-ui/src/i18n/locales/it/settings.json-871-871 (1)

871-871: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix corrupted UTF-8 in Italian modelPicker.automaticFetch.

The string includes mojibake (pi├╣) and will display incorrectly.

💡 Suggested fix
-		"automaticFetch": "L'estensione recupera automaticamente l'elenco pi├╣ recente dei modelli disponibili su <serviceLink>{{serviceName}}</serviceLink>. Se non sei sicuro di quale modello scegliere, Zoo Code funziona meglio con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Puoi anche cercare \"free\" per opzioni gratuite attualmente disponibili.",
+		"automaticFetch": "L'estensione recupera automaticamente l'elenco più recente dei modelli disponibili su <serviceLink>{{serviceName}}</serviceLink>. Se non sei sicuro di quale modello scegliere, Zoo Code funziona meglio con <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Puoi anche cercare \"free\" per opzioni gratuite attualmente disponibili.",
🤖 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 `@webview-ui/src/i18n/locales/it/settings.json` at line 871, The value for the
i18n key modelPicker.automaticFetch contains mojibake ("pi├╣") instead of the
correct Italian character; update the string for modelPicker.automaticFetch to
replace "pi├╣ recente" with "più recente" (keep the existing HTML-like links
<serviceLink>{{serviceName}}</serviceLink> and
<defaultModelLink>{{defaultModelId}}</defaultModelLink> and preserve any escaped
quotes), ensuring the file is saved as UTF-8 so the "ù" character is stored
correctly.
src/core/webview/__tests__/ClineProvider.spec.ts-3760-3771 (1)

3760-3771: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert the state refresh you claim in the test.

This case only verifies the log path. A regression where handleZooCodeCallback() stops calling postStateToWebview() would still pass, despite the test name promising that behavior. Add an explicit expect(provider.postStateToWebview).toHaveBeenCalled() or rename the test.

🤖 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 `@src/core/webview/__tests__/ClineProvider.spec.ts` around lines 3760 - 3771,
The test "logs and posts state when profile persistence fails" currently only
asserts the log path; update the spec to also assert that
provider.postStateToWebview was invoked after calling
provider.handleZooCodeCallback("zoo_ext_token") (or alternatively rename the
test to reflect it only verifies logging). Specifically, locate the test using
provider.handleZooCodeCallback and add an
expect(provider.postStateToWebview).toHaveBeenCalled() (or rename the it(...)
description) so the test actually verifies the state-post behavior.
webview-ui/src/i18n/locales/ca/settings.json-455-455 (1)

455-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the encoding corruption in these translations.

These strings contain visible mojibake, so Catalan users will see broken copy in the settings UI. Please restore the intended text and save the file with the correct encoding.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/ca/settings.json` at line 455, The Catalan
translation for the key "googleCloudCredentialsPathWarning" contains mojibake
("a continuaci├│")—replace it with the correct text ("a continuació") and verify
the corresponding duplicate entry later in the same settings.json (the other
occurrence flagged by the reviewer) is fixed the same way; finally re-save the
file in UTF-8 (no BOM) to prevent encoding corruption going forward.
webview-ui/src/i18n/locales/fr/settings.json-455-455 (1)

455-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Restore these French strings before merge.

Both values contain mojibake, so the settings UI will show broken text instead of proper French copy. Reinsert the intended translation and save the file as UTF-8.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/fr/settings.json` at line 455, The JSON value for
the "googleCloudCredentialsPathWarning" key contains mojibake (garbled
characters); replace it with the correct French translation (use proper accents)
and ensure the file is saved as UTF-8; also locate and fix the other occurrence
noted (same mojibake at the other key around line 871) so both keys contain
proper French strings with correct accents and encoding.
webview-ui/src/i18n/locales/ja/settings.json-455-455 (1)

455-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the mojibake in these localized strings.

Both entries are unreadable in the shipped UI because the text appears to have been saved with the wrong encoding. Restore the intended Japanese copy and re-save the file as UTF-8.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/ja/settings.json` at line 455, The value for the
i18n key "googleCloudCredentialsPathWarning" contains mojibake (wrong encoding);
open the locale file, replace the garbled string with the correct Japanese copy
for that key (preserving the intended inline tokens like <strong>Google
Cloud…</strong> and <code>GOOGLE_APPLICATION_CREDENTIALS</code>), ensure the
file is saved as UTF-8 (preferably UTF-8 without BOM), and apply the same fix to
the other corrupted localized entry in the same file that was flagged as also
affected.
🧹 Nitpick comments (2)
webview-ui/src/components/settings/providers/__tests__/ZooGateway.spec.tsx (1)

150-152: ⚡ Quick win

Make the non-call assertion wait past effect flush.

This can pass too early before async effects settle, so it may miss a late setApiConfigurationField call.

Proposed test hardening
+import { act } from "`@/utils/test-utils`"
...
-		await waitFor(() => {
-			expect(setApiConfigurationField).not.toHaveBeenCalled()
-		})
+		await act(async () => {
+			await Promise.resolve()
+		})
+		expect(setApiConfigurationField).not.toHaveBeenCalled()
🤖 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 `@webview-ui/src/components/settings/providers/__tests__/ZooGateway.spec.tsx`
around lines 150 - 152, The non-call assertion for setApiConfigurationField in
ZooGateway.spec.tsx can pass too early; wrap the expectation in waitFor that
waits long enough for async effects (e.g., await waitFor(() =>
expect(setApiConfigurationField).not.toHaveBeenCalled(), { timeout: 1000 })) or
explicitly flush pending promises before the assertion (e.g., await
flushPromises(); expect(setApiConfigurationField).not.toHaveBeenCalled());
update the test to use one of these approaches targeting the
waitFor/setApiConfigurationField usage so the assertion runs after effects
settle.
src/core/webview/__tests__/webviewMessageHandler.spec.ts (1)

397-433: ⚡ Quick win

Harden shared mock cleanup to avoid test state bleed.

These tests mutate mockClineProvider globally and rely on inline cleanup. If a test fails early, state can leak into later tests. Move restoration to afterEach (or try/finally) for providerSettingsManager, upsertProviderProfile, and overridden contextProxy fields.

Suggested stabilization pattern
+let originalContextProxy: any
+
+beforeEach(() => {
+  originalContextProxy = mockClineProvider.contextProxy
+})
+
+afterEach(() => {
+  delete (mockClineProvider as any).providerSettingsManager
+  delete (mockClineProvider as any).upsertProviderProfile
+  ;(mockClineProvider as any).contextProxy = originalContextProxy
+})

Also applies to: 1163-1229

🤖 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 `@src/core/webview/__tests__/webviewMessageHandler.spec.ts` around lines 397 -
433, Tests mutate the shared mockClineProvider (providerSettingsManager,
upsertProviderProfile, contextProxy) inline which can leak state if a test
fails; instead, capture original values at test start and restore them in an
afterEach hook (or wrap each test body in try/finally), e.g. save const
origProviderSettings = (mockClineProvider as any).providerSettingsManager,
origUpsert = (mockClineProvider as any).upsertProviderProfile, origContext =
(mockClineProvider as any).contextProxy and restore them after the test; apply
this stabilization for the tests that set providerSettingsManager,
upsertProviderProfile, or override contextProxy (the block around
webviewMessageHandler and the other similar test blocks).
🤖 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 `@src/activate/handleUri.ts`:
- Around line 65-67: The loop over allInstances calls
instance.handleZooCodeCallback(token) directly, so one rejected call aborts the
whole loop; update the loop to call handleZooCodeCallback for each instance
inside a try/catch (e.g., within the for (const instance of allInstances)
block), catch and log the error (including instance identifier if available) and
continue to the next instance so one failure does not prevent other instances
from receiving the callback.

In `@src/api/providers/zoo-gateway.ts`:
- Around line 102-107: The code currently prefers options.zooSessionToken over
getCachedZooCodeToken(), which can keep using a stale profile token; change the
selection so the cached token is preferred (e.g., set sessionToken by calling
getCachedZooCodeToken() first and falling back to options.zooSessionToken) —
update the assignment around the sessionToken variable in the zoo-gateway.ts
handler where options.zooSessionToken and getCachedZooCodeToken() are used so
fresh cached tokens are used before the persisted profile token.

In `@src/core/webview/ClineProvider.ts`:
- Around line 873-916: ensureZooGatewayProfileSeeded currently only compares
profile.zooSessionToken to getCachedZooCodeToken(); also check that each
profile.zooGatewayBaseUrl equals the current getZooCodeBaseUrl() and treat any
mismatch as stale so seeding occurs. In the loop that inspects
zooGatewayProfiles (using providerSettingsManager.getProfile and the token
check), fetch the current base URL via getZooCodeBaseUrl(), compare it to
fullProfile.zooGatewayBaseUrl, and if different set allUpToDate = false, log a
descriptive message, and break so handleZooCodeCallback(token) will be invoked
to reseed both tokens and base URLs. Ensure references to
ensureZooGatewayProfileSeeded, getCachedZooCodeToken, getZooCodeBaseUrl,
providerSettingsManager.getProfile, and handleZooCodeCallback are used to locate
the changes.

In `@src/core/webview/webviewMessageHandler.ts`:
- Around line 948-968: The switch case for "requestRouterModels" contains
block-scoped declarations (e.g., const { apiConfiguration }, let
zooGatewayToken, const candidates) that must be isolated to avoid leaking across
cases; wrap the entire case "requestRouterModels" body in its own braces { ... }
so these let/const bindings are scoped to that case, ensuring code like
provider.providerSettingsManager.listConfig and related
zooGatewayToken/zooGatewayBaseUrl logic are enclosed and won't conflict with
other cases.

In `@webview-ui/src/i18n/locales/hi/settings.json`:
- Line 455: The string value for "googleCloudCredentialsPathWarning" (and the
other mojibake entry at line 871) contains garbled text; replace these mojibake
strings with proper Hindi translations while preserving inline HTML tags
(<strong>, <code>) and meaning about Google Cloud credentials and
GOOGLE_APPLICATION_CREDENTIALS, updating the JSON values for the keys (e.g.,
"googleCloudCredentialsPathWarning") so the help/setup content reads correctly
in Hindi.

In `@webview-ui/src/i18n/locales/ko/settings.json`:
- Line 455: Replace the garbled mojibake for the
"googleCloudCredentialsPathWarning" JSON value with the correct Korean
translation (restore the intended readable Korean copy), fix the other corrupted
string mentioned (line 871) the same way, and re-save the file as UTF-8 (no BOM)
so the encoding is preserved; locate these keys
("googleCloudCredentialsPathWarning" and the other corrupted key at line 871) in
webview-ui/src/i18n/locales/ko/settings.json and update their string values with
the proper Korean text.

In `@webview-ui/src/i18n/locales/pl/settings.json`:
- Line 455: The string value for "googleCloudCredentialsPathWarning" contains
mojibake (garbled Unicode) and should be replaced with correctly encoded Polish
text (use proper characters like ą,ę,ś,ł,ż,ó,ć,ń) and similarly fix the
corrupted message at the model-selection key on the other occurrence (line
~871); open the JSON entry for "googleCloudCredentialsPathWarning" and the
model-selection key, replace the garbled characters with the correct Polish
phrasing, and ensure the file is saved with UTF-8 encoding so the Polish
diacritics persist.

In `@webview-ui/src/i18n/locales/ru/settings.json`:
- Line 455: The JSON values for Russian locale contain encoding-corrupted text;
replace the corrupted value for the key "googleCloudCredentialsPathWarning" in
settings.json with a proper Russian translation and likewise locate and restore
the other corrupted Russian string near line 871 (search for non-UTF8/garbled
characters) so both warning/help messages are readable; ensure the replacements
are valid UTF-8, preserve existing HTML/inline code tags like <strong> and
<code> exactly, and run a quick JSON lint to confirm no syntax changes.

In `@webview-ui/src/i18n/locales/vi/settings.json`:
- Line 455: The string value for the locale key
"googleCloudCredentialsPathWarning" (and the other corrupted Vietnamese entry in
the same file) is mojibake; replace the corrupted text with the correct
Vietnamese translations, ensure the HTML (<strong>) and code (<code>) fragments
remain intact, save the file encoded as UTF-8 without BOM, and validate the JSON
(lint/parse) after the replacement so the locale renders correctly.

In `@webview-ui/src/i18n/locales/zh-CN/settings.json`:
- Line 455: Fix the mojibake in the Simplified Chinese locale by replacing the
corrupted string value for the key "googleCloudCredentialsPathWarning" (and the
other corrupted entry at the second occurrence referenced) with a proper
Simplified Chinese translation that preserves the embedded HTML and code tags
(<strong>...</strong> and <code>GOOGLE_APPLICATION_CREDENTIALS</code>); locate
the entries by the key "googleCloudCredentialsPathWarning" and the other
unreadable key near the same block, correct the text to clear, idiomatic Chinese
guidance about placing a Google Cloud service account JSON file and setting
GOOGLE_APPLICATION_CREDENTIALS, and keep surrounding JSON syntax and punctuation
unchanged.

In `@webview-ui/src/utils/validate.ts`:
- Around line 130-133: The validation for "zoo-gateway" currently accepts a user
if zooCodeIsAuthenticated is true even when apiConfiguration.zooSessionToken is
missing; change the condition in validate.ts (the "zoo-gateway" case) to require
the persisted token (apiConfiguration.zooSessionToken) be present before passing
validation and do not treat zooCodeIsAuthenticated as a substitute, or
alternatively add and check a seeding-complete flag (set by
ensureZooGatewayProfileSeeded) so validation only passes when the stored token
is present or seeding has finished; update the return logic that currently
references apiConfiguration.zooSessionToken and zooCodeIsAuthenticated
accordingly.

---

Minor comments:
In `@src/api/providers/fetchers/zoo-gateway.ts`:
- Around line 68-77: The code issues an axios.get to `${baseURL}/models` even
when no session token is available (sessionToken from options?.zooSessionToken
|| getCachedZooCodeToken), causing needless failed requests; update the logic to
short-circuit before the network call when sessionToken is falsy (e.g., return
an empty models list or null from the enclosing function), so do not call
axios.get or use MODEL_DISCOVERY_TIMEOUT_MS without credentials—use the
sessionToken variable and the axios.get call sites as the anchors to implement
the early return.

In `@src/core/webview/__tests__/ClineProvider.spec.ts`:
- Around line 3760-3771: The test "logs and posts state when profile persistence
fails" currently only asserts the log path; update the spec to also assert that
provider.postStateToWebview was invoked after calling
provider.handleZooCodeCallback("zoo_ext_token") (or alternatively rename the
test to reflect it only verifies logging). Specifically, locate the test using
provider.handleZooCodeCallback and add an
expect(provider.postStateToWebview).toHaveBeenCalled() (or rename the it(...)
description) so the test actually verifies the state-post behavior.

In `@webview-ui/src/i18n/locales/ca/settings.json`:
- Line 455: The Catalan translation for the key
"googleCloudCredentialsPathWarning" contains mojibake ("a continuaci├│")—replace
it with the correct text ("a continuació") and verify the corresponding
duplicate entry later in the same settings.json (the other occurrence flagged by
the reviewer) is fixed the same way; finally re-save the file in UTF-8 (no BOM)
to prevent encoding corruption going forward.

In `@webview-ui/src/i18n/locales/de/settings.json`:
- Line 455: The German strings contain mojibake where umlauts were corrupted;
update the values for the keys googleCloudCredentialsPathWarning and
modelPicker.automaticFetch in the locales file to use the correct German
characters (e.g., "Schlüssel" and "Schlüsseldateipfad") so the messages read
correctly—specifically replace "Schl├╝ssel" and "Schl├╝sseldateipfad" with
"Schlüssel" and "Schlüsseldateipfad" and ensure the rest of the
punctuation/HTML/templating (like <strong> and <code>) remains unchanged.

In `@webview-ui/src/i18n/locales/es/settings.json`:
- Line 455: The Spanish locale string under the key
"googleCloudCredentialsPathWarning" contains mojibake (e.g., "pégala", "a
continuaci├│n"); update that value to use proper UTF-8 accented characters
(e.g., "pégala", "a continuación") and scan the same file for the other affected
key around line 871 to fix similar garbled sequences so all Spanish strings are
valid UTF-8.

In `@webview-ui/src/i18n/locales/fr/settings.json`:
- Line 455: The JSON value for the "googleCloudCredentialsPathWarning" key
contains mojibake (garbled characters); replace it with the correct French
translation (use proper accents) and ensure the file is saved as UTF-8; also
locate and fix the other occurrence noted (same mojibake at the other key around
line 871) so both keys contain proper French strings with correct accents and
encoding.

In `@webview-ui/src/i18n/locales/it/settings.json`:
- Line 871: The value for the i18n key modelPicker.automaticFetch contains
mojibake ("pi├╣") instead of the correct Italian character; update the string
for modelPicker.automaticFetch to replace "pi├╣ recente" with "più recente"
(keep the existing HTML-like links <serviceLink>{{serviceName}}</serviceLink>
and <defaultModelLink>{{defaultModelId}}</defaultModelLink> and preserve any
escaped quotes), ensuring the file is saved as UTF-8 so the "ù" character is
stored correctly.

In `@webview-ui/src/i18n/locales/ja/settings.json`:
- Line 455: The value for the i18n key "googleCloudCredentialsPathWarning"
contains mojibake (wrong encoding); open the locale file, replace the garbled
string with the correct Japanese copy for that key (preserving the intended
inline tokens like <strong>Google Cloud…</strong> and
<code>GOOGLE_APPLICATION_CREDENTIALS</code>), ensure the file is saved as UTF-8
(preferably UTF-8 without BOM), and apply the same fix to the other corrupted
localized entry in the same file that was flagged as also affected.

In `@webview-ui/src/i18n/locales/pt-BR/settings.json`:
- Line 455: The Portuguese translation for the key
"googleCloudCredentialsPathWarning" (and the other affected key around the same
area) contains mojibake (UTF-8 corruption) and must be replaced with correctly
encoded UTF-8 text; locate the "googleCloudCredentialsPathWarning" entry in the
pt-BR locale and update the string to use proper Portuguese characters (e.g.,
"conteúdo", "conta de serviço", "não", "você", "variável de ambiente", "Caminho
do Arquivo de Chave Google Cloud") so the UI renders correctly; ensure the same
corrections are applied to the other corrupted pt-BR string referenced in the
review.

In `@webview-ui/src/i18n/locales/tr/settings.json`:
- Line 455: The Turkish strings for keys googleCloudCredentialsPathWarning and
modelPicker.automaticFetch contain mojibake (corrupted characters); open the
localization entries for these keys, replace the corrupted characters with the
correct Turkish characters/words (e.g., restore characters like ı, ş, ç, ğ, ö,
ü) so the sentences read naturally, ensure the file is saved in UTF-8 without
BOM, and also fix the identical corrupted instance noted around the other
occurrence (modelPicker.automaticFetch) so both entries render correctly.

In `@webview-ui/src/i18n/locales/zh-TW/settings.json`:
- Line 465: The Traditional Chinese strings for the keys
googleCloudCredentialsPathWarning and modelPicker.automaticFetch are corrupted
(mojibake); locate the JSON entries for "googleCloudCredentialsPathWarning" and
"modelPicker.automaticFetch" and replace the garbled text with correct
Traditional Chinese translations, preserving any inline HTML tags like <strong>
and <code> and ensuring the meaning about setting GOOGLE_APPLICATION_CREDENTIALS
and automatic model fetching remains accurate; also fix the duplicate occurrence
noted (the other affected entry around the second mention) so both occurrences
show readable Traditional Chinese.

---

Nitpick comments:
In `@src/core/webview/__tests__/webviewMessageHandler.spec.ts`:
- Around line 397-433: Tests mutate the shared mockClineProvider
(providerSettingsManager, upsertProviderProfile, contextProxy) inline which can
leak state if a test fails; instead, capture original values at test start and
restore them in an afterEach hook (or wrap each test body in try/finally), e.g.
save const origProviderSettings = (mockClineProvider as
any).providerSettingsManager, origUpsert = (mockClineProvider as
any).upsertProviderProfile, origContext = (mockClineProvider as
any).contextProxy and restore them after the test; apply this stabilization for
the tests that set providerSettingsManager, upsertProviderProfile, or override
contextProxy (the block around webviewMessageHandler and the other similar test
blocks).

In `@webview-ui/src/components/settings/providers/__tests__/ZooGateway.spec.tsx`:
- Around line 150-152: The non-call assertion for setApiConfigurationField in
ZooGateway.spec.tsx can pass too early; wrap the expectation in waitFor that
waits long enough for async effects (e.g., await waitFor(() =>
expect(setApiConfigurationField).not.toHaveBeenCalled(), { timeout: 1000 })) or
explicitly flush pending promises before the assertion (e.g., await
flushPromises(); expect(setApiConfigurationField).not.toHaveBeenCalled());
update the test to use one of these approaches targeting the
waitFor/setApiConfigurationField usage so the assertion runs after effects
settle.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 087f53ae-b7bd-4ddc-b44c-cb6d44c2080d

📥 Commits

Reviewing files that changed from the base of the PR and between 3251b6e and 89559d5.

📒 Files selected for processing (50)
  • PRIVACY.md
  • packages/types/src/provider-settings.ts
  • packages/types/src/providers/index.ts
  • packages/types/src/providers/zoo-gateway.ts
  • src/activate/__tests__/handleUri.spec.ts
  • src/activate/handleUri.ts
  • src/api/index.ts
  • src/api/providers/fetchers/__tests__/zoo-gateway.spec.ts
  • src/api/providers/fetchers/modelCache.ts
  • src/api/providers/fetchers/zoo-gateway.ts
  • src/api/providers/index.ts
  • src/api/providers/zoo-gateway.ts
  • src/core/webview/ClineProvider.ts
  • src/core/webview/__tests__/ClineProvider.spec.ts
  • src/core/webview/__tests__/webviewMessageHandler.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • src/i18n/locales/en/common.json
  • src/services/__tests__/zoo-telemetry.test.ts
  • src/services/zoo-telemetry.ts
  • src/shared/api.ts
  • webview-ui/src/components/settings/ApiOptions.tsx
  • webview-ui/src/components/settings/ModelPicker.tsx
  • webview-ui/src/components/settings/__tests__/ApiOptions.spec.tsx
  • webview-ui/src/components/settings/constants.ts
  • webview-ui/src/components/settings/providers/ZooGateway.tsx
  • webview-ui/src/components/settings/providers/__tests__/ZooGateway.spec.tsx
  • webview-ui/src/components/settings/providers/index.ts
  • webview-ui/src/components/ui/hooks/useSelectedModel.ts
  • webview-ui/src/components/welcome/WelcomeViewProvider.tsx
  • webview-ui/src/i18n/locales/ca/settings.json
  • webview-ui/src/i18n/locales/de/settings.json
  • webview-ui/src/i18n/locales/en/settings.json
  • webview-ui/src/i18n/locales/es/settings.json
  • webview-ui/src/i18n/locales/fr/settings.json
  • webview-ui/src/i18n/locales/hi/settings.json
  • webview-ui/src/i18n/locales/id/settings.json
  • webview-ui/src/i18n/locales/it/settings.json
  • webview-ui/src/i18n/locales/ja/settings.json
  • webview-ui/src/i18n/locales/ko/settings.json
  • webview-ui/src/i18n/locales/nl/settings.json
  • webview-ui/src/i18n/locales/pl/settings.json
  • webview-ui/src/i18n/locales/pt-BR/settings.json
  • webview-ui/src/i18n/locales/ru/settings.json
  • webview-ui/src/i18n/locales/tr/settings.json
  • webview-ui/src/i18n/locales/vi/settings.json
  • webview-ui/src/i18n/locales/zh-CN/settings.json
  • webview-ui/src/i18n/locales/zh-TW/settings.json
  • webview-ui/src/utils/__tests__/validate.spec.ts
  • webview-ui/src/utils/validate.ts
  • webview-ui/vite.config.ts
✅ Files skipped from review due to trivial changes (6)
  • webview-ui/src/components/settings/providers/index.ts
  • webview-ui/src/components/settings/constants.ts
  • webview-ui/src/utils/tests/validate.spec.ts
  • webview-ui/src/i18n/locales/en/settings.json
  • webview-ui/src/i18n/locales/nl/settings.json
  • PRIVACY.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/services/tests/zoo-telemetry.test.ts

Comment thread src/activate/handleUri.ts
Comment on lines +65 to 67
for (const instance of allInstances) {
await instance.handleZooCodeCallback(token)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Isolate per-instance callback failures so one throw doesn’t block the rest.

A single rejected handleZooCodeCallback aborts the loop and leaves other active instances stale.

Proposed resilience fix
 					const allInstances = ClineProvider.getAllInstances()
 					for (const instance of allInstances) {
-						await instance.handleZooCodeCallback(token)
+						try {
+							await instance.handleZooCodeCallback(token)
+						} catch (error) {
+							console.error("Failed to persist Zoo Code callback for one provider instance")
+						}
 					}
🤖 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 `@src/activate/handleUri.ts` around lines 65 - 67, The loop over allInstances
calls instance.handleZooCodeCallback(token) directly, so one rejected call
aborts the whole loop; update the loop to call handleZooCodeCallback for each
instance inside a try/catch (e.g., within the for (const instance of
allInstances) block), catch and log the error (including instance identifier if
available) and continue to the next instance so one failure does not prevent
other instances from receiving the callback.

Comment on lines +102 to +107
// Prefer the profile-persisted token; fall back to the secret-storage cache so
// requests work when the user is signed in but the profile hasn't been seeded yet
// (e.g. auth callback arrived before any webview instance was open).
const sessionToken = options.zooSessionToken || getCachedZooCodeToken()
if (!sessionToken) {
throw new Error("Zoo Gateway requires authentication. Please sign in to Zoo Code first.")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prefer the cached Zoo Code token over the persisted profile token.

After re-auth or token rotation, options.zooSessionToken can be stale while getCachedZooCodeToken() already holds the fresh session. The current order keeps using the stale profile token, so the handler can stay stuck on repeated 401s until profile sync finishes successfully.

Suggested fix
-		const sessionToken = options.zooSessionToken || getCachedZooCodeToken()
+		const sessionToken = getCachedZooCodeToken() || options.zooSessionToken
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Prefer the profile-persisted token; fall back to the secret-storage cache so
// requests work when the user is signed in but the profile hasn't been seeded yet
// (e.g. auth callback arrived before any webview instance was open).
const sessionToken = options.zooSessionToken || getCachedZooCodeToken()
if (!sessionToken) {
throw new Error("Zoo Gateway requires authentication. Please sign in to Zoo Code first.")
// Prefer the profile-persisted token; fall back to the secret-storage cache so
// requests work when the user is signed in but the profile hasn't been seeded yet
// (e.g. auth callback arrived before any webview instance was open).
const sessionToken = getCachedZooCodeToken() || options.zooSessionToken
if (!sessionToken) {
throw new Error("Zoo Gateway requires authentication. Please sign in to Zoo Code first.")
🤖 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 `@src/api/providers/zoo-gateway.ts` around lines 102 - 107, The code currently
prefers options.zooSessionToken over getCachedZooCodeToken(), which can keep
using a stale profile token; change the selection so the cached token is
preferred (e.g., set sessionToken by calling getCachedZooCodeToken() first and
falling back to options.zooSessionToken) — update the assignment around the
sessionToken variable in the zoo-gateway.ts handler where
options.zooSessionToken and getCachedZooCodeToken() are used so fresh cached
tokens are used before the persisted profile token.

Comment on lines +873 to 916
private async ensureZooGatewayProfileSeeded(): Promise<void> {
const { getCachedZooCodeToken } = await import("../../services/zoo-code-auth")
const token = getCachedZooCodeToken()
if (!token) return

// Check ALL zoo-gateway profiles — only skip seeding if every profile has the current token.
// Using .find() would miss stale tokens in duplicate/renamed profiles since handleZooCodeCallback
// uses .filter() and updates all of them — the early-return guard must match.
const allProfiles = await this.providerSettingsManager.listConfig()
const zooGatewayProfiles = allProfiles.filter((p) => p.apiProvider === "zoo-gateway")

if (zooGatewayProfiles.length === 0) {
this.log("[ensureZooGatewayProfileSeeded] No zoo-gateway profile found, creating one")
} else {
let allUpToDate = true

for (const entry of zooGatewayProfiles) {
try {
const fullProfile = await this.providerSettingsManager.getProfile({ name: entry.name })
if (fullProfile.zooSessionToken !== token) {
allUpToDate = false
this.log(
fullProfile.zooSessionToken
? "[ensureZooGatewayProfileSeeded] Token mismatch (stale session?), updating with current token"
: "[ensureZooGatewayProfileSeeded] Existing zoo-gateway profile has no token, updating with cached token",
)
break
}
} catch {
allUpToDate = false
this.log("[ensureZooGatewayProfileSeeded] Failed to read existing profile, will re-seed")
break
}
}

if (allUpToDate) {
// All profiles have the current token — nothing to do
return
}
}

// User has token but either no profile, some profiles without token, or stale tokens — seed all
await this.handleZooCodeCallback(token)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Also repair stale zooGatewayBaseUrl values here.

The early-return only verifies that each profile already has the cached token. If getZooCodeBaseUrl() changes between sessions, every profile can look "up to date" while still pointing at the old gateway host, so requests keep routing to the wrong environment until the user re-authenticates.

Suggested fix
 private async ensureZooGatewayProfileSeeded(): Promise<void> {
-	const { getCachedZooCodeToken } = await import("../../services/zoo-code-auth")
+	const { getCachedZooCodeToken, getZooCodeBaseUrl } = await import("../../services/zoo-code-auth")
 	const token = getCachedZooCodeToken()
 	if (!token) return
+	const derivedGatewayBaseUrl = `${getZooCodeBaseUrl()}/api/gateway/v1`

 	// Check ALL zoo-gateway profiles — only skip seeding if every profile has the current token.
 	// Using .find() would miss stale tokens in duplicate/renamed profiles since handleZooCodeCallback
 	// uses .filter() and updates all of them — the early-return guard must match.
 	const allProfiles = await this.providerSettingsManager.listConfig()
 	const zooGatewayProfiles = allProfiles.filter((p) => p.apiProvider === "zoo-gateway")

 	if (zooGatewayProfiles.length === 0) {
 		this.log("[ensureZooGatewayProfileSeeded] No zoo-gateway profile found, creating one")
 	} else {
 		let allUpToDate = true

 		for (const entry of zooGatewayProfiles) {
 			try {
 				const fullProfile = await this.providerSettingsManager.getProfile({ name: entry.name })
-				if (fullProfile.zooSessionToken !== token) {
+				if (
+					fullProfile.zooSessionToken !== token ||
+					fullProfile.zooGatewayBaseUrl !== derivedGatewayBaseUrl
+				) {
 					allUpToDate = false
-					this.log(
-						fullProfile.zooSessionToken
-							? "[ensureZooGatewayProfileSeeded] Token mismatch (stale session?), updating with current token"
-							: "[ensureZooGatewayProfileSeeded] Existing zoo-gateway profile has no token, updating with cached token",
-					)
+					this.log("[ensureZooGatewayProfileSeeded] Existing zoo-gateway profile is stale, updating")
 					break
 				}
 			} catch {
 				allUpToDate = false
 				this.log("[ensureZooGatewayProfileSeeded] Failed to read existing profile, will re-seed")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private async ensureZooGatewayProfileSeeded(): Promise<void> {
const { getCachedZooCodeToken } = await import("../../services/zoo-code-auth")
const token = getCachedZooCodeToken()
if (!token) return
// Check ALL zoo-gateway profiles — only skip seeding if every profile has the current token.
// Using .find() would miss stale tokens in duplicate/renamed profiles since handleZooCodeCallback
// uses .filter() and updates all of them — the early-return guard must match.
const allProfiles = await this.providerSettingsManager.listConfig()
const zooGatewayProfiles = allProfiles.filter((p) => p.apiProvider === "zoo-gateway")
if (zooGatewayProfiles.length === 0) {
this.log("[ensureZooGatewayProfileSeeded] No zoo-gateway profile found, creating one")
} else {
let allUpToDate = true
for (const entry of zooGatewayProfiles) {
try {
const fullProfile = await this.providerSettingsManager.getProfile({ name: entry.name })
if (fullProfile.zooSessionToken !== token) {
allUpToDate = false
this.log(
fullProfile.zooSessionToken
? "[ensureZooGatewayProfileSeeded] Token mismatch (stale session?), updating with current token"
: "[ensureZooGatewayProfileSeeded] Existing zoo-gateway profile has no token, updating with cached token",
)
break
}
} catch {
allUpToDate = false
this.log("[ensureZooGatewayProfileSeeded] Failed to read existing profile, will re-seed")
break
}
}
if (allUpToDate) {
// All profiles have the current token — nothing to do
return
}
}
// User has token but either no profile, some profiles without token, or stale tokens — seed all
await this.handleZooCodeCallback(token)
}
private async ensureZooGatewayProfileSeeded(): Promise<void> {
const { getCachedZooCodeToken, getZooCodeBaseUrl } = await import("../../services/zoo-code-auth")
const token = getCachedZooCodeToken()
if (!token) return
const derivedGatewayBaseUrl = `${getZooCodeBaseUrl()}/api/gateway/v1`
// Check ALL zoo-gateway profiles — only skip seeding if every profile has the current token.
// Using .find() would miss stale tokens in duplicate/renamed profiles since handleZooCodeCallback
// uses .filter() and updates all of them — the early-return guard must match.
const allProfiles = await this.providerSettingsManager.listConfig()
const zooGatewayProfiles = allProfiles.filter((p) => p.apiProvider === "zoo-gateway")
if (zooGatewayProfiles.length === 0) {
this.log("[ensureZooGatewayProfileSeeded] No zoo-gateway profile found, creating one")
} else {
let allUpToDate = true
for (const entry of zooGatewayProfiles) {
try {
const fullProfile = await this.providerSettingsManager.getProfile({ name: entry.name })
if (
fullProfile.zooSessionToken !== token ||
fullProfile.zooGatewayBaseUrl !== derivedGatewayBaseUrl
) {
allUpToDate = false
this.log("[ensureZooGatewayProfileSeeded] Existing zoo-gateway profile is stale, updating")
break
}
} catch {
allUpToDate = false
this.log("[ensureZooGatewayProfileSeeded] Failed to read existing profile, will re-seed")
break
}
}
if (allUpToDate) {
// All profiles have the current token — nothing to do
return
}
}
// User has token but either no profile, some profiles without token, or stale tokens — seed all
await this.handleZooCodeCallback(token)
}
🤖 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 `@src/core/webview/ClineProvider.ts` around lines 873 - 916,
ensureZooGatewayProfileSeeded currently only compares profile.zooSessionToken to
getCachedZooCodeToken(); also check that each profile.zooGatewayBaseUrl equals
the current getZooCodeBaseUrl() and treat any mismatch as stale so seeding
occurs. In the loop that inspects zooGatewayProfiles (using
providerSettingsManager.getProfile and the token check), fetch the current base
URL via getZooCodeBaseUrl(), compare it to fullProfile.zooGatewayBaseUrl, and if
different set allUpToDate = false, log a descriptive message, and break so
handleZooCodeCallback(token) will be invoked to reseed both tokens and base
URLs. Ensure references to ensureZooGatewayProfileSeeded, getCachedZooCodeToken,
getZooCodeBaseUrl, providerSettingsManager.getProfile, and handleZooCodeCallback
are used to locate the changes.

Comment thread src/core/webview/webviewMessageHandler.ts
},
"googleCloudCredentials": "Google Cloud क्रेडेंशियल्स",
"googleCloudCredentialsPathWarning": "इस फ़ील्ड में सर्विस-अकाउंट कुंजी फ़ाइल की JSON सामग्री अपेक्षित है, पथ नहीं। यदि आपके पास पथ है, तो उसे नीचे दिए गए <strong>Google Cloud कुंजी फ़ाइल पथ</strong> फ़ील्ड में पेस्ट करें, या इस फ़ील्ड को खाली करें और <code>GOOGLE_APPLICATION_CREDENTIALS</code> पर्यावरण चर का उपयोग करें।",
"googleCloudCredentialsPathWarning": "इस फ़ील्ड में सर्विस-अकाउंट कुंजी फ़ाइल की JSON सामग्री अपेक्षित है, पथ नहीं। यदि आपके पास पथ है, तो उसे नीचे दिए गए <strong>Google Cloud कुंजी फ़ाइल पथ</strong> फ़ील्ड में पेस्ट करें, या इस फ़ील्ड को खाली करें और <code>GOOGLE_APPLICATION_CREDENTIALS</code> पर्यावरण चर का उपयोग करें।",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace mojibake strings with valid Hindi copy.

Line 455 and Line 871 contain unreadable encoded text, so critical setup/help content is broken for Hindi users.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/hi/settings.json` at line 455, The string value
for "googleCloudCredentialsPathWarning" (and the other mojibake entry at line
871) contains garbled text; replace these mojibake strings with proper Hindi
translations while preserving inline HTML tags (<strong>, <code>) and meaning
about Google Cloud credentials and GOOGLE_APPLICATION_CREDENTIALS, updating the
JSON values for the keys (e.g., "googleCloudCredentialsPathWarning") so the
help/setup content reads correctly in Hindi.

},
"googleCloudCredentials": "Poświadczenia Google Cloud",
"googleCloudCredentialsPathWarning": "To pole oczekuje zawartości JSON pliku klucza konta usługi, a nie ścieżki. Jeśli masz ścieżkę, wklej do pola <strong>Ścieżka pliku klucza Google Cloud</strong> poniżej lub wyczyść to pole i użyj zmiennej środowiskowej <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
"googleCloudCredentialsPathWarning": "To pole oczekuje zawartości JSON pliku klucza konta usługi, a nie ścieżki. Jeśli masz ścieżkę, wklej ją do pola <strong>Ścieżka pliku klucza Google Cloud</strong> poniżej lub wyczyść to pole i użyj zmiennej środowiskowej <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace mojibake in Polish localized messages.

Line 455 and Line 871 contain corrupted characters, making key setup and model-selection text hard to understand.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/pl/settings.json` at line 455, The string value
for "googleCloudCredentialsPathWarning" contains mojibake (garbled Unicode) and
should be replaced with correctly encoded Polish text (use proper characters
like ą,ę,ś,ł,ż,ó,ć,ń) and similarly fix the corrupted message at the
model-selection key on the other occurrence (line ~871); open the JSON entry for
"googleCloudCredentialsPathWarning" and the model-selection key, replace the
garbled characters with the correct Polish phrasing, and ensure the file is
saved with UTF-8 encoding so the Polish diacritics persist.

},
"googleCloudCredentials": "Учётные данные Google Cloud",
"googleCloudCredentialsPathWarning": "Это поле ожидает JSON-содержимое файла ключа сервисного аккаунта, а не путь. Если у вас есть путь, вставьте его в поле <strong>Путь к ключу Google Cloud</strong> ниже, либо очистите это поле и используйте переменную окружения <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
"googleCloudCredentialsPathWarning": "Это поле ожидает JSON-содержимое файла ключа сервисного аккаунта, а не путь. Если у вас есть путь, вставьте его в поле <strong>Путь к ключу Google Cloud</strong> ниже, либо очистите это поле и используйте переменную окружения <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore valid Russian text for the modified warning/help strings.

Line 455 and Line 871 are encoding-corrupted, so users can’t read key setup/model-selection guidance.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/ru/settings.json` at line 455, The JSON values
for Russian locale contain encoding-corrupted text; replace the corrupted value
for the key "googleCloudCredentialsPathWarning" in settings.json with a proper
Russian translation and likewise locate and restore the other corrupted Russian
string near line 871 (search for non-UTF8/garbled characters) so both
warning/help messages are readable; ensure the replacements are valid UTF-8,
preserve existing HTML/inline code tags like <strong> and <code> exactly, and
run a quick JSON lint to confirm no syntax changes.

},
"googleCloudCredentials": "Thông tin xác thực Google Cloud",
"googleCloudCredentialsPathWarning": "Trường này mong đợi nội dung JSON của tệp khóa tài khoản dịch vụ, không phải đường dẫn. Nếu bạn có đường dẫn, hãy dán vào trường <strong>Đường dẫn tệp khóa Google Cloud</strong> bên dưới, hoặc xóa trường này và sử dụng biến môi trường <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
"googleCloudCredentialsPathWarning": "Trường này mong đợi nội dung JSON của tệp khóa tài khoản dịch vụ, không phải đường dẫn. Nếu bạn có đường dẫn, hãy dán vào trường <strong>Đường dẫn tệp khóa Google Cloud</strong> bên dưới, hoặc xóa trường này và sử dụng biến môi trường <code>GOOGLE_APPLICATION_CREDENTIALS</code>.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix encoding-corrupted Vietnamese strings.

Line 455 and Line 871 are mojibake, so important provider instructions are unreadable in this locale.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/vi/settings.json` at line 455, The string value
for the locale key "googleCloudCredentialsPathWarning" (and the other corrupted
Vietnamese entry in the same file) is mojibake; replace the corrupted text with
the correct Vietnamese translations, ensure the HTML (<strong>) and code
(<code>) fragments remain intact, save the file encoded as UTF-8 without BOM,
and validate the JSON (lint/parse) after the replacement so the locale renders
correctly.

},
"googleCloudCredentials": "Google Cloud 凭证",
"googleCloudCredentialsPathWarning": "此字段需要服务账号密钥文件的 JSON 内容,而不是路径。如果您有路径,请将其粘贴到下方的<strong>Google Cloud 密钥文件路径</strong>字段中,或清除此字段并使用 <code>GOOGLE_APPLICATION_CREDENTIALS</code> 环境变量。",
"googleCloudCredentialsPathWarning": "此字段需要服务账号密钥文件的 JSON 内容,而不是路径。如果您有路径,请将其粘贴到下方的<strong>Google Cloud 密钥文件路径</strong>字段中,或清除此字段并使用 <code>GOOGLE_APPLICATION_CREDENTIALS</code> 环境变量。",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix corrupted Simplified Chinese translations.

Line 455 and Line 871 are unreadable mojibake, which breaks important provider guidance in this locale.

Also applies to: 871-871

🤖 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 `@webview-ui/src/i18n/locales/zh-CN/settings.json` at line 455, Fix the
mojibake in the Simplified Chinese locale by replacing the corrupted string
value for the key "googleCloudCredentialsPathWarning" (and the other corrupted
entry at the second occurrence referenced) with a proper Simplified Chinese
translation that preserves the embedded HTML and code tags (<strong>...</strong>
and <code>GOOGLE_APPLICATION_CREDENTIALS</code>); locate the entries by the key
"googleCloudCredentialsPathWarning" and the other unreadable key near the same
block, correct the text to clear, idiomatic Chinese guidance about placing a
Google Cloud service account JSON file and setting
GOOGLE_APPLICATION_CREDENTIALS, and keep surrounding JSON syntax and punctuation
unchanged.

Comment on lines +130 to +133
case "zoo-gateway":
if (!apiConfiguration.zooSessionToken && !zooCodeIsAuthenticated) {
return i18next.t("settings:validation.zooGatewaySignIn")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't treat Zoo Code auth state as a substitute for a seeded gateway token.

This branch now accepts zoo-gateway while zooSessionToken is still missing. Since ensureZooGatewayProfileSeeded() is kicked off in the background during webview init, a signed-in user can pass validation and start a request before the profile has actually been repaired, so the first gateway call is still unauthenticated. Keep validation gated on the stored token, or block Zoo Gateway until seeding completes.

🤖 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 `@webview-ui/src/utils/validate.ts` around lines 130 - 133, The validation for
"zoo-gateway" currently accepts a user if zooCodeIsAuthenticated is true even
when apiConfiguration.zooSessionToken is missing; change the condition in
validate.ts (the "zoo-gateway" case) to require the persisted token
(apiConfiguration.zooSessionToken) be present before passing validation and do
not treat zooCodeIsAuthenticated as a substitute, or alternatively add and check
a seeding-complete flag (set by ensureZooGatewayProfileSeeded) so validation
only passes when the stored token is present or seeding has finished; update the
return logic that currently references apiConfiguration.zooSessionToken and
zooCodeIsAuthenticated accordingly.

@JamesRobert20 JamesRobert20 force-pushed the feat/zoo-gateway-telemetry-policy branch from 89559d5 to 9750f48 Compare May 28, 2026 20:48
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 `@src/i18n/locales/tr/common.json`:
- Around line 264-278: This PR includes new Turkish locale keys
(could_not_verify_token, session_expired, out_of_credits, account_unavailable,
budget_exceeded, info.connected, info.disconnected, buttons.sign_in,
buttons.add_credits, buttons.contact_support) that are unrelated to the stated
privacy/telemetry changes; please confirm whether these i18n additions are part
of a separate Zoo Gateway auth/billing feature and if so remove them from this
branch and open a dedicated PR for the Gateway UX, otherwise update the PR
description to list these locale changes; also verify that the intended
privacy/telemetry edits (PRIVACY.md and zoo-telemetry.ts) are present on the
branch—if they are missing, add those files/changes or point to the correct
branch/commit that contains them before merging.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 098eec11-2d23-4f57-b28f-37e11d4eb16d

📥 Commits

Reviewing files that changed from the base of the PR and between 89559d5 and 9750f48.

📒 Files selected for processing (20)
  • PRIVACY.md
  • src/i18n/locales/ca/common.json
  • src/i18n/locales/de/common.json
  • src/i18n/locales/es/common.json
  • src/i18n/locales/fr/common.json
  • src/i18n/locales/hi/common.json
  • src/i18n/locales/id/common.json
  • src/i18n/locales/it/common.json
  • src/i18n/locales/ja/common.json
  • src/i18n/locales/ko/common.json
  • src/i18n/locales/nl/common.json
  • src/i18n/locales/pl/common.json
  • src/i18n/locales/pt-BR/common.json
  • src/i18n/locales/ru/common.json
  • src/i18n/locales/tr/common.json
  • src/i18n/locales/vi/common.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/zh-TW/common.json
  • src/services/__tests__/zoo-telemetry.test.ts
  • src/services/zoo-telemetry.ts
✅ Files skipped from review due to trivial changes (8)
  • src/i18n/locales/nl/common.json
  • src/i18n/locales/it/common.json
  • PRIVACY.md
  • src/i18n/locales/ko/common.json
  • src/i18n/locales/ca/common.json
  • src/i18n/locales/de/common.json
  • src/i18n/locales/ja/common.json
  • src/i18n/locales/pl/common.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/services/tests/zoo-telemetry.test.ts

Comment thread src/i18n/locales/tr/common.json
James Mtendamema and others added 11 commits May 28, 2026 15:17
The downstream stack (settings-ui) calls getCachedZooCodeToken and
clearZooCodeToken from the auth handler. CI on stacked PRs merges base
into head so this spec runs against the cached-token-aware handler;
expand the auth module mock so the auth guard test exercises the real
throw path instead of vitest's missing-mock-export error.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
- Resolve ModelPicker serviceUrl from zooCodeBaseUrl so staging/dev
  environments link to the matching dashboard.
- Fall back to getCachedZooCodeToken() in the handler and model fetcher
  when the profile has not been seeded yet (auth before webview open).

Co-authored-by: Cursor <cursoragent@cursor.com>
…-lockfile installs

Co-authored-by: Cursor <cursoragent@cursor.com>
…ch 'free' search hint dropped on rebase

Co-authored-by: Cursor <cursoragent@cursor.com>
… 4.5

Resolves Sonnet 4.5 from the gateway model catalog instead of a static Vercel slug so test (Bedrock) and live accounts both get a valid default. Reassigns stale profile model IDs when they are not in the catalog.

Co-authored-by: Cursor <cursoragent@cursor.com>
Exports pickZooGatewayDefaultModelId so the helper is unit-testable and adds
component tests for the auto-default useEffect (no-op while catalog loads,
auto-pick on empty profile, repair stale id, no-op when valid).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add ClineProvider tests for handleZooCodeCallback, ensureZooGatewayProfileSeeded, and webviewMessageHandler zooCodeSignOut to satisfy codecov patch on PR #347.

Co-authored-by: Cursor <cursoragent@cursor.com>
Clear the cached token on 401 and offer sign-in. On insufficient credits
or budget limits, open the credits page. On account frozen/banned, open
support. Errors still propagate to the task layer after the toast.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ocales

Adds session_expired, out_of_credits, account_unavailable, budget_exceeded
under zooAuth.errors and a new zooAuth.buttons block (sign_in, add_credits,
contact_support) introduced by the gateway 401/402/403 UX so check-translations
passes.

Co-authored-by: Cursor <cursoragent@cursor.com>
James Mtendamema and others added 3 commits May 28, 2026 15:28
…ov patch

Adds vscode + i18n mocks and asserts the 401/402/403/429 paths in
surfaceGatewayApiError: token clear + sign-in URL on 401, add-credits
URL on 402 and budget-coded 429, support URL on 403, no-op on 429
without a budget code or on errors without a status. Also verifies the
helper still runs before completePrompt rewraps the upstream error.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…tion gating expectation

Co-authored-by: Cursor <cursoragent@cursor.com>
@JamesRobert20 JamesRobert20 force-pushed the feat/zoo-gateway-telemetry-policy branch from 9750f48 to 91f52ae Compare May 28, 2026 21:29
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 `@src/core/webview/webviewMessageHandler.ts`:
- Around line 956-963: The code currently picks the first zoo-gateway profile
from provider.providerSettingsManager.listConfig() and uses its token, which
fails if that profile lacks zooSessionToken; instead, iterate or map over all
profiles where p.apiProvider === "zoo-gateway", fetch each profile via
provider.providerSettingsManager.getProfile({ name: ... }) (e.g., Promise.all or
sequentially), and select the first fullProfile with a truthy
fullProfile.zooSessionToken, then assign zooGatewayToken =
fullProfile.zooSessionToken and zooGatewayBaseUrl =
fullProfile.zooGatewayBaseUrl ?? zooGatewayBaseUrl; ensure you fall back to the
previous base URL if none found.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9aa8a0a1-882a-4229-9619-5e386802f9f7

📥 Commits

Reviewing files that changed from the base of the PR and between 9750f48 and 91f52ae.

📒 Files selected for processing (59)
  • PRIVACY.md
  • src/activate/__tests__/handleUri.spec.ts
  • src/activate/handleUri.ts
  • src/api/providers/__tests__/zoo-gateway.spec.ts
  • src/api/providers/fetchers/__tests__/zoo-gateway.spec.ts
  • src/api/providers/fetchers/zoo-gateway.ts
  • src/api/providers/zoo-gateway.ts
  • src/core/webview/ClineProvider.ts
  • src/core/webview/__tests__/ClineProvider.spec.ts
  • src/core/webview/__tests__/webviewMessageHandler.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • src/i18n/locales/ca/common.json
  • src/i18n/locales/de/common.json
  • src/i18n/locales/en/common.json
  • src/i18n/locales/es/common.json
  • src/i18n/locales/fr/common.json
  • src/i18n/locales/hi/common.json
  • src/i18n/locales/id/common.json
  • src/i18n/locales/it/common.json
  • src/i18n/locales/ja/common.json
  • src/i18n/locales/ko/common.json
  • src/i18n/locales/nl/common.json
  • src/i18n/locales/pl/common.json
  • src/i18n/locales/pt-BR/common.json
  • src/i18n/locales/ru/common.json
  • src/i18n/locales/tr/common.json
  • src/i18n/locales/vi/common.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/zh-TW/common.json
  • src/services/__tests__/zoo-telemetry.test.ts
  • src/services/zoo-telemetry.ts
  • webview-ui/src/components/settings/ApiOptions.tsx
  • webview-ui/src/components/settings/ModelPicker.tsx
  • webview-ui/src/components/settings/__tests__/ApiOptions.spec.tsx
  • webview-ui/src/components/settings/constants.ts
  • webview-ui/src/components/settings/providers/ZooGateway.tsx
  • webview-ui/src/components/settings/providers/__tests__/ZooGateway.spec.tsx
  • webview-ui/src/components/settings/providers/index.ts
  • webview-ui/src/components/welcome/WelcomeViewProvider.tsx
  • webview-ui/src/i18n/locales/ca/settings.json
  • webview-ui/src/i18n/locales/de/settings.json
  • webview-ui/src/i18n/locales/en/settings.json
  • webview-ui/src/i18n/locales/es/settings.json
  • webview-ui/src/i18n/locales/fr/settings.json
  • webview-ui/src/i18n/locales/hi/settings.json
  • webview-ui/src/i18n/locales/id/settings.json
  • webview-ui/src/i18n/locales/it/settings.json
  • webview-ui/src/i18n/locales/ja/settings.json
  • webview-ui/src/i18n/locales/ko/settings.json
  • webview-ui/src/i18n/locales/nl/settings.json
  • webview-ui/src/i18n/locales/pl/settings.json
  • webview-ui/src/i18n/locales/pt-BR/settings.json
  • webview-ui/src/i18n/locales/ru/settings.json
  • webview-ui/src/i18n/locales/tr/settings.json
  • webview-ui/src/i18n/locales/vi/settings.json
  • webview-ui/src/i18n/locales/zh-CN/settings.json
  • webview-ui/src/i18n/locales/zh-TW/settings.json
  • webview-ui/src/utils/validate.ts
  • webview-ui/vite.config.ts
✅ Files skipped from review due to trivial changes (13)
  • webview-ui/src/components/settings/providers/index.ts
  • webview-ui/src/components/settings/constants.ts
  • PRIVACY.md
  • src/i18n/locales/ru/common.json
  • src/i18n/locales/hi/common.json
  • webview-ui/src/i18n/locales/id/settings.json
  • src/i18n/locales/ja/common.json
  • src/i18n/locales/vi/common.json
  • webview-ui/src/i18n/locales/en/settings.json
  • webview-ui/src/i18n/locales/es/settings.json
  • src/i18n/locales/pl/common.json
  • src/i18n/locales/tr/common.json
  • src/i18n/locales/pt-BR/common.json
🚧 Files skipped from review as they are similar to previous changes (40)
  • webview-ui/src/i18n/locales/de/settings.json
  • webview-ui/src/components/welcome/WelcomeViewProvider.tsx
  • webview-ui/src/components/settings/ModelPicker.tsx
  • src/i18n/locales/es/common.json
  • src/i18n/locales/id/common.json
  • webview-ui/src/utils/validate.ts
  • webview-ui/src/components/settings/tests/ApiOptions.spec.tsx
  • webview-ui/src/components/settings/ApiOptions.tsx
  • webview-ui/vite.config.ts
  • src/services/tests/zoo-telemetry.test.ts
  • webview-ui/src/i18n/locales/zh-CN/settings.json
  • src/services/zoo-telemetry.ts
  • src/activate/tests/handleUri.spec.ts
  • src/api/providers/fetchers/zoo-gateway.ts
  • src/api/providers/fetchers/tests/zoo-gateway.spec.ts
  • webview-ui/src/i18n/locales/ru/settings.json
  • webview-ui/src/i18n/locales/nl/settings.json
  • webview-ui/src/i18n/locales/tr/settings.json
  • src/i18n/locales/ca/common.json
  • src/i18n/locales/zh-CN/common.json
  • webview-ui/src/i18n/locales/vi/settings.json
  • webview-ui/src/i18n/locales/pt-BR/settings.json
  • src/i18n/locales/nl/common.json
  • src/core/webview/ClineProvider.ts
  • src/i18n/locales/zh-TW/common.json
  • webview-ui/src/i18n/locales/ko/settings.json
  • src/core/webview/tests/ClineProvider.spec.ts
  • webview-ui/src/i18n/locales/zh-TW/settings.json
  • webview-ui/src/i18n/locales/ja/settings.json
  • src/i18n/locales/it/common.json
  • src/api/providers/zoo-gateway.ts
  • src/i18n/locales/fr/common.json
  • webview-ui/src/i18n/locales/pl/settings.json
  • webview-ui/src/components/settings/providers/ZooGateway.tsx
  • webview-ui/src/i18n/locales/ca/settings.json
  • src/i18n/locales/en/common.json
  • src/core/webview/tests/webviewMessageHandler.spec.ts
  • webview-ui/src/i18n/locales/fr/settings.json
  • src/activate/handleUri.ts
  • webview-ui/src/i18n/locales/it/settings.json

Comment on lines +956 to +963
const allProfiles = await provider.providerSettingsManager.listConfig()
const zooGatewayProfile = allProfiles.find((p) => p.apiProvider === "zoo-gateway")
if (zooGatewayProfile) {
const fullProfile = await provider.providerSettingsManager.getProfile({
name: zooGatewayProfile.name,
})
zooGatewayToken = fullProfile.zooSessionToken
zooGatewayBaseUrl = fullProfile.zooGatewayBaseUrl ?? zooGatewayBaseUrl
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Search all zoo-gateway profiles for a usable token.

Line 957 selects only the first zoo-gateway profile. If that profile has no zooSessionToken, model fetch can fail even when another zoo-gateway profile has a valid token.

💡 Suggested fix
-					const zooGatewayProfile = allProfiles.find((p) => p.apiProvider === "zoo-gateway")
-					if (zooGatewayProfile) {
-						const fullProfile = await provider.providerSettingsManager.getProfile({
-							name: zooGatewayProfile.name,
-						})
-						zooGatewayToken = fullProfile.zooSessionToken
-						zooGatewayBaseUrl = fullProfile.zooGatewayBaseUrl ?? zooGatewayBaseUrl
-					}
+					const zooGatewayProfiles = allProfiles.filter((p) => p.apiProvider === "zoo-gateway")
+					for (const profileMeta of zooGatewayProfiles) {
+						const fullProfile = await provider.providerSettingsManager.getProfile({ name: profileMeta.name })
+						if (fullProfile.zooSessionToken) {
+							zooGatewayToken = fullProfile.zooSessionToken
+							zooGatewayBaseUrl = fullProfile.zooGatewayBaseUrl ?? zooGatewayBaseUrl
+							break
+						}
+					}
🤖 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 `@src/core/webview/webviewMessageHandler.ts` around lines 956 - 963, The code
currently picks the first zoo-gateway profile from
provider.providerSettingsManager.listConfig() and uses its token, which fails if
that profile lacks zooSessionToken; instead, iterate or map over all profiles
where p.apiProvider === "zoo-gateway", fetch each profile via
provider.providerSettingsManager.getProfile({ name: ... }) (e.g., Promise.all or
sequentially), and select the first fullProfile with a truthy
fullProfile.zooSessionToken, then assign zooGatewayToken =
fullProfile.zooSessionToken and zooGatewayBaseUrl =
fullProfile.zooGatewayBaseUrl ?? zooGatewayBaseUrl; ensure you fall back to the
previous base URL if none found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants