@nemesis-oss/ollama-sdk 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +168 -1
  2. package/README.md +181 -10
  3. package/dist/anthropic-5oYIRS6D.d.ts +1649 -0
  4. package/dist/anthropic-BIh45UXj.d.cts +1649 -0
  5. package/dist/{compose-DLStUfaF.d.ts → compose-DCVYMvOL.d.ts} +1 -1
  6. package/dist/{compose-DS-UWFx8.d.cts → compose-Dj6FdF2n.d.cts} +1 -1
  7. package/dist/generated-api.cjs +116 -9
  8. package/dist/generated-api.cjs.map +1 -1
  9. package/dist/generated-api.d.cts +321 -630
  10. package/dist/generated-api.d.ts +321 -630
  11. package/dist/generated-api.js +112 -10
  12. package/dist/generated-api.js.map +1 -1
  13. package/dist/generated-models-schemas.cjs +151 -3
  14. package/dist/generated-models-schemas.cjs.map +1 -1
  15. package/dist/generated-models-schemas.d.cts +228 -3
  16. package/dist/generated-models-schemas.d.ts +228 -3
  17. package/dist/generated-models-schemas.js +134 -4
  18. package/dist/generated-models-schemas.js.map +1 -1
  19. package/dist/generated-runtime.cjs +679 -60
  20. package/dist/generated-runtime.cjs.map +1 -1
  21. package/dist/generated-runtime.d.cts +22 -24
  22. package/dist/generated-runtime.d.ts +22 -24
  23. package/dist/generated-runtime.js +678 -61
  24. package/dist/generated-runtime.js.map +1 -1
  25. package/dist/index.cjs +2468 -132
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +1666 -864
  28. package/dist/index.d.ts +1666 -864
  29. package/dist/index.js +2432 -133
  30. package/dist/index.js.map +1 -1
  31. package/dist/mcp/tools.json +306 -73
  32. package/dist/mcp-generated.cjs +138 -7
  33. package/dist/mcp-generated.cjs.map +1 -1
  34. package/dist/mcp-generated.d.cts +2 -2
  35. package/dist/mcp-generated.d.ts +2 -2
  36. package/dist/mcp-generated.js +138 -7
  37. package/dist/mcp-generated.js.map +1 -1
  38. package/dist/{runtime-qwD72cpn.d.ts → runtime-C3rfpkZw.d.ts} +286 -5
  39. package/dist/{runtime-bQ48I-RC.d.cts → runtime-D2W9TfCJ.d.cts} +286 -5
  40. package/dist/skills.cjs.map +1 -1
  41. package/dist/skills.d.cts +3 -3
  42. package/dist/skills.d.ts +3 -3
  43. package/dist/skills.js.map +1 -1
  44. package/dist/{types-5PAjLoCp.d.cts → types-DVcX_zMp.d.cts} +110 -10
  45. package/dist/{types-5PAjLoCp.d.ts → types-DVcX_zMp.d.ts} +110 -10
  46. package/package.json +9 -5
package/dist/index.d.cts CHANGED
@@ -1,14 +1,127 @@
1
- import { F as FetchLike, M as Middleware, L as Logger, R as RequestLifecycleHook, H as HttpClient, c as OllamaStreamEvent, A as AbortableAsyncIterable, d as OllamaStreamEventType, P as ProgressStreamResult, B as BinaryBody, e as SseEvent, f as OllamaClientError, O as OllamaRuntime, C as ChatStreamResult, G as GenerateStreamResult, g as RawUsageSource, T as TokenUsage } from './runtime-bQ48I-RC.cjs';
2
- export { D as DoneEvent, E as ErrorEvent, h as HttpBody, i as HttpClientOptions, j as HttpRequestOptions, k as LifecycleErrorEvent, l as LifecycleRetryEvent, m as LifecycleStartEvent, n as LifecycleSuccessEvent, o as LogFn, p as MessageEvent, q as MiddlewareContext, N as NANOS_PER_MS, r as NANOS_PER_SECOND, s as NOOP_LOGGER, t as NextFunction, u as OllamaAbortError, v as OllamaAgentMaxIterationsError, w as OllamaAgentMaxToolCallsError, x as OllamaAuthError, y as OllamaClientErrorOptions, z as OllamaErrorRequestContext, J as OllamaErrorResponseContext, K as OllamaGenericClientError, Q as OllamaIncompatibleModelError, U as OllamaMcpError, V as OllamaModelRoutingError, W as OllamaNetworkError, X as OllamaNotFoundError, Y as OllamaQuotaExceededError, Z as OllamaRateLimitError, _ as OllamaRequestValidationError, $ as OllamaServerError, a0 as OllamaSkillInvalidError, a1 as OllamaSkillNotFoundError, a2 as OllamaTimeoutError, a3 as OllamaToolTimeoutError, a4 as OllamaToolValidationError, a5 as OllamaUnsupportedCapabilityError, a6 as RequestContext, a7 as RequestLifecycleEvent, a8 as ResponseContext, a9 as ThinkingEvent, aa as TokenEvent, ab as ToolCallEvent, ac as composeMiddleware, ad as createConsoleLogger, ae as extractUsage, af as mapError, ag as parseSseStream } from './runtime-bQ48I-RC.cjs';
3
- import { T as ThinkingMetadata, M as ModelResponse, S as ShowRequestOptions, a as ShowResponse, P as PullRequestOptions, b as ProgressResponse, c as PushRequestOptions, C as CreateRequestOptions, D as DeleteRequestOptions, d as StatusResponse, e as CopyRequestOptions, f as PsResponse, V as VersionResponse, g as ChatRequestOptions, h as ChatResponse, G as GenerateRequestOptions, i as GenerateResponse, E as EmbedRequestOptions, j as EmbedResponse, k as EmbeddingsRequestOptions, l as EmbeddingsResponse, W as WebSearchRequestOptions, m as WebSearchResponse, n as WebFetchRequestOptions, o as WebFetchResponse, p as ToolDefinition, q as ToolCall, r as Message, s as ModelOptions, t as ThinkValue } from './types-5PAjLoCp.cjs';
4
- export { F as FormatOption, L as ListResponse, u as Logprob, v as LogprobToken, w as ModelDetails, R as RequestCancellationOptions, x as Role, y as ToolCallFunction, z as ToolFunctionDefinition, A as ToolParameters, B as ToolProperty, H as WebSearchResult } from './types-5PAjLoCp.cjs';
1
+ import { F as FetchLike, M as Middleware, L as Logger, R as RequestLifecycleHook, H as HttpClient, c as OllamaStreamEvent, A as AbortableAsyncIterable, d as OllamaStreamEventType, P as ProgressStreamResult, B as BinaryBody, O as OllamaRuntime, C as ChatStreamResult, G as GenerateStreamResult, e as RawUsageSource, T as TokenUsage } from './runtime-D2W9TfCJ.cjs';
2
+ export { D as DoneEvent, E as ErrorEvent, f as HttpBody, g as HttpClientOptions, h as HttpRequestOptions, i as LifecycleErrorEvent, j as LifecycleRetryEvent, k as LifecycleStartEvent, l as LifecycleSuccessEvent, m as LogFn, n as MessageEvent, o as MiddlewareContext, N as NANOS_PER_MS, p as NANOS_PER_SECOND, q as NOOP_LOGGER, r as NextFunction, s as OllamaAbortError, t as OllamaAgentMaxIterationsError, u as OllamaAgentMaxToolCallsError, v as OllamaAuthError, w as OllamaBadGatewayError, x as OllamaClientError, y as OllamaClientErrorOptions, z as OllamaErrorRequestContext, J as OllamaErrorResponseContext, K as OllamaGenericClientError, Q as OllamaIncompatibleModelError, U as OllamaMcpError, V as OllamaModelRoutingError, W as OllamaNetworkError, X as OllamaNotFoundError, Y as OllamaOverloadedError, Z as OllamaQuotaExceededError, _ as OllamaRateLimitError, $ as OllamaRequestTooLargeError, a0 as OllamaRequestValidationError, a1 as OllamaResponseValidationError, a2 as OllamaServerError, a3 as OllamaServerVersionUnknownError, a4 as OllamaSkillInvalidError, a5 as OllamaSkillNotFoundError, a6 as OllamaStreamError, a7 as OllamaTimeoutError, a8 as OllamaToolTimeoutError, a9 as OllamaToolValidationError, aa as OllamaUnsupportedCapabilityError, ab as RequestContext, ac as RequestLifecycleEvent, ad as ResponseContext, ae as SseEvent, af as ThinkingEvent, ag as TokenEvent, ah as ToolCallEvent, ai as composeMiddleware, aj as createConsoleLogger, ak as extractUsage, al as mapError, am as parseSseStream } from './runtime-D2W9TfCJ.cjs';
3
+ import { T as ThinkingMetadata, M as ModelResponse, S as ShowRequestOptions, a as ShowResponse, P as PullRequestOptions, b as ProgressResponse, c as PushRequestOptions, C as CreateRequestOptions, D as DeleteRequestOptions, d as StatusResponse, e as CopyRequestOptions, f as PsResponse, V as VersionResponse, R as RequestCancellationOptions, g as ToolParameters, h as ThinkValue, i as ToolCall, j as ChatRequestOptions, k as ModelOptions, l as ToolDefinition, F as FormatOption, m as ChatResponse, n as Message, G as GenerateRequestOptions, o as GenerateResponse, E as EmbedRequestOptions, p as EmbedResponse, q as EmbeddingsRequestOptions, r as EmbeddingsResponse, W as WebSearchRequestOptions, s as WebSearchResponse, t as WebFetchRequestOptions, u as WebFetchResponse, U as UsageRequestOptions, B as BalanceRequestOptions, v as VisionInput } from './types-DVcX_zMp.cjs';
4
+ export { L as ListResponse, w as Logprob, x as LogprobToken, y as ModelDetails, z as Role, A as ToolCallFunction, H as ToolFunctionDefinition, I as ToolProperty, J as UsageRange, K as UsageScope, N as WebSearchResult, O as imageStringNeedsResolution, Q as resolveImageInput } from './types-DVcX_zMp.cjs';
5
5
  import { z } from 'zod';
6
- import { T as ToolHandler, a as Tool, A as AnyTool, b as ToolRegistry, c as ToolExecutionResult } from './compose-DS-UWFx8.cjs';
7
- export { d as AppliedSkillResult, e as ApplySkillOptions, P as ParsedFrontmatter, S as Skill, f as SkillFrontmatter, g as SkillSummary, h as ToolExecutionContext, i as ToolExecutionFailure, j as ToolExecutionSuccess, k as ToolRegistryOptions, l as applySkill, p as parseFrontmatter } from './compose-DS-UWFx8.cjs';
6
+ import { R as RequestRunner, S as SystemOneChoiceAnswer, o as SystemOneNoulAnswer, p as SystemOneScoreAnswer, q as SystemOneChoiceQuestion, r as SystemOneNoulQuestion, s as SystemOneScoreQuestion, t as SystemOneRequest$1, u as SystemOneResponse$1, v as SystemOneContent, N as NativeApi, w as OpenAICompatClient, x as AnthropicCompatClient } from './anthropic-BIh45UXj.cjs';
7
+ export { y as AnthropicCacheControl, z as AnthropicContentBlock, B as AnthropicImageContentBlock, C as AnthropicMessage, n as AnthropicMessageStreamEvent, A as AnthropicMessagesRequest, m as AnthropicMessagesResponse, D as AnthropicMessagesStream, E as AnthropicMetadata, F as AnthropicOutputConfig, G as AnthropicRedactedThinkingContentBlock, H as AnthropicSystem, I as AnthropicSystemTextBlock, J as AnthropicTextContentBlock, K as AnthropicThinkingConfig, L as AnthropicThinkingContentBlock, M as AnthropicTool, P as AnthropicToolChoice, Q as AnthropicToolResultContentBlock, T as AnthropicToolUseContentBlock, U as AnthropicUnknownStreamEvent, V as OllamaAnthropicContentBlock, W as OllamaAnthropicMessage, X as OllamaAnthropicMessagesRequest, Y as OllamaAnthropicSystem, Z as OllamaAnthropicSystemTextBlock, _ as OllamaAnthropicTextContentBlock, $ as OllamaAnthropicThinkingConfig, a0 as OllamaAnthropicTool, a1 as OllamaAnthropicToolResultContentBlock, a2 as OllamaOpenAIChatCompletionRequest, a3 as OllamaOpenAICompletionRequest, a4 as OllamaOpenAIEmbeddingRequest, a5 as OllamaOpenAIReasoningEffort, a6 as OllamaOpenAIResponsesRequest, a7 as OpenAIChatCompletionChoice, b as OpenAIChatCompletionChunk, a8 as OpenAIChatCompletionChunkChoice, a9 as OpenAIChatCompletionDelta, O as OpenAIChatCompletionRequest, a as OpenAIChatCompletionResponse, aa as OpenAIChatCompletionStream, ab as OpenAICompletionChoice, e as OpenAICompletionChunk, c as OpenAICompletionRequest, d as OpenAICompletionResponse, ac as OpenAICompletionStream, ad as OpenAIContentPart, ae as OpenAIEmbeddingInput, af as OpenAIEmbeddingItem, f as OpenAIEmbeddingRequest, g as OpenAIEmbeddingResponse, ag as OpenAIFunctionDefinition, ah as OpenAIImageUrlContentPart, h as OpenAIListModelsResponse, ai as OpenAIMessage, i as OpenAIModelItem, aj as OpenAIReasoningEffort, ak as OpenAIResponseFormat, al as OpenAIResponsesCompletedEvent, am as OpenAIResponsesContentPartAddedEvent, an as OpenAIResponsesContentPartDoneEvent, ao as OpenAIResponsesCreatedEvent, ap as OpenAIResponsesError, aq as OpenAIResponsesEventBase, ar as OpenAIResponsesFailedEvent, as as OpenAIResponsesFunctionCallArgumentsDeltaEvent, at as OpenAIResponsesFunctionCallArgumentsDoneEvent, au as OpenAIResponsesInProgressEvent, av as OpenAIResponsesIncompleteDetails, aw as OpenAIResponsesIncompleteEvent, ax as OpenAIResponsesOutputContent, ay as OpenAIResponsesOutputFunctionCall, az as OpenAIResponsesOutputItem, aA as OpenAIResponsesOutputItemAddedEvent, aB as OpenAIResponsesOutputItemDoneEvent, aC as OpenAIResponsesOutputMessage, aD as OpenAIResponsesOutputReasoning, aE as OpenAIResponsesOutputRefusal, aF as OpenAIResponsesOutputTextContent, aG as OpenAIResponsesOutputTextDeltaEvent, aH as OpenAIResponsesOutputTextDoneEvent, aI as OpenAIResponsesQueuedEvent, aJ as OpenAIResponsesReasoningSummaryPartAddedEvent, aK as OpenAIResponsesReasoningSummaryPartDoneEvent, aL as OpenAIResponsesReasoningSummaryTextDeltaEvent, aM as OpenAIResponsesReasoningSummaryTextDoneEvent, aN as OpenAIResponsesReasoningTextDeltaEvent, aO as OpenAIResponsesReasoningTextDoneEvent, aP as OpenAIResponsesRefusalDeltaEvent, aQ as OpenAIResponsesRefusalDoneEvent, j as OpenAIResponsesRequest, k as OpenAIResponsesResponse, aR as OpenAIResponsesStatus, aS as OpenAIResponsesStream, aT as OpenAIResponsesStreamError, l as OpenAIResponsesStreamEvent, aU as OpenAIResponsesUsage, aV as OpenAIStreamOptions, aW as OpenAITextContentPart, aX as OpenAITool, aY as OpenAIToolCall, aZ as OpenAIToolCallDelta, a_ as OpenAIUsage, a$ as SystemOneConfidence, b0 as SystemOneProbabilities } from './anthropic-BIh45UXj.cjs';
8
+ import { T as ToolHandler, a as Tool, A as AnyTool, b as ToolRegistry, c as ToolExecutionResult } from './compose-Dj6FdF2n.cjs';
9
+ export { d as AppliedSkillResult, e as ApplySkillOptions, P as ParsedFrontmatter, S as Skill, f as SkillFrontmatter, g as SkillSummary, h as ToolExecutionContext, i as ToolExecutionFailure, j as ToolExecutionSuccess, k as ToolRegistryOptions, l as applySkill, p as parseFrontmatter } from './compose-Dj6FdF2n.cjs';
8
10
  import { M as McpClientLike, a as McpToolDescriptor, b as McpTask, c as McpCallToolResult } from './types-CI-gM2u5.cjs';
9
11
  export { d as McpContentBlock, e as McpCreateTaskResult, f as McpElicitationFormRequest, g as McpElicitationHandlers, h as McpElicitationRequest, i as McpElicitationResult, j as McpElicitationUrlRequest, k as McpIcon, l as McpInputRequiredResult, m as McpListToolsParams, n as McpListToolsResult, o as McpRequestOptions, p as McpServerCapabilities, q as McpTaskMethod, r as McpTaskRequest, s as McpTaskStatus, t as McpToolAnnotations, u as McpToolCallResult, v as McpToolExecution } from './types-CI-gM2u5.cjs';
10
12
  import * as Otel from '@opentelemetry/api';
11
13
 
14
+ /**
15
+ * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
16
+ * Source: contracts/ir/ollama.ir.json (canonical Ollama IR).
17
+ * See ADR 0013 and ADR 0014 for the contract-first architecture.
18
+ */
19
+
20
+ interface BalanceResponse {
21
+ readonly included: IncludedBalance | LegacyIncludedBalance;
22
+ readonly purchased: {
23
+ /** Remaining unexpired purchased credits in USD. */
24
+ readonly balance_usd: number;
25
+ };
26
+ }
27
+
28
+ /**
29
+ * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
30
+ * Source: contracts/ir/ollama.ir.json (canonical Ollama IR).
31
+ * See ADR 0013 and ADR 0014 for the contract-first architecture.
32
+ */
33
+ interface IncludedBalance {
34
+ /** Remaining included credits in USD. */
35
+ readonly balance_usd: number;
36
+ /** Included credits available for the full period in USD. */
37
+ readonly allowance_usd: number;
38
+ readonly period: {
39
+ /** Start of the included period in UTC, inclusive. */
40
+ readonly from: string;
41
+ /** End of the included period in UTC, exclusive. */
42
+ readonly until: string;
43
+ };
44
+ }
45
+
46
+ /**
47
+ * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
48
+ * Source: contracts/ir/ollama.ir.json (canonical Ollama IR).
49
+ * See ADR 0013 and ADR 0014 for the contract-first architecture.
50
+ */
51
+ interface LegacyBalanceLimit {
52
+ /** Percentage of the limit remaining. */
53
+ readonly remaining_percent: number;
54
+ /** Next reset time in UTC. */
55
+ readonly resets_at: string;
56
+ }
57
+
58
+ /**
59
+ * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
60
+ * Source: contracts/ir/ollama.ir.json (canonical Ollama IR).
61
+ * See ADR 0013 and ADR 0014 for the contract-first architecture.
62
+ */
63
+
64
+ interface LegacyIncludedBalance {
65
+ readonly session: LegacyBalanceLimit;
66
+ readonly weekly: LegacyBalanceLimit;
67
+ }
68
+
69
+ /**
70
+ * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
71
+ * Source: contracts/ir/ollama.ir.json (canonical Ollama IR).
72
+ * See ADR 0013 and ADR 0014 for the contract-first architecture.
73
+ */
74
+
75
+ type UsageBucket = UsageMetrics & {
76
+ /** Start of the bucket in UTC, inclusive. */
77
+ readonly from: string;
78
+ /** End of the bucket in UTC, exclusive. */
79
+ readonly until: string;
80
+ /** Present and true for the current hour or day, which is still in progress. */
81
+ readonly partial?: boolean | undefined;
82
+ };
83
+
84
+ /**
85
+ * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
86
+ * Source: contracts/ir/ollama.ir.json (canonical Ollama IR).
87
+ * See ADR 0013 and ADR 0014 for the contract-first architecture.
88
+ */
89
+ interface UsageMetrics {
90
+ /** Number of recorded requests. */
91
+ readonly request_count: number;
92
+ /** Total value of the requests in USD, including usage covered by your plan and usage paid from purchased credits. */
93
+ readonly usage_usd?: number | undefined;
94
+ /** Recorded input tokens, including cached input tokens. */
95
+ readonly input_tokens?: number | undefined;
96
+ /** Recorded input tokens read from cache, already included in input_tokens. */
97
+ readonly cached_input_tokens?: number | undefined;
98
+ /** Recorded output tokens. */
99
+ readonly output_tokens?: number | undefined;
100
+ }
101
+
102
+ /**
103
+ * AUTO-GENERATED by `npm run contract:generate`. DO NOT EDIT.
104
+ * Source: contracts/ir/ollama.ir.json (canonical Ollama IR).
105
+ * See ADR 0013 and ADR 0014 for the contract-first architecture.
106
+ */
107
+
108
+ interface UsageResponse {
109
+ /** Selected time range. */
110
+ readonly range: '24h' | '7d' | '30d';
111
+ /** Selected usage scope. */
112
+ readonly scope: 'self' | 'team';
113
+ /** Set automatically - hour for 24h, day for 7d and 30d. */
114
+ readonly granularity: 'hour' | 'day';
115
+ /** Start of the range in UTC, inclusive. */
116
+ readonly from: string;
117
+ /** End of the range in UTC, exclusive. */
118
+ readonly until: string;
119
+ /** Usage across the entire range. */
120
+ readonly totals: UsageMetrics;
121
+ /** Usage in chronological order, including buckets with no recorded requests. */
122
+ readonly buckets: readonly UsageBucket[];
123
+ }
124
+
12
125
  /**
13
126
  * Exponential backoff with full jitter calculation.
14
127
  */
