@nemesis-oss/ollama-sdk 1.19.0 → 1.19.1
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 +20 -0
- package/README.md +8 -8
- package/dist/{anthropic-CAvwqIjx.d.ts → anthropic-Bf16hGLL.d.cts} +1 -1
- package/dist/{anthropic-DIPnBwlf.d.cts → anthropic-BmFk4Pjq.d.ts} +1 -1
- package/dist/generated-api.d.cts +4 -4
- package/dist/generated-api.d.ts +4 -4
- package/dist/generated-runtime.cjs.map +1 -1
- package/dist/generated-runtime.d.cts +1 -1
- package/dist/generated-runtime.d.ts +1 -1
- package/dist/generated-runtime.js.map +1 -1
- package/dist/index.cjs +115 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -34
- package/dist/index.d.ts +73 -34
- package/dist/index.js +115 -15
- package/dist/index.js.map +1 -1
- package/dist/mcp-generated.d.cts +1 -1
- package/dist/mcp-generated.d.ts +1 -1
- package/dist/{runtime-C28YEAHC.d.cts → runtime-CjCriL5A.d.cts} +29 -1
- package/dist/{runtime-DYCxYGG-.d.ts → runtime-EwyUaNnZ.d.ts} +29 -1
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.19.1] — Honoring `Retry-After` on 429s: closing the dead-`retryAfterMs` gap (audit v1.19.0 parity)
|
|
4
|
+
|
|
5
|
+
The daily audit against the v1.19.0 baseline (`2d3ec47`) claimed six capability domains all PASS; point-by-point verification found five true and one false — "Native client methods with `OllamaRateLimitError.retryAfterMs` and jittered 429 retries". The field existed and the docs already described it, but nothing populated or consumed it: all three `HttpClient` error-mapping sites discarded response headers when building error contexts, `statusToError`'s 429 branch never parsed `Retry-After`, and `withRetry` slept full-jitter backoff regardless. The pinned upstream contract documents `Retry-After` ("Seconds to wait before retrying", `type: integer`) on the 429 responses of both cloud account endpoints (`/api/usage`, `/api/balance`) — this was contract-required behavior our own `docs-site/api/errors.md` already claimed. All changes live in the handwritten layer; no contract or generated-surface changes (see [ADR 0035](./docs/adr/0035-retry-after-honoring.md)). 1057 pre-existing tests stay green, 30 net-new tests added.
|
|
6
|
+
|
|
7
|
+
### `OllamaRateLimitError.retryAfterMs` is now real
|
|
8
|
+
|
|
9
|
+
- **`parseRetryAfterMs(headerValue, now?)` — new root-exported parser**: delay-seconds (`"120"` → 120 000 ms) or strict IMF-fixdate HTTP-date (→ milliseconds until that instant, clamped at `0` for past dates). The HTTP-date branch validates the shape **before** `Date.parse` because engine date parsers are dangerously lenient (V8 accepts `"1.5"` as a year-2001 date); malformed or overflow values return `undefined`, which falls back to jitter instead of overriding it with a bogus delay. `lookupHeader` (module-level export) does the case-insensitive header lookup on error-context header records.
|
|
10
|
+
- `statusToError`'s 429 branch injects `retryAfterMs` from the response headers — one mapping chokepoint, one status. No other status mapping parses the header: 503/502 keep jitter, because nothing documents `Retry-After` for them (the same invented-behavior reasoning ADR 0034 § 5 applied to the cloud limits).
|
|
11
|
+
|
|
12
|
+
### Transport capture and retry pacing
|
|
13
|
+
|
|
14
|
+
- `HttpClient` now captures `retry-after` at all three error-mapping sites (`request()`, `requestStream()`, `requestSseStream()`) and the no-middleware lifecycle error event (the middleware path already reported headers) — deliberately capturing **only that one header**, so sensitive fields like `set-cookie` never leak into thrown error objects that callers log. The capture is defensive by design: mock `Response` shapes without a `Headers` implementation degrade to the pre-1.19.1 error-context shape instead of throwing mid-enrichment.
|
|
15
|
+
- **`withRetry` honors the server's delay verbatim** — no jitter, no clamping to `maxDelayMs` — via the new `retryDelayMs(error, attempt, backoff)`: the server explicitly said when the client may retry, and re-issuing earlier would only compound the rate limiting the 429 exists to prevent. Callers who consider a server value excessive keep three sanctioned exits: `shouldRetry` rejecting the error, the abort signal (live for the whole sleep), or a `maxRetries` budget. Absent/unparseable headers — and every other retryable error — keep the full-jitter exponential backoff, unchanged. `onRetry` reports the delay actually used, either way.
|
|
16
|
+
- `fetchWithBackoff` honors `Retry-After` on 429s identically — its own docs claim "the same retry discipline as the SDK's internal transport", which is kept honest rather than re-worded. The honoring is 429-scoped: 503s keep full jitter even if a header is present.
|
|
17
|
+
|
|
18
|
+
### Docs
|
|
19
|
+
|
|
20
|
+
- New [ADR 0035](./docs/adr/0035-retry-after-honoring.md) recording the fix and the declined alternatives with reasoning (clamping to `maxDelayMs`, capturing the full header record, extending `Retry-After` parsing to 503/502, jittering the server value). ADR indexes updated: `docs/adr/README.md` and `docs-site/adr/index.md` — the latter also gains its missing 0034 row from the 1.19.0 wave.
|
|
21
|
+
- `docs-site/api/errors.md`'s `OllamaRateLimitError` section now describes the honored-by-`withRetry` semantics and the `parseRetryAfterMs` export; `client.ts`'s cloud-endpoint JSDoc (`webSearch`/`webFetch`/`usage`/`balance`) notes the contract-declared `Retry-After` on 429s.
|
|
22
|
+
|
|
3
23
|
## [1.19.0] — System One cloud launch contract refresh: dual request-size cap, 402 taxonomy, re-pin d9b8601
|
|
4
24
|
|
|
5
25
|
The scheduled upstream snapshot freshness check (offered after the Task 24 docs fix, accepted) found upstream `openapi.yaml@main` had moved from `2a9ffe3` to `d9b8601` with the **System One cloud launch** — audited point-by-point against the pinned snapshot before any change, per house discipline (see [ADR 0034](./docs/adr/0034-systemone-cloud-launch-contract-refresh.md)). Upstream now declares `/v1/systemone` with local **and cloud** servers (`https://ollama.com`, optional `bearerAuth`), the `model` field accepts cloud models (`clef:cloud`, requiring Ollama >= 0.40.5 or the hosted endpoint), the local byte caps were **clarified from an either/or reading to a dual bound**, and 401/402 joined the documented response set. A second discovery retired an old deviation: the "corrupted Usage enum literals" the 2026-10-07 pin repaired were our own Bash display artifact eating `[24h`/`[h` CSI-style sequences — upstream serves them clean inline, so the repair deviation is retired. All changes additive or contract-aligning; no breaking API changes. 1047 pre-existing tests stay green, 10 net-new tests added (5 rewritten onto the new semantics).
|
package/README.md
CHANGED
|
@@ -337,7 +337,7 @@ Ollama implements the Responses API **non-statefully** — `previous_response_id
|
|
|
337
337
|
|
|
338
338
|
### Context-Window Safety (silent-truncation guard)
|
|
339
339
|
|
|
340
|
-
With `num_ctx` unset, Ollama
|
|
340
|
+
With `num_ctx` unset, Ollama sizes the default window by available VRAM — 4,096 tokens below 24 GiB, 32,768 at 24–48 GiB, 262,144 at 48 GiB and up (daemon-wide override via `OLLAMA_CONTEXT_LENGTH`; cloud models run at their maximum) — and **silently truncates** prompts that don't fit. The client estimates the prompt size before every `chat`/`generate` call and surfaces the risk:
|
|
341
341
|
|
|
342
342
|
```typescript
|
|
343
343
|
const client = new OllamaClient({
|
|
@@ -359,7 +359,7 @@ The estimators are exported for custom pipelines: `estimateTokens(text)` (CJK-aw
|
|
|
359
359
|
|
|
360
360
|
### Discovering the Real Context Window
|
|
361
361
|
|
|
362
|
-
Guessing context windows ("it's probably 2048… or 4096?") is how silent truncation happens. Ollama advertises the real numbers in two places, and they answer _different questions_: `GET /api/ps` reports the window the **running instance actually allocated** (exact, reflects the Modelfile `num_ctx` default and what fit in memory), while `POST /api/show` exposes the Modelfile's `num_ctx` default _and_ the model's **native GGUF maximum** in `model_info["<architecture>.context_length"]` — the official API examples show a model with a 131072-token native max whose running instance allocated 4096, a 32× gap. `getContextLength()` consults them in precedence order and returns every signal it found:
|
|
362
|
+
Guessing context windows ("it's probably 2048… or 4096?") is how silent truncation happens — worse, current daemons tier the unset-`num_ctx` default by VRAM (4k / 32k / 256k), so a hardcoded guess is now wrong in both directions. Ollama advertises the real numbers in two places, and they answer _different questions_: `GET /api/ps` reports the window the **running instance actually allocated** (exact, reflects the Modelfile `num_ctx` default and what fit in memory), while `POST /api/show` exposes the Modelfile's `num_ctx` default _and_ the model's **native GGUF maximum** in `model_info["<architecture>.context_length"]` — the official API examples show a model with a 131072-token native max whose running instance allocated 4096, a 32× gap. `getContextLength()` consults them in precedence order and returns every signal it found:
|
|
363
363
|
|
|
364
364
|
```typescript
|
|
365
365
|
const window = await client.models.getContextLength({ model: 'gemma4' });
|
|
@@ -467,12 +467,12 @@ Dispatch is **affinity-sticky, not round-robin**: when a queued model is already
|
|
|
467
467
|
|
|
468
468
|
The server-side knobs (official FAQ defaults) and the client-side surfaces that map onto them:
|
|
469
469
|
|
|
470
|
-
| Server knob | Default
|
|
471
|
-
| ----------------------------------- |
|
|
472
|
-
| `OLLAMA_NUM_PARALLEL` | 1
|
|
473
|
-
| `OLLAMA_MAX_LOADED_MODELS` | 3× GPUs (3 on CPU)
|
|
474
|
-
| `OLLAMA_MAX_QUEUE` | 512
|
|
475
|
-
| `OLLAMA_CONTEXT_LENGTH` / `num_ctx` |
|
|
470
|
+
| Server knob | Default | Effect | Client-side counterpart |
|
|
471
|
+
| ----------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
472
|
+
| `OLLAMA_NUM_PARALLEL` | 1 | Parallel requests **per loaded model**; required memory scales `NUM_PARALLEL × CONTEXT_LENGTH` (a 4K-context model at 4 parallel allocates a 16K KV cache) | `ModelAffinityScheduler({ perModelConcurrency })`, `ToolRegistry({ maxConcurrency })` for agent tool dispatch |
|
|
473
|
+
| `OLLAMA_MAX_LOADED_MODELS` | 3× GPUs (3 on CPU) | Concurrently loaded models; beyond it, requests queue until a model goes idle or is evicted — the swap/thrash cycle | `ModelAffinityScheduler({ concurrentModels })` — keep the working set small; `client.models.pin()`/`unload()` for explicit lifecycle |
|
|
474
|
+
| `OLLAMA_MAX_QUEUE` | 512 | Queued requests beyond this are rejected immediately with **503** | `endpointHealth.maxConcurrentPerEndpoint` (queue client-side instead of saturating the daemon), `embedBatch({ batchSize, concurrency })` for ingestion, retry/failover on 503 |
|
|
475
|
+
| `OLLAMA_CONTEXT_LENGTH` / `num_ctx` | VRAM-tiered: 4k / 32k / 256k | The window per request — prompts beyond it are **silently truncated** | `models.getContextLength()` for the real number, `defaultContextLength` to make it explicit, pre-flight warnings + `session.compact()` to stay inside it |
|
|
476
476
|
|
|
477
477
|
The two failure modes this table prevents: `Promise.all`-style floods (hundreds of simultaneous requests → queue saturation → 503s, VRAM spikes) and model ping-pong (alternating models → repeated unload/reload stalls). The SDK's request path already caps and queues per endpoint via `endpointHealth` — including `strategy: 'least-connections'` for pools — and `embedBatch`/`ModelAffinityScheduler` extend that discipline to ingestion and multi-model workloads. `OLLAMA_KV_CACHE_TYPE` (`f16`/`q8_0`/`q4_0`) trades KV precision for memory headroom at the daemon level; benchmark its latency impact against these client-side levers before relying on it for throughput.
|
|
478
478
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ah as SseEvent, z as OllamaClientError } from './runtime-
|
|
1
|
+
import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ah as SseEvent, z as OllamaClientError } from './runtime-CjCriL5A.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ah as SseEvent, z as OllamaClientError } from './runtime-
|
|
1
|
+
import { O as OllamaRuntime, H as HttpClient, A as AbortableAsyncIterable, ah as SseEvent, z as OllamaClientError } from './runtime-EwyUaNnZ.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
|
package/dist/generated-api.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { O as OpenAIChatCompletionRequest, a as OpenAIChatCompletionResponse, b as OpenAIChatCompletionChunk, c as OpenAICompletionRequest, d as OpenAICompletionResponse, e as OpenAICompletionChunk, f as OpenAIEmbeddingRequest, g as OpenAIEmbeddingResponse, h as OpenAIListModelsResponse, i as OpenAIModelItem, j as OpenAIResponsesRequest, k as OpenAIResponsesResponse, l as OpenAIResponsesStreamEvent, A as AnthropicMessagesRequest, m as AnthropicMessagesResponse, n as AnthropicMessageStreamEvent } from './anthropic-
|
|
2
|
-
export { N as NativeApi } from './anthropic-
|
|
3
|
-
import { O as OllamaRuntime } from './runtime-
|
|
4
|
-
export { a as OperationDefinition } from './runtime-
|
|
1
|
+
import { O as OpenAIChatCompletionRequest, a as OpenAIChatCompletionResponse, b as OpenAIChatCompletionChunk, c as OpenAICompletionRequest, d as OpenAICompletionResponse, e as OpenAICompletionChunk, f as OpenAIEmbeddingRequest, g as OpenAIEmbeddingResponse, h as OpenAIListModelsResponse, i as OpenAIModelItem, j as OpenAIResponsesRequest, k as OpenAIResponsesResponse, l as OpenAIResponsesStreamEvent, A as AnthropicMessagesRequest, m as AnthropicMessagesResponse, n as AnthropicMessageStreamEvent } from './anthropic-Bf16hGLL.cjs';
|
|
2
|
+
export { N as NativeApi } from './anthropic-Bf16hGLL.cjs';
|
|
3
|
+
import { O as OllamaRuntime } from './runtime-CjCriL5A.cjs';
|
|
4
|
+
export { a as OperationDefinition } from './runtime-CjCriL5A.cjs';
|
|
5
5
|
import './types-Y3u0FtdN.cjs';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
package/dist/generated-api.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { O as OpenAIChatCompletionRequest, a as OpenAIChatCompletionResponse, b as OpenAIChatCompletionChunk, c as OpenAICompletionRequest, d as OpenAICompletionResponse, e as OpenAICompletionChunk, f as OpenAIEmbeddingRequest, g as OpenAIEmbeddingResponse, h as OpenAIListModelsResponse, i as OpenAIModelItem, j as OpenAIResponsesRequest, k as OpenAIResponsesResponse, l as OpenAIResponsesStreamEvent, A as AnthropicMessagesRequest, m as AnthropicMessagesResponse, n as AnthropicMessageStreamEvent } from './anthropic-
|
|
2
|
-
export { N as NativeApi } from './anthropic-
|
|
3
|
-
import { O as OllamaRuntime } from './runtime-
|
|
4
|
-
export { a as OperationDefinition } from './runtime-
|
|
1
|
+
import { O as OpenAIChatCompletionRequest, a as OpenAIChatCompletionResponse, b as OpenAIChatCompletionChunk, c as OpenAICompletionRequest, d as OpenAICompletionResponse, e as OpenAICompletionChunk, f as OpenAIEmbeddingRequest, g as OpenAIEmbeddingResponse, h as OpenAIListModelsResponse, i as OpenAIModelItem, j as OpenAIResponsesRequest, k as OpenAIResponsesResponse, l as OpenAIResponsesStreamEvent, A as AnthropicMessagesRequest, m as AnthropicMessagesResponse, n as AnthropicMessageStreamEvent } from './anthropic-BmFk4Pjq.js';
|
|
2
|
+
export { N as NativeApi } from './anthropic-BmFk4Pjq.js';
|
|
3
|
+
import { O as OllamaRuntime } from './runtime-EwyUaNnZ.js';
|
|
4
|
+
export { a as OperationDefinition } from './runtime-EwyUaNnZ.js';
|
|
5
5
|
import './types-Y3u0FtdN.js';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|