diff --git a/packages/kilo-gateway/src/api/models.ts b/packages/kilo-gateway/src/api/models.ts index 451855e245..72e4e30d60 100644 --- a/packages/kilo-gateway/src/api/models.ts +++ b/packages/kilo-gateway/src/api/models.ts @@ -5,7 +5,7 @@ import { KILO_API_BASE, KILO_OPENROUTER_BASE, MODELS_FETCH_TIMEOUT_MS, PROMPTS, export type KiloModelsResult = { models: Record - error?: { kind: "unauthorized" | "network" | "schema"; status?: number } + error?: { kind: "unauthorized" | "network" | "schema" | "http"; status?: number } } /** @@ -107,7 +107,8 @@ export async function fetchKiloModels(options?: { if (response.status === 401 && (token || organizationId)) { return fetchKiloModels({}) } - return { models: {}, error: { kind: "unauthorized", status: response.status } } + const kind = response.status === 401 || response.status === 403 ? "unauthorized" : "http" + return { models: {}, error: { kind, status: response.status } } } const json = await response.json() diff --git a/packages/kilo-gateway/src/api/modes.ts b/packages/kilo-gateway/src/api/modes.ts index b0bec67c18..ac67d8332d 100644 --- a/packages/kilo-gateway/src/api/modes.ts +++ b/packages/kilo-gateway/src/api/modes.ts @@ -90,7 +90,8 @@ export async function fetchOrganizationModes(token: string, organizationId: stri const modes = parsed.data.modes cache.set(organizationId, { modes, timestamp: Date.now() }) return modes - } catch { + } catch (err) { + console.warn("[Kilo Gateway] Error fetching organization modes:", err) return [] } } diff --git a/packages/kilo-gateway/test/api/models.test.ts b/packages/kilo-gateway/test/api/models.test.ts index ae7cc9ceb4..df3762ea41 100644 --- a/packages/kilo-gateway/test/api/models.test.ts +++ b/packages/kilo-gateway/test/api/models.test.ts @@ -76,7 +76,7 @@ test("returns error with kind=network on fetch exception", async () => { expect(result.error?.kind).toBe("network") }) -test("returns error with kind=unauthorized on non-401 HTTP error without auth", async () => { +test("returns error with kind=http on non-auth HTTP error (e.g. 500)", async () => { const orig = globalThis.fetch stubFetch(async () => new Response("Server Error", { status: 500, statusText: "Internal Server Error" })) @@ -85,7 +85,7 @@ test("returns error with kind=unauthorized on non-401 HTTP error without auth", ;(globalThis as any).fetch = orig expect(result.models).toEqual({}) - expect(result.error?.kind).toBe("unauthorized") + expect(result.error?.kind).toBe("http") expect(result.error?.status).toBe(500) }) diff --git a/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx b/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx index 938329296e..1b38f8b0d4 100644 --- a/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx +++ b/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx @@ -29,12 +29,16 @@ export function renderGutter( } /** - * Returns a `(reconnect)` description suffix when the provider has failed auth, + * Returns a description suffix when the provider has encountered an error, * or `undefined` to leave the default description unchanged. + * + * NOTE: The sync state only carries failed provider IDs, not the error kind. + * A generic message is used so it remains accurate for auth, network, and + * schema failure types alike. */ export function failedDescription(providerID: string, failed: string[]): string | undefined { if (!failed.includes(providerID)) return undefined - return "(reconnect)" + return "(connection error — click to reconnect)" } // --------------------------------------------------------------------------- diff --git a/packages/opencode/src/provider/model-cache.ts b/packages/opencode/src/provider/model-cache.ts index 5411ee0b09..df10863528 100644 --- a/packages/opencode/src/provider/model-cache.ts +++ b/packages/opencode/src/provider/model-cache.ts @@ -78,7 +78,10 @@ export namespace ModelCache { // Cache miss - fetch models log.info("fetching models", { providerID }) - const authOptions = await getAuthOptions(providerID) + const authOptions = await getAuthOptions(providerID).catch((err) => { + log.warn("getAuthOptions failed", { providerID, err }) + return {} + }) const mergedOptions = { ...authOptions, ...options } const result = await fetchModels(providerID, mergedOptions) @@ -120,7 +123,10 @@ export namespace ModelCache { const refreshPromise = (async () => { log.info("refreshing models", { providerID }) - const authOptions = await getAuthOptions(providerID) + const authOptions = await getAuthOptions(providerID).catch((err) => { + log.warn("getAuthOptions failed during refresh", { providerID, err }) + return {} + }) const mergedOptions = { ...authOptions, ...options } const result = await fetchModels(providerID, mergedOptions)