Skip to content

Commit 27705c4

Browse files
James Mtendamemacursoragent
andcommitted
fix(zoo-gateway): dynamic dashboard URL and cached-token fallback
- 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>
1 parent 27fe01d commit 27705c4

4 files changed

Lines changed: 21 additions & 11 deletions

File tree

src/api/providers/fetchers/__tests__/zoo-gateway.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import axios from "axios"
55
import { getZooGatewayModels, parseZooGatewayModel } from "../zoo-gateway"
66

77
vitest.mock("axios")
8+
vitest.mock("../../../../services/zoo-code-auth", () => ({
9+
getCachedZooCodeToken: vitest.fn(() => ""),
10+
getZooCodeBaseUrl: vitest.fn(() => "https://example.test"),
11+
}))
812
const mockedAxios = axios as any
913

1014
describe("Zoo Gateway Fetchers", () => {

src/api/providers/fetchers/zoo-gateway.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import axios from "axios"
33
import type { ModelInfo } from "@roo-code/types"
44

55
import type { ApiHandlerOptions } from "../../../shared/api"
6-
import { getZooCodeBaseUrl } from "../../../services/zoo-code-auth"
6+
import { getCachedZooCodeToken, getZooCodeBaseUrl } from "../../../services/zoo-code-auth"
77

88
// Reuse the same schemas and parsing logic from vercel-ai-gateway since the API format is identical
99
import { type VercelAiGatewayModel, parseVercelAiGatewayModel } from "./vercel-ai-gateway"
@@ -63,10 +63,12 @@ export async function getZooGatewayModels(options?: ApiHandlerOptions): Promise<
6363
const models: Record<string, ModelInfo> = {}
6464
const baseURL = options?.zooGatewayBaseUrl ?? `${getZooCodeBaseUrl()}/api/gateway/v1`
6565

66-
// Build headers - Zoo Gateway requires authentication via the zoo_ext_ session token
66+
// Build headers - Zoo Gateway requires authentication via the zoo_ext_ session token.
67+
// Fall back to the secret-storage cache when the profile hasn't been seeded yet.
68+
const sessionToken = options?.zooSessionToken || getCachedZooCodeToken()
6769
const headers: Record<string, string> = {}
68-
if (options?.zooSessionToken) {
69-
headers["Authorization"] = `Bearer ${options.zooSessionToken}`
70+
if (sessionToken) {
71+
headers["Authorization"] = `Bearer ${sessionToken}`
7072
}
7173

7274
try {

src/api/providers/zoo-gateway.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from "@roo-code/types"
1010

1111
import { ApiHandlerOptions } from "../../shared/api"
12-
import { getZooCodeBaseUrl } from "../../services/zoo-code-auth"
12+
import { getCachedZooCodeToken, getZooCodeBaseUrl } from "../../services/zoo-code-auth"
1313
import { Package } from "../../shared/package"
1414

1515
import { ApiStream } from "../transform/stream"
@@ -29,10 +29,11 @@ export class ZooGatewayHandler extends RouterProvider implements SingleCompletio
2929
constructor(options: ApiHandlerOptions) {
3030
const baseURL = options.zooGatewayBaseUrl ?? `${getZooCodeBaseUrl()}/api/gateway/v1`
3131

32-
// Fail fast with a clear message instead of waiting for a 401.
33-
// The token is set automatically by handleZooCodeCallback() after the user
34-
// authenticates via the "Sign in with Zoo Code" flow in the extension.
35-
if (!options.zooSessionToken) {
32+
// Prefer the profile-persisted token; fall back to the secret-storage cache so
33+
// requests work when the user is signed in but the profile hasn't been seeded yet
34+
// (e.g. auth callback arrived before any webview instance was open).
35+
const sessionToken = options.zooSessionToken || getCachedZooCodeToken()
36+
if (!sessionToken) {
3637
throw new Error("Zoo Gateway requires authentication. Please sign in to Zoo Code first.")
3738
}
3839

@@ -51,7 +52,7 @@ export class ZooGatewayHandler extends RouterProvider implements SingleCompletio
5152
},
5253
name: "zoo-gateway",
5354
baseURL,
54-
apiKey: options.zooSessionToken,
55+
apiKey: sessionToken,
5556
modelId: options.zooGatewayModelId,
5657
defaultModelId: zooGatewayDefaultModelId,
5758
defaultModelInfo: zooGatewayDefaultModelInfo,

webview-ui/src/components/settings/providers/ZooGateway.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export const ZooGateway = ({
3333
useExtensionState()
3434

3535
const authUrl = getZooCodeAuthUrl(uriScheme, zooCodeBaseUrl, deviceName)
36+
// Resolve the dashboard link off the same base URL the auth/gateway flow uses,
37+
// so non-prod environments (staging/dev) point at the matching dashboard.
38+
const resolvedDashboardBase = zooCodeBaseUrl?.replace(/\/$/, "") || "https://www.zoocode.dev"
3639

3740
return (
3841
<>
@@ -73,7 +76,7 @@ export const ZooGateway = ({
7376
models={routerModels?.["zoo-gateway"] ?? {}}
7477
modelIdKey="zooGatewayModelId"
7578
serviceName="Zoo Gateway"
76-
serviceUrl="https://www.zoocode.dev/dashboard/models"
79+
serviceUrl={`${resolvedDashboardBase}/dashboard/models`}
7780
organizationAllowList={organizationAllowList}
7881
errorMessage={modelValidationError}
7982
simplifySettings={simplifySettings}

0 commit comments

Comments
 (0)