@orkestrel/ollama 0.0.14 → 0.0.16

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.
@@ -1,542 +0,0 @@
1
- import { ContextFormat } from '@orkestrel/agent';
2
- import { Message } from '@orkestrel/agent';
3
- import { ProviderDelta } from '@orkestrel/agent';
4
- import { ProviderInterface } from '@orkestrel/agent';
5
- import { ProviderResult } from '@orkestrel/agent';
6
- import { ProviderStreamOptions } from '@orkestrel/agent';
7
- import { ThinkSplitterInterface } from '@orkestrel/agent';
8
- import { TimeoutInterface } from '@orkestrel/timeout';
9
- import { TokenUsage } from '@orkestrel/budget';
10
- import { ToolCall } from '@orkestrel/tool';
11
- import { ToolDefinition } from '@orkestrel/tool';
12
-
13
- /**
14
- * Builds a provider result from a turn's content, reasoning, tool calls, and usage.
15
- *
16
- * @remarks
17
- * Only the present optionals are set: no empty `thinking`, no empty `tools`, and no
18
- * `usage` unless the wire reported one.
19
- *
20
- * @param content - The clean assistant content the splitter accumulated
21
- * @param thinking - The joined reasoning, empty when the turn produced none
22
- * @param tools - The tool calls collected across the turn
23
- * @param usage - The token usage, or `undefined` when the wire reported none
24
- * @returns The result carrying only its populated fields
25
- *
26
- * @example
27
- * ```ts
28
- * buildResult('ok', '', [], undefined) // { content: 'ok' }
29
- * ```
30
- */
31
- export declare function buildResult(content: string, thinking: string, tools: readonly ToolCall[], usage: TokenUsage | undefined): ProviderResult;
32
-
33
- /**
34
- * Creates a local Ollama inference provider — a {@link ProviderInterface} over the
35
- * daemon's `POST /api/chat`, supporting non-streaming `generate` and streaming
36
- * `stream`.
37
- *
38
- * @remarks
39
- * Only `model` is required; `url` defaults to the local daemon, `keepAlive` to `'5m'`,
40
- * `timeout` to `120_000`ms, and `options` is forwarded verbatim as sampling
41
- * parameters (`temperature`, `seed`, and `num_predict`). Both calls take an
42
- * `AbortSignal` to bound the request; a `stream` cancelled mid-flight throws a
43
- * `ProviderAbortError` carrying the partial result.
44
- *
45
- * The optional `fetch` + `headers` form a transport seam (see {@link OllamaOptions}):
46
- * point `url` at your own server, inject a custom `fetch`, and have `headers` attach a
47
- * generated/obfuscated bearer token your server validates — so a browser runtime
48
- * reaches the LLM through your middleware WITHOUT this library ever handling the real API
49
- * key. Both omitted ⇒ the global `fetch` and only a JSON content type.
50
- *
51
- * The optional `format` is the provider's context-framing default — the PROVIDER-DEFAULT
52
- * level of `AgentContext`'s format cascade (beaten by a manager-options or per-item
53
- * override, beating the managers' built-in framing), declaring how this
54
- * provider's models prefer context sections framed (for example XML group wrappers vs. Markdown
55
- * headers). It is EXPOSED on the provider for the Agent's `build()` and is NOT Ollama's
56
- * `/api/chat` `format` wire parameter (structured output) — the two are unrelated despite
57
- * the shared word. Omitted ⇒ the provider is framing-agnostic (core's built-in defaults).
58
- *
59
- * @param options - `model` (required), and optional `url` / `keepAlive` / `timeout` /
60
- * `options` / `fetch` / `headers` / `format` (see {@link OllamaOptions})
61
- * @returns A working {@link ProviderInterface} backed by Ollama
62
- *
63
- * @example
64
- * ```ts
65
- * import { createAbort } from '@orkestrel/abort'
66
- * import { createOllama } from '@orkestrel/ollama'
67
- *
68
- * const provider = createOllama({ model: 'qwen3.5:2b-q4_K_M' })
69
- * const abort = createAbort()
70
- * const result = await provider.generate(messages, abort.signal)
71
- * ```
72
- *
73
- * @example
74
- * Route through your own server with an obfuscated token:
75
- * ```ts
76
- * const provider = createOllama({
77
- * model: 'qwen3.5:2b-q4_K_M',
78
- * url: 'https://my-app.example.com/llm', // your server, not the daemon
79
- * fetch: myFetch, // optional custom transport
80
- * headers: () => ({ authorization: `Bearer ${myToken}` }), // your server validates this
81
- * })
82
- * ```
83
- *
84
- * @example
85
- * Declare a context-framing default — wrap the instructions section in an XML group (the
86
- * provider-default level of `AgentContext`'s cascade; NOT the wire `format`):
87
- * ```ts
88
- * const provider = createOllama({
89
- * model: 'qwen3.5:2b-q4_K_M',
90
- * format: {
91
- * instructions: {
92
- * open: '<instructions>',
93
- * render: (i) => `<instruction>${i.content}</instruction>`,
94
- * close: '</instructions>',
95
- * },
96
- * },
97
- * })
98
- * ```
99
- */
100
- export declare function createOllama(options: OllamaOptions): ProviderInterface;
101
-
102
- /**
103
- * Names how long the model stays resident after a call when `OllamaOptions.keepAlive` is
104
- * omitted — Ollama's own `keep_alive` default, expressed as a duration string.
105
- *
106
- * @remarks
107
- * The name mirrors the Ollama `/api/chat` `keep_alive` field this value is sent as, so
108
- * the constant, the `OllamaOptions.keepAlive` key, and the wire member read as one term.
109
- */
110
- export declare const DEFAULT_KEEP_ALIVE = "5m";
111
-
112
- /** Names the local Ollama daemon base URL assumed when `OllamaOptions.url` is omitted. */
113
- export declare const DEFAULT_OLLAMA_URL = "http://localhost:11434";
114
-
115
- /**
116
- * Names the per-call deadline in milliseconds when `OllamaOptions.timeout` is omitted —
117
- * generous enough that a cold model load does not trip it.
118
- */
119
- export declare const DEFAULT_PROVIDER_TIMEOUT = 120000;
120
-
121
- /**
122
- * Extracts a wire `arguments` value as a record.
123
- *
124
- * @remarks
125
- * Total: an object passes through, a JSON string is parsed when it yields a record, and
126
- * a malformed string yields `{}` rather than throwing.
127
- *
128
- * @param value - The wire's `function.arguments` value, of unknown shape
129
- * @returns The argument record, or `{}` when the value carries none
130
- *
131
- * @example
132
- * ```ts
133
- * extractArguments('{"city":"Oslo"}') // { city: 'Oslo' }
134
- * ```
135
- */
136
- export declare function extractArguments(value: unknown): Readonly<Record<string, unknown>>;
137
-
138
- /**
139
- * Extracts the assistant text of one wire record.
140
- *
141
- * @param record - One parsed `/api/chat` record — a non-stream body or an NDJSON line
142
- * @returns The record's `message.content` when it is a string, else `''`
143
- *
144
- * @example
145
- * ```ts
146
- * extractContent({ message: { content: 'ok' } }) // 'ok'
147
- * ```
148
- */
149
- export declare function extractContent(record: Readonly<Record<string, unknown>>): string;
150
-
151
- /**
152
- * Extracts the daemon-side reasoning of one wire record.
153
- *
154
- * @remarks
155
- * `message.thinking` is the `think: true` wire shape. It is read whatever the configured
156
- * flag says, because a daemon may separate reasoning on its own.
157
- *
158
- * @param record - One parsed `/api/chat` record — a non-stream body or an NDJSON line
159
- * @returns The record's `message.thinking` when it is a string, else `''`
160
- *
161
- * @example
162
- * ```ts
163
- * extractThinking({ message: { thinking: 'weighing it' } }) // 'weighing it'
164
- * ```
165
- */
166
- export declare function extractThinking(record: Readonly<Record<string, unknown>>): string;
167
-
168
- /**
169
- * Extracts the tool calls of one wire record's `message.tool_calls`.
170
- *
171
- * @remarks
172
- * Each entry narrows to `{ id, name, arguments }`: the entry and its `function` must be
173
- * records and `name` a string, else the entry is dropped. An id is minted when the wire
174
- * omits one.
175
- *
176
- * @param record - One parsed `/api/chat` record — a non-stream body or an NDJSON line
177
- * @returns The narrowed tool calls, empty when the record carries none
178
- *
179
- * @example
180
- * ```ts
181
- * extractTools({ message: { tool_calls: [{ function: { name: 'weather' } }] } })
182
- * // [{ id: '…', name: 'weather', arguments: {} }]
183
- * ```
184
- */
185
- export declare function extractTools(record: Readonly<Record<string, unknown>>): readonly ToolCall[];
186
-
187
- /**
188
- * Extracts the token usage of one wire record.
189
- *
190
- * @remarks
191
- * Both counts must be numbers, which is true of the non-stream body and the stream's
192
- * `done: true` line. A delta line carries neither, so it yields `undefined`.
193
- *
194
- * @param record - One parsed `/api/chat` record — a non-stream body or an NDJSON line
195
- * @returns The `TokenUsage` shape, or `undefined` when either count is absent
196
- *
197
- * @example
198
- * ```ts
199
- * extractUsage({ prompt_eval_count: 3, eval_count: 4 })
200
- * // { prompt: 3, completion: 4, total: 7 }
201
- * ```
202
- */
203
- export declare function extractUsage(record: Readonly<Record<string, unknown>>): TokenUsage | undefined;
204
-
205
- /**
206
- * Checks whether a value is an {@link OllamaHTTPError}.
207
- *
208
- * @param value - The value to test
209
- * @returns True if `value` is an `OllamaHTTPError`; false otherwise
210
- */
211
- export declare function isOllamaHTTPError(value: unknown): value is OllamaHTTPError;
212
-
213
- /**
214
- * Joins a call's two reasoning carriers into the result's `thinking`.
215
- *
216
- * @param splitter - The per-call splitter holding the separated in-content spans
217
- * @param wired - The accumulated wire-side `message.thinking` text
218
- * @returns The two carriers separated by a blank line, or whichever one is non-empty
219
- *
220
- * @example
221
- * ```ts
222
- * joinThinking(createThinkSplitter(), 'from the wire') // 'from the wire'
223
- * ```
224
- */
225
- export declare function joinThinking(splitter: ThinkSplitterInterface, wired: string): string;
226
-
227
- /**
228
- * Maps conversation turns onto the `/api/chat` wire's minimal message shape.
229
- *
230
- * @remarks
231
- * `tool_calls` is emitted only on a turn that replays them and `images` only on a
232
- * multimodal turn, so an empty optional never reaches the wire.
233
- *
234
- * @param messages - The conversation turns to send
235
- * @returns The wire `messages` array, one entry per turn, in order
236
- *
237
- * @example
238
- * ```ts
239
- * mapMessages([{ id: '1', role: 'user', content: 'Say hello.' }])
240
- * // [{ role: 'user', content: 'Say hello.' }]
241
- * ```
242
- */
243
- export declare function mapMessages(messages: readonly Message[]): WireChatRequest['messages'];
244
-
245
- /**
246
- * Names the cap, in characters, on how much of a non-OK response body is
247
- * incorporated into a thrown {@link OllamaHTTPError}'s message.
248
- *
249
- * @remarks
250
- * Bounds the excerpt so a defensive proxy or a misbehaving daemon handing
251
- * back an unbounded response body cannot inflate the thrown error's message
252
- * without limit. `2048` characters is generous enough to carry a
253
- * useful diagnostic snippet while staying well short of any practical size
254
- * concern.
255
- */
256
- export declare const MAX_ERROR_BODY_LENGTH = 2048;
257
-
258
- /**
259
- * Represents an error thrown when the Ollama `/api/chat` HTTP transport fails.
260
- *
261
- * @remarks
262
- * Carries the machine-readable `code` `'HTTP'` and the response `status` (0 when no
263
- * HTTP response was received at all, for example a `null` body). Thrown by
264
- * {@link OllamaProvider} at its HTTP failure sites — the non-OK status branch and the
265
- * null-body branch — so a caller can branch on `error.code` and read `error.status`
266
- * for the HTTP number instead of parsing the message. Narrow a caught value with
267
- * {@link isOllamaHTTPError}.
268
- *
269
- * @example
270
- * ```ts
271
- * try {
272
- * await provider.generate(messages, signal)
273
- * } catch (error) {
274
- * if (isOllamaHTTPError(error) && error.status === 404) {
275
- * // the configured model isn't pulled
276
- * }
277
- * }
278
- * ```
279
- */
280
- export declare class OllamaHTTPError extends Error {
281
- /**
282
- * Names the machine-readable condition this error reports — `'HTTP'`: an `/api/chat`
283
- * transport, status, or body failure.
284
- */
285
- readonly code: "HTTP";
286
- readonly status: number;
287
- constructor(message: string, status: number, options?: OllamaHTTPErrorOptions);
288
- }
289
-
290
- /**
291
- * Represents the options a thrown {@link OllamaHTTPError} accepts beside its message and status —
292
- * the standard error `cause` link, named so a consumer can reference the shape.
293
- *
294
- * @remarks
295
- * `cause` is the underlying value that produced the HTTP failure: the transport or
296
- * body-read rejection the provider caught before rethrowing. It is `unknown` because a
297
- * thrown value is unconstrained. Omitted ⇒ the error carries no cause.
298
- */
299
- export declare interface OllamaHTTPErrorOptions {
300
- readonly cause?: unknown;
301
- }
302
-
303
- /**
304
- * Represents the configuration `createOllama` accepts for the local Ollama backend.
305
- *
306
- * @remarks
307
- * Only `model` is required. `url` defaults to the local daemon, `keepAlive` controls
308
- * how long the model stays resident after a call, `timeout` is the per-call deadline
309
- * in milliseconds, and `options` is a passthrough bag of sampling parameters
310
- * (`temperature`, `seed`, and `num_predict`) forwarded verbatim to the wire.
311
- *
312
- * The optional `fetch` + `headers` form a **transport seam**: by default the provider
313
- * talks straight to a local daemon over `globalThis.fetch` with only a JSON content
314
- * type, but a browser-side runtime can inject a custom transport AND a dynamic header
315
- * (for example an obfuscated bearer token) so requests route through the developer's OWN
316
- * server, which validates that header and forwards to the real LLM. Your app never
317
- * holds a real API key — the real key lives only on the developer's server; the
318
- * `headers` hook supplies whatever short-lived/obfuscated token that server expects.
319
- */
320
- export declare interface OllamaOptions {
321
- readonly model: string;
322
- /** Sets the daemon base URL; defaults to `'http://localhost:11434'`. */
323
- readonly url?: string;
324
- /**
325
- * Sets how long the model stays resident after a call; defaults to `'5m'`. Mirrors the
326
- * Ollama `/api/chat` `keep_alive` field, whose value this key carries verbatim onto
327
- * {@link WireChatRequest.keep_alive}.
328
- */
329
- readonly keepAlive?: string | number;
330
- /** Sets the per-call deadline in milliseconds; defaults to `120_000`. */
331
- readonly timeout?: number;
332
- /**
333
- * Carries passthrough sampling parameters (`temperature`, `seed`, and `num_predict`).
334
- * Mirrors the Ollama `/api/chat` `options` field, whose value this key carries verbatim
335
- * onto {@link WireChatRequest.options}.
336
- */
337
- readonly options?: Readonly<Record<string, unknown>>;
338
- /**
339
- * Sets the `/api/chat` `think` wire flag; defaults to `false`. When `true`, a thinking-capable
340
- * model (for example `qwen3`) separates its reasoning NATIVELY at the wire — the daemon returns it
341
- * on the distinct `message.thinking` channel (surfaced on `ProviderResult.thinking`) rather
342
- * than inline in `message.content`. The default is `false`, so a non-thinking model needs no
343
- * configuration and answers immediately; the per-call ThinkSplitter
344
- * remains the defensive fallback for daemons/models that still inline `<think>` tags either
345
- * way. Set it `true` for a thinking model whose reasoning you intend to DISPLAY separately.
346
- */
347
- readonly think?: boolean;
348
- /**
349
- * Sets a custom `fetch` implementation for every request; defaults to
350
- * `globalThis.fetch`. Lets a runtime inject its own transport (a browser fetch
351
- * pointed at the developer's server, an instrumented wrapper) without changing
352
- * the wire protocol. Omitted ⇒ the global `fetch`.
353
- */
354
- readonly fetch?: typeof globalThis.fetch;
355
- /**
356
- * Sets a dynamic, possibly-async header injector called once per request; its returned
357
- * headers are merged into the request on top of the base `Content-Type`. Use it to
358
- * attach an authorization header — for example an obfuscated/generated bearer token the
359
- * developer's server validates before relaying to the real LLM — so a browser
360
- * runtime can authenticate WITHOUT your app ever handling a real API key. Async so a
361
- * token can be refreshed/fetched per call. A returned `Content-Type` overrides the
362
- * default; other headers add to it. Omitted ⇒ only `Content-Type: application/json`.
363
- */
364
- readonly headers?: () => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>;
365
- /**
366
- * Sets the provider's OPTIONAL context-framing default — the PROVIDER-DEFAULT level of
367
- * `AgentContext`'s format cascade (beaten by a manager-options or per-item override,
368
- * beating the managers' built-in framing). Declares how this provider's models prefer
369
- * context sections framed (for example XML group wrappers vs. Markdown headers). Omitted ⇒
370
- * the provider is framing-agnostic and core's built-in defaults apply unchanged. NOTE:
371
- * this is the prompt-CONTEXT framing consumed by `AgentContext.build()` — it is NOT
372
- * Ollama's `/api/chat` `format` wire parameter (structured-output / JSON schema),
373
- * which this provider sends only when a call supplies a `schema`; the two are unrelated
374
- * despite the shared word.
375
- */
376
- readonly format?: ContextFormat;
377
- }
378
-
379
- /**
380
- * Implements the local Ollama inference boundary — a {@link ProviderInterface} over Ollama's
381
- * `POST /api/chat`, both non-streaming (`generate`) and streaming NDJSON (`stream`).
382
- *
383
- * @remarks
384
- * - **Wire protocol.** Posts `{ model, messages, stream, keep_alive, think }` plus
385
- * passthrough sampling `options` and mapped function `tools`. The `think` flag is
386
- * CONFIGURABLE through {@link OllamaOptions.think} (default `false`). Non-stream parses
387
- * one JSON body; stream consumes NDJSON (one JSON object per `\n`-terminated line) —
388
- * deltas carry `message.content`, the final `done: true` line carries the token usage.
389
- * - **Think separation.** The wire `think` flag is configurable
390
- * ({@link OllamaOptions.think}, default `false`). With `think: true` a thinking model's
391
- * daemon separates reasoning NATIVELY — returning it on the distinct `message.thinking`
392
- * channel (read here through `extractThinking`) instead of inline in `message.content`. EITHER
393
- * way the per-call {@link ThinkSplitterInterface} is the defensive guarantee: a daemon
394
- * may ignore `think: false` for a thinking model and inline `<think>` tags, so every
395
- * content delta routes through the splitter, only CLEAN content is yielded / assembled,
396
- * and the separated reasoning (plus any daemon-side `message.thinking` deltas) lands on
397
- * `ProviderResult.thinking`, never in the conversation.
398
- * - **Boundary narrowing.** Every wire value arrives as `unknown` and is
399
- * narrowed through guards (`isRecord` / `isString` / `isNumber`) — never `as`. A
400
- * missing / malformed field degrades to a sensible default (empty content, no
401
- * usage, `{}` arguments), never a throw.
402
- * - **Bounded.** Each call arms a {@link Timeout} for `OllamaOptions.timeout` and
403
- * passes `AbortSignal.any([timeout.signal, signal])` to `fetch`, so the caller's
404
- * signal AND the deadline both cancel the request. The timeout is always cleared —
405
- * in `#fetch` if the request fails/aborts, otherwise in the consuming call's `finally`.
406
- * - **Abort recovers partial.** A `stream` cancelled mid-flight throws a
407
- * `ProviderAbortError` carrying the partial result assembled so far; pairing the
408
- * `TextDecoder({ stream: true })` with the {@link NDJSONParser} parser keeps multi-byte
409
- * UTF-8 splits and partial lines honest.
410
- * - **Event-free.** A pure functional boundary — no Emitter, no events.
411
- * - **Transport seam.** {@link OllamaOptions.fetch} swaps the transport (default
412
- * `globalThis.fetch`) and {@link OllamaOptions.headers} is a per-request, possibly
413
- * async header injector merged over the base `Content-Type` — so a browser runtime
414
- * can route through the developer's own server with an obfuscated bearer token,
415
- * without this library ever handling a real API key. Both omitted ⇒ the global `fetch`
416
- * and only a JSON content type.
417
- * Orthogonal to the deadline: the hook is awaited inside `#fetch`'s try, so a hook
418
- * rejection clears the armed timer like any other request failure.
419
- *
420
- * @example
421
- * ```ts
422
- * const provider = new OllamaProvider({ model: 'qwen3.5:2b-q4_K_M' })
423
- * const result = await provider.generate(messages, abort.signal)
424
- * ```
425
- */
426
- export declare class OllamaProvider implements ProviderInterface {
427
- #private;
428
- readonly name = "ollama";
429
- constructor(options: OllamaOptions);
430
- /**
431
- * Exposes this instance's identity — a fresh `crypto.randomUUID()` minted at
432
- * construction, satisfying the {@link ProviderInterface.id} contract member. A second
433
- * provider built from identical options carries a distinct id.
434
- *
435
- * @returns The instance's minted identifier
436
- */
437
- get id(): string;
438
- /**
439
- * Exposes the provider's context-framing default — the PROVIDER-DEFAULT level of
440
- * {@link import('@orkestrel/agent').AgentContextInterface.build}'s format cascade (it BEATS
441
- * the managers' built-in framing, is BEATEN by a manager-options or per-item override).
442
- * Satisfies the OPTIONAL {@link ProviderInterface.format} contract member: `undefined`
443
- * when {@link OllamaOptions.format} was omitted (the framing-agnostic default ⇒ core's
444
- * built-in framing applies unchanged), else the exact configured framing the Agent
445
- * threads into `build()`.
446
- *
447
- * @remarks
448
- * EXPOSE-ONLY — read by the Agent loop and consumed by core's cascade; it is NEVER sent
449
- * on the `/api/chat` wire (it is absent from `#body` / the request). This is NOT Ollama's
450
- * structured-output `format` wire parameter — that one IS sent in `#body`, but only when
451
- * a per-call `ProviderStreamOptions.schema` is supplied; only the word collides.
452
- *
453
- * @returns The configured {@link ContextFormat}, or `undefined` when none
454
- */
455
- get format(): ContextFormat | undefined;
456
- generate(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): Promise<ProviderResult>;
457
- stream(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): AsyncGenerator<ProviderDelta, ProviderResult>;
458
- }
459
-
460
- /**
461
- * Represents an open `POST /api/chat` response together with the deadline and the
462
- * combined signal that bound the request.
463
- *
464
- * @remarks
465
- * The `response` is the open `POST /api/chat` `Response`; `timeout` is the armed
466
- * {@link TimeoutInterface} the consuming call clears once it finishes reading the body
467
- * (or that the provider clears on a failed or aborted request); `combined` is the
468
- * `AbortSignal.any([timeout.signal, callerSignal])` the request was issued under, which
469
- * the streaming path checks to tell a mid-stream cancel apart from any other error.
470
- */
471
- export declare interface OllamaResponse {
472
- readonly response: Response;
473
- readonly timeout: TimeoutInterface;
474
- readonly combined: AbortSignal;
475
- }
476
-
477
- /**
478
- * Parses a non-stream `/api/chat` response body into a wire record.
479
- *
480
- * @remarks
481
- * Total by construction: an empty body, a body that is not JSON, and a body whose JSON is
482
- * not an object all yield `undefined`, so a malformed daemon response never escapes as a
483
- * `SyntaxError`. The call site supplies the empty-record default that reads as empty
484
- * content and no usage.
485
- *
486
- * @param response - The 200-OK `/api/chat` response whose body is read as text
487
- * @returns The parsed record, or `undefined` when the body is empty or malformed
488
- *
489
- * @example
490
- * ```ts
491
- * await parseBody(new Response('{"message":{"content":"ok"}}'))
492
- * // { message: { content: 'ok' } }
493
- * ```
494
- */
495
- export declare function parseBody(response: Response): Promise<Readonly<Record<string, unknown>> | undefined>;
496
-
497
- /**
498
- * Represents the exact `POST /api/chat` request body `OllamaProvider` sends — the internal typed
499
- * wire contract.
500
- *
501
- * @remarks
502
- * This is the typed wire shape asserted against the official `ollama` client's
503
- * `ChatRequest` by the compile-time parity test; `src/` never imports `ollama` itself.
504
- * `messages` mirrors the minimal turn shape `mapMessages` builds (`role` / `content`, plus
505
- * `tool_calls` only on a turn that replays them and `images` only on a multimodal
506
- * turn); `options` and `tools` are only present when configured.
507
- */
508
- export declare interface WireChatRequest {
509
- readonly model: string;
510
- readonly messages: ReadonlyArray<{
511
- readonly role: string;
512
- readonly content: string;
513
- readonly tool_calls?: ReadonlyArray<{
514
- readonly function: {
515
- readonly name: string;
516
- readonly arguments: Readonly<Record<string, unknown>>;
517
- };
518
- }>;
519
- readonly images?: readonly string[];
520
- }>;
521
- readonly stream: boolean;
522
- readonly keep_alive: string | number;
523
- readonly think: boolean;
524
- readonly options?: Readonly<Record<string, unknown>>;
525
- readonly tools?: ReadonlyArray<{
526
- readonly type: 'function';
527
- readonly function: {
528
- readonly name: string;
529
- readonly description?: string;
530
- readonly parameters?: Readonly<Record<string, unknown>>;
531
- };
532
- }>;
533
- /**
534
- * Holds the `/api/chat` structured-output constraint — a JSON-Schema object forwarded
535
- * verbatim from the per-call `ProviderStreamOptions.schema`. This is NOT
536
- * `OllamaOptions.format` (the unrelated prompt-context framing); only present
537
- * when a call supplies a `schema`.
538
- */
539
- readonly format?: Readonly<Record<string, unknown>>;
540
- }
541
-
542
- export { }