@nemesis-oss/ollama-sdk 1.17.0 → 1.19.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 +58 -0
- package/README.md +79 -0
- package/dist/{anthropic-AKbXnWJU.d.cts → anthropic-CAvwqIjx.d.ts} +5 -5
- package/dist/{anthropic-CTv2acbj.d.ts → anthropic-DIPnBwlf.d.cts} +5 -5
- package/dist/{compose-CeFbHJeO.d.ts → compose-75UFDzOO.d.ts} +1 -1
- package/dist/{compose-DFkmtUOP.d.cts → compose-C4QxEZOS.d.cts} +1 -1
- package/dist/generated-api.cjs +5 -3
- package/dist/generated-api.cjs.map +1 -1
- package/dist/generated-api.d.cts +9 -9
- package/dist/generated-api.d.ts +9 -9
- package/dist/generated-api.js +5 -3
- package/dist/generated-api.js.map +1 -1
- package/dist/generated-models-schemas.cjs +2 -2
- package/dist/generated-models-schemas.cjs.map +1 -1
- package/dist/generated-models-schemas.js +2 -2
- package/dist/generated-models-schemas.js.map +1 -1
- package/dist/generated-runtime.cjs +24 -6
- package/dist/generated-runtime.cjs.map +1 -1
- package/dist/generated-runtime.d.cts +2 -2
- package/dist/generated-runtime.d.ts +2 -2
- package/dist/generated-runtime.js +24 -6
- package/dist/generated-runtime.js.map +1 -1
- package/dist/index.cjs +132 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +294 -40
- package/dist/index.d.ts +294 -40
- package/dist/index.js +128 -21
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools.json +8 -10
- package/dist/mcp-generated.cjs +5 -3
- package/dist/mcp-generated.cjs.map +1 -1
- package/dist/mcp-generated.d.cts +2 -2
- package/dist/mcp-generated.d.ts +2 -2
- package/dist/mcp-generated.js +5 -3
- package/dist/mcp-generated.js.map +1 -1
- package/dist/{runtime-CdZP-N7j.d.cts → runtime-C28YEAHC.d.cts} +28 -5
- package/dist/{runtime-CFuv7Ifh.d.ts → runtime-DYCxYGG-.d.ts} +28 -5
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.d.cts +3 -3
- package/dist/skills.d.ts +3 -3
- package/dist/skills.js.map +1 -1
- package/dist/{types-DbPnfVh-.d.cts → types-Y3u0FtdN.d.cts} +10 -0
- package/dist/{types-DbPnfVh-.d.ts → types-Y3u0FtdN.d.ts} +10 -0
- package/package.json +2 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as Message, m as ChatResponse, i as ToolCall, b as ProgressResponse, o as GenerateResponse } from './types-
|
|
1
|
+
import { n as Message, m as ChatResponse, i as ToolCall, b as ProgressResponse, o as GenerateResponse } from './types-Y3u0FtdN.cjs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -140,6 +140,23 @@ declare class OllamaTimeoutError extends OllamaClientError {
|
|
|
140
140
|
declare class OllamaAuthError extends OllamaClientError {
|
|
141
141
|
constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined);
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Thrown for HTTP 402 responses — payment required. Ollama's cloud returns
|
|
145
|
+
* 402 when a cloud model (for example `clef:cloud` through
|
|
146
|
+
* `/v1/systemone`) is not included in the Free plan, when usage credits
|
|
147
|
+
* are needed, or when a payment fails.
|
|
148
|
+
*
|
|
149
|
+
* Distinct from {@link OllamaAuthError} (401/403): the credentials are
|
|
150
|
+
* fine; the billing relationship is the problem. Callers should branch
|
|
151
|
+
* to an upgrade/add-credits flow, not re-prompt for an API key.
|
|
152
|
+
*
|
|
153
|
+
* 2026-10-16 refresh: 402 joined the documented `/v1/systemone` response
|
|
154
|
+
* set with the System One cloud launch; previously it fell through to
|
|
155
|
+
* {@link OllamaGenericClientError}.
|
|
156
|
+
*/
|
|
157
|
+
declare class OllamaPaymentRequiredError extends OllamaClientError {
|
|
158
|
+
constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined);
|
|
159
|
+
}
|
|
143
160
|
declare class OllamaNotFoundError extends OllamaClientError {
|
|
144
161
|
constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined);
|
|
145
162
|
}
|
|
@@ -264,9 +281,15 @@ declare class OllamaRequestValidationError extends OllamaClientError {
|
|
|
264
281
|
}
|
|
265
282
|
/**
|
|
266
283
|
* Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the
|
|
267
|
-
* serialized request body exceeds the operation's declared
|
|
268
|
-
*
|
|
269
|
-
*
|
|
284
|
+
* serialized request body exceeds the operation's declared size constraints.
|
|
285
|
+
* The Ollama server returns 413 for such payloads; this client-side check
|
|
286
|
+
* fails fast so the round-trip is avoided.
|
|
287
|
+
*
|
|
288
|
+
* Dual bound (2026-10-16 refresh, matching the upstream clarification):
|
|
289
|
+
* `constraints.maxRequestBytes` bounds the text and schema portion of the
|
|
290
|
+
* body (images excluded), `constraints.maxRequestBytesWithImages` bounds
|
|
291
|
+
* the whole serialized request (images included) — both apply to every
|
|
292
|
+
* request simultaneously.
|
|
270
293
|
*
|
|
271
294
|
* Wave 12 (P0 #5): the IR has carried `maxRequestBytes` for System One
|
|
272
295
|
* (64 KiB) since v1.7.0, but the runtime never enforced it. This closes
|
|
@@ -956,4 +979,4 @@ declare class OllamaRuntime {
|
|
|
956
979
|
private assertOperationAllowed;
|
|
957
980
|
}
|
|
958
981
|
|
|
959
|
-
export {
|
|
982
|
+
export { OllamaPaymentRequiredError as $, type AbortableAsyncIterable as A, type BinaryBody as B, type ChatStreamResult as C, type DoneEvent as D, type ErrorEvent as E, type FetchLike as F, type GenerateStreamResult as G, HttpClient as H, type InvokeRequest as I, type OllamaClientErrorOptions as J, type OllamaErrorRequestContext as K, type Logger as L, type Middleware as M, NANOS_PER_MS as N, OllamaRuntime as O, type ProgressStreamResult as P, type OllamaErrorResponseContext as Q, type RequestLifecycleHook as R, type SchemaRef as S, type TokenUsage as T, OllamaGenericClientError as U, OllamaIncompatibleModelError as V, OllamaMcpError as W, OllamaModelRoutingError as X, OllamaNetworkError as Y, OllamaNotFoundError as Z, OllamaOverloadedError as _, type OperationDefinition as a, OllamaQuotaExceededError as a0, OllamaRateLimitError as a1, OllamaRequestTooLargeError as a2, OllamaRequestValidationError as a3, OllamaResponseValidationError as a4, OllamaServerError as a5, OllamaServerVersionUnknownError as a6, OllamaSkillInvalidError as a7, OllamaSkillNotFoundError as a8, OllamaStreamError as a9, OllamaTimeoutError as aa, OllamaToolTimeoutError as ab, OllamaToolValidationError as ac, OllamaUnsupportedCapabilityError as ad, type RequestContext as ae, type RequestLifecycleEvent as af, type ResponseContext as ag, type SseEvent as ah, type ThinkingEvent as ai, type TokenEvent as aj, type ToolCallEvent as ak, composeMiddleware as al, createConsoleLogger as am, extractUsage as an, isNetworkLevelError as ao, mapError as ap, parseSseStream as aq, type OllamaRuntimeOptions as b, type OllamaStreamEvent as c, type OllamaStreamEventType as d, type RawUsageSource as e, type HttpBody as f, type HttpClientOptions as g, type HttpRequestOptions as h, type LifecycleErrorEvent as i, type LifecycleRetryEvent as j, type LifecycleStartEvent as k, type LifecycleSuccessEvent as l, type LogFn as m, type MessageEvent as n, type MiddlewareContext as o, NANOS_PER_SECOND as p, NETWORK_ERROR_CODES as q, NOOP_LOGGER as r, type NextFunction as s, OllamaAbortError as t, OllamaAgentMaxIterationsError as u, OllamaAgentMaxToolCallsError as v, OllamaAgentToolLoopError as w, OllamaAuthError as x, OllamaBadGatewayError as y, OllamaClientError as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as Message, m as ChatResponse, i as ToolCall, b as ProgressResponse, o as GenerateResponse } from './types-
|
|
1
|
+
import { n as Message, m as ChatResponse, i as ToolCall, b as ProgressResponse, o as GenerateResponse } from './types-Y3u0FtdN.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -140,6 +140,23 @@ declare class OllamaTimeoutError extends OllamaClientError {
|
|
|
140
140
|
declare class OllamaAuthError extends OllamaClientError {
|
|
141
141
|
constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined);
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Thrown for HTTP 402 responses — payment required. Ollama's cloud returns
|
|
145
|
+
* 402 when a cloud model (for example `clef:cloud` through
|
|
146
|
+
* `/v1/systemone`) is not included in the Free plan, when usage credits
|
|
147
|
+
* are needed, or when a payment fails.
|
|
148
|
+
*
|
|
149
|
+
* Distinct from {@link OllamaAuthError} (401/403): the credentials are
|
|
150
|
+
* fine; the billing relationship is the problem. Callers should branch
|
|
151
|
+
* to an upgrade/add-credits flow, not re-prompt for an API key.
|
|
152
|
+
*
|
|
153
|
+
* 2026-10-16 refresh: 402 joined the documented `/v1/systemone` response
|
|
154
|
+
* set with the System One cloud launch; previously it fell through to
|
|
155
|
+
* {@link OllamaGenericClientError}.
|
|
156
|
+
*/
|
|
157
|
+
declare class OllamaPaymentRequiredError extends OllamaClientError {
|
|
158
|
+
constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined);
|
|
159
|
+
}
|
|
143
160
|
declare class OllamaNotFoundError extends OllamaClientError {
|
|
144
161
|
constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined);
|
|
145
162
|
}
|
|
@@ -264,9 +281,15 @@ declare class OllamaRequestValidationError extends OllamaClientError {
|
|
|
264
281
|
}
|
|
265
282
|
/**
|
|
266
283
|
* Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the
|
|
267
|
-
* serialized request body exceeds the operation's declared
|
|
268
|
-
*
|
|
269
|
-
*
|
|
284
|
+
* serialized request body exceeds the operation's declared size constraints.
|
|
285
|
+
* The Ollama server returns 413 for such payloads; this client-side check
|
|
286
|
+
* fails fast so the round-trip is avoided.
|
|
287
|
+
*
|
|
288
|
+
* Dual bound (2026-10-16 refresh, matching the upstream clarification):
|
|
289
|
+
* `constraints.maxRequestBytes` bounds the text and schema portion of the
|
|
290
|
+
* body (images excluded), `constraints.maxRequestBytesWithImages` bounds
|
|
291
|
+
* the whole serialized request (images included) — both apply to every
|
|
292
|
+
* request simultaneously.
|
|
270
293
|
*
|
|
271
294
|
* Wave 12 (P0 #5): the IR has carried `maxRequestBytes` for System One
|
|
272
295
|
* (64 KiB) since v1.7.0, but the runtime never enforced it. This closes
|
|
@@ -956,4 +979,4 @@ declare class OllamaRuntime {
|
|
|
956
979
|
private assertOperationAllowed;
|
|
957
980
|
}
|
|
958
981
|
|
|
959
|
-
export {
|
|
982
|
+
export { OllamaPaymentRequiredError as $, type AbortableAsyncIterable as A, type BinaryBody as B, type ChatStreamResult as C, type DoneEvent as D, type ErrorEvent as E, type FetchLike as F, type GenerateStreamResult as G, HttpClient as H, type InvokeRequest as I, type OllamaClientErrorOptions as J, type OllamaErrorRequestContext as K, type Logger as L, type Middleware as M, NANOS_PER_MS as N, OllamaRuntime as O, type ProgressStreamResult as P, type OllamaErrorResponseContext as Q, type RequestLifecycleHook as R, type SchemaRef as S, type TokenUsage as T, OllamaGenericClientError as U, OllamaIncompatibleModelError as V, OllamaMcpError as W, OllamaModelRoutingError as X, OllamaNetworkError as Y, OllamaNotFoundError as Z, OllamaOverloadedError as _, type OperationDefinition as a, OllamaQuotaExceededError as a0, OllamaRateLimitError as a1, OllamaRequestTooLargeError as a2, OllamaRequestValidationError as a3, OllamaResponseValidationError as a4, OllamaServerError as a5, OllamaServerVersionUnknownError as a6, OllamaSkillInvalidError as a7, OllamaSkillNotFoundError as a8, OllamaStreamError as a9, OllamaTimeoutError as aa, OllamaToolTimeoutError as ab, OllamaToolValidationError as ac, OllamaUnsupportedCapabilityError as ad, type RequestContext as ae, type RequestLifecycleEvent as af, type ResponseContext as ag, type SseEvent as ah, type ThinkingEvent as ai, type TokenEvent as aj, type ToolCallEvent as ak, composeMiddleware as al, createConsoleLogger as am, extractUsage as an, isNetworkLevelError as ao, mapError as ap, parseSseStream as aq, type OllamaRuntimeOptions as b, type OllamaStreamEvent as c, type OllamaStreamEventType as d, type RawUsageSource as e, type HttpBody as f, type HttpClientOptions as g, type HttpRequestOptions as h, type LifecycleErrorEvent as i, type LifecycleRetryEvent as j, type LifecycleStartEvent as k, type LifecycleSuccessEvent as l, type LogFn as m, type MessageEvent as n, type MiddlewareContext as o, NANOS_PER_SECOND as p, NETWORK_ERROR_CODES as q, NOOP_LOGGER as r, type NextFunction as s, OllamaAbortError as t, OllamaAgentMaxIterationsError as u, OllamaAgentMaxToolCallsError as v, OllamaAgentToolLoopError as w, OllamaAuthError as x, OllamaBadGatewayError as y, OllamaClientError as z };
|
package/dist/skills.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/skills/frontmatter.ts","../src/skills/compose.ts","../src/skills/skill-registry.ts"],"names":["readdir","join","readFile"],"mappings":"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","file":"skills.cjs","sourcesContent":["/**\n * Structured, typed error hierarchy for OllamaClient.\n */\n\nimport type { z } from 'zod';\n\nexport interface OllamaErrorRequestContext {\n readonly method?: string | undefined;\n readonly url?: string | undefined;\n readonly model?: string | undefined;\n}\n\nexport interface OllamaErrorResponseContext {\n readonly status?: number | undefined;\n readonly headers?: Record<string, string> | undefined;\n readonly body?: unknown;\n}\n\nexport interface OllamaClientErrorOptions extends ErrorOptions {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable?: boolean | undefined;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n}\n\nexport class OllamaClientError extends Error {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable: boolean;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n\n constructor(message: string, options: OllamaClientErrorOptions) {\n super(message, { cause: options.cause });\n this.name = this.constructor.name;\n this.code = options.code;\n this.status = options.status;\n this.retryable = options.retryable ?? false;\n this.request = options.request;\n this.response = options.response;\n }\n}\n\nexport class OllamaNetworkError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'network_error', retryable: true });\n }\n}\n\nexport class OllamaTimeoutError extends OllamaClientError {\n readonly timeoutMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { timeoutMs?: number | undefined })\n | undefined,\n ) {\n super(message, { ...options, code: 'timeout', retryable: true });\n this.timeoutMs = options?.timeoutMs;\n }\n}\n\nexport class OllamaAuthError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'auth_error', retryable: false });\n }\n}\n\nexport class OllamaNotFoundError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'not_found', retryable: false });\n }\n}\n\nexport class OllamaRateLimitError extends OllamaClientError {\n readonly retryAfterMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n retryAfterMs?: number | undefined;\n })\n | undefined,\n ) {\n super(message, { ...options, code: 'rate_limited', retryable: true });\n this.retryAfterMs = options?.retryAfterMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, by `QuotaManager.assertCanProceed`\n * (see `src/quota.ts`) when issuing the request would exceed a configured usage budget for\n * one of its rolling windows. This is distinct from `OllamaRateLimitError`, which reflects\n * the server's own 429 response — Ollama Cloud does not expose account-level quota via the\n * API, so `QuotaManager` tracks usage against budgets the caller configures locally and\n * fails fast rather than waiting for the server to reject the request.\n */\nexport class OllamaQuotaExceededError extends OllamaClientError {\n readonly windowId: string;\n readonly resetAt: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n windowId: string;\n resetAt: number;\n },\n ) {\n super(message, { ...options, code: 'quota_exceeded', retryable: false });\n this.windowId = options.windowId;\n this.resetAt = options.resetAt;\n }\n}\n\nexport class OllamaServerError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'server_error', retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **503 Service Unavailable**,\n * indicating that the request queue is saturated (`OLLAMA_MAX_QUEUE`\n * exceeded, default 512 — see the FAQ).\n *\n * Semantically a specialization of {@link OllamaServerError} (503 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'overloaded'` —\n * `OllamaServerError`'s constructor unconditionally forces\n * `code: 'server_error'`. Callers wanting to catch any 5xx should\n * use `error.status >= 500 && error.status < 600` OR explicitly\n * list both `OllamaServerError` and `OllamaOverloadedError`/\n * `OllamaBadGatewayError` in their `instanceof` checks.\n *\n * `retryable` is `true` because the queue will eventually drain;\n * callers using {@link withRetry} will get automatic backoff.\n */\nexport class OllamaOverloadedError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'overloaded', status: 503, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **502 Bad Gateway**,\n * indicating that a cloud model could not be reached by the\n * Ollama Cloud proxy. The model may be temporarily down, the\n * cloud provider may be experiencing an outage, or the model\n * may have been deprovisioned.\n *\n * Semantically a specialization of {@link OllamaServerError} (502 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'bad_gateway'` —\n * see {@link OllamaOverloadedError} for the rationale. Callers wanting\n * to catch any 5xx should use `error.status >= 500 && error.status < 600`\n * OR explicitly list both classes in their `instanceof` checks.\n *\n * `retryable` is `true` for transient cloud-provider outages.\n */\nexport class OllamaBadGatewayError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'bad_gateway', status: 502, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server emits an in-band error frame inside\n * an NDJSON stream (chat / generate / pull / push / create).\n *\n * Ollama streams start with HTTP 200 OK and chunked transfer encoding.\n * If an error occurs mid-generation (GPU OOM, driver crash, context\n * window overflow, model unload race, etc.), the server emits a final\n * JSON chunk of the form `{\"error\": \"...\"}` and closes the stream.\n * The HTTP status code never changes from 200, so HTTP-status-based\n * error detection misses these errors entirely — they would silently\n * bleed into the assistant's content stream as garbage tokens or\n * undefined-field accesses.\n *\n * `partialContent` carries whatever was accumulated before the error\n * frame, so callers can log/diagnose what the model produced before\n * failing. For chat streams this is the concatenated `message.content`;\n * for generate streams it's the concatenated `response`; for pull/push\n * streams it's empty (progress events don't accumulate content).\n *\n * See: https://github.com/ollama/ollama/blob/main/docs/api.md\n */\nexport class OllamaStreamError extends OllamaClientError {\n /** Content accumulated before the in-band error frame, or '' if none. */\n readonly partialContent: string;\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n partialContent?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'stream_error', retryable: false });\n this.partialContent = options?.partialContent ?? '';\n }\n}\n\nexport class OllamaAbortError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'aborted', retryable: false });\n }\n}\n\nexport class OllamaToolValidationError extends OllamaClientError {\n readonly toolName: string;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { toolName: string; issues?: unknown },\n ) {\n super(message, { ...options, code: 'tool_validation_error', retryable: false });\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` when `validateRequests: true` is set and\n * the request body fails Zod validation against the operation's registered\n * schema. See ADR 0020 (runtime Zod validation).\n *\n * The error carries the original Zod issues so callers can inspect which\n * fields failed. No HTTP request is made when this error is thrown.\n */\nexport class OllamaRequestValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'request_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * serialized request body exceeds the operation's declared\n * `constraints.maxRequestBytes`. The Ollama server returns 413 for such\n * payloads; this client-side check fails fast so the round-trip is avoided.\n *\n * Wave 12 (P0 #5): the IR has carried `maxRequestBytes` for System One\n * (64 KiB) since v1.7.0, but the runtime never enforced it. This closes\n * that contract/runtime gap.\n */\nexport class OllamaRequestTooLargeError extends OllamaClientError {\n readonly operationId: string;\n readonly actualBytes: number;\n readonly maxBytes: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> & {\n operationId: string;\n actualBytes: number;\n maxBytes: number;\n },\n ) {\n super(message, { ...options, code: 'request_too_large', retryable: false, status: 413 });\n this.operationId = options.operationId;\n this.actualBytes = options.actualBytes;\n this.maxBytes = options.maxBytes;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` AFTER the HTTP response is received\n * when `validateResponses: true` is set and the response body fails Zod\n * validation against the operation's registered response schema.\n *\n * Wave 13: the runtime previously never validated responses (see ADR\n * 0020). This opt-in error gives callers a way to detect wire-format\n * mismatches for operations where typed response semantics are critical\n * (e.g. System One). The error carries the original Zod issues so\n * callers can inspect which fields failed.\n */\nexport class OllamaResponseValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'response_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * operation declares `constraints.minOllamaVersion` and the runtime could\n * not obtain a server version to compare against (e.g. `enforceVersion:\n * 'strict'` was set and `/api/version` was unreachable). Distinct from\n * {@link OllamaGenericClientError} so callers can branch on the failure\n * mode rather than parsing the message.\n */\nexport class OllamaServerVersionUnknownError extends OllamaClientError {\n readonly operationId: string;\n readonly minRequiredVersion: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n minRequiredVersion: string;\n },\n ) {\n super(message, { ...options, code: 'server_version_unknown', retryable: false });\n this.operationId = options.operationId;\n this.minRequiredVersion = options.minRequiredVersion;\n }\n}\n\nexport class OllamaToolTimeoutError extends OllamaClientError {\n readonly toolName: string;\n readonly timeoutMs: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n toolName: string;\n timeoutMs: number;\n },\n ) {\n super(message, { ...options, code: 'tool_timeout', retryable: false });\n this.toolName = options.toolName;\n this.timeoutMs = options.timeoutMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, when a request asks for a\n * capability an endpoint is known not to support (e.g. structured output `format` against\n * an Ollama Cloud endpoint — see `ModelCapabilities.supportsStructuredOutputRequest` in\n * `src/capabilities/capabilities.ts`). Its `code` is included in `DEFAULT_FAILOVER_CODES`\n * by default, so in a multi-endpoint setup it causes failover to the next candidate rather\n * than failing outright — it only surfaces to the caller if every candidate is rejected.\n */\nexport class OllamaUnsupportedCapabilityError extends OllamaClientError {\n readonly capability: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { capability: string },\n ) {\n super(message, { ...options, code: 'unsupported_capability', retryable: false });\n this.capability = options.capability;\n }\n}\n\n/**\n * Thrown client-side, before any network call, when `config.endpoints` uses\n * `OllamaEndpoint.models` to scope endpoints/credentials to specific models and the\n * requested `model` isn't in any configured endpoint's allow-list. This is a routing\n * misconfiguration, not a connectivity problem — the SDK deliberately does not \"probe\"\n * unauthorized endpoints to find one that happens to work (that would burn quota on keys\n * that were never entitled to the model and produce non-deterministic startup behavior).\n */\nexport class OllamaModelRoutingError extends OllamaClientError {\n readonly model: string;\n readonly availableModels: readonly string[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n availableModels: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'model_routing_error', retryable: false });\n this.model = options.model;\n this.availableModels = options.availableModels;\n }\n}\n\n/**\n * Thrown before an agent tool loop starts when the selected model's /api/show metadata\n * does not advertise a capability required by the loop.\n */\nexport class OllamaIncompatibleModelError extends OllamaClientError {\n readonly model: string;\n readonly capability: string;\n readonly reportedCapabilities: readonly string[];\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n capability: string;\n reportedCapabilities: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'incompatible_model', retryable: false });\n this.model = options.model;\n this.capability = options.capability;\n this.reportedCapabilities = options.reportedCapabilities;\n }\n}\nexport class OllamaAgentMaxToolCallsError extends OllamaClientError {\n readonly maxToolCalls: number;\n readonly toolCallsExecuted: number;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n maxToolCalls: number;\n toolCallsExecuted: number;\n },\n ) {\n super(message, { ...options, code: 'agent_max_tool_calls_exceeded', retryable: false });\n this.maxToolCalls = options.maxToolCalls;\n this.toolCallsExecuted = options.toolCallsExecuted;\n }\n}\n\nexport class OllamaAgentMaxIterationsError extends OllamaClientError {\n readonly maxIterations: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { maxIterations: number },\n ) {\n super(message, { ...options, code: 'agent_max_iterations_exceeded', retryable: false });\n this.maxIterations = options.maxIterations;\n }\n}\n\n/**\n * Thrown when the agent's cycle detection fires: the same tool call —\n * identical name **and** identical arguments — would execute more times than\n * `maxRepeatedToolCalls` allows during one run.\n *\n * This is the fail-fast diagnosis for a model stuck in a tool loop (repeatedly\n * calling the same function with the same arguments, never reacting to the\n * results); without it, a looping model only surfaces as a generic\n * {@link OllamaAgentMaxIterationsError} after burning the full iteration\n * budget on wasted calls.\n */\nexport class OllamaAgentToolLoopError extends OllamaClientError {\n /** Name of the tool whose identical call would exceed the repeat budget. */\n readonly toolName: string;\n /** How many times this exact call would have executed including the rejected one. */\n readonly repeatedExecutions: number;\n /** The configured per-signature execution budget. */\n readonly maxRepeatedToolCalls: number;\n /** Canonical `name(args)` signature of the repeated call (very large payloads truncated). */\n readonly signature: string;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n toolName: string;\n repeatedExecutions: number;\n maxRepeatedToolCalls: number;\n signature: string;\n },\n ) {\n super(message, { ...options, code: 'agent_tool_loop_detected', retryable: false });\n this.toolName = options.toolName;\n this.repeatedExecutions = options.repeatedExecutions;\n this.maxRepeatedToolCalls = options.maxRepeatedToolCalls;\n this.signature = options.signature;\n }\n}\n\nexport class OllamaMcpError extends OllamaClientError {\n readonly mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n readonly toolName?: string | undefined;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n toolName?: string | undefined;\n issues?: unknown;\n },\n ) {\n super(message, { ...options, code: 'mcp_error', retryable: options.retryable ?? false });\n this.mcpMethod = options.mcpMethod;\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\nexport class OllamaSkillNotFoundError extends OllamaClientError {\n readonly skillName: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { skillName: string },\n ) {\n super(message, { ...options, code: 'skill_not_found', retryable: false });\n this.skillName = options.skillName;\n }\n}\n\nexport class OllamaSkillInvalidError extends OllamaClientError {\n readonly skillName: string;\n readonly path?: string | undefined;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n skillName: string;\n path?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'skill_invalid', retryable: false });\n this.skillName = options.skillName;\n this.path = options.path;\n }\n}\n\nexport class OllamaGenericClientError extends OllamaClientError {\n constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code'> | undefined) {\n super(message, { ...options, code: 'client_error' });\n }\n}\n\nfunction isDomAbortError(error: unknown): error is DOMException {\n return (\n typeof DOMException !== 'undefined' &&\n error instanceof DOMException &&\n error.name === 'AbortError'\n );\n}\n\n/**\n * Error `code`s that mean the transport never delivered a usable response —\n * the request died at the socket/connection layer. This is the stale-socket\n * family: keep-alive connections recycled by a restarting/idle-timeouting\n * daemon (`ECONNRESET`, `EPIPE`, undici's `UND_ERR_SOCKET`/`UND_ERR_CLOSED`\n * when the pooled socket is reused after the server closed it), connections\n * that never established (`ECONNREFUSED`, `EAI_AGAIN`, `ENOTFOUND`), and\n * connect/header/body timeouts from the undici dispatcher.\n *\n * `UND_ERR_ABORTED` is deliberately NOT here: it is the dispatcher's shape\n * for caller-initiated aborts, which map to `OllamaAbortError` (never\n * retried) — classifying it as a network failure would re-dispatch requests\n * the caller explicitly cancelled.\n */\nexport const NETWORK_ERROR_CODES: ReadonlySet<string> = new Set([\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'ECONNABORTED',\n 'EHOSTUNREACH',\n 'ENETUNREACH',\n 'ENOTFOUND',\n 'EAI_AGAIN',\n 'UND_ERR_SOCKET',\n 'UND_ERR_CONNECT_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_BODY_TIMEOUT',\n 'UND_ERR_CLOSED',\n]);\n\n/** How many `cause` links to walk looking for a network-level `code`. */\nconst MAX_CAUSE_DEPTH = 4;\n\n/**\n * Structural network-failure detection: looks for a `code` from\n * {@link NETWORK_ERROR_CODES} on the error itself or anywhere down its\n * `cause` chain (bounded depth — cause cycles must not spin forever).\n *\n * Deliberately does NOT match on message text (`String(err).includes(...)`\n * style): undici/Node message wording is not a stable contract across\n * versions, while `error.code` is. Custom `fetch` implementations built on\n * `node:http` reject with these codes natively (WHATWG `fetch` wraps them in\n * a `TypeError`, which `mapError` already classifies); this predicate closes\n * the gap for the non-`TypeError` shapes.\n */\nexport function isNetworkLevelError(error: unknown): boolean {\n let current: unknown = error;\n for (\n let depth = 0;\n depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null;\n depth += 1\n ) {\n if (typeof current === 'object' && 'code' in current) {\n const code = (current as { code?: unknown }).code;\n if (typeof code === 'string' && NETWORK_ERROR_CODES.has(code)) {\n return true;\n }\n }\n current = (current as { cause?: unknown }).cause;\n }\n return false;\n}\n\nfunction statusToError(\n status: number,\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'status'>,\n): OllamaClientError {\n if (status === 401 || status === 403) {\n return new OllamaAuthError(message, { ...options, status });\n }\n if (status === 404) {\n return new OllamaNotFoundError(message, { ...options, status });\n }\n if (status === 429) {\n return new OllamaRateLimitError(message, { ...options, status });\n }\n if (status === 502) {\n // Cloud model could not be reached. Distinct from generic 5xx so\n // callers running multi-model agents can branch on cloud-provider\n // failures specifically (fail over to a different model/endpoint\n // rather than blindly retrying the same one).\n return new OllamaBadGatewayError(message, { ...options });\n }\n if (status === 503) {\n // Queue saturation (OLLAMA_MAX_QUEUE exceeded). Retryable — the\n // queue will eventually drain. Distinct from generic 5xx so\n // callers running parallel swarms can branch on saturation.\n return new OllamaOverloadedError(message, { ...options });\n }\n if (status >= 500) {\n return new OllamaServerError(message, { ...options, status });\n }\n return new OllamaGenericClientError(message, { ...options, status });\n}\n\n/**\n * Maps arbitrary thrown exceptions into structured OllamaClientError instances.\n */\nexport function mapError(\n error: unknown,\n context: {\n request?: OllamaErrorRequestContext | undefined;\n response?: OllamaErrorResponseContext | undefined;\n } = {},\n): OllamaClientError {\n if (error instanceof OllamaClientError) {\n return error;\n }\n if (isDomAbortError(error)) {\n return new OllamaAbortError(error.message || 'Request was aborted', {\n cause: error,\n request: context.request,\n });\n }\n // Socket/connection-level failures — including the non-TypeError shapes a\n // custom `fetch` implementation produces (`Error` + `code: 'ECONNRESET'`\n // and friends) and network codes nested in `cause` chains. Checked before\n // the `TypeError` branch so a code-carrying TypeError maps through the same\n // specialized construction with a better message. Retryable + failover-eligible.\n if (isNetworkLevelError(error)) {\n const message =\n error instanceof Error && error.message ? error.message : 'Network request failed';\n return new OllamaNetworkError(message, {\n cause: error,\n request: context.request,\n });\n }\n if (error instanceof TypeError) {\n return new OllamaNetworkError(error.message || 'Network request failed', {\n cause: error,\n request: context.request,\n });\n }\n if (context.response?.status !== undefined) {\n const message = error instanceof Error ? error.message : String(error);\n return statusToError(context.response.status, message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new OllamaGenericClientError(message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n}\n","/**\n * Lightweight frontmatter parser for SKILL.md files.\n */\n\nimport { OllamaSkillInvalidError } from '../errors.js';\nimport type { SkillFrontmatter } from './types.js';\n\nexport interface ParsedFrontmatter {\n readonly frontmatter: SkillFrontmatter;\n readonly body: string;\n}\n\nfunction parseYamlValue(raw: string): unknown {\n const trimmed = raw.trim();\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n if (!Number.isNaN(Number(trimmed)) && trimmed !== '') return Number(trimmed);\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\nfunction parseYamlBlock(yamlText: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = yamlText.split('\\n');\n let currentKey: string | undefined;\n let currentList: unknown[] | undefined;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n if (trimmed.startsWith('- ') && currentKey) {\n if (!currentList) {\n currentList = [];\n result[currentKey] = currentList;\n }\n currentList.push(parseYamlValue(trimmed.slice(2)));\n continue;\n }\n\n currentList = undefined;\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim();\n const valStr = line.slice(colonIndex + 1).trim();\n currentKey = key;\n if (valStr.length > 0) {\n result[key] = parseYamlValue(valStr);\n }\n }\n }\n\n return result;\n}\n\nexport function parseFrontmatter(source: string, path = ''): ParsedFrontmatter {\n const match = source.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n if (!match) {\n throw new OllamaSkillInvalidError('Missing YAML frontmatter delimiters (---)', {\n skillName: path || 'unknown',\n path,\n });\n }\n\n const rawYaml = match[1] ?? '';\n const body = match[2]?.trim() ?? '';\n const parsed = parseYamlBlock(rawYaml);\n\n if (!parsed['name'] || typeof parsed['name'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"name\"', {\n skillName: String(parsed['name'] ?? 'unknown'),\n path,\n });\n }\n if (!parsed['description'] || typeof parsed['description'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"description\"', {\n skillName: parsed['name'],\n path,\n });\n }\n\n return {\n frontmatter: parsed as unknown as SkillFrontmatter,\n body,\n };\n}\n","/**\n * Skill composition and context injection.\n */\n\nimport type { Message } from '../types.js';\nimport type { ToolRegistry } from '../tools/registry.js';\nimport type { Skill } from './types.js';\n\nexport interface ApplySkillOptions {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\nexport interface AppliedSkillResult {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\n/**\n * Injects a skill's body into messages as a system prompt and applies allowed tool filters.\n */\nexport function applySkill(skill: Skill, options: ApplySkillOptions): AppliedSkillResult {\n const systemPrompt = `[Skill: ${skill.name}]\\n${skill.description}\\n\\n${skill.body}`;\n const messages = [...options.messages];\n const systemIndex = messages.findIndex((m) => m.role === 'system');\n\n if (systemIndex >= 0) {\n const existing = messages[systemIndex];\n if (existing) {\n messages[systemIndex] = {\n role: 'system',\n content: `${existing.content}\\n\\n${systemPrompt}`,\n };\n }\n } else {\n messages.unshift({ role: 'system', content: systemPrompt });\n }\n\n return {\n messages,\n ...(options.tools !== undefined ? { tools: options.tools } : {}),\n };\n}\n","/**\n * Node.js filesystem skill registry for SKILL.md packages.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { OllamaSkillNotFoundError } from '../errors.js';\nimport { parseFrontmatter } from './frontmatter.js';\nimport type { Skill, SkillSummary } from './types.js';\n\nexport interface SkillRegistryOptions {\n readonly directory: string;\n}\n\nexport class SkillRegistry {\n readonly directory: string;\n\n constructor(options: SkillRegistryOptions) {\n this.directory = options.directory;\n }\n\n async list(): Promise<SkillSummary[]> {\n const entries = await readdir(this.directory, { withFileTypes: true });\n const summaries: SkillSummary[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillPath = join(this.directory, entry.name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n summaries.push({\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n });\n } catch {\n // Skip directories without valid SKILL.md\n }\n }\n\n return summaries;\n }\n\n async load(name: string): Promise<Skill> {\n const skillPath = join(this.directory, name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n return {\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n frontmatter: parsed.frontmatter,\n body: parsed.body,\n allowedTools: parsed.frontmatter['allowed-tools'],\n };\n } catch (err) {\n throw new OllamaSkillNotFoundError(`Skill \"${name}\" not found at ${skillPath}`, {\n skillName: name,\n cause: err,\n });\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/skills/frontmatter.ts","../src/skills/compose.ts","../src/skills/skill-registry.ts"],"names":["readdir","join","readFile"],"mappings":"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","file":"skills.cjs","sourcesContent":["/**\n * Structured, typed error hierarchy for OllamaClient.\n */\n\nimport type { z } from 'zod';\n\nexport interface OllamaErrorRequestContext {\n readonly method?: string | undefined;\n readonly url?: string | undefined;\n readonly model?: string | undefined;\n}\n\nexport interface OllamaErrorResponseContext {\n readonly status?: number | undefined;\n readonly headers?: Record<string, string> | undefined;\n readonly body?: unknown;\n}\n\nexport interface OllamaClientErrorOptions extends ErrorOptions {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable?: boolean | undefined;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n}\n\nexport class OllamaClientError extends Error {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable: boolean;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n\n constructor(message: string, options: OllamaClientErrorOptions) {\n super(message, { cause: options.cause });\n this.name = this.constructor.name;\n this.code = options.code;\n this.status = options.status;\n this.retryable = options.retryable ?? false;\n this.request = options.request;\n this.response = options.response;\n }\n}\n\nexport class OllamaNetworkError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'network_error', retryable: true });\n }\n}\n\nexport class OllamaTimeoutError extends OllamaClientError {\n readonly timeoutMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { timeoutMs?: number | undefined })\n | undefined,\n ) {\n super(message, { ...options, code: 'timeout', retryable: true });\n this.timeoutMs = options?.timeoutMs;\n }\n}\n\nexport class OllamaAuthError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'auth_error', retryable: false });\n }\n}\n\n/**\n * Thrown for HTTP 402 responses — payment required. Ollama's cloud returns\n * 402 when a cloud model (for example `clef:cloud` through\n * `/v1/systemone`) is not included in the Free plan, when usage credits\n * are needed, or when a payment fails.\n *\n * Distinct from {@link OllamaAuthError} (401/403): the credentials are\n * fine; the billing relationship is the problem. Callers should branch\n * to an upgrade/add-credits flow, not re-prompt for an API key.\n *\n * 2026-10-16 refresh: 402 joined the documented `/v1/systemone` response\n * set with the System One cloud launch; previously it fell through to\n * {@link OllamaGenericClientError}.\n */\nexport class OllamaPaymentRequiredError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'payment_required', retryable: false, status: 402 });\n }\n}\n\nexport class OllamaNotFoundError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'not_found', retryable: false });\n }\n}\n\nexport class OllamaRateLimitError extends OllamaClientError {\n readonly retryAfterMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n retryAfterMs?: number | undefined;\n })\n | undefined,\n ) {\n super(message, { ...options, code: 'rate_limited', retryable: true });\n this.retryAfterMs = options?.retryAfterMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, by `QuotaManager.assertCanProceed`\n * (see `src/quota.ts`) when issuing the request would exceed a configured usage budget for\n * one of its rolling windows. This is distinct from `OllamaRateLimitError`, which reflects\n * the server's own 429 response — Ollama Cloud does not expose account-level quota via the\n * API, so `QuotaManager` tracks usage against budgets the caller configures locally and\n * fails fast rather than waiting for the server to reject the request.\n */\nexport class OllamaQuotaExceededError extends OllamaClientError {\n readonly windowId: string;\n readonly resetAt: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n windowId: string;\n resetAt: number;\n },\n ) {\n super(message, { ...options, code: 'quota_exceeded', retryable: false });\n this.windowId = options.windowId;\n this.resetAt = options.resetAt;\n }\n}\n\nexport class OllamaServerError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'server_error', retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **503 Service Unavailable**,\n * indicating that the request queue is saturated (`OLLAMA_MAX_QUEUE`\n * exceeded, default 512 — see the FAQ).\n *\n * Semantically a specialization of {@link OllamaServerError} (503 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'overloaded'` —\n * `OllamaServerError`'s constructor unconditionally forces\n * `code: 'server_error'`. Callers wanting to catch any 5xx should\n * use `error.status >= 500 && error.status < 600` OR explicitly\n * list both `OllamaServerError` and `OllamaOverloadedError`/\n * `OllamaBadGatewayError` in their `instanceof` checks.\n *\n * `retryable` is `true` because the queue will eventually drain;\n * callers using {@link withRetry} will get automatic backoff.\n */\nexport class OllamaOverloadedError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'overloaded', status: 503, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **502 Bad Gateway**,\n * indicating that a cloud model could not be reached by the\n * Ollama Cloud proxy. The model may be temporarily down, the\n * cloud provider may be experiencing an outage, or the model\n * may have been deprovisioned.\n *\n * Semantically a specialization of {@link OllamaServerError} (502 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'bad_gateway'` —\n * see {@link OllamaOverloadedError} for the rationale. Callers wanting\n * to catch any 5xx should use `error.status >= 500 && error.status < 600`\n * OR explicitly list both classes in their `instanceof` checks.\n *\n * `retryable` is `true` for transient cloud-provider outages.\n */\nexport class OllamaBadGatewayError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'bad_gateway', status: 502, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server emits an in-band error frame inside\n * an NDJSON stream (chat / generate / pull / push / create).\n *\n * Ollama streams start with HTTP 200 OK and chunked transfer encoding.\n * If an error occurs mid-generation (GPU OOM, driver crash, context\n * window overflow, model unload race, etc.), the server emits a final\n * JSON chunk of the form `{\"error\": \"...\"}` and closes the stream.\n * The HTTP status code never changes from 200, so HTTP-status-based\n * error detection misses these errors entirely — they would silently\n * bleed into the assistant's content stream as garbage tokens or\n * undefined-field accesses.\n *\n * `partialContent` carries whatever was accumulated before the error\n * frame, so callers can log/diagnose what the model produced before\n * failing. For chat streams this is the concatenated `message.content`;\n * for generate streams it's the concatenated `response`; for pull/push\n * streams it's empty (progress events don't accumulate content).\n *\n * See: https://github.com/ollama/ollama/blob/main/docs/api.md\n */\nexport class OllamaStreamError extends OllamaClientError {\n /** Content accumulated before the in-band error frame, or '' if none. */\n readonly partialContent: string;\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n partialContent?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'stream_error', retryable: false });\n this.partialContent = options?.partialContent ?? '';\n }\n}\n\nexport class OllamaAbortError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'aborted', retryable: false });\n }\n}\n\nexport class OllamaToolValidationError extends OllamaClientError {\n readonly toolName: string;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { toolName: string; issues?: unknown },\n ) {\n super(message, { ...options, code: 'tool_validation_error', retryable: false });\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` when `validateRequests: true` is set and\n * the request body fails Zod validation against the operation's registered\n * schema. See ADR 0020 (runtime Zod validation).\n *\n * The error carries the original Zod issues so callers can inspect which\n * fields failed. No HTTP request is made when this error is thrown.\n */\nexport class OllamaRequestValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'request_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * serialized request body exceeds the operation's declared size constraints.\n * The Ollama server returns 413 for such payloads; this client-side check\n * fails fast so the round-trip is avoided.\n *\n * Dual bound (2026-10-16 refresh, matching the upstream clarification):\n * `constraints.maxRequestBytes` bounds the text and schema portion of the\n * body (images excluded), `constraints.maxRequestBytesWithImages` bounds\n * the whole serialized request (images included) — both apply to every\n * request simultaneously.\n *\n * Wave 12 (P0 #5): the IR has carried `maxRequestBytes` for System One\n * (64 KiB) since v1.7.0, but the runtime never enforced it. This closes\n * that contract/runtime gap.\n */\nexport class OllamaRequestTooLargeError extends OllamaClientError {\n readonly operationId: string;\n readonly actualBytes: number;\n readonly maxBytes: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> & {\n operationId: string;\n actualBytes: number;\n maxBytes: number;\n },\n ) {\n super(message, { ...options, code: 'request_too_large', retryable: false, status: 413 });\n this.operationId = options.operationId;\n this.actualBytes = options.actualBytes;\n this.maxBytes = options.maxBytes;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` AFTER the HTTP response is received\n * when `validateResponses: true` is set and the response body fails Zod\n * validation against the operation's registered response schema.\n *\n * Wave 13: the runtime previously never validated responses (see ADR\n * 0020). This opt-in error gives callers a way to detect wire-format\n * mismatches for operations where typed response semantics are critical\n * (e.g. System One). The error carries the original Zod issues so\n * callers can inspect which fields failed.\n */\nexport class OllamaResponseValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'response_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * operation declares `constraints.minOllamaVersion` and the runtime could\n * not obtain a server version to compare against (e.g. `enforceVersion:\n * 'strict'` was set and `/api/version` was unreachable). Distinct from\n * {@link OllamaGenericClientError} so callers can branch on the failure\n * mode rather than parsing the message.\n */\nexport class OllamaServerVersionUnknownError extends OllamaClientError {\n readonly operationId: string;\n readonly minRequiredVersion: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n minRequiredVersion: string;\n },\n ) {\n super(message, { ...options, code: 'server_version_unknown', retryable: false });\n this.operationId = options.operationId;\n this.minRequiredVersion = options.minRequiredVersion;\n }\n}\n\nexport class OllamaToolTimeoutError extends OllamaClientError {\n readonly toolName: string;\n readonly timeoutMs: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n toolName: string;\n timeoutMs: number;\n },\n ) {\n super(message, { ...options, code: 'tool_timeout', retryable: false });\n this.toolName = options.toolName;\n this.timeoutMs = options.timeoutMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, when a request asks for a\n * capability an endpoint is known not to support (e.g. structured output `format` against\n * an Ollama Cloud endpoint — see `ModelCapabilities.supportsStructuredOutputRequest` in\n * `src/capabilities/capabilities.ts`). Its `code` is included in `DEFAULT_FAILOVER_CODES`\n * by default, so in a multi-endpoint setup it causes failover to the next candidate rather\n * than failing outright — it only surfaces to the caller if every candidate is rejected.\n */\nexport class OllamaUnsupportedCapabilityError extends OllamaClientError {\n readonly capability: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { capability: string },\n ) {\n super(message, { ...options, code: 'unsupported_capability', retryable: false });\n this.capability = options.capability;\n }\n}\n\n/**\n * Thrown client-side, before any network call, when `config.endpoints` uses\n * `OllamaEndpoint.models` to scope endpoints/credentials to specific models and the\n * requested `model` isn't in any configured endpoint's allow-list. This is a routing\n * misconfiguration, not a connectivity problem — the SDK deliberately does not \"probe\"\n * unauthorized endpoints to find one that happens to work (that would burn quota on keys\n * that were never entitled to the model and produce non-deterministic startup behavior).\n */\nexport class OllamaModelRoutingError extends OllamaClientError {\n readonly model: string;\n readonly availableModels: readonly string[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n availableModels: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'model_routing_error', retryable: false });\n this.model = options.model;\n this.availableModels = options.availableModels;\n }\n}\n\n/**\n * Thrown before an agent tool loop starts when the selected model's /api/show metadata\n * does not advertise a capability required by the loop.\n */\nexport class OllamaIncompatibleModelError extends OllamaClientError {\n readonly model: string;\n readonly capability: string;\n readonly reportedCapabilities: readonly string[];\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n capability: string;\n reportedCapabilities: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'incompatible_model', retryable: false });\n this.model = options.model;\n this.capability = options.capability;\n this.reportedCapabilities = options.reportedCapabilities;\n }\n}\nexport class OllamaAgentMaxToolCallsError extends OllamaClientError {\n readonly maxToolCalls: number;\n readonly toolCallsExecuted: number;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n maxToolCalls: number;\n toolCallsExecuted: number;\n },\n ) {\n super(message, { ...options, code: 'agent_max_tool_calls_exceeded', retryable: false });\n this.maxToolCalls = options.maxToolCalls;\n this.toolCallsExecuted = options.toolCallsExecuted;\n }\n}\n\nexport class OllamaAgentMaxIterationsError extends OllamaClientError {\n readonly maxIterations: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { maxIterations: number },\n ) {\n super(message, { ...options, code: 'agent_max_iterations_exceeded', retryable: false });\n this.maxIterations = options.maxIterations;\n }\n}\n\n/**\n * Thrown when the agent's cycle detection fires: the same tool call —\n * identical name **and** identical arguments — would execute more times than\n * `maxRepeatedToolCalls` allows during one run.\n *\n * This is the fail-fast diagnosis for a model stuck in a tool loop (repeatedly\n * calling the same function with the same arguments, never reacting to the\n * results); without it, a looping model only surfaces as a generic\n * {@link OllamaAgentMaxIterationsError} after burning the full iteration\n * budget on wasted calls.\n */\nexport class OllamaAgentToolLoopError extends OllamaClientError {\n /** Name of the tool whose identical call would exceed the repeat budget. */\n readonly toolName: string;\n /** How many times this exact call would have executed including the rejected one. */\n readonly repeatedExecutions: number;\n /** The configured per-signature execution budget. */\n readonly maxRepeatedToolCalls: number;\n /** Canonical `name(args)` signature of the repeated call (very large payloads truncated). */\n readonly signature: string;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n toolName: string;\n repeatedExecutions: number;\n maxRepeatedToolCalls: number;\n signature: string;\n },\n ) {\n super(message, { ...options, code: 'agent_tool_loop_detected', retryable: false });\n this.toolName = options.toolName;\n this.repeatedExecutions = options.repeatedExecutions;\n this.maxRepeatedToolCalls = options.maxRepeatedToolCalls;\n this.signature = options.signature;\n }\n}\n\nexport class OllamaMcpError extends OllamaClientError {\n readonly mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n readonly toolName?: string | undefined;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n toolName?: string | undefined;\n issues?: unknown;\n },\n ) {\n super(message, { ...options, code: 'mcp_error', retryable: options.retryable ?? false });\n this.mcpMethod = options.mcpMethod;\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\nexport class OllamaSkillNotFoundError extends OllamaClientError {\n readonly skillName: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { skillName: string },\n ) {\n super(message, { ...options, code: 'skill_not_found', retryable: false });\n this.skillName = options.skillName;\n }\n}\n\nexport class OllamaSkillInvalidError extends OllamaClientError {\n readonly skillName: string;\n readonly path?: string | undefined;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n skillName: string;\n path?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'skill_invalid', retryable: false });\n this.skillName = options.skillName;\n this.path = options.path;\n }\n}\n\nexport class OllamaGenericClientError extends OllamaClientError {\n constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code'> | undefined) {\n super(message, { ...options, code: 'client_error' });\n }\n}\n\nfunction isDomAbortError(error: unknown): error is DOMException {\n return (\n typeof DOMException !== 'undefined' &&\n error instanceof DOMException &&\n error.name === 'AbortError'\n );\n}\n\n/**\n * Error `code`s that mean the transport never delivered a usable response —\n * the request died at the socket/connection layer. This is the stale-socket\n * family: keep-alive connections recycled by a restarting/idle-timeouting\n * daemon (`ECONNRESET`, `EPIPE`, undici's `UND_ERR_SOCKET`/`UND_ERR_CLOSED`\n * when the pooled socket is reused after the server closed it), connections\n * that never established (`ECONNREFUSED`, `EAI_AGAIN`, `ENOTFOUND`), and\n * connect/header/body timeouts from the undici dispatcher.\n *\n * `UND_ERR_ABORTED` is deliberately NOT here: it is the dispatcher's shape\n * for caller-initiated aborts, which map to `OllamaAbortError` (never\n * retried) — classifying it as a network failure would re-dispatch requests\n * the caller explicitly cancelled.\n */\nexport const NETWORK_ERROR_CODES: ReadonlySet<string> = new Set([\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'ECONNABORTED',\n 'EHOSTUNREACH',\n 'ENETUNREACH',\n 'ENOTFOUND',\n 'EAI_AGAIN',\n 'UND_ERR_SOCKET',\n 'UND_ERR_CONNECT_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_BODY_TIMEOUT',\n 'UND_ERR_CLOSED',\n]);\n\n/** How many `cause` links to walk looking for a network-level `code`. */\nconst MAX_CAUSE_DEPTH = 4;\n\n/**\n * Structural network-failure detection: looks for a `code` from\n * {@link NETWORK_ERROR_CODES} on the error itself or anywhere down its\n * `cause` chain (bounded depth — cause cycles must not spin forever).\n *\n * Deliberately does NOT match on message text (`String(err).includes(...)`\n * style): undici/Node message wording is not a stable contract across\n * versions, while `error.code` is. Custom `fetch` implementations built on\n * `node:http` reject with these codes natively (WHATWG `fetch` wraps them in\n * a `TypeError`, which `mapError` already classifies); this predicate closes\n * the gap for the non-`TypeError` shapes.\n */\nexport function isNetworkLevelError(error: unknown): boolean {\n let current: unknown = error;\n for (\n let depth = 0;\n depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null;\n depth += 1\n ) {\n if (typeof current === 'object' && 'code' in current) {\n const code = (current as { code?: unknown }).code;\n if (typeof code === 'string' && NETWORK_ERROR_CODES.has(code)) {\n return true;\n }\n }\n current = (current as { cause?: unknown }).cause;\n }\n return false;\n}\n\nfunction statusToError(\n status: number,\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'status'>,\n): OllamaClientError {\n if (status === 401 || status === 403) {\n return new OllamaAuthError(message, { ...options, status });\n }\n if (status === 402) {\n // Cloud billing, not credentials: the cloud model isn't in the Free\n // plan, credits are needed, or a payment failed (documented on\n // /v1/systemone since the 2026-10-16 System One cloud launch).\n // Distinct from auth failures so callers can branch to an\n // upgrade/credits flow instead of re-prompting for an API key.\n return new OllamaPaymentRequiredError(message, options);\n }\n if (status === 404) {\n return new OllamaNotFoundError(message, { ...options, status });\n }\n if (status === 429) {\n return new OllamaRateLimitError(message, { ...options, status });\n }\n if (status === 502) {\n // Cloud model could not be reached. Distinct from generic 5xx so\n // callers running multi-model agents can branch on cloud-provider\n // failures specifically (fail over to a different model/endpoint\n // rather than blindly retrying the same one).\n return new OllamaBadGatewayError(message, { ...options });\n }\n if (status === 503) {\n // Queue saturation (OLLAMA_MAX_QUEUE exceeded). Retryable — the\n // queue will eventually drain. Distinct from generic 5xx so\n // callers running parallel swarms can branch on saturation.\n return new OllamaOverloadedError(message, { ...options });\n }\n if (status >= 500) {\n return new OllamaServerError(message, { ...options, status });\n }\n return new OllamaGenericClientError(message, { ...options, status });\n}\n\n/**\n * Maps arbitrary thrown exceptions into structured OllamaClientError instances.\n */\nexport function mapError(\n error: unknown,\n context: {\n request?: OllamaErrorRequestContext | undefined;\n response?: OllamaErrorResponseContext | undefined;\n } = {},\n): OllamaClientError {\n if (error instanceof OllamaClientError) {\n return error;\n }\n if (isDomAbortError(error)) {\n return new OllamaAbortError(error.message || 'Request was aborted', {\n cause: error,\n request: context.request,\n });\n }\n // Socket/connection-level failures — including the non-TypeError shapes a\n // custom `fetch` implementation produces (`Error` + `code: 'ECONNRESET'`\n // and friends) and network codes nested in `cause` chains. Checked before\n // the `TypeError` branch so a code-carrying TypeError maps through the same\n // specialized construction with a better message. Retryable + failover-eligible.\n if (isNetworkLevelError(error)) {\n const message =\n error instanceof Error && error.message ? error.message : 'Network request failed';\n return new OllamaNetworkError(message, {\n cause: error,\n request: context.request,\n });\n }\n if (error instanceof TypeError) {\n return new OllamaNetworkError(error.message || 'Network request failed', {\n cause: error,\n request: context.request,\n });\n }\n if (context.response?.status !== undefined) {\n const message = error instanceof Error ? error.message : String(error);\n return statusToError(context.response.status, message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new OllamaGenericClientError(message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n}\n","/**\n * Lightweight frontmatter parser for SKILL.md files.\n */\n\nimport { OllamaSkillInvalidError } from '../errors.js';\nimport type { SkillFrontmatter } from './types.js';\n\nexport interface ParsedFrontmatter {\n readonly frontmatter: SkillFrontmatter;\n readonly body: string;\n}\n\nfunction parseYamlValue(raw: string): unknown {\n const trimmed = raw.trim();\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n if (!Number.isNaN(Number(trimmed)) && trimmed !== '') return Number(trimmed);\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\nfunction parseYamlBlock(yamlText: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = yamlText.split('\\n');\n let currentKey: string | undefined;\n let currentList: unknown[] | undefined;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n if (trimmed.startsWith('- ') && currentKey) {\n if (!currentList) {\n currentList = [];\n result[currentKey] = currentList;\n }\n currentList.push(parseYamlValue(trimmed.slice(2)));\n continue;\n }\n\n currentList = undefined;\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim();\n const valStr = line.slice(colonIndex + 1).trim();\n currentKey = key;\n if (valStr.length > 0) {\n result[key] = parseYamlValue(valStr);\n }\n }\n }\n\n return result;\n}\n\nexport function parseFrontmatter(source: string, path = ''): ParsedFrontmatter {\n const match = source.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n if (!match) {\n throw new OllamaSkillInvalidError('Missing YAML frontmatter delimiters (---)', {\n skillName: path || 'unknown',\n path,\n });\n }\n\n const rawYaml = match[1] ?? '';\n const body = match[2]?.trim() ?? '';\n const parsed = parseYamlBlock(rawYaml);\n\n if (!parsed['name'] || typeof parsed['name'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"name\"', {\n skillName: String(parsed['name'] ?? 'unknown'),\n path,\n });\n }\n if (!parsed['description'] || typeof parsed['description'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"description\"', {\n skillName: parsed['name'],\n path,\n });\n }\n\n return {\n frontmatter: parsed as unknown as SkillFrontmatter,\n body,\n };\n}\n","/**\n * Skill composition and context injection.\n */\n\nimport type { Message } from '../types.js';\nimport type { ToolRegistry } from '../tools/registry.js';\nimport type { Skill } from './types.js';\n\nexport interface ApplySkillOptions {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\nexport interface AppliedSkillResult {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\n/**\n * Injects a skill's body into messages as a system prompt and applies allowed tool filters.\n */\nexport function applySkill(skill: Skill, options: ApplySkillOptions): AppliedSkillResult {\n const systemPrompt = `[Skill: ${skill.name}]\\n${skill.description}\\n\\n${skill.body}`;\n const messages = [...options.messages];\n const systemIndex = messages.findIndex((m) => m.role === 'system');\n\n if (systemIndex >= 0) {\n const existing = messages[systemIndex];\n if (existing) {\n messages[systemIndex] = {\n role: 'system',\n content: `${existing.content}\\n\\n${systemPrompt}`,\n };\n }\n } else {\n messages.unshift({ role: 'system', content: systemPrompt });\n }\n\n return {\n messages,\n ...(options.tools !== undefined ? { tools: options.tools } : {}),\n };\n}\n","/**\n * Node.js filesystem skill registry for SKILL.md packages.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { OllamaSkillNotFoundError } from '../errors.js';\nimport { parseFrontmatter } from './frontmatter.js';\nimport type { Skill, SkillSummary } from './types.js';\n\nexport interface SkillRegistryOptions {\n readonly directory: string;\n}\n\nexport class SkillRegistry {\n readonly directory: string;\n\n constructor(options: SkillRegistryOptions) {\n this.directory = options.directory;\n }\n\n async list(): Promise<SkillSummary[]> {\n const entries = await readdir(this.directory, { withFileTypes: true });\n const summaries: SkillSummary[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillPath = join(this.directory, entry.name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n summaries.push({\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n });\n } catch {\n // Skip directories without valid SKILL.md\n }\n }\n\n return summaries;\n }\n\n async load(name: string): Promise<Skill> {\n const skillPath = join(this.directory, name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n return {\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n frontmatter: parsed.frontmatter,\n body: parsed.body,\n allowedTools: parsed.frontmatter['allowed-tools'],\n };\n } catch (err) {\n throw new OllamaSkillNotFoundError(`Skill \"${name}\" not found at ${skillPath}`, {\n skillName: name,\n cause: err,\n });\n }\n }\n}\n"]}
|
package/dist/skills.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { g as SkillSummary, S as Skill } from './compose-
|
|
2
|
-
export { d as AppliedSkillResult, e as ApplySkillOptions, P as ParsedFrontmatter, f as SkillFrontmatter, l as applySkill, p as parseFrontmatter } from './compose-
|
|
3
|
-
import './types-
|
|
1
|
+
import { g as SkillSummary, S as Skill } from './compose-C4QxEZOS.cjs';
|
|
2
|
+
export { d as AppliedSkillResult, e as ApplySkillOptions, P as ParsedFrontmatter, f as SkillFrontmatter, l as applySkill, p as parseFrontmatter } from './compose-C4QxEZOS.cjs';
|
|
3
|
+
import './types-Y3u0FtdN.cjs';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/skills.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { g as SkillSummary, S as Skill } from './compose-
|
|
2
|
-
export { d as AppliedSkillResult, e as ApplySkillOptions, P as ParsedFrontmatter, f as SkillFrontmatter, l as applySkill, p as parseFrontmatter } from './compose-
|
|
3
|
-
import './types-
|
|
1
|
+
import { g as SkillSummary, S as Skill } from './compose-75UFDzOO.js';
|
|
2
|
+
export { d as AppliedSkillResult, e as ApplySkillOptions, P as ParsedFrontmatter, f as SkillFrontmatter, l as applySkill, p as parseFrontmatter } from './compose-75UFDzOO.js';
|
|
3
|
+
import './types-Y3u0FtdN.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/skills.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/skills/frontmatter.ts","../src/skills/compose.ts","../src/skills/skill-registry.ts"],"names":[],"mappings":"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","file":"skills.js","sourcesContent":["/**\n * Structured, typed error hierarchy for OllamaClient.\n */\n\nimport type { z } from 'zod';\n\nexport interface OllamaErrorRequestContext {\n readonly method?: string | undefined;\n readonly url?: string | undefined;\n readonly model?: string | undefined;\n}\n\nexport interface OllamaErrorResponseContext {\n readonly status?: number | undefined;\n readonly headers?: Record<string, string> | undefined;\n readonly body?: unknown;\n}\n\nexport interface OllamaClientErrorOptions extends ErrorOptions {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable?: boolean | undefined;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n}\n\nexport class OllamaClientError extends Error {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable: boolean;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n\n constructor(message: string, options: OllamaClientErrorOptions) {\n super(message, { cause: options.cause });\n this.name = this.constructor.name;\n this.code = options.code;\n this.status = options.status;\n this.retryable = options.retryable ?? false;\n this.request = options.request;\n this.response = options.response;\n }\n}\n\nexport class OllamaNetworkError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'network_error', retryable: true });\n }\n}\n\nexport class OllamaTimeoutError extends OllamaClientError {\n readonly timeoutMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { timeoutMs?: number | undefined })\n | undefined,\n ) {\n super(message, { ...options, code: 'timeout', retryable: true });\n this.timeoutMs = options?.timeoutMs;\n }\n}\n\nexport class OllamaAuthError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'auth_error', retryable: false });\n }\n}\n\nexport class OllamaNotFoundError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'not_found', retryable: false });\n }\n}\n\nexport class OllamaRateLimitError extends OllamaClientError {\n readonly retryAfterMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n retryAfterMs?: number | undefined;\n })\n | undefined,\n ) {\n super(message, { ...options, code: 'rate_limited', retryable: true });\n this.retryAfterMs = options?.retryAfterMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, by `QuotaManager.assertCanProceed`\n * (see `src/quota.ts`) when issuing the request would exceed a configured usage budget for\n * one of its rolling windows. This is distinct from `OllamaRateLimitError`, which reflects\n * the server's own 429 response — Ollama Cloud does not expose account-level quota via the\n * API, so `QuotaManager` tracks usage against budgets the caller configures locally and\n * fails fast rather than waiting for the server to reject the request.\n */\nexport class OllamaQuotaExceededError extends OllamaClientError {\n readonly windowId: string;\n readonly resetAt: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n windowId: string;\n resetAt: number;\n },\n ) {\n super(message, { ...options, code: 'quota_exceeded', retryable: false });\n this.windowId = options.windowId;\n this.resetAt = options.resetAt;\n }\n}\n\nexport class OllamaServerError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'server_error', retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **503 Service Unavailable**,\n * indicating that the request queue is saturated (`OLLAMA_MAX_QUEUE`\n * exceeded, default 512 — see the FAQ).\n *\n * Semantically a specialization of {@link OllamaServerError} (503 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'overloaded'` —\n * `OllamaServerError`'s constructor unconditionally forces\n * `code: 'server_error'`. Callers wanting to catch any 5xx should\n * use `error.status >= 500 && error.status < 600` OR explicitly\n * list both `OllamaServerError` and `OllamaOverloadedError`/\n * `OllamaBadGatewayError` in their `instanceof` checks.\n *\n * `retryable` is `true` because the queue will eventually drain;\n * callers using {@link withRetry} will get automatic backoff.\n */\nexport class OllamaOverloadedError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'overloaded', status: 503, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **502 Bad Gateway**,\n * indicating that a cloud model could not be reached by the\n * Ollama Cloud proxy. The model may be temporarily down, the\n * cloud provider may be experiencing an outage, or the model\n * may have been deprovisioned.\n *\n * Semantically a specialization of {@link OllamaServerError} (502 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'bad_gateway'` —\n * see {@link OllamaOverloadedError} for the rationale. Callers wanting\n * to catch any 5xx should use `error.status >= 500 && error.status < 600`\n * OR explicitly list both classes in their `instanceof` checks.\n *\n * `retryable` is `true` for transient cloud-provider outages.\n */\nexport class OllamaBadGatewayError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'bad_gateway', status: 502, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server emits an in-band error frame inside\n * an NDJSON stream (chat / generate / pull / push / create).\n *\n * Ollama streams start with HTTP 200 OK and chunked transfer encoding.\n * If an error occurs mid-generation (GPU OOM, driver crash, context\n * window overflow, model unload race, etc.), the server emits a final\n * JSON chunk of the form `{\"error\": \"...\"}` and closes the stream.\n * The HTTP status code never changes from 200, so HTTP-status-based\n * error detection misses these errors entirely — they would silently\n * bleed into the assistant's content stream as garbage tokens or\n * undefined-field accesses.\n *\n * `partialContent` carries whatever was accumulated before the error\n * frame, so callers can log/diagnose what the model produced before\n * failing. For chat streams this is the concatenated `message.content`;\n * for generate streams it's the concatenated `response`; for pull/push\n * streams it's empty (progress events don't accumulate content).\n *\n * See: https://github.com/ollama/ollama/blob/main/docs/api.md\n */\nexport class OllamaStreamError extends OllamaClientError {\n /** Content accumulated before the in-band error frame, or '' if none. */\n readonly partialContent: string;\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n partialContent?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'stream_error', retryable: false });\n this.partialContent = options?.partialContent ?? '';\n }\n}\n\nexport class OllamaAbortError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'aborted', retryable: false });\n }\n}\n\nexport class OllamaToolValidationError extends OllamaClientError {\n readonly toolName: string;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { toolName: string; issues?: unknown },\n ) {\n super(message, { ...options, code: 'tool_validation_error', retryable: false });\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` when `validateRequests: true` is set and\n * the request body fails Zod validation against the operation's registered\n * schema. See ADR 0020 (runtime Zod validation).\n *\n * The error carries the original Zod issues so callers can inspect which\n * fields failed. No HTTP request is made when this error is thrown.\n */\nexport class OllamaRequestValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'request_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * serialized request body exceeds the operation's declared\n * `constraints.maxRequestBytes`. The Ollama server returns 413 for such\n * payloads; this client-side check fails fast so the round-trip is avoided.\n *\n * Wave 12 (P0 #5): the IR has carried `maxRequestBytes` for System One\n * (64 KiB) since v1.7.0, but the runtime never enforced it. This closes\n * that contract/runtime gap.\n */\nexport class OllamaRequestTooLargeError extends OllamaClientError {\n readonly operationId: string;\n readonly actualBytes: number;\n readonly maxBytes: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> & {\n operationId: string;\n actualBytes: number;\n maxBytes: number;\n },\n ) {\n super(message, { ...options, code: 'request_too_large', retryable: false, status: 413 });\n this.operationId = options.operationId;\n this.actualBytes = options.actualBytes;\n this.maxBytes = options.maxBytes;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` AFTER the HTTP response is received\n * when `validateResponses: true` is set and the response body fails Zod\n * validation against the operation's registered response schema.\n *\n * Wave 13: the runtime previously never validated responses (see ADR\n * 0020). This opt-in error gives callers a way to detect wire-format\n * mismatches for operations where typed response semantics are critical\n * (e.g. System One). The error carries the original Zod issues so\n * callers can inspect which fields failed.\n */\nexport class OllamaResponseValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'response_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * operation declares `constraints.minOllamaVersion` and the runtime could\n * not obtain a server version to compare against (e.g. `enforceVersion:\n * 'strict'` was set and `/api/version` was unreachable). Distinct from\n * {@link OllamaGenericClientError} so callers can branch on the failure\n * mode rather than parsing the message.\n */\nexport class OllamaServerVersionUnknownError extends OllamaClientError {\n readonly operationId: string;\n readonly minRequiredVersion: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n minRequiredVersion: string;\n },\n ) {\n super(message, { ...options, code: 'server_version_unknown', retryable: false });\n this.operationId = options.operationId;\n this.minRequiredVersion = options.minRequiredVersion;\n }\n}\n\nexport class OllamaToolTimeoutError extends OllamaClientError {\n readonly toolName: string;\n readonly timeoutMs: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n toolName: string;\n timeoutMs: number;\n },\n ) {\n super(message, { ...options, code: 'tool_timeout', retryable: false });\n this.toolName = options.toolName;\n this.timeoutMs = options.timeoutMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, when a request asks for a\n * capability an endpoint is known not to support (e.g. structured output `format` against\n * an Ollama Cloud endpoint — see `ModelCapabilities.supportsStructuredOutputRequest` in\n * `src/capabilities/capabilities.ts`). Its `code` is included in `DEFAULT_FAILOVER_CODES`\n * by default, so in a multi-endpoint setup it causes failover to the next candidate rather\n * than failing outright — it only surfaces to the caller if every candidate is rejected.\n */\nexport class OllamaUnsupportedCapabilityError extends OllamaClientError {\n readonly capability: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { capability: string },\n ) {\n super(message, { ...options, code: 'unsupported_capability', retryable: false });\n this.capability = options.capability;\n }\n}\n\n/**\n * Thrown client-side, before any network call, when `config.endpoints` uses\n * `OllamaEndpoint.models` to scope endpoints/credentials to specific models and the\n * requested `model` isn't in any configured endpoint's allow-list. This is a routing\n * misconfiguration, not a connectivity problem — the SDK deliberately does not \"probe\"\n * unauthorized endpoints to find one that happens to work (that would burn quota on keys\n * that were never entitled to the model and produce non-deterministic startup behavior).\n */\nexport class OllamaModelRoutingError extends OllamaClientError {\n readonly model: string;\n readonly availableModels: readonly string[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n availableModels: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'model_routing_error', retryable: false });\n this.model = options.model;\n this.availableModels = options.availableModels;\n }\n}\n\n/**\n * Thrown before an agent tool loop starts when the selected model's /api/show metadata\n * does not advertise a capability required by the loop.\n */\nexport class OllamaIncompatibleModelError extends OllamaClientError {\n readonly model: string;\n readonly capability: string;\n readonly reportedCapabilities: readonly string[];\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n capability: string;\n reportedCapabilities: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'incompatible_model', retryable: false });\n this.model = options.model;\n this.capability = options.capability;\n this.reportedCapabilities = options.reportedCapabilities;\n }\n}\nexport class OllamaAgentMaxToolCallsError extends OllamaClientError {\n readonly maxToolCalls: number;\n readonly toolCallsExecuted: number;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n maxToolCalls: number;\n toolCallsExecuted: number;\n },\n ) {\n super(message, { ...options, code: 'agent_max_tool_calls_exceeded', retryable: false });\n this.maxToolCalls = options.maxToolCalls;\n this.toolCallsExecuted = options.toolCallsExecuted;\n }\n}\n\nexport class OllamaAgentMaxIterationsError extends OllamaClientError {\n readonly maxIterations: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { maxIterations: number },\n ) {\n super(message, { ...options, code: 'agent_max_iterations_exceeded', retryable: false });\n this.maxIterations = options.maxIterations;\n }\n}\n\n/**\n * Thrown when the agent's cycle detection fires: the same tool call —\n * identical name **and** identical arguments — would execute more times than\n * `maxRepeatedToolCalls` allows during one run.\n *\n * This is the fail-fast diagnosis for a model stuck in a tool loop (repeatedly\n * calling the same function with the same arguments, never reacting to the\n * results); without it, a looping model only surfaces as a generic\n * {@link OllamaAgentMaxIterationsError} after burning the full iteration\n * budget on wasted calls.\n */\nexport class OllamaAgentToolLoopError extends OllamaClientError {\n /** Name of the tool whose identical call would exceed the repeat budget. */\n readonly toolName: string;\n /** How many times this exact call would have executed including the rejected one. */\n readonly repeatedExecutions: number;\n /** The configured per-signature execution budget. */\n readonly maxRepeatedToolCalls: number;\n /** Canonical `name(args)` signature of the repeated call (very large payloads truncated). */\n readonly signature: string;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n toolName: string;\n repeatedExecutions: number;\n maxRepeatedToolCalls: number;\n signature: string;\n },\n ) {\n super(message, { ...options, code: 'agent_tool_loop_detected', retryable: false });\n this.toolName = options.toolName;\n this.repeatedExecutions = options.repeatedExecutions;\n this.maxRepeatedToolCalls = options.maxRepeatedToolCalls;\n this.signature = options.signature;\n }\n}\n\nexport class OllamaMcpError extends OllamaClientError {\n readonly mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n readonly toolName?: string | undefined;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n toolName?: string | undefined;\n issues?: unknown;\n },\n ) {\n super(message, { ...options, code: 'mcp_error', retryable: options.retryable ?? false });\n this.mcpMethod = options.mcpMethod;\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\nexport class OllamaSkillNotFoundError extends OllamaClientError {\n readonly skillName: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { skillName: string },\n ) {\n super(message, { ...options, code: 'skill_not_found', retryable: false });\n this.skillName = options.skillName;\n }\n}\n\nexport class OllamaSkillInvalidError extends OllamaClientError {\n readonly skillName: string;\n readonly path?: string | undefined;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n skillName: string;\n path?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'skill_invalid', retryable: false });\n this.skillName = options.skillName;\n this.path = options.path;\n }\n}\n\nexport class OllamaGenericClientError extends OllamaClientError {\n constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code'> | undefined) {\n super(message, { ...options, code: 'client_error' });\n }\n}\n\nfunction isDomAbortError(error: unknown): error is DOMException {\n return (\n typeof DOMException !== 'undefined' &&\n error instanceof DOMException &&\n error.name === 'AbortError'\n );\n}\n\n/**\n * Error `code`s that mean the transport never delivered a usable response —\n * the request died at the socket/connection layer. This is the stale-socket\n * family: keep-alive connections recycled by a restarting/idle-timeouting\n * daemon (`ECONNRESET`, `EPIPE`, undici's `UND_ERR_SOCKET`/`UND_ERR_CLOSED`\n * when the pooled socket is reused after the server closed it), connections\n * that never established (`ECONNREFUSED`, `EAI_AGAIN`, `ENOTFOUND`), and\n * connect/header/body timeouts from the undici dispatcher.\n *\n * `UND_ERR_ABORTED` is deliberately NOT here: it is the dispatcher's shape\n * for caller-initiated aborts, which map to `OllamaAbortError` (never\n * retried) — classifying it as a network failure would re-dispatch requests\n * the caller explicitly cancelled.\n */\nexport const NETWORK_ERROR_CODES: ReadonlySet<string> = new Set([\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'ECONNABORTED',\n 'EHOSTUNREACH',\n 'ENETUNREACH',\n 'ENOTFOUND',\n 'EAI_AGAIN',\n 'UND_ERR_SOCKET',\n 'UND_ERR_CONNECT_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_BODY_TIMEOUT',\n 'UND_ERR_CLOSED',\n]);\n\n/** How many `cause` links to walk looking for a network-level `code`. */\nconst MAX_CAUSE_DEPTH = 4;\n\n/**\n * Structural network-failure detection: looks for a `code` from\n * {@link NETWORK_ERROR_CODES} on the error itself or anywhere down its\n * `cause` chain (bounded depth — cause cycles must not spin forever).\n *\n * Deliberately does NOT match on message text (`String(err).includes(...)`\n * style): undici/Node message wording is not a stable contract across\n * versions, while `error.code` is. Custom `fetch` implementations built on\n * `node:http` reject with these codes natively (WHATWG `fetch` wraps them in\n * a `TypeError`, which `mapError` already classifies); this predicate closes\n * the gap for the non-`TypeError` shapes.\n */\nexport function isNetworkLevelError(error: unknown): boolean {\n let current: unknown = error;\n for (\n let depth = 0;\n depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null;\n depth += 1\n ) {\n if (typeof current === 'object' && 'code' in current) {\n const code = (current as { code?: unknown }).code;\n if (typeof code === 'string' && NETWORK_ERROR_CODES.has(code)) {\n return true;\n }\n }\n current = (current as { cause?: unknown }).cause;\n }\n return false;\n}\n\nfunction statusToError(\n status: number,\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'status'>,\n): OllamaClientError {\n if (status === 401 || status === 403) {\n return new OllamaAuthError(message, { ...options, status });\n }\n if (status === 404) {\n return new OllamaNotFoundError(message, { ...options, status });\n }\n if (status === 429) {\n return new OllamaRateLimitError(message, { ...options, status });\n }\n if (status === 502) {\n // Cloud model could not be reached. Distinct from generic 5xx so\n // callers running multi-model agents can branch on cloud-provider\n // failures specifically (fail over to a different model/endpoint\n // rather than blindly retrying the same one).\n return new OllamaBadGatewayError(message, { ...options });\n }\n if (status === 503) {\n // Queue saturation (OLLAMA_MAX_QUEUE exceeded). Retryable — the\n // queue will eventually drain. Distinct from generic 5xx so\n // callers running parallel swarms can branch on saturation.\n return new OllamaOverloadedError(message, { ...options });\n }\n if (status >= 500) {\n return new OllamaServerError(message, { ...options, status });\n }\n return new OllamaGenericClientError(message, { ...options, status });\n}\n\n/**\n * Maps arbitrary thrown exceptions into structured OllamaClientError instances.\n */\nexport function mapError(\n error: unknown,\n context: {\n request?: OllamaErrorRequestContext | undefined;\n response?: OllamaErrorResponseContext | undefined;\n } = {},\n): OllamaClientError {\n if (error instanceof OllamaClientError) {\n return error;\n }\n if (isDomAbortError(error)) {\n return new OllamaAbortError(error.message || 'Request was aborted', {\n cause: error,\n request: context.request,\n });\n }\n // Socket/connection-level failures — including the non-TypeError shapes a\n // custom `fetch` implementation produces (`Error` + `code: 'ECONNRESET'`\n // and friends) and network codes nested in `cause` chains. Checked before\n // the `TypeError` branch so a code-carrying TypeError maps through the same\n // specialized construction with a better message. Retryable + failover-eligible.\n if (isNetworkLevelError(error)) {\n const message =\n error instanceof Error && error.message ? error.message : 'Network request failed';\n return new OllamaNetworkError(message, {\n cause: error,\n request: context.request,\n });\n }\n if (error instanceof TypeError) {\n return new OllamaNetworkError(error.message || 'Network request failed', {\n cause: error,\n request: context.request,\n });\n }\n if (context.response?.status !== undefined) {\n const message = error instanceof Error ? error.message : String(error);\n return statusToError(context.response.status, message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new OllamaGenericClientError(message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n}\n","/**\n * Lightweight frontmatter parser for SKILL.md files.\n */\n\nimport { OllamaSkillInvalidError } from '../errors.js';\nimport type { SkillFrontmatter } from './types.js';\n\nexport interface ParsedFrontmatter {\n readonly frontmatter: SkillFrontmatter;\n readonly body: string;\n}\n\nfunction parseYamlValue(raw: string): unknown {\n const trimmed = raw.trim();\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n if (!Number.isNaN(Number(trimmed)) && trimmed !== '') return Number(trimmed);\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\nfunction parseYamlBlock(yamlText: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = yamlText.split('\\n');\n let currentKey: string | undefined;\n let currentList: unknown[] | undefined;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n if (trimmed.startsWith('- ') && currentKey) {\n if (!currentList) {\n currentList = [];\n result[currentKey] = currentList;\n }\n currentList.push(parseYamlValue(trimmed.slice(2)));\n continue;\n }\n\n currentList = undefined;\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim();\n const valStr = line.slice(colonIndex + 1).trim();\n currentKey = key;\n if (valStr.length > 0) {\n result[key] = parseYamlValue(valStr);\n }\n }\n }\n\n return result;\n}\n\nexport function parseFrontmatter(source: string, path = ''): ParsedFrontmatter {\n const match = source.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n if (!match) {\n throw new OllamaSkillInvalidError('Missing YAML frontmatter delimiters (---)', {\n skillName: path || 'unknown',\n path,\n });\n }\n\n const rawYaml = match[1] ?? '';\n const body = match[2]?.trim() ?? '';\n const parsed = parseYamlBlock(rawYaml);\n\n if (!parsed['name'] || typeof parsed['name'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"name\"', {\n skillName: String(parsed['name'] ?? 'unknown'),\n path,\n });\n }\n if (!parsed['description'] || typeof parsed['description'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"description\"', {\n skillName: parsed['name'],\n path,\n });\n }\n\n return {\n frontmatter: parsed as unknown as SkillFrontmatter,\n body,\n };\n}\n","/**\n * Skill composition and context injection.\n */\n\nimport type { Message } from '../types.js';\nimport type { ToolRegistry } from '../tools/registry.js';\nimport type { Skill } from './types.js';\n\nexport interface ApplySkillOptions {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\nexport interface AppliedSkillResult {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\n/**\n * Injects a skill's body into messages as a system prompt and applies allowed tool filters.\n */\nexport function applySkill(skill: Skill, options: ApplySkillOptions): AppliedSkillResult {\n const systemPrompt = `[Skill: ${skill.name}]\\n${skill.description}\\n\\n${skill.body}`;\n const messages = [...options.messages];\n const systemIndex = messages.findIndex((m) => m.role === 'system');\n\n if (systemIndex >= 0) {\n const existing = messages[systemIndex];\n if (existing) {\n messages[systemIndex] = {\n role: 'system',\n content: `${existing.content}\\n\\n${systemPrompt}`,\n };\n }\n } else {\n messages.unshift({ role: 'system', content: systemPrompt });\n }\n\n return {\n messages,\n ...(options.tools !== undefined ? { tools: options.tools } : {}),\n };\n}\n","/**\n * Node.js filesystem skill registry for SKILL.md packages.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { OllamaSkillNotFoundError } from '../errors.js';\nimport { parseFrontmatter } from './frontmatter.js';\nimport type { Skill, SkillSummary } from './types.js';\n\nexport interface SkillRegistryOptions {\n readonly directory: string;\n}\n\nexport class SkillRegistry {\n readonly directory: string;\n\n constructor(options: SkillRegistryOptions) {\n this.directory = options.directory;\n }\n\n async list(): Promise<SkillSummary[]> {\n const entries = await readdir(this.directory, { withFileTypes: true });\n const summaries: SkillSummary[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillPath = join(this.directory, entry.name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n summaries.push({\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n });\n } catch {\n // Skip directories without valid SKILL.md\n }\n }\n\n return summaries;\n }\n\n async load(name: string): Promise<Skill> {\n const skillPath = join(this.directory, name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n return {\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n frontmatter: parsed.frontmatter,\n body: parsed.body,\n allowedTools: parsed.frontmatter['allowed-tools'],\n };\n } catch (err) {\n throw new OllamaSkillNotFoundError(`Skill \"${name}\" not found at ${skillPath}`, {\n skillName: name,\n cause: err,\n });\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/skills/frontmatter.ts","../src/skills/compose.ts","../src/skills/skill-registry.ts"],"names":[],"mappings":"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","file":"skills.js","sourcesContent":["/**\n * Structured, typed error hierarchy for OllamaClient.\n */\n\nimport type { z } from 'zod';\n\nexport interface OllamaErrorRequestContext {\n readonly method?: string | undefined;\n readonly url?: string | undefined;\n readonly model?: string | undefined;\n}\n\nexport interface OllamaErrorResponseContext {\n readonly status?: number | undefined;\n readonly headers?: Record<string, string> | undefined;\n readonly body?: unknown;\n}\n\nexport interface OllamaClientErrorOptions extends ErrorOptions {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable?: boolean | undefined;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n}\n\nexport class OllamaClientError extends Error {\n readonly code: string;\n readonly status?: number | undefined;\n readonly retryable: boolean;\n readonly request?: OllamaErrorRequestContext | undefined;\n readonly response?: OllamaErrorResponseContext | undefined;\n\n constructor(message: string, options: OllamaClientErrorOptions) {\n super(message, { cause: options.cause });\n this.name = this.constructor.name;\n this.code = options.code;\n this.status = options.status;\n this.retryable = options.retryable ?? false;\n this.request = options.request;\n this.response = options.response;\n }\n}\n\nexport class OllamaNetworkError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'network_error', retryable: true });\n }\n}\n\nexport class OllamaTimeoutError extends OllamaClientError {\n readonly timeoutMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { timeoutMs?: number | undefined })\n | undefined,\n ) {\n super(message, { ...options, code: 'timeout', retryable: true });\n this.timeoutMs = options?.timeoutMs;\n }\n}\n\nexport class OllamaAuthError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'auth_error', retryable: false });\n }\n}\n\n/**\n * Thrown for HTTP 402 responses — payment required. Ollama's cloud returns\n * 402 when a cloud model (for example `clef:cloud` through\n * `/v1/systemone`) is not included in the Free plan, when usage credits\n * are needed, or when a payment fails.\n *\n * Distinct from {@link OllamaAuthError} (401/403): the credentials are\n * fine; the billing relationship is the problem. Callers should branch\n * to an upgrade/add-credits flow, not re-prompt for an API key.\n *\n * 2026-10-16 refresh: 402 joined the documented `/v1/systemone` response\n * set with the System One cloud launch; previously it fell through to\n * {@link OllamaGenericClientError}.\n */\nexport class OllamaPaymentRequiredError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'payment_required', retryable: false, status: 402 });\n }\n}\n\nexport class OllamaNotFoundError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'not_found', retryable: false });\n }\n}\n\nexport class OllamaRateLimitError extends OllamaClientError {\n readonly retryAfterMs?: number | undefined;\n constructor(\n message: string,\n options?:\n | (Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n retryAfterMs?: number | undefined;\n })\n | undefined,\n ) {\n super(message, { ...options, code: 'rate_limited', retryable: true });\n this.retryAfterMs = options?.retryAfterMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, by `QuotaManager.assertCanProceed`\n * (see `src/quota.ts`) when issuing the request would exceed a configured usage budget for\n * one of its rolling windows. This is distinct from `OllamaRateLimitError`, which reflects\n * the server's own 429 response — Ollama Cloud does not expose account-level quota via the\n * API, so `QuotaManager` tracks usage against budgets the caller configures locally and\n * fails fast rather than waiting for the server to reject the request.\n */\nexport class OllamaQuotaExceededError extends OllamaClientError {\n readonly windowId: string;\n readonly resetAt: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n windowId: string;\n resetAt: number;\n },\n ) {\n super(message, { ...options, code: 'quota_exceeded', retryable: false });\n this.windowId = options.windowId;\n this.resetAt = options.resetAt;\n }\n}\n\nexport class OllamaServerError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'server_error', retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **503 Service Unavailable**,\n * indicating that the request queue is saturated (`OLLAMA_MAX_QUEUE`\n * exceeded, default 512 — see the FAQ).\n *\n * Semantically a specialization of {@link OllamaServerError} (503 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'overloaded'` —\n * `OllamaServerError`'s constructor unconditionally forces\n * `code: 'server_error'`. Callers wanting to catch any 5xx should\n * use `error.status >= 500 && error.status < 600` OR explicitly\n * list both `OllamaServerError` and `OllamaOverloadedError`/\n * `OllamaBadGatewayError` in their `instanceof` checks.\n *\n * `retryable` is `true` because the queue will eventually drain;\n * callers using {@link withRetry} will get automatic backoff.\n */\nexport class OllamaOverloadedError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'overloaded', status: 503, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server returns HTTP **502 Bad Gateway**,\n * indicating that a cloud model could not be reached by the\n * Ollama Cloud proxy. The model may be temporarily down, the\n * cloud provider may be experiencing an outage, or the model\n * may have been deprovisioned.\n *\n * Semantically a specialization of {@link OllamaServerError} (502 is a\n * kind of 5xx server error), but extends {@link OllamaClientError}\n * directly to preserve the subclass-specific `code: 'bad_gateway'` —\n * see {@link OllamaOverloadedError} for the rationale. Callers wanting\n * to catch any 5xx should use `error.status >= 500 && error.status < 600`\n * OR explicitly list both classes in their `instanceof` checks.\n *\n * `retryable` is `true` for transient cloud-provider outages.\n */\nexport class OllamaBadGatewayError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> | undefined,\n ) {\n super(message, { ...options, code: 'bad_gateway', status: 502, retryable: true });\n }\n}\n\n/**\n * Thrown when the Ollama server emits an in-band error frame inside\n * an NDJSON stream (chat / generate / pull / push / create).\n *\n * Ollama streams start with HTTP 200 OK and chunked transfer encoding.\n * If an error occurs mid-generation (GPU OOM, driver crash, context\n * window overflow, model unload race, etc.), the server emits a final\n * JSON chunk of the form `{\"error\": \"...\"}` and closes the stream.\n * The HTTP status code never changes from 200, so HTTP-status-based\n * error detection misses these errors entirely — they would silently\n * bleed into the assistant's content stream as garbage tokens or\n * undefined-field accesses.\n *\n * `partialContent` carries whatever was accumulated before the error\n * frame, so callers can log/diagnose what the model produced before\n * failing. For chat streams this is the concatenated `message.content`;\n * for generate streams it's the concatenated `response`; for pull/push\n * streams it's empty (progress events don't accumulate content).\n *\n * See: https://github.com/ollama/ollama/blob/main/docs/api.md\n */\nexport class OllamaStreamError extends OllamaClientError {\n /** Content accumulated before the in-band error frame, or '' if none. */\n readonly partialContent: string;\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n partialContent?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'stream_error', retryable: false });\n this.partialContent = options?.partialContent ?? '';\n }\n}\n\nexport class OllamaAbortError extends OllamaClientError {\n constructor(\n message: string,\n options?: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> | undefined,\n ) {\n super(message, { ...options, code: 'aborted', retryable: false });\n }\n}\n\nexport class OllamaToolValidationError extends OllamaClientError {\n readonly toolName: string;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { toolName: string; issues?: unknown },\n ) {\n super(message, { ...options, code: 'tool_validation_error', retryable: false });\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` when `validateRequests: true` is set and\n * the request body fails Zod validation against the operation's registered\n * schema. See ADR 0020 (runtime Zod validation).\n *\n * The error carries the original Zod issues so callers can inspect which\n * fields failed. No HTTP request is made when this error is thrown.\n */\nexport class OllamaRequestValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'request_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * serialized request body exceeds the operation's declared size constraints.\n * The Ollama server returns 413 for such payloads; this client-side check\n * fails fast so the round-trip is avoided.\n *\n * Dual bound (2026-10-16 refresh, matching the upstream clarification):\n * `constraints.maxRequestBytes` bounds the text and schema portion of the\n * body (images excluded), `constraints.maxRequestBytesWithImages` bounds\n * the whole serialized request (images included) — both apply to every\n * request simultaneously.\n *\n * Wave 12 (P0 #5): the IR has carried `maxRequestBytes` for System One\n * (64 KiB) since v1.7.0, but the runtime never enforced it. This closes\n * that contract/runtime gap.\n */\nexport class OllamaRequestTooLargeError extends OllamaClientError {\n readonly operationId: string;\n readonly actualBytes: number;\n readonly maxBytes: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable' | 'status'> & {\n operationId: string;\n actualBytes: number;\n maxBytes: number;\n },\n ) {\n super(message, { ...options, code: 'request_too_large', retryable: false, status: 413 });\n this.operationId = options.operationId;\n this.actualBytes = options.actualBytes;\n this.maxBytes = options.maxBytes;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` AFTER the HTTP response is received\n * when `validateResponses: true` is set and the response body fails Zod\n * validation against the operation's registered response schema.\n *\n * Wave 13: the runtime previously never validated responses (see ADR\n * 0020). This opt-in error gives callers a way to detect wire-format\n * mismatches for operations where typed response semantics are critical\n * (e.g. System One). The error carries the original Zod issues so\n * callers can inspect which fields failed.\n */\nexport class OllamaResponseValidationError extends OllamaClientError {\n readonly operationId: string;\n readonly issues: readonly z.ZodIssue[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n issues: readonly z.ZodIssue[];\n },\n ) {\n super(message, { ...options, code: 'response_validation_error', retryable: false });\n this.operationId = options.operationId;\n this.issues = options.issues;\n }\n}\n\n/**\n * Thrown by `OllamaRuntime.invoke` BEFORE any HTTP request is made when the\n * operation declares `constraints.minOllamaVersion` and the runtime could\n * not obtain a server version to compare against (e.g. `enforceVersion:\n * 'strict'` was set and `/api/version` was unreachable). Distinct from\n * {@link OllamaGenericClientError} so callers can branch on the failure\n * mode rather than parsing the message.\n */\nexport class OllamaServerVersionUnknownError extends OllamaClientError {\n readonly operationId: string;\n readonly minRequiredVersion: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n operationId: string;\n minRequiredVersion: string;\n },\n ) {\n super(message, { ...options, code: 'server_version_unknown', retryable: false });\n this.operationId = options.operationId;\n this.minRequiredVersion = options.minRequiredVersion;\n }\n}\n\nexport class OllamaToolTimeoutError extends OllamaClientError {\n readonly toolName: string;\n readonly timeoutMs: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n toolName: string;\n timeoutMs: number;\n },\n ) {\n super(message, { ...options, code: 'tool_timeout', retryable: false });\n this.toolName = options.toolName;\n this.timeoutMs = options.timeoutMs;\n }\n}\n\n/**\n * Thrown client-side, before a network request is made, when a request asks for a\n * capability an endpoint is known not to support (e.g. structured output `format` against\n * an Ollama Cloud endpoint — see `ModelCapabilities.supportsStructuredOutputRequest` in\n * `src/capabilities/capabilities.ts`). Its `code` is included in `DEFAULT_FAILOVER_CODES`\n * by default, so in a multi-endpoint setup it causes failover to the next candidate rather\n * than failing outright — it only surfaces to the caller if every candidate is rejected.\n */\nexport class OllamaUnsupportedCapabilityError extends OllamaClientError {\n readonly capability: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & { capability: string },\n ) {\n super(message, { ...options, code: 'unsupported_capability', retryable: false });\n this.capability = options.capability;\n }\n}\n\n/**\n * Thrown client-side, before any network call, when `config.endpoints` uses\n * `OllamaEndpoint.models` to scope endpoints/credentials to specific models and the\n * requested `model` isn't in any configured endpoint's allow-list. This is a routing\n * misconfiguration, not a connectivity problem — the SDK deliberately does not \"probe\"\n * unauthorized endpoints to find one that happens to work (that would burn quota on keys\n * that were never entitled to the model and produce non-deterministic startup behavior).\n */\nexport class OllamaModelRoutingError extends OllamaClientError {\n readonly model: string;\n readonly availableModels: readonly string[];\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n availableModels: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'model_routing_error', retryable: false });\n this.model = options.model;\n this.availableModels = options.availableModels;\n }\n}\n\n/**\n * Thrown before an agent tool loop starts when the selected model's /api/show metadata\n * does not advertise a capability required by the loop.\n */\nexport class OllamaIncompatibleModelError extends OllamaClientError {\n readonly model: string;\n readonly capability: string;\n readonly reportedCapabilities: readonly string[];\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'retryable'> & {\n model: string;\n capability: string;\n reportedCapabilities: readonly string[];\n },\n ) {\n super(message, { ...options, code: 'incompatible_model', retryable: false });\n this.model = options.model;\n this.capability = options.capability;\n this.reportedCapabilities = options.reportedCapabilities;\n }\n}\nexport class OllamaAgentMaxToolCallsError extends OllamaClientError {\n readonly maxToolCalls: number;\n readonly toolCallsExecuted: number;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n maxToolCalls: number;\n toolCallsExecuted: number;\n },\n ) {\n super(message, { ...options, code: 'agent_max_tool_calls_exceeded', retryable: false });\n this.maxToolCalls = options.maxToolCalls;\n this.toolCallsExecuted = options.toolCallsExecuted;\n }\n}\n\nexport class OllamaAgentMaxIterationsError extends OllamaClientError {\n readonly maxIterations: number;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { maxIterations: number },\n ) {\n super(message, { ...options, code: 'agent_max_iterations_exceeded', retryable: false });\n this.maxIterations = options.maxIterations;\n }\n}\n\n/**\n * Thrown when the agent's cycle detection fires: the same tool call —\n * identical name **and** identical arguments — would execute more times than\n * `maxRepeatedToolCalls` allows during one run.\n *\n * This is the fail-fast diagnosis for a model stuck in a tool loop (repeatedly\n * calling the same function with the same arguments, never reacting to the\n * results); without it, a looping model only surfaces as a generic\n * {@link OllamaAgentMaxIterationsError} after burning the full iteration\n * budget on wasted calls.\n */\nexport class OllamaAgentToolLoopError extends OllamaClientError {\n /** Name of the tool whose identical call would exceed the repeat budget. */\n readonly toolName: string;\n /** How many times this exact call would have executed including the rejected one. */\n readonly repeatedExecutions: number;\n /** The configured per-signature execution budget. */\n readonly maxRepeatedToolCalls: number;\n /** Canonical `name(args)` signature of the repeated call (very large payloads truncated). */\n readonly signature: string;\n\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n toolName: string;\n repeatedExecutions: number;\n maxRepeatedToolCalls: number;\n signature: string;\n },\n ) {\n super(message, { ...options, code: 'agent_tool_loop_detected', retryable: false });\n this.toolName = options.toolName;\n this.repeatedExecutions = options.repeatedExecutions;\n this.maxRepeatedToolCalls = options.maxRepeatedToolCalls;\n this.signature = options.signature;\n }\n}\n\nexport class OllamaMcpError extends OllamaClientError {\n readonly mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n readonly toolName?: string | undefined;\n readonly issues?: unknown;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n mcpMethod:\n 'listTools' | 'callTool' | 'tools/call' | 'tasks/get' | 'tasks/result' | 'tasks/cancel';\n toolName?: string | undefined;\n issues?: unknown;\n },\n ) {\n super(message, { ...options, code: 'mcp_error', retryable: options.retryable ?? false });\n this.mcpMethod = options.mcpMethod;\n this.toolName = options.toolName;\n this.issues = options.issues;\n }\n}\n\nexport class OllamaSkillNotFoundError extends OllamaClientError {\n readonly skillName: string;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & { skillName: string },\n ) {\n super(message, { ...options, code: 'skill_not_found', retryable: false });\n this.skillName = options.skillName;\n }\n}\n\nexport class OllamaSkillInvalidError extends OllamaClientError {\n readonly skillName: string;\n readonly path?: string | undefined;\n constructor(\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code'> & {\n skillName: string;\n path?: string | undefined;\n },\n ) {\n super(message, { ...options, code: 'skill_invalid', retryable: false });\n this.skillName = options.skillName;\n this.path = options.path;\n }\n}\n\nexport class OllamaGenericClientError extends OllamaClientError {\n constructor(message: string, options?: Omit<OllamaClientErrorOptions, 'code'> | undefined) {\n super(message, { ...options, code: 'client_error' });\n }\n}\n\nfunction isDomAbortError(error: unknown): error is DOMException {\n return (\n typeof DOMException !== 'undefined' &&\n error instanceof DOMException &&\n error.name === 'AbortError'\n );\n}\n\n/**\n * Error `code`s that mean the transport never delivered a usable response —\n * the request died at the socket/connection layer. This is the stale-socket\n * family: keep-alive connections recycled by a restarting/idle-timeouting\n * daemon (`ECONNRESET`, `EPIPE`, undici's `UND_ERR_SOCKET`/`UND_ERR_CLOSED`\n * when the pooled socket is reused after the server closed it), connections\n * that never established (`ECONNREFUSED`, `EAI_AGAIN`, `ENOTFOUND`), and\n * connect/header/body timeouts from the undici dispatcher.\n *\n * `UND_ERR_ABORTED` is deliberately NOT here: it is the dispatcher's shape\n * for caller-initiated aborts, which map to `OllamaAbortError` (never\n * retried) — classifying it as a network failure would re-dispatch requests\n * the caller explicitly cancelled.\n */\nexport const NETWORK_ERROR_CODES: ReadonlySet<string> = new Set([\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'ECONNABORTED',\n 'EHOSTUNREACH',\n 'ENETUNREACH',\n 'ENOTFOUND',\n 'EAI_AGAIN',\n 'UND_ERR_SOCKET',\n 'UND_ERR_CONNECT_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_BODY_TIMEOUT',\n 'UND_ERR_CLOSED',\n]);\n\n/** How many `cause` links to walk looking for a network-level `code`. */\nconst MAX_CAUSE_DEPTH = 4;\n\n/**\n * Structural network-failure detection: looks for a `code` from\n * {@link NETWORK_ERROR_CODES} on the error itself or anywhere down its\n * `cause` chain (bounded depth — cause cycles must not spin forever).\n *\n * Deliberately does NOT match on message text (`String(err).includes(...)`\n * style): undici/Node message wording is not a stable contract across\n * versions, while `error.code` is. Custom `fetch` implementations built on\n * `node:http` reject with these codes natively (WHATWG `fetch` wraps them in\n * a `TypeError`, which `mapError` already classifies); this predicate closes\n * the gap for the non-`TypeError` shapes.\n */\nexport function isNetworkLevelError(error: unknown): boolean {\n let current: unknown = error;\n for (\n let depth = 0;\n depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null;\n depth += 1\n ) {\n if (typeof current === 'object' && 'code' in current) {\n const code = (current as { code?: unknown }).code;\n if (typeof code === 'string' && NETWORK_ERROR_CODES.has(code)) {\n return true;\n }\n }\n current = (current as { cause?: unknown }).cause;\n }\n return false;\n}\n\nfunction statusToError(\n status: number,\n message: string,\n options: Omit<OllamaClientErrorOptions, 'code' | 'status'>,\n): OllamaClientError {\n if (status === 401 || status === 403) {\n return new OllamaAuthError(message, { ...options, status });\n }\n if (status === 402) {\n // Cloud billing, not credentials: the cloud model isn't in the Free\n // plan, credits are needed, or a payment failed (documented on\n // /v1/systemone since the 2026-10-16 System One cloud launch).\n // Distinct from auth failures so callers can branch to an\n // upgrade/credits flow instead of re-prompting for an API key.\n return new OllamaPaymentRequiredError(message, options);\n }\n if (status === 404) {\n return new OllamaNotFoundError(message, { ...options, status });\n }\n if (status === 429) {\n return new OllamaRateLimitError(message, { ...options, status });\n }\n if (status === 502) {\n // Cloud model could not be reached. Distinct from generic 5xx so\n // callers running multi-model agents can branch on cloud-provider\n // failures specifically (fail over to a different model/endpoint\n // rather than blindly retrying the same one).\n return new OllamaBadGatewayError(message, { ...options });\n }\n if (status === 503) {\n // Queue saturation (OLLAMA_MAX_QUEUE exceeded). Retryable — the\n // queue will eventually drain. Distinct from generic 5xx so\n // callers running parallel swarms can branch on saturation.\n return new OllamaOverloadedError(message, { ...options });\n }\n if (status >= 500) {\n return new OllamaServerError(message, { ...options, status });\n }\n return new OllamaGenericClientError(message, { ...options, status });\n}\n\n/**\n * Maps arbitrary thrown exceptions into structured OllamaClientError instances.\n */\nexport function mapError(\n error: unknown,\n context: {\n request?: OllamaErrorRequestContext | undefined;\n response?: OllamaErrorResponseContext | undefined;\n } = {},\n): OllamaClientError {\n if (error instanceof OllamaClientError) {\n return error;\n }\n if (isDomAbortError(error)) {\n return new OllamaAbortError(error.message || 'Request was aborted', {\n cause: error,\n request: context.request,\n });\n }\n // Socket/connection-level failures — including the non-TypeError shapes a\n // custom `fetch` implementation produces (`Error` + `code: 'ECONNRESET'`\n // and friends) and network codes nested in `cause` chains. Checked before\n // the `TypeError` branch so a code-carrying TypeError maps through the same\n // specialized construction with a better message. Retryable + failover-eligible.\n if (isNetworkLevelError(error)) {\n const message =\n error instanceof Error && error.message ? error.message : 'Network request failed';\n return new OllamaNetworkError(message, {\n cause: error,\n request: context.request,\n });\n }\n if (error instanceof TypeError) {\n return new OllamaNetworkError(error.message || 'Network request failed', {\n cause: error,\n request: context.request,\n });\n }\n if (context.response?.status !== undefined) {\n const message = error instanceof Error ? error.message : String(error);\n return statusToError(context.response.status, message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new OllamaGenericClientError(message, {\n cause: error,\n request: context.request,\n response: context.response,\n });\n}\n","/**\n * Lightweight frontmatter parser for SKILL.md files.\n */\n\nimport { OllamaSkillInvalidError } from '../errors.js';\nimport type { SkillFrontmatter } from './types.js';\n\nexport interface ParsedFrontmatter {\n readonly frontmatter: SkillFrontmatter;\n readonly body: string;\n}\n\nfunction parseYamlValue(raw: string): unknown {\n const trimmed = raw.trim();\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n if (!Number.isNaN(Number(trimmed)) && trimmed !== '') return Number(trimmed);\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\nfunction parseYamlBlock(yamlText: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = yamlText.split('\\n');\n let currentKey: string | undefined;\n let currentList: unknown[] | undefined;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n if (trimmed.startsWith('- ') && currentKey) {\n if (!currentList) {\n currentList = [];\n result[currentKey] = currentList;\n }\n currentList.push(parseYamlValue(trimmed.slice(2)));\n continue;\n }\n\n currentList = undefined;\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim();\n const valStr = line.slice(colonIndex + 1).trim();\n currentKey = key;\n if (valStr.length > 0) {\n result[key] = parseYamlValue(valStr);\n }\n }\n }\n\n return result;\n}\n\nexport function parseFrontmatter(source: string, path = ''): ParsedFrontmatter {\n const match = source.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n if (!match) {\n throw new OllamaSkillInvalidError('Missing YAML frontmatter delimiters (---)', {\n skillName: path || 'unknown',\n path,\n });\n }\n\n const rawYaml = match[1] ?? '';\n const body = match[2]?.trim() ?? '';\n const parsed = parseYamlBlock(rawYaml);\n\n if (!parsed['name'] || typeof parsed['name'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"name\"', {\n skillName: String(parsed['name'] ?? 'unknown'),\n path,\n });\n }\n if (!parsed['description'] || typeof parsed['description'] !== 'string') {\n throw new OllamaSkillInvalidError('Frontmatter missing required string \"description\"', {\n skillName: parsed['name'],\n path,\n });\n }\n\n return {\n frontmatter: parsed as unknown as SkillFrontmatter,\n body,\n };\n}\n","/**\n * Skill composition and context injection.\n */\n\nimport type { Message } from '../types.js';\nimport type { ToolRegistry } from '../tools/registry.js';\nimport type { Skill } from './types.js';\n\nexport interface ApplySkillOptions {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\nexport interface AppliedSkillResult {\n readonly messages: readonly Message[];\n readonly tools?: ToolRegistry;\n}\n\n/**\n * Injects a skill's body into messages as a system prompt and applies allowed tool filters.\n */\nexport function applySkill(skill: Skill, options: ApplySkillOptions): AppliedSkillResult {\n const systemPrompt = `[Skill: ${skill.name}]\\n${skill.description}\\n\\n${skill.body}`;\n const messages = [...options.messages];\n const systemIndex = messages.findIndex((m) => m.role === 'system');\n\n if (systemIndex >= 0) {\n const existing = messages[systemIndex];\n if (existing) {\n messages[systemIndex] = {\n role: 'system',\n content: `${existing.content}\\n\\n${systemPrompt}`,\n };\n }\n } else {\n messages.unshift({ role: 'system', content: systemPrompt });\n }\n\n return {\n messages,\n ...(options.tools !== undefined ? { tools: options.tools } : {}),\n };\n}\n","/**\n * Node.js filesystem skill registry for SKILL.md packages.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { OllamaSkillNotFoundError } from '../errors.js';\nimport { parseFrontmatter } from './frontmatter.js';\nimport type { Skill, SkillSummary } from './types.js';\n\nexport interface SkillRegistryOptions {\n readonly directory: string;\n}\n\nexport class SkillRegistry {\n readonly directory: string;\n\n constructor(options: SkillRegistryOptions) {\n this.directory = options.directory;\n }\n\n async list(): Promise<SkillSummary[]> {\n const entries = await readdir(this.directory, { withFileTypes: true });\n const summaries: SkillSummary[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillPath = join(this.directory, entry.name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n summaries.push({\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n });\n } catch {\n // Skip directories without valid SKILL.md\n }\n }\n\n return summaries;\n }\n\n async load(name: string): Promise<Skill> {\n const skillPath = join(this.directory, name, 'SKILL.md');\n try {\n const content = await readFile(skillPath, 'utf-8');\n const parsed = parseFrontmatter(content, skillPath);\n return {\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillPath,\n frontmatter: parsed.frontmatter,\n body: parsed.body,\n allowedTools: parsed.frontmatter['allowed-tools'],\n };\n } catch (err) {\n throw new OllamaSkillNotFoundError(`Skill \"${name}\" not found at ${skillPath}`, {\n skillName: name,\n cause: err,\n });\n }\n }\n}\n"]}
|
|
@@ -173,6 +173,11 @@ interface ModelOptions {
|
|
|
173
173
|
readonly top_p?: number | undefined;
|
|
174
174
|
readonly min_p?: number | undefined;
|
|
175
175
|
readonly tfs_z?: number | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* @deprecated Upstream dropped `typical_p` from the documented generation options
|
|
178
|
+
* (absent from the pinned OpenAPI); the generated contract omits it. Kept here for
|
|
179
|
+
* wire compatibility with older servers — new code should not set it.
|
|
180
|
+
*/
|
|
176
181
|
readonly typical_p?: number | undefined;
|
|
177
182
|
readonly repeat_last_n?: number | undefined;
|
|
178
183
|
readonly temperature?: number | undefined;
|
|
@@ -260,6 +265,11 @@ interface GenerateRequestOptions extends RequestCancellationOptions {
|
|
|
260
265
|
readonly suffix?: string | undefined;
|
|
261
266
|
readonly system?: string | undefined;
|
|
262
267
|
readonly template?: string | undefined;
|
|
268
|
+
/**
|
|
269
|
+
* @deprecated Legacy generate state-passing (token id array). Upstream no longer
|
|
270
|
+
* documents it and the generated contract omits it; conversation state belongs in
|
|
271
|
+
* `/api/chat` messages (`client.chat()`).
|
|
272
|
+
*/
|
|
263
273
|
readonly context?: readonly number[] | undefined;
|
|
264
274
|
readonly stream?: boolean | undefined;
|
|
265
275
|
readonly raw?: boolean | undefined;
|
|
@@ -173,6 +173,11 @@ interface ModelOptions {
|
|
|
173
173
|
readonly top_p?: number | undefined;
|
|
174
174
|
readonly min_p?: number | undefined;
|
|
175
175
|
readonly tfs_z?: number | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* @deprecated Upstream dropped `typical_p` from the documented generation options
|
|
178
|
+
* (absent from the pinned OpenAPI); the generated contract omits it. Kept here for
|
|
179
|
+
* wire compatibility with older servers — new code should not set it.
|
|
180
|
+
*/
|
|
176
181
|
readonly typical_p?: number | undefined;
|
|
177
182
|
readonly repeat_last_n?: number | undefined;
|
|
178
183
|
readonly temperature?: number | undefined;
|
|
@@ -260,6 +265,11 @@ interface GenerateRequestOptions extends RequestCancellationOptions {
|
|
|
260
265
|
readonly suffix?: string | undefined;
|
|
261
266
|
readonly system?: string | undefined;
|
|
262
267
|
readonly template?: string | undefined;
|
|
268
|
+
/**
|
|
269
|
+
* @deprecated Legacy generate state-passing (token id array). Upstream no longer
|
|
270
|
+
* documents it and the generated contract omits it; conversation state belongs in
|
|
271
|
+
* `/api/chat` messages (`client.chat()`).
|
|
272
|
+
*/
|
|
263
273
|
readonly context?: readonly number[] | undefined;
|
|
264
274
|
readonly stream?: boolean | undefined;
|
|
265
275
|
readonly raw?: boolean | undefined;
|