@nemesis-oss/ollama-sdk 1.0.0 → 1.3.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,160 @@ All notable changes to `@nemesis-oss/ollama-sdk` will be documented in this file
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.3.0] - 2026-08-25
9
+
10
+ ### Added
11
+
12
+ - **Client-side quota monitoring (`QuotaManager`).** Ollama Cloud doesn't expose
13
+ account-level quota through the API — no response header or endpoint reports how much
14
+ of your plan's session/weekly limit is left (see
15
+ [ollama/ollama#15663](https://github.com/ollama/ollama/issues/15663)). `QuotaManager`
16
+ tracks usage you record (via `recordUsage`, which reads `extractUsage`-normalized token
17
+ counts off a raw response) against budgets you configure over one or more rolling
18
+ windows, and refuses to proceed (`canProceed`/`assertCanProceed`) once a window's budget
19
+ is spent — a local safety net to complement, not replace, catching the server's own
20
+ `OllamaRateLimitError`. `createOllamaCloudFreeTierQuota` is a convenience factory
21
+ wiring up the free tier's documented 5-hour session and 7-day weekly window cadence
22
+ (you still supply the token/request budgets, since Ollama doesn't publish the actual
23
+ ceilings). New `OllamaQuotaExceededError` (`code: 'quota_exceeded'`) is thrown by
24
+ `assertCanProceed`. See the [Quota Monitoring](./README.md#quota-monitoring) README
25
+ section.
26
+ - **Credential-scoped multi-key routing.** `OllamaEndpoint` gains an optional `models`
27
+ allow-list, for the common case of several Ollama Cloud API keys each entitled to a
28
+ different model. `EndpointRegistry.candidates(model)` now filters to endpoints whose
29
+ `models` includes the requested model (endpoints without `models` stay eligible for
30
+ every model — fully backward compatible), so `chat`/`generate`/`embed`/`embeddings` and
31
+ model-lifecycle calls (`showModel`, `pullModel`, etc.) automatically resolve the
32
+ authorized credential for the model requested, and cross-endpoint failover between
33
+ differently-scoped endpoints never sends a request to a key that isn't entitled to that
34
+ model. Requesting a model no configured endpoint is scoped to throws the new
35
+ `OllamaModelRoutingError` (`code: 'model_routing_error'`) immediately, before any
36
+ network call — the SDK never probes unauthorized keys to see which one happens to
37
+ work. See the README's
38
+ ["Multiple API keys, each entitled to different models"](./README.md#multiple-api-keys-each-entitled-to-different-models)
39
+ and the
40
+ [multi-model agent benchmarking guide](./docs/guides/multi-model-agent-benchmarking.md).
41
+ - **`credentials` + `modelBindings` config.** An ergonomic, map-based alternative to
42
+ writing `endpoints` with per-entry `models` allow-lists by hand: `OllamaClientConfig`
43
+ gains `credentials` (named `{ apiKey, baseUrl?, headers? }` entries, keyed by an id you
44
+ choose), `modelBindings` (maps a model to the credential id, or ids, authorized to serve
45
+ it), and `defaultCredential` (a fallback credential for any model with no explicit
46
+ binding). Both config shapes compile down to the same `EndpointRegistry`/
47
+ `executeWithFailover` routing above — this is config sugar, not a second routing
48
+ mechanism — so behavior (including `OllamaModelRoutingError` on an unrouted model) is
49
+ identical either way. `modelBindings` referencing an unknown credential id throws at
50
+ construction. New `resolveCredentialEndpoints` export for anyone who wants the
51
+ translation without going through `OllamaClient`.
52
+ - **Round-robin candidate selection.** `EndpointRegistryOptions` (passed via
53
+ `OllamaClientConfig.endpointHealth`) gains `strategy: 'priority' | 'round-robin'`
54
+ (default `'priority'`, unchanged prior behavior). With `'round-robin'`,
55
+ `EndpointRegistry.candidates()` rotates each same-priority group of healthy candidates
56
+ by one position per call, so consecutive `chat`/`generate`/`embed`/etc. calls spread
57
+ across a pool of interchangeable endpoints or unbound `credentials` (e.g. several
58
+ free-tier Ollama Cloud keys with no `models`/`modelBindings` restriction) instead of
59
+ always preferring the first one. Candidates at different priorities are unaffected —
60
+ a higher-priority candidate is still always tried first — and failover to the rest of
61
+ the (rotated) list still applies if the first pick fails. See the README's
62
+ ["A free pool of interchangeable keys — and spreading load across it"](./README.md#a-free-pool-of-interchangeable-keys--and-spreading-load-across-it).
63
+ - **Least-connections candidate selection.** `EndpointRegistryOptions.strategy` gains a
64
+ third value, `'least-connections'`, alongside `'priority'` (default) and
65
+ `'round-robin'`. Each same-priority tier is ordered by ascending in-flight request
66
+ count (new `EndpointRegistry.acquire`/`release`, wired into `OllamaClient.executeWithFailover`
67
+ around each attempt) rather than a fixed rotation, so concurrent `Promise.all`-style
68
+ fan-out deterministically lands on distinct candidates — the motivating case being
69
+ several Ollama Cloud free-tier accounts, each capped at 1 concurrent request: `N`
70
+ concurrent requests against `N` such accounts land one-per-account rather than risking
71
+ two on the same still-busy one, because the endpoint choice and its `acquire()` happen
72
+ synchronously with no `await` in between (JS's single-threaded execution rules out the
73
+ race entirely). `EndpointHealth` gains `activeRequests`, also exposed via
74
+ `client.endpointStatus()`, for observability regardless of `strategy`. See the README's
75
+ ["Concurrent requests across single-slot accounts (least-connections)"](./README.md#concurrent-requests-across-single-slot-accounts-least-connections).
76
+ - **`maxConcurrentPerEndpoint` — queueing past capacity.** `EndpointRegistryOptions`
77
+ gains `maxConcurrentPerEndpoint`, capping in-flight requests per endpoint exactly. Once
78
+ every otherwise-eligible candidate is at that cap, a request waits (FIFO, new
79
+ `EndpointRegistry.filterWithCapacity`/`waitForCapacity`) for one to free rather than
80
+ being routed to an already-saturated candidate — the gap `'least-connections'` alone
81
+ doesn't close for `N + 1` concurrent calls against `N` capacity-1 candidates. Waiting is
82
+ bounded by the request's own `timeoutMs`/`AbortSignal`; a queued call that times out or
83
+ is cancelled is dequeued and rejects without ever being sent.
84
+
85
+ ### Fixed
86
+
87
+ - **Streaming requests (`chatStream`/`generateStream`) now hold their endpoint's
88
+ concurrency slot for the lifetime of the stream, not just until it starts.**
89
+ Previously, `acquire`/`release` around a streaming call released the slot as soon as
90
+ `http.requestStream` resolved (response headers received) — before any tokens were
91
+ actually read — so `'least-connections'`/`maxConcurrentPerEndpoint` accounting stopped
92
+ reflecting reality the moment a stream was returned, undercounting real concurrency for
93
+ as long as the caller kept consuming it. `executeWithFailover` gains an internal
94
+ `holdUntil` hook, wired to the returned `OllamaStream`'s `finalResult` for `chatStream`/
95
+ `generateStream` (and the streaming `pull`/`push`/`create` progress endpoints), so the
96
+ slot now releases only once the stream is fully drained, errors, or is aborted.
97
+
98
+ ## [1.2.0] - 2026-08-24
99
+
100
+ Closes gaps found during a documentation/API-parity review against the official Ollama
101
+ API — two of which were genuine issues, the rest already covered (multimodal `images`,
102
+ native `think`, `/api/embed`, and full model-lifecycle management all predate this
103
+ release; see the new README sections documenting them).
104
+
105
+ ### Fixed
106
+
107
+ - **`webSearch`/`webFetch` were non-functional against real Ollama Cloud.** They
108
+ previously posted to `<configured-baseUrl>/api/websearch` and `/webfetch` — the wrong
109
+ host (Ollama's web tools only ever exist at `https://ollama.com`, never proxied through
110
+ a local server) _and_ the wrong path (missing the underscore: `/api/web_search`,
111
+ `/api/web_fetch`) _and_ the wrong request/response field names. Both methods now always
112
+ target `https://ollama.com` regardless of `baseUrl`/`endpoints`, using the resolved
113
+ `apiKey`/`OLLAMA_API_KEY`, and use the real field names (`max_results` request,
114
+ `content` response). `WebSearchRequestOptions.count` and `WebSearchResult.snippet` are
115
+ kept as `@deprecated` back-compat aliases (mapped to/mirrored from the correct fields)
116
+ rather than removed outright. `WebFetchResponse` gains the `title`/`links` fields the
117
+ real API actually returns.
118
+
119
+ ### Added
120
+
121
+ - **`logprobs`/`top_logprobs`:** Added to `ChatRequestOptions`/`GenerateRequestOptions`
122
+ (request) and `ChatResponse`/`GenerateResponse` (response, as a new `Logprob[]` typed
123
+ by the new `Logprob`/`LogprobToken` types), matching the official `/api/chat` and
124
+ `/api/generate` schemas.
125
+ - `OLLAMA_CLOUD_BASE_URL` exported for consumers who want to reference the fixed web-tools
126
+ host directly.
127
+
128
+ ## [1.1.0] - 2026-08-23
129
+
130
+ Brings the SDK's typed surface up to date with Ollama v0.13.3+.
131
+
132
+ ### Added
133
+
134
+ - **`/api/create` field parity:** `CreateRequestOptions` now exposes the documented
135
+ `template`, `renderer`, `parser`, `license`, `system`, `parameters`, and `messages`
136
+ fields alongside the existing `from`/`files`/`adapters`/`quantize`. The old
137
+ `modelfile` string field is kept for backward compatibility but marked `@deprecated`
138
+ in favor of the discrete fields.
139
+ - **OpenAI Responses API bridge:** `client.openai.responses()` / `createResponses()`
140
+ POST to `/v1/responses`. Ollama implements this non-statefully, so
141
+ `previous_response_id`/`conversation` are typed but documented as ignored.
142
+ - **`reasoning_effort` / `reasoning.effort`:** Added to `OpenAIChatCompletionRequest`
143
+ for thinking models (`deepseek-r1`, `qwen3`, etc.), matching Ollama's OpenAI
144
+ compatibility docs.
145
+ - **`tool_choice` / `parallel_tool_calls`:** Now typed as accepted-but-ignored on
146
+ `OpenAIChatCompletionRequest` (previously omitted entirely), so passing a standard
147
+ OpenAI request object type-checks without modification.
148
+ - **Raw image bytes:** `Message.images` and `GenerateRequestOptions.images` accept
149
+ `Uint8Array` alongside base64 strings. `OllamaClient.chat()`/`generate()` encode any
150
+ `Uint8Array` entries to base64 automatically via the new `encodeImage` utility
151
+ (exported from the package root), using `Buffer` on Node and `btoa` elsewhere so it
152
+ stays Edge Runtime-safe.
153
+ - **`doneReason` in stream results:** `ChatStreamResult`/`GenerateStreamResult` now
154
+ carry `doneReason`, mapped from the final chunk's `done_reason` (e.g. `"stop"`,
155
+ `"load"`, `"unload"`).
156
+
157
+ ### Fixed
158
+
159
+ - `package.json`'s `homepage`, `repository`, and `bugs` URLs now point at
160
+ `ollama-sdk` instead of the pre-rename `ollama-client-ts`.
161
+
8
162
  ## [1.0.0] - 2026-08-17
9
163
 
10
164
  First public release. The version was `0.1.0` throughout development but was never