@nemesis-oss/ollama-sdk 1.9.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/README.md +242 -2
- package/dist/{anthropic-5oYIRS6D.d.ts → anthropic-CfricAhK.d.ts} +1 -1
- package/dist/{anthropic-BIh45UXj.d.cts → anthropic-DinrABof.d.cts} +1 -1
- package/dist/{compose-DCVYMvOL.d.ts → compose-BQYXdpar.d.ts} +1 -1
- package/dist/{compose-Dj6FdF2n.d.cts → compose-lt-Qz3lI.d.cts} +1 -1
- package/dist/generated-api.d.cts +5 -5
- package/dist/generated-api.d.ts +5 -5
- package/dist/generated-runtime.cjs.map +1 -1
- package/dist/generated-runtime.d.cts +2 -2
- package/dist/generated-runtime.d.ts +2 -2
- package/dist/generated-runtime.js.map +1 -1
- package/dist/index.cjs +787 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +780 -97
- package/dist/index.d.ts +780 -97
- package/dist/index.js +771 -97
- package/dist/index.js.map +1 -1
- package/dist/mcp-generated.d.cts +2 -2
- package/dist/mcp-generated.d.ts +2 -2
- package/dist/{runtime-C3rfpkZw.d.ts → runtime-CCm4CtU_.d.ts} +29 -2
- package/dist/{runtime-D2W9TfCJ.d.cts → runtime-DTtWCxDs.d.cts} +29 -2
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.d.cts +3 -3
- package/dist/skills.d.ts +3 -3
- package/dist/skills.js.map +1 -1
- package/dist/{types-DVcX_zMp.d.cts → types-BtQexFpT.d.cts} +5 -2
- package/dist/{types-DVcX_zMp.d.ts → types-BtQexFpT.d.ts} +5 -2
- package/package.json +4 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
1
|
+
import { T as ThinkingMetadata, M as ModelResponse, R as RequestCancellationOptions, 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 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-BtQexFpT.cjs';
|
|
2
|
+
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-BtQexFpT.cjs';
|
|
3
|
+
import { H as HttpClient, F as FetchLike, M as Middleware, L as Logger, R as RequestLifecycleHook, 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-DTtWCxDs.cjs';
|
|
4
|
+
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 OllamaAgentToolLoopError, w as OllamaAuthError, x as OllamaBadGatewayError, y as OllamaClientError, z as OllamaClientErrorOptions, J as OllamaErrorRequestContext, K as OllamaErrorResponseContext, Q as OllamaGenericClientError, U as OllamaIncompatibleModelError, V as OllamaMcpError, W as OllamaModelRoutingError, X as OllamaNetworkError, Y as OllamaNotFoundError, Z as OllamaOverloadedError, _ as OllamaQuotaExceededError, $ as OllamaRateLimitError, a0 as OllamaRequestTooLargeError, a1 as OllamaRequestValidationError, a2 as OllamaResponseValidationError, a3 as OllamaServerError, a4 as OllamaServerVersionUnknownError, a5 as OllamaSkillInvalidError, a6 as OllamaSkillNotFoundError, a7 as OllamaStreamError, a8 as OllamaTimeoutError, a9 as OllamaToolTimeoutError, aa as OllamaToolValidationError, ab as OllamaUnsupportedCapabilityError, ac as RequestContext, ad as RequestLifecycleEvent, ae as ResponseContext, af as SseEvent, ag as ThinkingEvent, ah as TokenEvent, ai as ToolCallEvent, aj as composeMiddleware, ak as createConsoleLogger, al as extractUsage, am as mapError, an as parseSseStream } from './runtime-DTtWCxDs.cjs';
|
|
5
5
|
import { z } from 'zod';
|
|
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-
|
|
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-
|
|
8
|
-
import { T as ToolHandler, a as Tool, A as AnyTool, b as ToolRegistry, c as ToolExecutionResult } from './compose-
|
|
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-
|
|
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-DinrABof.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-DinrABof.cjs';
|
|
8
|
+
import { T as ToolHandler, a as Tool, A as AnyTool, b as ToolRegistry, c as ToolExecutionResult } from './compose-lt-Qz3lI.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-lt-Qz3lI.cjs';
|
|
10
10
|
import { M as McpClientLike, a as McpToolDescriptor, b as McpTask, c as McpCallToolResult } from './types-CI-gM2u5.cjs';
|
|
11
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';
|
|
12
12
|
import * as Otel from '@opentelemetry/api';
|
|
@@ -122,6 +122,211 @@ interface UsageResponse {
|
|
|
122
122
|
readonly buckets: readonly UsageBucket[];
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Model capability detection and runtime environment inference.
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
type RuntimeMode = 'local' | 'cloud' | 'unknown';
|
|
130
|
+
/**
|
|
131
|
+
* Best-effort classification of a model's parallel tool-call emission
|
|
132
|
+
* behavior. Used by agent loops that need to know whether the model
|
|
133
|
+
* is likely to emit multiple `tool_calls` in a single assistant
|
|
134
|
+
* message (parallel) or one-at-a-time (sequential).
|
|
135
|
+
*
|
|
136
|
+
* This is a **heuristic** derived from runtime mode + model family
|
|
137
|
+
* pattern matching against `/api/show`'s reported model_info. The
|
|
138
|
+
* SDK does NOT normalize between cloud and local — it reports the
|
|
139
|
+
* best assessment it can and lets the caller decide how to act.
|
|
140
|
+
*
|
|
141
|
+
* See ADR 0023 for the rationale and the recommended caller pattern.
|
|
142
|
+
*/
|
|
143
|
+
type ParallelToolCallBehavior = 'yes' | 'no' | 'unknown';
|
|
144
|
+
interface ModelCapabilities {
|
|
145
|
+
readonly model: string;
|
|
146
|
+
readonly reported: readonly string[];
|
|
147
|
+
readonly supportsTools: boolean;
|
|
148
|
+
readonly supportsVision: boolean;
|
|
149
|
+
readonly supportsEmbedding: boolean;
|
|
150
|
+
readonly supportsCompletion: boolean;
|
|
151
|
+
readonly supportsThinking: boolean;
|
|
152
|
+
/** Model-defined thinking values and default, when /api/show reports them. */
|
|
153
|
+
readonly thinking?: ThinkingMetadata | undefined;
|
|
154
|
+
readonly supportsStreaming: true;
|
|
155
|
+
/** Maximum model context length reported by /api/show model_info, when available. */
|
|
156
|
+
readonly contextLength?: number | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Best-effort inference, not a guarantee: Ollama's `/api/show` does not report structured
|
|
159
|
+
* output support as a queryable capability, so this is inferred from {@link inferRuntimeMode}
|
|
160
|
+
* — `false` for `cloud`, since Ollama Cloud does not currently support structured outputs;
|
|
161
|
+
* `true` for `local`/`unknown`. A locally-hosted model that genuinely can't follow a JSON
|
|
162
|
+
* schema will still report `true` here; the request itself is the only reliable way to find
|
|
163
|
+
* out. `OllamaClient.chat`/`generate` apply this same inference as a fail-fast pre-flight
|
|
164
|
+
* guard whenever `format` is set, throwing `OllamaUnsupportedCapabilityError` rather than
|
|
165
|
+
* making a network call that Ollama Cloud is known to reject.
|
|
166
|
+
*/
|
|
167
|
+
readonly supportsStructuredOutputRequest: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Best-effort inference of whether the model is likely to emit
|
|
170
|
+
* **multiple `tool_calls` in a single assistant message** (parallel)
|
|
171
|
+
* vs **one tool call per assistant turn** (sequential).
|
|
172
|
+
*
|
|
173
|
+
* The SDK does NOT normalize between cloud and local — it reports
|
|
174
|
+
* the best assessment it can and lets the caller decide. Agent
|
|
175
|
+
* authors who need hard sequential execution should set
|
|
176
|
+
* `ToolRegistry`'s `maxConcurrency: 1` regardless of this field's
|
|
177
|
+
* value, since the model's behavior is not deterministic across
|
|
178
|
+
* prompts.
|
|
179
|
+
*
|
|
180
|
+
* Inference matrix (see ADR 0023):
|
|
181
|
+
*
|
|
182
|
+
* - **`'yes'`** — the model is known to emit parallel tool calls:
|
|
183
|
+
* - Cloud-mode endpoints (the OpenAI/Anthropic compat bridges
|
|
184
|
+
* proxy to proprietary models like GPT-4o, Claude, which
|
|
185
|
+
* freely emit parallel tool calls).
|
|
186
|
+
* - Local models from families that ship with parallel-tool-call
|
|
187
|
+
* training (Qwen 2.5+, Llama 3.1+ tool-use variants, Mistral
|
|
188
|
+
* function-calling fine-tunes, Hermes 2/3, Command R+).
|
|
189
|
+
*
|
|
190
|
+
* - **`'no'`** — the model is known to emit at most one tool call
|
|
191
|
+
* per assistant turn. Currently no model family is classified
|
|
192
|
+
* as `'no'` by default; the field is reserved for future
|
|
193
|
+
* narrowing as more is learned about specific models.
|
|
194
|
+
*
|
|
195
|
+
* - **`'unknown'`** — the model family is not in the known-yes or
|
|
196
|
+
* known-no list, OR `/api/show` didn't return enough
|
|
197
|
+
* information to make an assessment. Callers should treat
|
|
198
|
+
* `'unknown'` as "ask the model and see what it does" — the
|
|
199
|
+
* `ToolRegistry` will execute whatever calls the model emits,
|
|
200
|
+
* in parallel via `Promise.all` by default.
|
|
201
|
+
*
|
|
202
|
+
* See: `src/tools/registry.ts` for `maxConcurrency` enforcement,
|
|
203
|
+
* and ADR 0023 for the full design rationale.
|
|
204
|
+
*/
|
|
205
|
+
readonly parallelToolCalls: ParallelToolCallBehavior;
|
|
206
|
+
}
|
|
207
|
+
declare function inferRuntimeMode(baseUrl: string): RuntimeMode;
|
|
208
|
+
/**
|
|
209
|
+
* Scans `/api/show`'s `model_info` for the model's **native** context length
|
|
210
|
+
* (keys are architecture-prefixed: `llama.context_length`,
|
|
211
|
+
* `gemma4.context_length`, …). Also re-exported by `src/context-discovery.ts`
|
|
212
|
+
* as `extractNativeContextLength` for the context-window discovery flow.
|
|
213
|
+
*/
|
|
214
|
+
declare function extractContextLength(modelInfo?: Record<string, unknown>): number | undefined;
|
|
215
|
+
declare function detectModelCapabilities(http: HttpClient, model: string, signal?: AbortSignal): Promise<ModelCapabilities>;
|
|
216
|
+
declare function listAvailableModels(http: HttpClient): Promise<ModelResponse[]>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Dynamic context-window discovery.
|
|
220
|
+
*
|
|
221
|
+
* Guessing context windows ("it's probably 2048… or 4096?") is how silent
|
|
222
|
+
* truncation happens. Ollama advertises the real numbers in two places, and
|
|
223
|
+
* they answer *different questions*:
|
|
224
|
+
*
|
|
225
|
+
* - **`GET /api/ps`** reports `context_length` for every currently-running
|
|
226
|
+
* model — the window the runner has **actually allocated**. This is the
|
|
227
|
+
* exact, server-enforced number: it already reflects the model's Modelfile
|
|
228
|
+
* `num_ctx` default (if any) and the memory the runner was able to claim.
|
|
229
|
+
* Only meaningful while the model is loaded.
|
|
230
|
+
* - **`POST /api/show`** exposes two deeper signals in its response:
|
|
231
|
+
* - `model_info["<architecture>.context_length"]` — the model's **native**
|
|
232
|
+
* maximum from its GGUF metadata (e.g. `gemma4.context_length: 131072`).
|
|
233
|
+
* This is the ceiling you could raise `num_ctx` to, not the window you
|
|
234
|
+
* have. The official API examples show a model whose native max is
|
|
235
|
+
* 131072 while its running instance allocated 4096 — a 32× gap.
|
|
236
|
+
* - `parameters` — the Modelfile's serialized option list; a
|
|
237
|
+
* `num_ctx <n>` line (when the model's author set one) is the default
|
|
238
|
+
* window the runner will allocate for this model.
|
|
239
|
+
*
|
|
240
|
+
* `OllamaClient.models.getContextLength()` consults them in precedence order
|
|
241
|
+
* (see {@link resolveContextLength}) and returns every signal it found, so
|
|
242
|
+
* callers can both act on the effective window *now* and know how much
|
|
243
|
+
* headroom exists for raising it.
|
|
244
|
+
*/
|
|
245
|
+
|
|
246
|
+
/** Request shape for {@link ModelsClient.getContextLength}. */
|
|
247
|
+
interface ContextDiscoveryRequestOptions extends RequestCancellationOptions {
|
|
248
|
+
/** Model to introspect (tag optional — `"llama3.1"` matches `"llama3.1:latest"`). */
|
|
249
|
+
readonly model: string;
|
|
250
|
+
/**
|
|
251
|
+
* Skip the `GET /api/ps` lookup — e.g. on cloud endpoints where the local
|
|
252
|
+
* running-models listing isn't meaningful, or when the extra round-trip
|
|
253
|
+
* isn't wanted. Discovery then falls back to `/api/show` signals only.
|
|
254
|
+
*/
|
|
255
|
+
readonly skipRunningCheck?: boolean | undefined;
|
|
256
|
+
}
|
|
257
|
+
/** Where a discovered context window came from, in precedence order. */
|
|
258
|
+
type ContextLengthSource =
|
|
259
|
+
/** `GET /api/ps` — window actually allocated by the running instance (exact). */
|
|
260
|
+
'running'
|
|
261
|
+
/** `POST /api/show` `parameters` — Modelfile-authored `num_ctx` default. */
|
|
262
|
+
| 'parameters'
|
|
263
|
+
/** `POST /api/show` `model_info["*.context_length"]` — native GGUF maximum. */
|
|
264
|
+
| 'model-info'
|
|
265
|
+
/** Nothing discoverable — Ollama's conservative unset-`num_ctx` default (2048). */
|
|
266
|
+
| 'fallback';
|
|
267
|
+
/** Result of {@link ModelsClient.getContextLength}. */
|
|
268
|
+
interface DiscoveredContextLength {
|
|
269
|
+
/**
|
|
270
|
+
* The effective context window to program against, resolved by precedence:
|
|
271
|
+
* `running` (exact, when loaded) → `parameters` (Modelfile default) →
|
|
272
|
+
* `model-info` (native max) → `2048` fallback.
|
|
273
|
+
*/
|
|
274
|
+
readonly contextLength: number;
|
|
275
|
+
/** Which source produced {@link contextLength}. */
|
|
276
|
+
readonly source: ContextLengthSource;
|
|
277
|
+
/** Window allocated by the running instance, when the model is loaded and reports it. */
|
|
278
|
+
readonly runningContextLength?: number | undefined;
|
|
279
|
+
/** Modelfile `num_ctx` default from `/api/show`'s `parameters` string, when set. */
|
|
280
|
+
readonly parameterContextLength?: number | undefined;
|
|
281
|
+
/** Native GGUF maximum from `model_info["*.context_length"]`, when reported. */
|
|
282
|
+
readonly nativeContextLength?: number | undefined;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Parses `num_ctx <n>` out of `/api/show`'s `parameters` string.
|
|
286
|
+
*
|
|
287
|
+
* The string is the Modelfile's serialized option list — one `name value`
|
|
288
|
+
* pair per line, value separated by whitespace padding, e.g.
|
|
289
|
+
* `"num_stop 8192\nnum_ctx 4096"`. Returns `undefined` when no positive
|
|
290
|
+
* integer `num_ctx` line is present.
|
|
291
|
+
*/
|
|
292
|
+
declare function extractParameterNumCtx(parameters?: string | undefined): number | undefined;
|
|
293
|
+
/**
|
|
294
|
+
* Finds the context window Ollama actually allocated for `model`, from a
|
|
295
|
+
* `GET /api/ps` response. Matching mirrors Ollama's own model resolution:
|
|
296
|
+
* exact match on the entry's `name`/`model`, or — when `model` carries no
|
|
297
|
+
* tag — any entry whose name starts with `<model>:`.
|
|
298
|
+
*
|
|
299
|
+
* Returns `undefined` when the model isn't loaded or the running entry
|
|
300
|
+
* doesn't report `context_length` (older server versions).
|
|
301
|
+
*/
|
|
302
|
+
declare function findRunningModelContextLength(psModels: readonly ModelResponse[], model: string): number | undefined;
|
|
303
|
+
/** Internal inputs to {@link resolveContextLength}; each signal independently optional. */
|
|
304
|
+
interface ContextLengthSignals {
|
|
305
|
+
readonly running?: number | undefined;
|
|
306
|
+
readonly parameter?: number | undefined;
|
|
307
|
+
readonly native?: number | undefined;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Resolves the effective context window from whatever signals were
|
|
311
|
+
* discovered, by precedence:
|
|
312
|
+
*
|
|
313
|
+
* 1. **`running`** — the allocated window of the loaded instance. When the
|
|
314
|
+
* model is in memory this is the ground truth; it already incorporates
|
|
315
|
+
* any Modelfile `num_ctx` default.
|
|
316
|
+
* 2. **`parameter`** — the Modelfile's `num_ctx`, i.e. the window the
|
|
317
|
+
* runner *will* allocate for this model on the next cold load.
|
|
318
|
+
* 3. **`native`** — the GGUF maximum. Only used when nothing tighter is
|
|
319
|
+
* known: a fresh `num_ctx`-less load may allocate far less than native
|
|
320
|
+
* (Ollama's conservative default), so native is a *ceiling*, not an
|
|
321
|
+
* expectation.
|
|
322
|
+
* 4. **Fallback** — {@link OLLAMA_FALLBACK_CONTEXT_LENGTH} (2048), the
|
|
323
|
+
* conservative server-side default, so the result is always actionable.
|
|
324
|
+
*
|
|
325
|
+
* Pure — used by `ModelsClient.getContextLength()` and exported for callers
|
|
326
|
+
* that already hold `/api/ps` / `/api/show` responses.
|
|
327
|
+
*/
|
|
328
|
+
declare function resolveContextLength(signals: ContextLengthSignals): DiscoveredContextLength;
|
|
329
|
+
|
|
125
330
|
/**
|
|
126
331
|
* Exponential backoff with full jitter calculation.
|
|
127
332
|
*/
|
|
@@ -445,92 +650,6 @@ interface EndpointHealthCheckResult {
|
|
|
445
650
|
}
|
|
446
651
|
declare function checkEndpointHealth(endpoint: OllamaEndpoint, fetchImpl?: FetchLike, timeoutMs?: number, middleware?: readonly Middleware[] | undefined, onLifecycleEvent?: RequestLifecycleHook | undefined): Promise<EndpointHealthCheckResult>;
|
|
447
652
|
|
|
448
|
-
/**
|
|
449
|
-
* Model capability detection and runtime environment inference.
|
|
450
|
-
*/
|
|
451
|
-
|
|
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';
|
|
467
|
-
interface ModelCapabilities {
|
|
468
|
-
readonly model: string;
|
|
469
|
-
readonly reported: readonly string[];
|
|
470
|
-
readonly supportsTools: boolean;
|
|
471
|
-
readonly supportsVision: boolean;
|
|
472
|
-
readonly supportsEmbedding: boolean;
|
|
473
|
-
readonly supportsCompletion: boolean;
|
|
474
|
-
readonly supportsThinking: boolean;
|
|
475
|
-
/** Model-defined thinking values and default, when /api/show reports them. */
|
|
476
|
-
readonly thinking?: ThinkingMetadata | undefined;
|
|
477
|
-
readonly supportsStreaming: true;
|
|
478
|
-
/** Maximum model context length reported by /api/show model_info, when available. */
|
|
479
|
-
readonly contextLength?: number | undefined;
|
|
480
|
-
/**
|
|
481
|
-
* Best-effort inference, not a guarantee: Ollama's `/api/show` does not report structured
|
|
482
|
-
* output support as a queryable capability, so this is inferred from {@link inferRuntimeMode}
|
|
483
|
-
* — `false` for `cloud`, since Ollama Cloud does not currently support structured outputs;
|
|
484
|
-
* `true` for `local`/`unknown`. A locally-hosted model that genuinely can't follow a JSON
|
|
485
|
-
* schema will still report `true` here; the request itself is the only reliable way to find
|
|
486
|
-
* out. `OllamaClient.chat`/`generate` apply this same inference as a fail-fast pre-flight
|
|
487
|
-
* guard whenever `format` is set, throwing `OllamaUnsupportedCapabilityError` rather than
|
|
488
|
-
* making a network call that Ollama Cloud is known to reject.
|
|
489
|
-
*/
|
|
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;
|
|
529
|
-
}
|
|
530
|
-
declare function inferRuntimeMode(baseUrl: string): RuntimeMode;
|
|
531
|
-
declare function detectModelCapabilities(http: HttpClient, model: string, signal?: AbortSignal): Promise<ModelCapabilities>;
|
|
532
|
-
declare function listAvailableModels(http: HttpClient): Promise<ModelResponse[]>;
|
|
533
|
-
|
|
534
653
|
/**
|
|
535
654
|
* Dual-mode (AsyncIterator and EventEmitter-like) stream wrapper.
|
|
536
655
|
*/
|
|
@@ -606,7 +725,39 @@ declare class ModelsClient {
|
|
|
606
725
|
create(request: CreateRequestOptions): Promise<ProgressResponse | OllamaStream<ProgressResponse, ProgressStreamResult>>;
|
|
607
726
|
delete(request: DeleteRequestOptions): Promise<StatusResponse>;
|
|
608
727
|
copy(request: CopyRequestOptions): Promise<StatusResponse>;
|
|
609
|
-
ps(): Promise<PsResponse>;
|
|
728
|
+
ps(request?: RequestCancellationOptions): Promise<PsResponse>;
|
|
729
|
+
/**
|
|
730
|
+
* Discovers the model's real context window from the server — no more
|
|
731
|
+
* 2048/4096 guesswork. Consults, in precedence order:
|
|
732
|
+
*
|
|
733
|
+
* 1. `GET /api/ps` — the window the **running instance actually
|
|
734
|
+
* allocated** (exact, reflects the Modelfile `num_ctx` default and
|
|
735
|
+
* what fit in memory); skipped when the model isn't loaded, when
|
|
736
|
+
* `skipRunningCheck` is set, or harmlessly on servers without the
|
|
737
|
+
* field.
|
|
738
|
+
* 2. `POST /api/show` `parameters` — a Modelfile-authored
|
|
739
|
+
* `num_ctx <n>` default, i.e. the window a cold load will allocate.
|
|
740
|
+
* 3. `POST /api/show` `model_info["<arch>.context_length"]` — the
|
|
741
|
+
* model's **native GGUF maximum** (a ceiling to raise `num_ctx`
|
|
742
|
+
* toward, not the allocated window).
|
|
743
|
+
* 4. Fallback — Ollama's conservative unset-`num_ctx` default (2048).
|
|
744
|
+
*
|
|
745
|
+
* The result carries every signal it found, so `nativeContextLength:
|
|
746
|
+
* 131072` vs `contextLength: 4096` (a 32× gap seen in the official API
|
|
747
|
+
* examples) is visible rather than guessed. Typical wiring:
|
|
748
|
+
*
|
|
749
|
+
* ```ts
|
|
750
|
+
* const { contextLength, source, nativeContextLength } =
|
|
751
|
+
* await client.models.getContextLength({ model: 'gemma4' });
|
|
752
|
+
* // -> { contextLength: 4096, source: 'running', nativeContextLength: 131072 }
|
|
753
|
+
* ```
|
|
754
|
+
*
|
|
755
|
+
* Makes two server calls (`/api/ps` + `/api/show`) unless
|
|
756
|
+
* `skipRunningCheck` is set. A 404 from `/api/ps` (endpoint without the
|
|
757
|
+
* listing) is treated as "not running" and never fails the lookup;
|
|
758
|
+
* other transport errors propagate normally.
|
|
759
|
+
*/
|
|
760
|
+
getContextLength(request: ContextDiscoveryRequestOptions): Promise<DiscoveredContextLength>;
|
|
610
761
|
version(): Promise<VersionResponse>;
|
|
611
762
|
/**
|
|
612
763
|
* Immediately unloads `model` from VRAM/RAM by issuing an empty
|
|
@@ -904,6 +1055,147 @@ interface SessionTurn {
|
|
|
904
1055
|
/** The full underlying `/api/chat` response (usage, durations, thinking, …). */
|
|
905
1056
|
readonly response: ChatResponse;
|
|
906
1057
|
}
|
|
1058
|
+
/** Options for {@link compactConversationHistory} / {@link ConversationSession.compact}. */
|
|
1059
|
+
interface CompactionOptions {
|
|
1060
|
+
/**
|
|
1061
|
+
* Estimated-token budget the compacted history must fit within (including
|
|
1062
|
+
* any retained system message and the 10%-style reply reservation below).
|
|
1063
|
+
* Estimated with the same CJK-aware heuristic as the pre-flight checks
|
|
1064
|
+
* (`estimateMessageTokens` — ±20–30%, message overhead + tool calls +
|
|
1065
|
+
* `IMAGE_TOKEN_ESTIMATE` per image included).
|
|
1066
|
+
*/
|
|
1067
|
+
readonly maxEstimatedTokens: number;
|
|
1068
|
+
/**
|
|
1069
|
+
* Tokens subtracted from the budget and reserved for the model's next
|
|
1070
|
+
* reply (default `0` for the pure function; `session.compact()` defaults
|
|
1071
|
+
* to ~10% of the window, mirroring the pre-flight warning threshold's
|
|
1072
|
+
* headroom).
|
|
1073
|
+
*/
|
|
1074
|
+
readonly reserveForReply?: number | undefined;
|
|
1075
|
+
/**
|
|
1076
|
+
* Trailing messages always retained, even when they don't fit the budget
|
|
1077
|
+
* (default `2` — the latest user/assistant exchange). Guarantees a
|
|
1078
|
+
* compacted conversation never loses its most recent context; an
|
|
1079
|
+
* oversized tail is retained deliberately rather than truncated, because
|
|
1080
|
+
* silent truncation is the server's failure mode, not one this SDK
|
|
1081
|
+
* reproduces.
|
|
1082
|
+
*/
|
|
1083
|
+
readonly minTailMessages?: number | undefined;
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Sliding-window history compaction: keep the pinned system message(s) plus
|
|
1087
|
+
* the most recent turns that fit `maxEstimatedTokens`, dropping the oldest
|
|
1088
|
+
* turns in between.
|
|
1089
|
+
*
|
|
1090
|
+
* Deliberately **not** automatic anywhere in the SDK: compaction rewrites the
|
|
1091
|
+
* prompt prefix, so the next request's KV-cache hit rate drops to zero and
|
|
1092
|
+
* the whole retained suffix re-evaluates. That tradeoff (latency + recompute
|
|
1093
|
+
* for a window that now fits) is sometimes exactly right — long-running
|
|
1094
|
+
* agent threads that would otherwise silently lose their oldest turns — and
|
|
1095
|
+
* sometimes catastrophic (a hot cache-friendly session that never actually
|
|
1096
|
+
* overflows). `ConversationSession.cacheStats` makes the "session no longer
|
|
1097
|
+
* fits" case visible; this function is the explicit, caller-initiated fix.
|
|
1098
|
+
*
|
|
1099
|
+
* Semantics:
|
|
1100
|
+
*
|
|
1101
|
+
* - **Leading `system` messages are always retained** and count against
|
|
1102
|
+
* the budget (they consume context too).
|
|
1103
|
+
* - Non-system messages are walked newest → oldest; each is retained while
|
|
1104
|
+
* it fits the remaining budget, or while fewer than `minTailMessages`
|
|
1105
|
+
* have been retained.
|
|
1106
|
+
* - Mid-conversation `system`/`tool` messages are ordinary tailable
|
|
1107
|
+
* history (only the *leading* system block is pinned).
|
|
1108
|
+
* - Returns a new array; the input is never mutated. Message objects are
|
|
1109
|
+
* reused by reference (sessions freeze them; external arrays are copied
|
|
1110
|
+
* defensively by the caller if needed).
|
|
1111
|
+
*
|
|
1112
|
+
* ```ts
|
|
1113
|
+
* const kept = compactConversationHistory(session.getMessages(), {
|
|
1114
|
+
* maxEstimatedTokens: window.contextLength,
|
|
1115
|
+
* reserveForReply: 512,
|
|
1116
|
+
* });
|
|
1117
|
+
* ```
|
|
1118
|
+
*/
|
|
1119
|
+
declare function compactConversationHistory(messages: readonly Message[], options: CompactionOptions): readonly Message[];
|
|
1120
|
+
/** Options for {@link sanitizeHistoryForNextTurn}; all fields optional. */
|
|
1121
|
+
interface HistorySanitizeOptions {
|
|
1122
|
+
/**
|
|
1123
|
+
* Messages — counted from the **end** of the array — whose `images` are
|
|
1124
|
+
* preserved. Default `1`: only the final message keeps its image payload,
|
|
1125
|
+
* which is the rolling one-image window long-running vision chats almost
|
|
1126
|
+
* always want (sanitize after appending the newest turn, and every prior
|
|
1127
|
+
* base64 payload is gone by the next request). `0` evicts images
|
|
1128
|
+
* everywhere; negative values clamp to `0`.
|
|
1129
|
+
*/
|
|
1130
|
+
readonly keepImagesOnLastMessages?: number | undefined;
|
|
1131
|
+
/**
|
|
1132
|
+
* Optional note appended to the `content` of each evicted message so the
|
|
1133
|
+
* model can still tell an image used to be there — e.g.
|
|
1134
|
+
* `"[image from an earlier turn removed to save context]"`. When omitted
|
|
1135
|
+
* (default) the `images` field is dropped and the text is untouched,
|
|
1136
|
+
* matching the wire behavior of never having sent the image at all.
|
|
1137
|
+
*/
|
|
1138
|
+
readonly imagePlaceholder?: string | undefined;
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Vision-history hygiene: returns a copy of `messages` with image payloads
|
|
1142
|
+
* evicted from every message outside the trailing keep-window, conversation
|
|
1143
|
+
* text fully preserved.
|
|
1144
|
+
*
|
|
1145
|
+
* Ollama's `/api/chat` is stateless — each request re-sends and re-bills the
|
|
1146
|
+
* whole history, base64 images included (each one costing real context
|
|
1147
|
+
* tokens via `IMAGE_TOKEN_ESTIMATE` in the pre-flight estimators). A
|
|
1148
|
+
* consumer-managed `messages` array therefore re-uploads every image from
|
|
1149
|
+
* every prior turn on every request, long after the model has already
|
|
1150
|
+
* answered the question that needed them. This helper is the explicit fix:
|
|
1151
|
+
*
|
|
1152
|
+
* ```ts
|
|
1153
|
+
* history.push({ role: 'user', content: 'What is in THIS photo?', images: [nextImage] });
|
|
1154
|
+
* await client.chat({ model, messages: sanitizeHistoryForNextTurn(history) });
|
|
1155
|
+
* ```
|
|
1156
|
+
*
|
|
1157
|
+
* Same philosophy as {@link compactConversationHistory}: caller-initiated,
|
|
1158
|
+
* never automatic. Two deliberate tradeoffs, both documented in ADR 0027:
|
|
1159
|
+
*
|
|
1160
|
+
* - **The model loses access to evicted images** — it keeps the
|
|
1161
|
+
* conversation text (and the optional `imagePlaceholder` note) but can
|
|
1162
|
+
* no longer "see" earlier pictures. That is the point: a bounded
|
|
1163
|
+
* payload in exchange for fading visual memory.
|
|
1164
|
+
* - **KV-prefix invalidation** — evicting rewrites the message at that
|
|
1165
|
+
* position, so the next turn's prompt prefix diverges and the cache
|
|
1166
|
+
* re-evaluates from that point. A hot cache-friendly session shouldn't
|
|
1167
|
+
* sanitize; a growing vision session should.
|
|
1168
|
+
*
|
|
1169
|
+
* Pure: the input array is never mutated, and messages that keep their
|
|
1170
|
+
* images are reused by reference (identity-stable for the untouched ones,
|
|
1171
|
+
* fresh copies only where eviction happened).
|
|
1172
|
+
*/
|
|
1173
|
+
declare function sanitizeHistoryForNextTurn(messages: readonly Message[], options?: HistorySanitizeOptions): readonly Message[];
|
|
1174
|
+
/** Options for {@link ConversationSession.compact}; all fields optional. */
|
|
1175
|
+
interface SessionCompactionOptions {
|
|
1176
|
+
/**
|
|
1177
|
+
* Token budget for the compacted history. Defaults to the session's own
|
|
1178
|
+
* window: `options.num_ctx` from the session config, or Ollama's
|
|
1179
|
+
* conservative 2048 fallback when unset — pair with
|
|
1180
|
+
* `client.models.getContextLength()` to program against the real window.
|
|
1181
|
+
*/
|
|
1182
|
+
readonly maxEstimatedTokens?: number | undefined;
|
|
1183
|
+
/** Reply reservation; defaults to ~10% of the (derived) budget. */
|
|
1184
|
+
readonly reserveForReply?: number | undefined;
|
|
1185
|
+
/** Trailing messages always kept (default `2`). See {@link CompactionOptions}. */
|
|
1186
|
+
readonly minTailMessages?: number | undefined;
|
|
1187
|
+
}
|
|
1188
|
+
/** What {@link ConversationSession.compact} did. */
|
|
1189
|
+
interface SessionCompactionResult {
|
|
1190
|
+
/** Number of messages dropped from the front of the tailable history. */
|
|
1191
|
+
readonly droppedMessages: number;
|
|
1192
|
+
/** Estimated tokens of the whole history before compaction. */
|
|
1193
|
+
readonly estimatedTokensBefore: number;
|
|
1194
|
+
/** Estimated tokens of the retained history after compaction. */
|
|
1195
|
+
readonly estimatedTokensAfter: number;
|
|
1196
|
+
/** The budget that was applied (after the reply reservation). */
|
|
1197
|
+
readonly effectiveBudget: number;
|
|
1198
|
+
}
|
|
907
1199
|
/** Per-turn overrides — none of these touch the history prefix, so they are KV-safe. */
|
|
908
1200
|
interface ConversationSendOptions extends Pick<ChatRequestOptions, 'signal' | 'timeoutMs'> {
|
|
909
1201
|
readonly options?: ModelOptions | undefined;
|
|
@@ -973,6 +1265,23 @@ declare class ConversationSession {
|
|
|
973
1265
|
* its frozen messages has no effect on the session.
|
|
974
1266
|
*/
|
|
975
1267
|
getMessages(): readonly Message[];
|
|
1268
|
+
/**
|
|
1269
|
+
* Compacts the session's history in place: pinned system prompt plus the
|
|
1270
|
+
* most recent turns that fit the budget, oldest tailable turns dropped.
|
|
1271
|
+
*
|
|
1272
|
+
* This is the explicit escape hatch for sessions that outgrew their
|
|
1273
|
+
* window — `cacheStats.hitRate` collapsing toward zero while history grows
|
|
1274
|
+
* is the usual symptom, and the pre-flight warnings on `chat()` fire once
|
|
1275
|
+
* the prompt estimate crosses the threshold. After compaction the next
|
|
1276
|
+
* turn's prompt prefix differs from everything before it, so the KV cache
|
|
1277
|
+
* starts cold — visible as a one-turn `evaluatedTokens` spike in
|
|
1278
|
+
* `cacheStats`. Cumulative cache tallies are deliberately **not** reset:
|
|
1279
|
+
* they are observations, and the spike is part of the story.
|
|
1280
|
+
*
|
|
1281
|
+
* Returns the before/after estimates and the drop count. No-op (zero
|
|
1282
|
+
* drops, equal before/after estimates) when the history already fits.
|
|
1283
|
+
*/
|
|
1284
|
+
compact(options?: SessionCompactionOptions): SessionCompactionResult;
|
|
976
1285
|
/**
|
|
977
1286
|
* Clears the conversation back to its initial state (system prompt, zero
|
|
978
1287
|
* turns, zeroed cache statistics). The next turn starts with a cold cache
|
|
@@ -981,6 +1290,131 @@ declare class ConversationSession {
|
|
|
981
1290
|
reset(): void;
|
|
982
1291
|
}
|
|
983
1292
|
|
|
1293
|
+
/**
|
|
1294
|
+
* Batch-constrained embedding generation for high-volume ingestion pipelines.
|
|
1295
|
+
*
|
|
1296
|
+
* Ollama's `/api/embed` accepts an array of inputs, but two independent limits
|
|
1297
|
+
* make naive usage fragile at corpus scale:
|
|
1298
|
+
*
|
|
1299
|
+
* 1. **Concurrency.** `Promise.all(inputs.map(...))` fires every request at
|
|
1300
|
+
* once; against a local Ollama daemon this contends sockets, saturates the
|
|
1301
|
+
* request queue (`OLLAMA_MAX_QUEUE`, surfacing as 503 `overloaded`), and —
|
|
1302
|
+
* worst case — exhausts GPU VRAM as the model instance serves N prompts
|
|
1303
|
+
* simultaneously.
|
|
1304
|
+
* 2. **Context window.** Ollama truncates any input string longer than the
|
|
1305
|
+
* model's context window (`num_ctx`) *silently* unless `truncate: false` is
|
|
1306
|
+
* set — degraded vectors with no error, no warning, nothing on the wire.
|
|
1307
|
+
*
|
|
1308
|
+
* {@link batchEmbed} addresses the first with a fixed-size worker pool over
|
|
1309
|
+
* `client.embed()` (so every batch still rides the client's full pipeline:
|
|
1310
|
+
* failover, retry, auth, logging, telemetry). The client-level
|
|
1311
|
+
* `embedBatch()` wrapper addresses the second with a pre-flight per-string
|
|
1312
|
+
* token estimate against the resolved `num_ctx` window (see
|
|
1313
|
+
* {@link findOversizedEmbedInputs}).
|
|
1314
|
+
*
|
|
1315
|
+
* Semantics:
|
|
1316
|
+
* - **Order-preserving** — result index `i` is always the embedding of
|
|
1317
|
+
* `input[i]`, regardless of which batch completed first.
|
|
1318
|
+
* - **Fail-fast** — the first batch error aborts every sibling in-flight
|
|
1319
|
+
* batch (surfaces the *original* error, not the derived aborts) and rejects
|
|
1320
|
+
* the whole operation. Vector indexing that half-succeeds is a corrupted
|
|
1321
|
+
* index; callers re-running an ingestion prefer all-or-nothing.
|
|
1322
|
+
* - **Abortable** — the caller's `signal` cancels queued and in-flight batches
|
|
1323
|
+
* alike and rejects with `code: 'aborted'`.
|
|
1324
|
+
*/
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* Default number of input strings per `/api/embed` request. 32 keeps a single
|
|
1328
|
+
* request's prompt comfortably inside typical embedding-model context windows
|
|
1329
|
+
* (2048+) while amortizing HTTP overhead across the corpus.
|
|
1330
|
+
*/
|
|
1331
|
+
declare const DEFAULT_EMBED_BATCH_SIZE = 32;
|
|
1332
|
+
/**
|
|
1333
|
+
* Default number of batches kept in flight concurrently. 3 is deliberately
|
|
1334
|
+
* conservative: a local Ollama daemon serves one model instance per GPU, so
|
|
1335
|
+
* 3 concurrent embedding prompts bound queue depth and VRAM pressure without
|
|
1336
|
+
* leaving the hardware idle between batches. Raise for multi-endpoint
|
|
1337
|
+
* clients or remote daemons; lower (to 1) for constrained devices.
|
|
1338
|
+
*/
|
|
1339
|
+
declare const DEFAULT_EMBED_CONCURRENCY = 3;
|
|
1340
|
+
interface EmbedBatchOptions {
|
|
1341
|
+
/** Model to embed with (e.g. `'nomic-embed-text:latest'`). */
|
|
1342
|
+
readonly model: string;
|
|
1343
|
+
/** Input strings, in corpus order. Result index `i` matches `input[i]`. */
|
|
1344
|
+
readonly input: readonly string[];
|
|
1345
|
+
/**
|
|
1346
|
+
* Inputs per `/api/embed` request. Default {@link DEFAULT_EMBED_BATCH_SIZE}
|
|
1347
|
+
* (32). Must be a positive integer.
|
|
1348
|
+
*/
|
|
1349
|
+
readonly batchSize?: number | undefined;
|
|
1350
|
+
/**
|
|
1351
|
+
* Batches kept in flight simultaneously. Default
|
|
1352
|
+
* {@link DEFAULT_EMBED_CONCURRENCY} (3). Must be a positive integer.
|
|
1353
|
+
*/
|
|
1354
|
+
readonly concurrency?: number | undefined;
|
|
1355
|
+
/** Passed through to each batch request — `false` makes oversized inputs
|
|
1356
|
+
* a server-side error instead of a silent truncation. */
|
|
1357
|
+
readonly truncate?: boolean | undefined;
|
|
1358
|
+
/** Passed through to each batch request (dimensionality truncation). */
|
|
1359
|
+
readonly dimensions?: number | undefined;
|
|
1360
|
+
/** Passed through to each batch request (model unload policy). */
|
|
1361
|
+
readonly keep_alive?: string | number | undefined;
|
|
1362
|
+
/** Ollama model options (`num_ctx`, …) passed through to each batch request. */
|
|
1363
|
+
readonly options?: ModelOptions | undefined;
|
|
1364
|
+
/** Aborts the whole batch operation — queued and in-flight alike. */
|
|
1365
|
+
readonly signal?: AbortSignal | undefined;
|
|
1366
|
+
/** Per-request timeout applied to each individual batch request. */
|
|
1367
|
+
readonly timeoutMs?: number | undefined;
|
|
1368
|
+
/**
|
|
1369
|
+
* Progress callback invoked after each successfully embedded batch as
|
|
1370
|
+
* `onBatchComplete(completedBatches, totalBatches)`. Never called after the
|
|
1371
|
+
* operation rejects.
|
|
1372
|
+
*/
|
|
1373
|
+
readonly onBatchComplete?: ((completedBatches: number, totalBatches: number) => void) | undefined;
|
|
1374
|
+
}
|
|
1375
|
+
interface EmbedBatchResult {
|
|
1376
|
+
readonly model: string;
|
|
1377
|
+
/**
|
|
1378
|
+
* Embeddings in input order — `embeddings[i]` corresponds to
|
|
1379
|
+
* `options.input[i]`, independent of batch completion order.
|
|
1380
|
+
*/
|
|
1381
|
+
readonly embeddings: readonly (readonly number[])[];
|
|
1382
|
+
/** Number of `/api/embed` requests the corpus was split into. */
|
|
1383
|
+
readonly batchCount: number;
|
|
1384
|
+
}
|
|
1385
|
+
/** An input string whose estimated token count exceeds the context window. */
|
|
1386
|
+
interface OversizedEmbedInput {
|
|
1387
|
+
/** Index into the input array. */
|
|
1388
|
+
readonly index: number;
|
|
1389
|
+
/** Estimated token count for `input[index]`. */
|
|
1390
|
+
readonly estimate: number;
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Finds input strings whose heuristic token estimate exceeds `contextLength`
|
|
1394
|
+
* (typically the resolved `num_ctx`). Unlike chat/generate pre-flight there is
|
|
1395
|
+
* no warning margin and no output-token headroom: an embedding request's
|
|
1396
|
+
* prompt IS the whole input, so the exact window is the trip point, and
|
|
1397
|
+
* crossing it means silent truncation (or, with `truncate: false`, a
|
|
1398
|
+
* server-side rejection).
|
|
1399
|
+
*/
|
|
1400
|
+
declare function findOversizedEmbedInputs(input: readonly string[], contextLength: number): OversizedEmbedInput[];
|
|
1401
|
+
/**
|
|
1402
|
+
* Builds the warn/throw message for oversized embed inputs (mirrors
|
|
1403
|
+
* `contextWarningMessage` for chat/generate).
|
|
1404
|
+
*/
|
|
1405
|
+
declare function embedBatchOverflowMessage(oversized: readonly OversizedEmbedInput[], totalInputs: number, contextLength: number, truncateFalse: boolean): string;
|
|
1406
|
+
/**
|
|
1407
|
+
* Splits `input` into `batchSize` slices and embeds them through `client.embed()`
|
|
1408
|
+
* with at most `concurrency` batches in flight. Order-preserving and fail-fast —
|
|
1409
|
+
* see the module doc for the full semantics.
|
|
1410
|
+
*
|
|
1411
|
+
* Prefer the {@link OllamaClient.embedBatch} wrapper, which additionally
|
|
1412
|
+
* injects `defaultContextLength` as `num_ctx` and enforces the client's
|
|
1413
|
+
* `onContextOverflow` policy against per-string estimates before any request
|
|
1414
|
+
* is sent.
|
|
1415
|
+
*/
|
|
1416
|
+
declare function batchEmbed(client: OllamaClient, options: EmbedBatchOptions): Promise<EmbedBatchResult>;
|
|
1417
|
+
|
|
984
1418
|
/**
|
|
985
1419
|
* Ergonomic System One types — key-safe generics on top of the generated
|
|
986
1420
|
* contract models.
|
|
@@ -1425,6 +1859,14 @@ declare class OllamaClient {
|
|
|
1425
1859
|
private readonly contextWarningThreshold;
|
|
1426
1860
|
/** Configured overflow policy — `'warn'` (default) or `'throw'`. */
|
|
1427
1861
|
private readonly onContextOverflow;
|
|
1862
|
+
/**
|
|
1863
|
+
* Controllers for every in-flight request and active stream managed by this
|
|
1864
|
+
* client — see {@link OllamaClient.destroy} and {@link createRequestScope}.
|
|
1865
|
+
* Entries live for exactly as long as the underlying work does: until the
|
|
1866
|
+
* response settles (requests) or the stream's `finalResult` settles
|
|
1867
|
+
* (streams, via `executeWithFailover`'s `holdUntil` release path).
|
|
1868
|
+
*/
|
|
1869
|
+
private readonly activeRequests;
|
|
1428
1870
|
constructor(config?: OllamaClientConfig);
|
|
1429
1871
|
get modelsClient(): ModelsClient;
|
|
1430
1872
|
/**
|
|
@@ -1523,6 +1965,17 @@ declare class OllamaClient {
|
|
|
1523
1965
|
* reference when there's nothing to inject (the common case).
|
|
1524
1966
|
*/
|
|
1525
1967
|
private injectDefaultContextLength;
|
|
1968
|
+
/**
|
|
1969
|
+
* Creates the per-request abort scope registered with {@link destroy}:
|
|
1970
|
+
* a controller that fires when the caller's `signal` aborts OR when
|
|
1971
|
+
* `destroy()` runs, whichever comes first. `dispose()` removes the
|
|
1972
|
+
* registration when the work it guards settles — for plain requests when
|
|
1973
|
+
* the response settles, for streams when `finalResult` settles (the same
|
|
1974
|
+
* moment `executeWithFailover`'s `holdUntil` releases the endpoint slot),
|
|
1975
|
+
* so a destroy() can tear down a stream mid-consumption but never outlives
|
|
1976
|
+
* one that already finished.
|
|
1977
|
+
*/
|
|
1978
|
+
private createRequestScope;
|
|
1526
1979
|
/**
|
|
1527
1980
|
* Fail-fast guard for `format` (structured output) requests: throws before any network
|
|
1528
1981
|
* call if the candidate endpoint is inferred as Ollama Cloud, which does not currently
|
|
@@ -1585,6 +2038,36 @@ declare class OllamaClient {
|
|
|
1585
2038
|
generateWithSchema<T>(req: Omit<GenerateRequestOptions, 'stream' | 'format'>, schema: z.ZodType<T>): Promise<T>;
|
|
1586
2039
|
embed(req: EmbedRequestOptions): Promise<EmbedResponse>;
|
|
1587
2040
|
embedText(model: string, input: string | readonly string[]): Promise<readonly (readonly number[])[]>;
|
|
2041
|
+
/**
|
|
2042
|
+
* Batch-constrained, order-preserving embedding generation for large
|
|
2043
|
+
* corpora — the safe building block for RAG/vector-index ingestion at
|
|
2044
|
+
* scale. Splits `input` into `batchSize` slices and embeds them through
|
|
2045
|
+
* {@link embed} with at most `concurrency` batches in flight (defaults:
|
|
2046
|
+
* 32 × 3), so `Promise.all`-style floods that OOM local daemons and
|
|
2047
|
+
* saturate `OLLAMA_MAX_QUEUE` can't happen by accident. Fail-fast: the
|
|
2048
|
+
* first batch error aborts every sibling in-flight batch and rejects the
|
|
2049
|
+
* whole operation with the original error.
|
|
2050
|
+
*
|
|
2051
|
+
* Before any request is sent, `defaultContextLength` is injected as
|
|
2052
|
+
* `num_ctx` (same as chat/generate) and each input string's token estimate
|
|
2053
|
+
* is checked against the resolved window: Ollama silently truncates
|
|
2054
|
+
* oversized embedding inputs by default, so the client warns (or throws,
|
|
2055
|
+
* under `onContextOverflow: 'throw'`) with the offending indexes — see
|
|
2056
|
+
* `src/embed-batch.ts` for the exact trip point (no margin: an embedding
|
|
2057
|
+
* prompt IS the whole input).
|
|
2058
|
+
*
|
|
2059
|
+
* ```ts
|
|
2060
|
+
* const { embeddings, batchCount } = await client.embedBatch({
|
|
2061
|
+
* model: 'nomic-embed-text:latest',
|
|
2062
|
+
* input: corpus, // e.g. 50k chunks
|
|
2063
|
+
* batchSize: 32, // inputs per /api/embed request
|
|
2064
|
+
* concurrency: 3, // batches in flight
|
|
2065
|
+
* onBatchComplete: (done, total) => progress.log(`${done}/${total}`),
|
|
2066
|
+
* });
|
|
2067
|
+
* // embeddings[i] always corresponds to corpus[i]
|
|
2068
|
+
* ```
|
|
2069
|
+
*/
|
|
2070
|
+
embedBatch(options: EmbedBatchOptions): Promise<EmbedBatchResult>;
|
|
1588
2071
|
/**
|
|
1589
2072
|
* @deprecated Ollama's `/api/embeddings` endpoint has been superseded by `/api/embed`
|
|
1590
2073
|
* (exposed here as {@link OllamaClient.embed}), which additionally supports batch
|
|
@@ -1598,7 +2081,15 @@ declare class OllamaClient {
|
|
|
1598
2081
|
readonly createModel: (r: CreateRequestOptions) => Promise<ProgressResponse | OllamaStream<ProgressResponse, ProgressStreamResult>>;
|
|
1599
2082
|
readonly deleteModel: (req: DeleteRequestOptions) => Promise<StatusResponse>;
|
|
1600
2083
|
readonly copyModel: (req: CopyRequestOptions) => Promise<StatusResponse>;
|
|
1601
|
-
readonly ps: () => Promise<PsResponse>;
|
|
2084
|
+
readonly ps: (request?: RequestCancellationOptions) => Promise<PsResponse>;
|
|
2085
|
+
/**
|
|
2086
|
+
* Discovers the model's real context window — the allocated window of the
|
|
2087
|
+
* running instance (`/api/ps`), the Modelfile `num_ctx` default, and the
|
|
2088
|
+
* native GGUF maximum (`/api/show` `model_info`), resolved by precedence.
|
|
2089
|
+
* Convenience alias for {@link ModelsClient.getContextLength} — see that
|
|
2090
|
+
* method for the full contract and the precedence order.
|
|
2091
|
+
*/
|
|
2092
|
+
readonly getContextLength: (request: ContextDiscoveryRequestOptions) => Promise<DiscoveredContextLength>;
|
|
1602
2093
|
readonly version: () => Promise<VersionResponse>;
|
|
1603
2094
|
readonly createBlob: (digest: string, data: BinaryBody) => Promise<void>;
|
|
1604
2095
|
readonly checkBlob: (digest: string) => Promise<boolean>;
|
|
@@ -1710,6 +2201,26 @@ declare class OllamaClient {
|
|
|
1710
2201
|
runtimeMode(): RuntimeMode;
|
|
1711
2202
|
healthCheck(): Promise<EndpointHealthCheckResult[]>;
|
|
1712
2203
|
endpointStatus(): EndpointHealth[];
|
|
2204
|
+
/**
|
|
2205
|
+
* Immediately aborts every in-flight request and active stream managed by
|
|
2206
|
+
* this client — the clean teardown path for short-lived processes, CLI
|
|
2207
|
+
* runners, and `node:worker_threads` tasks where dangling fetch bodies,
|
|
2208
|
+
* unconsumed stream readers, or queued capacity waiters would otherwise
|
|
2209
|
+
* keep the event loop (and thus the thread/process) alive.
|
|
2210
|
+
*
|
|
2211
|
+
* Every aborted operation rejects with an {@link OllamaAbortError}
|
|
2212
|
+
* (`code: 'aborted'`) carrying `reason` as its message — including requests
|
|
2213
|
+
* still queued behind `maxConcurrentPerEndpoint`, not just dispatched ones.
|
|
2214
|
+
* Streams reject their `finalResult` and release their endpoint slots.
|
|
2215
|
+
*
|
|
2216
|
+
* Idempotent: calling it again (or on a client with nothing in flight)
|
|
2217
|
+
* is a no-op that returns `0`. The client remains usable afterward —
|
|
2218
|
+
* `destroy()` is a drain, not a permanent disable; callers that want a
|
|
2219
|
+
* permanently-dead client should discard the instance.
|
|
2220
|
+
*
|
|
2221
|
+
* @returns the number of in-flight operations that were aborted.
|
|
2222
|
+
*/
|
|
2223
|
+
destroy(reason?: string): number;
|
|
1713
2224
|
get openai(): OpenAICompatClient;
|
|
1714
2225
|
get anthropic(): AnthropicCompatClient;
|
|
1715
2226
|
}
|
|
@@ -2413,6 +2924,22 @@ interface AgentConfig {
|
|
|
2413
2924
|
readonly maxIterations?: number | undefined;
|
|
2414
2925
|
/** Maximum total tool calls allowed during one agent run. */
|
|
2415
2926
|
readonly maxToolCalls?: number | undefined;
|
|
2927
|
+
/**
|
|
2928
|
+
* Cycle detection: maximum executions of one *identical* tool call — same
|
|
2929
|
+
* tool name and same arguments — during a single run. When the model would
|
|
2930
|
+
* exceed this budget (the classic stuck-loop signature: re-emitting the
|
|
2931
|
+
* same call without reacting to its results), the run fails fast with
|
|
2932
|
+
* {@link OllamaAgentToolLoopError} instead of burning the remaining
|
|
2933
|
+
* iterations on the same wasted call.
|
|
2934
|
+
*
|
|
2935
|
+
* Off by default (`undefined`), matching `maxToolCalls`: an explicit,
|
|
2936
|
+
* caller-owned guardrail. Counting is per canonical signature, so
|
|
2937
|
+
* argument key order never splits one repeated call into several
|
|
2938
|
+
* "distinct" ones. Every call handed to the registry counts — failed,
|
|
2939
|
+
* unregistered, and timed-out executions included, since re-calling a
|
|
2940
|
+
* failing tool with unchanged arguments is exactly the loop this catches.
|
|
2941
|
+
*/
|
|
2942
|
+
readonly maxRepeatedToolCalls?: number | undefined;
|
|
2416
2943
|
readonly hooks?: AgentHooks | undefined;
|
|
2417
2944
|
/** Validate tool support from /api/show before starting a tool-enabled run. Default: true. */
|
|
2418
2945
|
readonly validateToolCapability?: boolean | undefined;
|
|
@@ -2448,6 +2975,18 @@ interface AgentChatClient {
|
|
|
2448
2975
|
readonly message: Message;
|
|
2449
2976
|
}>;
|
|
2450
2977
|
}
|
|
2978
|
+
/**
|
|
2979
|
+
* Canonical signature of a tool call for cycle detection: `name(args)` with
|
|
2980
|
+
* recursively key-sorted arguments, so the same call re-emitted by a model
|
|
2981
|
+
* in a different argument key order collapses to one signature instead of
|
|
2982
|
+
* counting as two "distinct" calls.
|
|
2983
|
+
*
|
|
2984
|
+
* ```ts
|
|
2985
|
+
* canonicalToolCallSignature({ function: { name: 'search', arguments: { q: 'x' } } })
|
|
2986
|
+
* // 'search({"q":"x"})'
|
|
2987
|
+
* ```
|
|
2988
|
+
*/
|
|
2989
|
+
declare function canonicalToolCallSignature(toolCall: ToolCall): string;
|
|
2451
2990
|
/**
|
|
2452
2991
|
* Runs a multi-turn `chat` + tool-execution loop until the model responds without
|
|
2453
2992
|
* requesting further tool calls, or `maxIterations` is exceeded. Tool calls within a
|
|
@@ -2464,6 +3003,7 @@ declare class Agent {
|
|
|
2464
3003
|
private readonly tools?;
|
|
2465
3004
|
private readonly maxIterations;
|
|
2466
3005
|
private readonly maxToolCalls?;
|
|
3006
|
+
private readonly maxRepeatedToolCalls?;
|
|
2467
3007
|
private readonly hooks?;
|
|
2468
3008
|
private readonly validateToolCapability;
|
|
2469
3009
|
private readonly toolContextSize;
|
|
@@ -2602,6 +3142,11 @@ declare const IMAGE_TOKEN_ESTIMATE = 300;
|
|
|
2602
3142
|
* model-specific tokenizer.
|
|
2603
3143
|
*/
|
|
2604
3144
|
declare function estimateTokens(text: string): number;
|
|
3145
|
+
/**
|
|
3146
|
+
* Rough per-message framing overhead: role tags, chat-template delimiters.
|
|
3147
|
+
*/
|
|
3148
|
+
declare const MESSAGE_OVERHEAD_TOKENS = 4;
|
|
3149
|
+
declare function estimateMessageTokens(message: Message): number;
|
|
2605
3150
|
/**
|
|
2606
3151
|
* Estimated prompt tokens for a `/api/chat` request: every message plus
|
|
2607
3152
|
* tool-schema overhead (each tool definition's JSON schema serializes into
|
|
@@ -2657,4 +3202,142 @@ declare const OLLAMA_FALLBACK_CONTEXT_LENGTH = 2048;
|
|
|
2657
3202
|
*/
|
|
2658
3203
|
declare function contextWarningMessage(check: ContextCheck, kind: 'chat' | 'generate'): string;
|
|
2659
3204
|
|
|
2660
|
-
|
|
3205
|
+
/**
|
|
3206
|
+
* Model-affinity scheduling: keep the daemon's working set small.
|
|
3207
|
+
*
|
|
3208
|
+
* Ollama's concurrency model (per the official FAQ):
|
|
3209
|
+
*
|
|
3210
|
+
* - A model's KV cache scales by `OLLAMA_NUM_PARALLEL × context_length` —
|
|
3211
|
+
* parallel requests to the *same* loaded model are cheap (each gets its
|
|
3212
|
+
* own slot of the already-allocated cache).
|
|
3213
|
+
* - Requests for a *different* model queue until the first goes idle or is
|
|
3214
|
+
* evicted (`OLLAMA_MAX_LOADED_MODELS`, default 3× GPU count) — a swap is
|
|
3215
|
+
* an expensive unload/cold-load cycle: seconds of VRAM churn that a
|
|
3216
|
+
* concurrent multi-model workload pays again and again when it
|
|
3217
|
+
* interleaves models arbitrarily.
|
|
3218
|
+
* - Once `OLLAMA_MAX_QUEUE` (default 512) requests are waiting, new ones
|
|
3219
|
+
* are rejected outright with 503s.
|
|
3220
|
+
*
|
|
3221
|
+
* `ModelAffinityScheduler` is the client-side counterpart for workloads that
|
|
3222
|
+
* juggle several models — extraction on a coder model, reasoning on a
|
|
3223
|
+
* thinking model, embeddings for retrieval. It groups tasks into per-model
|
|
3224
|
+
* serial queues and caps how many *distinct* models have work in flight
|
|
3225
|
+
* (`concurrentModels`, default 1), preferring to deepen the currently-active
|
|
3226
|
+
* model over starting the next one — the anti-thrashing order. Candidate
|
|
3227
|
+
* lists let a task run on whichever of several interchangeable models is
|
|
3228
|
+
* already loaded (`GET /api/ps`, cached with a TTL).
|
|
3229
|
+
*
|
|
3230
|
+
* It is a user-space primitive, deliberately not wired into `OllamaClient`'s
|
|
3231
|
+
* request path: affinity decisions are workload policy, and the scheduler is
|
|
3232
|
+
* the foundation the multi-instance routing work builds on. See ADR 0026.
|
|
3233
|
+
*/
|
|
3234
|
+
|
|
3235
|
+
/**
|
|
3236
|
+
* The minimal client surface the scheduler needs. `OllamaClient` satisfies it
|
|
3237
|
+
* structurally; tests and custom setups can pass any compatible object.
|
|
3238
|
+
*/
|
|
3239
|
+
interface ModelAffinityClient {
|
|
3240
|
+
readonly models: {
|
|
3241
|
+
ps(): Promise<{
|
|
3242
|
+
readonly models: ReadonlyArray<{
|
|
3243
|
+
readonly name: string;
|
|
3244
|
+
}>;
|
|
3245
|
+
}>;
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3248
|
+
/** Options for {@link ModelAffinityScheduler}. */
|
|
3249
|
+
interface ModelAffinitySchedulerOptions {
|
|
3250
|
+
/**
|
|
3251
|
+
* Maximum number of *distinct* models with work in flight at once
|
|
3252
|
+
* (default `1`). `1` is the anti-thrashing setting: one model stays hot
|
|
3253
|
+
* until its queue drains, then the next loads. Raise it only when the
|
|
3254
|
+
* host has VRAM for several concurrent models
|
|
3255
|
+
* (`OLLAMA_MAX_LOADED_MODELS`).
|
|
3256
|
+
*/
|
|
3257
|
+
readonly concurrentModels?: number | undefined;
|
|
3258
|
+
/**
|
|
3259
|
+
* Parallel tasks allowed per active model (default `1`). Raising this
|
|
3260
|
+
* mirrors the server's own `OLLAMA_NUM_PARALLEL` — same-model parallelism
|
|
3261
|
+
* reuses the loaded weights without swap cost.
|
|
3262
|
+
*/
|
|
3263
|
+
readonly perModelConcurrency?: number | undefined;
|
|
3264
|
+
/**
|
|
3265
|
+
* How long a `GET /api/ps` result is reused when choosing among candidate
|
|
3266
|
+
* models (default `30_000` ms). Only multi-candidate `run()` calls and
|
|
3267
|
+
* `loadedModels()` consult the server; single-model tasks never do.
|
|
3268
|
+
*/
|
|
3269
|
+
readonly psCacheTtlMs?: number | undefined;
|
|
3270
|
+
}
|
|
3271
|
+
/** Live scheduling state, from {@link ModelAffinityScheduler.stats}. */
|
|
3272
|
+
interface ModelAffinityStats {
|
|
3273
|
+
/** Models with at least one task currently executing. */
|
|
3274
|
+
readonly activeModels: readonly string[];
|
|
3275
|
+
/** Tasks waiting in queues (not yet started). */
|
|
3276
|
+
readonly queuedTasks: number;
|
|
3277
|
+
}
|
|
3278
|
+
/**
|
|
3279
|
+
* Groups async work by model with load-aware dispatch.
|
|
3280
|
+
*
|
|
3281
|
+
* ```ts
|
|
3282
|
+
* const scheduler = new ModelAffinityScheduler(client);
|
|
3283
|
+
*
|
|
3284
|
+
* // Serial queue per model; one model hot at a time (default):
|
|
3285
|
+
* await scheduler.run('deepseek-r1', () => reason(client));
|
|
3286
|
+
* await scheduler.run('qwen2.5:coder', () => extract(client));
|
|
3287
|
+
*
|
|
3288
|
+
* // Either-or: picks whichever candidate is already loaded (/api/ps):
|
|
3289
|
+
* const summary = await scheduler.run(
|
|
3290
|
+
* ['qwen2.5:coder', 'qwen2.5:14b'],
|
|
3291
|
+
* (model) => extractWith(client, model),
|
|
3292
|
+
* );
|
|
3293
|
+
* ```
|
|
3294
|
+
*
|
|
3295
|
+
* Dispatch order is **affinity-sticky, not round-robin**: when a queued
|
|
3296
|
+
* model is already active, its tasks start before a different model's (up to
|
|
3297
|
+
* `perModelConcurrency`), because deepening the hot model avoids a swap.
|
|
3298
|
+
* Tasks run in FIFO order within each model's queue. Task functions are the
|
|
3299
|
+
* caller's own — the scheduler adds no retry, timeout, or failover, and a
|
|
3300
|
+
* rejected task simply rejects its `run()` promise while its siblings
|
|
3301
|
+
* proceed.
|
|
3302
|
+
*/
|
|
3303
|
+
declare class ModelAffinityScheduler {
|
|
3304
|
+
private readonly client;
|
|
3305
|
+
private readonly queues;
|
|
3306
|
+
private readonly concurrentModels;
|
|
3307
|
+
private readonly perModelConcurrency;
|
|
3308
|
+
private readonly psCacheTtlMs;
|
|
3309
|
+
private psCache;
|
|
3310
|
+
private readonly drainWaiters;
|
|
3311
|
+
constructor(client: ModelAffinityClient, options?: ModelAffinitySchedulerOptions);
|
|
3312
|
+
/**
|
|
3313
|
+
* Runs `task` on the scheduler, serialized per model. When `model` is a
|
|
3314
|
+
* list of candidates, the already-loaded one is preferred (fresh
|
|
3315
|
+
* `/api/ps` data subject to the TTL cache); with none loaded — or when the
|
|
3316
|
+
* lookup fails — the first candidate runs. The chosen model is handed to
|
|
3317
|
+
* the task.
|
|
3318
|
+
*/
|
|
3319
|
+
run<T>(model: string | readonly string[], task: (model: string) => Promise<T>): Promise<T>;
|
|
3320
|
+
/**
|
|
3321
|
+
* Names of the models currently loaded, per `GET /api/ps`, cached for
|
|
3322
|
+
* `psCacheTtlMs`. Degrades to an empty list when the server can't answer
|
|
3323
|
+
* (never throws; candidate selection treats it as "nothing loaded").
|
|
3324
|
+
*/
|
|
3325
|
+
loadedModels(): Promise<readonly string[]>;
|
|
3326
|
+
/** Current scheduling state — active models and queued task count. */
|
|
3327
|
+
get stats(): ModelAffinityStats;
|
|
3328
|
+
/**
|
|
3329
|
+
* Resolves once every queue is empty and no task is running. Does not
|
|
3330
|
+
* abort anything — tasks are caller-owned; abort them via their own
|
|
3331
|
+
* signals before disposing if needed.
|
|
3332
|
+
*/
|
|
3333
|
+
dispose(): Promise<void>;
|
|
3334
|
+
private chooseCandidate;
|
|
3335
|
+
private refreshPsNames;
|
|
3336
|
+
private pump;
|
|
3337
|
+
private activeModelCount;
|
|
3338
|
+
private execute;
|
|
3339
|
+
}
|
|
3340
|
+
/** Convenience factory — `createModelAffinityScheduler(client, opts)` reads better in setups. */
|
|
3341
|
+
declare function createModelAffinityScheduler(client: ModelAffinityClient | OllamaClient, options?: ModelAffinitySchedulerOptions): ModelAffinityScheduler;
|
|
3342
|
+
|
|
3343
|
+
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 CompactionOptions, type ContextCheck, type ContextCheckOptions, type ContextDiscoveryRequestOptions, type ContextLengthSignals, type ContextLengthSource, type ContextWindowSource, type ConversationSendOptions, ConversationSession, type ConversationSessionOptions, CopyRequestOptions, CreateRequestOptions, type CumulativeCacheStats, DEFAULT_BACKOFF, DEFAULT_BASE_URL, DEFAULT_CONTEXT_WARNING_THRESHOLD, DEFAULT_EMBED_BATCH_SIZE, DEFAULT_EMBED_CONCURRENCY, DEFAULT_FAILOVER_CODES, DEFAULT_FETCH_BACKOFF_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TIMEOUT_MS, type Decision, type DefineToolOptions, DeleteRequestOptions, type DiscoveredContextLength, type EmbedBatchOptions, type EmbedBatchResult, EmbedRequestOptions, EmbedResponse, EmbeddingsRequestOptions, EmbeddingsResponse, type EndpointHealth, type EndpointHealthCheckResult, EndpointRegistry, type EndpointRegistryOptions, FetchLike, type FetchWithBackoffConfig, FormatOption, GEN_AI_SYSTEM_OLLAMA, GenerateRequestOptions, GenerateResponse, GenerateStreamResult, type HistorySanitizeOptions, 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, MESSAGE_OVERHEAD_TOKENS, McpBridge, type McpBridgeOptions, McpCallToolResult, McpClientLike, McpTask, McpToolDescriptor, Message, Middleware, type ModelAffinityClient, ModelAffinityScheduler, type ModelAffinitySchedulerOptions, type ModelAffinityStats, 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 OversizedEmbedInput, 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 SessionCompactionOptions, type SessionCompactionResult, 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, batchEmbed, calculateBackoff, canonicalToolCallSignature, checkChatContext, checkEndpointHealth, checkGenerateContext, compactConversationHistory, contextWarningMessage, createDecision, createModelAffinityScheduler, createOllamaCloudFreeTierQuota, createTimeoutSignal, defineTool, detectModelCapabilities, embedBatchOverflowMessage, encodeImage, estimateChatRequestTokens, estimateGenerateRequestTokens, estimateMessageTokens, estimateSystemOneRequestBytes, estimateTokens, extractContextLength as extractNativeContextLength, extractParameterNumCtx, fetchWithBackoff, findOversizedEmbedInputs, findRunningModelContextLength, inferRuntimeMode, isKeepAliveSugar, isKnownDoneReason, isSameToolCall, listAllMcpTools, listAvailableModels, loadMcpTools, mergeToolCall, mergeToolCallArgumentsString, mergeToolCallArrays, normalizeChatStream, normalizeGenerateStream, normalizeKeepAlive, normalizeProgressStream, parseNdjsonStream, parseStructuredOutput, registerMcpTools, resolveContextLength, resolveCredentialEndpoints, sanitizeHistoryForNextTurn, setSpanError, toDataStream, toResponse, toTextStream, withRetry, withSpan, zodToJsonSchema };
|