From dd202cd7564c093ee356e8e20038d111015821f7 Mon Sep 17 00:00:00 2001 From: Christian Taillon Date: Thu, 27 Aug 2026 09:30:44 -0700 Subject: [PATCH 1/2] fix: handle nested Ollama Cloud usage response --- src/lib/ollama-cloud.ts | 8 +++-- tests/lib.ollama-cloud.test.ts | 57 +++++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/lib/ollama-cloud.ts b/src/lib/ollama-cloud.ts index 12bf3bce..a5a563f8 100644 --- a/src/lib/ollama-cloud.ts +++ b/src/lib/ollama-cloud.ts @@ -82,6 +82,8 @@ function parseWindow(value: unknown): OllamaCloudWindow | undefined { } function parseModels(value: unknown, rowErrors: string[]): OllamaCloudModelUsage[] { + if (value === undefined) return []; + if (!Array.isArray(value)) { rowErrors.push("Models: expected an array"); return []; @@ -130,7 +132,9 @@ function parseOllamaCloudUsage(payload: unknown): OllamaCloudResult { }; } - if (Array.isArray(payload.models) && payload.models.length > MAX_MODEL_ROWS) { + const topLevelModels = payload.models; + + if (Array.isArray(topLevelModels) && topLevelModels.length > MAX_MODEL_ROWS) { return { success: false, error: `Ollama Cloud usage API returned more than ${MAX_MODEL_ROWS} model rows`, @@ -152,7 +156,7 @@ function parseOllamaCloudUsage(payload: unknown): OllamaCloudResult { rowErrors.push("Limits: expected an object"); } - const models = parseModels(payload.models, rowErrors); + const models = parseModels(topLevelModels, rowErrors); if (!session && !weekly && models.length === 0) { return { success: false, diff --git a/tests/lib.ollama-cloud.test.ts b/tests/lib.ollama-cloud.test.ts index c9fc4f3a..ab1c80f8 100644 --- a/tests/lib.ollama-cloud.test.ts +++ b/tests/lib.ollama-cloud.test.ts @@ -48,13 +48,21 @@ function mockResponse(params: { const usagePayload = { limits: { - session: { usage: 0.25 }, - weekly: { usage: 0.405 }, + session: { + usage: 0.25, + models: [ + { name: "qwen3-coder:480b", request_count: 3 }, + { name: "deepseek-v3.1:671b", request_count: 1 }, + ], + }, + weekly: { + usage: 0.405, + models: [ + { name: "qwen3-coder:480b", request_count: 12 }, + { name: "deepseek-v3.1:671b", request_count: 1 }, + ], + }, }, - models: [ - { model: "qwen3-coder:480b", requests: 12 }, - { model: "deepseek-v3.1:671b", requests: 1 }, - ], }; describe("queryOllamaCloudQuota", () => { @@ -108,10 +116,11 @@ describe("queryOllamaCloudQuota", () => { ); }); - it("maps usage fractions and sorts model request counts", async () => { + it("maps usage fractions from a real nested Ollama response", async () => { mockResponse({ ok: true, status: 200, json: usagePayload }); - await expect(queryOllamaCloudQuota()).resolves.toEqual({ + const out = await queryOllamaCloudQuota(); + expect(out).toEqual({ success: true, session: { usageFraction: 0.25, @@ -123,6 +132,27 @@ describe("queryOllamaCloudQuota", () => { usagePercent: 40.5, percentRemaining: 59.5, }, + models: [], + }); + expect(out && out.success ? out.rowErrors : undefined).toBeUndefined(); + }); + + it("parses legacy top-level models for backwards compatibility", () => { + const out = _parseOllamaCloudUsage({ + limits: { + session: { usage: 0.25 }, + weekly: { usage: 0.405 }, + }, + models: [ + { model: "qwen3-coder:480b", requests: 12 }, + { model: "deepseek-v3.1:671b", requests: 1 }, + ], + }); + + expect(out).toEqual({ + success: true, + session: { usageFraction: 0.25, usagePercent: 25, percentRemaining: 75 }, + weekly: { usageFraction: 0.405, usagePercent: 40.5, percentRemaining: 59.5 }, models: [ { model: "deepseek-v3.1:671b", requests: 1 }, { model: "qwen3-coder:480b", requests: 12 }, @@ -133,8 +163,10 @@ describe("queryOllamaCloudQuota", () => { it("preserves zero and fully-used fraction boundaries", () => { expect( _parseOllamaCloudUsage({ - limits: { session: { usage: 0 }, weekly: { usage: 1 } }, - models: [], + limits: { + session: { usage: 0 }, + weekly: { usage: 1, models: [] }, + }, }), ).toEqual({ success: true, @@ -187,7 +219,10 @@ describe("queryOllamaCloudQuota", () => { it("rejects more than 100 model rows", () => { expect( _parseOllamaCloudUsage({ - limits: { session: { usage: 0.1 } }, + limits: { + session: { usage: 0.1 }, + weekly: { usage: 0.2 }, + }, models: Array.from({ length: 101 }, (_, index) => ({ model: `model-${index}`, requests: index, From a761584f09c11d4c34afe3e3d53e38fa914731a9 Mon Sep 17 00:00:00 2001 From: Christian Taillon Date: Mon, 31 Aug 2026 09:25:12 -0700 Subject: [PATCH 2/2] fix: hide Ollama Cloud model request counts --- docs/readme/providers.md | 2 +- src/lib/ollama-cloud.ts | 63 +-------------- src/lib/provider-registration.ts | 3 +- src/lib/types.ts | 10 +-- src/providers/ollama-cloud.ts | 23 +----- tests/helpers/provider-assertions.ts | 6 -- tests/lib.ollama-cloud.test.ts | 80 ++----------------- tests/lib.provider-metadata.test.ts | 3 +- tests/providers.ollama-cloud.surfaces.test.ts | 14 +--- tests/providers.ollama-cloud.test.ts | 37 +-------- 10 files changed, 18 insertions(+), 223 deletions(-) diff --git a/docs/readme/providers.md b/docs/readme/providers.md index ace73e69..f8467b6a 100644 --- a/docs/readme/providers.md +++ b/docs/readme/providers.md @@ -562,7 +562,7 @@ Per-API-key costs remain unsupported until Xiaomi exposes endpoint and schema ev ### Ollama Cloud -Ollama Cloud calls `https://ollama.com/api/usage` and reports session and weekly quota plus per-model request counts. Create an Ollama API key, then set: +Ollama Cloud calls `https://ollama.com/api/usage` and reports session and weekly usage fractions. The API-key response does not include quota reset timestamps or per-model request rows. Create an Ollama API key, then set: ```bash export OLLAMA_API_KEY="your-api-key" diff --git a/src/lib/ollama-cloud.ts b/src/lib/ollama-cloud.ts index a5a563f8..76791e77 100644 --- a/src/lib/ollama-cloud.ts +++ b/src/lib/ollama-cloud.ts @@ -1,18 +1,17 @@ /** * Ollama Cloud usage API client. * - * Fetches session and weekly usage fractions plus per-model request counts - * from the authenticated Ollama Cloud usage endpoint. + * Fetches session and weekly usage fractions from the authenticated Ollama + * Cloud usage endpoint. */ import { sanitizeSingleLineDisplayText } from "./display-sanitize.js"; import { fetchWithTimeout } from "./http.js"; import { resolveOllamaCloudApiKey } from "./ollama-cloud-config.js"; -import type { OllamaCloudModelUsage, OllamaCloudResult, OllamaCloudWindow } from "./types.js"; +import type { OllamaCloudResult, OllamaCloudWindow } from "./types.js"; const OLLAMA_CLOUD_USAGE_URL = "https://ollama.com/api/usage"; const MAX_RESPONSE_BYTES = 256 * 1024; -const MAX_MODEL_ROWS = 100; type JsonRecord = Record; @@ -81,49 +80,6 @@ function parseWindow(value: unknown): OllamaCloudWindow | undefined { }; } -function parseModels(value: unknown, rowErrors: string[]): OllamaCloudModelUsage[] { - if (value === undefined) return []; - - if (!Array.isArray(value)) { - rowErrors.push("Models: expected an array"); - return []; - } - - const models: OllamaCloudModelUsage[] = []; - const seenModels = new Set(); - - for (const candidate of value) { - if (!isRecord(candidate)) { - rowErrors.push("Models: ignored an invalid row"); - continue; - } - - const model = - typeof candidate.model === "string" - ? sanitizeRemoteSingleLineText(candidate.model).slice(0, 160) - : ""; - const requests = candidate.requests; - - if (!model) { - rowErrors.push("Models: ignored a row without a model name"); - continue; - } - if (typeof requests !== "number" || !Number.isSafeInteger(requests) || requests < 0) { - rowErrors.push(`Models: ignored invalid request count for ${model}`); - continue; - } - if (seenModels.has(model)) { - rowErrors.push(`Models: ignored duplicate model ${model}`); - continue; - } - - seenModels.add(model); - models.push({ model, requests }); - } - - return models.sort((left, right) => left.model.localeCompare(right.model)); -} - function parseOllamaCloudUsage(payload: unknown): OllamaCloudResult { if (!isRecord(payload)) { return { @@ -132,15 +88,6 @@ function parseOllamaCloudUsage(payload: unknown): OllamaCloudResult { }; } - const topLevelModels = payload.models; - - if (Array.isArray(topLevelModels) && topLevelModels.length > MAX_MODEL_ROWS) { - return { - success: false, - error: `Ollama Cloud usage API returned more than ${MAX_MODEL_ROWS} model rows`, - }; - } - const rowErrors: string[] = []; const limits = isRecord(payload.limits) ? payload.limits : undefined; const session = parseWindow(limits?.session); @@ -156,8 +103,7 @@ function parseOllamaCloudUsage(payload: unknown): OllamaCloudResult { rowErrors.push("Limits: expected an object"); } - const models = parseModels(topLevelModels, rowErrors); - if (!session && !weekly && models.length === 0) { + if (!session && !weekly) { return { success: false, error: "Ollama Cloud usage API returned no usable usage data", @@ -168,7 +114,6 @@ function parseOllamaCloudUsage(payload: unknown): OllamaCloudResult { success: true, ...(session ? { session } : {}), ...(weekly ? { weekly } : {}), - models, ...(rowErrors.length > 0 ? { rowErrors } : {}), }; } diff --git a/src/lib/provider-registration.ts b/src/lib/provider-registration.ts index 7f25d391..b64a7fd4 100644 --- a/src/lib/provider-registration.ts +++ b/src/lib/provider-registration.ts @@ -359,8 +359,7 @@ export const QUOTA_PROVIDER_REGISTRATION_SOURCE = [ authentication: "opencode_auth_api_key", authFallbacks: ["env_api_key", "global_opencode_config"], quota: "remote_api", - notes: - "Queries the Ollama Cloud usage API; reports session and weekly quota plus model request counts", + notes: "Queries the Ollama Cloud usage API; reports session and weekly usage fractions", }, }, { diff --git a/src/lib/types.ts b/src/lib/types.ts index 95aba028..2f8b2866 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -870,12 +870,6 @@ export interface OllamaCloudWindow { percentRemaining: number; } -/** Per-model request count from the Ollama Cloud usage API */ -export interface OllamaCloudModelUsage { - model: string; - requests: number; -} - /** Result from the Ollama Cloud usage API */ export type OllamaCloudResult = | { @@ -884,9 +878,7 @@ export type OllamaCloudResult = session?: OllamaCloudWindow; /** Weekly usage window, when present */ weekly?: OllamaCloudWindow; - /** Valid per-model request counts */ - models: OllamaCloudModelUsage[]; - /** Independent response rows that could not be used */ + /** Independent response fields that could not be used */ rowErrors?: string[]; } | QuotaError diff --git a/src/providers/ollama-cloud.ts b/src/providers/ollama-cloud.ts index 29e4623b..a13b930a 100644 --- a/src/providers/ollama-cloud.ts +++ b/src/providers/ollama-cloud.ts @@ -1,8 +1,7 @@ /** * Ollama Cloud provider wrapper. * - * Queries the Ollama Cloud usage API and reports session/weekly quota plus - * provider-reported per-model request counts. + * Queries the Ollama Cloud usage API and reports session/weekly quota. */ import type { @@ -32,10 +31,6 @@ const REMOTE_API_ACCOUNTING = { type OllamaCloudSuccess = Extract; -function formatRequestCount(requests: number): string { - return `${requests} ${requests === 1 ? "request" : "requests"}`; -} - function mapOllamaCloudSuccess(result: OllamaCloudSuccess): QuotaProviderResult { const entries: QuotaToastEntry[] = []; @@ -65,21 +60,6 @@ function mapOllamaCloudSuccess(result: OllamaCloudSuccess): QuotaProviderResult }); } - for (const model of result.models) { - entries.push({ - kind: "value", - accounting: { - resultType: "usage", - ...REMOTE_API_ACCOUNTING, - }, - name: `${OLLAMA_CLOUD_PROVIDER_LABEL} ${model.model}`, - group: OLLAMA_CLOUD_PROVIDER_LABEL, - label: `${model.model}:`, - metricLabel: model.model, - value: formatRequestCount(model.requests), - }); - } - const errors = (result.rowErrors ?? []).map((message) => ({ label: OLLAMA_CLOUD_PROVIDER_LABEL, message, @@ -95,7 +75,6 @@ function mapOllamaCloudSuccess(result: OllamaCloudSuccess): QuotaProviderResult ...statusDetailsFromRecord({ session_usage_fraction: result.session?.usageFraction.toString(), weekly_usage_fraction: result.weekly?.usageFraction.toString(), - model_rows: result.models.length.toString(), }), ...(result.rowErrors ?? []).map((message, index) => ({ key: `live_error_${index + 1}`, diff --git a/tests/helpers/provider-assertions.ts b/tests/helpers/provider-assertions.ts index 2b520f7f..5982abae 100644 --- a/tests/helpers/provider-assertions.ts +++ b/tests/helpers/provider-assertions.ts @@ -298,12 +298,6 @@ export const PROVIDER_ACCOUNTING_LEDGER: Record { usagePercent: 40.5, percentRemaining: 59.5, }, - models: [], - }); - expect(out && out.success ? out.rowErrors : undefined).toBeUndefined(); - }); - - it("parses legacy top-level models for backwards compatibility", () => { - const out = _parseOllamaCloudUsage({ - limits: { - session: { usage: 0.25 }, - weekly: { usage: 0.405 }, - }, - models: [ - { model: "qwen3-coder:480b", requests: 12 }, - { model: "deepseek-v3.1:671b", requests: 1 }, - ], - }); - - expect(out).toEqual({ - success: true, - session: { usageFraction: 0.25, usagePercent: 25, percentRemaining: 75 }, - weekly: { usageFraction: 0.405, usagePercent: 40.5, percentRemaining: 59.5 }, - models: [ - { model: "deepseek-v3.1:671b", requests: 1 }, - { model: "qwen3-coder:480b", requests: 12 }, - ], }); + expect(out?.success ? out.rowErrors : undefined).toBeUndefined(); }); it("preserves zero and fully-used fraction boundaries", () => { @@ -165,48 +135,29 @@ describe("queryOllamaCloudQuota", () => { _parseOllamaCloudUsage({ limits: { session: { usage: 0 }, - weekly: { usage: 1, models: [] }, + weekly: { usage: 1 }, }, }), ).toEqual({ success: true, session: { usageFraction: 0, usagePercent: 0, percentRemaining: 100 }, weekly: { usageFraction: 1, usagePercent: 100, percentRemaining: 0 }, - models: [], }); }); - it("keeps valid rows and reports invalid independent rows", () => { + it("reports invalid independent usage windows", () => { const out = _parseOllamaCloudUsage({ limits: { session: { usage: 0.2 }, weekly: { usage: 1.5 }, }, - models: [ - { model: "valid-model", requests: 0 }, - { model: "negative", requests: -1 }, - { model: "decimal", requests: 1.5 }, - { model: "valid-model", requests: 3 }, - { model: " unsafe\nmodel\u202e\u001b[31m ", requests: 2 }, - null, - ], }); expect(out).toMatchObject({ success: true, session: { usageFraction: 0.2, usagePercent: 20, percentRemaining: 80 }, - models: [ - { model: "unsafe model", requests: 2 }, - { model: "valid-model", requests: 0 }, - ], }); - expect(out && out.success ? out.rowErrors : []).toEqual([ - "Weekly: ignored invalid usage fraction", - "Models: ignored invalid request count for negative", - "Models: ignored invalid request count for decimal", - "Models: ignored duplicate model valid-model", - "Models: ignored an invalid row", - ]); + expect(out?.success ? out.rowErrors : []).toEqual(["Weekly: ignored invalid usage fraction"]); }); it.each([null, [], "invalid"])("rejects an invalid root payload: %j", (payload) => { @@ -216,29 +167,10 @@ describe("queryOllamaCloudQuota", () => { }); }); - it("rejects more than 100 model rows", () => { - expect( - _parseOllamaCloudUsage({ - limits: { - session: { usage: 0.1 }, - weekly: { usage: 0.2 }, - }, - models: Array.from({ length: 101 }, (_, index) => ({ - model: `model-${index}`, - requests: index, - })), - }), - ).toEqual({ - success: false, - error: "Ollama Cloud usage API returned more than 100 model rows", - }); - }); - it("rejects an object with no usable usage data", () => { expect( _parseOllamaCloudUsage({ limits: { session: { usage: -1 }, weekly: { usage: Number.NaN } }, - models: [{ model: "bad", requests: -1 }], }), ).toEqual({ success: false, diff --git a/tests/lib.provider-metadata.test.ts b/tests/lib.provider-metadata.test.ts index 89b2deee..c79282e5 100644 --- a/tests/lib.provider-metadata.test.ts +++ b/tests/lib.provider-metadata.test.ts @@ -197,8 +197,7 @@ describe("provider-metadata", () => { authentication: "opencode_auth_api_key", authFallbacks: ["env_api_key", "global_opencode_config"], quota: "remote_api", - notes: - "Queries the Ollama Cloud usage API; reports session and weekly quota plus model request counts", + notes: "Queries the Ollama Cloud usage API; reports session and weekly usage fractions", }, { id: "quota-providers", diff --git a/tests/providers.ollama-cloud.surfaces.test.ts b/tests/providers.ollama-cloud.surfaces.test.ts index 4910526c..00a3f8ca 100644 --- a/tests/providers.ollama-cloud.surfaces.test.ts +++ b/tests/providers.ollama-cloud.surfaces.test.ts @@ -28,15 +28,6 @@ const data: QuotaRenderData = { label: "Weekly:", percentRemaining: 60, }, - { - kind: "value", - accounting: { resultType: "usage", ...accounting }, - name: "Ollama Cloud qwen3", - group: "Ollama Cloud", - label: "qwen3:", - metricLabel: "qwen3", - value: "12 requests", - }, ], errors: [], }; @@ -60,9 +51,8 @@ describe("Ollama Cloud four-surface formatting", () => { expect(output).toContain("75%"); } - expect(command).toContain("qwen3"); - for (const output of [command, toast, sidebar]) { - expect(output).toContain("12 requests"); + for (const output of [command, toast, sidebar, compact]) { + expect(output).not.toContain("requests"); } }); }); diff --git a/tests/providers.ollama-cloud.test.ts b/tests/providers.ollama-cloud.test.ts index 8abd419c..98e559f4 100644 --- a/tests/providers.ollama-cloud.test.ts +++ b/tests/providers.ollama-cloud.test.ts @@ -48,7 +48,7 @@ describe("ollama-cloud provider", () => { expect(out.statusDetails).toContainEqual({ key: "api_key_configured", value: "true" }); }); - it("maps session, weekly, and sorted model request entries", async () => { + it("maps session and weekly quota entries", async () => { mocks.queryOllamaCloudQuota.mockResolvedValueOnce({ success: true, session: { @@ -61,10 +61,6 @@ describe("ollama-cloud provider", () => { usagePercent: 40, percentRemaining: 60, }, - models: [ - { model: "deepseek-v3.1:671b", requests: 1 }, - { model: "qwen3-coder:480b", requests: 12 }, - ], }); const out = await runProviderFetch(); @@ -83,22 +79,6 @@ describe("ollama-cloud provider", () => { label: "Weekly:", percentRemaining: 60, }, - { - kind: "value", - name: "Ollama Cloud deepseek-v3.1:671b", - group: "Ollama Cloud", - label: "deepseek-v3.1:671b:", - metricLabel: "deepseek-v3.1:671b", - value: "1 request", - }, - { - kind: "value", - name: "Ollama Cloud qwen3-coder:480b", - group: "Ollama Cloud", - label: "qwen3-coder:480b:", - metricLabel: "qwen3-coder:480b", - value: "12 requests", - }, ]); expect(out.entries.map((entry) => entry.accounting)).toEqual([ { @@ -113,25 +93,12 @@ describe("ollama-cloud provider", () => { ownership: "maintained", authority: "provider_reported", }, - { - resultType: "usage", - acquisitionMethod: "remote_api", - ownership: "maintained", - authority: "provider_reported", - }, - { - resultType: "usage", - acquisitionMethod: "remote_api", - ownership: "maintained", - authority: "provider_reported", - }, ]); expect(out.statusDetails).toEqual( expect.arrayContaining([ { key: "api_key_source", value: "env:OLLAMA_API_KEY" }, { key: "session_usage_fraction", value: "0.25" }, { key: "weekly_usage_fraction", value: "0.4" }, - { key: "model_rows", value: "2" }, ]), ); }); @@ -144,7 +111,6 @@ describe("ollama-cloud provider", () => { usagePercent: 25, percentRemaining: 75, }, - models: [], rowErrors: ["Weekly: ignored invalid usage fraction"], }); @@ -164,7 +130,6 @@ describe("ollama-cloud provider", () => { mocks.queryOllamaCloudQuota.mockResolvedValue({ success: true, weekly: { usageFraction: 0.1, usagePercent: 10, percentRemaining: 90 }, - models: [], }); await runProviderFetch({ requestTimeoutMs: 1234, requestTimeoutMsConfigured: true });