@nemesis-oss/ollama-sdk 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/README.md +181 -10
  3. package/dist/{anthropic-B_UXplNF.d.ts → anthropic-5oYIRS6D.d.ts} +4 -2
  4. package/dist/{anthropic-CVDFy_a0.d.cts → anthropic-BIh45UXj.d.cts} +4 -2
  5. package/dist/{compose-DLStUfaF.d.ts → compose-DCVYMvOL.d.ts} +1 -1
  6. package/dist/{compose-DS-UWFx8.d.cts → compose-Dj6FdF2n.d.cts} +1 -1
  7. package/dist/generated-api.cjs +42 -3
  8. package/dist/generated-api.cjs.map +1 -1
  9. package/dist/generated-api.d.cts +96 -6
  10. package/dist/generated-api.d.ts +96 -6
  11. package/dist/generated-api.js +41 -4
  12. package/dist/generated-api.js.map +1 -1
  13. package/dist/generated-models-schemas.cjs +62 -2
  14. package/dist/generated-models-schemas.cjs.map +1 -1
  15. package/dist/generated-models-schemas.d.cts +108 -3
  16. package/dist/generated-models-schemas.d.ts +108 -3
  17. package/dist/generated-models-schemas.js +56 -3
  18. package/dist/generated-models-schemas.js.map +1 -1
  19. package/dist/generated-runtime.cjs +105 -5
  20. package/dist/generated-runtime.cjs.map +1 -1
  21. package/dist/generated-runtime.d.cts +2 -2
  22. package/dist/generated-runtime.d.ts +2 -2
  23. package/dist/generated-runtime.js +105 -5
  24. package/dist/generated-runtime.js.map +1 -1
  25. package/dist/index.cjs +1384 -51
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +1312 -14
  28. package/dist/index.d.ts +1312 -14
  29. package/dist/index.js +1352 -52
  30. package/dist/index.js.map +1 -1
  31. package/dist/mcp/tools.json +43 -24
  32. package/dist/mcp-generated.cjs +43 -1
  33. package/dist/mcp-generated.cjs.map +1 -1
  34. package/dist/mcp-generated.d.cts +2 -2
  35. package/dist/mcp-generated.d.ts +2 -2
  36. package/dist/mcp-generated.js +43 -1
  37. package/dist/mcp-generated.js.map +1 -1
  38. package/dist/{runtime-C6UYtBRB.d.ts → runtime-C3rfpkZw.d.ts} +69 -2
  39. package/dist/{runtime-DTmUeU6K.d.cts → runtime-D2W9TfCJ.d.cts} +69 -2
  40. package/dist/skills.cjs.map +1 -1
  41. package/dist/skills.d.cts +3 -3
  42. package/dist/skills.d.ts +3 -3
  43. package/dist/skills.js.map +1 -1
  44. package/dist/{types-5PAjLoCp.d.cts → types-DVcX_zMp.d.cts} +110 -10
  45. package/dist/{types-5PAjLoCp.d.ts → types-DVcX_zMp.d.ts} +110 -10
  46. package/package.json +8 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,163 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.9.0] — Digest upgrades: vision resolver, dual-mode Responses bridge, KV-cache sessions, context safety, blob publishing, cloud usage & balance