@@ -289,6 +402,31 @@ interface OllamaClientConfig {
289
402
  readonly logger?: Logger;
290
403
  /** Enables console debug logger if true. */
291
404
  readonly debug?: boolean;
405
+ /**
406
+ * Default context window (`num_ctx`) applied to every `chat`/`generate`
407
+ * request that doesn't set `options.num_ctx` itself. Injected as
408
+ * `options.num_ctx` on the wire, making the effective window explicit
409
+ * instead of leaving it to Ollama's server default (commonly 2048–4096,
410
+ * model-dependent) — which **silently truncates** prompts that don't fit,
411
+ * with no error and no warning. See `src/context-safety.ts`.
412
+ */
413
+ readonly defaultContextLength?: number;
414
+ /**
415
+ * Fraction of the effective context window at which the client warns that
416
+ * a request's estimated prompt size is approaching truncation (default
417
+ * `0.9` — see `DEFAULT_CONTEXT_WARNING_THRESHOLD`).
418
+ */
419
+ readonly contextWarningThreshold?: number;
420
+ /**
421
+ * What happens when the pre-flight context check (see
422
+ * `src/context-safety.ts`) concludes a request will likely be truncated:
423
+ * `'warn'` (default) logs a warning through the configured logger and sends
424
+ * the request anyway; `'throw'` rejects the request client-side with
425
+ * `OllamaClientError` before anything hits the wire. `'throw'` is the
426
+ * safety-critical choice — use it when silent history truncation would
427
+ * corrupt application behavior (e.g. long-context RAG, agents).
428
+ */
429
+ readonly onContextOverflow?: 'warn' | 'throw';
292
430
  /** Request lifecycle hook for telemetry/metrics. */
293
431
  readonly onLifecycleEvent?: RequestLifecycleHook;
294
432
  }
@@ -312,6 +450,20 @@ declare function checkEndpointHealth(endpoint: OllamaEndpoint, fetchImpl?: Fetch
312
450
  */
313
451
 
314
452
  type RuntimeMode = 'local' | 'cloud' | 'unknown';
453
+ /**
454
+ * Best-effort classification of a model's parallel tool-call emission
455
+ * behavior. Used by agent loops that need to know whether the model
456
+ * is likely to emit multiple `tool_calls` in a single assistant
457
+ * message (parallel) or one-at-a-time (sequential).
458
+ *
459
+ * This is a **heuristic** derived from runtime mode + model family
460
+ * pattern matching against `/api/show`'s reported model_info. The
461
+ * SDK does NOT normalize between cloud and local — it reports the
462
+ * best assessment it can and lets the caller decide how to act.
463
+ *
464
+ * See ADR 0023 for the rationale and the recommended caller pattern.
465
+ */
466
+ type ParallelToolCallBehavior = 'yes' | 'no' | 'unknown';
315
467
  interface ModelCapabilities {
316
468
  readonly model: string;
317
469
  readonly reported: readonly string[];
@@ -336,6 +488,44 @@ interface ModelCapabilities {
336
488
  * making a network call that Ollama Cloud is known to reject.
337
489
  */
338
490
  readonly supportsStructuredOutputRequest: boolean;
491
+ /**
492
+ * Best-effort inference of whether the model is likely to emit
493
+ * **multiple `tool_calls` in a single assistant message** (parallel)
494
+ * vs **one tool call per assistant turn** (sequential).
495
+ *
496
+ * The SDK does NOT normalize between cloud and local — it reports
497
+ * the best assessment it can and lets the caller decide. Agent
498
+ * authors who need hard sequential execution should set
499
+ * `ToolRegistry`'s `maxConcurrency: 1` regardless of this field's
500
+ * value, since the model's behavior is not deterministic across
501
+ * prompts.
502
+ *
503
+ * Inference matrix (see ADR 0023):
504
+ *
505
+ * - **`'yes'`** — the model is known to emit parallel tool calls:
506
+ * - Cloud-mode endpoints (the OpenAI/Anthropic compat bridges
507
+ * proxy to proprietary models like GPT-4o, Claude, which
508
+ * freely emit parallel tool calls).
509
+ * - Local models from families that ship with parallel-tool-call
510
+ * training (Qwen 2.5+, Llama 3.1+ tool-use variants, Mistral
511
+ * function-calling fine-tunes, Hermes 2/3, Command R+).
512
+ *
513
+ * - **`'no'`** — the model is known to emit at most one tool call
514
+ * per assistant turn. Currently no model family is classified
515
+ * as `'no'` by default; the field is reserved for future
516
+ * narrowing as more is learned about specific models.
517
+ *
518
+ * - **`'unknown'`** — the model family is not in the known-yes or
519
+ * known-no list, OR `/api/show` didn't return enough
520
+ * information to make an assessment. Callers should treat
521
+ * `'unknown'` as "ask the model and see what it does" — the
522
+ * `ToolRegistry` will execute whatever calls the model emits,
523
+ * in parallel via `Promise.all` by default.
524
+ *
525
+ * See: `src/tools/registry.ts` for `maxConcurrency` enforcement,
526
+ * and ADR 0023 for the full design rationale.
527
+ */
528
+ readonly parallelToolCalls: ParallelToolCallBehavior;
339
529
  }
340
530
  declare function inferRuntimeMode(baseUrl: string): RuntimeMode;
341
531
  declare function detectModelCapabilities(http: HttpClient, model: string, signal?: AbortSignal): Promise<ModelCapabilities>;
@@ -369,23 +559,17 @@ declare class OllamaStream<TChunk, TFinal> implements AsyncIterable<OllamaStream
369
559
  [Symbol.asyncIterator](): AsyncGenerator<OllamaStreamEvent<TChunk, TFinal>, void, undefined>;
370
560
  }
371
561
 
372
- /**
373
- * Shared request-runner contract used by native and compatibility clients.
374
- */
375
-
376
- type RequestRunner = <T>(op: (http: HttpClient, signal: AbortSignal) => Promise<T>, opts?: {
377
- readonly signal?: AbortSignal | undefined;
378
- readonly timeoutMs?: number | undefined;
379
- readonly singleEndpoint?: boolean | undefined;
380
- readonly model?: string | undefined;
381
- /** Defers endpoint capacity release until the returned promise settles. */
382
- readonly holdUntil?: ((result: T) => Promise<unknown>) | undefined;
383
- }) => Promise<T>;
384
-
385
562
  /**
386
563
  * Model and blob management operations.
387
564
  */
388
565
 
566
+ /** Result of a convenience blob upload ({@link ModelsClient.createBlobFromData}). */
567
+ interface BlobUploadResult {
568
+ /** Content digest (`sha256:<hex>`) of the uploaded payload. */
569
+ readonly digest: string;
570
+ /** True when the server already had this blob (HTTP 200) and skipped writing. */
571
+ readonly alreadyExisted: boolean;
572
+ }
389
573
  /**
390
574
  * Every operation here targets one specific Ollama server's local model catalog or blob
391
575
  * store — unlike `chat`/`generate`/`embed`, a different endpoint isn't an interchangeable
@@ -424,881 +608,764 @@ declare class ModelsClient {
424
608
  copy(request: CopyRequestOptions): Promise<StatusResponse>;
425
609
  ps(): Promise<PsResponse>;
426
610
  version(): Promise<VersionResponse>;
611
+ /**
612
+ * Immediately unloads `model` from VRAM/RAM by issuing an empty
613
+ * `/api/generate` request with `keep_alive: 0`. The server
614
+ * finalizes any in-flight generation, releases the model's
615
+ * weights from GPU memory, and frees the slot for subsequent
616
+ * pipelines (e.g. swap a vision encoder out before loading an
617
+ * LLM).
618
+ *
619
+ * This is the ergonomic equivalent of:
620
+ *
621
+ * ```ts
622
+ * client.generate({ model, prompt: '', keep_alive: 0 });
623
+ * ```
624
+ *
625
+ * Use {@link pin} for the opposite lifecycle — pinning a model
626
+ * indefinitely in VRAM for hot-loop inference.
627
+ *
628
+ * Resolves once the server acknowledges the unload. The promise
629
+ * rejects on transport errors, model-not-found (404), or auth
630
+ * failures — callers handling transient issues can retry via the
631
+ * standard {@link withRetry} policy.
632
+ *
633
+ * See: https://github.com/ollama/ollama/blob/main/docs/faq.md
634
+ * #how-do-i-keep-a-model-loaded-in-memory-or-make-it-unload-immediately
635
+ */
636
+ unload(model: string): Promise<void>;
637
+ /**
638
+ * Pre-loads and pins `model` into VRAM indefinitely by issuing an
639
+ * empty `/api/generate` request with `keep_alive: -1`. The server
640
+ * loads the model into GPU memory (paying the cold-load latency
641
+ * once) and keeps it resident until either:
642
+ *
643
+ * - an explicit {@link unload} call is made,
644
+ * - the server process is restarted, or
645
+ * - the host runs out of VRAM and the server's own eviction
646
+ * policy kicks in.
647
+ *
648
+ * This is the ergonomic equivalent of:
649
+ *
650
+ * ```ts
651
+ * client.generate({ model, prompt: '', keep_alive: -1 });
652
+ * ```
653
+ *
654
+ * Use {@link unload} to release the pinned slot when the hot loop
655
+ * is done — leaving models pinned indefinitely exhausts VRAM and
656
+ * starves subsequent pipelines.
657
+ *
658
+ * Resolves once the server acknowledges the pin (i.e. the model
659
+ * is fully loaded). The promise rejects on transport errors,
660
+ * model-not-found (404), or VRAM-exhaustion failures.
661
+ */
662
+ pin(model: string): Promise<void>;
427
663
  createBlob(digest: string, data: BinaryBody): Promise<void>;
428
664
  checkBlob(digest: string): Promise<boolean>;
665
+ /**
666
+ * Computes a blob digest the way Ollama's content-addressed store expects:
667
+ * SHA-256 over the raw bytes, formatted as `sha256:<64 lowercase hex>`.
668
+ *
669
+ * Uses the Web Crypto API (`crypto.subtle.digest`), which exists in every
670
+ * supported runtime — Node.js ≥ 19 exposes it as a global (this SDK
671
+ * requires Node ≥ 20), and browsers/edge runtimes have always had it.
672
+ */
673
+ computeBlobDigest(data: Uint8Array): Promise<string>;
674
+ /**
675
+ * Computes the SHA-256 digest of `data` and pushes it as a blob in one
676
+ * step — the content-addressed upload Ollama's own tooling performs
677
+ * (`curl -T file http://…/api/blobs/sha256:…`). Returns the digest, which
678
+ * `/api/create`'s `files` field references.
679
+ *
680
+ * Pass `digest` to skip recomputation when the caller already knows it —
681
+ * the server verifies the content against the digest and rejects mismatches.
682
+ */
683
+ createBlobFromData(data: Uint8Array, opts?: {
684
+ readonly digest?: string | undefined;
685
+ readonly signal?: AbortSignal | undefined;
686
+ }): Promise<BlobUploadResult>;
687
+ /**
688
+ * Reads a local file and uploads it as a blob (Node.js only — dynamic
689
+ * `node:fs` import, so browser bundles never pull it in). The file name
690
+ * (basename) is what `/api/create`'s `files` map expects as the key, so
691
+ * this returns it alongside the digest.
692
+ */
693
+ createBlobFromFile(path: string, opts?: {
694
+ readonly signal?: AbortSignal | undefined;
695
+ }): Promise<BlobUploadResult & {
696
+ readonly fileName: string;
697
+ }>;
698
+ /**
699
+ * One-shot custom-model publishing from raw GGUF weights, following the
700
+ * protocol Ollama's API reference documents: push a blob for the GGUF
701
+ * bytes, then `POST /api/create` with `files: { <fileName>: <digest> }`.
702
+ * Split GGUFs are supported via `files` — pass every shard's path.
703
+ *
704
+ * ```ts
705
+ * await client.models.createModelFromGguf('my-model', '/path/to/model.gguf', {
706
+ * template: '{{ .Prompt }}',
707
+ * });
708
+ * ```
709
+ *
710
+ * @param model Name for the new model (e.g. `'my-model:latest'`).
711
+ * @param gguf Path(s) to GGUF file(s) on the local filesystem.
712
+ * @param opts Everything else `/api/create` accepts (`template`, `system`,
713
+ * `parameters`, `license`, `quantize`, …) except `files` and `from`.
714
+ */
715
+ createModelFromGguf(model: string, gguf: string | readonly string[], opts?: Omit<CreateRequestOptions, 'model' | 'files' | 'from' | 'stream'>): Promise<ProgressResponse>;
429
716
  }
430
717
 
431
718
  /**
432
- * OpenAI Compatibility interfaces and client helpers for Ollama.
433
- * Ollama exposes OpenAI-compatible /v1 endpoints.
719
+ * Ergonomic OpenAI Responses API bridge — `client.responses.create()`.
434
720
  *
435
- * @remarks
436
- * This is a typed pass-through to Ollama's own OpenAI-compatible `/v1` endpoints — it
437
- * implements the subset of the OpenAI API surface that Ollama documents as supported
438
- * (https://docs.ollama.com/api/openai-compatibility), not the full OpenAI surface (hosted
439
- * tools like web/file search, computer use, code interpreter, or stateful server-side
440
- * conversation state). Notably, `tools` is supported by Ollama's compat layer but
441
- * `tool_choice` and `parallel_tool_calls` are not — both are still typed on
442
- * {@link OpenAIChatCompletionRequest} (accepted-but-ignored) so consumers passing a
443
- * standard OpenAI request object don't get spurious type errors; see the `@remarks` on
444
- * each field. `/v1/responses` is supported non-statefully — see
445
- * {@link OpenAIResponsesRequest}.
721
+ * Ollama (v0.13.3+) exposes OpenAI's Responses API at `POST /v1/responses` as
722
+ * a **stateless** compatibility endpoint: it accepts `model`, `input`,
723
+ * `instructions`, `tools`, `stream`, `temperature`, `top_p`,
724
+ * `max_output_tokens`, `reasoning.effort`, `truncation`, and the Ollama
725
+ * extension `think` — and rejects OpenAI's stateful `previous_response_id` /
726
+ * `conversation` fields, because every call is independent. Responses deliver
727
+ * text inside `output[] → message → content[] → output_text` blocks rather
728
+ * than chat-completion `choices`.
729
+ *
730
+ * This module wraps that endpoint with a small, OpenAI-SDK-shaped surface for
731
+ * teams migrating from `openai.responses.create()` — and adds a safety net the
732
+ * raw compat layer doesn't have: **dual-mode transport**.
733
+ *
734
+ * 1. **Native** — POST `/v1/responses` directly. Used when the server
735
+ * supports it (Ollama ≥ v0.13.3, or Ollama Cloud).
736
+ * 2. **Chat adapter** — on `404 Not Found` (older Ollama builds without the
737
+ * endpoint), the same request is transparently re-issued against
738
+ * `/api/chat` with `instructions` mapped to a system message,
739
+ * `max_output_tokens` to `options.num_predict`, and tools mapped to the
740
+ * native tool-definition shape. The response is normalized back into the
741
+ * Responses form (`output_text`, `usage.input_tokens`/`output_tokens`),
742
+ * so migrating code works unchanged against old servers.
743
+ *
744
+ * The `transport` field on the result records which path served the request.
745
+ *
746
+ * For the full OpenAI-shaped surface (stateful fields accepted-but-ignored,
747
+ * raw `output` items, SSE event objects), use `client.openai.responses()`
748
+ * instead — this module is the ergonomic subset.
446
749
  */
447
750
 
448
- interface OpenAIToolCall {
449
- readonly id: string;
450
- readonly type: 'function';
451
- readonly function: {
452
- readonly name: string;
453
- /** JSON-encoded arguments string, matching OpenAI's wire format (not a parsed object). */
454
- readonly arguments: string;
455
- };
456
- }
457
- interface OpenAITextContentPart {
458
- readonly type: 'text';
459
- readonly text: string;
460
- }
461
- interface OpenAIImageUrlContentPart {
462
- readonly type: 'image_url';
463
- /** Ollama accepts a data/image URL string or the standard OpenAI URL object. */
464
- readonly image_url: string | {
465
- readonly url: string;
466
- readonly detail?: 'auto' | 'low' | 'high' | 'original' | undefined;
467
- };
468
- }
469
- type OpenAIContentPart = OpenAITextContentPart | OpenAIImageUrlContentPart;
470
- interface OpenAIMessage {
471
- readonly role: 'system' | 'user' | 'assistant' | 'tool';
472
- readonly content: string | readonly OpenAIContentPart[];
473
- readonly name?: string | undefined;
474
- readonly tool_calls?: readonly OpenAIToolCall[] | undefined;
475
- /** Ollama may emit model reasoning alongside assistant content. */
476
- readonly reasoning?: string | undefined;
477
- /** Set on a `role: 'tool'` message to identify which call this is a result for. */
478
- readonly tool_call_id?: string | undefined;
479
- }
480
- interface OpenAIStreamOptions {
481
- /** Emit a final SSE chunk carrying `usage` (prompt/completion/total tokens) before `[DONE]`. */
482
- readonly include_usage?: boolean | undefined;
483
- }
484
- interface OpenAIFunctionDefinition {
751
+ /** Flat tool definition, matching the `openai` npm SDK's `tools[]` shape. */
752
+ interface ResponsesToolDefinition {
485
753
  readonly name: string;
486
754
  readonly description?: string | undefined;
487
- readonly parameters?: Record<string, unknown> | undefined;
488
- }
489
- interface OpenAITool {
490
- readonly type: 'function';
491
- readonly function: OpenAIFunctionDefinition;
492
- }
493
- type OpenAIReasoningEffort = 'high' | 'medium' | 'low' | 'max' | 'none' | 'minimal' | 'xhigh' | 'ultra' | (string & {});
494
- type OpenAIResponseFormat = {
495
- readonly type: 'text';
496
- } | {
497
- readonly type: 'json_object';
498
- } | {
499
- readonly type: 'json_schema';
500
- readonly json_schema: Record<string, unknown>;
501
- };
502
- interface OpenAIChatCompletionRequest {
503
- readonly model: string;
504
- readonly messages: readonly OpenAIMessage[];
505
- readonly temperature?: number | undefined;
506
- readonly top_p?: number | undefined;
507
- readonly stream?: boolean | undefined;
508
- /** Only meaningful when `stream: true`; ignored otherwise. */
509
- readonly stream_options?: OpenAIStreamOptions | undefined;
510
- readonly max_tokens?: number | undefined;
511
- readonly stop?: readonly string[] | undefined;
512
- readonly response_format?: OpenAIResponseFormat | undefined;
513
- readonly seed?: number | undefined;
514
- readonly presence_penalty?: number | undefined;
515
- readonly frequency_penalty?: number | undefined;
516
- readonly user?: string | undefined;
517
- readonly logit_bias?: Record<string, number> | undefined;
518
- readonly n?: number | undefined;
519
- /** Ollama exposes log probabilities for supported reasoning/chat models. */
520
- readonly logprobs?: boolean | undefined;
521
- readonly top_logprobs?: number | undefined;
522
- readonly tools?: readonly OpenAITool[] | undefined;
523
- /**
524
- * @remarks Accepted for OpenAI compatibility but ignored by Ollama — every tool the
525
- * model is given remains callable regardless of this value.
526
- */
527
- readonly tool_choice?: 'none' | 'auto' | 'required' | {
528
- readonly type: 'function';
529
- readonly function: {
530
- readonly name: string;
531
- };
532
- } | undefined;
533
- /**
534
- * @remarks Accepted for OpenAI compatibility but ignored by Ollama — Ollama does not
535
- * control tool-call parallelism through this flag.
536
- */
537
- readonly parallel_tool_calls?: boolean | undefined;
538
- /**
539
- * Effort level for thinking models (e.g. `deepseek-r1`, `qwen3`). Equivalent to
540
- * `reasoning.effort`; only effective for models that support reasoning/thinking.
541
- */
542
- readonly reasoning_effort?: OpenAIReasoningEffort | undefined;
543
- /**
544
- * Effort level for thinking models (e.g. `deepseek-r1`, `qwen3`), nested OpenAI-style.
545
- * Equivalent to `reasoning_effort`; only effective for models that support
546
- * reasoning/thinking.
547
- */
548
- readonly reasoning?: {
549
- readonly effort?: OpenAIReasoningEffort | undefined;
550
- } | undefined;
551
- }
552
- /** Ollama Chat Completions supports text plus base64 image content via a string image URL. */
553
- type OllamaOpenAIChatContentPart = OpenAITextContentPart | {
554
- readonly type: 'image_url';
555
- /** Ollama's current compatibility docs accept an image URL string, including data URLs. */
556
- readonly image_url: string;
557
- };
558
- type OllamaOpenAIReasoningEffort = 'high' | 'medium' | 'low' | 'max' | 'none';
559
- type OllamaOpenAIChatMessage = Omit<OpenAIMessage, 'content'> & {
560
- readonly content: string | readonly OllamaOpenAIChatContentPart[];
561
- };
562
- /** Strict Ollama-documented Chat Completions request; excludes only the SDK-only parallel tool flag. */
563
- type OllamaOpenAIChatCompletionRequest = Omit<OpenAIChatCompletionRequest, 'messages' | 'parallel_tool_calls' | 'reasoning_effort' | 'reasoning'> & {
564
- readonly messages: readonly OllamaOpenAIChatMessage[];
565
- readonly reasoning_effort?: OllamaOpenAIReasoningEffort | undefined;
566
- readonly reasoning?: {
567
- readonly effort?: OllamaOpenAIReasoningEffort | undefined;
568
- } | undefined;
569
- };
570
- interface OpenAIChatCompletionChoice {
571
- readonly index: number;
572
- readonly message: OpenAIMessage;
573
- readonly finish_reason: string;
574
- readonly logprobs?: Record<string, unknown> | null | undefined;
575
- }
576
- interface OpenAIToolCallDelta {
577
- readonly index: number;
578
- readonly id?: string | undefined;
579
- readonly type?: 'function' | undefined;
580
- readonly function?: {
581
- readonly name?: string | undefined;
582
- readonly arguments?: string | undefined;
583
- } | undefined;
584
- }
585
- interface OpenAIChatCompletionDelta {
586
- readonly role?: OpenAIMessage['role'] | undefined;
587
- readonly content?: string | null | undefined;
588
- readonly reasoning?: string | null | undefined;
589
- readonly refusal?: string | null | undefined;
590
- readonly tool_calls?: readonly OpenAIToolCallDelta[] | undefined;
591
- }
592
- interface OpenAIChatCompletionChunkChoice {
593
- readonly index: number;
594
- readonly delta: OpenAIChatCompletionDelta;
595
- readonly finish_reason?: string | null | undefined;
596
- readonly logprobs?: Record<string, unknown> | null | undefined;
597
- }
598
- interface OpenAIChatCompletionChunk {
599
- readonly id: string;
600
- readonly object: 'chat.completion.chunk';
601
- readonly created: number;
602
- readonly model: string;
603
- readonly system_fingerprint?: string | undefined;
604
- readonly choices: readonly OpenAIChatCompletionChunkChoice[];
605
- readonly usage?: {
606
- readonly prompt_tokens: number;
607
- readonly completion_tokens: number;
608
- readonly total_tokens: number;
609
- } | null | undefined;
610
- }
611
- interface OpenAIUsage {
612
- readonly prompt_tokens: number;
613
- readonly completion_tokens: number;
614
- readonly total_tokens: number;
615
- readonly prompt_tokens_details?: {
616
- readonly cached_tokens?: number | undefined;
617
- } | undefined;
618
- }
619
- interface OpenAIChatCompletionResponse {
620
- readonly id: string;
621
- readonly object: 'chat.completion';
622
- readonly created: number;
623
- readonly model: string;
624
- readonly system_fingerprint?: string | undefined;
625
- readonly choices: readonly OpenAIChatCompletionChoice[];
626
- readonly usage?: OpenAIUsage | undefined;
627
- }
628
- interface OpenAIModelItem {
629
- readonly id: string;
630
- readonly object: 'model';
631
- readonly created: number;
632
- readonly owned_by: string;
633
- }
634
- interface OpenAIListModelsResponse {
635
- readonly object: 'list';
636
- readonly data: readonly OpenAIModelItem[];
637
- }
638
- interface OpenAICompletionRequest {
639
- readonly model: string;
640
- /** Ollama currently accepts a string prompt for /v1/completions. */
641
- readonly prompt: string;
642
- /** Number of log probability alternatives requested for completion tokens. */
643
- readonly logprobs?: number | undefined;
644
- readonly frequency_penalty?: number | undefined;
645
- readonly presence_penalty?: number | undefined;
646
- readonly seed?: number | undefined;
647
- readonly stop?: readonly string[] | undefined;
648
- readonly stream?: boolean | undefined;
649
- readonly stream_options?: OpenAIStreamOptions | undefined;
650
- readonly temperature?: number | undefined;
651
- readonly top_p?: number | undefined;
652
- readonly max_tokens?: number | undefined;
653
- readonly suffix?: string | undefined;
654
- readonly best_of?: number | undefined;
655
- readonly echo?: boolean | undefined;
656
- readonly logit_bias?: Record<string, number> | undefined;
657
- readonly user?: string | undefined;
658
- readonly n?: number | undefined;
659
- }
660
- /** Strict Ollama-documented Completions request. */
661
- type OllamaOpenAICompletionRequest = OpenAICompletionRequest;
662
- interface OpenAICompletionChoice {
663
- readonly text: string;
664
- readonly index: number;
665
- readonly logprobs?: Record<string, unknown> | null | undefined;
666
- readonly finish_reason: string | null;
667
- }
668
- interface OpenAICompletionChunk {
669
- readonly id: string;
670
- readonly object: 'text_completion';
671
- readonly created: number;
672
- readonly model: string;
673
- readonly system_fingerprint?: string | undefined;
674
- readonly choices: readonly {
675
- readonly text: string;
676
- readonly index: number;
677
- readonly logprobs?: Record<string, unknown> | null | undefined;
678
- readonly finish_reason?: string | null | undefined;
679
- }[];
680
- readonly usage?: {
681
- readonly prompt_tokens: number;
682
- readonly completion_tokens: number;
683
- readonly total_tokens: number;
684
- } | null | undefined;
685
- }
686
- interface OpenAICompletionResponse {
687
- readonly id: string;
688
- readonly object: 'text_completion';
689
- readonly created: number;
690
- readonly model: string;
691
- readonly system_fingerprint?: string | undefined;
692
- readonly choices: readonly OpenAICompletionChoice[];
693
- readonly usage?: OpenAIUsage | undefined;
694
- }
695
- type OpenAIEmbeddingInput = string | readonly string[] | readonly number[] | readonly (readonly number[])[];
696
- interface OpenAIEmbeddingRequest {
697
- readonly model: string;
698
- readonly input: OpenAIEmbeddingInput;
699
- readonly encoding_format?: 'float' | 'base64' | undefined;
700
- readonly dimensions?: number | undefined;
701
- readonly user?: string | undefined;
702
- }
703
- /** Strict Ollama-documented Embeddings request. */
704
- type OllamaOpenAIEmbeddingRequest = OpenAIEmbeddingRequest;
705
- interface OpenAIEmbeddingItem {
706
- readonly object: 'embedding';
707
- readonly embedding: readonly number[] | string;
708
- readonly index: number;
709
- }
710
- interface OpenAIEmbeddingResponse {
711
- readonly object: 'list';
712
- readonly data: readonly OpenAIEmbeddingItem[];
713
- readonly model: string;
714
- readonly usage?: {
715
- readonly prompt_tokens: number;
716
- readonly total_tokens: number;
717
- } | undefined;
755
+ readonly parameters?: ToolParameters | undefined;
718
756
  }
757
+ /** Reasoning effort levels Ollama's `/v1/responses` accepts under `reasoning.effort`. */
758
+ type ResponsesReasoningEffort = 'low' | 'medium' | 'high';
719
759
  /**
720
- * Request body for OpenAI's Responses API (`/v1/responses`), added in Ollama v0.13.3.
721
- *
722
- * @remarks
723
- * Ollama implements this **non-statefully**: every call is independent, so
724
- * {@link previous_response_id} and {@link conversation} — OpenAI's mechanisms for
725
- * resuming server-side conversation state — are accepted for compatibility but ignored.
726
- * Send the full conversation in `input` on every call, the same as `/api/chat`.
760
+ * Ergonomic request for {@link ResponsesModule.create} — the subset of
761
+ * OpenAI's Responses API that Ollama supports, minus the stateful fields
762
+ * (`previous_response_id`, `conversation`) Ollama rejects.
727
763
  */
728
- interface OpenAIResponsesRequest {
764
+ interface ResponsesCreateRequest extends RequestCancellationOptions {
729
765
  readonly model: string;
730
- readonly input: string | readonly OpenAIMessage[];
766
+ /** The user prompt. Send the full conversation here — Ollama is stateless. */
767
+ readonly input: string;
768
+ /** System/developer instructions, mapped to a system message. */
731
769
  readonly instructions?: string | undefined;
732
- readonly tools?: readonly OpenAITool[] | undefined;
733
- readonly stream?: boolean | undefined;
770
+ readonly tools?: readonly ResponsesToolDefinition[] | undefined;
734
771
  readonly temperature?: number | undefined;
735
772
  readonly top_p?: number | undefined;
736
773
  readonly max_output_tokens?: number | undefined;
737
- /** @remarks Not supported by Ollama, which is stateless across calls — accepted but ignored. */
738
- readonly previous_response_id?: string | undefined;
739
- /** @remarks Not supported by Ollama, which is stateless across calls — accepted but ignored. */
740
- readonly conversation?: string | undefined;
741
- readonly truncation?: string | undefined;
742
- readonly reasoning?: {
743
- readonly effort?: OpenAIReasoningEffort | undefined;
744
- } | undefined;
745
- /** Ollama extension: boolean, model-defined string, or null for model default. */
746
- readonly think?: boolean | string | null | undefined;
747
- }
748
- /** Strict Ollama-documented Responses request; excludes stateful and SDK-only request fields. */
749
- /** Strict Ollama-documented Responses request; excludes only unsupported stateful fields. */
750
- type OllamaOpenAIResponsesRequest = Omit<OpenAIResponsesRequest, 'previous_response_id' | 'conversation'>;
751
- type OpenAIResponsesStatus = 'completed' | 'failed' | 'in_progress' | 'cancelled' | 'queued' | 'incomplete';
752
- interface OpenAIResponsesError {
753
- readonly code?: string | undefined;
754
- readonly message?: string | undefined;
755
- readonly [key: string]: unknown;
756
- }
757
- interface OpenAIResponsesIncompleteDetails {
758
- readonly reason?: string | undefined;
759
- readonly [key: string]: unknown;
760
- }
761
- interface OpenAIResponsesOutputTextContent {
762
- readonly type: 'output_text';
763
- readonly text: string;
764
- readonly annotations?: readonly Record<string, unknown>[] | undefined;
765
- readonly logprobs?: readonly Record<string, unknown>[] | undefined;
766
- }
767
- interface OpenAIResponsesOutputRefusal {
768
- readonly type: 'refusal';
769
- readonly refusal: string;
770
- }
771
- type OpenAIResponsesOutputContent = OpenAIResponsesOutputTextContent | OpenAIResponsesOutputRefusal;
772
- interface OpenAIResponsesOutputMessage {
773
- readonly type: 'message';
774
- readonly id?: string | undefined;
775
- readonly status?: OpenAIResponsesStatus | undefined;
776
- readonly role?: string | undefined;
777
- readonly phase?: string | undefined;
778
- readonly content: readonly OpenAIResponsesOutputContent[];
779
- }
780
- interface OpenAIResponsesOutputFunctionCall {
781
- readonly type: 'function_call';
782
- readonly id?: string | undefined;
783
- readonly call_id?: string | undefined;
784
- readonly name: string;
785
- readonly arguments: string;
786
- readonly status?: OpenAIResponsesStatus | undefined;
787
- }
788
- interface OpenAIResponsesOutputReasoning {
789
- readonly type: 'reasoning';
790
- readonly id?: string | undefined;
791
- readonly status?: OpenAIResponsesStatus | undefined;
792
- readonly summary?: readonly {
793
- readonly type: 'summary_text';
794
- readonly text: string;
795
- }[] | undefined;
796
- readonly text?: string | undefined;
797
- readonly encrypted_content?: string | undefined;
774
+ /** Maps to `reasoning.effort` on the native endpoint; ignored by the chat adapter. */
775
+ readonly reasoning_effort?: ResponsesReasoningEffort | undefined;
776
+ /** Ollama-specific extension: thinking output control (boolean or model-defined level). */
777
+ readonly think?: ThinkValue | undefined;
798
778
  }
799
- type OpenAIResponsesOutputItem = OpenAIResponsesOutputMessage | OpenAIResponsesOutputFunctionCall | OpenAIResponsesOutputReasoning;
800
- interface OpenAIResponsesUsage {
779
+ /** Token usage in OpenAI Responses naming. */
780
+ interface ResponsesUsage {
801
781
  readonly input_tokens: number;
802
782
  readonly output_tokens: number;
803
783
  readonly total_tokens: number;
804
- readonly input_tokens_details?: Record<string, unknown> | undefined;
805
- readonly output_tokens_details?: Record<string, unknown> | undefined;
806
784
  }
807
- /** Non-stateful response shape for the Ollama Responses compatibility endpoint. */
808
- interface OpenAIResponsesResponse {
785
+ /**
786
+ * Normalized, non-stateful Responses result — `output_text` is the joined
787
+ * text of all `output_text` content blocks, so consumers never touch the
788
+ * nested `output[]` structure.
789
+ */
790
+ interface ResponsesCreateResponse {
809
791
  readonly id: string;
810
- readonly object: 'response';
811
- readonly created: number;
812
- readonly created_at?: number | undefined;
813
- readonly status?: OpenAIResponsesStatus | undefined;
814
- readonly completed_at?: number | null | undefined;
815
- readonly error?: OpenAIResponsesError | null | undefined;
816
- readonly incomplete_details?: OpenAIResponsesIncompleteDetails | null | undefined;
817
792
  readonly model: string;
818
- readonly output: readonly OpenAIResponsesOutputItem[];
819
- readonly output_text?: string | undefined;
820
- readonly previous_response_id?: string | null | undefined;
821
- readonly parallel_tool_calls?: boolean | undefined;
822
- readonly usage?: OpenAIResponsesUsage | undefined;
823
- }
824
- declare class OpenAIResponsesStreamError extends OllamaClientError {
825
- readonly responsePayload: OpenAIResponsesResponse;
826
- constructor(message: string, responsePayload: OpenAIResponsesResponse);
827
- }
828
- declare class OpenAIChatCompletionStream implements AsyncIterable<OpenAIChatCompletionChunk> {
829
- private readonly source;
830
- private readonly finalResultPromise;
831
- private resolveFinal;
832
- private rejectFinal;
833
- private removeAbortListener;
834
- constructor(source: AbortableAsyncIterable<SseEvent>, signal?: AbortSignal);
835
- get finalResult(): Promise<OpenAIChatCompletionResponse>;
836
- abort(): void;
837
- [Symbol.asyncIterator](): AsyncGenerator<OpenAIChatCompletionChunk, void, undefined>;
838
- }
839
- declare class OpenAICompletionStream implements AsyncIterable<OpenAICompletionChunk> {
840
- private readonly source;
841
- private readonly finalResultPromise;
842
- private resolveFinal;
843
- private rejectFinal;
844
- private removeAbortListener;
845
- constructor(source: AbortableAsyncIterable<SseEvent>, signal?: AbortSignal);
846
- get finalResult(): Promise<OpenAICompletionResponse>;
847
- abort(): void;
848
- [Symbol.asyncIterator](): AsyncGenerator<OpenAICompletionChunk, void, undefined>;
849
- }
850
- interface OpenAIResponsesEventBase {
851
- readonly response_id?: string | undefined;
852
- readonly sequence_number?: number | undefined;
853
- }
854
- interface OpenAIResponsesOutputTextDeltaEvent extends OpenAIResponsesEventBase {
855
- readonly type: 'response.output_text.delta';
856
- readonly item_id: string;
857
- readonly output_index: number;
858
- readonly content_index: number;
859
- readonly delta: string;
860
- }
861
- interface OpenAIResponsesOutputTextDoneEvent extends OpenAIResponsesEventBase {
862
- readonly type: 'response.output_text.done';
863
- readonly item_id: string;
864
- readonly output_index: number;
865
- readonly content_index: number;
866
- readonly text: string;
867
- }
868
- interface OpenAIResponsesFunctionCallArgumentsDeltaEvent extends OpenAIResponsesEventBase {
869
- readonly type: 'response.function_call_arguments.delta';
870
- readonly item_id: string;
871
- readonly output_index: number;
872
- readonly delta: string;
873
- }
874
- interface OpenAIResponsesFunctionCallArgumentsDoneEvent extends OpenAIResponsesEventBase {
875
- readonly type: 'response.function_call_arguments.done';
876
- readonly item_id: string;
877
- readonly output_index: number;
878
- readonly arguments: string;
879
- readonly name?: string | undefined;
880
- }
881
- interface OpenAIResponsesReasoningTextDeltaEvent extends OpenAIResponsesEventBase {
882
- readonly type: 'response.reasoning_text.delta';
883
- readonly item_id: string;
884
- readonly output_index: number;
885
- readonly content_index: number;
886
- readonly delta: string;
887
- }
888
- interface OpenAIResponsesReasoningTextDoneEvent extends OpenAIResponsesEventBase {
889
- readonly type: 'response.reasoning_text.done';
890
- readonly item_id: string;
891
- readonly output_index: number;
892
- readonly content_index: number;
893
- readonly text: string;
894
- }
895
- interface OpenAIResponsesReasoningSummaryPartAddedEvent extends OpenAIResponsesEventBase {
896
- readonly type: 'response.reasoning_summary_part.added';
897
- readonly item_id: string;
898
- readonly output_index: number;
899
- readonly summary_index: number;
900
- readonly part: {
901
- readonly type: 'summary_text';
902
- readonly text: string;
903
- };
904
- }
905
- interface OpenAIResponsesReasoningSummaryPartDoneEvent extends OpenAIResponsesEventBase {
906
- readonly type: 'response.reasoning_summary_part.done';
907
- readonly item_id: string;
908
- readonly output_index: number;
909
- readonly summary_index: number;
910
- readonly part: {
911
- readonly type: 'summary_text';
912
- readonly text: string;
913
- };
914
- readonly status?: 'incomplete' | undefined;
915
- }
916
- interface OpenAIResponsesReasoningSummaryTextDeltaEvent extends OpenAIResponsesEventBase {
917
- readonly type: 'response.reasoning_summary_text.delta';
918
- readonly item_id: string;
919
- readonly output_index: number;
920
- readonly summary_index: number;
793
+ readonly created_at: string;
794
+ readonly output_text: string;
795
+ /** Reasoning-model thinking trace, when produced with `think` enabled. */
796
+ readonly thinking?: string | undefined;
797
+ /** Parsed function calls the model requested, when `tools` were provided. */
798
+ readonly tool_calls?: readonly ToolCall[] | undefined;
799
+ readonly usage?: ResponsesUsage | undefined;
800
+ /** Which transport served the request — see the module doc on dual-mode. */
801
+ readonly transport: 'native' | 'chat-adapter';
802
+ }
803
+ /** Simplified streaming events from {@link ResponsesModule.stream}. */
804
+ type ResponsesStreamEvent = {
805
+ readonly type: 'text_delta';
921
806
  readonly delta: string;
922
- }
923
- interface OpenAIResponsesReasoningSummaryTextDoneEvent extends OpenAIResponsesEventBase {
924
- readonly type: 'response.reasoning_summary_text.done';
925
- readonly item_id: string;
926
- readonly output_index: number;
927
- readonly summary_index: number;
928
- readonly text: string;
929
- }
930
- interface OpenAIResponsesOutputItemAddedEvent extends OpenAIResponsesEventBase {
931
- readonly type: 'response.output_item.added';
932
- readonly item: OpenAIResponsesOutputItem;
933
- readonly output_index: number;
934
- }
935
- interface OpenAIResponsesOutputItemDoneEvent extends OpenAIResponsesEventBase {
936
- readonly type: 'response.output_item.done';
937
- readonly item: OpenAIResponsesOutputItem;
938
- readonly output_index: number;
939
- }
940
- interface OpenAIResponsesContentPartAddedEvent extends OpenAIResponsesEventBase {
941
- readonly type: 'response.content_part.added';
942
- readonly item_id: string;
943
- readonly output_index: number;
944
- readonly content_index: number;
945
- readonly part: OpenAIResponsesOutputContent | {
946
- readonly type: string;
947
- readonly [key: string]: unknown;
948
- };
949
- }
950
- interface OpenAIResponsesContentPartDoneEvent extends OpenAIResponsesEventBase {
951
- readonly type: 'response.content_part.done';
952
- readonly item_id: string;
953
- readonly output_index: number;
954
- readonly content_index: number;
955
- readonly part: OpenAIResponsesOutputContent | {
956
- readonly type: string;
957
- readonly [key: string]: unknown;
958
- };
959
- }
960
- interface OpenAIResponsesRefusalDeltaEvent extends OpenAIResponsesEventBase {
961
- readonly type: 'response.refusal.delta';
962
- readonly item_id: string;
963
- readonly output_index: number;
964
- readonly content_index: number;
807
+ } | {
808
+ readonly type: 'thinking_delta';
965
809
  readonly delta: string;
966
- }
967
- interface OpenAIResponsesRefusalDoneEvent extends OpenAIResponsesEventBase {
968
- readonly type: 'response.refusal.done';
969
- readonly item_id: string;
970
- readonly output_index: number;
971
- readonly content_index: number;
972
- readonly refusal: string;
973
- }
974
- interface OpenAIResponsesCreatedEvent extends OpenAIResponsesEventBase {
975
- readonly type: 'response.created';
976
- readonly response: OpenAIResponsesResponse;
977
- }
978
- interface OpenAIResponsesInProgressEvent extends OpenAIResponsesEventBase {
979
- readonly type: 'response.in_progress';
980
- readonly response: OpenAIResponsesResponse;
981
- }
982
- interface OpenAIResponsesQueuedEvent extends OpenAIResponsesEventBase {
983
- readonly type: 'response.queued';
984
- readonly response: OpenAIResponsesResponse;
985
- }
986
- interface OpenAIResponsesCompletedEvent extends OpenAIResponsesEventBase {
987
- readonly type: 'response.completed' | 'response.done';
988
- readonly response: OpenAIResponsesResponse;
989
- }
990
- interface OpenAIResponsesFailedEvent extends OpenAIResponsesEventBase {
991
- readonly type: 'response.failed';
992
- readonly response: OpenAIResponsesResponse;
993
- }
994
- interface OpenAIResponsesIncompleteEvent extends OpenAIResponsesEventBase {
995
- readonly type: 'response.incomplete';
996
- readonly response: OpenAIResponsesResponse;
997
- }
998
- type OpenAIResponsesStreamEvent = OpenAIResponsesOutputTextDeltaEvent | OpenAIResponsesOutputTextDoneEvent | OpenAIResponsesFunctionCallArgumentsDeltaEvent | OpenAIResponsesFunctionCallArgumentsDoneEvent | OpenAIResponsesReasoningTextDeltaEvent | OpenAIResponsesReasoningTextDoneEvent | OpenAIResponsesReasoningSummaryPartAddedEvent | OpenAIResponsesReasoningSummaryPartDoneEvent | OpenAIResponsesReasoningSummaryTextDeltaEvent | OpenAIResponsesReasoningSummaryTextDoneEvent | OpenAIResponsesOutputItemAddedEvent | OpenAIResponsesOutputItemDoneEvent | OpenAIResponsesContentPartAddedEvent | OpenAIResponsesContentPartDoneEvent | OpenAIResponsesRefusalDeltaEvent | OpenAIResponsesRefusalDoneEvent | OpenAIResponsesCreatedEvent | OpenAIResponsesInProgressEvent | OpenAIResponsesQueuedEvent | OpenAIResponsesCompletedEvent | OpenAIResponsesFailedEvent | OpenAIResponsesIncompleteEvent | {
999
- readonly type: string;
1000
- readonly [key: string]: unknown;
810
+ } | {
811
+ readonly type: 'done';
812
+ readonly response: ResponsesCreateResponse;
1001
813
  };
1002
- declare class OpenAIResponsesStream implements AsyncIterable<OpenAIResponsesStreamEvent> {
1003
- private readonly source;
1004
- private readonly finalResultPromise;
1005
- private resolveFinal;
1006
- private rejectFinal;
1007
- private removeAbortListener;
1008
- constructor(source: AbortableAsyncIterable<SseEvent>, signal?: AbortSignal);
1009
- get finalResult(): Promise<OpenAIResponsesResponse>;
1010
- abort(): void;
1011
- [Symbol.asyncIterator](): AsyncGenerator<OpenAIResponsesStreamEvent, void, undefined>;
1012
- }
1013
- declare class OpenAICompatClient {
1014
- private readonly http;
1015
- private readonly runner?;
1016
- constructor(http: HttpClient, runner?: RequestRunner | undefined);
1017
- private request;
1018
- createChatCompletion(request: OpenAIChatCompletionRequest & {
1019
- stream: true;
1020
- }, signal?: AbortSignal): Promise<OpenAIChatCompletionStream>;
1021
- createChatCompletion(request: OpenAIChatCompletionRequest & {
1022
- stream?: false | undefined;
1023
- }, signal?: AbortSignal): Promise<OpenAIChatCompletionResponse>;
1024
- chatCompletions(request: OpenAIChatCompletionRequest & {
1025
- stream: true;
1026
- }, signal?: AbortSignal): Promise<OpenAIChatCompletionStream>;
1027
- chatCompletions(request: OpenAIChatCompletionRequest & {
1028
- stream?: false | undefined;
1029
- }, signal?: AbortSignal): Promise<OpenAIChatCompletionResponse>;
1030
- listModels(signal?: AbortSignal): Promise<OpenAIListModelsResponse>;
1031
- retrieveModel(model: string, signal?: AbortSignal): Promise<OpenAIModelItem>;
1032
- getModel(model: string, signal?: AbortSignal): Promise<OpenAIModelItem>;
1033
- createCompletion(request: OpenAICompletionRequest & {
1034
- stream: true;
1035
- }, signal?: AbortSignal): Promise<OpenAICompletionStream>;
1036
- createCompletion(request: OpenAICompletionRequest & {
1037
- stream?: false | undefined;
1038
- }, signal?: AbortSignal): Promise<OpenAICompletionResponse>;
1039
- completions(request: OpenAICompletionRequest & {
1040
- stream: true;
1041
- }, signal?: AbortSignal): Promise<OpenAICompletionStream>;
1042
- completions(request: OpenAICompletionRequest & {
1043
- stream?: false | undefined;
1044
- }, signal?: AbortSignal): Promise<OpenAICompletionResponse>;
1045
- createEmbedding(request: OpenAIEmbeddingRequest, signal?: AbortSignal): Promise<OpenAIEmbeddingResponse>;
1046
- embeddings(request: OpenAIEmbeddingRequest, signal?: AbortSignal): Promise<OpenAIEmbeddingResponse>;
1047
- createResponses(request: OpenAIResponsesRequest & {
1048
- stream: true;
1049
- }, signal?: AbortSignal): Promise<OpenAIResponsesStream>;
1050
- createResponses(request: OpenAIResponsesRequest & {
1051
- stream?: false | undefined;
1052
- }, signal?: AbortSignal): Promise<OpenAIResponsesResponse>;
1053
- responses(request: OpenAIResponsesRequest & {
1054
- stream: true;
1055
- }, signal?: AbortSignal): Promise<OpenAIResponsesStream>;
1056
- responses(request: OpenAIResponsesRequest & {
1057
- stream?: false | undefined;
1058
- }, signal?: AbortSignal): Promise<OpenAIResponsesResponse>;
814
+ /**
815
+ * Dual-mode Responses API bridge. Access via `client.responses` — see the
816
+ * module doc for the transport selection rules.
817
+ */
818
+ declare class ResponsesModule {
819
+ private readonly runner;
820
+ constructor(runner: RequestRunner);
821
+ /** The request body sent to the native endpoint (also reused for streaming). */
822
+ private nativeBody;
823
+ /**
824
+ * Runs one Responses request, preferring the native `POST /v1/responses`
825
+ * endpoint and transparently re-issuing via `/api/chat` when the server
826
+ * answers `404` (pre-v0.13.3 Ollama without the compatibility endpoint).
827
+ */
828
+ create(req: ResponsesCreateRequest): Promise<ResponsesCreateResponse>;
829
+ /** Convenience: `create()` returning only the `output_text` string. */
830
+ createText(req: ResponsesCreateRequest): Promise<string>;
831
+ private createViaChatAdapter;
832
+ /**
833
+ * Streams a Responses request as simplified
834
+ * `{type: 'text_delta' | 'thinking_delta' | 'done'}` events. Dual-mode like
835
+ * {@link create}: native SSE from `/v1/responses` when available, otherwise
836
+ * the normalized `/api/chat` token stream. Tool calls are not delta'd —
837
+ * collect them from the final `done` event's `response.tool_calls`.
838
+ *
839
+ * This is a lazy async generator: nothing is sent until the first
840
+ * iteration, matching `for await (... of client.responses.stream(req))`
841
+ * intuition. The generator is also cancellable through `req.signal`.
842
+ */
843
+ stream(req: ResponsesCreateRequest): AsyncGenerator<ResponsesStreamEvent, void, void>;
1059
844
  }
1060
845
 
1061
846
  /**
1062
- * Anthropic Compatibility interfaces and client helpers for Ollama.
1063
- * Ollama supports the Anthropic Messages API format.
847
+ * KV-prefix-preserving conversation sessions.
848
+ *
849
+ * Ollama reuses the model's KV cache across turns of a conversation by
850
+ * **prompt prefix matching**: if the new prompt's leading tokens are
851
+ * byte-identical to the previous turn's, the cached prefix is reused and
852
+ * only the new suffix is evaluated — surfaced by the server as
853
+ * `prompt_eval_cached_count`. Anything that mutates the prefix invalidates
854
+ * the whole cache and forces a full re-evaluation (`prompt_eval_count`
855
+ * spikes, latency jumps): changing the system prompt, prepending dynamic
856
+ * timestamps or request IDs to the conversation, or reordering past turns.
857
+ *
858
+ * `ConversationSession` makes the cache-friendly structure the default:
859
+ *
860
+ * - The system prompt (if any) is fixed at construction and always the
861
+ * first message. There is deliberately **no API to mutate it later** —
862
+ * a mutable system prompt is the #1 silent KV-cache killer.
863
+ * - History is append-only. Messages are never reordered, rewritten, or
864
+ * re-serialized between turns — `getMessages()` copies, so external
865
+ * mutation can't leak in either.
866
+ * - Per-turn options (`options`, `think`, `tools`, …) ride on the request,
867
+ * not the history, so changing them never disturbs the prefix.
868
+ *
869
+ * Each turn records what the server reported about the cache, so degrading
870
+ * hit rates (a symptom of prefix churn somewhere upstream, or a context
871
+ * window that no longer holds the whole history) are visible in
872
+ * {@link ConversationSession.cacheStats} instead of hiding in raw responses.
1064
873
  */
1065
874
 
1066
- interface AnthropicCacheControl {
1067
- readonly type: 'ephemeral';
1068
- readonly ttl?: '5m' | '1h' | undefined;
1069
- }
1070
- interface AnthropicTextContentBlock {
1071
- readonly type: 'text';
1072
- readonly text: string;
1073
- readonly cache_control?: AnthropicCacheControl | undefined;
1074
- }
1075
- interface AnthropicImageContentBlock {
1076
- readonly type: 'image';
1077
- readonly source: {
1078
- readonly type: 'base64';
1079
- readonly media_type: string;
1080
- readonly data: string;
1081
- };
1082
- }
1083
- interface AnthropicToolUseContentBlock {
1084
- readonly type: 'tool_use';
1085
- readonly id: string;
1086
- readonly name: string;
1087
- readonly input: Record<string, unknown>;
1088
- }
1089
- interface AnthropicToolResultContentBlock {
1090
- readonly type: 'tool_result';
1091
- readonly tool_use_id: string;
1092
- readonly content?: string | readonly AnthropicTextContentBlock[] | undefined;
1093
- readonly is_error?: boolean | undefined;
1094
- }
1095
- interface AnthropicThinkingContentBlock {
1096
- readonly type: 'thinking';
1097
- readonly thinking: string;
1098
- readonly signature?: string | undefined;
1099
- }
1100
- interface AnthropicRedactedThinkingContentBlock {
1101
- readonly type: 'redacted_thinking';
1102
- readonly data: string;
875
+ /** What one turn's response reported about KV-cache reuse and evaluation. */
876
+ interface TurnCacheStats {
877
+ /** Prompt tokens served from the KV cache this turn. */
878
+ readonly cachedTokens: number;
879
+ /** Prompt tokens freshly evaluated this turn. */
880
+ readonly evaluatedTokens: number;
881
+ /**
882
+ * Cache hit rate for this turn: `cached / (cached + evaluated)`.
883
+ *
884
+ * Note the denominator adds both counters — when the *entire* prompt hits
885
+ * the cache, Ollama reports `prompt_eval_count: 0`, so dividing by
886
+ * `prompt_eval_count` alone would falsely yield a 0% hit rate on the
887
+ * best-case turn.
888
+ */
889
+ readonly hitRate: number;
890
+ }
891
+ /** Cumulative cache statistics across every completed turn so far. */
892
+ interface CumulativeCacheStats extends TurnCacheStats {
893
+ /** Number of completed turns (user+assistant pairs). */
894
+ readonly turns: number;
895
+ /** Total prompt tokens across turns, cached + evaluated. */
896
+ readonly totalPromptTokens: number;
897
+ }
898
+ /** Everything one {@link ConversationSession.sendTurn} call knows. */
899
+ interface SessionTurn {
900
+ /** The assistant's text reply (same value `send()` returns). */
901
+ readonly content: string;
902
+ /** What the server reported about KV-cache reuse for this turn. */
903
+ readonly cache: TurnCacheStats;
904
+ /** The full underlying `/api/chat` response (usage, durations, thinking, …). */
905
+ readonly response: ChatResponse;
906
+ }
907
+ /** Per-turn overrides — none of these touch the history prefix, so they are KV-safe. */
908
+ interface ConversationSendOptions extends Pick<ChatRequestOptions, 'signal' | 'timeoutMs'> {
909
+ readonly options?: ModelOptions | undefined;
910
+ readonly think?: ThinkValue | undefined;
911
+ readonly keep_alive?: string | number | undefined;
912
+ readonly tools?: readonly ToolDefinition[] | undefined;
913
+ readonly format?: FormatOption | undefined;
1103
914
  }
1104
- type AnthropicContentBlock = AnthropicTextContentBlock | AnthropicImageContentBlock | AnthropicToolUseContentBlock | AnthropicToolResultContentBlock | AnthropicThinkingContentBlock | AnthropicRedactedThinkingContentBlock;
1105
- interface AnthropicMessage {
1106
- readonly role: 'user' | 'assistant';
1107
- readonly content: string | readonly AnthropicContentBlock[];
915
+ /** Static configuration for a session, fixed at construction (KV-prefix safety). */
916
+ interface ConversationSessionOptions {
917
+ readonly model: string;
918
+ /**
919
+ * System prompt, pinned as the first history message for the session's
920
+ * whole lifetime. Avoid dynamic content here (timestamps, request IDs) —
921
+ * a per-call system prompt defeats prefix caching entirely.
922
+ */
923
+ readonly systemPrompt?: string | undefined;
924
+ /** Default `options` (sampler settings, `num_ctx`, …) applied to every turn. */
925
+ readonly options?: ModelOptions | undefined;
926
+ /** Default `think` control applied to every turn. */
927
+ readonly think?: ThinkValue | undefined;
928
+ /** Default `keep_alive` applied to every turn. */
929
+ readonly keep_alive?: string | number | undefined;
930
+ /** Default `tools` applied to every turn. */
931
+ readonly tools?: readonly ToolDefinition[] | undefined;
932
+ /** Default `format` (structured output) applied to every turn. */
933
+ readonly format?: FormatOption | undefined;
1108
934
  }
1109
- interface AnthropicSystemTextBlock {
1110
- readonly type: 'text';
1111
- readonly text: string;
1112
- readonly cache_control?: AnthropicCacheControl | undefined;
935
+ /**
936
+ * A multi-turn chat session with an immutable, cache-friendly message
937
+ * history. Create via `client.session(...)` or construct directly:
938
+ *
939
+ * ```ts
940
+ * const session = client.session('llama3.1', 'You are a concise assistant.');
941
+ * await session.send('Hi!'); // turn 1 — cold cache
942
+ * await session.send('Why is the sky blue?'); // turn 2 — prefix reused
943
+ * session.cacheStats; // cumulative hit rate
944
+ * ```
945
+ */
946
+ declare class ConversationSession {
947
+ private readonly client;
948
+ private readonly config;
949
+ /** Ordered, append-only history. Message objects are frozen on push. */
950
+ private readonly history;
951
+ /** Mutable tallies behind the read-only {@link cacheStats} view. */
952
+ private readonly tallies;
953
+ constructor(client: OllamaClient, config: ConversationSessionOptions);
954
+ /** The model name this session talks to. */
955
+ get model(): string;
956
+ /** Number of completed turns. */
957
+ get turnCount(): number;
958
+ /** Cumulative KV-cache statistics across completed turns. */
959
+ get cacheStats(): CumulativeCacheStats;
960
+ /**
961
+ * Sends the user's message and returns the assistant's reply text —
962
+ * the ergonomic path. Use {@link sendTurn} when you also need the
963
+ * per-turn cache statistics or the raw response.
964
+ */
965
+ send(content: string, overrides?: ConversationSendOptions): Promise<string>;
966
+ /**
967
+ * Sends the user's message and returns the full turn record: reply text,
968
+ * per-turn KV-cache statistics, and the raw `/api/chat` response.
969
+ */
970
+ sendTurn(content: string, overrides?: ConversationSendOptions): Promise<SessionTurn>;
971
+ /**
972
+ * A defensive copy of the session history — mutating the returned array or
973
+ * its frozen messages has no effect on the session.
974
+ */
975
+ getMessages(): readonly Message[];
976
+ /**
977
+ * Clears the conversation back to its initial state (system prompt, zero
978
+ * turns, zeroed cache statistics). The next turn starts with a cold cache
979
+ * by definition — there is nothing upstream of it to reuse.
980
+ */
981
+ reset(): void;
1113
982
  }
1114
- type AnthropicSystem = string | readonly AnthropicSystemTextBlock[];
1115
- interface AnthropicTool {
1116
- readonly name: string;
1117
- readonly description?: string | undefined;
1118
- readonly input_schema: Record<string, unknown>;
1119
- readonly eager_input_streaming?: boolean | undefined;
983
+
984
+ /**
985
+ * Ergonomic System One types — key-safe generics on top of the generated
986
+ * contract models.
987
+ *
988
+ * The generated `SystemOneRequest` and `SystemOneResponse` (in
989
+ * `src/generated/models/`) use `Record<string, ...>` for the
990
+ * questions/answers maps. That's structurally correct but loses the
991
+ * connection between the question names the caller sends and the answer
992
+ * names they receive back — `response.answers.someRandomKey` would
993
+ * compile even though the caller never asked that question.
994
+ *
995
+ * This file adds a generic layer:
996
+ *
997
+ * ```ts
998
+ * const result = await ollama.systemOne({
999
+ * model: 'tev1:4b',
1000
+ * state: { ticket: 'charged twice' },
1001
+ * questions: {
1002
+ * intent: { type: 'choice', ... },
1003
+ * urgent: { type: 'noul', ... },
1004
+ * },
1005
+ * });
1006
+ *
1007
+ * // Key-safe: 'intent' and 'urgent' are the only valid keys.
1008
+ * result.answers.intent // ✓ SystemOneAnswer
1009
+ * result.answers.urgent // ✓ SystemOneAnswer
1010
+ * result.answers.typo // ✗ TypeScript error
1011
+ * ```
1012
+ *
1013
+ * The generic is purely a compile-time wrapper — the runtime behavior is
1014
+ * unchanged. The generated types remain the canonical contract; these
1015
+ * types are an SDK-level convenience that OpenAPI cannot express.
1016
+ *
1017
+ * Wave 13.
1018
+ */
1019
+
1020
+ /**
1021
+ * Maximum total request size, in bytes, accepted by `/v1/systemone`
1022
+ * when the request body carries a non-empty `images` array.
1023
+ *
1024
+ * The Ollama server enforces this limit server-side and rejects
1025
+ * oversized payloads with HTTP 413. The SDK's runtime also enforces
1026
+ * it client-side (see `OllamaRuntime`'s `maxRequestBytesWithImages`
1027
+ * handling) so the round-trip is avoided.
1028
+ *
1029
+ * Without images, the limit is the much smaller
1030
+ * {@link MAX_SYSTEM_ONE_REQUEST_BYTES} (64 KiB) — the bumped
1031
+ * images-cap exists specifically to accommodate base64-encoded image
1032
+ * bytes shared across all questions in a single System One call.
1033
+ */
1034
+ declare const MAX_SYSTEM_ONE_IMAGES_BYTES: number;
1035
+ /**
1036
+ * Maximum total request size, in bytes, for `/v1/systemone` when no
1037
+ * images are attached. The Ollama server caps the JSON-only payload
1038
+ * at 64 KiB; the runtime enforces this client-side (see
1039
+ * `OllamaRuntime`'s `maxRequestBytes`).
1040
+ */
1041
+ declare const MAX_SYSTEM_ONE_REQUEST_BYTES: number;
1042
+ /**
1043
+ * Discriminated union of the three question kinds. The upstream OpenAPI
1044
+ * defines this inline as `oneOf` within SystemOneRequest.questions; we
1045
+ * reconstruct it as a named type for SDK ergonomics.
1046
+ */
1047
+ type SystemOneQuestion = SystemOneChoiceQuestion | SystemOneNoulQuestion | SystemOneScoreQuestion;
1048
+ /**
1049
+ * Discriminated union of the three answer kinds. The upstream OpenAPI
1050
+ * defines this inline as `oneOf` within SystemOneResponse.answers; we
1051
+ * reconstruct it as a named type for SDK ergonomics.
1052
+ */
1053
+ type SystemOneAnswer = SystemOneChoiceAnswer | SystemOneNoulAnswer | SystemOneScoreAnswer;
1054
+ /**
1055
+ * Token usage for a System One call. The upstream OpenAPI defines this
1056
+ * inline within SystemOneResponse; we reconstruct it as a named type
1057
+ * for SDK ergonomics. Carries input_tokens and output_tokens (not
1058
+ * prompt_tokens/completion_tokens).
1059
+ */
1060
+ interface SystemOneUsage {
1061
+ readonly input_tokens: number;
1062
+ readonly output_tokens: number;
1120
1063
  }
1121
- type AnthropicToolChoice = {
1122
- readonly type: 'auto';
1123
- readonly disable_parallel_tool_use?: boolean | undefined;
1124
- } | {
1125
- readonly type: 'any';
1126
- readonly disable_parallel_tool_use?: boolean | undefined;
1127
- } | {
1128
- readonly type: 'tool';
1129
- readonly name: string;
1130
- readonly disable_parallel_tool_use?: boolean | undefined;
1131
- } | {
1132
- readonly type: 'none';
1064
+ /** Map of question id → question descriptor. */
1065
+ type SystemOneQuestions = Record<string, SystemOneQuestion>;
1066
+ /**
1067
+ * Wave 16 (P2): conditional mapping from a question type to its
1068
+ * corresponding answer type. This gives compile-time type correlation:
1069
+ *
1070
+ * choice question → choice answer
1071
+ * noul question → noul answer
1072
+ * score question → score answer
1073
+ *
1074
+ * Without this, `SystemOneAnswers<Q>` maps every key to the full
1075
+ * `SystemOneAnswer` union, requiring manual narrowing. With this,
1076
+ * `result.answers.myChoiceQuestion` is automatically typed as
1077
+ * `SystemOneChoiceAnswer`.
1078
+ */
1079
+ type AnswerFor<Q> = Q extends {
1080
+ readonly type: 'choice';
1081
+ } ? SystemOneChoiceAnswer : Q extends {
1082
+ readonly type: 'noul';
1083
+ } ? SystemOneNoulAnswer : Q extends {
1084
+ readonly type: 'score';
1085
+ } ? SystemOneScoreAnswer : SystemOneAnswer;
1086
+ /**
1087
+ * Key-safe answers map: for every question key `K` in `Q`, the response
1088
+ * carries the answer type that corresponds to that question's type.
1089
+ * Wave 16: now uses `AnswerFor<Q[K]>` for exact type correlation.
1090
+ */
1091
+ type SystemOneAnswers<Q extends SystemOneQuestions = SystemOneQuestions> = {
1092
+ readonly [K in keyof Q]: AnswerFor<Q[K]>;
1133
1093
  };
1134
- interface AnthropicThinkingConfig {
1135
- readonly type: 'enabled' | 'disabled' | 'adaptive';
1136
- readonly display?: 'omitted' | 'summarized' | 'updates' | undefined;
1137
- /** Accepted by Ollama for compatibility but currently not enforced by the server. */
1138
- readonly budget_tokens?: number | undefined;
1139
- }
1140
- interface AnthropicOutputConfig {
1141
- readonly effort?: string | undefined;
1094
+ /**
1095
+ * Generic System One request. When `Q` is provided, `questions` is typed
1096
+ * as `Q` (the caller's specific question map) rather than the loose
1097
+ * `Record<string, SystemOneQuestion>`. The response's `answers` will
1098
+ * then carry the same keys.
1099
+ *
1100
+ * The `model`, `state`, `images`, and `keep_alive` fields are inherited
1101
+ * from the generated base type unchanged.
1102
+ *
1103
+ * ## Image support
1104
+ *
1105
+ * The `images` field accepts up to N base64-encoded images shared by
1106
+ * all questions in the request. Total request payload (JSON + images)
1107
+ * must remain within {@link MAX_SYSTEM_ONE_IMAGES_BYTES} (32 MiB);
1108
+ * requests without images are capped at
1109
+ * {@link MAX_SYSTEM_ONE_REQUEST_BYTES} (64 KiB).
1110
+ *
1111
+ * Use {@link estimateSystemOneRequestBytes} for a client-side pre-flight
1112
+ * check before sending a large multi-image batch — the runtime also
1113
+ * enforces the limit, but the early check avoids the round-trip when
1114
+ * the caller already knows the payload is too large.
1115
+ *
1116
+ * Requires Clef or Clef Flash with vision weights. URLs and data URLs
1117
+ * are NOT supported — pre-encode the bytes to base64 before adding to
1118
+ * the array.
1119
+ */
1120
+ interface SystemOneRequest<Q extends SystemOneQuestions = SystemOneQuestions> extends Omit<SystemOneRequest$1, 'questions'> {
1121
+ readonly questions: Q;
1142
1122
  }
1143
- interface AnthropicMetadata {
1144
- readonly user_id?: string | undefined;
1123
+ /**
1124
+ * Generic System One response. When `Q` is provided, `answers` is typed
1125
+ * as `SystemOneAnswers<Q>` — a key-safe map matching the questions the
1126
+ * caller asked.
1127
+ */
1128
+ interface SystemOneResponse<Q extends SystemOneQuestions = SystemOneQuestions> extends Omit<SystemOneResponse$1, 'answers' | 'usage'> {
1129
+ readonly answers: SystemOneAnswers<Q>;
1130
+ readonly usage: SystemOneUsage;
1145
1131
  }
1146
- interface AnthropicMessagesRequest {
1147
- readonly model: string;
1148
- readonly messages: readonly AnthropicMessage[];
1149
- readonly system?: AnthropicSystem | undefined;
1150
- readonly max_tokens?: number | undefined;
1151
- readonly temperature?: number | undefined;
1152
- readonly top_p?: number | undefined;
1153
- readonly top_k?: number | undefined;
1154
- readonly stop_sequences?: readonly string[] | undefined;
1155
- readonly stream?: boolean | undefined;
1156
- readonly tools?: readonly AnthropicTool[] | undefined;
1157
- readonly thinking?: AnthropicThinkingConfig | undefined;
1158
- readonly output_config?: AnthropicOutputConfig | undefined;
1159
- /**
1160
- * Accepted for Anthropic compatibility but currently ignored by Ollama.
1161
- * Tool selection cannot be forced through the Ollama compatibility endpoint.
1162
- */
1163
- readonly tool_choice?: AnthropicToolChoice | undefined;
1164
- /** Accepted for compatibility but currently ignored by Ollama. */
1165
- readonly metadata?: AnthropicMetadata | undefined;
1132
+ /**
1133
+ * Estimate the on-the-wire byte size of a System One request body, for
1134
+ * pre-flight size validation against {@link MAX_SYSTEM_ONE_REQUEST_BYTES}
1135
+ * (no images) or {@link MAX_SYSTEM_ONE_IMAGES_BYTES} (with images).
1136
+ *
1137
+ * The estimate is conservative: it uses `JSON.stringify` length and
1138
+ * assumes UTF-8 encoding. The actual wire size may differ slightly due
1139
+ * to server-side JSON normalization (key ordering, whitespace), but the
1140
+ * estimate is always within a few percent of the real payload size and
1141
+ * is suitable for "fail fast before sending" checks.
1142
+ *
1143
+ * @example
1144
+ * ```ts
1145
+ * const request: SystemOneRequest = { ... };
1146
+ * const bytes = estimateSystemOneRequestBytes(request);
1147
+ * const cap = request.images?.length ? MAX_SYSTEM_ONE_IMAGES_BYTES : MAX_SYSTEM_ONE_REQUEST_BYTES;
1148
+ * if (bytes > cap) throw new Error(`payload ${bytes}B exceeds cap ${cap}B`);
1149
+ * await client.systemOne(request);
1150
+ * ```
1151
+ */
1152
+ declare function estimateSystemOneRequestBytes(request: SystemOneRequest | SystemOneRequest$1): number;
1153
+
1154
+ /**
1155
+ * Higher-level System One decision helpers.
1156
+ *
1157
+ * Wave 14B: These helpers wrap the low-level `OllamaClient.systemOne()`
1158
+ * with ergonomic APIs for the six most common decision patterns. Each
1159
+ * helper constructs a single-question request, sends it, and extracts
1160
+ * the typed answer — so callers don't have to deal with the question
1161
+ * map / answer map indirection for single-decision calls.
1162
+ *
1163
+ * The helpers return typed results (not generic SystemOneAnswer) so
1164
+ * callers can branch on the discriminated union without manual
1165
+ * type narrowing.
1166
+ *
1167
+ * For multi-question calls (e.g. routing + urgency + difficulty in
1168
+ * one request), use `OllamaClient.systemOne()` directly with the
1169
+ * generic key-safe wrapper.
1170
+ */
1171
+
1172
+ /**
1173
+ * Result of a choice decision: the selected option key + probability
1174
+ * distribution + confidence.
1175
+ */
1176
+ interface ChoiceDecision {
1177
+ /** The selected option key (highest probability). */
1178
+ readonly choice: string;
1179
+ /** Probability distribution over all options. */
1180
+ readonly probabilities: Record<string, number>;
1181
+ /** Distribution concentration (0–1). NOT a guarantee of correctness. */
1182
+ readonly confidence: number;
1183
+ /** Token usage for the call. */
1184
+ readonly usage: {
1185
+ readonly input_tokens: number;
1186
+ readonly output_tokens: number;
1187
+ };
1166
1188
  }
1167
- /** Strict Ollama-documented Messages request; excludes fields Ollama marks unsupported. */
1168
- type OllamaAnthropicTextContentBlock = Omit<AnthropicTextContentBlock, 'cache_control'>;
1169
- type OllamaAnthropicTool = Omit<AnthropicTool, 'eager_input_streaming'>;
1170
- type OllamaAnthropicThinkingConfig = {
1171
- readonly type: 'enabled' | 'disabled';
1172
- /** Accepted by Ollama for compatibility but currently not enforced by the server. */
1173
- readonly budget_tokens?: number | undefined;
1174
- };
1175
- type OllamaAnthropicToolResultContentBlock = Omit<AnthropicToolResultContentBlock, 'content'> & {
1176
- readonly content?: string | readonly OllamaAnthropicTextContentBlock[] | undefined;
1177
- };
1178
- type OllamaAnthropicContentBlock = OllamaAnthropicTextContentBlock | AnthropicImageContentBlock | AnthropicToolUseContentBlock | OllamaAnthropicToolResultContentBlock | AnthropicThinkingContentBlock;
1179
- type OllamaAnthropicMessage = Omit<AnthropicMessage, 'content'> & {
1180
- readonly content: string | readonly OllamaAnthropicContentBlock[];
1181
- };
1182
- type OllamaAnthropicSystemTextBlock = Omit<AnthropicSystemTextBlock, 'cache_control'>;
1183
- type OllamaAnthropicSystem = string | readonly OllamaAnthropicSystemTextBlock[];
1184
- /** Strict Ollama-documented Messages request; excludes unsupported caching/tool-choice metadata. */
1185
- type OllamaAnthropicMessagesRequest = Omit<AnthropicMessagesRequest, 'messages' | 'system' | 'tools' | 'thinking' | 'tool_choice' | 'metadata'> & {
1186
- readonly messages: readonly OllamaAnthropicMessage[];
1187
- readonly system?: OllamaAnthropicSystem | undefined;
1188
- readonly tools?: readonly OllamaAnthropicTool[] | undefined;
1189
- readonly thinking?: OllamaAnthropicThinkingConfig | undefined;
1190
- };
1191
- interface AnthropicMessagesResponse {
1192
- readonly id: string;
1193
- readonly type: 'message';
1194
- readonly role: 'assistant';
1195
- readonly content: readonly AnthropicContentBlock[];
1196
- readonly model: string;
1197
- readonly stop_reason: string | null;
1198
- readonly stop_sequence?: string | null | undefined;
1199
- readonly usage?: {
1189
+ /**
1190
+ * Result of a noul (yes/no) decision: the probability of true + a
1191
+ * boolean derived from it (>= 0.5 → true).
1192
+ */
1193
+ interface NoulDecision {
1194
+ /** Probability of true (0–1). */
1195
+ readonly noul: number;
1196
+ /** Boolean decision: true if noul >= 0.5, false otherwise. */
1197
+ readonly bool: boolean;
1198
+ /** Token usage for the call. */
1199
+ readonly usage: {
1200
1200
  readonly input_tokens: number;
1201
1201
  readonly output_tokens: number;
1202
- readonly cache_creation_input_tokens?: number | undefined;
1203
- readonly cache_read_input_tokens?: number | undefined;
1204
- readonly cache_creation?: Record<string, unknown> | undefined;
1205
- } | undefined;
1206
- }
1207
- interface AnthropicMessageStartEvent {
1208
- readonly type: 'message_start';
1209
- readonly message: AnthropicMessagesResponse;
1210
- }
1211
- interface AnthropicContentBlockStartEvent {
1212
- readonly type: 'content_block_start';
1213
- readonly index: number;
1214
- readonly content_block: AnthropicContentBlock;
1215
- }
1216
- type AnthropicContentBlockDelta = {
1217
- readonly type: 'text_delta';
1218
- readonly text: string;
1219
- } | {
1220
- readonly type: 'input_json_delta';
1221
- readonly partial_json: string;
1222
- } | {
1223
- readonly type: 'thinking_delta';
1224
- readonly thinking: string;
1225
- } | {
1226
- readonly type: 'signature_delta';
1227
- readonly signature: string;
1228
- };
1229
- interface AnthropicContentBlockDeltaEvent {
1230
- readonly type: 'content_block_delta';
1231
- readonly index: number;
1232
- readonly delta: AnthropicContentBlockDelta;
1233
- }
1234
- interface AnthropicContentBlockStopEvent {
1235
- readonly type: 'content_block_stop';
1236
- readonly index: number;
1237
- }
1238
- interface AnthropicMessageDeltaEvent {
1239
- readonly type: 'message_delta';
1240
- readonly delta: {
1241
- readonly stop_reason?: string | null | undefined;
1242
- readonly stop_sequence?: string | null | undefined;
1243
1202
  };
1244
- readonly usage?: {
1245
- readonly input_tokens?: number | undefined;
1246
- readonly output_tokens: number;
1247
- readonly cache_creation_input_tokens?: number | undefined;
1248
- readonly cache_read_input_tokens?: number | undefined;
1249
- readonly cache_creation?: Record<string, unknown> | undefined;
1250
- } | undefined;
1251
1203
  }
1252
- interface AnthropicMessageStopEvent {
1253
- readonly type: 'message_stop';
1254
- }
1255
- interface AnthropicPingEvent {
1256
- readonly type: 'ping';
1257
- }
1258
- interface AnthropicErrorEvent {
1259
- readonly type: 'error';
1260
- readonly error: {
1261
- readonly type: string;
1262
- readonly message: string;
1204
+ /**
1205
+ * Result of a score decision: the probability-weighted average score,
1206
+ * the legend (index → description), the probability distribution, and
1207
+ * confidence.
1208
+ */
1209
+ interface ScoreDecision {
1210
+ /** Probability-weighted average of zero-based criterion indices (0 to N-1). */
1211
+ readonly score: number;
1212
+ /** Zero-based indices as string keys → criterion descriptions. */
1213
+ readonly legend: Record<string, string>;
1214
+ /** Probabilities keyed by zero-based criterion indices as strings. */
1215
+ readonly probabilities: Record<string, number>;
1216
+ /** Distribution concentration (0–1). NOT a guarantee of correctness. */
1217
+ readonly confidence: number;
1218
+ /** Token usage for the call. */
1219
+ readonly usage: {
1220
+ readonly input_tokens: number;
1221
+ readonly output_tokens: number;
1263
1222
  };
1264
1223
  }
1265
- interface AnthropicUnknownStreamEvent {
1266
- /** Forward-compatible event type not yet modeled by this SDK. */
1267
- readonly type: string;
1268
- readonly [key: string]: unknown;
1269
- }
1270
- type AnthropicMessageStreamEvent = AnthropicMessageStartEvent | AnthropicContentBlockStartEvent | AnthropicContentBlockDeltaEvent | AnthropicContentBlockStopEvent | AnthropicMessageDeltaEvent | AnthropicMessageStopEvent | AnthropicPingEvent | AnthropicErrorEvent | AnthropicUnknownStreamEvent;
1271
- declare class AnthropicMessagesStream implements AsyncIterable<AnthropicMessageStreamEvent> {
1272
- private readonly source;
1273
- private readonly finalResultPromise;
1274
- private resolveFinal;
1275
- private rejectFinal;
1276
- private removeAbortListener;
1277
- constructor(source: AbortableAsyncIterable<SseEvent>, signal?: AbortSignal);
1278
- get finalResult(): Promise<AnthropicMessagesResponse>;
1279
- abort(): void;
1280
- [Symbol.asyncIterator](): AsyncGenerator<AnthropicMessageStreamEvent, void, undefined>;
1281
- }
1282
- declare class AnthropicCompatClient {
1283
- private readonly http;
1284
- private readonly runner?;
1285
- constructor(http: HttpClient, runner?: RequestRunner | undefined);
1286
- private request;
1287
- createMessage(request: AnthropicMessagesRequest & {
1288
- stream: true;
1289
- }, signal?: AbortSignal): Promise<AnthropicMessagesStream>;
1290
- createMessage(request: AnthropicMessagesRequest & {
1291
- stream?: false | undefined;
1292
- }, signal?: AbortSignal): Promise<AnthropicMessagesResponse>;
1293
- createMessage(request: AnthropicMessagesRequest, signal?: AbortSignal): Promise<AnthropicMessagesResponse | AnthropicMessagesStream>;
1294
- messages(request: AnthropicMessagesRequest & {
1295
- stream: true;
1296
- }, signal?: AbortSignal): Promise<AnthropicMessagesStream>;
1297
- messages(request: AnthropicMessagesRequest & {
1298
- stream?: false | undefined;
1299
- }, signal?: AbortSignal): Promise<AnthropicMessagesResponse>;
1300
- messages(request: AnthropicMessagesRequest, signal?: AbortSignal): Promise<AnthropicMessagesResponse | AnthropicMessagesStream>;
1224
+ /**
1225
+ * Result of a ranking call: candidates sorted by score (highest first),
1226
+ * each with its score and probability distribution.
1227
+ */
1228
+ interface RankResult<T extends string> {
1229
+ readonly candidate: T;
1230
+ readonly score: number;
1231
+ readonly confidence: number;
1301
1232
  }
1233
+ /**
1234
+ * Higher-level System One decision helpers.
1235
+ *
1236
+ * Create via `createDecision(client)` or access via `client.decision`
1237
+ * (if the accessor is wired). Each helper constructs a single-question
1238
+ * System One request and extracts the typed answer.
1239
+ *
1240
+ * Example:
1241
+ * ```ts
1242
+ * const decision = createDecision(client);
1243
+ * const result = await decision.choice({
1244
+ * model: 'tev1:4b',
1245
+ * state: 'Customer was charged twice',
1246
+ * instructions: 'What is the primary intent?',
1247
+ * criteria: {
1248
+ * refund: 'Customer wants a refund',
1249
+ * duplicate_charge: 'Customer reports multiple charges',
1250
+ * cancellation: 'Customer wants to cancel',
1251
+ * },
1252
+ * });
1253
+ * console.log(result.choice); // 'duplicate_charge'
1254
+ * console.log(result.confidence); // 0.89
1255
+ * ```
1256
+ */
1257
+ interface Decision {
1258
+ /**
1259
+ * Ask a single choice question. Returns the selected option + full
1260
+ * probability distribution + confidence.
1261
+ *
1262
+ * Use for: routing, classification, model selection, tool selection,
1263
+ * category assignment — any "which one?" decision with bounded options.
1264
+ */
1265
+ choice(params: {
1266
+ model: string;
1267
+ state: SystemOneContent;
1268
+ instructions: SystemOneContent;
1269
+ criteria: Record<string, string | null>;
1270
+ images?: string[];
1271
+ keepAlive?: string | number;
1272
+ }): Promise<ChoiceDecision>;
1273
+ /**
1274
+ * Ask a single yes/no (noul) question. Returns the probability of
1275
+ * true (0–1) + a boolean derived from it (>= 0.5 → true).
1276
+ *
1277
+ * Use for: gating, verification, safety checks, eligibility, prompt-
1278
+ * injection detection — any "is this true?" decision.
1279
+ */
1280
+ noul(params: {
1281
+ model: string;
1282
+ state: SystemOneContent;
1283
+ instructions: SystemOneContent;
1284
+ images?: string[];
1285
+ keepAlive?: string | number;
1286
+ }): Promise<NoulDecision>;
1287
+ /**
1288
+ * Ask a single score question. Returns the probability-weighted
1289
+ * average score + legend + probability distribution + confidence.
1290
+ *
1291
+ * Use for: severity, priority, difficulty, relevance, quality — any
1292
+ * "how strongly does this fit this ordered rubric?" decision.
1293
+ */
1294
+ score(params: {
1295
+ model: string;
1296
+ state: SystemOneContent;
1297
+ instructions: SystemOneContent;
1298
+ /** Ordered criteria from lowest (index 0) to highest. 2–26 items. */
1299
+ criteria: string[];
1300
+ images?: string[];
1301
+ keepAlive?: string | number;
1302
+ }): Promise<ScoreDecision>;
1303
+ /**
1304
+ * Route a request to one of N named options. Convenience wrapper
1305
+ * around `choice()` that returns just the selected route name.
1306
+ *
1307
+ * Use for: workflow routing, model routing, agent dispatch, tool
1308
+ * selection — any "which handler?" decision.
1309
+ */
1310
+ route<T extends string>(params: {
1311
+ model: string;
1312
+ state: SystemOneContent;
1313
+ instructions: SystemOneContent;
1314
+ criteria: Record<T, string | null>;
1315
+ images?: string[];
1316
+ keepAlive?: string | number;
1317
+ }): Promise<{
1318
+ readonly route: T;
1319
+ readonly confidence: number;
1320
+ }>;
1321
+ /**
1322
+ * Verify whether a claim is supported by evidence. Convenience
1323
+ * wrapper around `noul()` that returns a boolean + the probability
1324
+ * of true (not System One's confidence score — noul answers don't
1325
+ * carry a separate confidence field).
1326
+ *
1327
+ * Use for: evidence verification, safety gates, prompt-injection
1328
+ * detection, compliance checks — any "is this claim true given
1329
+ * this evidence?" decision.
1330
+ */
1331
+ verify(params: {
1332
+ model: string;
1333
+ claim: SystemOneContent;
1334
+ evidence: SystemOneContent;
1335
+ instructions?: SystemOneContent;
1336
+ images?: string[];
1337
+ keepAlive?: string | number;
1338
+ }): Promise<{
1339
+ readonly verified: boolean;
1340
+ readonly probability: number;
1341
+ }>;
1342
+ /**
1343
+ * Rank candidates by score. Sends one System One call per candidate
1344
+ * (parallelized), then sorts by score descending.
1345
+ *
1346
+ * Use for: semantic reranking, candidate ranking, priority scoring,
1347
+ * relevance scoring — any "which of these is best?" decision where
1348
+ * each candidate is scored independently against the same rubric.
1349
+ *
1350
+ * Note: this makes N parallel requests (one per candidate). For
1351
+ * large candidate sets, consider batching or using a single choice
1352
+ * question with all candidates as options instead.
1353
+ */
1354
+ rank<T extends string>(params: {
1355
+ model: string;
1356
+ instructions: SystemOneContent;
1357
+ /** Ordered criteria from lowest (index 0) to highest. 2–26 items. */
1358
+ criteria: string[];
1359
+ candidates: ReadonlyArray<{
1360
+ readonly id: T;
1361
+ readonly state: SystemOneContent;
1362
+ }>;
1363
+ images?: string[];
1364
+ keepAlive?: string | number;
1365
+ }): Promise<ReadonlyArray<RankResult<T>>>;
1366
+ }
1367
+ /** Create a Decision helper bound to an OllamaClient. */
1368
+ declare function createDecision(client: OllamaClient): Decision;
1302
1369
 
1303
1370
  /**
1304
1371
  * High-level Ollama client — the original, hand-written API surface.
@@ -1352,6 +1419,12 @@ declare class OllamaClient {
1352
1419
  * `OLLAMA_API_KEY`), independent of whether `config.endpoints` was used instead.
1353
1420
  */
1354
1421
  private readonly cloudApiKey;
1422
+ /** Configured `defaultContextLength` — injected as `num_ctx` when a request omits it. */
1423
+ private readonly defaultContextLength;
1424
+ /** Configured `contextWarningThreshold` (default 0.9). */
1425
+ private readonly contextWarningThreshold;
1426
+ /** Configured overflow policy — `'warn'` (default) or `'throw'`. */
1427
+ private readonly onContextOverflow;
1355
1428
  constructor(config?: OllamaClientConfig);
1356
1429
  get modelsClient(): ModelsClient;
1357
1430
  /**
@@ -1362,23 +1435,94 @@ declare class OllamaClient {
1362
1435
  * API with the generated `NativeApi` / `OpenAIApi` / `AnthropicApi`
1363
1436
  * surface without configuring two separate HttpClient instances.
1364
1437
  *
1365
- * The returned runtime is bound to the registry's first candidate
1366
- * endpoint (or the resolved single-endpoint config if no `endpoints`
1367
- * array was provided). For multi-endpoint configs that need per-call
1368
- * routing, prefer constructing `OllamaRuntime` directly with a
1369
- * specific HttpClient:
1370
- *
1371
- * ```ts
1372
- * const http = new HttpClient({ baseUrl: 'http://host-a:11434' });
1373
- * const runtime = new OllamaRuntime({ http });
1374
- * const api = new NativeApi(runtime);
1375
- * ```
1438
+ * Wave 14: the runtime now participates in multi-endpoint failover.
1439
+ * Each request is routed through this client's `executeWithFailover`
1440
+ * machinery via a {@link FailoverHttpClient} wrapper. If the first
1441
+ * candidate endpoint is down, requests automatically fail over to
1442
+ * the next healthy candidate — matching the behavior of the
1443
+ * hand-written OllamaClient methods (chat, generate, etc.).
1376
1444
  *
1377
1445
  * The runtime is cached on first call — subsequent calls return the
1378
- * same instance.
1446
+ * same instance. The `FailoverHttpClient` holds a reference to this
1447
+ * client, so it always sees the current endpoint registry state.
1379
1448
  */
1380
1449
  get runtime(): OllamaRuntime;
1381
1450
  private _runtime;
1451
+ /**
1452
+ * Lazily-constructed `NativeApi` bound to this client's runtime. Exposes
1453
+ * the full generated native API surface (chat, generate, embed, systemOne,
1454
+ * etc.) with contract-driven types and runtime enforcement.
1455
+ *
1456
+ * Wave 13: `systemOne()` delegates to this accessor.
1457
+ */
1458
+ get native(): NativeApi;
1459
+ private _nativeApi;
1460
+ /**
1461
+ * Higher-level System One decision helpers (Wave 14B).
1462
+ *
1463
+ * Ergonomic wrappers around `systemOne()` for the six most common
1464
+ * decision patterns: `choice()`, `noul()`, `score()`, `route()`,
1465
+ * `verify()`, `rank()`. Each constructs a single-question request
1466
+ * and extracts the typed answer.
1467
+ *
1468
+ * ```ts
1469
+ * const result = await client.decision.choice({
1470
+ * model: 'tev1:4b',
1471
+ * state: 'Customer was charged twice',
1472
+ * instructions: 'What is the primary intent?',
1473
+ * criteria: {
1474
+ * refund: 'Customer wants a refund',
1475
+ * duplicate_charge: 'Customer reports multiple charges',
1476
+ * },
1477
+ * });
1478
+ * console.log(result.choice); // 'duplicate_charge'
1479
+ * console.log(result.confidence); // 0.89
1480
+ * ```
1481
+ */
1482
+ get decision(): Decision;
1483
+ private _decision;
1484
+ /**
1485
+ * Ergonomic OpenAI Responses API bridge (`client.responses.create()` /
1486
+ * `.stream()`). Dual-mode transport: prefers the native `POST
1487
+ * /v1/responses` endpoint (Ollama ≥ v0.13.3) and transparently re-issues via
1488
+ * `/api/chat` when the server answers 404, so migrating OpenAI code works
1489
+ * unchanged against older servers. See `src/responses.ts`.
1490
+ */
1491
+ get responses(): ResponsesModule;
1492
+ private _responses;
1493
+ /**
1494
+ * Starts a KV-prefix-preserving multi-turn conversation session.
1495
+ *
1496
+ * ```ts
1497
+ * const session = client.session('llama3.1', 'You are a concise assistant.');
1498
+ * const reply = await session.send('Hi!');
1499
+ * const detail = await session.sendTurn('Why is the sky blue?');
1500
+ * detail.cache.hitRate; // per-turn KV-cache hit rate
1501
+ * session.cacheStats; // cumulative stats across turns
1502
+ * ```
1503
+ *
1504
+ * Accepts either `(model, systemPrompt?)` or a full options object
1505
+ * (`{ model, systemPrompt, options, think, keep_alive, tools }`). See
1506
+ * `src/conversation.ts` for why the system prompt is pinned for the
1507
+ * session's lifetime.
1508
+ */
1509
+ session(model: string, systemPrompt?: string): ConversationSession;
1510
+ session(options: ConversationSessionOptions): ConversationSession;
1511
+ /**
1512
+ * Context-window pre-flight enforcement — see `src/context-safety.ts` and
1513
+ * the `defaultContextLength` / `onContextOverflow` config docs. Logs a
1514
+ * warning (default) or throws client-side when the estimated prompt size
1515
+ * is close to / beyond the effective context window.
1516
+ */
1517
+ private enforceContextSafety;
1518
+ /**
1519
+ * Returns `options` with `num_ctx` injected from the client's
1520
+ * `defaultContextLength` when the request didn't set one — making the
1521
+ * effective context window explicit on the wire instead of relying on
1522
+ * Ollama's silently-truncating server default. Returns the original
1523
+ * reference when there's nothing to inject (the common case).
1524
+ */
1525
+ private injectDefaultContextLength;
1382
1526
  /**
1383
1527
  * Fail-fast guard for `format` (structured output) requests: throws before any network
1384
1528
  * call if the candidate endpoint is inferred as Ollama Cloud, which does not currently
@@ -1458,6 +1602,50 @@ declare class OllamaClient {
1458
1602
  readonly version: () => Promise<VersionResponse>;
1459
1603
  readonly createBlob: (digest: string, data: BinaryBody) => Promise<void>;
1460
1604
  readonly checkBlob: (digest: string) => Promise<boolean>;
1605
+ /**
1606
+ * Immediately unloads `model` from VRAM. Convenience alias for
1607
+ * {@link ModelsClient.unload} — see that method for the full
1608
+ * lifecycle contract.
1609
+ */
1610
+ readonly unloadModel: (model: string) => Promise<void>;
1611
+ /**
1612
+ * Pre-loads and pins `model` into VRAM indefinitely. Convenience
1613
+ * alias for {@link ModelsClient.pin} — see that method for the
1614
+ * full lifecycle contract.
1615
+ */
1616
+ readonly pinModel: (model: string) => Promise<void>;
1617
+ /**
1618
+ * Ollama's System One decision layer (`POST /v1/systemone`) — evaluates
1619
+ * 1–64 typed questions (choice, noul, or score) against a provided state
1620
+ * and returns typed answers with probabilities and confidence.
1621
+ *
1622
+ * Local-only; requires Ollama >= 0.35.0. The runtime enforces the
1623
+ * version constraint automatically (lazily fetching `/api/version` when
1624
+ * `enforceVersion` is `'auto'` or `'strict'`) and rejects cloud-mode
1625
+ * calls. Request size is checked client-side: 64 KiB without images,
1626
+ * 32 MiB with images.
1627
+ *
1628
+ * The generic `Q` parameter captures the caller's question map at
1629
+ * compile time, giving key-safe answer access:
1630
+ *
1631
+ * ```ts
1632
+ * const result = await ollama.systemOne({
1633
+ * model: 'tev1:4b',
1634
+ * state: { ticket: 'Customer was charged twice' },
1635
+ * questions: {
1636
+ * intent: { type: 'choice', instructions: '...', criteria: { ... } },
1637
+ * urgent: { type: 'noul', instructions: '...' },
1638
+ * },
1639
+ * });
1640
+ * result.answers.intent // ✓ SystemOneAnswer (choice)
1641
+ * result.answers.urgent // ✓ SystemOneAnswer (noul)
1642
+ * result.answers.typo // ✗ TypeScript error
1643
+ * ```
1644
+ *
1645
+ * For the low-level generated API (without the generic wrapper), use
1646
+ * `client.native.systemOne(request)` directly.
1647
+ */
1648
+ systemOne<Q extends SystemOneQuestions = SystemOneQuestions>(request: SystemOneRequest<Q>): Promise<SystemOneResponse<Q>>;
1461
1649
  /**
1462
1650
  * Ollama's hosted web search tool (`POST https://ollama.com/api/web_search`) — a fixed
1463
1651
  * Ollama Cloud service, unrelated to `config.endpoints`/`baseUrl` and not proxied
@@ -1473,6 +1661,45 @@ declare class OllamaClient {
1473
1661
  * which applies identically here.
1474
1662
  */
1475
1663
  webFetch(req: WebFetchRequestOptions): Promise<WebFetchResponse>;
1664
+ /**
1665
+ * Ollama Cloud usage statistics (`GET https://ollama.com/api/usage`) — request counts,
1666
+ * USD spend, and token totals (including cached input tokens) for cloud inference,
1667
+ * web search, and web fetch, bucketed by hour (`range: '24h'`) or day (`'7d'`/`'30d'`).
1668
+ *
1669
+ * See {@link OllamaClient.webSearch} for the cloud-endpoint/auth/timeout/retry
1670
+ * behavior, which applies identically here. Query parameters mirror the official
1671
+ * endpoint: `range` (`'24h' | '7d' | '30d'`, server default `'7d'`) and `scope`
1672
+ * (`'self' | 'team'`, server default `'self'`; team scope requires a team admin).
1673
+ * Omitted options are left unset so the server applies its own defaults.
1674
+ *
1675
+ * ```ts
1676
+ * const usage = await client.usage({ range: '24h' });
1677
+ * console.log(usage.totals.request_count, usage.totals.usage_usd);
1678
+ * for (const bucket of usage.buckets) {
1679
+ * if (bucket.partial) continue; // current hour, still in progress
1680
+ * // ...
1681
+ * }
1682
+ * ```
1683
+ */
1684
+ usage(req?: UsageRequestOptions): Promise<UsageResponse>;
1685
+ /**
1686
+ * Ollama Cloud balance (`GET https://ollama.com/api/balance`) — remaining included
1687
+ * and purchased usage credits. The included balance is either a plan-period credit
1688
+ * object (`balance_usd`/`allowance_usd`/`period`) or, on legacy plans, session/weekly
1689
+ * percentage limits; the shape is discriminated at runtime by the server response.
1690
+ * See {@link OllamaClient.webSearch} for the cloud-endpoint/auth/timeout/retry
1691
+ * behavior, which applies identically here.
1692
+ *
1693
+ * ```ts
1694
+ * const balance = await client.balance();
1695
+ * if ('balance_usd' in balance.included) {
1696
+ * console.log(balance.included.balance_usd, balance.purchased.balance_usd);
1697
+ * } else {
1698
+ * console.log(balance.included.session.remaining_percent, '% of session limit left');
1699
+ * }
1700
+ * ```
1701
+ */
1702
+ balance(req?: BalanceRequestOptions): Promise<BalanceResponse>;
1476
1703
  /**
1477
1704
  * Runs `operation` against the fixed Ollama Cloud host with this client's default
1478
1705
  * timeout and retry policy — the same primitives `executeWithFailover` uses, minus the
@@ -1499,6 +1726,269 @@ interface TimeoutSignal {
1499
1726
  */
1500
1727
  declare function createTimeoutSignal(timeoutMs?: number, userSignal?: AbortSignal): TimeoutSignal;
1501
1728
 
1729
+ /**
1730
+ * Standalone fetch-with-backoff helper.
1731
+ *
1732
+ * Ollama's server caps in-flight work via `OLLAMA_MAX_QUEUE` (default
1733
+ * 512); when the queue saturates, excess requests are rejected with
1734
+ * HTTP **503 Service Unavailable**. The same retry discipline applies
1735
+ * to **429 Too Many Requests** for rate-limited cloud endpoints.
1736
+ *
1737
+ * Callers running parallel agentic swarms (multi-turn tool loops,
1738
+ * fan-out embed batches, speculative-decoding pipelines) can't always
1739
+ * predict saturation ahead of time, so the SDK exposes this helper —
1740
+ * a thin wrapper around `fetch` that retries 503/429 responses with
1741
+ * the same jittered exponential backoff used by the SDK's internal
1742
+ * transport (see `./backoff.ts` and `./retry.ts`).
1743
+ *
1744
+ * The helper is intentionally standalone: it works with any
1745
+ * `fetch`-shaped function (browser `globalThis.fetch`, `undici`, an
1746
+ * Edge runtime polyfill, or a `vi.fn()` mock) and does not depend on
1747
+ * the wider `OllamaClient` / `HttpClient` machinery. Use it when you
1748
+ * want the SDK's retry ergonomics on raw HTTP traffic that doesn't go
1749
+ * through `OllamaClient` — for example, when calling the OpenAI / Anthropic
1750
+ * compatibility bridges directly, or when talking to a sibling Ollama
1751
+ * instance outside the configured endpoint registry.
1752
+ *
1753
+ * For SDK-routed traffic (`client.chat`, `client.generate`, …),
1754
+ * retry/backoff is already applied automatically by the transport
1755
+ * layer; you do NOT need to wrap those calls in `fetchWithBackoff`.
1756
+ */
1757
+
1758
+ /**
1759
+ * Configuration for {@link fetchWithBackoff}.
1760
+ *
1761
+ * All fields optional; sensible defaults are provided.
1762
+ */
1763
+ interface FetchWithBackoffConfig {
1764
+ /**
1765
+ * Maximum number of retry attempts after the initial request.
1766
+ * Defaults to `3` (i.e. up to 4 total HTTP requests).
1767
+ */
1768
+ readonly maxRetries?: number | undefined;
1769
+ /**
1770
+ * Backoff tuning. Defaults to {@link DEFAULT_BACKOFF}
1771
+ * (`initialDelayMs: 500`, `maxDelayMs: 30_000`, `backoffFactor: 2`).
1772
+ */
1773
+ readonly backoff?: BackoffOptions | undefined;
1774
+ /**
1775
+ * Optional callback fired before each retry sleep. Useful for
1776
+ * logging, OpenTelemetry span events, or surfacing the
1777
+ * backoff in observability dashboards.
1778
+ *
1779
+ * Receives the attempt index (0-based for the original request,
1780
+ * 1+ for retries), the HTTP status that triggered the retry
1781
+ * (or `0` for network-level failures), and the calculated delay
1782
+ * in milliseconds (already jittered).
1783
+ */
1784
+ readonly onRetry?: ((attempt: number, status: number, delayMs: number) => void) | undefined;
1785
+ /**
1786
+ * Optional `AbortSignal` forwarded to the underlying `fetch`.
1787
+ * Aborting mid-backoff cancels the sleep and rejects with an
1788
+ * `AbortError`-shaped error (the same shape `fetch` itself
1789
+ * rejects with on abort).
1790
+ */
1791
+ readonly signal?: AbortSignal | undefined;
1792
+ /**
1793
+ * Optional `fetch` implementation to use. Defaults to
1794
+ * `globalThis.fetch`. Pass an explicit implementation when
1795
+ * running in environments without a global `fetch` (legacy
1796
+ * Node.js, custom sandboxes), or to inject a mock for testing.
1797
+ */
1798
+ readonly fetch?: typeof globalThis.fetch | undefined;
1799
+ }
1800
+ /**
1801
+ * HTTP statuses that trigger a retry by default. Both indicate
1802
+ * transient, server-side saturation — the queue is full and the
1803
+ * request is rejected without consuming inference resources.
1804
+ *
1805
+ * - `503 Service Unavailable` — Ollama queue saturated
1806
+ * (`OLLAMA_MAX_QUEUE` exceeded).
1807
+ * - `429 Too Many Requests` — rate limit hit (typically Ollama
1808
+ * Cloud endpoints).
1809
+ */
1810
+ declare const RETRYABLE_STATUS_CODES: ReadonlySet<number>;
1811
+ /**
1812
+ * Default retry configuration used when {@link FetchWithBackoffConfig}
1813
+ * is omitted entirely. Matches the SDK's internal transport defaults
1814
+ * so consumers see identical retry behavior whether they go through
1815
+ * `OllamaClient` or call `fetchWithBackoff` directly.
1816
+ */
1817
+ declare const DEFAULT_FETCH_BACKOFF_CONFIG: {
1818
+ readonly maxRetries: 3;
1819
+ };
1820
+ /**
1821
+ * Wrapper around any `fetch`-shaped function that retries HTTP 429 / 503
1822
+ * responses with jittered exponential backoff (full-jitter strategy —
1823
+ * see `./backoff.ts` for the rationale and AWS Architecture Blog
1824
+ * citation).
1825
+ *
1826
+ * The wrapper:
1827
+ * - forwards `input`/`init` unchanged to every attempt,
1828
+ * - sleeps before each retry using the configured backoff,
1829
+ * - retries up to `maxRetries` times (default 3), then returns the
1830
+ * final `Response` (whatever its status) so the caller can
1831
+ * branch on it,
1832
+ * - rethrows network errors (TypeError under WHATWG fetch) only
1833
+ * after exhausting retries — intermediate attempts also sleep,
1834
+ * - honors `AbortSignal` for both the underlying `fetch` and the
1835
+ * sleep between retries.
1836
+ *
1837
+ * @example
1838
+ * ```ts
1839
+ * const res = await fetchWithBackoff(
1840
+ * 'http://localhost:11434/api/chat',
1841
+ * { method: 'POST', body: JSON.stringify(payload) },
1842
+ * {
1843
+ * maxRetries: 5,
1844
+ * onRetry: (attempt, status, delayMs) =>
1845
+ * console.warn(`retry ${attempt} (HTTP ${status}) in ${delayMs}ms`),
1846
+ * },
1847
+ * );
1848
+ * if (!res.ok) throw new Error(`chat failed: HTTP ${res.status}`);
1849
+ * ```
1850
+ */
1851
+ declare function fetchWithBackoff(input: string | URL | Request, init?: RequestInit | undefined, config?: FetchWithBackoffConfig): Promise<Response>;
1852
+
1853
+ /**
1854
+ * VRAM lifecycle helpers — ergonomic `keep_alive` primitives.
1855
+ *
1856
+ * Ollama's `keep_alive` parameter (accepted by `/api/generate`,
1857
+ * `/api/chat`, `/api/embed`, `/api/embeddings`, and `/v1/systemone`)
1858
+ * controls how long a model remains resident in VRAM after a request
1859
+ * completes. The upstream spec defines four operational semantics:
1860
+ *
1861
+ * - **Duration string** (`"5m"`, `"10s"`, `"24h"`) — explicit window.
1862
+ * - **Integer seconds** (`3600`, `300`) — explicit window in seconds.
1863
+ * - **Indefinite pinning** (`-1` or `"-1m"`) — keep the model
1864
+ * permanently resident in VRAM until the server is restarted or
1865
+ * an explicit `0` request is made. Useful for hot-loop inference
1866
+ * where load latency dominates.
1867
+ * - **Immediate eviction** (`0` or `"0s"`) — unload the model from
1868
+ * VRAM as soon as the response is finalized. Frees GPU memory
1869
+ * for the next pipeline (e.g. swap a vision model out before
1870
+ * loading an LLM).
1871
+ *
1872
+ * These primitives let callers express VRAM-lifecycle intent with
1873
+ * readable names instead of magic integers, while preserving full
1874
+ * backward compatibility with raw `string | number` values.
1875
+ *
1876
+ * See: https://github.com/ollama/ollama/blob/main/docs/faq.md
1877
+ * #how-do-i-keep-a-model-loaded-in-memory-or-make-it-unload-immediately
1878
+ */
1879
+ /**
1880
+ * Sentinel value that, when passed as `keep_alive`, instructs the
1881
+ * server to evict the model from VRAM as soon as the in-flight
1882
+ * request finalizes its response. Equivalent to passing `0` or
1883
+ * `"0s"`.
1884
+ */
1885
+ declare const KEEP_ALIVE_UNLOAD: 0;
1886
+ /**
1887
+ * Sentinel value that, when passed as `keep_alive`, instructs the
1888
+ * server to keep the model resident in VRAM indefinitely (until
1889
+ * the server is restarted or an explicit `0` request arrives).
1890
+ * Equivalent to passing `-1` or `"-1m"`.
1891
+ */
1892
+ declare const KEEP_ALIVE_INDEFINITE: -1;
1893
+ /**
1894
+ * Ergonomic union for the `keep_alive` field on chat/generate/embed/
1895
+ * embeddings/System One requests.
1896
+ *
1897
+ * Accepts every upstream-supported shape plus two SDK-level sugar
1898
+ * literals:
1899
+ *
1900
+ * - `'unload'` — same as `0`; frees GPU VRAM after this request.
1901
+ * - `'indefinite'` — same as `-1`; pins the model in VRAM until
1902
+ * an explicit unload.
1903
+ *
1904
+ * Use {@link normalizeKeepAlive} to convert this into the raw
1905
+ * `string | number` shape the wire expects.
1906
+ */
1907
+ type KeepAlive = string | number | 'unload' | 'indefinite';
1908
+ /**
1909
+ * Convert a {@link KeepAlive} value into the raw `string | number`
1910
+ * shape Ollama's REST API expects.
1911
+ *
1912
+ * - `'unload'` → `0` (immediate eviction)
1913
+ * - `'indefinite'` → `-1` (perpetual pinning)
1914
+ * - everything else is passed through unchanged
1915
+ *
1916
+ * Returns `undefined` for `undefined` input so callers can pipe
1917
+ * optional fields straight through without conditional spreads.
1918
+ *
1919
+ * @example
1920
+ * normalizeKeepAlive('unload') // → 0
1921
+ * normalizeKeepAlive('indefinite') // → -1
1922
+ * normalizeKeepAlive('5m') // → '5m'
1923
+ * normalizeKeepAlive(3600) // → 3600
1924
+ * normalizeKeepAlive(undefined) // → undefined
1925
+ */
1926
+ declare function normalizeKeepAlive(keepAlive: KeepAlive | undefined): string | number | undefined;
1927
+ /**
1928
+ * Type guard: `true` when the value is one of the SDK-level sugar
1929
+ * literals (`'unload'` or `'indefinite'`). Useful for callers that
1930
+ * want to branch on intent rather than magic integers.
1931
+ */
1932
+ declare function isKeepAliveSugar(value: KeepAlive | unknown): value is 'unload' | 'indefinite';
1933
+
1934
+ /**
1935
+ * `done_reason` decoder helpers — graceful handling of upstream
1936
+ * variance in the `done_reason` field returned by `/api/chat` and
1937
+ * `/api/generate`.
1938
+ *
1939
+ * The Ollama OpenAPI documents `done_reason` as a free-form string,
1940
+ * but the values actually observed on the wire fall into a small,
1941
+ * stable set:
1942
+ *
1943
+ * - `"stop"` — natural stop token hit or end-of-text.
1944
+ * - `"length"` — `num_predict` ceiling reached mid-generation.
1945
+ * - `"load"` — model load event (seen in streaming chunks
1946
+ * before the first token is generated; the
1947
+ * server reports `done: true` with `done_reason:
1948
+ * 'load'` to indicate the load phase completed).
1949
+ * - `"unload"` — model unloaded (seen after a `keep_alive: 0`
1950
+ * request finalizes the unload).
1951
+ *
1952
+ * The SDK accepts any string for `done_reason` (so unknown values
1953
+ * don't cause runtime errors — the conformance-test failure mode
1954
+ * the Wave 13 CI run flagged). These helpers give callers who want
1955
+ * to narrow on the known set a type-safe way to do so.
1956
+ *
1957
+ * See: https://github.com/ollama/ollama/blob/main/docs/api.md
1958
+ */
1959
+ /**
1960
+ * The set of `done_reason` values Ollama documents and emits in
1961
+ * practice. Unknown upstream additions pass through as plain
1962
+ * strings — use {@link isKnownDoneReason} to narrow.
1963
+ */
1964
+ type KnownDoneReason = 'stop' | 'length' | 'load' | 'unload';
1965
+ /**
1966
+ * Set of known `done_reason` literals, exposed for callers building
1967
+ * exhaustive `switch` statements or runtime validation tables.
1968
+ */
1969
+ declare const KNOWN_DONE_REASONS: ReadonlySet<KnownDoneReason>;
1970
+ /**
1971
+ * Type guard: `true` when `value` is one of the documented
1972
+ * `done_reason` literals. Use this to safely narrow from
1973
+ * `string | undefined` to {@link KnownDoneReason} before a
1974
+ * `switch` block.
1975
+ *
1976
+ * @example
1977
+ * ```ts
1978
+ * if (isKnownDoneReason(res.done_reason)) {
1979
+ * switch (res.done_reason) {
1980
+ * case 'stop': // …
1981
+ * case 'length': // …
1982
+ * case 'load': // …
1983
+ * case 'unload': // …
1984
+ * }
1985
+ * } else {
1986
+ * // forward-compat: an unknown reason we didn't list
1987
+ * }
1988
+ * ```
1989
+ */
1990
+ declare function isKnownDoneReason(value: string | undefined | null): value is KnownDoneReason;
1991
+
1502
1992
  /**
1503
1993
  * Normalization mappers and aggregators for Ollama streaming responses.
1504
1994
  */
@@ -1509,9 +1999,27 @@ declare function normalizeProgressStream(source: AbortableAsyncIterable<Progress
1509
1999
 
1510
2000
  /**
1511
2001
  * NDJSON (newline-delimited JSON) stream reader for native fetch Response bodies.
2002
+ *
2003
+ * Ollama's streaming endpoints (chat / generate / pull / push / create)
2004
+ * emit newline-delimited JSON objects. Each line is a complete JSON
2005
+ * document. The transport is chunked HTTP with status 200 OK — meaning
2006
+ * the HTTP status never changes mid-stream even when the server
2007
+ * encounters an error after generation has started.
2008
+ *
2009
+ * Instead, Ollama emits a final JSON frame of the form
2010
+ * `{"error": "..."}` and closes the stream. This reader detects such
2011
+ * in-band error frames and throws {@link OllamaStreamError} immediately,
2012
+ * so callers don't see the error message bleed into the assistant's
2013
+ * content stream as garbage tokens.
1512
2014
  */
1513
2015
  /**
1514
2016
  * Parses a byte stream from fetch body into an async generator of typed JSON chunks.
2017
+ *
2018
+ * Throws {@link OllamaStreamError} immediately upon encountering an
2019
+ * in-band `{"error": "..."}` frame. The thrown error carries an empty
2020
+ * `partialContent` (this low-level parser does not accumulate content;
2021
+ * the higher-level aggregator in `streaming/normalize.ts` is the
2022
+ * right place to surface partial content if needed).
1515
2023
  */
1516
2024
  declare function parseNdjsonStream<T>(stream: ReadableStream<Uint8Array>): AsyncGenerator<T, void, undefined>;
1517
2025
 
@@ -1653,6 +2161,184 @@ interface DefineToolOptions<TParams, TResult> {
1653
2161
  */
1654
2162
  declare function defineTool<TParams, TResult>(options: DefineToolOptions<TParams, TResult>): Tool<TParams, TResult>;
1655
2163
 
2164
+ /**
2165
+ * Tool-call streaming accumulator — defensive merge logic for
2166
+ * `message.tool_calls` arrays that arrive across multiple NDJSON
2167
+ * chunks.
2168
+ *
2169
+ * ## When this matters
2170
+ *
2171
+ * Ollama's **native `/api/chat`** streaming protocol emits
2172
+ * `message.tool_calls` as a complete JSON array (with parsed-object
2173
+ * `arguments`, not stringified deltas) in a single `done: true` chunk.
2174
+ * For native streaming, the accumulator here is mostly a no-op —
2175
+ * one chunk carries the full array, the next chunk has nothing.
2176
+ *
2177
+ * The accumulator becomes load-bearing in three scenarios:
2178
+ *
2179
+ * 1. **OpenAI-compat streaming** (`/v1/chat/completions` with
2180
+ * `stream: true`): tool call arguments come as string deltas
2181
+ * spread across multiple chunks, identified by `index`. The
2182
+ * compat layer at `src/integrations/openai.ts` already does
2183
+ * its own per-index accumulation; this utility exists for
2184
+ * callers who want the same logic on raw NDJSON chunks.
2185
+ *
2186
+ * 2. **Defensive native streaming**: although the documented
2187
+ * Ollama behavior is "tool_calls arrive in the final chunk",
2188
+ * a future server version could legitimately stream them
2189
+ * incrementally. The SDK shouldn't crash or produce
2190
+ * duplicates if that happens.
2191
+ *
2192
+ * 3. **Caller-side buffering**: agent loops that consume
2193
+ * `OllamaStream` events directly may want to buffer tool-call
2194
+ * deltas themselves rather than trust the SDK's aggregator —
2195
+ * this utility gives them a typed, tested building block.
2196
+ *
2197
+ * ## Merge semantics
2198
+ *
2199
+ * Two `ToolCall` entries are considered "the same call" when they
2200
+ * share the same `id` (the SDK-synthesized stable identifier — see
2201
+ * `src/tools/tool-call-id.ts`), OR when they're at the same array
2202
+ * position and neither has an `id`. When two same-call entries are
2203
+ * merged:
2204
+ *
2205
+ * - `function.name` — the later chunk's name wins (the model may
2206
+ * emit the name in a later chunk after an initial empty one).
2207
+ * - `function.arguments` — the two objects are merged with
2208
+ * spread semantics: `{...earlier, ...later}`. This handles
2209
+ * the case where the model emits arguments incrementally as
2210
+ * partial JSON objects (which is non-standard but seen in some
2211
+ * open-weights fine-tunes).
2212
+ *
2213
+ * For arguments-as-string deltas (the OpenAI-compat case), the
2214
+ * accumulator concatenates the strings rather than merging — see
2215
+ * {@link mergeToolCallArgumentsString}.
2216
+ */
2217
+
2218
+ /**
2219
+ * Determine whether two `ToolCall` entries refer to the same logical
2220
+ * call (and should therefore be merged rather than appended).
2221
+ *
2222
+ * Returns `true` when:
2223
+ * - both have an `id` and the ids match, OR
2224
+ * - neither has an `id` and they're at the same array index
2225
+ * (caller is responsible for the index check — this helper
2226
+ * only handles the id case).
2227
+ */
2228
+ declare function isSameToolCall(a: ToolCall, b: ToolCall, aIndex?: number, bIndex?: number): boolean;
2229
+ /**
2230
+ * Merge two `ToolCall` entries that refer to the same logical call.
2231
+ *
2232
+ * The later chunk's `function.name` wins when present; otherwise the
2233
+ * earlier one's name is preserved. The two `arguments` objects are
2234
+ * merged with spread semantics (`{...earlier, ...later}`), which
2235
+ * handles the (non-standard but observed) case where the model
2236
+ * emits arguments as partial JSON objects across chunks.
2237
+ *
2238
+ * For arguments-as-string deltas (OpenAI-compat streaming), use
2239
+ * {@link mergeToolCallArgumentsString} instead.
2240
+ */
2241
+ declare function mergeToolCall(earlier: ToolCall, later: ToolCall): ToolCall;
2242
+ /**
2243
+ * Merge two `ToolCall` entries where `function.arguments` is a JSON
2244
+ * string (the OpenAI-compat streaming format), concatenating the
2245
+ * string deltas rather than spreading objects.
2246
+ *
2247
+ * Returns a `ToolCall` whose `function.arguments` is the
2248
+ * concatenated string. The caller is responsible for JSON-parsing
2249
+ * the final string when the stream completes.
2250
+ */
2251
+ declare function mergeToolCallArgumentsString(earlier: ToolCall, later: ToolCall): ToolCall;
2252
+ /**
2253
+ * Defensive accumulator for `message.tool_calls` arrays that arrive
2254
+ * across multiple NDJSON chunks. Used internally by
2255
+ * `aggregateChat` in `src/streaming/normalize.ts` so the SDK doesn't
2256
+ * produce duplicate tool_call entries if a future server version
2257
+ * starts streaming them incrementally.
2258
+ *
2259
+ * The merge strategy is:
2260
+ *
2261
+ * - For each tool call in the new chunk, check whether an existing
2262
+ * entry matches (by `id` if both have one, by array position
2263
+ * otherwise).
2264
+ * - If a match is found, merge the two entries via
2265
+ * {@link mergeToolCall}.
2266
+ * - If no match is found, append the new entry.
2267
+ *
2268
+ * This preserves the documented native Ollama behavior (tool_calls
2269
+ * arrive complete in one chunk → no merge happens, just one append)
2270
+ * while being defensive against incremental streaming.
2271
+ *
2272
+ * @example
2273
+ * ```ts
2274
+ * const acc = new ToolCallAccumulator();
2275
+ * acc.process([
2276
+ * { function: { name: 'get_weather', arguments: { city: 'Tokyo' } } },
2277
+ * ]);
2278
+ * acc.process([
2279
+ * { function: { name: 'get_weather', arguments: { unit: 'celsius' } } },
2280
+ * ]);
2281
+ * const result = acc.finalize();
2282
+ * // → [{ function: { name: 'get_weather', arguments: { city: 'Tokyo', unit: 'celsius' } } }]
2283
+ * ```
2284
+ */
2285
+ declare class ToolCallAccumulator {
2286
+ private readonly entries;
2287
+ /**
2288
+ * Process a chunk's `tool_calls` array. Entries that match an
2289
+ * existing accumulated entry (by id or array position) are merged;
2290
+ * new entries are appended.
2291
+ *
2292
+ * Returns the current accumulated state (a shallow copy — entries
2293
+ * themselves are NOT deep-cloned, so callers that mutate
2294
+ * `function.arguments` on a returned entry will mutate the
2295
+ * accumulator's internal state. Use {@link snapshot} for an
2296
+ * explicitly read-only view, or deep-clone the result if you need
2297
+ * full isolation).
2298
+ */
2299
+ process(toolCalls: readonly ToolCall[] | undefined): readonly ToolCall[];
2300
+ /**
2301
+ * Returns the final accumulated tool calls. Identical to calling
2302
+ * `process(undefined)` — included for ergonomics so callers can
2303
+ * express "I'm done, give me the result" without a no-op call.
2304
+ *
2305
+ * The returned array is a shallow copy; entries themselves are
2306
+ * the same object references the accumulator holds internally.
2307
+ */
2308
+ finalize(): readonly ToolCall[];
2309
+ /**
2310
+ * Returns the current accumulated state without modifying the
2311
+ * accumulator. Useful for mid-stream inspection.
2312
+ *
2313
+ * The returned array is a shallow copy; mutating it (e.g.
2314
+ * `result.push(...)`) does not affect the accumulator, but
2315
+ * mutating an entry's `function.arguments` object DOES affect
2316
+ * the accumulator's internal state because the entry reference
2317
+ * is shared. Deep-clone the result if you need full isolation.
2318
+ */
2319
+ snapshot(): readonly ToolCall[];
2320
+ /**
2321
+ * Returns the number of accumulated tool calls so far.
2322
+ */
2323
+ get length(): number;
2324
+ }
2325
+ /**
2326
+ * Convenience function: merge two `tool_calls` arrays using the
2327
+ * default accumulator semantics, returning the merged array.
2328
+ *
2329
+ * Stateless equivalent of:
2330
+ *
2331
+ * ```ts
2332
+ * const acc = new ToolCallAccumulator();
2333
+ * acc.process(earlier);
2334
+ * acc.process(later);
2335
+ * return acc.finalize();
2336
+ * ```
2337
+ *
2338
+ * Useful for one-off merges without instantiating an accumulator.
2339
+ */
2340
+ declare function mergeToolCallArrays(earlier: readonly ToolCall[] | undefined, later: readonly ToolCall[] | undefined): readonly ToolCall[];
2341
+
1656
2342
  /**
1657
2343
  * Converts MCP tools into Ollama-compatible tools.
1658
2344
  */
@@ -1844,15 +2530,131 @@ declare const GEN_AI_SYSTEM_OLLAMA = "ollama";
1844
2530
  * Cross-runtime helpers with no Node.js API dependency, so they stay safe to import from
1845
2531
  * the core client bundle (see ADR 0006 — Edge Runtime CI).
1846
2532
  */
2533
+
1847
2534
  /**
1848
2535
  * Encodes an image to a base64 string, matching the wire format Ollama's `/api/chat` and
1849
2536
  * `/api/generate` `images` arrays expect.
1850
2537
  *
1851
- * - A `string` is assumed to already be base64-encoded and is returned unchanged.
1852
- * - A `Uint8Array` is base64-encoded using whichever universal primitive the runtime
1853
- * exposes: `Buffer` on Node.js, `btoa` on browsers/Edge runtimes. Chunked so it doesn't
1854
- * blow the engine's max call-stack/argument-count limits on large images.
2538
+ * - A `string` is assumed to already be base64-encoded and is returned unchanged. For
2539
+ * data URIs, URLs, and local file paths use {@link resolveImageInput}, which this SDK's
2540
+ * request pipeline applies automatically (see {@link withEncodedImages}).
2541
+ * - A `Uint8Array` (or Node `Buffer`) is base64-encoded using whichever universal primitive
2542
+ * the runtime exposes: `Buffer` on Node.js, `btoa` on browsers/Edge runtimes. Chunked so it
2543
+ * doesn't blow the engine's max call-stack/argument-count limits on large images.
2544
+ */
2545
+ declare function encodeImage(image: VisionInput): Promise<string>;
2546
+
2547
+ /**
2548
+ * Context-window safety: client-side token estimation and pre-flight overflow
2549
+ * warnings for `/api/chat` and `/api/generate`.
2550
+ *
2551
+ * Why this exists: when `options.num_ctx` is left unset, Ollama loads the
2552
+ * model with a conservative default context window (commonly 2048–4096
2553
+ * tokens, model-dependent) and **silently truncates** any prompt that doesn't
2554
+ * fit — the model just loses the top of the conversation with no error, no
2555
+ * warning, and often no visible symptom beyond degraded answers. This module
2556
+ * estimates the prompt size client-side (a fast heuristic — no tokenizer
2557
+ * download, no model dependency) and surfaces a warning *before* the request
2558
+ * is sent, when the estimate approaches the effective context window.
2559
+ *
2560
+ * The estimator is deliberately simple and documented as approximate
2561
+ * (±20–30% vs a real BPE tokenizer):
2562
+ *
2563
+ * - CJK code points (Chinese/Japanese/Korean) count as ~1 token each —
2564
+ * modern tokenizers emit roughly one token per CJK character.
2565
+ * - Everything else estimates at ~4 characters per token, the classic
2566
+ * English GPT-style average.
2567
+ * - Each attached image adds a fixed {@link IMAGE_TOKEN_ESTIMATE} —
2568
+ * vision encoders consume a roughly predictable tile budget per image
2569
+ * (e.g. LLaVA-family encoders emit a few hundred tokens per image).
2570
+ *
2571
+ * It is used in three places:
2572
+ *
2573
+ * 1. `OllamaClient.chat()`/`generate()` pre-flight — logs a warning (or
2574
+ * throws, per `onContextOverflow`) when the estimate crosses
2575
+ * {@link DEFAULT_CONTEXT_WARNING_THRESHOLD} of the effective window.
2576
+ * 2. The `defaultContextLength` client config — injects `num_ctx` when the
2577
+ * caller didn't set one, making the effective window explicit instead
2578
+ * of server-default guesswork.
2579
+ * 3. `ConversationSession` — sessions grow monotonically, so they surface
2580
+ * cache and context stats per turn.
2581
+ */
2582
+
2583
+ /**
2584
+ * Fraction of the effective context window at which a pre-flight warning
2585
+ * fires. 0.9 = warn when the estimated prompt reaches 90% of `num_ctx`.
2586
+ * Above this, the response has little room left and the next turn's history
2587
+ * will almost certainly overflow.
2588
+ */
2589
+ declare const DEFAULT_CONTEXT_WARNING_THRESHOLD = 0.9;
2590
+ /**
2591
+ * Rough token budget consumed per attached image. Vision encoders emit a few
2592
+ * hundred embedding tokens per image tile; 300 sits between LLaVA-1.5's ~258
2593
+ * and qwen-vl's higher tile counts. This is an estimate for warning purposes
2594
+ * only — it never gates a request on its own unless images push the total
2595
+ * past the threshold.
2596
+ */
2597
+ declare const IMAGE_TOKEN_ESTIMATE = 300;
2598
+ /**
2599
+ * Heuristic token estimate for a single text string: ~1 token per CJK
2600
+ * character + ~1 token per 4 non-CJK characters. Approximate by design —
2601
+ * accurate enough to warn against silent truncation without shipping a
2602
+ * model-specific tokenizer.
2603
+ */
2604
+ declare function estimateTokens(text: string): number;
2605
+ /**
2606
+ * Estimated prompt tokens for a `/api/chat` request: every message plus
2607
+ * tool-schema overhead (each tool definition's JSON schema serializes into
2608
+ * the prompt on Ollama's side).
2609
+ */
2610
+ declare function estimateChatRequestTokens(req: ChatRequestOptions): number;
2611
+ /** Estimated prompt tokens for a `/api/generate` request (prompt + system + images). */
2612
+ declare function estimateGenerateRequestTokens(req: GenerateRequestOptions): number;
2613
+ /** Where the context window used by a pre-flight check came from. */
2614
+ type ContextWindowSource =
2615
+ /** Explicit `options.num_ctx` on the request — exact, server-enforced. */
2616
+ 'request'
2617
+ /** Client `defaultContextLength` config — injected as `num_ctx` by the pipeline. */
2618
+ | 'client-default'
2619
+ /** Neither set; Ollama's server default applies (2048–4096, model-dependent). */
2620
+ | 'server-fallback';
2621
+ /** What the pre-flight check concluded about one request. */
2622
+ interface ContextCheck {
2623
+ /** Estimated prompt tokens (heuristic — see {@link estimateTokens}). */
2624
+ readonly estimatedPromptTokens: number;
2625
+ /** The context window the estimate was compared against. */
2626
+ readonly effectiveContextLength: number;
2627
+ /** Where that window came from. */
2628
+ readonly windowSource: ContextWindowSource;
2629
+ /** True when the estimate crossed the warning threshold of the effective window. */
2630
+ readonly exceedsThreshold: boolean;
2631
+ }
2632
+ interface ContextCheckOptions {
2633
+ /** Client `defaultContextLength`, applied when the request doesn't set `num_ctx`. */
2634
+ readonly defaultContextLength?: number | undefined;
2635
+ /** Warning threshold; defaults to {@link DEFAULT_CONTEXT_WARNING_THRESHOLD}. */
2636
+ readonly threshold?: number | undefined;
2637
+ }
2638
+ /**
2639
+ * Runs the pre-flight context check for a chat request. Pure — callers decide
2640
+ * what to do with the result (log, throw, ignore).
2641
+ */
2642
+ declare function checkChatContext(req: ChatRequestOptions, options?: ContextCheckOptions): ContextCheck;
2643
+ /**
2644
+ * Runs the pre-flight context check for a generate request. Pure — callers
2645
+ * decide what to do with the result (log, throw, ignore).
2646
+ */
2647
+ declare function checkGenerateContext(req: GenerateRequestOptions, options?: ContextCheckOptions): ContextCheck;
2648
+ /**
2649
+ * The conservative server-side default (2048) Ollama most commonly applies
2650
+ * when `num_ctx` is unset — used to warn about *likely* truncation even when
2651
+ * no effective window is known client-side.
2652
+ */
2653
+ declare const OLLAMA_FALLBACK_CONTEXT_LENGTH = 2048;
2654
+ /**
2655
+ * Builds the human-readable warning text for a failed pre-flight check.
2656
+ * Exported for reuse by `ConversationSession` and for tests.
1855
2657
  */
1856
- declare function encodeImage(image: Uint8Array | string): Promise<string>;
2658
+ declare function contextWarningMessage(check: ContextCheck, kind: 'chat' | 'generate'): string;
1857
2659
 
1858
- export { ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_SYSTEM, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_OLLAMA_AGENT_ITERATION, ATTR_OLLAMA_AGENT_MAX_ITERATIONS, ATTR_OLLAMA_ENDPOINT_ATTEMPT, ATTR_OLLAMA_ENDPOINT_NAME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_FULL, AbortableAsyncIterable, Agent, type AgentChatClient, type AgentConfig, type AgentHooks, type AgentResult, type AgentRunInput, type AgentTurn, type AnthropicCacheControl, AnthropicCompatClient, type AnthropicContentBlock, type AnthropicImageContentBlock, type AnthropicMessage, type AnthropicMessageStreamEvent, type AnthropicMessagesRequest, type AnthropicMessagesResponse, AnthropicMessagesStream, type AnthropicMetadata, type AnthropicOutputConfig, type AnthropicRedactedThinkingContentBlock, type AnthropicSystem, type AnthropicSystemTextBlock, type AnthropicTextContentBlock, type AnthropicThinkingConfig, type AnthropicThinkingContentBlock, type AnthropicTool, type AnthropicToolChoice, type AnthropicToolResultContentBlock, type AnthropicToolUseContentBlock, type AnthropicUnknownStreamEvent, AnyTool, type BackoffOptions, ChatRequestOptions, ChatResponse, ChatStreamResult, CopyRequestOptions, CreateRequestOptions, DEFAULT_BACKOFF, DEFAULT_BASE_URL, DEFAULT_FAILOVER_CODES, DEFAULT_RETRY_CONFIG, DEFAULT_TIMEOUT_MS, type DefineToolOptions, DeleteRequestOptions, EmbedRequestOptions, EmbedResponse, EmbeddingsRequestOptions, EmbeddingsResponse, type EndpointHealth, type EndpointHealthCheckResult, EndpointRegistry, type EndpointRegistryOptions, FetchLike, GEN_AI_SYSTEM_OLLAMA, GenerateRequestOptions, GenerateResponse, GenerateStreamResult, HttpClient, type LoadMcpToolsOptions, Logger, McpBridge, type McpBridgeOptions, McpCallToolResult, McpClientLike, McpTask, McpToolDescriptor, Message, Middleware, type ModelCapabilities, ModelOptions, ModelResponse, ModelsClient, OLLAMA_CLOUD_BASE_URL, type OllamaAnthropicContentBlock, type OllamaAnthropicMessage, type OllamaAnthropicMessagesRequest, type OllamaAnthropicSystem, type OllamaAnthropicSystemTextBlock, type OllamaAnthropicTextContentBlock, type OllamaAnthropicThinkingConfig, type OllamaAnthropicTool, type OllamaAnthropicToolResultContentBlock, OllamaClient, type OllamaClientConfig, OllamaClientError, type OllamaCloudFreeTierQuotaBudgets, type OllamaCredentialConfig, type OllamaEndpoint, type OllamaOpenAIChatCompletionRequest, type OllamaOpenAICompletionRequest, type OllamaOpenAIEmbeddingRequest, type OllamaOpenAIReasoningEffort, type OllamaOpenAIResponsesRequest, OllamaStream, OllamaStreamEvent, OllamaStreamEventType, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionChunkChoice, type OpenAIChatCompletionDelta, type OpenAIChatCompletionRequest, type OpenAIChatCompletionResponse, OpenAIChatCompletionStream, OpenAICompatClient, type OpenAICompletionChoice, type OpenAICompletionChunk, type OpenAICompletionRequest, type OpenAICompletionResponse, OpenAICompletionStream, type OpenAIContentPart, type OpenAIEmbeddingInput, type OpenAIEmbeddingItem, type OpenAIEmbeddingRequest, type OpenAIEmbeddingResponse, type OpenAIFunctionDefinition, type OpenAIImageUrlContentPart, type OpenAIListModelsResponse, type OpenAIMessage, type OpenAIModelItem, type OpenAIReasoningEffort, type OpenAIResponseFormat, type OpenAIResponsesCompletedEvent, type OpenAIResponsesContentPartAddedEvent, type OpenAIResponsesContentPartDoneEvent, type OpenAIResponsesCreatedEvent, type OpenAIResponsesError, type OpenAIResponsesEventBase, type OpenAIResponsesFailedEvent, type OpenAIResponsesFunctionCallArgumentsDeltaEvent, type OpenAIResponsesFunctionCallArgumentsDoneEvent, type OpenAIResponsesInProgressEvent, type OpenAIResponsesIncompleteDetails, type OpenAIResponsesIncompleteEvent, type OpenAIResponsesOutputContent, type OpenAIResponsesOutputFunctionCall, type OpenAIResponsesOutputItem, type OpenAIResponsesOutputItemAddedEvent, type OpenAIResponsesOutputItemDoneEvent, type OpenAIResponsesOutputMessage, type OpenAIResponsesOutputReasoning, type OpenAIResponsesOutputRefusal, type OpenAIResponsesOutputTextContent, type OpenAIResponsesOutputTextDeltaEvent, type OpenAIResponsesOutputTextDoneEvent, type OpenAIResponsesQueuedEvent, type OpenAIResponsesReasoningSummaryPartAddedEvent, type OpenAIResponsesReasoningSummaryPartDoneEvent, type OpenAIResponsesReasoningSummaryTextDeltaEvent, type OpenAIResponsesReasoningSummaryTextDoneEvent, type OpenAIResponsesReasoningTextDeltaEvent, type OpenAIResponsesReasoningTextDoneEvent, type OpenAIResponsesRefusalDeltaEvent, type OpenAIResponsesRefusalDoneEvent, type OpenAIResponsesRequest, type OpenAIResponsesResponse, type OpenAIResponsesStatus, OpenAIResponsesStream, OpenAIResponsesStreamError, type OpenAIResponsesStreamEvent, type OpenAIResponsesUsage, type OpenAIStreamOptions, type OpenAITextContentPart, type OpenAITool, type OpenAIToolCall, type OpenAIToolCallDelta, type OpenAIUsage, ProgressResponse, ProgressStreamResult, PsResponse, PullRequestOptions, PushRequestOptions, QuotaManager, type QuotaManagerOptions, type QuotaWindowConfig, type QuotaWindowStatus, RawUsageSource, RequestLifecycleHook, type RequestRunner, type RetryConfig, type RuntimeMode, ShowRequestOptions, ShowResponse, type SpanAttributeValue, type SpanAttributes, SseEvent, StatusResponse, type SupportedSchema, ThinkValue, ThinkingMetadata, type TimeoutSignal, TokenUsage, Tool, ToolCall, ToolDefinition, ToolExecutionResult, ToolHandler, ToolRegistry, VersionResponse, WebFetchRequestOptions, WebFetchResponse, WebSearchRequestOptions, WebSearchResponse, addSpanEvent, calculateBackoff, checkEndpointHealth, createOllamaCloudFreeTierQuota, createTimeoutSignal, defineTool, detectModelCapabilities, encodeImage, inferRuntimeMode, listAllMcpTools, listAvailableModels, loadMcpTools, normalizeChatStream, normalizeGenerateStream, normalizeProgressStream, parseNdjsonStream, parseStructuredOutput, registerMcpTools, resolveCredentialEndpoints, setSpanError, toDataStream, toResponse, toTextStream, withRetry, withSpan, zodToJsonSchema };
2660
+ export { ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_SYSTEM, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_OLLAMA_AGENT_ITERATION, ATTR_OLLAMA_AGENT_MAX_ITERATIONS, ATTR_OLLAMA_ENDPOINT_ATTEMPT, ATTR_OLLAMA_ENDPOINT_NAME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_FULL, AbortableAsyncIterable, Agent, type AgentChatClient, type AgentConfig, type AgentHooks, type AgentResult, type AgentRunInput, type AgentTurn, type AnswerFor, AnthropicCompatClient, AnyTool, type BackoffOptions, BalanceRequestOptions, type BalanceResponse, type BlobUploadResult, ChatRequestOptions, ChatResponse, ChatStreamResult, type ChoiceDecision, type ContextCheck, type ContextCheckOptions, type ContextWindowSource, type ConversationSendOptions, ConversationSession, type ConversationSessionOptions, CopyRequestOptions, CreateRequestOptions, type CumulativeCacheStats, DEFAULT_BACKOFF, DEFAULT_BASE_URL, DEFAULT_CONTEXT_WARNING_THRESHOLD, DEFAULT_FAILOVER_CODES, DEFAULT_FETCH_BACKOFF_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TIMEOUT_MS, type Decision, type DefineToolOptions, DeleteRequestOptions, EmbedRequestOptions, EmbedResponse, EmbeddingsRequestOptions, EmbeddingsResponse, type EndpointHealth, type EndpointHealthCheckResult, EndpointRegistry, type EndpointRegistryOptions, FetchLike, type FetchWithBackoffConfig, FormatOption, GEN_AI_SYSTEM_OLLAMA, GenerateRequestOptions, GenerateResponse, GenerateStreamResult, HttpClient, IMAGE_TOKEN_ESTIMATE, type IncludedBalance, KEEP_ALIVE_INDEFINITE, KEEP_ALIVE_UNLOAD, KNOWN_DONE_REASONS, type KeepAlive, type KnownDoneReason, type LegacyBalanceLimit, type LegacyIncludedBalance, type LoadMcpToolsOptions, Logger, MAX_SYSTEM_ONE_IMAGES_BYTES, MAX_SYSTEM_ONE_REQUEST_BYTES, McpBridge, type McpBridgeOptions, McpCallToolResult, McpClientLike, McpTask, McpToolDescriptor, Message, Middleware, type ModelCapabilities, ModelOptions, ModelResponse, ModelsClient, type NoulDecision, OLLAMA_CLOUD_BASE_URL, OLLAMA_FALLBACK_CONTEXT_LENGTH, OllamaClient, type OllamaClientConfig, type OllamaCloudFreeTierQuotaBudgets, type OllamaCredentialConfig, type OllamaEndpoint, OllamaStream, OllamaStreamEvent, OllamaStreamEventType, OpenAICompatClient, type ParallelToolCallBehavior, ProgressResponse, ProgressStreamResult, PsResponse, PullRequestOptions, PushRequestOptions, QuotaManager, type QuotaManagerOptions, type QuotaWindowConfig, type QuotaWindowStatus, RETRYABLE_STATUS_CODES, type RankResult, RawUsageSource, RequestCancellationOptions, RequestLifecycleHook, RequestRunner, type ResponsesCreateRequest, type ResponsesCreateResponse, ResponsesModule, type ResponsesReasoningEffort, type ResponsesStreamEvent, type ResponsesToolDefinition, type ResponsesUsage, type RetryConfig, type RuntimeMode, type ScoreDecision, type SessionTurn, ShowRequestOptions, ShowResponse, type SpanAttributeValue, type SpanAttributes, StatusResponse, type SupportedSchema, type SystemOneAnswer, type SystemOneAnswers, SystemOneChoiceAnswer, SystemOneChoiceQuestion, SystemOneContent, SystemOneNoulAnswer, SystemOneNoulQuestion, type SystemOneQuestion, type SystemOneQuestions, type SystemOneRequest, type SystemOneResponse, SystemOneScoreAnswer, SystemOneScoreQuestion, type SystemOneUsage, ThinkValue, ThinkingMetadata, type TimeoutSignal, TokenUsage, Tool, ToolCall, ToolCallAccumulator, ToolDefinition, ToolExecutionResult, ToolHandler, ToolParameters, ToolRegistry, type TurnCacheStats, type UsageBucket, type UsageMetrics, UsageRequestOptions, type UsageResponse, VersionResponse, VisionInput, WebFetchRequestOptions, WebFetchResponse, WebSearchRequestOptions, WebSearchResponse, addSpanEvent, calculateBackoff, checkChatContext, checkEndpointHealth, checkGenerateContext, contextWarningMessage, createDecision, createOllamaCloudFreeTierQuota, createTimeoutSignal, defineTool, detectModelCapabilities, encodeImage, estimateChatRequestTokens, estimateGenerateRequestTokens, estimateSystemOneRequestBytes, estimateTokens, fetchWithBackoff, inferRuntimeMode, isKeepAliveSugar, isKnownDoneReason, isSameToolCall, listAllMcpTools, listAvailableModels, loadMcpTools, mergeToolCall, mergeToolCallArgumentsString, mergeToolCallArrays, normalizeChatStream, normalizeGenerateStream, normalizeKeepAlive, normalizeProgressStream, parseNdjsonStream, parseStructuredOutput, registerMcpTools, resolveCredentialEndpoints, setSpanError, toDataStream, toResponse, toTextStream, withRetry, withSpan, zodToJsonSchema };