4
+
5
+ Five upgrades closing the gaps surfaced by the official Ollama documentation review (see [ADR 0024](./docs/adr/0024-digest-upgrades-vision-responses-sessions-context-blobs.md)) — plus a second-pass recheck against the current official docs (see the last section) that added the Ollama Cloud account endpoints and a missing `/api/create` field. All additive — no breaking changes; 689 pre-existing tests stay green, 60 new tests added.
6
+
7
+ ### Universal vision asset resolver (`src/vision.ts`)
8
+
9
+ - **`VisionInput = string | Buffer | Uint8Array`** accepted anywhere `images` is (`Message.images`, `generate()`), implementing the official SDK vision convention: SDKs accept polymorphic sources; the REST API strictly requires raw base64 strings.
10
+ - String resolution order: `data:image/...;base64,` data URIs (header stripped) → `http(s)://` URLs (fetched via global `fetch`, abortable through the request's `signal`) → image-extension file paths (`.png`/`.jpg`/`.webp`/…, read via **dynamically imported** `node:fs` — Node only, browser bundles unaffected; graceful passthrough when the read fails) → assume raw base64.
11
+ - Path detection is extension-based, not slash-based — `/` is a legal base64 alphabet character, and a contains-slash heuristic would misfire on long payloads.
12
+ - The request pipeline stays allocation-free when every entry is already base64 (`withEncodedImages` returns the same array reference).
13
+ - Previously-broken inputs are silently fixed: data-URI strings, which used to ship the `data:image/...;base64,` header to the server, are now stripped.
14
+ - New exports: `resolveImageInput()`, `imageStringNeedsResolution()`, `resolveImages()`, `type VisionInput`.
15
+
16
+ ### Dual-mode OpenAI Responses bridge (`src/responses.ts`)
17
+
18
+ - **`client.responses.create()`** — ergonomic, OpenAI-SDK-shaped bridge (`model`, `input`, `instructions`, `tools`, `temperature`, `top_p`, `max_output_tokens`, `reasoning_effort`, `think`) over `POST /v1/responses` (Ollama ≥ v0.13.3), with **transparent `/api/chat` fallback on 404** for older servers: `instructions` → system message, `max_output_tokens` → `options.num_predict`, reply normalized back into the Responses shape (`output_text`, `usage.input_tokens`/`output_tokens`). The result's `transport` field (`'native' | 'chat-adapter'`) records the path taken.
19
+ - **`client.responses.stream()`** — lazy async generator yielding simplified `{type: 'text_delta' | 'thinking_delta' | 'done'}` events; same dual-mode transport, fallback only on establishment failure (never mid-stream, which would duplicate consumed deltas).
20
+ - **`client.responses.createText()`** — convenience returning just the output text.
21
+ - Native-mode mapping extracts joined `output_text` blocks (including refusals), reasoning traces (`thinking`), and parsed `function_call` items (`tool_calls` with parsed `arguments` objects).
22
+ - 404-only fallback, deliberately: 5xx remains a retryable error for the existing retry policy; 4xx is a request bug — neither means "endpoint absent."
23
+ - The full wire-shaped surface stays on `client.openai.responses()`; this module is the ergonomic migration subset documented in the new **MIGRATION.md** (openai npm SDK → this SDK mapping table).
24
+
25
+ ### KV-cache-aware conversation sessions (`src/conversation.ts`)
26
+
27
+ - **`client.session(model, systemPrompt?)`** (or `new ConversationSession(client, options)`) — multi-turn session with an **append-only frozen history** and a system prompt **pinned at construction** (no mutation API — a per-call system prompt is the #1 silent KV-cache killer), maximizing Ollama's prompt-prefix KV-cache reuse across turns.
28
+ - **Per-turn and cumulative cache statistics** from `prompt_eval_cached_count` / `prompt_eval_count`: `session.cacheStats` (cumulative) and `sendTurn()`'s `TurnCacheStats` (per turn).
29
+ - Hit-rate denominator is `cached / (cached + evaluated)`: when the entire prompt hits the cache, Ollama reports `prompt_eval_count: 0`, so dividing by `prompt_eval_count` alone would score the best case as 0%.
30
+ - `send()` (reply text), `sendTurn()` (full turn record), `getMessages()` (defensive copy of the frozen history), `reset()` (restores system prompt, zeroes stats). Per-turn overrides (`options`, `think`, `keep_alive`, `tools`, `format`, `signal`, `timeoutMs`) ride on the request, never the history.
31
+
32
+ ### Context-window safety (`src/context-safety.ts`)
33
+
34
+ - **Pre-flight estimation on every `chat()`/`generate()` call** guards against Ollama's silent prompt truncation when `num_ctx` is unset (server default 2048–4096, model-dependent): CJK-aware heuristic (~1 token per CJK character, ~4 chars/token elsewhere, `IMAGE_TOKEN_ESTIMATE` per image, per-message overhead, tool schemas), ±20–30% by design — no tokenizer download.
35
+ - **`defaultContextLength`** client config — injected as `options.num_ctx` on every request that omits it, making the effective window explicit on the wire.
36
+ - **`onContextOverflow: 'warn' | 'throw'`** (default `'warn'`) — log through the configured logger and send anyway, or reject client-side with `OllamaClientError` (`code: 'context_overflow'`) before anything hits the wire. `contextWarningThreshold` (default `0.9`) tunes the trip point.
37
+ - Window resolution order: request `num_ctx` → client `defaultContextLength` → conservative 2048 fallback, which warns only when the estimate _outright exceeds_ it (no margin — the real server default may be 4096, and a margin would generate false positives).
38
+ - New exports: `estimateTokens()`, `estimateChatRequestTokens()`, `estimateGenerateRequestTokens()`, `checkChatContext()`, `checkGenerateContext()`, `contextWarningMessage()`, `DEFAULT_CONTEXT_WARNING_THRESHOLD`, `IMAGE_TOKEN_ESTIMATE`, `OLLAMA_FALLBACK_CONTEXT_LENGTH`.
39
+
40
+ ### Blob management & custom GGUF model publishing (`src/models-client.ts`)
41
+
42
+ - **`computeBlobDigest(data)`** — SHA-256 via the Web Crypto API (`crypto.subtle`, global in Node ≥ 20 and every browser/edge runtime), formatted `sha256:<64 lowercase hex>` exactly as Ollama's content-addressed store expects.
43
+ - **`createBlobFromData(data, {digest?})`** / **`createBlobFromFile(path)`** — HEAD existence check then upload, skipping the POST (and the wasted bandwidth) when the blob is already present; returns `BlobUploadResult { digest, alreadyExisted }` (file variant adds `fileName` — the basename `/api/create`'s `files` map keys on).
44
+ - **`createModelFromGguf(model, ggufPath | paths, opts)`** — one-shot implementation of Ollama's documented import protocol: push a blob per GGUF shard, then `POST /api/create` with `files: { <fileName>: <digest> }` (verified against the official API reference).
45
+
46
+ ### Docs recheck: Ollama Cloud account endpoints + contract refresh
47
+
48
+ A second full audit against the current official Ollama docs (`docs/openapi.yaml`, `docs/api/*.mdx`, `docs/capabilities/*.mdx`, `docs/modelfile.mdx`, `docs/import.mdx`, `docs/context-length.mdx`) found the SDK already at parity everywhere except three items — all closed here:
49
+
50
+ - **`client.usage(options?)`** — wraps `GET https://ollama.com/api/usage` (cloud-only): request counts, USD spend, and token totals (input / cached-input / output) across the whole range plus hourly (`range: '24h'`) or daily (`'7d'`/`'30d'`) buckets, including `partial: true` markers for the in-progress hour/day. Query parameters `range` (`'24h' | '7d' | '30d'`, server default `'7d'`) and `scope` (`'self' | 'team'`, server default `'self'`, team requires an admin) are typed and only sent when provided.
51
+ - **`client.balance(options?)`** — wraps `GET https://ollama.com/api/balance`: remaining included + purchased credits, with the included shape a runtime-discriminated union of the plan-period credits object (`balance_usd`/`allowance_usd`/`period`) and the legacy session/weekly percentage-limits shape.
52
+ - Both ride the same fixed-cloud-host pipeline as `webSearch`/`webFetch` (`https://ollama.com`, `apiKey`/`OLLAMA_API_KEY`, default timeout + retry, never multi-endpoint failover) and both endpoints' documented 10-req/min rate limit is respected by the shared `OllamaRateLimitError` retry semantics (429 + `Retry-After`).
53
+ - **`CreateRequestOptions.capabilities`** — the one field-level gap the drift detector surfaced: the official `/api/create` payload accepts `capabilities: string[]` (e.g. `'decision'`) to add capabilities without removing inherited/inferred ones; now typed and forwarded. `files` also joined the create parity manifest.
54
+ - **Contract refresh** — the pinned OpenAPI snapshot (`contracts/sources/ollama.openapi.yaml` + verbatim `docs/upstream/ollama-openapi.yaml`) moved from the 2026-10-02 pin to 2026-10-07 (source SHA `675c8bb`), bringing the `Usage*`/`Balance*` schemas into the IR (7 new contract-generated models), repairing the corrupted enum literals the upstream file carries (`[24h, 7d, 30d]`, `[hour, day]`), and adding a new `contracts/overlays/cloud.yaml` so bidirectional endpoint discovery, the MCP tool registry, and the IR inspector all see the account endpoints.
55
+ - **Generator fix**: top-level `allOf` schemas (like `UsageBucket` = `UsageMetrics & {from, until, partial?}`) previously emitted as an empty interface — the models emitter dropped the intersection. `allOf` now emits a correct type alias; the Zod emitter already handled it.
56
+ - Everything else audited clean: all 15 core REST endpoints (incl. legacy `/api/embeddings`), `/v1/systemone`, `web_search`/`web_fetch`, the full OpenAI-compat surface (incl. `reasoning_effort`, `reasoning.effort`, `think`, `instructions`, `max_output_tokens`) and Anthropic-compat surface (incl. `output_config`, thinking, tool results, all streaming events), field-level sync on every request/response schema (`logprobs`, `top_logprobs`, `think`, `remote_host`/`remote_model`, `draft_files`, `parser`, `renderer`, `requires`, Ps `context_length`/`size_vram`, Show `capabilities`/`thinking`), auth (`OLLAMA_API_KEY` scoping), and the capability docs (vision, structured outputs, thinking, embeddings, tool calling, context length, GGUF import).
57
+ - New exports: `client.usage()`, `client.balance()`, `UsageRequestOptions`, `UsageRange`, `UsageScope`, `BalanceRequestOptions`, and the contract-generated `UsageResponse`, `UsageMetrics`, `UsageBucket`, `BalanceResponse`, `IncludedBalance`, `LegacyBalanceLimit`, `LegacyIncludedBalance`.
58
+ - 10 new unit tests (`test/usage-balance.test.ts`, mocked fetch — CI-safe) and updated guard tests (`test/security-invariants.test.ts` host allowlist now covers the four cloud ops; `test/contract/parity.test.ts` new-ops set extended).
59
+
60
+ ### Documentation & examples
61
+
62
+ - README: four new Quick Start sections (sessions, dual-mode Responses, context safety, blob publishing) + rewritten vision section; five new feature bullets.
63
+ - **MIGRATION.md** (new): openai npm SDK → this SDK mapping table, responses/chat-completions/vision/statefulness/reasoning/error mapping.
64
+ - **ADR 0024** (new) + ADR index now lists 0022–0024.
65
+ - Five runnable examples: `examples/vision-inputs.ts`, `examples/responses-bridge.ts`, `examples/conversation-session.ts`, `examples/context-safety.ts`, `examples/blob-publishing.ts` (`npm run example <file>`) — plus `examples/usage-balance.ts` from the docs-recheck pass.
66
+ - 50 new unit tests (mocked fetch — CI-safe, no daemon): `test/vision-resolver.test.ts`, `test/responses-bridge.test.ts`, `test/conversation-session.test.ts`, `test/context-safety.test.ts`, `test/blob-helpers.test.ts` — plus 10 more in `test/usage-balance.test.ts`.
67
+
68
+ ## [Unreleased]
69
+
70
+ ### Fix: IPv6 loopback was classified as Ollama Cloud
71
+
72
+ - `inferRuntimeMode()` compared `URL.hostname` to `'::1'`, but WHATWG URL reports an IPv6 literal with its brackets (`'[::1]'`), so `http://[::1]:11434` was classified as `cloud`. Structured-output (`format`) requests to a local Ollama on IPv6 loopback were therefore refused pre-flight with `OllamaUnsupportedCapabilityError`, and `localMode` was off for capability detection. The brackets are now stripped before comparing. Public IPv6 addresses are still `cloud`.
73
+
74
+ ### Host normalization and scoped `OLLAMA_API_KEY`
75
+
76
+ - **Base URL normalization.** `baseUrl`, `OLLAMA_HOST`, per-credential `baseUrl` and `endpoints[].baseUrl` now accept the bare forms the Ollama CLI accepts: `127.0.0.1:11434`, `0.0.0.0`, `:11434`, `myhost`. A missing scheme defaults to `http://`, a missing port on a scheme-less host defaults to `11434`, scheme-less port `443` selects `https://`, and `:port` means `127.0.0.1`. Full URLs and reverse-proxy path prefixes are unchanged. Previously a scheme-less value produced an invalid request URL.
77
+ - **Behavior change: `OLLAMA_API_KEY` is no longer forwarded to arbitrary hosts.** The env-sourced key is applied to the default endpoint only when its host is Ollama Cloud (`ollama.com`, `*.ollama.com`) or loopback. An explicit `apiKey` is always sent, to any host. If you relied on `OLLAMA_API_KEY` for a LAN or proxied server, pass `apiKey` explicitly. Web search/fetch (always `https://ollama.com`) still use the env key.
78
+
79
+ ### Production-readiness audit — tool-call accumulator, mock server
80
+
81
+ - **Offline wire-format conformance tests** (`test/conformance/native-api-offline.test.ts`). The sibling `native-api.test.ts` hits a REAL Ollama server and skips when none is available. The new offline tests use `OllamaMockServer` to emit contract-shaped NDJSON frames without any model inference, so they run in every CI environment — including those without an Ollama daemon. They validate ONLY the wire format (schema conformance, error-class mapping, optional-field handling), NOT model behavior. The split exists because wire-format drift is a contract concern (catchable offline), while model-behavior drift is a server/model concern (only catchable against a live server). 22 new tests covering:
82
+ - `GET /api/version`, `/api/tags`, `/api/ps`, `POST /api/show` schema conformance
83
+ - `POST /api/chat`, `/api/generate`, `/api/embed` schema conformance (non-streaming)
84
+ - `POST /api/chat`, `/api/generate` streaming chunk schema conformance
85
+ - Error-class mapping: 404 → `OllamaNotFoundError`, 503 → `OllamaOverloadedError`, in-band `{"error":"..."}` → `OllamaStreamError`
86
+ - Optional telemetry fields (`prompt_eval_cached_count`, `thinking`, `done_reason`) — verifies the SDK does NOT throw when these are absent (the Wave 13 conformance failure mode)
87
+ - `done_reason` variants: `"stop"`, `"length"`, `"load"`, `"unload"` all parse cleanly; an undocumented value also parses cleanly (forward-compat)
88
+ - `OllamaClient` vs `NativeApi` shape parity (mirrors the live parity test)
89
+ - Updated `test/conformance/harness.ts` docstring to document the live-vs-offline split.
90
+
91
+ ### Production-readiness audit — tool-call accumulator, mock server
92
+
93
+ - **Defensive tool-call streaming accumulator (`src/tools/tool-call-accumulator.ts`).** The original `aggregateChat` in `src/streaming/normalize.ts` blindly appended every chunk's `tool_calls` array, which would produce duplicate entries if Ollama ever started streaming them incrementally. The new `ToolCallAccumulator` matches entries by `id` (the SDK-synthesized stable identifier) or by array position, and merges them with spread-semantics on `function.arguments`. For the documented native Ollama behavior (tool_calls arrive complete in one chunk), the accumulator is a no-op — one chunk carries the full array, the next chunk has nothing, and the accumulator appends exactly once. The accumulator is also exported for callers who want the same merge logic on raw NDJSON chunks.
94
+ - New exports: `ToolCallAccumulator` class, `mergeToolCallArrays()` stateless helper, `mergeToolCall()` / `mergeToolCallArgumentsString()` / `isSameToolCall()` standalone helpers.
95
+ - `aggregateChat` now uses `mergeToolCallArrays` instead of the naive `[...accumulated, ...incoming]` spread.
96
+ - Includes a dedicated `mergeToolCallArgumentsString` helper for the OpenAI-compat streaming format (where `function.arguments` arrives as string deltas like `'{"city":'` + `' "Bengaluru"}'`); the OpenAI-compat bridge at `src/integrations/openai.ts` already does its own per-index accumulation, but the helper is exported for callers who want the same logic elsewhere.
97
+
98
+ - **In-memory mock server for deterministic CI testing (`test/mocks/ollama-mock-server.ts`).** A thin `node:http` wrapper that lets tests register route handlers with programmable delay, chunk fragmentation, mid-stream error injection, and connection drops. Complements the existing VCR cassette system (`test/vcr.ts`) with capabilities cassettes can't provide:
99
+ - Programmable inter-chunk delay (test backpressure handling).
100
+ - Mid-stream error frame injection (test in-band `{"error":"..."}` trapping).
101
+ - Chunk fragmentation across TCP packets (test parser buffering).
102
+ - 503/502/429 error status codes with custom bodies.
103
+ - Connection drops mid-stream (test recovery from network failures).
104
+ - Request body capture via `onRequest` callback.
105
+ - Idempotent `stop()` — safe to call from `afterEach` hooks without tracking whether `start()` ran.
106
+ - Ephemeral port support (`port: 0`) for parallel test runs.
107
+
108
+ ### Second digest — mid-stream errors, 502/503 specialization, pull-progress ergonomics
109
+
110
+ - **In-band stream-error trapping (NDJSON).** Ollama's streaming endpoints start with HTTP 200 OK and chunked transfer encoding; if generation fails mid-flight (GPU OOM, driver crash, context window overflow, model unload race), the server emits a final `{"error": "..."}` JSON frame and closes the stream. The HTTP status code never changes from 200, so HTTP-status-based error detection misses these errors entirely — they would silently bleed into the assistant's content stream as garbage tokens or undefined-field accesses.
111
+ - `parseNdjsonStream` now detects bare `{"error": "..."}` frames and throws `OllamaStreamError` immediately, with the error message preserved.
112
+ - `OllamaStreamError.partialContent` carries whatever content was accumulated before the error frame arrived (concatenated `message.content` for chat streams, concatenated `response` for generate streams, empty string for pull/push streams).
113
+ - The stream's `finalResult` promise rejects with the enriched `OllamaStreamError`; the `for await ... of stream` iterator yields an `{ type: 'error', data: { error } }` event before completing.
114
+ - See: https://github.com/ollama/ollama/blob/main/docs/api.md
115
+
116
+ - **Granular HTTP status specialization.** Two new error subclasses give callers a way to branch on the failure mode rather than parsing messages or branching on `status` numbers.
117
+ - `OllamaOverloadedError` (HTTP 503) — server queue saturation (`OLLAMA_MAX_QUEUE` exceeded, default 512). `retryable: true`.
118
+ - `OllamaBadGatewayError` (HTTP 502) — cloud model could not be reached by the Ollama Cloud proxy. `retryable: true`.
119
+ - Both extend `OllamaClientError` directly (NOT `OllamaServerError`) because `OllamaServerError`'s constructor unconditionally forces `code: 'server_error'`. Callers wanting "any 5xx" should branch on `error.status >= 500 && error.status < 600` rather than `instanceof OllamaServerError`.
120
+ - Existing `instanceof` handlers for `OllamaNotFoundError` (404), `OllamaRateLimitError` (429), and `OllamaServerError` (generic 5xx) remain unchanged.
121
+
122
+ - **Typed pull/push progress callback (`onProgress`).** The SDK already exposed pull/push progress as a typed `OllamaStream` via `models.pull({ stream: true })`. The new `onProgress(stream, cb)` helper wraps the stream iteration with a pre-computed `percent` field for callers building download/upload UIs:
123
+
124
+ ```ts
125
+ const stream = await client.models.pull({ model: 'llama3.2', stream: true });
126
+ await onProgress(stream, (event) => {
127
+ if (event.percent !== undefined) {
128
+ console.log(`${event.status}: ${event.percent}% (${event.digest?.slice(0, 12) ?? '-'})`);
129
+ }
130
+ });
131
+ ```
132
+ - `computeProgressPercent(chunk)` and `toPullProgressEvent(chunk)` exported for callers who want the percent calculation without subscribing to a stream.
133
+ - `PullProgressEvent` type carries `{ status, digest?, total?, completed?, percent?, raw }`.
134
+
135
+ - **Cloud-vs-local tool-replay investigation (ADR 0023).** Documented the SDK's stance on parallel-vs-sequential tool-call emission from cloud vs local models: the SDK is a transparent passthrough, models decide, agent authors enforce sequential execution via `ToolRegistry`'s `maxConcurrency` option if they need it. Implemented the proposed `ModelCapabilities.parallelToolCalls` field as a best-effort heuristic:
136
+ - New `ParallelToolCallBehavior` union: `'yes' | 'no' | 'unknown'`.
137
+ - Cloud-mode + tool-capable → `'yes'` (the OpenAI/Anthropic compat bridges proxy to proprietary models that freely emit parallel tool calls).
138
+ - Cloud-mode + no tools → `'unknown'`.
139
+ - Local-mode + family in known-parallel list (`qwen2`, `qwen2.5`, `qwen3`, `llama3.1`, `llama3.2`, `llama3.3`, `llama4`, `mistral`, `mixtral`, `hermes`, `command-r`, `command-r-plus`) → `'yes'`.
140
+ - Local-mode + model name (including `:tag`) contains a tool-use variant hint (`tool-use`, `instruct`, `hermes`, `command-r`, etc.) → `'yes'`.
141
+ - Otherwise → `'unknown'` (caller should treat as "ask the model and see what it does").
142
+ - The family is extracted from `/api/show`'s `model_info.*.architecture` (with fallbacks to `details.family` then `details.families[0]`).
143
+
144
+ ### First digest — VRAM lifecycle, fetchWithBackoff, System One image caps, done_reason decoder
145
+
146
+ - **VRAM lifecycle primitives.** Added ergonomic helpers for explicit GPU memory management, addressing the upstream `keep_alive` semantics documented in the Ollama FAQ:
147
+ - `KeepAlive` type union (`string | number | 'unload' | 'indefinite'`) and `normalizeKeepAlive()` helper map the SDK-level sugar literals `'unload'` and `'indefinite'` to the wire-level `0` and `-1` sentinels.
148
+ - `ModelsClient.unload(model)` issues an empty `/api/generate` request with `keep_alive: 0` to evict a model from VRAM immediately, freeing GPU memory for subsequent pipelines.
149
+ - `ModelsClient.pin(model)` issues an empty `/api/generate` request with `keep_alive: -1` to pre-load and pin a model indefinitely for hot-loop inference.
150
+ - `OllamaClient.unloadModel(model)` and `OllamaClient.pinModel(model)` convenience aliases mirror the existing `listModels` / `pullModel` pattern.
151
+ - `KEEP_ALIVE_UNLOAD` and `KEEP_ALIVE_INDEFINITE` exported constants for callers who want the raw sentinel values directly.
152
+
153
+ - **Overload resiliency for HTTP 503 / 429.** New standalone `fetchWithBackoff()` helper wraps any fetch-shaped function with jittered exponential backoff for transient saturation responses. Mirrors the SDK's internal transport retry policy (`maxRetries: 3`, `initialDelayMs: 500`, `maxDelayMs: 30_000`, full-jitter strategy) so consumers see identical retry behavior whether they go through `OllamaClient` or call the helper directly. Useful for raw HTTP traffic to Ollama's compatibility bridges (Anthropic / OpenAI) or sibling Ollama instances outside the configured endpoint registry. `RETRYABLE_STATUS_CODES` and `DEFAULT_FETCH_BACKOFF_CONFIG` exported for downstream tooling.
154
+
155
+ - **System One image support ergonomics.** The generated `SystemOneRequest.images?: readonly string[]` field (already on the wire) is now backed by:
156
+ - `MAX_SYSTEM_ONE_REQUEST_BYTES` (64 KiB) and `MAX_SYSTEM_ONE_IMAGES_BYTES` (32 MiB) constants documenting the conditional server-side size limits.
157
+ - `estimateSystemOneRequestBytes(request)` helper for pre-flight size validation before sending a multi-image batch — the runtime enforces the limit too, but the early check avoids the round-trip when the caller already knows the payload is too large.
158
+
159
+ - **Response decoder hardening (Wave 13 conformance fix).** Added `KnownDoneReason` literal type (`'stop' | 'length' | 'load' | 'unload'`) and `isKnownDoneReason()` type guard so callers can narrow `done_reason` from `string | undefined` without risking `TypeError` on undefined access — the failure mode flagged in CI run #36962280416. The `done_reason` field on `ChatResponse` / `GenerateResponse` remains `string | undefined` for forward-compat with future upstream additions; the type guard provides opt-in narrowing.
160
+
3
161
  ## [1.8.0] - 2026-10-02
4
162
 
5
163
  - **Contract execution completion (Waves 12-16).** The SDK's contract-first architecture is now fully executable: every operation in the canonical IR is represented, generated, typed, and runtime-enforced with no `Record<string, unknown>` escape hatches on the generated surface.
package/README.md CHANGED
@@ -12,14 +12,18 @@
12
12
 
13
13
  - 🚀 **Native Web Standards**: Built on native `fetch` and Web Streams. Zero external HTTP dependencies.
14
14
  - 🧠 **Reasoning & Thinking Tokens**: First-class support for reasoning models (`qwen3:8b`, `deepseek-r1:8b`) via the native `think` parameter, with discrete `thinking` and `token` streaming events, plus `logprobs`/`top_logprobs` for token-level confidence scoring.
15
- - 🖼️ **Multimodal / Vision Input**: `images` on `Message`/`generate()` accepts base64 strings or raw `Uint8Array` bytes (auto-encoded) for vision models like `llava` or `qwen2.5vl`.
15
+ - 🖼️ **Multimodal / Vision Input**: `images` on `Message`/`generate()` is a universal resolver — pass raw base64 strings, `data:image/...;base64,` data URIs, `http(s)://` URLs (fetched), local file paths (`.png`/`.jpg`/`.webp`/…, read via `node:fs` on Node), or raw `Buffer`/`Uint8Array` bytes — everything is normalized to the raw base64 Ollama's REST API expects, matching the official SDK vision convention.
16
16
  - 🎯 **Zod-Powered Structured Outputs**: Strictly typed schema enforcement via `chatWithSchema` and `generateWithSchema` with resilient markdown JSON parsing.
17
17
  - 🛠️ **Autonomous Agent & Tool Calling**: Multi-turn agent loop (`Agent`) with automated tool execution, parameter validation, and self-correcting error recovery.
18
18
  - 🌐 **High Availability & Failover**: Multi-endpoint registry with priority routing, circuit breaker failover, active health checks, and per-endpoint `models` allow-lists for routing several model-specific API keys through one client.
19
19
  - 🔌 **Model Context Protocol (MCP)**: First-class, transport-neutral `McpBridge` for converting MCP tool descriptors into Ollama function definitions and registering executable MCP-backed tools.
20
20
  - 📚 **Full Model Lifecycle**: `pullModel`, `pushModel`, `createModel`, `copyModel`, `deleteModel`, `listModels`, `showModel`, and `ps()` (currently loaded models) — full parity with Ollama's model management API.
21
21
  - 🔎 **Ollama Cloud Web Tools**: `webSearch`/`webFetch` wrap Ollama's hosted `/api/web_search` and `/api/web_fetch` tools at `ollama.com` (requires an `OLLAMA_API_KEY`), independent of any local `baseUrl`.
22
- - 🌉 **OpenAI & Anthropic Compatibility Bridges**: Built-in clients for `/v1/chat/completions`, `/v1/responses`, `/v1/models`, and `/v1/messages`, including `reasoning_effort`/`reasoning.effort` for thinking models.
22
+ - 💳 **Ollama Cloud Usage & Balance**: `usage()`/`balance()` wrap Ollama's hosted account endpoints (`GET /api/usage`, `GET /api/balance`) — request counts, USD spend, cached-token totals bucketed by hour/day, and remaining included/purchased credits (including the legacy session/weekly plan shapes) — with the same fixed-cloud-host, API-key, timeout, and retry semantics as the web tools.
23
+ - 🌉 **OpenAI & Anthropic Compatibility Bridges**: Built-in clients for `/v1/chat/completions`, `/v1/responses`, `/v1/models`, and `/v1/messages`, including `reasoning_effort`/`reasoning.effort` for thinking models — plus an ergonomic dual-mode `client.responses.create()` bridge that prefers native `/v1/responses` and transparently re-issues via `/api/chat` on older servers (pre-v0.13.3).
24
+ - 💬 **KV-Cache-Aware Conversation Sessions**: `client.session(model, systemPrompt)` keeps an append-only, prefix-stable history that maximizes Ollama's KV-cache reuse across turns, and surfaces per-turn + cumulative cache hit rates (`prompt_eval_cached_count`) so cache degradation is visible instead of silent.
25
+ - 🛑 **Context-Window Safety**: Heuristic client-side token estimation warns (or throws, `onContextOverflow: 'throw'`) before a request is sent when the prompt approaches the effective `num_ctx` window — Ollama's default behavior is to _silently truncate_ oversized prompts — and `defaultContextLength` makes the window explicit on every request.
26
+ - 📦 **Blob & Custom Model Publishing**: Content-addressed blob management per Ollama's documented protocol — `computeBlobDigest()` (SHA-256 → `sha256:<hex>`), `createBlobFromData()`/`createBlobFromFile()` (HEAD-check + upload, skipping existing blobs), and one-shot `createModelFromGguf()` (upload GGUF shard blobs, then `/api/create` with `files: {name: digest}`).
23
27
  - 🌊 **Web Stream Adapters**: Drop-in adapters (`toTextStream`, `toDataStream`, `toResponse`) for Next.js Route Handlers and Vercel AI SDK.
24
28
  - 📈 **OpenTelemetry Instrumentation**: Automatic spans for HTTP requests, endpoint failover, chat/generate calls, and agent runs — zero-cost when OpenTelemetry isn't installed.
25
29
  - 📊 **Client-Side Quota Monitoring**: `QuotaManager` tracks token/request usage against budgets you configure across rolling windows (e.g. Ollama Cloud's 5-hour session / 7-day weekly resets) and fails fast with `OllamaQuotaExceededError` before a request is sent.
@@ -241,6 +245,105 @@ console.log(res.prompt_eval_count, res.prompt_eval_cached_count);
241
245
  console.log(res.prompt_eval_cached_count ?? 0);
242
246
  ```
243
247
 
248
+ ### KV-Cache-Aware Conversation Sessions
249
+
250
+ Ollama reuses the model's KV cache across turns by **prompt prefix matching** — anything that mutates the prefix (changing the system prompt, injecting per-call timestamps, reordering past turns) invalidates the whole cache and forces a full re-evaluation. `client.session()` makes the cache-friendly structure the default: a system prompt pinned at construction, an append-only frozen history, and per-turn options that never touch the prefix.
251
+
252
+ ```typescript
253
+ const session = client.session('llama3.1', 'You are a concise assistant.');
254
+
255
+ // Ergonomic path — just the reply text
256
+ await session.send('Hi!');
257
+
258
+ // Detailed path — per-turn KV-cache statistics + raw response
259
+ const turn = await session.sendTurn('Why is the sky blue?');
260
+ console.log(turn.cache);
261
+ // { cachedTokens: 48, evaluatedTokens: 6, hitRate: 0.89 }
262
+
263
+ // Cumulative view across the whole session
264
+ console.log(session.cacheStats);
265
+ // { turns: 2, cachedTokens: 48, evaluatedTokens: 54, totalPromptTokens: 102, hitRate: 0.47 }
266
+
267
+ session.reset(); // back to system-prompt-only, stats zeroed
268
+ session.getMessages(); // defensive copy of the frozen history
269
+ ```
270
+
271
+ Note the hit-rate denominator: when the _entire_ prompt hits the cache, Ollama reports `prompt_eval_count: 0` — the session's `hitRate` adds both counters so the best case scores `1`, not `0`.
272
+
273
+ ### OpenAI Responses API (dual-mode)
274
+
275
+ `client.responses.create()` gives migrating OpenAI code a small, familiar surface (`model`, `input`, `instructions`, `tools`, `temperature`, `top_p`, `max_output_tokens`, `reasoning_effort`, `think`) with **dual-mode transport**: the native `POST /v1/responses` endpoint is preferred (Ollama ≥ v0.13.3), and a `404` from older servers transparently re-issues the request through `/api/chat` — `instructions` mapped to a system message, the reply mapped back into the Responses shape. The result's `transport` field records which path served it.
276
+
277
+ ```typescript
278
+ const res = await client.responses.create({
279
+ model: 'gpt-oss:20b',
280
+ input: 'Explain KV caches in one paragraph.',
281
+ instructions: 'Be precise.',
282
+ max_output_tokens: 256,
283
+ reasoning_effort: 'medium',
284
+ });
285
+
286
+ console.log(res.output_text);
287
+ console.log(res.usage); // { input_tokens, output_tokens, total_tokens }
288
+ console.log(res.transport); // 'native' | 'chat-adapter'
289
+
290
+ // Streaming variant — simplified text/thinking deltas + final response
291
+ for await (const event of client.responses.stream({ model: 'qwen3', input: 'Tell me a haiku.' })) {
292
+ if (event.type === 'text_delta') process.stdout.write(event.delta);
293
+ else if (event.type === 'done') console.log('\n', event.response.usage);
294
+ }
295
+ ```
296
+
297
+ Ollama implements the Responses API **non-statefully** — `previous_response_id` and `conversation` don't exist, so send the full conversation in `input` every call (or use `ConversationSession` to manage it). For the full OpenAI-shaped surface (raw `output` items, SSE event objects), use `client.openai.responses()`.
298
+
299
+ ### Context-Window Safety (silent-truncation guard)
300
+
301
+ With `num_ctx` unset, Ollama loads the model with a conservative default window (commonly 2048–4096 tokens) and **silently truncates** prompts that don't fit — the model simply loses the top of the conversation with no error. The client estimates the prompt size before every `chat`/`generate` call and surfaces the risk:
302
+
303
+ ```typescript
304
+ const client = new OllamaClient({
305
+ // Make the window explicit on every request that omits options.num_ctx
306
+ defaultContextLength: 8192,
307
+
308
+ // 'warn' (default): log through `logger` and send anyway
309
+ // 'throw': reject client-side with OllamaClientError before anything hits the wire
310
+ onContextOverflow: 'warn',
311
+ });
312
+
313
+ // Warnings fire when the estimate crosses 90% of the effective window:
314
+ // "OllamaClient.chat(): estimated prompt size ~1900 tokens is close to or
315
+ // beyond the request's context window (num_ctx=2048). The server will
316
+ // likely silently truncate …"
317
+ ```
318
+
319
+ The estimators are exported for custom pipelines: `estimateTokens(text)` (CJK-aware — ~1 token per CJK character, ~4 chars/token elsewhere), `estimateChatRequestTokens(req)` / `estimateGenerateRequestTokens(req)` (message overhead + tool schemas + `IMAGE_TOKEN_ESTIMATE` per image), and the underlying `checkChatContext` / `checkGenerateContext` / `contextWarningMessage`. All are heuristics (±20–30%) — for exact counts, ask the server (`prompt_eval_count`).
320
+
321
+ ### Blob Management & Custom GGUF Model Publishing
322
+
323
+ Ollama's documented import protocol: push a blob for each file, then reference it in `/api/create`'s `files` map by file name and SHA-256 digest. The SDK wraps the whole flow:
324
+
325
+ ```typescript
326
+ // Content-addressed digest: SHA-256 -> "sha256:<64 lowercase hex>"
327
+ const digest = await client.models.computeBlobDigest(ggufBytes);
328
+
329
+ // HEAD-check + upload (skips the POST when the blob already exists)
330
+ const { digest, alreadyExisted } = await client.models.createBlobFromData(ggufBytes);
331
+ const upload = await client.models.createBlobFromFile('/models/my-model.gguf');
332
+ // -> { digest: 'sha256:…', alreadyExisted: false, fileName: 'my-model.gguf' }
333
+
334
+ // One-shot: upload every GGUF shard, then POST /api/create with files: {name: digest}
335
+ await client.models.createModelFromGguf('my-model', '/models/my-model.gguf', {
336
+ template: '{{ .Prompt }}',
337
+ parameters: { temperature: 0.7 },
338
+ });
339
+
340
+ // Split GGUFs: pass every shard
341
+ await client.models.createModelFromGguf('my-model', [
342
+ '/models/model-00001-of-00002.gguf',
343
+ '/models/model-00002-of-00002.gguf',
344
+ ]);
345
+ ```
346
+
244
347
  ### Token Log Probabilities (`logprobs`)
245
348
 
246
349
  Set `logprobs: true` (optionally with `top_logprobs`) on `chat()`/`generate()` to get per-token log probabilities back — useful for confidence scoring, speculative decoding, or agent routing decisions.
@@ -261,27 +364,62 @@ for (const entry of res.logprobs ?? []) {
261
364
 
262
365
  ### Multimodal / Vision Input
263
366
 
264
- `images` on a `Message` (or on `generate()`'s top-level request) accepts base64-encoded strings or raw `Uint8Array` bytes — `Uint8Array` entries are base64-encoded automatically before the request is sent.
367
+ `images` on a `Message` (or on `generate()`'s top-level request) is a **universal vision resolver** — every polymorphic form is normalized to the raw base64 string Ollama's REST API expects (no `data:image/...;base64,` URI prefixes ever reach the wire):
265
368
 
266
369
  ```typescript
267
- import { readFile } from 'node:fs/promises';
370
+ // 1. Local file paths (Node.js — read via dynamically-imported node:fs)
371
+ const res = await client.chatText({
372
+ model: 'llava',
373
+ messages: [
374
+ {
375
+ role: 'user',
376
+ content: 'What is in this image?',
377
+ images: ['./cat.png'],
378
+ },
379
+ ],
380
+ });
268
381
 
269
- const imageBytes = await readFile('./cat.png'); // Buffer, a Uint8Array subclass
382
+ // 2. Data URIs — the header is stripped automatically
383
+ await client.chat({
384
+ model: 'llava',
385
+ messages: [
386
+ {
387
+ role: 'user',
388
+ content: 'Describe this.',
389
+ images: ['data:image/png;base64,iVBORw0KGgo...'],
390
+ },
391
+ ],
392
+ });
270
393
 
271
- const res = await client.chatText({
394
+ // 3. Web URLs — fetched and encoded
395
+ await client.chat({
272
396
  model: 'llava',
273
- messages: [{ role: 'user', content: 'What is in this image?', images: [imageBytes] }],
397
+ messages: [{ role: 'user', content: 'OCR this.', images: ['https://example.com/receipt.png'] }],
274
398
  });
275
- console.log(res);
276
399
 
277
- // Base64 strings work too, unchanged:
278
- const base64Res = await client.generateText({
400
+ // 4. Raw bytes — Buffer / Uint8Array, base64-encoded automatically
401
+ import { readFile } from 'node:fs/promises';
402
+ await client.chat({
403
+ model: 'llava',
404
+ messages: [
405
+ {
406
+ role: 'user',
407
+ content: 'What is in this image?',
408
+ images: [await readFile('./cat.png')],
409
+ },
410
+ ],
411
+ });
412
+
413
+ // 5. Plain base64 strings — passed through unchanged
414
+ await client.generateText({
279
415
  model: 'llava',
280
416
  prompt: 'Describe this image.',
281
417
  images: ['iVBORw0KGgoAAAANSUhEUgAA...'],
282
418
  });
283
419
  ```
284
420
 
421
+ The resolver is also exported standalone for custom pipelines: `resolveImageInput(input)` (single) and `resolveImages(images)` (batch, parallel). In browsers/edge runtimes, file-path strings throw a descriptive error (no `node:fs`) — read the file yourself and pass the bytes.
422
+
285
423
  ### Structured Outputs with Zod
286
424
 
287
425
  ```typescript
@@ -367,6 +505,39 @@ console.log(page.title, page.content.slice(0, 200));
367
505
 
368
506
  These two methods don't participate in the multi-endpoint failover below — there's only ever the one cloud host to call — but they do use the same default `timeoutMs` and retry policy as everything else.
369
507
 
508
+ ### Cloud Usage & Balance (Ollama Cloud account)
509
+
510
+ `usage`/`balance` wrap Ollama's **hosted account endpoints** (`GET https://ollama.com/api/usage` and `/api/balance`) — the same fixed Ollama Cloud service and API-key requirements as `webSearch`/`webFetch` above, so everything said there about auth, timeouts, and retry applies identically here:
511
+
512
+ ```typescript
513
+ const client = new OllamaClient({
514
+ baseUrl: 'http://localhost:11434', // local inference — unrelated to the calls below
515
+ apiKey: process.env.OLLAMA_API_KEY, // required for usage/balance specifically
516
+ });
517
+
518
+ // Usage for the last 24 hours, bucketed hourly (omit options for the server
519
+ // defaults: range='7d', scope='self'). Team scope requires a team admin.
520
+ const usage = await client.usage({ range: '24h' });
521
+ console.log(usage.totals.request_count, usage.totals.usage_usd, usage.totals.cached_input_tokens);
522
+ for (const bucket of usage.buckets) {
523
+ if (bucket.partial) continue; // the current hour — still in progress
524
+ console.log(bucket.from, bucket.request_count);
525
+ }
526
+
527
+ // Remaining credits. `included` is either the plan-period credits object
528
+ // (`balance_usd`/`allowance_usd`/`period`) or, on legacy plans, the
529
+ // session/weekly percentage-limits shape — discriminated by the response.
530
+ const balance = await client.balance();
531
+ if ('balance_usd' in balance.included) {
532
+ console.log(`included: $${balance.included.balance_usd} of $${balance.included.allowance_usd}`);
533
+ } else {
534
+ console.log(`session limit: ${balance.included.session.remaining_percent}% remaining`);
535
+ }
536
+ console.log(`purchased: $${balance.purchased.balance_usd}`);
537
+ ```
538
+
539
+ Both endpoints are rate-limited to 10 requests/minute per user (429 responses carry `Retry-After`); polling about once a minute is the recommended cadence.
540
+
370
541
  ### Autonomous Agent & Tool Calling
371
542
 
372
543
  ```typescript
@@ -1,4 +1,4 @@
1
- import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ab as SseEvent, w as OllamaClientError } from './runtime-C6UYtBRB.js';
1
+ import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ae as SseEvent, x as OllamaClientError } from './runtime-C3rfpkZw.js';
2
2
 
3
3
  /**
4
4
  * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
@@ -139,6 +139,8 @@ interface CreateRequest {
139
139
  readonly draft_quantize?: string | undefined;
140
140
  /** Minimum Ollama version required by the model */
141
141
  readonly requires?: string | undefined;
142
+ /** Capabilities to add without removing inherited or inferred capabilities (e.g. `decision` for compatible decision models) */
143
+ readonly capabilities?: readonly string[] | undefined;
142
144
  /** Stream status updates */
143
145
  readonly stream?: boolean | undefined;
144
146
  }
@@ -342,7 +344,7 @@ interface ModelSummary {
342
344
  /** Primary model family (for example `llama`) */
343
345
  readonly family?: string | undefined;
344
346
  /** All families the model belongs to, when applicable */
345
- readonly families?: readonly string[] | undefined;
347
+ readonly families?: readonly string[] | null | undefined;
346
348
  /** Approximate parameter count label (for example `7B`, `13B`) */
347
349
  readonly parameter_size?: string | undefined;
348
350
  /** Quantization level used (for example `Q4_0`) */
@@ -1,4 +1,4 @@
1
- import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ab as SseEvent, w as OllamaClientError } from './runtime-DTmUeU6K.cjs';
1
+ import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ae as SseEvent, x as OllamaClientError } from './runtime-D2W9TfCJ.cjs';
2
2
 
3
3
  /**
4
4
  * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
@@ -139,6 +139,8 @@ interface CreateRequest {
139
139
  readonly draft_quantize?: string | undefined;
140
140
  /** Minimum Ollama version required by the model */
141
141
  readonly requires?: string | undefined;
142
+ /** Capabilities to add without removing inherited or inferred capabilities (e.g. `decision` for compatible decision models) */
143
+ readonly capabilities?: readonly string[] | undefined;
142
144
  /** Stream status updates */
143
145
  readonly stream?: boolean | undefined;
144
146
  }
@@ -342,7 +344,7 @@ interface ModelSummary {
342
344
  /** Primary model family (for example `llama`) */
343
345
  readonly family?: string | undefined;
344
346
  /** All families the model belongs to, when applicable */
345
- readonly families?: readonly string[] | undefined;
347
+ readonly families?: readonly string[] | null | undefined;
346
348
  /** Approximate parameter count label (for example `7B`, `13B`) */
347
349
  readonly parameter_size?: string | undefined;
348
350
  /** Quantization level used (for example `Q4_0`) */
@@ -1,4 +1,4 @@
1
- import { p as ToolDefinition, q as ToolCall, r as Message } from './types-5PAjLoCp.js';
1
+ import { l as ToolDefinition, i as ToolCall, n as Message } from './types-DVcX_zMp.js';
2
2
  import { z } from 'zod';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { p as ToolDefinition, q as ToolCall, r as Message } from './types-5PAjLoCp.cjs';
1
+ import { l as ToolDefinition, i as ToolCall, n as Message } from './types-DVcX_zMp.cjs';
2
2
  import { z } from 'zod';
3
3
 
4
4
  /**
@@ -1,6 +1,25 @@
1
1
  'use strict';
2
2
 
3
3
  // src/generated/api/operations.ts
4
+ var balanceOp = {
5
+ operationId: "balance",
6
+ method: "GET",
7
+ path: "/api/balance",
8
+ response: { $ref: "#/schemas/BalanceResponse" },
9
+ environment: { local: false, cloud: true },
10
+ host: "https://ollama.com",
11
+ transport: { mode: "json", streaming: false },
12
+ capabilities: {},
13
+ status: { documented: true },
14
+ domain: "native",
15
+ notes: [
16
+ "Cloud-only account endpoint \u2014 targets https://ollama.com, not the local Ollama server.",
17
+ "Requires an Ollama Cloud API key (set via OllamaClient credentials).",
18
+ "Takes no parameters. For usage history see the usage operation.",
19
+ "Rate limited to 10 requests/minute per user; 429 responses carry a Retry-After header.",
20
+ "Use OllamaClient.balance() \u2014 the generated NativeApi class does not expose this operation."
21
+ ]
22
+ };
4
23
  var blobsOp = {
5
24
  operationId: "blobs",
6
25
  method: "HEAD",
@@ -208,6 +227,25 @@ var tagsOp = {
208
227
  status: { documented: true },
209
228
  domain: "native"
210
229
  };
230
+ var usageOp = {
231
+ operationId: "usage",
232
+ method: "GET",
233
+ path: "/api/usage",
234
+ response: { $ref: "#/schemas/UsageResponse" },
235
+ environment: { local: false, cloud: true },
236
+ host: "https://ollama.com",
237
+ transport: { mode: "json", streaming: false },
238
+ capabilities: {},
239
+ status: { documented: true },
240
+ domain: "native",
241
+ notes: [
242
+ "Cloud-only account endpoint \u2014 targets https://ollama.com, not the local Ollama server.",
243
+ "Requires an Ollama Cloud API key (set via OllamaClient credentials).",
244
+ "Query parameters (not modeled by the generated runtime): range = 24h | 7d | 30d (server default 7d), scope = self | team (server default self; team scope requires a team admin).",
245
+ "Rate limited to 10 requests/minute per user; 429 responses carry a Retry-After header.",
246
+ "Use OllamaClient.usage() \u2014 the generated NativeApi class does not expose this operation."
247
+ ]
248
+ };
211
249
  var versionOp = {
212
250
  operationId: "version",
213
251
  method: "GET",
@@ -344,6 +382,7 @@ var anthropicMessagesOp = {
344
382
  ]
345
383
  };
346
384
  var allOperations = [
385
+ balanceOp,
347
386
  blobsOp,
348
387
  chatOp,
349
388
  copyOp,
@@ -358,6 +397,7 @@ var allOperations = [
358
397
  showOp,
359
398
  systemOneOp,
360
399
  tagsOp,
400
+ usageOp,
361
401
  versionOp,
362
402
  webFetchOp,
363
403
  webSearchOp,
@@ -375,7 +415,6 @@ var NativeApi = class {
375
415
  constructor(runtime) {
376
416
  this.runtime = runtime;
377
417
  }
378
- runtime;
379
418
  blobs(digest, options) {
380
419
  return this.runtime.invoke({
381
420
  operation: blobsOp,
@@ -477,7 +516,6 @@ var OpenAIApi = class {
477
516
  constructor(runtime) {
478
517
  this.runtime = runtime;
479
518
  }
480
- runtime;
481
519
  openaiChatCompletions(request) {
482
520
  return this.runtime.invoke({
483
521
  operation: openaiChatCompletionsOp,
@@ -524,7 +562,6 @@ var AnthropicApi = class {
524
562
  constructor(runtime) {
525
563
  this.runtime = runtime;
526
564
  }
527
- runtime;
528
565
  anthropicMessages(request) {
529
566
  return this.runtime.invoke({
530
567
  operation: anthropicMessagesOp,
@@ -538,6 +575,7 @@ exports.NativeApi = NativeApi;
538
575
  exports.OpenAIApi = OpenAIApi;
539
576
  exports.allOperations = allOperations;
540
577
  exports.anthropicMessages = anthropicMessagesOp;
578
+ exports.balance = balanceOp;
541
579
  exports.blobs = blobsOp;
542
580
  exports.chat = chatOp;
543
581
  exports.copy = copyOp;
@@ -558,6 +596,7 @@ exports.push = pushOp;
558
596
  exports.show = showOp;
559
597
  exports.systemOne = systemOneOp;
560
598
  exports.tags = tagsOp;
599
+ exports.usage = usageOp;
561
600
  exports.version = versionOp;
562
601
  exports.webFetch = webFetchOp;
563
602
  exports.webSearch = webSearchOp;