@orkestrel/agent 0.0.20 → 0.0.22
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/README.md +16 -13
- package/dist/src/core/index.cjs +1357 -352
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1715 -739
- package/dist/src/core/index.d.ts +1715 -739
- package/dist/src/core/index.js +1332 -355
- package/dist/src/core/index.js.map +1 -1
- package/package.json +24 -23
|
@@ -1,29 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { ArrayShape } from '@orkestrel/contract';
|
|
2
|
+
import { BooleanShape } from '@orkestrel/contract';
|
|
3
|
+
import type { BudgetInterface } from '@orkestrel/budget';
|
|
4
|
+
import { ContractInterface } from '@orkestrel/contract';
|
|
5
|
+
import type { ContractShape } from '@orkestrel/contract';
|
|
6
|
+
import type { ControllerInterface } from '@orkestrel/workflow';
|
|
7
|
+
import type { DriverInterface } from '@orkestrel/database';
|
|
8
|
+
import type { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
9
|
+
import type { EmitterHooks } from '@orkestrel/emitter';
|
|
10
|
+
import type { EmitterInterface } from '@orkestrel/emitter';
|
|
11
|
+
import type { FileInterface } from '@orkestrel/workspace';
|
|
12
|
+
import { JSONShape } from '@orkestrel/contract';
|
|
8
13
|
import { JSONValue } from '@orkestrel/contract';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
14
|
+
import { LiteralShape } from '@orkestrel/contract';
|
|
15
|
+
import { NumberShape } from '@orkestrel/contract';
|
|
16
|
+
import { ObjectShape } from '@orkestrel/contract';
|
|
17
|
+
import { OptionalShape } from '@orkestrel/contract';
|
|
18
|
+
import type { QueueContext } from '@orkestrel/queue';
|
|
19
|
+
import type { QueueInterface } from '@orkestrel/queue';
|
|
20
|
+
import type { QueueStoreInterface } from '@orkestrel/queue';
|
|
21
|
+
import type { RunnerInterface } from '@orkestrel/workflow';
|
|
22
|
+
import type { SchedulerInterface } from '@orkestrel/workflow';
|
|
23
|
+
import { StringShape } from '@orkestrel/contract';
|
|
24
|
+
import type { TableInterface } from '@orkestrel/database';
|
|
25
|
+
import type { TokenUsage } from '@orkestrel/budget';
|
|
26
|
+
import type { ToolCall } from '@orkestrel/tool';
|
|
27
|
+
import type { ToolDefinition } from '@orkestrel/tool';
|
|
28
|
+
import type { ToolInterface } from '@orkestrel/tool';
|
|
29
|
+
import type { ToolManagerInterface } from '@orkestrel/tool';
|
|
30
|
+
import type { ToolResult } from '@orkestrel/tool';
|
|
31
|
+
import { UnionShape } from '@orkestrel/contract';
|
|
32
|
+
import type { WorkspaceManagerInterface } from '@orkestrel/workspace';
|
|
22
33
|
|
|
23
34
|
/**
|
|
24
35
|
* Composes a {@link ProviderInterface}, an {@link AgentContext}, and a
|
|
25
|
-
* {@link ToolManagerInterface} into a bounded context → provider → tools → repeat
|
|
26
|
-
*
|
|
36
|
+
* {@link ToolManagerInterface} into a bounded context → provider → tools → repeat turn, exposed
|
|
37
|
+
* as both a one-shot `generate` and a live `stream` that share one private run — bounded by the
|
|
38
|
+
* run `signal`, the `timeout`, and the `budget` folded through `AbortSignal.any`, paced by
|
|
39
|
+
* `scheduler`, with tool iteration capped at `limit`.
|
|
27
40
|
*
|
|
28
41
|
* @remarks
|
|
29
42
|
* - **One loop, two faces.** A single private async generator (`#run`) drives the
|
|
@@ -40,15 +53,15 @@ import { WorkspaceManagerInterface } from '@orkestrel/workspace';
|
|
|
40
53
|
* assistant message and stop.
|
|
41
54
|
* - **Bounded.** Each run arms one cancel through `createAbort({ signal: AbortSignal.any([
|
|
42
55
|
* …]) })` folding the external `signal`, the `timeout` deadline, and the `budget`
|
|
43
|
-
* signal; `abort()` fires it. Any trip stops the loop and commits a
|
|
44
|
-
* (the `result` promise
|
|
56
|
+
* signal; `abort()` fires it. Any trip stops the loop and commits a partial result
|
|
57
|
+
* (the `result` promise resolves, never rejects, on a cancel) — only a genuine
|
|
45
58
|
* provider / tool error rejects.
|
|
46
59
|
* - **Paced + capped.** The `scheduler` (when given) `yield`s between turns; tool
|
|
47
60
|
* iteration is capped at `limit`.
|
|
48
|
-
* - **Two observation surfaces.** The
|
|
49
|
-
* deltas (+ usage/tool chunks); the
|
|
61
|
+
* - **Two observation surfaces.** The pull {@link AgentChunk} stream carries per-token
|
|
62
|
+
* deltas (+ usage/tool chunks); the push {@link emitter} ({@link AgentEventMap}) carries
|
|
50
63
|
* lifecycle + usage/tool/deny moments for fire-and-forget observers. Every event is
|
|
51
|
-
* emitted directly,
|
|
64
|
+
* emitted directly, after the relevant state transition / settle; the emitter isolates a
|
|
52
65
|
* listener throw and routes it to its `error` handler (the `error` option), so a buggy
|
|
53
66
|
* observer can never escape into / reorder / corrupt the settle-once loop — observation is
|
|
54
67
|
* purely a side-channel.
|
|
@@ -74,15 +87,15 @@ export declare class Agent implements AgentInterface {
|
|
|
74
87
|
|
|
75
88
|
/**
|
|
76
89
|
* Represents a streamed step of an agent turn — the union the loop yields as it runs, discriminated
|
|
77
|
-
* by the `category` of step it carries.
|
|
90
|
+
* by the `category` of step it carries, and the pull surface beside the push {@link AgentEventMap}.
|
|
78
91
|
*
|
|
79
92
|
* @remarks
|
|
80
93
|
* - `token` — a content delta the provider streamed (the `'content'`
|
|
81
94
|
* {@link ProviderDelta}s a {@link ProviderInterface}'s `stream` yields), re-surfaced for
|
|
82
|
-
* live rendering of the assistant
|
|
95
|
+
* live rendering of the assistant answer.
|
|
83
96
|
* - `think` — a reasoning delta the provider streamed (the `'thinking'`
|
|
84
97
|
* {@link ProviderDelta}s, the daemon's native `message.thinking` channel), surfaced so a
|
|
85
|
-
* consumer can stream the model's reasoning
|
|
98
|
+
* consumer can stream the model's reasoning live into a collapsible; never answer content
|
|
86
99
|
* (it is never fed into the accumulated `content`).
|
|
87
100
|
* - `tool` — a {@link ToolCall} the loop dispatched paired with its {@link ToolResult},
|
|
88
101
|
* emitted once the tool ran (so a consumer sees what was called and what came back).
|
|
@@ -107,58 +120,59 @@ export declare type AgentChunk = {
|
|
|
107
120
|
/**
|
|
108
121
|
* Assembles a provider request from the richer turn context — the optional system prompt, the
|
|
109
122
|
* observable context managers (instructions / workspaces), the
|
|
110
|
-
* {@link ConversationManagerInterface} message source
|
|
111
|
-
*
|
|
112
|
-
* {@link AgentContextInterface.apply}.
|
|
123
|
+
* {@link ConversationManagerInterface} message source whose active conversation is `messages`, the
|
|
124
|
+
* {@link ToolManagerInterface} registry, and an active {@link ScopeInterface} changed through
|
|
125
|
+
* {@link AgentContextInterface.apply}. `build()` folds the scoped managers and the active
|
|
126
|
+
* workspace into one system block, then the conversation, and never reads `tools`.
|
|
113
127
|
*
|
|
114
128
|
* @remarks
|
|
115
129
|
* - **Composition.** `system` is the optional system prompt; `instructions` / `tools` /
|
|
116
130
|
* `workspaces` / `conversations` are the registries passed in `options` (bring your own), or
|
|
117
|
-
* fresh empty ones when omitted (so `workspaces` is
|
|
118
|
-
* conversation's live tail (
|
|
131
|
+
* fresh empty ones when omitted (so `workspaces` is always present); `messages` is the active
|
|
132
|
+
* conversation's live tail (always defined — see the following item). `scope` is the active filter —
|
|
119
133
|
* `undefined` (the default) ⇒ no filtering; change it through `apply(scope)`. The structural
|
|
120
134
|
* `workspaces` / `conversations` registries are fixed at construction; switch their active
|
|
121
135
|
* members through their own `switch(id)` methods.
|
|
122
|
-
* - **The message source — the conversation registry's
|
|
123
|
-
* {@link ConversationManagerInterface}; the context
|
|
124
|
-
* (at construction it `add`s a default when the manager has none), so the
|
|
125
|
-
* getter — `this.#conversations.active` — is
|
|
126
|
-
* conversation
|
|
136
|
+
* - **The message source — the conversation registry's active conversation.** `conversations` is a
|
|
137
|
+
* {@link ConversationManagerInterface}; the context ensures it always has an active conversation
|
|
138
|
+
* (at construction it `add`s a default when the manager has none), so the dynamic `messages`
|
|
139
|
+
* getter — `this.#conversations.active` — is always defined. `messages` returns the active
|
|
140
|
+
* conversation itself (it owns the live tail + the message verbs directly, satisfying
|
|
127
141
|
* {@link MessageManagerInterface} structurally — the same reference, no duplication), and
|
|
128
142
|
* `build()` folds that conversation's `view()` (its per-section summaries + live tail) as the
|
|
129
|
-
*
|
|
143
|
+
* authoritative message inclusion — the scope does not filter the conversation (it owns inclusion
|
|
130
144
|
* through compaction; scope filters only instructions / tools / workspace files). Because `messages`
|
|
131
|
-
* is read dynamically, an agent
|
|
132
|
-
* conversation
|
|
145
|
+
* is read dynamically, an agent switches the active
|
|
146
|
+
* conversation between runs (`conversations.switch(id)`) to serve many threads (the real
|
|
133
147
|
* multi-conversation pattern); switch between runs, not during a run, and use separate agents
|
|
134
148
|
* for concurrent threads.
|
|
135
149
|
* - **`build(format?)` — the scoped assembly + the format cascade.** It folds, in order,
|
|
136
|
-
* the system prompt then the scope-filtered instructions → the
|
|
150
|
+
* the system prompt then the scope-filtered instructions → the active workspace's text files
|
|
137
151
|
* (each as a block: the section's resolved `open` text, each item's resolved rendering, then
|
|
138
|
-
* any resolved `close` text) into
|
|
139
|
-
* one part exists), then appends the
|
|
140
|
-
* message inclusion through compaction — the scope does
|
|
152
|
+
* any resolved `close` text) into one leading `system` message (prepended only when at least
|
|
153
|
+
* one part exists), then appends the active conversation's `view()` (the conversation owns
|
|
154
|
+
* message inclusion through compaction — the scope does not filter the conversation). Each
|
|
141
155
|
* `open` / item / `close`
|
|
142
|
-
* resolves
|
|
143
|
-
* per-section default) is the
|
|
156
|
+
* resolves independently, most-specific-first — `build()`'s optional `format` (a provider's
|
|
157
|
+
* per-section default) is the provider level: `open` = manager-options-override > provider >
|
|
144
158
|
* built-in; per item = item-override > manager-options-override > provider > built-in; `close` =
|
|
145
|
-
* manager-options-override > provider (
|
|
146
|
-
* {@link AgentContextInterface.build}). Passing
|
|
159
|
+
* manager-options-override > provider (no built-in ⇒ no closing line when unset) (see
|
|
160
|
+
* {@link AgentContextInterface.build}). Passing no `format` (and with no overrides / no per-item
|
|
147
161
|
* override) reproduces the built-in framing byte-for-byte (each section is its built-in header +
|
|
148
162
|
* items, no closing line). The active workspace's scoped-in image files' `base64` payload is attached to
|
|
149
|
-
* the
|
|
163
|
+
* the last user message (a vision provider reads images off a user turn); when no user message
|
|
150
164
|
* exists the attachment is skipped. Built fresh each call (recomputed, never cached), so it
|
|
151
165
|
* always reflects the current managers / messages / scope / active workspace; it never mutates a
|
|
152
166
|
* manager or the stored messages.
|
|
153
|
-
* - **The
|
|
167
|
+
* - **The active workspace, rendered by carrier — the sole document/image context.**
|
|
154
168
|
* `workspaces.active` (when set) has its {@link import('@orkestrel/workspace').FileInterface}s scope-filtered by `scope.files`,
|
|
155
|
-
* then split:
|
|
156
|
-
* blocks — placed right after the instructions section), and
|
|
157
|
-
* to the last user message.
|
|
158
|
-
* workspace nothing renders for workspaces. `build()`
|
|
169
|
+
* then split: text files fold into a dedicated `## Workspace` system section (fenced reference
|
|
170
|
+
* blocks — placed right after the instructions section), and image files' `base64` payload attaches
|
|
171
|
+
* to the last user message. Active-only — never the other registered workspaces; with no active
|
|
172
|
+
* workspace nothing renders for workspaces. `build()` owns this render (a `Workspace` /
|
|
159
173
|
* `WorkspaceManager` stays file-focused).
|
|
160
174
|
* - **Tools are structural, not in the prompt.** The registry is advertised to the provider
|
|
161
|
-
* through `tools.definitions()` (scope-filtered by the loop),
|
|
175
|
+
* through `tools.definitions()` (scope-filtered by the loop), never serialized into the
|
|
162
176
|
* message array — so `build()`'s output carries no tool content, scoped or not.
|
|
163
177
|
* - **Event-free context; observable managers.** The context itself owns no Emitter; the
|
|
164
178
|
* context managers each carry their own (the push observation surface).
|
|
@@ -194,12 +208,12 @@ export declare class AgentContext implements AgentContextInterface {
|
|
|
194
208
|
* (`instructions` / `workspaces` / `conversations`), `messages` (the active
|
|
195
209
|
* conversation's live tail, satisfying {@link MessageManagerInterface}), and the current `scope`
|
|
196
210
|
* (the active {@link ScopeInterface} filter, or `undefined` for no filtering). `build()` folds the
|
|
197
|
-
* scoped instructions into
|
|
198
|
-
* each item through its `render`) —
|
|
199
|
-
* (rendered as fenced reference blocks) — and appends the
|
|
200
|
-
* the active workspace's scope-filtered image files' `base64` payload to the
|
|
201
|
-
* active workspace is the
|
|
202
|
-
*
|
|
211
|
+
* scoped instructions into one leading `system` message (under the manager's `open`,
|
|
212
|
+
* each item through its `render`) — plus the active workspace's scope-filtered text files
|
|
213
|
+
* (rendered as fenced reference blocks) — and appends the active conversation's `view()`, attaching
|
|
214
|
+
* the active workspace's scope-filtered image files' `base64` payload to the last user message. The
|
|
215
|
+
* active workspace is the sole document/image context. Tools are advertised to the provider
|
|
216
|
+
* structurally (through `tools.definitions()`, scope-filtered by the loop), not serialized into
|
|
203
217
|
* the prompt, so they never appear in `build()`'s output. The context managers are observable
|
|
204
218
|
* (their own `emitter`s); the context itself is event-free.
|
|
205
219
|
*/
|
|
@@ -207,32 +221,32 @@ export declare interface AgentContextInterface {
|
|
|
207
221
|
readonly system: string | undefined;
|
|
208
222
|
readonly instructions: InstructionManagerInterface;
|
|
209
223
|
/**
|
|
210
|
-
* Holds the {@link WorkspaceManagerInterface} whose
|
|
224
|
+
* Holds the {@link WorkspaceManagerInterface} whose active workspace `build()` renders by carrier —
|
|
211
225
|
* its text files folded into the system block (fenced reference blocks) and its image files'
|
|
212
|
-
* `base64` payload attached to the
|
|
213
|
-
* document/image context.
|
|
214
|
-
* `build()` reads its `active` (and the active workspace's `files()`)
|
|
226
|
+
* `base64` payload attached to the last user message. The active workspace is the sole
|
|
227
|
+
* document/image context. Always present (a fresh empty manager when none was supplied).
|
|
228
|
+
* `build()` reads its `active` (and the active workspace's `files()`) fresh each call. With no
|
|
215
229
|
* active workspace, nothing is rendered for workspaces. Active-only — never the other registered
|
|
216
230
|
* workspaces.
|
|
217
231
|
*/
|
|
218
232
|
readonly workspaces: WorkspaceManagerInterface;
|
|
219
233
|
/**
|
|
220
|
-
* Holds the active conversation's
|
|
234
|
+
* Holds the active conversation's live tail — the agent's message source, always defined (the
|
|
221
235
|
* {@link conversations} registry always has an active conversation; a default is added at
|
|
222
|
-
* construction). It
|
|
236
|
+
* construction). It is the active {@link ConversationInterface} itself (which satisfies
|
|
223
237
|
* {@link MessageManagerInterface} structurally), so appends through `messages` route to the
|
|
224
238
|
* active conversation's tail and `build()` folds its `view()`. Computed dynamically (it follows
|
|
225
|
-
* `conversations.switch(id)`), the
|
|
239
|
+
* `conversations.switch(id)`), the same reference the active conversation exposes — no
|
|
226
240
|
* duplication.
|
|
227
241
|
*/
|
|
228
242
|
readonly messages: MessageManagerInterface;
|
|
229
243
|
/**
|
|
230
|
-
* Holds the {@link ConversationManagerInterface} the message source flows from — `messages`
|
|
231
|
-
*
|
|
244
|
+
* Holds the {@link ConversationManagerInterface} the message source flows from — `messages` is its
|
|
245
|
+
* active conversation's live tail and `build()` folds that conversation's `view()`. Always holds
|
|
232
246
|
* an active conversation (a default is added at construction when none was supplied), so
|
|
233
247
|
* `messages` is always defined. Switch the active conversation through
|
|
234
|
-
* `conversations.switch(id)` — so one agent can serve
|
|
235
|
-
* request). Switch
|
|
248
|
+
* `conversations.switch(id)` — so one agent can serve many conversations (set the active one per
|
|
249
|
+
* request). Switch between runs, not during one; for concurrent threads use separate agents.
|
|
236
250
|
*/
|
|
237
251
|
readonly conversations: ConversationManagerInterface;
|
|
238
252
|
/**
|
|
@@ -243,7 +257,8 @@ export declare interface AgentContextInterface {
|
|
|
243
257
|
/** Holds the active scope applied at `build()` time + the loop's tool-advertise step (`undefined` ⇒ no filtering). */
|
|
244
258
|
readonly scope: ScopeInterface | undefined;
|
|
245
259
|
/**
|
|
246
|
-
* Applies the active per-turn
|
|
260
|
+
* Applies the given scope as the active per-turn filter; passing `undefined` explicitly
|
|
261
|
+
* removes filtering.
|
|
247
262
|
*
|
|
248
263
|
* @param scope - The scope to apply, or `undefined` to remove the active filter
|
|
249
264
|
*
|
|
@@ -255,51 +270,57 @@ export declare interface AgentContextInterface {
|
|
|
255
270
|
*/
|
|
256
271
|
apply(scope: ScopeInterface | undefined): void;
|
|
257
272
|
/**
|
|
258
|
-
* Builds the provider input for the next turn: a leading `system` message folding the
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
273
|
+
* Builds the provider input for the next turn: a leading `system` message folding the
|
|
274
|
+
* prompt, the scope-filtered instructions (each section's header and each item's rendering
|
|
275
|
+
* resolved through the format cascade), and the active workspace's scope-filtered
|
|
276
|
+
* (`scope.files`) text files as fenced reference blocks in a `## Workspace` section, then
|
|
277
|
+
* the active conversation's `view()`, with the active workspace's image files' `base64`
|
|
278
|
+
* payload attached to the last user message. Takes an optional `format` — typically
|
|
279
|
+
* `provider.format`, the provider level of the cascade — and omitting it with no overrides
|
|
280
|
+
* set renders each section on its manager's built-in framing. The `system` message is
|
|
281
|
+
* prepended only when some part of it exists, the workspace render covers the active
|
|
282
|
+
* workspace alone, tools are advertised structurally rather than in the prompt, and the
|
|
283
|
+
* input is built fresh on each call.
|
|
263
284
|
*
|
|
264
285
|
* @remarks
|
|
265
|
-
* **The active workspace (rendered by carrier) — the
|
|
286
|
+
* **The active workspace (rendered by carrier) — the sole document/image context.** When
|
|
266
287
|
* `workspaces.active` is set, its
|
|
267
288
|
* {@link import('@orkestrel/workspace').WorkspaceInterface.files} are filtered by
|
|
268
289
|
* `scope.files` (a three-way allow-list; `undefined` ⇒ all active files), then split by
|
|
269
|
-
* carrier:
|
|
290
|
+
* carrier: text files ({@link import('@orkestrel/workspace').isText}) render into a dedicated
|
|
270
291
|
* `## Workspace` section in the system block — each a fenced
|
|
271
292
|
* `` File: <path>\n```<language>\n<text>\n``` `` block — placed immediately after the instructions
|
|
272
293
|
* section; binary files whose MIME starts with `image/` have their `base64` payload
|
|
273
|
-
* attached to the
|
|
274
|
-
*
|
|
294
|
+
* attached to the last user message (a vision provider reads images off a user turn).
|
|
295
|
+
* Active-only — never the other registered workspaces; with no active workspace nothing is
|
|
275
296
|
* rendered for workspaces.
|
|
276
297
|
*
|
|
277
298
|
* **The format cascade.** Each manager section frames as `[open, ...items.map(render), close]`
|
|
278
299
|
* (empty / absent slots dropped, the survivors `\n\n`-joined). The `open` (the section's
|
|
279
300
|
* leading text), each item's `render`, and the `close` (the section's trailing text)
|
|
280
|
-
* resolve
|
|
301
|
+
* resolve independently, most-specific-first, from a {@link ContextSectionFormat} at each
|
|
281
302
|
* level — an item override, a manager-options override, the provider `format` default,
|
|
282
303
|
* and the manager's built-in. For the `instructions` section kind `K`, manager
|
|
283
304
|
* `M`, and the supplied `format` `F`:
|
|
284
305
|
* - **open** = `M.format?.open ?? F?.[K]?.open ?? M.open` — that is,
|
|
285
306
|
* **manager-options override > provider default > built-in** (the leading text has no
|
|
286
|
-
* per-item level). The manager
|
|
307
|
+
* per-item level). The manager encapsulates the `[options-override → built-in]` half:
|
|
287
308
|
* `M.open` already returns the options override's `open` when one is set, else
|
|
288
|
-
* the built-in header — so `build()` only layers the provider default
|
|
309
|
+
* the built-in header — so `build()` only layers the provider default between them.
|
|
289
310
|
* - **item** `I` = `I.override ?? M.format?.render?.(I) ?? F?.[K]?.render?.(I) ?? M.render(I)`
|
|
290
311
|
* — that is, **item override > manager-options override > provider default > built-in**.
|
|
291
312
|
* Again `M.render(I)` already returns the options override when set, else the
|
|
292
|
-
* built-in, so `build()` layers the per-item `I.override`
|
|
293
|
-
* default
|
|
313
|
+
* built-in, so `build()` layers the per-item `I.override` on top and the provider
|
|
314
|
+
* default between.
|
|
294
315
|
* - **close** = `M.format?.close ?? F?.[K]?.close` — that is, **manager-options
|
|
295
|
-
* override > provider default**, with
|
|
316
|
+
* override > provider default**, with no built-in floor (the trailing text has no
|
|
296
317
|
* per-item level): unset at both levels ⇒ `undefined` ⇒ no closing line. Paired with
|
|
297
|
-
* `open`, it lets a level
|
|
318
|
+
* `open`, it lets a level wrap the group (`open: '<instructions>'` … `close: '</instructions>'`).
|
|
298
319
|
*
|
|
299
|
-
* Passing
|
|
300
|
-
* output is
|
|
320
|
+
* Passing no `format` (the default) leaves the provider-default level empty, so the
|
|
321
|
+
* output is byte-for-byte the managers' built-in framing — every section is its
|
|
301
322
|
* built-in header + items, with no closing line (the regression contract). Scope
|
|
302
|
-
* filtering runs
|
|
323
|
+
* filtering runs before formatting (unchanged); the workspace image-data attachment to the
|
|
303
324
|
* last user message is unchanged.
|
|
304
325
|
*
|
|
305
326
|
* @param format - The provider's optional {@link ContextFormat} default
|
|
@@ -312,7 +333,10 @@ export declare interface AgentContextInterface {
|
|
|
312
333
|
}
|
|
313
334
|
|
|
314
335
|
/**
|
|
315
|
-
* Configures `createAgentContext` — the
|
|
336
|
+
* Configures `createAgentContext` — the optional system prompt plus the pre-built managers to
|
|
337
|
+
* reuse: an `instructions` registry, a `workspaces` registry (the only document channel), a
|
|
338
|
+
* `conversations` registry (the message source), a `tools` registry (the loop's advertise and
|
|
339
|
+
* dispatch surface), and an initial `scope`.
|
|
316
340
|
*
|
|
317
341
|
* @remarks
|
|
318
342
|
* `system` is the optional system prompt prepended to the turn's input. `instructions` /
|
|
@@ -322,10 +346,10 @@ export declare interface AgentContextInterface {
|
|
|
322
346
|
* initial active filter applied at `build()` time (and at the loop's tool-advertise step); it
|
|
323
347
|
* defaults to `undefined` — no filtering — and can be changed through the context's `apply`
|
|
324
348
|
* method afterwards. `conversations` is the structural {@link ConversationManagerInterface} the
|
|
325
|
-
* context's message source flows from: `messages`
|
|
349
|
+
* context's message source flows from: `messages` is the manager's active conversation's live tail
|
|
326
350
|
* and `build()` folds that conversation's `view()` (section summaries + live). When omitted, a fresh
|
|
327
351
|
* {@link ConversationManagerInterface} is created and a default conversation is added (so
|
|
328
|
-
* `messages` is
|
|
352
|
+
* `messages` is always defined). All default to a context with no system prompt, empty registries,
|
|
329
353
|
* no scope, and a fresh conversation registry holding one default conversation.
|
|
330
354
|
*/
|
|
331
355
|
export declare interface AgentContextOptions {
|
|
@@ -339,21 +363,21 @@ export declare interface AgentContextOptions {
|
|
|
339
363
|
readonly instructions?: InstructionManagerInterface;
|
|
340
364
|
/**
|
|
341
365
|
* Reuses a pre-built {@link WorkspaceManagerInterface}; a fresh empty one is created when
|
|
342
|
-
* omitted (so `context.workspaces` is
|
|
366
|
+
* omitted (so `context.workspaces` is always present). `build()` renders the active workspace's
|
|
343
367
|
* files by carrier — text files into the system block (fenced), image files attached to the last
|
|
344
368
|
* user message. The registry is structural; change its active workspace through
|
|
345
|
-
* `workspaces.switch(id)`. The active workspace is the
|
|
369
|
+
* `workspaces.switch(id)`. The active workspace is the sole document/image context.
|
|
346
370
|
*/
|
|
347
371
|
readonly workspaces?: WorkspaceManagerInterface;
|
|
348
372
|
/** Sets the initial active scope (the build-time filter); `undefined` ⇒ no filtering. */
|
|
349
373
|
readonly scope?: ScopeInterface;
|
|
350
374
|
/**
|
|
351
375
|
* Reuses a pre-built {@link ConversationManagerInterface} as the message source; a fresh
|
|
352
|
-
* empty one is created when omitted. The context
|
|
353
|
-
* (it `add`s a default when the manager has none), so `messages` — the manager's
|
|
354
|
-
* conversation's
|
|
355
|
-
* `view()` (the per-section summaries + the live tail) as its
|
|
356
|
-
* the scope does
|
|
376
|
+
* empty one is created when omitted. The context ensures an active conversation at construction
|
|
377
|
+
* (it `add`s a default when the manager has none), so `messages` — the manager's active
|
|
378
|
+
* conversation's live tail — is always defined. `build()` folds the active conversation's
|
|
379
|
+
* `view()` (the per-section summaries + the live tail) as its authoritative message inclusion —
|
|
380
|
+
* the scope does not filter the conversation (it owns inclusion through compaction; scope filters
|
|
357
381
|
* only instructions / tools / workspace files). The registry is structural; change its active
|
|
358
382
|
* conversation through the manager's `switch(id)`.
|
|
359
383
|
*/
|
|
@@ -361,13 +385,16 @@ export declare interface AgentContextOptions {
|
|
|
361
385
|
}
|
|
362
386
|
|
|
363
387
|
/**
|
|
364
|
-
* Reports a concurrent run that would corrupt
|
|
388
|
+
* Reports a concurrent run that would corrupt shared per-agent accounting, or a rehydration
|
|
365
389
|
* name absent from its registry pool — thrown synchronously by an {@link AgentInterface}'s
|
|
366
|
-
* `stream()` and by
|
|
367
|
-
* `code
|
|
390
|
+
* `stream()` (and so by `generate()`, which calls it) and by an
|
|
391
|
+
* {@link AgentRegistryInterface}'s accessors, carrying the machine-readable `code`
|
|
392
|
+
* `'CONCURRENCY' | 'REGISTRY'`. Synchronous means a fire-and-forget
|
|
393
|
+
* `agent.generate().catch(…)` never catches it: `await` the call inside `try`/`catch`, or wrap
|
|
394
|
+
* the call expression itself.
|
|
368
395
|
*
|
|
369
396
|
* @remarks
|
|
370
|
-
* `'CONCURRENCY'` reports a run already in flight on the same agent,
|
|
397
|
+
* `'CONCURRENCY'` reports a run already in flight on the same agent, plus a construction-level
|
|
371
398
|
* `window` (a shared context budget) or a construction-level `budget` with no per-run override
|
|
372
399
|
* (a shared cost budget) — a second concurrent `stream()` would race its charges against the
|
|
373
400
|
* same shared instance, corrupting the accounting. Use separate agents, or per-run `budget`
|
|
@@ -382,26 +409,26 @@ export declare class AgentError extends Error {
|
|
|
382
409
|
}
|
|
383
410
|
|
|
384
411
|
/**
|
|
385
|
-
* Maps the push observation surface of an {@link AgentInterface} — the
|
|
386
|
-
*
|
|
387
|
-
*
|
|
412
|
+
* Maps the push observation surface of an {@link AgentInterface} — the lifecycle, usage, and tool
|
|
413
|
+
* moments a fire-and-forget observer (logging, metrics, tracing) subscribes to, beside the pull
|
|
414
|
+
* {@link AgentChunk} stream.
|
|
388
415
|
*
|
|
389
416
|
* @remarks
|
|
390
|
-
* Push vs. pull: the Emitter carries the loop's
|
|
417
|
+
* Push vs. pull: the Emitter carries the loop's lifecycle moments (a run begins /
|
|
391
418
|
* each turn / a settle / a cancel) plus usage and dispatched-tool events — the things
|
|
392
419
|
* the chunk stream can't express (a `deny` never reaches the stream) or that a
|
|
393
|
-
* fire-and-forget observer wants without draining the stream.
|
|
394
|
-
*
|
|
395
|
-
* deliberately
|
|
420
|
+
* fire-and-forget observer wants without draining the stream. Per-token deltas stay
|
|
421
|
+
* exclusively the {@link AgentChunk} stream's job (the pull surface) — there is
|
|
422
|
+
* deliberately no `token` event here. Subscribe through `agent.emitter.on(...)`.
|
|
396
423
|
*
|
|
397
424
|
* Observation is side-effect-free on the loop: listener isolation is the emitter's
|
|
398
|
-
* — every event is emitted directly and a listener throw is routed to the emitter's
|
|
425
|
+
* — every event is emitted directly and a listener throw is routed to the emitter's own
|
|
399
426
|
* `error` handler (the `error` option), never onto this domain map and never into the
|
|
400
427
|
* settle-once / wake-park engine — so a buggy observer can never reorder, throw into, or
|
|
401
428
|
* corrupt the run.
|
|
402
429
|
*
|
|
403
|
-
* A cancelled run emits `abort` (the cancel signal)
|
|
404
|
-
*
|
|
430
|
+
* A cancelled run emits `abort` (the cancel signal) and then `finish` (the settled
|
|
431
|
+
* partial result) — so an observer sees both that the run was cancelled and the partial
|
|
405
432
|
* outcome it committed; a genuine error emits `error` instead of `finish`.
|
|
406
433
|
*
|
|
407
434
|
* Declared as a `type` alias (not `interface extends EventMap` — `EventMap` is a
|
|
@@ -418,9 +445,9 @@ export declare type AgentEventMap = {
|
|
|
418
445
|
readonly tool: readonly [call: ToolCall, result: ToolResult];
|
|
419
446
|
/** Reports a turn's {@link TokenUsage} — emitted after a usage-bearing provider call. */
|
|
420
447
|
readonly usage: readonly [usage: TokenUsage];
|
|
421
|
-
/** Reports a call the authority
|
|
448
|
+
/** Reports a call the authority denied — the call + the optional reason (not in the chunk stream). */
|
|
422
449
|
readonly deny: readonly [call: ToolCall, reason: string | undefined];
|
|
423
|
-
/** Reports the run settled successfully (a natural finish
|
|
450
|
+
/** Reports the run settled successfully (a natural finish or a cancel's partial) — the {@link AgentResult}. */
|
|
424
451
|
readonly finish: readonly [result: AgentResult];
|
|
425
452
|
/** Reports the run settled with a genuine (non-cancel) error — the thrown value (always `unknown`). */
|
|
426
453
|
readonly error: readonly [error: unknown];
|
|
@@ -429,20 +456,20 @@ export declare type AgentEventMap = {
|
|
|
429
456
|
/**
|
|
430
457
|
* Reports the loop exhausting its `limit` while still holding unresolved tool intent (the model
|
|
431
458
|
* requested tools on the very last allowed turn) — the turn count reached. Distinct from
|
|
432
|
-
* `abort`: exhaustion is
|
|
433
|
-
* this fires
|
|
459
|
+
* `abort`: exhaustion is not a cancel (no external signal / timeout / budget tripped), so
|
|
460
|
+
* this fires instead of `abort`, still followed by `finish` carrying the partial result.
|
|
434
461
|
*/
|
|
435
462
|
readonly exhaust: readonly [turns: number];
|
|
436
463
|
/**
|
|
437
|
-
* Reports
|
|
464
|
+
* Reports automatic compaction's summarizer throwing — a non-fatal warn channel (the run continues; see
|
|
438
465
|
* {@link AgentOptions.window}). When the loop's between-turns / pre-first-turn auto-compaction
|
|
439
|
-
* (`conversation.compact()`) rejects, the run does
|
|
466
|
+
* (`conversation.compact()`) rejects, the run does not crash: the loop skips compaction that
|
|
440
467
|
* turn and surfaces the caught error here so the failure is observable, never silently lost.
|
|
441
|
-
* The run still
|
|
468
|
+
* The run still settles through the other events — `finish` for the lenient default, and
|
|
442
469
|
* `error` when {@link AgentOptions.strict} rethrows the same caught value — so `fault` reports
|
|
443
|
-
* the best-effort optimization that failed and never the run's own outcome. A
|
|
444
|
-
* `conversation.compact()` still propagates its own error; only the agent's
|
|
445
|
-
* resilient. A
|
|
470
|
+
* the best-effort optimization that failed and never the run's own outcome. A manual
|
|
471
|
+
* `conversation.compact()` still propagates its own error; only the agent's auto path is
|
|
472
|
+
* resilient. A domain event (the emitter isolates a listener throw separately, routing it to
|
|
446
473
|
* its `error` handler).
|
|
447
474
|
*/
|
|
448
475
|
readonly fault: readonly [error: unknown];
|
|
@@ -453,7 +480,7 @@ export declare type AgentEventMap = {
|
|
|
453
480
|
* {@link ToolManagerInterface} into a bounded context → provider → tools → repeat turn.
|
|
454
481
|
*
|
|
455
482
|
* @remarks
|
|
456
|
-
* - **One loop, two faces.** `generate` and `stream` share
|
|
483
|
+
* - **One loop, two faces.** `generate` and `stream` share one private run, so they
|
|
457
484
|
* can never diverge: `generate` drains the same stream `stream` exposes, then
|
|
458
485
|
* resolves its settled {@link AgentResult}.
|
|
459
486
|
* - **Bounded.** Each turn arms a single cancel folded from the external `signal`, the
|
|
@@ -461,11 +488,11 @@ export declare type AgentEventMap = {
|
|
|
461
488
|
* or `abort()` — stops the loop and settles the result `partial: true`.
|
|
462
489
|
* - **Paced + capped.** The `scheduler` (when given) yields between turns; tool
|
|
463
490
|
* iteration is capped at `limit` so the loop always terminates.
|
|
464
|
-
* - **Two observation surfaces.**
|
|
465
|
-
* carries per-token answer deltas, per-think reasoning deltas, and usage/tool chunks for a live consumer.
|
|
491
|
+
* - **Two observation surfaces.** Pull: the {@link AgentChunk} stream (`stream().events`)
|
|
492
|
+
* carries per-token answer deltas, per-think reasoning deltas, and usage/tool chunks for a live consumer. Push: the
|
|
466
493
|
* {@link emitter} ({@link AgentEventMap}) carries lifecycle + usage/tool/deny moments
|
|
467
494
|
* for fire-and-forget observers — the emitter isolates a listener throw and routes it to
|
|
468
|
-
* its `error` handler (the `error` option), so a buggy observer can
|
|
495
|
+
* its `error` handler (the `error` option), so a buggy observer can never corrupt the
|
|
469
496
|
* loop. Per-token / per-thinking deltas are the stream's job exclusively; there is no
|
|
470
497
|
* `token` or `think` event.
|
|
471
498
|
* - **Per-run overrides.** Both faces accept an optional {@link AgentRunOptions} bag whose
|
|
@@ -477,14 +504,14 @@ export declare interface AgentInterface {
|
|
|
477
504
|
readonly status: AgentStatus;
|
|
478
505
|
readonly context: AgentContextInterface;
|
|
479
506
|
/**
|
|
480
|
-
* Runs the turn to completion, discarding the live chunks — drains the shared
|
|
481
|
-
*
|
|
507
|
+
* Runs the turn to completion, discarding the live chunks — drains the shared stream and
|
|
508
|
+
* resolves the settled {@link AgentResult} (`partial: true` when cancelled).
|
|
482
509
|
*
|
|
483
510
|
* @remarks
|
|
484
511
|
* A concurrent run on a shared accounting agent throws an
|
|
485
512
|
* {@link import('./errors.js').AgentError} (`code: 'CONCURRENCY'`) — and it throws
|
|
486
|
-
*
|
|
487
|
-
* `agent.generate().catch(...)` therefore will
|
|
513
|
+
* synchronously, before any `Promise` is returned. A fire-and-forget
|
|
514
|
+
* `agent.generate().catch(...)` therefore will not catch it (the throw happens on the call
|
|
488
515
|
* itself, ahead of the `.catch` ever attaching) — `await` the call (inside a `try`/`catch`)
|
|
489
516
|
* or wrap the call expression itself in `try`/`catch`.
|
|
490
517
|
*
|
|
@@ -495,11 +522,12 @@ export declare interface AgentInterface {
|
|
|
495
522
|
generate(options?: AgentRunOptions): Promise<AgentResult>;
|
|
496
523
|
/**
|
|
497
524
|
* Runs the turn as a live stream — iterate `events` for {@link AgentChunk}s and
|
|
498
|
-
* `await result` for the settled outcome
|
|
525
|
+
* `await result` for the settled outcome; `result` resolves partial on a cancel and rejects
|
|
526
|
+
* on a genuine error.
|
|
499
527
|
*
|
|
500
528
|
* @remarks
|
|
501
529
|
* Like `generate()`, a concurrent run on a shared accounting agent throws an
|
|
502
|
-
* {@link import('./errors.js').AgentError} (`code: 'CONCURRENCY'`)
|
|
530
|
+
* {@link import('./errors.js').AgentError} (`code: 'CONCURRENCY'`) synchronously — before the
|
|
503
531
|
* {@link AgentStreamInterface} handle is even returned, so it cannot be caught by chaining
|
|
504
532
|
* off the (never-produced) handle; wrap the call itself in `try`/`catch`.
|
|
505
533
|
*
|
|
@@ -520,13 +548,13 @@ export declare interface AgentInterface {
|
|
|
520
548
|
/**
|
|
521
549
|
* Reports an {@link AgentInterface} run that ended {@link AgentResult.partial} under a
|
|
522
550
|
* `partial` policy of `false` (the default) — thrown by an agent-job handler (a
|
|
523
|
-
* `createAgentQueue` / `createAgentRunner` job), carrying the partial
|
|
524
|
-
*
|
|
551
|
+
* `createAgentQueue` / `createAgentRunner` job), carrying the partial {@link AgentResult} so
|
|
552
|
+
* the failure stays inspectable, and the machine-readable `code` `'PARTIAL'`.
|
|
525
553
|
*
|
|
526
554
|
* @remarks
|
|
527
555
|
* A partial result means the agent was cancelled (an external `signal` abort, a queue /
|
|
528
556
|
* runner abort threaded in, a `timeout` deadline, or an exhausted token `budget`) rather
|
|
529
|
-
* than finishing naturally. For a durable
|
|
557
|
+
* than finishing naturally. For a durable job that is a failure by default: throwing this
|
|
530
558
|
* lets the Queue's retries re-run the job and a Runner's fail-fast abort its siblings.
|
|
531
559
|
* Set `partial: true` (see `AgentQueueOptions` / `AgentRunnerOptions`) to treat a
|
|
532
560
|
* partial as success instead, in which case this is never thrown. Narrow a caught value
|
|
@@ -543,11 +571,11 @@ export declare class AgentJobError extends Error {
|
|
|
543
571
|
}
|
|
544
572
|
|
|
545
573
|
/**
|
|
546
|
-
* Represents a JSON-serializable agent job — the descriptor a durable queue
|
|
547
|
-
* non-serializable pieces (the provider, tools, authority, scheduler) are referenced by
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
574
|
+
* Represents a JSON-serializable agent job — the descriptor a durable queue or runner runs. Its
|
|
575
|
+
* non-serializable pieces (the provider, tools, authority, scheduler) are referenced by name and
|
|
576
|
+
* resolved to live objects through an {@link AgentRegistryInterface} at handler time, while its
|
|
577
|
+
* data fields (the seed `messages`, `system`, `limit`, `timeout`, and a token `budget` ceiling)
|
|
578
|
+
* carry directly.
|
|
551
579
|
*
|
|
552
580
|
* @remarks
|
|
553
581
|
* Because every field is JSON-serializable, a job survives a crash through the Queue's
|
|
@@ -581,7 +609,7 @@ export declare interface AgentJobInput {
|
|
|
581
609
|
/**
|
|
582
610
|
* Lists the sub-agent jobs this job fans out — each a nested {@link AgentJobInput} (so the whole
|
|
583
611
|
* tree stays serializable). On a `createAgentRunner`, the handler `controller.spawn`s
|
|
584
|
-
* each child through the same bounded queue
|
|
612
|
+
* each child through the same bounded queue before running this (parent) job, so the
|
|
585
613
|
* children run as sibling sub-agents and their results join the run after the declared
|
|
586
614
|
* jobs (in spawn order). Ignored by `createAgentQueue` (a queue has no fan-out).
|
|
587
615
|
*/
|
|
@@ -589,7 +617,11 @@ export declare interface AgentJobInput {
|
|
|
589
617
|
}
|
|
590
618
|
|
|
591
619
|
/**
|
|
592
|
-
* Configures `createAgent` — bounds and pacing
|
|
620
|
+
* Configures `createAgent` — the loop's bounds and pacing, the reserved `on` hooks, the
|
|
621
|
+
* construction-time context wiring (`instructions` / `workspaces` / `scope`), the `conversations`
|
|
622
|
+
* registry that is the message source, the context `window` budget that opts into automatic
|
|
623
|
+
* compaction of the active conversation, and the `strict` switch that aborts the run on an
|
|
624
|
+
* automatic-compaction summarizer failure instead of the lenient default.
|
|
593
625
|
*
|
|
594
626
|
* @remarks
|
|
595
627
|
* - `system` — an optional system prompt prepended to the turn (seeds the context).
|
|
@@ -609,16 +641,16 @@ export declare interface AgentJobInput {
|
|
|
609
641
|
* - `signal` — an optional external `AbortSignal` whose abort cancels the turn (a
|
|
610
642
|
* partial result).
|
|
611
643
|
* - `conversations` — an optional {@link ConversationManagerInterface} forwarded to the agent's
|
|
612
|
-
* context as the message source (so `context.messages` is its
|
|
644
|
+
* context as the message source (so `context.messages` is its active conversation's live tail);
|
|
613
645
|
* omitted ⇒ a fresh registry holding one default conversation. Auto-compaction (`window`) folds
|
|
614
|
-
* the
|
|
615
|
-
* - `window` — an optional
|
|
616
|
-
* compaction: when set, the loop measures the
|
|
646
|
+
* the active conversation when it is summarizable.
|
|
647
|
+
* - `window` — an optional context {@link BudgetInterface} for automatic conversation
|
|
648
|
+
* compaction: when set, the loop measures the current full prompt against this budget each turn
|
|
617
649
|
* (its `consumer` is a token estimator, its `max` the context window) and, when the prompt
|
|
618
|
-
* reaches the window
|
|
650
|
+
* reaches the window and the active conversation is summarizable, compacts the active
|
|
619
651
|
* conversation + continues on the rebuilt smaller view — compact-and-continue, distinct from
|
|
620
652
|
* `budget`'s hard abort. Omitted ⇒ no auto-compaction.
|
|
621
|
-
* - `strict` — when `true`, a summarizer failure during
|
|
653
|
+
* - `strict` — when `true`, a summarizer failure during automatic compaction aborts the run
|
|
622
654
|
* (rethrown after the `fault` event, propagating through `#run` to a genuine `error`
|
|
623
655
|
* settle) instead of skipping compaction and continuing over-window. Defaults to `false`
|
|
624
656
|
* (lenient — the prior, byte-for-byte behavior).
|
|
@@ -663,33 +695,153 @@ export declare interface AgentOptions {
|
|
|
663
695
|
*/
|
|
664
696
|
readonly authority?: AuthorityInterface;
|
|
665
697
|
/**
|
|
666
|
-
* Holds an optional {@link ConversationManagerInterface} that becomes the agent context's
|
|
667
|
-
*
|
|
668
|
-
* `agent.context.messages`
|
|
698
|
+
* Holds an optional {@link ConversationManagerInterface} that becomes the agent context's message
|
|
699
|
+
* source — forwarded to the {@link AgentContextInterface} the agent builds, so
|
|
700
|
+
* `agent.context.messages` is its active conversation's live tail and `build()` folds that
|
|
669
701
|
* conversation's `view()` (the per-section summaries + the live tail). Omitted ⇒ a fresh
|
|
670
|
-
* registry holding one default conversation. With `window` set,
|
|
671
|
-
*
|
|
702
|
+
* registry holding one default conversation. With `window` set, automatic compaction folds the
|
|
703
|
+
* active conversation between turns (when it is summarizable).
|
|
672
704
|
*/
|
|
673
705
|
readonly conversations?: ConversationManagerInterface;
|
|
674
706
|
/**
|
|
675
|
-
* Holds an optional
|
|
707
|
+
* Holds an optional context {@link BudgetInterface} for automatic compaction. Its `consumer` is a
|
|
676
708
|
* token estimator (for example the exported {@link import('./helpers.js').estimateMessages}) and
|
|
677
|
-
* its `max` is the context window. When set, the loop measures the
|
|
678
|
-
* next provider request) against this budget each turn; when that prompt reaches the window
|
|
709
|
+
* its `max` is the context window. When set, the loop measures the current full prompt (the
|
|
710
|
+
* next provider request) against this budget each turn; when that prompt reaches the window and
|
|
679
711
|
* the active conversation is summarizable, it **compacts the active conversation + continues on
|
|
680
712
|
* the rebuilt smaller view** (compact-and-continue) — the same consume-to-a-ceiling primitive
|
|
681
713
|
* as the cost `budget`, but compaction is the ceiling action instead of abort. Omit to disable.
|
|
682
714
|
*/
|
|
683
715
|
readonly window?: BudgetInterface<readonly Message[]>;
|
|
684
716
|
/**
|
|
685
|
-
* If `true`, a summarizer failure during
|
|
686
|
-
* `fault` event still fires, then the caught error is
|
|
717
|
+
* If `true`, a summarizer failure during automatic compaction aborts the run — the
|
|
718
|
+
* `fault` event still fires, then the caught error is rethrown so the run settles
|
|
687
719
|
* `error` instead of continuing over-window. Defaults to `false` (lenient — the run
|
|
688
720
|
* continues over-window, byte-for-byte the prior behavior).
|
|
689
721
|
*/
|
|
690
722
|
readonly strict?: boolean;
|
|
691
723
|
}
|
|
692
724
|
|
|
725
|
+
/**
|
|
726
|
+
* Implements bounded HTTP streaming and result assembly behind concrete wire seams.
|
|
727
|
+
*
|
|
728
|
+
* @remarks
|
|
729
|
+
* Every call owns its parser, splitter, deadline, and accumulation. Success bodies
|
|
730
|
+
* have no size limit. A qwen3 implicit-open reclassification corrects the final
|
|
731
|
+
* content while content deltas already yielded cannot be recalled. A subclass fills
|
|
732
|
+
* `name`, `frame`, `body`, `read`, and `finish`; the constructor takes the `split`
|
|
733
|
+
* and `strict` switches to control reasoning separation and settled-result requirements.
|
|
734
|
+
*
|
|
735
|
+
* @example Writing a provider for a new wire
|
|
736
|
+
* ```ts
|
|
737
|
+
* import type {
|
|
738
|
+
* ProviderIncrement,
|
|
739
|
+
* ProviderOptions,
|
|
740
|
+
* ProviderParserInterface,
|
|
741
|
+
* ProviderRequest,
|
|
742
|
+
* } from '@orkestrel/agent'
|
|
743
|
+
* import { AgentProvider } from '@orkestrel/agent'
|
|
744
|
+
*
|
|
745
|
+
* class TextFrame implements ProviderParserInterface<string> {
|
|
746
|
+
* parse(chunk: string): readonly string[] {
|
|
747
|
+
* return [chunk]
|
|
748
|
+
* }
|
|
749
|
+
* clear(): void {} // Raw text retains no framing state.
|
|
750
|
+
* }
|
|
751
|
+
*
|
|
752
|
+
* interface TextOptions extends ProviderOptions {
|
|
753
|
+
* readonly url: string
|
|
754
|
+
* }
|
|
755
|
+
*
|
|
756
|
+
* class TextProvider extends AgentProvider<string> {
|
|
757
|
+
* readonly name = 'text'
|
|
758
|
+
* constructor(options: TextOptions) {
|
|
759
|
+
* super({ ...options, path: '/generate' })
|
|
760
|
+
* }
|
|
761
|
+
* frame(): ProviderParserInterface<string> {
|
|
762
|
+
* return new TextFrame()
|
|
763
|
+
* }
|
|
764
|
+
* body(request: ProviderRequest): object {
|
|
765
|
+
* return { messages: request.messages }
|
|
766
|
+
* }
|
|
767
|
+
* read(record: string): ProviderIncrement {
|
|
768
|
+
* return { content: record, thinking: '', tools: [] }
|
|
769
|
+
* }
|
|
770
|
+
* finish(_parser: ProviderParserInterface<string>): readonly string[] {
|
|
771
|
+
* return [] // Raw text retains no records at end of input.
|
|
772
|
+
* }
|
|
773
|
+
* }
|
|
774
|
+
* ```
|
|
775
|
+
*/
|
|
776
|
+
export declare abstract class AgentProvider<TRecord = Readonly<Record<string, unknown>>> implements AgentProviderInterface<TRecord> {
|
|
777
|
+
#private;
|
|
778
|
+
constructor(input: AgentProviderInput);
|
|
779
|
+
/** Identifies the concrete backend. */
|
|
780
|
+
abstract readonly name: string;
|
|
781
|
+
/** Exposes the instance's minted UUID. */
|
|
782
|
+
get id(): string;
|
|
783
|
+
/** Exposes the context framing exactly as supplied. */
|
|
784
|
+
get format(): ContextFormat | undefined;
|
|
785
|
+
/** Creates fresh framing state for the call. */
|
|
786
|
+
abstract frame(): ProviderParserInterface<TRecord>;
|
|
787
|
+
/** Projects a domain request onto the concrete protocol's wire body. */
|
|
788
|
+
abstract body(request: ProviderRequest): object;
|
|
789
|
+
/** Decodes a framed record into a turn increment. */
|
|
790
|
+
abstract read(record: TRecord): ProviderIncrement;
|
|
791
|
+
/** Returns any records retained at end of input. */
|
|
792
|
+
abstract finish(parser: ProviderParserInterface<TRecord>): readonly TRecord[];
|
|
793
|
+
/**
|
|
794
|
+
* Generates a complete turn by draining the shared stream engine.
|
|
795
|
+
*
|
|
796
|
+
* @param messages - The conversation turns
|
|
797
|
+
* @param signal - The caller's cancellation bound
|
|
798
|
+
* @param tools - The advertised tool definitions
|
|
799
|
+
* @param options - The per-call generation configuration
|
|
800
|
+
* @returns The terminal stream result
|
|
801
|
+
*/
|
|
802
|
+
generate(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): Promise<ProviderResult>;
|
|
803
|
+
/**
|
|
804
|
+
* Streams decoded deltas and returns the authoritative or assembled turn result.
|
|
805
|
+
*
|
|
806
|
+
* @param messages - The conversation turns
|
|
807
|
+
* @param signal - The caller's cancellation bound
|
|
808
|
+
* @param tools - The advertised tool definitions
|
|
809
|
+
* @param options - The per-call generation configuration
|
|
810
|
+
* @returns Content and native thinking deltas followed by the settled result
|
|
811
|
+
* @throws ProviderAbortError Thrown when the combined cancellation bound fires
|
|
812
|
+
* @throws ProviderError Thrown for an HTTP or protocol failure
|
|
813
|
+
*/
|
|
814
|
+
stream(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): AsyncGenerator<ProviderDelta, ProviderResult>;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Configures the HTTP destination and stream assembly of a provider base.
|
|
819
|
+
*
|
|
820
|
+
* @remarks
|
|
821
|
+
* `path` appends to `url`. If `split` is true, separates in-content reasoning;
|
|
822
|
+
* if false, preserves content verbatim. Default: true.
|
|
823
|
+
* If `strict` is true, requires a settled result record; if false, assembles at end of input.
|
|
824
|
+
* Default: false.
|
|
825
|
+
*/
|
|
826
|
+
export declare interface AgentProviderInput extends ProviderOptions {
|
|
827
|
+
readonly url: string;
|
|
828
|
+
readonly path?: string;
|
|
829
|
+
readonly split?: boolean;
|
|
830
|
+
readonly strict?: boolean;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/** Defines the wire-specific seams of the shared HTTP provider engine. */
|
|
834
|
+
export declare interface AgentProviderInterface<TRecord = Readonly<Record<string, unknown>>> extends ProviderInterface {
|
|
835
|
+
/** Creates fresh framing state for a call. */
|
|
836
|
+
frame(): ProviderParserInterface<TRecord>;
|
|
837
|
+
/** Projects a request to the concrete protocol's serializable body. */
|
|
838
|
+
body(request: ProviderRequest): object;
|
|
839
|
+
/** Decodes a framed record into its contribution to the turn. */
|
|
840
|
+
read(record: TRecord): ProviderIncrement;
|
|
841
|
+
/** Returns records retained at end of input before the parser is cleared. */
|
|
842
|
+
finish(parser: ProviderParserInterface<TRecord>): readonly TRecord[];
|
|
843
|
+
}
|
|
844
|
+
|
|
693
845
|
/**
|
|
694
846
|
* Configures `createAgentQueue` — the registry that rehydrates jobs, the partial-result
|
|
695
847
|
* policy, and the substrate knobs threaded into the backing `createQueue`.
|
|
@@ -698,9 +850,9 @@ export declare interface AgentOptions {
|
|
|
698
850
|
* - `registry` — the {@link AgentRegistryInterface} the handler rehydrates each job
|
|
699
851
|
* through (required).
|
|
700
852
|
* - `partial` — the partial policy. A partial {@link AgentResult} (a job committed
|
|
701
|
-
* early from an abort / budget / timeout) is by
|
|
853
|
+
* early from an abort / budget / timeout) is by default a failure: the handler throws
|
|
702
854
|
* an {@link import('./errors.js').AgentJobError}, so the Queue's retries (and a
|
|
703
|
-
* Runner's fail-fast) engage. Set `true` to treat a partial as
|
|
855
|
+
* Runner's fail-fast) engage. Set `true` to treat a partial as success instead — the
|
|
704
856
|
* handler resolves the partial result rather than throwing.
|
|
705
857
|
* - `concurrency` / `retries` / `timeout` / `store` — passed straight to the backing
|
|
706
858
|
* `QueueInterface` (see `QueueOptions`): bounded concurrency, the retry budget, the
|
|
@@ -708,7 +860,7 @@ export declare interface AgentOptions {
|
|
|
708
860
|
*/
|
|
709
861
|
export declare interface AgentQueueOptions {
|
|
710
862
|
readonly registry: AgentRegistryInterface;
|
|
711
|
-
/** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it
|
|
863
|
+
/** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it throws and retries engage. */
|
|
712
864
|
readonly partial?: boolean;
|
|
713
865
|
readonly concurrency?: number;
|
|
714
866
|
readonly retries?: number;
|
|
@@ -717,9 +869,10 @@ export declare interface AgentQueueOptions {
|
|
|
717
869
|
}
|
|
718
870
|
|
|
719
871
|
/**
|
|
720
|
-
* Makes a durable, JSON-serializable {@link AgentJobInput} runnable — holds the named
|
|
721
|
-
*
|
|
722
|
-
*
|
|
872
|
+
* Makes a durable, JSON-serializable {@link AgentJobInput} runnable — holds the named pools of
|
|
873
|
+
* live, non-serializable pieces (providers, tools, authorities, schedulers), throws on a name
|
|
874
|
+
* absent from its pool, and `build`s a seeded, signal-wired {@link Agent} from a job's names and
|
|
875
|
+
* data.
|
|
723
876
|
*
|
|
724
877
|
* @remarks
|
|
725
878
|
* - **Why it exists.** An `AgentJobInput` is serializable so it can survive a crash in a
|
|
@@ -728,9 +881,9 @@ export declare interface AgentQueueOptions {
|
|
|
728
881
|
* construct it once with the live pools, then a queue / runner handler calls `build`
|
|
729
882
|
* on each (possibly restored) job to get a ready agent.
|
|
730
883
|
* - **Accessors throw on a miss.** `provider` / `tool` / `authority` / `scheduler` resolve a
|
|
731
|
-
* name against their pool and
|
|
884
|
+
* name against their pool and throw an {@link AgentError} carrying `code: 'REGISTRY'` and
|
|
732
885
|
* the message `unknown <category>: <name>` when it is absent — an unknown name in a
|
|
733
|
-
* rehydrated job is a programmer / config error that must fail
|
|
886
|
+
* rehydrated job is a programmer / config error that must fail loudly at build time, never
|
|
734
887
|
* silently resolve to `undefined` and run an agent missing a dependency.
|
|
735
888
|
* - **`build` rehydrates.** Resolve the job's `provider`; assemble a fresh
|
|
736
889
|
* {@link ToolManager} from the `tools` names; rebuild the token `budget` from its
|
|
@@ -767,7 +920,7 @@ export declare class AgentRegistry implements AgentRegistryInterface {
|
|
|
767
920
|
*
|
|
768
921
|
* @remarks
|
|
769
922
|
* - **Accessors throw on a miss.** `provider` / `tool` / `authority` / `scheduler` look one
|
|
770
|
-
* up by name and
|
|
923
|
+
* up by name and throw an {@link AgentError} carrying `code: 'REGISTRY'` and the message
|
|
771
924
|
* `unknown <category>: <name>` when the name is unregistered — an unknown name in a
|
|
772
925
|
* rehydrated job must fail loudly, never silently resolve to `undefined`, so a
|
|
773
926
|
* misconfigured job surfaces at once rather than running with a missing dependency.
|
|
@@ -780,7 +933,8 @@ export declare class AgentRegistry implements AgentRegistryInterface {
|
|
|
780
933
|
*/
|
|
781
934
|
export declare interface AgentRegistryInterface {
|
|
782
935
|
/**
|
|
783
|
-
* Resolves a registered {@link ProviderInterface} by name
|
|
936
|
+
* Resolves a registered {@link ProviderInterface} by name — throws `unknown provider: <name>` when
|
|
937
|
+
* absent.
|
|
784
938
|
*
|
|
785
939
|
* @param name - The provider's registry key
|
|
786
940
|
* @returns The live provider
|
|
@@ -788,7 +942,8 @@ export declare interface AgentRegistryInterface {
|
|
|
788
942
|
*/
|
|
789
943
|
provider(name: string): ProviderInterface;
|
|
790
944
|
/**
|
|
791
|
-
* Resolves a registered {@link ToolInterface} by name
|
|
945
|
+
* Resolves a registered {@link ToolInterface} by name — throws `unknown tool: <name>` when
|
|
946
|
+
* absent.
|
|
792
947
|
*
|
|
793
948
|
* @param name - The tool's registry key
|
|
794
949
|
* @returns The live tool
|
|
@@ -796,7 +951,8 @@ export declare interface AgentRegistryInterface {
|
|
|
796
951
|
*/
|
|
797
952
|
tool(name: string): ToolInterface;
|
|
798
953
|
/**
|
|
799
|
-
* Resolves a registered {@link AuthorityInterface} by name
|
|
954
|
+
* Resolves a registered {@link AuthorityInterface} by name — throws `unknown authority: <name>` when
|
|
955
|
+
* absent.
|
|
800
956
|
*
|
|
801
957
|
* @param name - The authority's registry key
|
|
802
958
|
* @returns The live authority
|
|
@@ -804,7 +960,8 @@ export declare interface AgentRegistryInterface {
|
|
|
804
960
|
*/
|
|
805
961
|
authority(name: string): AuthorityInterface;
|
|
806
962
|
/**
|
|
807
|
-
* Resolves a registered {@link SchedulerInterface} by name
|
|
963
|
+
* Resolves a registered {@link SchedulerInterface} by name — throws `unknown scheduler: <name>` when
|
|
964
|
+
* absent.
|
|
808
965
|
*
|
|
809
966
|
* @param name - The scheduler's registry key
|
|
810
967
|
* @returns The live scheduler
|
|
@@ -812,8 +969,9 @@ export declare interface AgentRegistryInterface {
|
|
|
812
969
|
*/
|
|
813
970
|
scheduler(name: string): SchedulerInterface;
|
|
814
971
|
/**
|
|
815
|
-
* Rehydrates a live, seeded {@link AgentInterface} from a serializable
|
|
816
|
-
* its names, rebuilding its budget, seeding its conversation, and wiring
|
|
972
|
+
* Rehydrates a live, seeded {@link AgentInterface} from a serializable {@link AgentJobInput}
|
|
973
|
+
* — resolving its names, rebuilding its token budget, seeding its conversation, and wiring
|
|
974
|
+
* `signal`; a name absent from its pool throws.
|
|
817
975
|
*
|
|
818
976
|
* @param input - The serializable {@link AgentJobInput} to rehydrate
|
|
819
977
|
* @param signal - An optional cancel threaded into the agent (a queue / runner abort)
|
|
@@ -824,20 +982,21 @@ export declare interface AgentRegistryInterface {
|
|
|
824
982
|
}
|
|
825
983
|
|
|
826
984
|
/**
|
|
827
|
-
* Configures `createAgentRegistry` — the named pools of live, non-serializable pieces
|
|
828
|
-
*
|
|
985
|
+
* Configures `createAgentRegistry` — the named pools of live, non-serializable pieces an {@link
|
|
986
|
+
* AgentJobInput}'s names resolve against, plus the optional durable `store` every built agent's
|
|
987
|
+
* conversation manager shares.
|
|
829
988
|
*
|
|
830
989
|
* @remarks
|
|
831
990
|
* `providers` is required (a job always names a provider); `tools` / `authorities` /
|
|
832
991
|
* `schedulers` are optional pools, each an entity-keyed record mapping a registry
|
|
833
992
|
* name to its live object. A name absent from its pool throws when resolved (see
|
|
834
993
|
* {@link AgentRegistryInterface}). `store` is the durable {@link ConversationStoreInterface}
|
|
835
|
-
* every agent this registry builds carries: each built agent gets its
|
|
836
|
-
* {@link ConversationManagerInterface} over
|
|
994
|
+
* every agent this registry builds carries: each built agent gets its own store-backed
|
|
995
|
+
* {@link ConversationManagerInterface} over this shared store — a fresh conversation id per
|
|
837
996
|
* build (minted by the seeded `add`), so concurrent builds never collide, and the store
|
|
838
997
|
* accumulates one snapshot per built agent that later calls `save`. Persistence
|
|
839
998
|
* stays caller-triggered (`open` / `save`) — `build` never hydrates, so `build` stays
|
|
840
|
-
*
|
|
999
|
+
* synchronous. Omitted ⇒ every built agent gets a registry-only manager, byte-identical
|
|
841
1000
|
* to today.
|
|
842
1001
|
*/
|
|
843
1002
|
export declare interface AgentRegistryOptions {
|
|
@@ -857,13 +1016,13 @@ export declare interface AgentRegistryOptions {
|
|
|
857
1016
|
* `partial` is `true` when the turn was committed early from a cancel — an external
|
|
858
1017
|
* `signal` abort, the turn's own `abort()`, a `timeout` deadline, or an exhausted
|
|
859
1018
|
* `budget` — in which case `content` is whatever had accumulated when the cancel
|
|
860
|
-
* landed. `partial` is
|
|
1019
|
+
* landed. `partial` is also `true` when the loop exhausted its `limit` while still
|
|
861
1020
|
* holding unresolved tool intent (the model requested tools on the very last allowed
|
|
862
1021
|
* turn) — a distinct, non-cancel cause covered by {@link RunOutcome.exhausted} (see
|
|
863
1022
|
* the `exhaust` {@link AgentEventMap} event). It is `false` for a turn that ran to a
|
|
864
1023
|
* natural finish (including a `limit: 0` run, which never enters the loop). `usage` is
|
|
865
1024
|
* present only when at least one provider call reported usage — an aborted run's `usage`
|
|
866
|
-
*
|
|
1025
|
+
* includes the cancelled turn's tokens when the provider reports partial usage on the
|
|
867
1026
|
* abort (folded in exactly like a completed turn's); a provider that cannot observe
|
|
868
1027
|
* usage mid-stream (for example a daemon whose final counts never arrive before the cancel)
|
|
869
1028
|
* reports none for that turn, and none is fabricated. `thinking` is present
|
|
@@ -881,8 +1040,11 @@ export declare interface AgentResult {
|
|
|
881
1040
|
}
|
|
882
1041
|
|
|
883
1042
|
/**
|
|
884
|
-
* Projects an unknown value onto
|
|
885
|
-
* {@link AgentResult}
|
|
1043
|
+
* Projects an unknown value onto a fresh, exact `JSONValue` representation of an
|
|
1044
|
+
* {@link AgentResult} — capturing each structural field once through a total boundary,
|
|
1045
|
+
* accepting conforming accessors and inherited properties, preserving finite negative and
|
|
1046
|
+
* fractional usage counts, dropping extras, and resolving `undefined` for a malformed field, a
|
|
1047
|
+
* non-finite usage number, a throwing getter, or a hostile or revoked proxy.
|
|
886
1048
|
*
|
|
887
1049
|
* @remarks
|
|
888
1050
|
* This is a total hostile-boundary projection. Each structural field is captured once
|
|
@@ -912,7 +1074,7 @@ export declare function agentResultToJSON(value: unknown): JSONValue | undefined
|
|
|
912
1074
|
*
|
|
913
1075
|
* @remarks
|
|
914
1076
|
* Identical partial policy to {@link AgentQueueOptions} (`partial` — a partial
|
|
915
|
-
* `AgentResult`
|
|
1077
|
+
* `AgentResult` throws by default so the run's fail-fast engages, `true` resolves it as
|
|
916
1078
|
* success). `concurrency` / `retries` / `timeout` pass straight to the backing
|
|
917
1079
|
* `RunnerInterface` (see `RunnerOptions`). The runner enables sub-agent fan-out: a
|
|
918
1080
|
* parent job's handler can `controller.spawn(childJob)` to launch a child agent job
|
|
@@ -920,7 +1082,7 @@ export declare function agentResultToJSON(value: unknown): JSONValue | undefined
|
|
|
920
1082
|
*/
|
|
921
1083
|
export declare interface AgentRunnerOptions {
|
|
922
1084
|
readonly registry: AgentRegistryInterface;
|
|
923
|
-
/** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it
|
|
1085
|
+
/** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it throws and fail-fast engages. */
|
|
924
1086
|
readonly partial?: boolean;
|
|
925
1087
|
readonly concurrency?: number;
|
|
926
1088
|
readonly retries?: number;
|
|
@@ -929,14 +1091,15 @@ export declare interface AgentRunnerOptions {
|
|
|
929
1091
|
|
|
930
1092
|
/**
|
|
931
1093
|
* Carries the per-run override bag an {@link AgentInterface}'s `generate` / `stream` accepts — each
|
|
932
|
-
* member overrides the matching {@link AgentOptions} value for
|
|
1094
|
+
* member overrides the matching {@link AgentOptions} value for one run, where `think` and `schema`
|
|
1095
|
+
* forward to the provider call and `signal` composes with the constructed one.
|
|
933
1096
|
*
|
|
934
1097
|
* @remarks
|
|
935
1098
|
* Every member is optional and resolved independently, so an omitted member leaves the
|
|
936
1099
|
* agent's constructed value in force and a caller that passes no options runs exactly the
|
|
937
1100
|
* agent it configured. `think` / `schema` ride through to the provider as
|
|
938
1101
|
* {@link ProviderStreamOptions}; `limit` / `timeout` / `budget` replace their construction
|
|
939
|
-
* defaults for this run only; `signal`
|
|
1102
|
+
* defaults for this run only; `signal` composes with the constructed `signal` (both fold into
|
|
940
1103
|
* the run's bound abort) rather than replacing it. Nothing here mutates the agent — the next
|
|
941
1104
|
* run reads the construction defaults again.
|
|
942
1105
|
*/
|
|
@@ -956,23 +1119,23 @@ export declare interface AgentRunOptions {
|
|
|
956
1119
|
*/
|
|
957
1120
|
readonly schema?: Readonly<Record<string, unknown>>;
|
|
958
1121
|
/**
|
|
959
|
-
* Overrides {@link AgentOptions.limit} for
|
|
1122
|
+
* Overrides {@link AgentOptions.limit} for this run only — the max tool-iteration turns
|
|
960
1123
|
* before the loop stops. Omitted ⇒ the agent's constructed `limit` applies.
|
|
961
1124
|
*/
|
|
962
1125
|
readonly limit?: number;
|
|
963
1126
|
/**
|
|
964
|
-
* Overrides {@link AgentOptions.timeout} for
|
|
1127
|
+
* Overrides {@link AgentOptions.timeout} for this run only — a wall-clock deadline (ms)
|
|
965
1128
|
* whose abort commits a partial result. Omitted ⇒ the agent's constructed `timeout` applies.
|
|
966
1129
|
*/
|
|
967
1130
|
readonly timeout?: number;
|
|
968
1131
|
/**
|
|
969
|
-
* Overrides {@link AgentOptions.budget} for
|
|
1132
|
+
* Overrides {@link AgentOptions.budget} for this run only — a token cost bound whose abort
|
|
970
1133
|
* commits a partial result; `start()`ed for this run exactly as the constructed budget is.
|
|
971
1134
|
* Omitted ⇒ the agent's constructed `budget` applies.
|
|
972
1135
|
*/
|
|
973
1136
|
readonly budget?: BudgetInterface<TokenUsage>;
|
|
974
1137
|
/**
|
|
975
|
-
* Carries an additional per-run external cancel,
|
|
1138
|
+
* Carries an additional per-run external cancel, composed with {@link AgentOptions.signal} (both
|
|
976
1139
|
* fold into the run's bound abort through `AbortSignal.any` — neither is dropped). Omitted ⇒
|
|
977
1140
|
* only the agent's constructed `signal` (if any) applies.
|
|
978
1141
|
*/
|
|
@@ -994,10 +1157,11 @@ export declare type AgentStreamInterface = StreamInterface<AgentChunk, AgentResu
|
|
|
994
1157
|
|
|
995
1158
|
/**
|
|
996
1159
|
* Assembles the settled {@link AgentResult} from a run's {@link RunOutcome} — `thinking` and
|
|
997
|
-
* `usage` are carried only when the run surfaced them
|
|
1160
|
+
* `usage` are carried only when the run surfaced them, and the loop-internal `exhausted` flag is
|
|
1161
|
+
* left out.
|
|
998
1162
|
*
|
|
999
1163
|
* @remarks
|
|
1000
|
-
* Pure and total. An absent optional is
|
|
1164
|
+
* Pure and total. An absent optional is omitted rather than stored as `undefined` (the
|
|
1001
1165
|
* present-when-given convention the message store follows), so a settled result JSON
|
|
1002
1166
|
* round-trips without an explicit `undefined` field. `exhausted` is loop bookkeeping and does
|
|
1003
1167
|
* not reach the public result — the `exhaust` event carries it instead.
|
|
@@ -1014,11 +1178,11 @@ export declare type AgentStreamInterface = StreamInterface<AgentChunk, AgentResu
|
|
|
1014
1178
|
export declare function assembleResult(outcome: RunOutcome): AgentResult;
|
|
1015
1179
|
|
|
1016
1180
|
/**
|
|
1017
|
-
* Copies a message with image data merged onto its `images` — the message's own images
|
|
1018
|
-
*
|
|
1181
|
+
* Copies a message with image data merged onto its `images` — the message's own images first,
|
|
1182
|
+
* then the attached data, carrying `calls` only when present and never mutating the original.
|
|
1019
1183
|
*
|
|
1020
1184
|
* @remarks
|
|
1021
|
-
* Pure and total: the original message is
|
|
1185
|
+
* Pure and total: the original message is never mutated. `calls` is carried only when the
|
|
1022
1186
|
* source message has one (kept omitted otherwise, mirroring the store's present-when-given
|
|
1023
1187
|
* convention).
|
|
1024
1188
|
*
|
|
@@ -1035,13 +1199,14 @@ export declare function assembleResult(outcome: RunOutcome): AgentResult;
|
|
|
1035
1199
|
export declare function attachImages(message: Message, data: readonly string[]): Message;
|
|
1036
1200
|
|
|
1037
1201
|
/**
|
|
1038
|
-
* Attaches image data to a conversation's
|
|
1039
|
-
*
|
|
1202
|
+
* Attaches image data to a conversation's last user message — the turn a vision provider reads
|
|
1203
|
+
* images off — as a new array with that one message replaced by its carrying copy, and unchanged
|
|
1204
|
+
* when there is no data or no user turn.
|
|
1040
1205
|
*
|
|
1041
1206
|
* @remarks
|
|
1042
|
-
* Pure and total: the conversation and its messages are
|
|
1207
|
+
* Pure and total: the conversation and its messages are never mutated, and the returned array
|
|
1043
1208
|
* replaces exactly the one target message with the copy {@link attachImages} builds. Empty
|
|
1044
|
-
* data returns the conversation unchanged; a conversation with
|
|
1209
|
+
* data returns the conversation unchanged; a conversation with no user message returns it
|
|
1045
1210
|
* unchanged too (there is nowhere to attach, and the images already rode the system block).
|
|
1046
1211
|
*
|
|
1047
1212
|
* @param conversation - The messages to attach into (left unchanged)
|
|
@@ -1057,18 +1222,20 @@ export declare function attachImages(message: Message, data: readonly string[]):
|
|
|
1057
1222
|
export declare function attachUserImages(conversation: readonly Message[], data: readonly string[]): readonly Message[];
|
|
1058
1223
|
|
|
1059
1224
|
/**
|
|
1060
|
-
* Gates the agent loop's tool calls — the synchronous policy consulted before each call
|
|
1061
|
-
*
|
|
1225
|
+
* Gates the agent loop's tool calls — the synchronous policy consulted before each call runs,
|
|
1226
|
+
* turning one {@link AuthorityContext} into an {@link AuthorityDecision} by walking the ordered
|
|
1227
|
+
* rules first-match-wins and falling back to a configurable default, which allows an unmatched
|
|
1228
|
+
* call unless its `fallback` denies.
|
|
1062
1229
|
*
|
|
1063
1230
|
* @remarks
|
|
1064
1231
|
* - **Ordered, first-match-wins.** `evaluate` walks the configured rules in order and
|
|
1065
|
-
* returns the
|
|
1066
|
-
* `{ zone, allowed: rule.allowed ?? true, reason }` — a matched rule
|
|
1067
|
-
* default and
|
|
1232
|
+
* returns the first whose `match(context)` is true as
|
|
1233
|
+
* `{ zone, allowed: rule.allowed ?? true, reason }` — a matched rule allows by
|
|
1234
|
+
* default and denies only when its `allowed` is explicitly `false`.
|
|
1068
1235
|
* - **Fallback.** When no rule matches, `evaluate` returns the configured `fallback`.
|
|
1069
1236
|
* It defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }` (allow-unmatched),
|
|
1070
|
-
* so a rules list of denials behaves as a
|
|
1071
|
-
* (an
|
|
1237
|
+
* so a rules list of denials behaves as a denylist. To make the gate deny-by-default
|
|
1238
|
+
* (an allowlist — only matched rules that allow get through), pass an `allowed: false`
|
|
1072
1239
|
* `fallback`.
|
|
1073
1240
|
* - **Consulted before each tool call.** The agent loop calls `evaluate({ call })` for
|
|
1074
1241
|
* every {@link import('@orkestrel/tool').ToolCall} the model emits; a denied call is fed
|
|
@@ -1133,7 +1300,8 @@ export declare interface AuthorityDecision {
|
|
|
1133
1300
|
*/
|
|
1134
1301
|
export declare interface AuthorityInterface {
|
|
1135
1302
|
/**
|
|
1136
|
-
* Evaluates one tool call against the ordered rules
|
|
1303
|
+
* Evaluates one tool call against the ordered rules — returns the first matching rule's
|
|
1304
|
+
* verdict, which allows unless `allowed: false`, or the fallback when none match.
|
|
1137
1305
|
*
|
|
1138
1306
|
* @param context - The call under consideration (see {@link AuthorityContext})
|
|
1139
1307
|
* @returns The first matching rule's verdict, or the fallback when none match
|
|
@@ -1146,7 +1314,7 @@ export declare interface AuthorityInterface {
|
|
|
1146
1314
|
*
|
|
1147
1315
|
* @remarks
|
|
1148
1316
|
* `rules` are evaluated in order, first match wins (see {@link AuthorityRule}).
|
|
1149
|
-
* `fallback` is the {@link AuthorityDecision} returned when
|
|
1317
|
+
* `fallback` is the {@link AuthorityDecision} returned when no rule matches; it
|
|
1150
1318
|
* defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }` (allow-unmatched — a
|
|
1151
1319
|
* rules list of denials acts as a denylist). Set `fallback` to an `allowed: false`
|
|
1152
1320
|
* decision to flip the gate to deny-by-default (an allowlist — only matched rules
|
|
@@ -1161,8 +1329,8 @@ export declare interface AuthorityOptions {
|
|
|
1161
1329
|
* Represents one ordered policy rule an {@link AuthorityInterface} evaluates.
|
|
1162
1330
|
*
|
|
1163
1331
|
* @remarks
|
|
1164
|
-
* The
|
|
1165
|
-
* `fallback` decides. A matched rule
|
|
1332
|
+
* The first rule whose `match` returns true decides; if none match, the authority's
|
|
1333
|
+
* `fallback` decides. A matched rule allows by default and denies only when its
|
|
1166
1334
|
* `allowed` is explicitly `false`. `zone` classifies the matched call; `reason` is the
|
|
1167
1335
|
* optional explanation carried into the {@link AuthorityDecision} (and, on a denial,
|
|
1168
1336
|
* into the denial {@link ToolResult}).
|
|
@@ -1175,13 +1343,28 @@ export declare interface AuthorityRule {
|
|
|
1175
1343
|
}
|
|
1176
1344
|
|
|
1177
1345
|
/**
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1180
|
-
*
|
|
1346
|
+
* Assembles a provider result with only populated optional fields.
|
|
1347
|
+
*
|
|
1348
|
+
* @param content - The authoritative answer
|
|
1349
|
+
* @param thinking - The joined reasoning
|
|
1350
|
+
* @param tools - The accumulated calls
|
|
1351
|
+
* @param usage - The reported token usage
|
|
1352
|
+
* @returns The assembled result
|
|
1353
|
+
* @example
|
|
1354
|
+
* ```ts
|
|
1355
|
+
* buildProviderResult('ok', '', [], undefined) // { content: 'ok' }
|
|
1356
|
+
* ```
|
|
1357
|
+
*/
|
|
1358
|
+
export declare function buildProviderResult(content: string, thinking: string, tools: readonly ToolCall[], usage: TokenUsage | undefined): ProviderResult;
|
|
1359
|
+
|
|
1360
|
+
/**
|
|
1361
|
+
* Builds the framed recap message for one compacted section — the same role and stable `id` as
|
|
1362
|
+
* {@link buildSummaryMessage}, with the content prefixed by {@link
|
|
1363
|
+
* import('./constants.js').CONVERSATION_RECAP_PREFIX}.
|
|
1181
1364
|
*
|
|
1182
1365
|
* @remarks
|
|
1183
|
-
* Pure and total. The prefix is what makes a small model read the message as a
|
|
1184
|
-
*
|
|
1366
|
+
* Pure and total. The prefix is what makes a small model read the message as a condensed
|
|
1367
|
+
* recap of earlier turns rather than a literal assistant turn to echo or answer from. It is a
|
|
1185
1368
|
* fixed handful of tokens, so a conversation's `view()` stays lean however many sections it
|
|
1186
1369
|
* carries.
|
|
1187
1370
|
*
|
|
@@ -1197,12 +1380,12 @@ export declare interface AuthorityRule {
|
|
|
1197
1380
|
export declare function buildRecapMessage(section: Section): Message;
|
|
1198
1381
|
|
|
1199
1382
|
/**
|
|
1200
|
-
* Builds the
|
|
1201
|
-
*
|
|
1383
|
+
* Builds the raw synthetic summary message for one compacted section — role `'assistant'`, the
|
|
1384
|
+
* section's stable `id`, and its `summary` verbatim as content.
|
|
1202
1385
|
*
|
|
1203
1386
|
* @remarks
|
|
1204
1387
|
* Pure and total. This is the unframed form the rollup regeneration digests (a
|
|
1205
|
-
* summary-of-summaries over the section summaries); the recap
|
|
1388
|
+
* summary-of-summaries over the section summaries); the recap label is a `view()`
|
|
1206
1389
|
* presentation concern kept out of what the summarizer re-reads — see
|
|
1207
1390
|
* {@link buildRecapMessage}.
|
|
1208
1391
|
*
|
|
@@ -1218,10 +1401,11 @@ export declare function buildRecapMessage(section: Section): Message;
|
|
|
1218
1401
|
export declare function buildSummaryMessage(section: Section): Message;
|
|
1219
1402
|
|
|
1220
1403
|
/**
|
|
1221
|
-
* Buffers chunks in a minimal unbounded async channel — the eager pump
|
|
1222
|
-
*
|
|
1223
|
-
*
|
|
1224
|
-
*
|
|
1404
|
+
* Buffers chunks in a minimal unbounded async channel — the eager pump writes them in (`push`)
|
|
1405
|
+
* and ends it (`close` / `fail`) regardless of consumption, while a consumer reads them back live
|
|
1406
|
+
* through the `drain` async-iterator. Decoupling write from read is what lets a producer make
|
|
1407
|
+
* progress without a consumer pulling, and it is why an agent's `result` settles whether or not
|
|
1408
|
+
* its `events` are drained.
|
|
1225
1409
|
*
|
|
1226
1410
|
* @remarks
|
|
1227
1411
|
* The standard resolver-swap: a waiting `drain` parks on `#wake` (a void resolver);
|
|
@@ -1250,24 +1434,25 @@ export declare class Channel<T> implements ChannelInterface<T> {
|
|
|
1250
1434
|
}
|
|
1251
1435
|
|
|
1252
1436
|
/**
|
|
1253
|
-
* Buffers values in an unbounded async channel — a producer
|
|
1254
|
-
*
|
|
1255
|
-
*
|
|
1437
|
+
* Buffers values in an unbounded async channel — a producer writes them in (`push`) and ends it
|
|
1438
|
+
* (`close` / `fail`) regardless of consumption, while a consumer reads them back live through
|
|
1439
|
+
* `drain`.
|
|
1256
1440
|
*
|
|
1257
1441
|
* @remarks
|
|
1258
1442
|
* Decoupling the write from the read is what lets a producer make progress with nobody
|
|
1259
1443
|
* pulling: an agent's eager pump writes each {@link AgentChunk} into one, so the run's
|
|
1260
1444
|
* `result` settles whether or not `events` is ever drained. A waiting `drain` parks on a
|
|
1261
1445
|
* resolver the next `push` / `close` / `fail` fires, so a value pushed at a parked reader is
|
|
1262
|
-
* delivered rather than dropped. Buffered values are always yielded
|
|
1263
|
-
* reported, so a `close` arriving alongside the last values still delivers them. The
|
|
1446
|
+
* delivered rather than dropped. Buffered values are always yielded before the end is
|
|
1447
|
+
* reported, so a `close` arriving alongside the last values still delivers them. The first
|
|
1264
1448
|
* failure wins — a later `close` / `fail` cannot override a recorded error. Event-free.
|
|
1265
1449
|
*
|
|
1266
1450
|
* @typeParam T - The value type the channel carries
|
|
1267
1451
|
*/
|
|
1268
1452
|
export declare interface ChannelInterface<T> {
|
|
1269
1453
|
/**
|
|
1270
|
-
* Writes one value — buffered, then handed to a parked consumer
|
|
1454
|
+
* Writes one value — buffered, then handed to a parked consumer; a value pushed at an
|
|
1455
|
+
* already-parked reader is delivered, never dropped.
|
|
1271
1456
|
*
|
|
1272
1457
|
* @param value - The value to enqueue
|
|
1273
1458
|
*/
|
|
@@ -1275,13 +1460,14 @@ export declare interface ChannelInterface<T> {
|
|
|
1275
1460
|
/** Ends the channel normally — a draining consumer returns once the buffer is empty. */
|
|
1276
1461
|
close(): void;
|
|
1277
1462
|
/**
|
|
1278
|
-
* Ends the channel with a failure — a draining consumer throws it once the buffer is empty
|
|
1463
|
+
* Ends the channel with a failure — a draining consumer throws it once the buffer is empty;
|
|
1464
|
+
* the first failure wins.
|
|
1279
1465
|
*
|
|
1280
1466
|
* @param error - The failure to surface (the first one recorded wins)
|
|
1281
1467
|
*/
|
|
1282
1468
|
fail(error: unknown): void;
|
|
1283
1469
|
/**
|
|
1284
|
-
* Reads the values back live, in write order
|
|
1470
|
+
* Reads the values back live, in write order — returning on `close` and throwing on `fail`.
|
|
1285
1471
|
*
|
|
1286
1472
|
* @returns A generator yielding each pushed value, returning on `close` and throwing on `fail`
|
|
1287
1473
|
*/
|
|
@@ -1289,11 +1475,11 @@ export declare interface ChannelInterface<T> {
|
|
|
1289
1475
|
}
|
|
1290
1476
|
|
|
1291
1477
|
/**
|
|
1292
|
-
* Collects the `base64` payload of the
|
|
1293
|
-
*
|
|
1478
|
+
* Collects the `base64` payload of the image files in a workspace file list — the data an agent
|
|
1479
|
+
* context attaches to the last user message.
|
|
1294
1480
|
*
|
|
1295
1481
|
* @remarks
|
|
1296
|
-
* Pure and total. `isBinary`
|
|
1482
|
+
* Pure and total. `isBinary` narrows the tagless content to its binary arm (a total guard,
|
|
1297
1483
|
* never an assertion), then the MIME prefix gates it to an image, so a text file and a non-image
|
|
1298
1484
|
* binary (a PDF) are both skipped. Order follows the file list.
|
|
1299
1485
|
*
|
|
@@ -1309,14 +1495,15 @@ export declare interface ChannelInterface<T> {
|
|
|
1309
1495
|
export declare function collectImageData(files: readonly FileInterface[]): readonly string[];
|
|
1310
1496
|
|
|
1311
1497
|
/**
|
|
1312
|
-
* Configures one {@link ConversationInterface.compact} call —
|
|
1498
|
+
* Configures one {@link ConversationInterface.compact} call — the retained-tail size, the
|
|
1499
|
+
* `sections` cap, or both, overridden for one fold.
|
|
1313
1500
|
*
|
|
1314
1501
|
* @remarks
|
|
1315
|
-
* `keep` overrides the conversation's configured retained-tail size for
|
|
1502
|
+
* `keep` overrides the conversation's configured retained-tail size for this compaction only
|
|
1316
1503
|
* (the older `count - keep` live messages fold; when `count <= keep` nothing folds and
|
|
1317
1504
|
* `compact()` is a no-op returning `undefined`). Omitted ⇒ the conversation's own `keep`
|
|
1318
1505
|
* (its option, or `DEFAULT_CONVERSATION_KEEP`) applies. `sections` overrides the conversation's
|
|
1319
|
-
* configured `sections` cap for
|
|
1506
|
+
* configured `sections` cap for this compaction only — after the new section is pushed, an
|
|
1320
1507
|
* overflow past `sections` folds the oldest sections into one merged section. Omitted ⇒ the
|
|
1321
1508
|
* conversation's own `sections` cap (or unlimited) applies.
|
|
1322
1509
|
*/
|
|
@@ -1328,17 +1515,17 @@ export declare interface CompactOptions {
|
|
|
1328
1515
|
}
|
|
1329
1516
|
|
|
1330
1517
|
/**
|
|
1331
|
-
* Holds a provider's
|
|
1332
|
-
*
|
|
1333
|
-
*
|
|
1518
|
+
* Holds a provider's optional context-framing default, keyed by section kind — the framing a model
|
|
1519
|
+
* prefers (for example XML tags against Markdown headers), declared by a {@link ProviderInterface}
|
|
1520
|
+
* that opts in.
|
|
1334
1521
|
*
|
|
1335
1522
|
* @remarks
|
|
1336
1523
|
* Each key is a {@link ContextSectionFormat} for one of the observable context sections
|
|
1337
1524
|
* (the `instructions` section), so a provider can frame each section independently — and any
|
|
1338
|
-
* it omits falls through to that manager's built-in default. It is the
|
|
1339
|
-
* level of the {@link import('./AgentContext.js').AgentContext} build cascade: it
|
|
1340
|
-
* manager's built-in default but is
|
|
1341
|
-
* override (see {@link AgentContextInterface.build}). It references the
|
|
1525
|
+
* it omits falls through to that manager's built-in default. It is the provider-default
|
|
1526
|
+
* level of the {@link import('./AgentContext.js').AgentContext} build cascade: it beats a
|
|
1527
|
+
* manager's built-in default but is beaten by a manager-options override and by a per-item
|
|
1528
|
+
* override (see {@link AgentContextInterface.build}). It references the abstract core
|
|
1342
1529
|
* item interface ({@link InstructionInterface}), so a provider opting in imports it from
|
|
1343
1530
|
* `@orkestrel/agent` — the type is provider-agnostic, with no backend coupling. Omitting it
|
|
1344
1531
|
* entirely (the default for an agnostic provider) leaves every section on its manager's
|
|
@@ -1356,17 +1543,17 @@ export declare interface ContextFormat {
|
|
|
1356
1543
|
* line rendered once after the items.
|
|
1357
1544
|
*
|
|
1358
1545
|
* @remarks
|
|
1359
|
-
* `open`, `render`, and `close` are
|
|
1546
|
+
* `open`, `render`, and `close` are optional and resolved independently (so an override may set only
|
|
1360
1547
|
* the top, only the per-item rendering, only the bottom, or any mix). A section assembles
|
|
1361
1548
|
* as `[open, ...items.map(render), close]` with empty / absent slots dropped, the survivors
|
|
1362
|
-
* blank-line (`\n\n`) joined — so `open` + `close` together let a developer
|
|
1549
|
+
* blank-line (`\n\n`) joined — so `open` + `close` together let a developer wrap the whole
|
|
1363
1550
|
* group (for example `open: '<instructions>'` … `close: '</instructions>'`). `open` is the
|
|
1364
1551
|
* section's leading text (the header, or a group's opening tag); `render` turns one section
|
|
1365
1552
|
* item (an {@link InstructionInterface}) into its prompt text; `close` is the trailing text.
|
|
1366
1553
|
* `open` and `render` cascade through the
|
|
1367
1554
|
* built-in floor (`open` ⇒ the manager's built-in header, `render` ⇒ the manager's built-in
|
|
1368
|
-
* rendering); `close` has
|
|
1369
|
-
* It is the unit
|
|
1555
|
+
* rendering); `close` has no built-in, so an unset `close` yields no closing line.
|
|
1556
|
+
* It is the unit both a provider's {@link ContextFormat} (a per-section-kind
|
|
1370
1557
|
* default) and a manager's `Options` carry — see {@link AgentContextInterface.build} for
|
|
1371
1558
|
* the full precedence.
|
|
1372
1559
|
*
|
|
@@ -1374,7 +1561,7 @@ export declare interface ContextFormat {
|
|
|
1374
1561
|
*/
|
|
1375
1562
|
export declare interface ContextSectionFormat<T> {
|
|
1376
1563
|
/**
|
|
1377
|
-
* Holds text rendered
|
|
1564
|
+
* Holds text rendered once before the section's items — the section header or a group's
|
|
1378
1565
|
* opening wrapper, for example `'<instructions>'`; omitted ⇒ the next cascade level decides
|
|
1379
1566
|
* (defaulting to the built-in header).
|
|
1380
1567
|
*/
|
|
@@ -1382,25 +1569,25 @@ export declare interface ContextSectionFormat<T> {
|
|
|
1382
1569
|
/** Overrides one item's rendering; omitted ⇒ the next cascade level decides. */
|
|
1383
1570
|
readonly render?: (item: T) => string;
|
|
1384
1571
|
/**
|
|
1385
|
-
* Holds text rendered
|
|
1572
|
+
* Holds text rendered once after the section's items — a group's closing wrapper, for
|
|
1386
1573
|
* example `'</instructions>'`; omitted ⇒ no closing line (there is no built-in close).
|
|
1387
1574
|
*/
|
|
1388
1575
|
readonly close?: string;
|
|
1389
1576
|
}
|
|
1390
1577
|
|
|
1391
1578
|
/**
|
|
1392
|
-
* Exposes the manager surface one context section's format cascade reads — its built-in
|
|
1393
|
-
* `
|
|
1394
|
-
*
|
|
1579
|
+
* Exposes the manager surface one context section's format cascade reads — its built-in `open` /
|
|
1580
|
+
* `render`, plus the raw options override the cascade layers a provider default beneath; {@link
|
|
1581
|
+
* InstructionManagerInterface} satisfies it structurally.
|
|
1395
1582
|
*
|
|
1396
1583
|
* @remarks
|
|
1397
1584
|
* The narrow contract the cascade resolvers
|
|
1398
1585
|
* ({@link import('./helpers.js').resolveOpen} / {@link import('./helpers.js').resolveClose} /
|
|
1399
|
-
* {@link import('./helpers.js').resolveItem}) take, so they stay independent of
|
|
1586
|
+
* {@link import('./helpers.js').resolveItem}) take, so they stay independent of which manager
|
|
1400
1587
|
* supplies the section: an {@link InstructionManagerInterface} satisfies it structurally.
|
|
1401
1588
|
* `open` and `render` already encapsulate `[options-override → built-in]` (so a manager
|
|
1402
1589
|
* used standalone renders correctly), and `format` exposes the raw override so `build()` can
|
|
1403
|
-
* interleave the provider default
|
|
1590
|
+
* interleave the provider default beneath it.
|
|
1404
1591
|
*
|
|
1405
1592
|
* @typeParam T - The section item this source renders
|
|
1406
1593
|
*/
|
|
@@ -1409,41 +1596,45 @@ export declare interface ContextSectionSourceInterface<T> {
|
|
|
1409
1596
|
readonly open: string;
|
|
1410
1597
|
/** Holds the raw manager-options override, or `undefined` when none was supplied. */
|
|
1411
1598
|
readonly format: ContextSectionFormat<T> | undefined;
|
|
1412
|
-
/**
|
|
1599
|
+
/**
|
|
1600
|
+
* Renders one section item, already resolved against the manager-options override and
|
|
1601
|
+
* otherwise on the built-in rendering.
|
|
1602
|
+
*/
|
|
1413
1603
|
render(item: T): string;
|
|
1414
1604
|
}
|
|
1415
1605
|
|
|
1416
1606
|
/**
|
|
1417
|
-
* Represents a conversation — a live uncompacted tail of messages it
|
|
1418
|
-
*
|
|
1419
|
-
* `
|
|
1420
|
-
* {@link ConversationSummaryHandler} seam
|
|
1607
|
+
* Represents a conversation — a live uncompacted tail of messages it owns directly above a flat
|
|
1608
|
+
* message store, plus compacted, summarized {@link Section}s, a regenerated rollup `summary`, and
|
|
1609
|
+
* a `summarizable` flag, with on-demand `rehydrate` and substring `search`, driven by a
|
|
1610
|
+
* provider-agnostic {@link ConversationSummaryHandler} seam so `core` never imports a provider.
|
|
1611
|
+
* Observable through its own `emitter`.
|
|
1421
1612
|
*
|
|
1422
1613
|
* @remarks
|
|
1423
|
-
* - **Live tail + sections.** The conversation
|
|
1614
|
+
* - **Live tail + sections.** The conversation owns its live tail directly — `#messages` is an
|
|
1424
1615
|
* insertion-ordered `Map` of immutable {@link Message}s keyed by their minted id
|
|
1425
|
-
* (the
|
|
1616
|
+
* (the same store mechanics a flat manager had, folded in: `add` / `message` / `messages` /
|
|
1426
1617
|
* `remove` / `clear` / `count`), exactly as a `Workspace` owns its files (no separate
|
|
1427
1618
|
* per-value manager). `#sections` are the compacted history (oldest → newest), each a
|
|
1428
|
-
* summarized slice that
|
|
1619
|
+
* summarized slice that retains its originals. `#summary` is the rollup (a
|
|
1429
1620
|
* summary-of-summaries over all sections), regenerated on each compaction (`undefined`
|
|
1430
1621
|
* until the first).
|
|
1431
|
-
* - **`view()`.** Each section folds to
|
|
1622
|
+
* - **`view()`.** Each section folds to one synthetic summary message (role `'assistant'` — a
|
|
1432
1623
|
* prior-context recap — keyed by the section's stable `id`), then the live messages
|
|
1433
|
-
* verbatim. The rollup `summary` is
|
|
1434
|
-
* carries the per-section summaries, which
|
|
1624
|
+
* verbatim. The rollup `summary` is not injected (it is separately pull-able); `view()`
|
|
1625
|
+
* carries the per-section summaries, which are the compaction benefit.
|
|
1435
1626
|
* - **`compact()`.** Folds the oldest `count - keep` live messages into a new section
|
|
1436
1627
|
* (its `summary` from `#summarize`), removes them from the live tail by id, regenerates the
|
|
1437
|
-
* rollup (a
|
|
1628
|
+
* rollup (a second `#summarize` over all section summaries), and emits `summary` then
|
|
1438
1629
|
* `compact`. Returns the section, or `undefined` when nothing folds (`count <= keep`).
|
|
1439
|
-
*
|
|
1440
|
-
*
|
|
1630
|
+
* Throws a {@link ConversationError} when no `#summarize` was supplied. A compaction calls
|
|
1631
|
+
* the summarizer for the section digest and again for the rollup.
|
|
1441
1632
|
* - **`rehydrate(id)` / `search(query)`.** `rehydrate` returns a section's full original
|
|
1442
1633
|
* messages (`[]` for an unknown id) and emits `rehydrate` — a pure read (the caller decides
|
|
1443
1634
|
* whether to re-add them; `rehydrate` never reinserts). `search` is a case-insensitive
|
|
1444
|
-
* substring scan of `content` across
|
|
1635
|
+
* substring scan of `content` across all messages (every section's originals + the live tail).
|
|
1445
1636
|
* - **Observable.** The owned {@link emitter} ({@link ConversationEventMap}) carries
|
|
1446
|
-
* `compact` / `summary` / `rehydrate`, emitted directly, strictly
|
|
1637
|
+
* `compact` / `summary` / `rehydrate`, emitted directly, strictly after the state change;
|
|
1447
1638
|
* the emitter isolates a listener throw and routes it to its `error` handler (the `error`
|
|
1448
1639
|
* option), so a buggy observer can never corrupt a compaction.
|
|
1449
1640
|
*
|
|
@@ -1485,12 +1676,13 @@ export declare class Conversation implements ConversationInterface {
|
|
|
1485
1676
|
|
|
1486
1677
|
/**
|
|
1487
1678
|
* Names the framing label a {@link ConversationInterface}'s `view()` prefixes onto each compacted
|
|
1488
|
-
* section's summary so a small model reads it as a
|
|
1489
|
-
* literal assistant turn to echo or treat as
|
|
1679
|
+
* section's summary so a small model reads it as a condensed recap of earlier turns — the lean
|
|
1680
|
+
* `'[Summary of earlier messages] '` marker, never a literal assistant turn to echo or treat as
|
|
1681
|
+
* the live answer.
|
|
1490
1682
|
*
|
|
1491
1683
|
* @remarks
|
|
1492
|
-
* Deliberately a
|
|
1493
|
-
* bounded `prefix × sections` overhead and
|
|
1684
|
+
* Deliberately a fixed, lean handful of tokens (a short bracketed marker) so the framing adds a
|
|
1685
|
+
* bounded `prefix × sections` overhead and never an open-ended blow-up — the
|
|
1494
1686
|
* {@link ConversationInterface} no-bloat test guard pins exactly that. Kept here (beside
|
|
1495
1687
|
* {@link DEFAULT_CONVERSATION_KEEP}) as the conversation layer's one tunable framing constant, so
|
|
1496
1688
|
* the wording has a single source of truth as it is optimized against real small-model behavior
|
|
@@ -1500,12 +1692,13 @@ export declare class Conversation implements ConversationInterface {
|
|
|
1500
1692
|
export declare const CONVERSATION_RECAP_PREFIX = "[Summary of earlier messages] ";
|
|
1501
1693
|
|
|
1502
1694
|
/**
|
|
1503
|
-
* Reports a conversation with no {@link ConversationSummaryHandler} to fold its messages
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1695
|
+
* Reports a conversation with no {@link ConversationSummaryHandler} to fold its messages with,
|
|
1696
|
+
* or with a `sections` cap below `1` — thrown by a {@link ConversationInterface}'s `compact()`
|
|
1697
|
+
* or its construction, carrying the machine-readable `code`
|
|
1698
|
+
* `'SUMMARIZER' | 'SECTIONS'`.
|
|
1506
1699
|
*
|
|
1507
1700
|
* @remarks
|
|
1508
|
-
* Compaction
|
|
1701
|
+
* Compaction requires a summarizer (it digests the folded slice into a section summary and
|
|
1509
1702
|
* regenerates the rollup); a conversation created without one can still store + `view()` its
|
|
1510
1703
|
* live tail, but a `compact()` is a programmer error and throws this with `'SUMMARIZER'`.
|
|
1511
1704
|
* A `sections` cap (on {@link import('./types.js').ConversationOptions} /
|
|
@@ -1526,7 +1719,7 @@ export declare class ConversationError extends Error {
|
|
|
1526
1719
|
*
|
|
1527
1720
|
* @remarks
|
|
1528
1721
|
* `compact` carries the newly-folded {@link Section}; `collapse` carries a section
|
|
1529
|
-
* created by folding multiple
|
|
1722
|
+
* created by folding multiple older sections together (a bounded-`sections` cap enforcement,
|
|
1530
1723
|
* distinct from `compact`'s fresh live-tail fold); `summary` carries the regenerated
|
|
1531
1724
|
* conversation rollup (refreshed on each compaction); `rehydrate` carries the `id` of a
|
|
1532
1725
|
* section whose originals were pulled back. Listener isolation is the emitter's:
|
|
@@ -1543,31 +1736,32 @@ export declare type ConversationEventMap = {
|
|
|
1543
1736
|
/** Reports a section's original messages pulled back — the section's `id`. */
|
|
1544
1737
|
readonly rehydrate: readonly [id: string];
|
|
1545
1738
|
/**
|
|
1546
|
-
* Reports the bounded-`sections` cap folding the oldest sections into
|
|
1739
|
+
* Reports the bounded-`sections` cap folding the oldest sections into one merged section — the
|
|
1547
1740
|
* merged {@link Section} that replaced them.
|
|
1548
1741
|
*/
|
|
1549
1742
|
readonly collapse: readonly [section: Section];
|
|
1550
1743
|
};
|
|
1551
1744
|
|
|
1552
1745
|
/**
|
|
1553
|
-
* Carries the data to author a {@link ConversationInterface} through a
|
|
1554
|
-
*
|
|
1555
|
-
* override,
|
|
1746
|
+
* Carries the data to author a {@link ConversationInterface} through a {@link
|
|
1747
|
+
* ConversationManagerInterface} — the optional `id`, a `summarize` override, a `keep` override, a
|
|
1748
|
+
* `sections` cap override, the reserved `on` hooks, and a {@link ConversationSnapshot} to hydrate
|
|
1749
|
+
* from.
|
|
1556
1750
|
*
|
|
1557
1751
|
* @remarks
|
|
1558
|
-
* `id` is the conversation's identity (minted when omitted). `summarize`
|
|
1752
|
+
* `id` is the conversation's identity (minted when omitted). `summarize` overrides the
|
|
1559
1753
|
* manager's default {@link ConversationSummaryHandler} for this conversation (omitted ⇒ the
|
|
1560
1754
|
* manager's default flows in). `keep` overrides the manager's default retained-tail size.
|
|
1561
1755
|
* `sections` overrides the manager's default `sections` cap. `on` is the reserved listener key
|
|
1562
1756
|
* (initial {@link ConversationEventMap} listeners). `snapshot` is
|
|
1563
1757
|
* the construction-time hydration seam — a {@link ConversationSnapshot} whose `id` / `summary` /
|
|
1564
|
-
* `sections` / live tail are
|
|
1758
|
+
* `sections` / live tail are restored into the new conversation (the live `summarize` / `keep` /
|
|
1565
1759
|
* `on` re-supplied alongside it), the conversation analogue of
|
|
1566
1760
|
* {@link import('@orkestrel/workspace').WorkspaceOptions}'s `seed`, carried onto
|
|
1567
1761
|
* {@link ConversationOptions.snapshot}, that a
|
|
1568
1762
|
* {@link ConversationManagerInterface.open} reads a stored snapshot back through; hydration is
|
|
1569
1763
|
* silent (no events). When both `snapshot.id` and `id` are given, `snapshot.id` wins (the snapshot
|
|
1570
|
-
*
|
|
1764
|
+
* is the conversation's identity).
|
|
1571
1765
|
*/
|
|
1572
1766
|
export declare interface ConversationInput {
|
|
1573
1767
|
readonly id?: string;
|
|
@@ -1583,52 +1777,53 @@ export declare interface ConversationInput {
|
|
|
1583
1777
|
}
|
|
1584
1778
|
|
|
1585
1779
|
/**
|
|
1586
|
-
* Groups messages
|
|
1587
|
-
*
|
|
1588
|
-
*
|
|
1589
|
-
* provider-agnostic {@link ConversationSummaryHandler} seam
|
|
1780
|
+
* Groups messages above the flat {@link MessageManagerInterface} — a live uncompacted tail plus
|
|
1781
|
+
* compacted, summarized {@link Section}s and a conversation rollup `summary`, with on-demand
|
|
1782
|
+
* `rehydrate`, substring `search`, a cross-conversation `reference`, and a JSON `snapshot`, driven
|
|
1783
|
+
* by a provider-agnostic {@link ConversationSummaryHandler} seam; `summarizable` reports whether
|
|
1784
|
+
* that seam was supplied, and the agent loop gates automatic compaction on it.
|
|
1590
1785
|
*
|
|
1591
1786
|
* @remarks
|
|
1592
|
-
* - **Live tail + sections.** The conversation
|
|
1787
|
+
* - **Live tail + sections.** The conversation owns its live uncompacted tail directly — a
|
|
1593
1788
|
* caller appends turns through its own message verbs (`add` mints each `id`, `message` /
|
|
1594
1789
|
* `messages` look up, `remove` / `clear` drop, `count` tallies), exactly as a `Workspace`
|
|
1595
1790
|
* owns its files (no separate per-value manager). `sections` are the compacted history
|
|
1596
|
-
* (oldest → newest), each a summarized slice that
|
|
1791
|
+
* (oldest → newest), each a summarized slice that retains its originals. `summary` is the
|
|
1597
1792
|
* conversation rollup (a summary-of-summaries over all sections), regenerated on each
|
|
1598
1793
|
* compaction (`undefined` until the first compaction).
|
|
1599
1794
|
* - **Message verbs (the inlined store).** `add` takes one {@link MessageInput} or a batch,
|
|
1600
|
-
*
|
|
1795
|
+
* mints each message's `id` (a random UUID), stores it, and returns the created
|
|
1601
1796
|
* message(s); a stored message is immutable. `message(id)` resolves one (`undefined` when
|
|
1602
1797
|
* absent); `messages()` lists the live tail in insertion order; `remove` drops one by id or
|
|
1603
|
-
* a batch (`true` only when
|
|
1798
|
+
* a batch (`true` only when every supplied id was removed); `clear` empties the tail;
|
|
1604
1799
|
* `count` is how many live messages are stored.
|
|
1605
|
-
* - **`view()` — the model input.** Each section folds to
|
|
1800
|
+
* - **`view()` — the model input.** Each section folds to one synthetic summary message,
|
|
1606
1801
|
* followed by the live messages verbatim: `[...sections-as-summary-messages, ...live]`. The
|
|
1607
|
-
* rollup `summary` is
|
|
1608
|
-
* cross-conversation case); `view()` carries the per-section summaries, which
|
|
1802
|
+
* rollup `summary` is not injected (it is a separately pull-able digest for a
|
|
1803
|
+
* cross-conversation case); `view()` carries the per-section summaries, which are the
|
|
1609
1804
|
* compaction benefit.
|
|
1610
1805
|
* - **`compact()` — fold older live → a section.** Folds the oldest `count - keep` live
|
|
1611
1806
|
* messages into a new {@link Section} (its `summary` from `summarize`), removes
|
|
1612
|
-
* them from the live tail,
|
|
1807
|
+
* them from the live tail, regenerates the rollup (a second `summarize` over all section
|
|
1613
1808
|
* summaries), and emits `summary` then `compact` — returning the new section (or
|
|
1614
|
-
* `undefined` when nothing folds).
|
|
1615
|
-
*
|
|
1616
|
-
* `summarize` was supplied.
|
|
1617
|
-
* - **`summarizable` — whether a `compact()`
|
|
1618
|
-
* {@link ConversationSummaryHandler} was supplied, `false` otherwise. The agent loop's
|
|
1809
|
+
* `undefined` when nothing folds). A compaction calls the summarizer for the section
|
|
1810
|
+
* digest and again for the rollup. Throws a
|
|
1811
|
+
* {@link import('./errors.js').ConversationError} when no `summarize` was supplied.
|
|
1812
|
+
* - **`summarizable` — whether a `compact()` can fold.** `true` when a
|
|
1813
|
+
* {@link ConversationSummaryHandler} was supplied, `false` otherwise. The agent loop's automatic
|
|
1619
1814
|
* compaction (`AgentOptions.window`) gates on it so a conversation that has no summarizer is
|
|
1620
1815
|
* never auto-compacted (and the loop never throws the `compact()` `SUMMARIZER` error from the
|
|
1621
|
-
* auto path). A
|
|
1816
|
+
* auto path). A manual `compact()` still throws without a summarizer — only the auto path is
|
|
1622
1817
|
* guarded.
|
|
1623
1818
|
* - **`rehydrate(id)` / `search(query)` — read the retained originals.** `rehydrate` returns
|
|
1624
1819
|
* a section's full original messages (`[]` for an unknown id) and emits `rehydrate` — a
|
|
1625
|
-
* pure
|
|
1626
|
-
* `search` is a case-insensitive substring scan of `content` across
|
|
1820
|
+
* pure read (the caller decides whether to re-add them; `rehydrate` never reinserts).
|
|
1821
|
+
* `search` is a case-insensitive substring scan of `content` across all messages (every
|
|
1627
1822
|
* section's originals + the live tail).
|
|
1628
|
-
* - **`reference(options?)` — pull
|
|
1823
|
+
* - **`reference(options?)` — pull this conversation into another with provenance.** A pure
|
|
1629
1824
|
* string render (no model call) of a self-labeled, fenced cross-conversation block — the
|
|
1630
1825
|
* rollup `summary` (when included + present) plus cherry-picked excerpts — framed so a small
|
|
1631
|
-
* model reads it as
|
|
1826
|
+
* model reads it as foreign material. Written into the active conversation's context through
|
|
1632
1827
|
* the active workspace (`context.workspaces.active?.write(path, block)`); the cherry-pick
|
|
1633
1828
|
* comes from this conversation's own `search` / `rehydrate`, never its whole history.
|
|
1634
1829
|
* - **Observable.** The owned `emitter` ({@link ConversationEventMap}) carries
|
|
@@ -1643,17 +1838,18 @@ export declare interface ConversationInterface {
|
|
|
1643
1838
|
/** Lists the compacted history, oldest → newest. */
|
|
1644
1839
|
readonly sections: readonly Section[];
|
|
1645
1840
|
/**
|
|
1646
|
-
* Reports whether a `compact()`
|
|
1647
|
-
* The agent loop's
|
|
1841
|
+
* Reports whether a `compact()` can fold — `true` when a {@link ConversationSummaryHandler} was supplied.
|
|
1842
|
+
* The agent loop's automatic compaction (`AgentOptions.window`) gates on it (a non-summarizable
|
|
1648
1843
|
* conversation is never auto-compacted, so the auto path never throws the `SUMMARIZER` error);
|
|
1649
|
-
* a
|
|
1844
|
+
* a manual `compact()` still throws without a summarizer.
|
|
1650
1845
|
*/
|
|
1651
1846
|
readonly summarizable: boolean;
|
|
1652
|
-
/** Counts the
|
|
1847
|
+
/** Counts the live (uncompacted) messages stored in the tail. */
|
|
1653
1848
|
readonly count: number;
|
|
1654
1849
|
/**
|
|
1655
|
-
* Appends one
|
|
1656
|
-
* (a random UUID) and returns the created message
|
|
1850
|
+
* Appends one {@link MessageInput} to the live tail, or a batch — mints each message's `id`
|
|
1851
|
+
* (a random UUID) and returns the created message or messages; a stored message is
|
|
1852
|
+
* immutable.
|
|
1657
1853
|
*
|
|
1658
1854
|
* @param input - One {@link MessageInput}, or a batch
|
|
1659
1855
|
* @returns The created {@link Message}(s), with their minted `id`s
|
|
@@ -1661,50 +1857,52 @@ export declare interface ConversationInterface {
|
|
|
1661
1857
|
add(input: MessageInput): Message;
|
|
1662
1858
|
add(inputs: readonly MessageInput[]): readonly Message[];
|
|
1663
1859
|
/**
|
|
1664
|
-
* Looks up one
|
|
1860
|
+
* Looks up one live message by id (`undefined` when absent).
|
|
1665
1861
|
*
|
|
1666
1862
|
* @param id - The message id to resolve
|
|
1667
1863
|
* @returns The {@link Message}, or `undefined` when absent
|
|
1668
1864
|
*/
|
|
1669
1865
|
message(id: string): Message | undefined;
|
|
1670
1866
|
/**
|
|
1671
|
-
* Lists every
|
|
1867
|
+
* Lists every live, uncompacted message in the tail, in insertion order.
|
|
1672
1868
|
*
|
|
1673
1869
|
* @returns The live tail, in insertion order
|
|
1674
1870
|
*/
|
|
1675
1871
|
messages(): readonly Message[];
|
|
1676
1872
|
/**
|
|
1677
|
-
* Removes one
|
|
1873
|
+
* Removes one live message by id, or a batch, from the tail — `true` only when every
|
|
1874
|
+
* supplied id was removed.
|
|
1678
1875
|
*
|
|
1679
1876
|
* @param id - One message id, or a batch
|
|
1680
1877
|
* @returns True when every supplied id was present and removed; false otherwise
|
|
1681
1878
|
*/
|
|
1682
1879
|
remove(id: string): boolean;
|
|
1683
1880
|
remove(ids: readonly string[]): boolean;
|
|
1684
|
-
/** Empties the live tail
|
|
1881
|
+
/** Empties the live tail, leaving the compacted `sections` untouched. */
|
|
1685
1882
|
clear(): void;
|
|
1686
1883
|
/**
|
|
1687
|
-
* Builds the model input for the next turn — each section as
|
|
1688
|
-
*
|
|
1884
|
+
* Builds the model input for the next turn — each section as one synthetic recap message,
|
|
1885
|
+
* its summary prefixed with `CONVERSATION_RECAP_PREFIX` so a small model reads it as a
|
|
1886
|
+
* recap rather than a literal turn, then the live tail verbatim; the rollup `summary` is
|
|
1887
|
+
* not injected.
|
|
1689
1888
|
*
|
|
1690
1889
|
* @returns `[...sections-as-summary-messages, ...live messages]`
|
|
1691
1890
|
*/
|
|
1692
1891
|
view(): readonly Message[];
|
|
1693
1892
|
/**
|
|
1694
|
-
* Folds the
|
|
1695
|
-
*
|
|
1893
|
+
* Folds the oldest `count - keep` live messages into a summarized {@link Section} through
|
|
1894
|
+
* the {@link ConversationSummaryHandler}, removes them from the live tail, regenerates the
|
|
1895
|
+
* rollup, and emits `summary` then `compact` — resolving `undefined` when nothing folds
|
|
1896
|
+
* (`count <= keep`). Throws a {@link import('./errors.js').ConversationError} when no
|
|
1897
|
+
* summarizer was supplied.
|
|
1696
1898
|
*
|
|
1697
1899
|
* @remarks
|
|
1698
|
-
*
|
|
1699
|
-
*
|
|
1700
|
-
* `undefined`. Otherwise it summarizes the slice into the section, removes those messages
|
|
1701
|
-
* from the live tail, regenerates the rollup (a second `summarize` over all sections), and
|
|
1702
|
-
* resolves the new section. Requires a {@link ConversationSummaryHandler} — THROWS a
|
|
1703
|
-
* {@link import('./errors.js').ConversationError} when none was supplied.
|
|
1900
|
+
* The effective `keep` comes from `options`, else the conversation's own. Regenerating the
|
|
1901
|
+
* rollup runs `summarize` again, over all sections.
|
|
1704
1902
|
*
|
|
1705
1903
|
* @remarks
|
|
1706
1904
|
* When a `sections` cap is set and the fold pushes the section count over it, an overflow
|
|
1707
|
-
* merge step folds the oldest sections into one — if
|
|
1905
|
+
* merge step folds the oldest sections into one — if that merge's `summarize` call throws,
|
|
1708
1906
|
* the merge is skipped (sections transiently sit at `cap + 1`, no loss) but the rollup still
|
|
1709
1907
|
* regenerates over the current unmerged sections (never left stale) before the error
|
|
1710
1908
|
* propagates; the next successful `compact()` self-heals the section count back to `cap`.
|
|
@@ -1714,35 +1912,38 @@ export declare interface ConversationInterface {
|
|
|
1714
1912
|
*/
|
|
1715
1913
|
compact(options?: CompactOptions): Promise<Section | undefined>;
|
|
1716
1914
|
/**
|
|
1717
|
-
* Returns a section's full original messages — a pure
|
|
1915
|
+
* Returns a section's full original messages — a pure read that emits `rehydrate`, empty for
|
|
1916
|
+
* an unknown id and never reinserting.
|
|
1718
1917
|
*
|
|
1719
1918
|
* @param id - The {@link Section} `id` to pull back
|
|
1720
1919
|
* @returns The section's retained original messages (empty when no such section)
|
|
1721
1920
|
*/
|
|
1722
1921
|
rehydrate(id: string): readonly Message[];
|
|
1723
1922
|
/**
|
|
1724
|
-
* Searches `content` for a case-insensitive substring across
|
|
1725
|
-
* retained originals
|
|
1923
|
+
* Searches `content` for a case-insensitive substring across every message — each section's
|
|
1924
|
+
* retained originals, then the live tail.
|
|
1726
1925
|
*
|
|
1727
1926
|
* @param query - The substring to match (case-insensitive)
|
|
1728
1927
|
* @returns The matching messages, sections' originals first then the live tail
|
|
1729
1928
|
*/
|
|
1730
1929
|
search(query: string): readonly Message[];
|
|
1731
1930
|
/**
|
|
1732
|
-
* Renders
|
|
1733
|
-
* conversation — a pure string
|
|
1734
|
-
*
|
|
1931
|
+
* Renders this conversation as a self-labeled, fenced provenance block to pull into another
|
|
1932
|
+
* conversation — a pure string with no model call: a leading
|
|
1933
|
+
* `[Reference — conversation "<label>" — NOT part of this conversation]` marker, the rollup
|
|
1934
|
+
* `Summary:` when `summary` is not `false` and a rollup exists, and the cherry-picked
|
|
1935
|
+
* excerpts (`- role: content`) when `messages` is supplied. `label` defaults to the `id`.
|
|
1735
1936
|
*
|
|
1736
1937
|
* @remarks
|
|
1737
1938
|
* The block leads with an unmistakable provenance marker
|
|
1738
1939
|
* (`[Reference — conversation "<label>" — NOT part of this conversation]`), then optionally
|
|
1739
|
-
* the rollup `Summary:` (when `options.summary !== false`
|
|
1940
|
+
* the rollup `Summary:` (when `options.summary !== false` and a rollup exists), then the
|
|
1740
1941
|
* cherry-picked `Relevant messages:` (each `- role: content`) when `options.messages` is
|
|
1741
1942
|
* supplied. The intended flow is to pull another conversation B into the active conversation
|
|
1742
1943
|
* A's active workspace: decide relevance from `B.summary`, select the few right turns with
|
|
1743
1944
|
* `B.search(query)` / `B.rehydrate(id)`, frame them here, then
|
|
1744
1945
|
* `A.context.workspaces.active?.write(\`conversation:${B.id}.md\`, B.reference({ label, messages }))`.
|
|
1745
|
-
* Keep the excerpts
|
|
1946
|
+
* Keep the excerpts cherry-picked, never B's whole history — this content enters another
|
|
1746
1947
|
* context a small model must read.
|
|
1747
1948
|
*
|
|
1748
1949
|
* @param options - The {@link ConversationReferenceOptions} (label / summary / cherry-picked messages)
|
|
@@ -1750,17 +1951,18 @@ export declare interface ConversationInterface {
|
|
|
1750
1951
|
*/
|
|
1751
1952
|
reference(options?: ConversationReferenceOptions): string;
|
|
1752
1953
|
/**
|
|
1753
|
-
* Serializes this conversation to a plain, JSON-serializable {@link ConversationSnapshot} —
|
|
1754
|
-
* `id`, the rollup `summary`, the compacted `sections`, and the live tail
|
|
1954
|
+
* Serializes this conversation to a plain, JSON-serializable {@link ConversationSnapshot} —
|
|
1955
|
+
* its `id`, the rollup `summary`, the compacted `sections`, and the live tail; the live
|
|
1956
|
+
* `summarize` / `keep` are configuration re-supplied on hydrate rather than serialized.
|
|
1755
1957
|
*
|
|
1756
1958
|
* @remarks
|
|
1757
|
-
* The container serializes
|
|
1959
|
+
* The container serializes itself (`{ id, summary, sections, messages: this.messages() }`) — the
|
|
1758
1960
|
* {@link ConversationStoreInterface} persistence seam's payload, the exact analogue of
|
|
1759
1961
|
* {@link import('@orkestrel/workspace').WorkspaceInterface}'s `snapshot`. The summarizer /
|
|
1760
|
-
* `keep` are
|
|
1761
|
-
*
|
|
1962
|
+
* `keep` are not serialized — they are live
|
|
1963
|
+
* config re-supplied on hydrate (a `ConversationSummaryHandler` is a function, not data). The snapshot
|
|
1762
1964
|
* is the durable analogue of the `snapshot` option: a {@link ConversationManagerInterface}
|
|
1763
|
-
*
|
|
1965
|
+
* hydrates a conversation from it through that seam (see {@link ConversationManagerInterface.open}).
|
|
1764
1966
|
* Pure — the sections + messages are already plain immutable records (so the snapshot
|
|
1765
1967
|
* `structuredClone`s / JSON-round-trips losslessly), and snapshotting mutates nothing.
|
|
1766
1968
|
*
|
|
@@ -1770,26 +1972,27 @@ export declare interface ConversationInterface {
|
|
|
1770
1972
|
}
|
|
1771
1973
|
|
|
1772
1974
|
/**
|
|
1773
|
-
* Registers {@link Conversation}s keyed by `id`, in insertion order,
|
|
1774
|
-
*
|
|
1775
|
-
* {@link import('../AgentContext.js').AgentContext} renders
|
|
1776
|
-
*
|
|
1777
|
-
*
|
|
1975
|
+
* Registers {@link Conversation}s keyed by `id`, in insertion order, with an active pointer —
|
|
1976
|
+
* the id-keyed store over the conversation layer, the `active` / `switch` seam the
|
|
1977
|
+
* {@link import('../AgentContext.js').AgentContext} renders, and the durable `open` / `save`
|
|
1978
|
+
* store seam. Event-free (a registry, like
|
|
1979
|
+
* {@link import('@orkestrel/workspace').WorkspaceManager}); the observability lives on each
|
|
1980
|
+
* {@link Conversation}.
|
|
1778
1981
|
*
|
|
1779
1982
|
* @remarks
|
|
1780
1983
|
* - **Registry.** Conversations live in an insertion-ordered `Map` keyed by `id`. `add(input?)`
|
|
1781
1984
|
* mints a {@link Conversation} (its `id` from `input` or `crypto.randomUUID()`), flowing the
|
|
1782
|
-
* manager's default `#summarize` / `#keep` in unless the `input`
|
|
1783
|
-
* it (an already-present `id`
|
|
1985
|
+
* manager's default `#summarize` / `#keep` in unless the `input` overrides them, and stores
|
|
1986
|
+
* it (an already-present `id` overwrites — last write wins). `count` is the map size,
|
|
1784
1987
|
* `conversation(id)` looks one up, `conversations()` lists them in insertion order.
|
|
1785
1988
|
* - **Active pointer.** `active` is the active conversation (the agent's message source the
|
|
1786
|
-
* context renders), `undefined` until the
|
|
1989
|
+
* context renders), `undefined` until the first `add` (which auto-activates it — a registry
|
|
1787
1990
|
* with conversations always has one active). A subsequent `add` leaves `active` unchanged.
|
|
1788
1991
|
* `switch(id)` re-points `active` to the conversation with `id` and returns it; an unknown `id`
|
|
1789
1992
|
* returns `undefined` and leaves `active` unchanged (the lenient lookup style — never throws,
|
|
1790
1993
|
* no new error code).
|
|
1791
|
-
* - **Removal.** `remove` drops one by id, or a batch — `true` only when
|
|
1792
|
-
* removed; removing the
|
|
1994
|
+
* - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id was
|
|
1995
|
+
* removed; removing the active conversation sets `active` to `undefined`. `clear` empties the registry
|
|
1793
1996
|
* and sets `active` to `undefined`.
|
|
1794
1997
|
* - **Event-free.** A purely registry store — no Emitter, no events (each conversation owns
|
|
1795
1998
|
* its own observable `emitter`).
|
|
@@ -1820,32 +2023,32 @@ export declare class ConversationManager implements ConversationManagerInterface
|
|
|
1820
2023
|
}
|
|
1821
2024
|
|
|
1822
2025
|
/**
|
|
1823
|
-
* Registers {@link ConversationInterface}s keyed by their `id`, in insertion order,
|
|
1824
|
-
*
|
|
1825
|
-
*
|
|
1826
|
-
* {@link import('@orkestrel/workspace').WorkspaceManagerInterface}); the
|
|
1827
|
-
* {@link ConversationInterface}.
|
|
2026
|
+
* Registers {@link ConversationInterface}s keyed by their `id`, in insertion order, with an active
|
|
2027
|
+
* pointer — the id-keyed store over the conversation layer, the `active` / `switch` seam the {@link
|
|
2028
|
+
* AgentContextInterface} renders, and the durable `open` / `save` store seam. Event-free (a
|
|
2029
|
+
* registry, like {@link import('@orkestrel/workspace').WorkspaceManagerInterface}); the
|
|
2030
|
+
* observability lives on each {@link ConversationInterface}.
|
|
1828
2031
|
*
|
|
1829
2032
|
* @remarks
|
|
1830
2033
|
* - **Registry.** `count` is how many are stored. `add(input?)` mints a
|
|
1831
2034
|
* {@link ConversationInterface} (its `id` from `input` or a random UUID), flowing the
|
|
1832
2035
|
* manager's default `summarize` / `keep` in unless the `input` overrides them; `add` of an
|
|
1833
|
-
* already-present `id`
|
|
2036
|
+
* already-present `id` overwrites it (last write wins). `conversation(id)` looks one up
|
|
1834
2037
|
* (`undefined` when absent); `conversations()` lists them in insertion order.
|
|
1835
2038
|
* - **Active pointer.** `active` is the active conversation (the agent's message source the
|
|
1836
|
-
* context renders), `undefined` until the
|
|
2039
|
+
* context renders), `undefined` until the first `add` (which auto-activates it — a registry
|
|
1837
2040
|
* with conversations always has one active). A subsequent `add` leaves `active` unchanged.
|
|
1838
2041
|
* `switch(id)` re-points `active` to the conversation with `id` and returns it; an unknown
|
|
1839
2042
|
* `id` returns `undefined` and leaves `active` unchanged (the lenient lookup style — never
|
|
1840
2043
|
* throws, no new error code).
|
|
1841
|
-
* - **Removal.** `remove` drops one by id, or a batch (array overload
|
|
1842
|
-
* only when
|
|
2044
|
+
* - **Removal.** `remove` drops one by id, or a batch (the array overload declared first) — `true`
|
|
2045
|
+
* only when every supplied id was removed; removing the active conversation sets `active` to `undefined`. `clear`
|
|
1843
2046
|
* empties the registry and sets `active` to `undefined`.
|
|
1844
2047
|
* - **Durable open / save (the optional `store` seam).** When a {@link ConversationStoreInterface}
|
|
1845
|
-
* is supplied (the `store` option), `open(id)`
|
|
2048
|
+
* is supplied (the `store` option), `open(id)` hydrates a conversation from the store on a registry
|
|
1846
2049
|
* miss (rebuilding it through the `snapshot` option, flowing the manager's
|
|
1847
|
-
* default `summarize` / `keep` in) and `save(id)`
|
|
1848
|
-
* {@link ConversationInterface.snapshot}. Both are
|
|
2050
|
+
* default `summarize` / `keep` in) and `save(id)` persists a registered conversation's
|
|
2051
|
+
* {@link ConversationInterface.snapshot}. Both are lenient without a store — `open` resolves only
|
|
1849
2052
|
* registered ids, `save` is a no-op (`false`) — consistent with the lenient `switch`. It mirrors
|
|
1850
2053
|
* the workspace package manager's `open` / `save` seam.
|
|
1851
2054
|
* - **Event-free.** A purely registry store — no Emitter, no events (each conversation owns
|
|
@@ -1855,47 +2058,66 @@ export declare interface ConversationManagerInterface {
|
|
|
1855
2058
|
readonly count: number;
|
|
1856
2059
|
/** Holds the active conversation — the agent's message source the context renders; `undefined` until the first `add`. */
|
|
1857
2060
|
readonly active: ConversationInterface | undefined;
|
|
2061
|
+
/** Looks up one conversation by id (`undefined` when absent). */
|
|
1858
2062
|
conversation(id: string): ConversationInterface | undefined;
|
|
2063
|
+
/** Lists every conversation, in insertion order. */
|
|
1859
2064
|
conversations(): readonly ConversationInterface[];
|
|
2065
|
+
/**
|
|
2066
|
+
* Mints a conversation, taking its `id` from the input or a fresh UUID and flowing the
|
|
2067
|
+
* manager's default `summarize` / `keep` in unless the input overrides them — auto-activates
|
|
2068
|
+
* the first, and an already-present `id` overwrites, last write wins.
|
|
2069
|
+
*/
|
|
1860
2070
|
add(input?: ConversationInput): ConversationInterface;
|
|
2071
|
+
/**
|
|
2072
|
+
* Re-points `active` at the conversation with `id` and returns it; an unknown `id` returns
|
|
2073
|
+
* `undefined` and leaves `active` unchanged, never throwing.
|
|
2074
|
+
*/
|
|
1861
2075
|
switch(id: string): ConversationInterface | undefined;
|
|
1862
2076
|
/**
|
|
1863
|
-
* Resolves a conversation by id
|
|
1864
|
-
* the optional {@link ConversationStoreInterface} (`store`)
|
|
2077
|
+
* Resolves a conversation by id and activates it — from the registry when present, else
|
|
2078
|
+
* hydrated from the optional {@link ConversationStoreInterface} (`store`); `undefined` when
|
|
2079
|
+
* it is neither registered nor stored.
|
|
1865
2080
|
*
|
|
1866
2081
|
* @remarks
|
|
1867
|
-
* - If `id` is
|
|
1868
|
-
* - Else if a `store` is set, `store.get(id)` is awaited; on a
|
|
2082
|
+
* - If `id` is already registered, it is activated (`switch`ed to) and returned — no store hit.
|
|
2083
|
+
* - Else if a `store` is set, `store.get(id)` is awaited; on a hit the snapshot is rehydrated
|
|
1869
2084
|
* into a fresh {@link ConversationInterface} through the `snapshot` option
|
|
1870
2085
|
* (`add({ snapshot, ... })`, flowing the manager's default `summarize` / `keep` in), which
|
|
1871
|
-
* registers
|
|
1872
|
-
* - Else (no store, or a store
|
|
2086
|
+
* registers and activates it, and it is returned.
|
|
2087
|
+
* - Else (no store, or a store miss) ⇒ `undefined` (lenient — no throw).
|
|
1873
2088
|
*
|
|
1874
2089
|
* @param id - The conversation id to open
|
|
1875
2090
|
* @returns The activated {@link ConversationInterface}, or `undefined` when neither registered nor stored
|
|
1876
2091
|
*/
|
|
1877
2092
|
open(id: string): Promise<ConversationInterface | undefined>;
|
|
1878
2093
|
/**
|
|
1879
|
-
* Persists a
|
|
1880
|
-
* {@link ConversationStoreInterface} (`store`)
|
|
2094
|
+
* Persists a registered conversation's {@link ConversationInterface.snapshot} to the optional
|
|
2095
|
+
* {@link ConversationStoreInterface} (`store`) — `true` when persisted, `false` when there is
|
|
2096
|
+
* no store or the id is unknown, and never throwing.
|
|
1881
2097
|
*
|
|
1882
2098
|
* @remarks
|
|
1883
|
-
* Lenient: when a `store` is set
|
|
1884
|
-
* awaited and `true` is returned; otherwise (no store,
|
|
2099
|
+
* Lenient: when a `store` is set and `id` is registered, `store.set(conversation.snapshot())` is
|
|
2100
|
+
* awaited and `true` is returned; otherwise (no store, or an unknown id) it is a no-op returning
|
|
1885
2101
|
* `false` — never a throw, consistent with the lenient `switch`.
|
|
1886
2102
|
*
|
|
1887
2103
|
* @param id - The id of the registered conversation to persist
|
|
1888
2104
|
* @returns True if the snapshot was persisted; false otherwise (no store, or an unknown id)
|
|
1889
2105
|
*/
|
|
1890
2106
|
save(id: string): Promise<boolean>;
|
|
2107
|
+
/**
|
|
2108
|
+
* Removes one conversation by id, or a batch — `true` only when every supplied id was
|
|
2109
|
+
* removed; clears `active` when a removed conversation was the active one.
|
|
2110
|
+
*/
|
|
1891
2111
|
remove(ids: readonly string[]): boolean;
|
|
1892
2112
|
remove(id: string): boolean;
|
|
2113
|
+
/** Removes every conversation and clears `active`. */
|
|
1893
2114
|
clear(): void;
|
|
1894
2115
|
}
|
|
1895
2116
|
|
|
1896
2117
|
/**
|
|
1897
|
-
* Configures `createConversationManager` — the default
|
|
1898
|
-
*
|
|
2118
|
+
* Configures `createConversationManager` — the default `ConversationSummaryHandler`, retained-tail
|
|
2119
|
+
* size, and `sections` cap the conversations it creates inherit, plus the optional durable `store`
|
|
2120
|
+
* backing `open` / `save`.
|
|
1899
2121
|
*
|
|
1900
2122
|
* @remarks
|
|
1901
2123
|
* `summarize` is the default summarizer flowed into every conversation the manager `add`s
|
|
@@ -1916,8 +2138,8 @@ export declare interface ConversationManagerOptions {
|
|
|
1916
2138
|
/**
|
|
1917
2139
|
* Holds the optional durable {@link ConversationStoreInterface} backing
|
|
1918
2140
|
* {@link ConversationManagerInterface.open} / {@link ConversationManagerInterface.save} — a memory
|
|
1919
|
-
* / JSON / SQLite / IndexedDB store a conversation is
|
|
1920
|
-
*
|
|
2141
|
+
* / JSON / SQLite / IndexedDB store a conversation is hydrated from (`open` a registry-miss) and
|
|
2142
|
+
* persisted to (`save`). Omitted ⇒ the manager is registry-only: `open` resolves only what is
|
|
1921
2143
|
* already registered, and `save` is a no-op (`false`). The exact analogue of
|
|
1922
2144
|
* {@link import('@orkestrel/workspace').WorkspaceManagerOptions}'s `store`.
|
|
1923
2145
|
*/
|
|
@@ -1926,25 +2148,26 @@ export declare interface ConversationManagerOptions {
|
|
|
1926
2148
|
|
|
1927
2149
|
/**
|
|
1928
2150
|
* Configures `createConversation` — the optional `id`, the reserved `on` hooks, the
|
|
1929
|
-
* provider-agnostic `summarize` seam,
|
|
2151
|
+
* provider-agnostic `summarize` seam, the retained-tail size, an optional cap on the compacted
|
|
2152
|
+
* `sections` list, and a {@link ConversationSnapshot} to hydrate from.
|
|
1930
2153
|
*
|
|
1931
2154
|
* @remarks
|
|
1932
2155
|
* `id` is the conversation's identity (a random UUID when omitted). `on` is the reserved
|
|
1933
2156
|
* listener key (initial {@link ConversationEventMap} listeners). `summarize` is the
|
|
1934
|
-
* {@link ConversationSummaryHandler} compaction needs —
|
|
2157
|
+
* {@link ConversationSummaryHandler} compaction needs — absent ⇒ `compact()` throws a
|
|
1935
2158
|
* {@link import('./errors.js').ConversationError} (a conversation can still store + view a
|
|
1936
2159
|
* live tail; it cannot fold). `keep` is how many recent live messages a `compact()`
|
|
1937
|
-
* retains
|
|
2160
|
+
* retains verbatim (folding only the older ones); it defaults to
|
|
1938
2161
|
* {@link import('./constants.js').DEFAULT_CONVERSATION_KEEP} (`0` — a manual `compact()`
|
|
1939
|
-
* folds the
|
|
2162
|
+
* folds the whole current live tail into one section). `sections` is an optional cap on the
|
|
1940
2163
|
* compacted `sections` list — when set (`>= 1`), a `compact()` that would leave more than
|
|
1941
|
-
* `sections` sections
|
|
2164
|
+
* `sections` sections folds the oldest overflow into one merged section so the list never
|
|
1942
2165
|
* exceeds `sections`, emitting `collapse`; omitted ⇒ unlimited (the prior behavior).
|
|
1943
|
-
* `snapshot` is the
|
|
1944
|
-
* `summary`, compacted `sections`, and live tail are
|
|
2166
|
+
* `snapshot` is the hydration seam — a {@link ConversationSnapshot} whose `id`, rollup
|
|
2167
|
+
* `summary`, compacted `sections`, and live tail are restored into the new conversation, with
|
|
1945
2168
|
* the live `summarize` / `keep` / `on` supplied alongside it (a summarizer is a function, not
|
|
1946
|
-
* serialized data). Restoring is
|
|
1947
|
-
*
|
|
2169
|
+
* serialized data). Restoring is silent (no events — nothing was edited), and a `snapshot.id`
|
|
2170
|
+
* wins over `id` (the snapshot is the conversation's identity). It is what lets
|
|
1948
2171
|
* `createConversation` hydrate, and what a {@link ConversationManagerInterface.open} reads a
|
|
1949
2172
|
* stored snapshot back through.
|
|
1950
2173
|
*/
|
|
@@ -1953,7 +2176,7 @@ export declare interface ConversationOptions {
|
|
|
1953
2176
|
readonly on?: EmitterHooks<ConversationEventMap>;
|
|
1954
2177
|
/** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
|
|
1955
2178
|
readonly error?: EmitterErrorHandler;
|
|
1956
|
-
/** Supplies the summarizer compaction needs;
|
|
2179
|
+
/** Supplies the summarizer compaction needs; absent ⇒ `compact()` throws a `ConversationError`. */
|
|
1957
2180
|
readonly summarize?: ConversationSummaryHandler;
|
|
1958
2181
|
/** Keeps this many recent live messages verbatim on `compact`; defaults to `DEFAULT_CONVERSATION_KEEP` (`0`). */
|
|
1959
2182
|
readonly keep?: number;
|
|
@@ -1964,22 +2187,23 @@ export declare interface ConversationOptions {
|
|
|
1964
2187
|
}
|
|
1965
2188
|
|
|
1966
2189
|
/**
|
|
1967
|
-
* Configures {@link ConversationInterface.reference} — how to render
|
|
1968
|
-
* self-labeled, fenced
|
|
1969
|
-
*
|
|
2190
|
+
* Configures {@link ConversationInterface.reference} — how to render one conversation as a
|
|
2191
|
+
* self-labeled, fenced provenance block to pull into another conversation by writing it to the
|
|
2192
|
+
* active context's active workspace: `label` defaults to the `id`, `summary` defaults to `true`,
|
|
2193
|
+
* and `messages` are cherry-picked excerpts defaulting to none.
|
|
1970
2194
|
*
|
|
1971
2195
|
* @remarks
|
|
1972
|
-
* The rendered block is a cross-conversation reference a
|
|
1973
|
-
* material,
|
|
2196
|
+
* The rendered block is a cross-conversation reference a small model must read as foreign
|
|
2197
|
+
* material, not as part of the live thread — so every member keeps it concise and unmistakably
|
|
1974
2198
|
* attributed:
|
|
1975
|
-
* - `label` — the human
|
|
2199
|
+
* - `label` — the human provenance name shown in the block's leading marker (for example `'planning'`);
|
|
1976
2200
|
* defaults to the conversation's own `id`. It is what the model attributes the content to.
|
|
1977
2201
|
* - `summary` — whether to include the conversation's rollup `summary` (its summary-of-summaries)
|
|
1978
|
-
* in the block; defaults to `true` (the rollup is included
|
|
2202
|
+
* in the block; defaults to `true` (the rollup is included when one exists — `undefined` until
|
|
1979
2203
|
* the first compaction omits the `Summary:` line). Pass `false` to exclude it.
|
|
1980
|
-
* - `messages` — the
|
|
1981
|
-
*
|
|
1982
|
-
* (select the few relevant turns),
|
|
2204
|
+
* - `messages` — the cherry-picked excerpts to include (each rendered `role: content`), default
|
|
2205
|
+
* none. The intended source is the conversation's own `search(query)` / `rehydrate(id)` output
|
|
2206
|
+
* (select the few relevant turns), not its whole history — dumping every message defeats the
|
|
1983
2207
|
* point (it re-bloats the destination context a small model then has to wade through).
|
|
1984
2208
|
*/
|
|
1985
2209
|
export declare interface ConversationReferenceOptions {
|
|
@@ -1998,11 +2222,11 @@ export declare interface ConversationReferenceOptions {
|
|
|
1998
2222
|
* {@link import('@orkestrel/workspace').WorkspaceSnapshot}.
|
|
1999
2223
|
*
|
|
2000
2224
|
* @remarks
|
|
2001
|
-
* Pure JSON
|
|
2002
|
-
* {@link Message} is already a
|
|
2225
|
+
* Pure JSON data (no class instances, no functions): each {@link Section} and
|
|
2226
|
+
* {@link Message} is already a plain record that `structuredClone`s / JSON-round-trips
|
|
2003
2227
|
* losslessly. The snapshot carries the rollup `summary` (a summary-of-summaries; `undefined` until
|
|
2004
|
-
* the first compaction), the compacted `sections` (each
|
|
2005
|
-
* live uncompacted tail `messages` — but
|
|
2228
|
+
* the first compaction), the compacted `sections` (each retaining its folded originals), and the
|
|
2229
|
+
* live uncompacted tail `messages` — but not the `summarize` / `keep`, which are live config
|
|
2006
2230
|
* re-supplied on hydrate (a summarizer is a function, not serializable data). The snapshot the
|
|
2007
2231
|
* container produces from itself ({@link ConversationInterface.snapshot}); the durable analogue of
|
|
2008
2232
|
* the {@link ConversationOptions.snapshot} hydration seam. A {@link ConversationManagerInterface}
|
|
@@ -2014,23 +2238,24 @@ export declare interface ConversationSnapshot {
|
|
|
2014
2238
|
readonly id: string;
|
|
2015
2239
|
/** Holds the rollup (a summary-of-summaries); `undefined` until the first compaction. */
|
|
2016
2240
|
readonly summary?: string;
|
|
2017
|
-
/** Lists the compacted history, oldest → newest (each section
|
|
2241
|
+
/** Lists the compacted history, oldest → newest (each section retains its folded originals). */
|
|
2018
2242
|
readonly sections: readonly Section[];
|
|
2019
2243
|
/** Lists the live uncompacted tail, in insertion order. */
|
|
2020
2244
|
readonly messages: readonly Message[];
|
|
2021
2245
|
}
|
|
2022
2246
|
|
|
2023
2247
|
/**
|
|
2024
|
-
* Represents one row of the table a
|
|
2025
|
-
*
|
|
2026
|
-
*
|
|
2027
|
-
*
|
|
2248
|
+
* Represents one row of the table a {@link
|
|
2249
|
+
* import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore} persists
|
|
2250
|
+
* — a conversation `id` plus its {@link ConversationSnapshot} held as one opaque JSON column, read
|
|
2251
|
+
* back as `unknown` and narrowed on `get`. The exact analogue of {@link
|
|
2252
|
+
* import('@orkestrel/workspace').WorkspaceSnapshotRow}.
|
|
2028
2253
|
*
|
|
2029
2254
|
* @remarks
|
|
2030
2255
|
* The Database twin of {@link ConversationStoreInterface} stores the snapshot whole (the `snapshot`
|
|
2031
2256
|
* column is a `rawShape`, an opaque JSON blob — exactly as
|
|
2032
2257
|
* {@link import('@orkestrel/workspace').WorkspaceSnapshotRow} stores a workspace snapshot), so the
|
|
2033
|
-
* row type stays
|
|
2258
|
+
* row type stays flat and the sections/messages snapshot shape never
|
|
2034
2259
|
* forces the contract to `Infer` it. The column therefore reads back as the broad `unknown`; the
|
|
2035
2260
|
* store narrows it to a {@link ConversationSnapshot} on `get`
|
|
2036
2261
|
* ({@link import('./validators.js').isConversationSnapshot}, the total boundary guard). `id`
|
|
@@ -2044,30 +2269,30 @@ export declare interface ConversationSnapshotRow {
|
|
|
2044
2269
|
}
|
|
2045
2270
|
|
|
2046
2271
|
/**
|
|
2047
|
-
* Persists a {@link ConversationSnapshot} durably —
|
|
2048
|
-
*
|
|
2049
|
-
*
|
|
2272
|
+
* Persists a {@link ConversationSnapshot} durably — the async `get` / `set` / `delete` primitives,
|
|
2273
|
+
* keyed by a conversation id and holding no expiry, the exact analogue of {@link
|
|
2274
|
+
* import('@orkestrel/workspace').WorkspaceStoreInterface}.
|
|
2050
2275
|
*
|
|
2051
2276
|
* @remarks
|
|
2052
2277
|
* The store persists the {@link ConversationSnapshot} — the self-contained, pure-JSON conversation
|
|
2053
|
-
* state — so a JSON / SQLite / IndexedDB backend swaps in
|
|
2278
|
+
* state — so a JSON / SQLite / IndexedDB backend swaps in without touching the manager or the
|
|
2054
2279
|
* conversation: the in-memory default
|
|
2055
2280
|
* {@link import('./conversations/stores/MemoryConversationStore.js').MemoryConversationStore} and its
|
|
2056
2281
|
* driver-pluggable twin
|
|
2057
2282
|
* {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore} (the
|
|
2058
|
-
* snapshot as one opaque JSON column) share
|
|
2283
|
+
* snapshot as one opaque JSON column) share this one interface. Hydration is not a store concern
|
|
2059
2284
|
* — a {@link ConversationManagerInterface} reads a snapshot back and rebuilds the live conversation
|
|
2060
2285
|
* through the {@link ConversationOptions.snapshot} seam (re-supplying the live `summarize` / `keep`; see
|
|
2061
2286
|
* {@link ConversationManagerInterface.open} / {@link ConversationManagerInterface.save}).
|
|
2062
2287
|
*
|
|
2063
2288
|
* Every primitive is async (a `Promise`), so a durable backend (a database round-trip) fits the
|
|
2064
|
-
* same shape as the memory one. The snapshot carries its
|
|
2289
|
+
* same shape as the memory one. The snapshot carries its own id, so `set` takes no separate id
|
|
2065
2290
|
* param (mirroring
|
|
2066
|
-
* {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`).
|
|
2067
|
-
* there is
|
|
2291
|
+
* {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`). Unlike a session store
|
|
2292
|
+
* there is no idle-TTL
|
|
2068
2293
|
* / eviction — a persisted conversation lives until an explicit `delete`. It is concrete over
|
|
2069
2294
|
* {@link ConversationSnapshot} — no generic parameter, because the
|
|
2070
|
-
* snapshot is the
|
|
2295
|
+
* snapshot is the one payload a conversation store persists.
|
|
2071
2296
|
*/
|
|
2072
2297
|
export declare interface ConversationStoreInterface {
|
|
2073
2298
|
/**
|
|
@@ -2093,10 +2318,10 @@ export declare interface ConversationStoreInterface {
|
|
|
2093
2318
|
}
|
|
2094
2319
|
|
|
2095
2320
|
/**
|
|
2096
|
-
* Summarizes a conversation, provider-agnostically — the seam the agent
|
|
2097
|
-
*
|
|
2098
|
-
*
|
|
2099
|
-
*
|
|
2321
|
+
* Summarizes a conversation, provider-agnostically — the seam the agent runtime supplies so core
|
|
2322
|
+
* never imports a provider. Given the folded messages, it resolves their digest, the model-written
|
|
2323
|
+
* summary used to summarize a compacted {@link Section} and to regenerate a {@link
|
|
2324
|
+
* ConversationInterface}'s rollup `summary`.
|
|
2100
2325
|
*
|
|
2101
2326
|
* @remarks
|
|
2102
2327
|
* The agent runtime builds one from its `ProviderInterface` (for example
|
|
@@ -2117,10 +2342,10 @@ export declare type ConversationSummaryHandler = (messages: readonly Message[])
|
|
|
2117
2342
|
* `generate` and a live `stream`.
|
|
2118
2343
|
*
|
|
2119
2344
|
* @remarks
|
|
2120
|
-
* One private loop drives the turn; `generate`
|
|
2345
|
+
* One private loop drives the turn; `generate` drains the same stream `stream`
|
|
2121
2346
|
* exposes, so they can never diverge. Each turn is bounded by one cancel folded from
|
|
2122
2347
|
* `signal` + `timeout` + `budget` (through `AbortSignal.any`) — any trip (or `abort()`)
|
|
2123
|
-
* commits a
|
|
2348
|
+
* commits a partial result (the stream's `result` resolves on a cancel, rejects only
|
|
2124
2349
|
* on a genuine provider / tool error). The `scheduler` paces between turns; tool
|
|
2125
2350
|
* iteration is capped at `limit` (default `DEFAULT_AGENT_LIMIT`). Tools are advertised
|
|
2126
2351
|
* structurally through `context.tools.definitions()`. Two observation surfaces: the
|
|
@@ -2155,19 +2380,20 @@ export declare type ConversationSummaryHandler = (messages: readonly Message[])
|
|
|
2155
2380
|
export declare function createAgent(provider: ProviderInterface, options?: AgentOptions): AgentInterface;
|
|
2156
2381
|
|
|
2157
2382
|
/**
|
|
2158
|
-
* Creates a richer turn context — an {@link AgentContextInterface} assembling a provider
|
|
2159
|
-
*
|
|
2160
|
-
* the conversation
|
|
2383
|
+
* Creates a richer turn context — an {@link AgentContextInterface} assembling a provider request
|
|
2384
|
+
* from the optional system prompt, the instruction registry, the workspace registry (the only
|
|
2385
|
+
* document channel), the conversation registry that is its `messages` source, the tool registry,
|
|
2386
|
+
* and the active scope, which `build()` folds into the next turn's input.
|
|
2161
2387
|
*
|
|
2162
2388
|
* @remarks
|
|
2163
2389
|
* `system` is the optional system prompt; `tools` / `instructions` / `workspaces` are pre-built
|
|
2164
|
-
* managers to reuse (empty ones are created when omitted, so `context.workspaces` is
|
|
2390
|
+
* managers to reuse (empty ones are created when omitted, so `context.workspaces` is always
|
|
2165
2391
|
* present); `scope` is the initial active filter (`undefined` ⇒ no filtering, changeable afterwards
|
|
2166
2392
|
* through `context.apply(...)`). The `messages` store is always fresh. `build()` folds the scoped
|
|
2167
|
-
* instructions —
|
|
2393
|
+
* instructions — plus the active workspace's scope-filtered text files (fenced) — into one leading
|
|
2168
2394
|
* `system` message and appends the scoped conversation (attaching the active workspace's
|
|
2169
2395
|
* scope-filtered image files' `base64` payload to the last user message), built fresh each call; the active
|
|
2170
|
-
* workspace is the
|
|
2396
|
+
* workspace is the sole document/image context. Tools are advertised structurally (through
|
|
2171
2397
|
* `tools.definitions()`, scope-filtered by the loop), never serialized into the prompt.
|
|
2172
2398
|
*
|
|
2173
2399
|
* @param options - Optional `system` / `tools` / `instructions` / `workspaces` / `scope`
|
|
@@ -2188,7 +2414,7 @@ export declare function createAgentContext(options?: AgentContextOptions): Agent
|
|
|
2188
2414
|
|
|
2189
2415
|
/**
|
|
2190
2416
|
* Creates a durable, bounded-concurrency agent-job queue — a {@link QueueInterface} over
|
|
2191
|
-
* serializable {@link AgentJobInput}s that
|
|
2417
|
+
* serializable {@link AgentJobInput}s that composes `createQueue`: each job is rehydrated
|
|
2192
2418
|
* through the `registry` into a live {@link AgentInterface}, run to its {@link AgentResult},
|
|
2193
2419
|
* and subjected to the partial-as-configurable-failure policy.
|
|
2194
2420
|
*
|
|
@@ -2201,9 +2427,9 @@ export declare function createAgentContext(options?: AgentContextOptions): Agent
|
|
|
2201
2427
|
* (for example `createMemoryQueueStore` / `createDatabaseQueueStore`) persists outstanding
|
|
2202
2428
|
* jobs; `restore()` re-enqueues them after a restart and the `registry` rehydrates the
|
|
2203
2429
|
* live pieces from the names — so a job survives a crash.
|
|
2204
|
-
* - **Partial policy.** A partial result
|
|
2430
|
+
* - **Partial policy.** A partial result throws an
|
|
2205
2431
|
* {@link import('./errors.js').AgentJobError} by default, so a job cancelled by its
|
|
2206
|
-
* attempt deadline / a queue abort
|
|
2432
|
+
* attempt deadline / a queue abort retries while attempts remain; `partial: true`
|
|
2207
2433
|
* resolves the partial as success instead.
|
|
2208
2434
|
* - **Cancellation threads through.** The handler passes `context.signal` into
|
|
2209
2435
|
* `registry.build`, so a queue `abort()` or a per-attempt timeout cancels the in-flight
|
|
@@ -2234,7 +2460,7 @@ export declare function createAgentQueue(options: AgentQueueOptions): QueueInter
|
|
|
2234
2460
|
*
|
|
2235
2461
|
* @remarks
|
|
2236
2462
|
* `providers` is required; `tools` / `authorities` / `schedulers` are optional pools.
|
|
2237
|
-
* The accessors (`provider` / `tool` / `authority` / `scheduler`)
|
|
2463
|
+
* The accessors (`provider` / `tool` / `authority` / `scheduler`) throw an
|
|
2238
2464
|
* {@link import('./errors.js').AgentError} carrying `code: 'REGISTRY'` and the message
|
|
2239
2465
|
* `unknown <category>: <name>` on an unregistered name — a misconfigured or crash-restored
|
|
2240
2466
|
* job fails loudly rather than running with a missing dependency. `build(input, signal)`
|
|
@@ -2263,21 +2489,21 @@ export declare function createAgentRegistry(options: AgentRegistryOptions): Agen
|
|
|
2263
2489
|
|
|
2264
2490
|
/**
|
|
2265
2491
|
* Creates an agent-job runner — a {@link RunnerInterface} over serializable
|
|
2266
|
-
* {@link AgentJobInput}s that
|
|
2267
|
-
*
|
|
2268
|
-
*
|
|
2492
|
+
* {@link AgentJobInput}s that composes `createRunner` (one-shot, ordered, fail-fast), each unit
|
|
2493
|
+
* rehydrated through the `registry` and subjected to the partial policy. The runner also carries
|
|
2494
|
+
* sub-agent fan-out: a parent job's handler can `controller.spawn(childJob)`.
|
|
2269
2495
|
*
|
|
2270
2496
|
* @remarks
|
|
2271
2497
|
* - **Composes the substrate (no new engine).** Bounded `concurrency`, `retries`, the
|
|
2272
2498
|
* per-attempt `timeout`, ordered results, and fail-fast are all the backing Runner's;
|
|
2273
2499
|
* the handler adds only rehydration + the partial policy.
|
|
2274
2500
|
* - **Sub-agent fan-out.** Each unit's handler receives a `ControllerInterface` whose
|
|
2275
|
-
* `spawn(childJob)` launches a
|
|
2501
|
+
* `spawn(childJob)` launches a child agent job through the same bounded queue (the
|
|
2276
2502
|
* child's result joins the run after the declared units, in spawn order). On a bounded
|
|
2277
|
-
* runner,
|
|
2503
|
+
* runner, fan out and return — do not inline-`await` a spawn from within the handler (a
|
|
2278
2504
|
* slot-holding handler awaiting its own spawn can deadlock; see `ControllerInterface`).
|
|
2279
2505
|
* - **Partial policy + cancellation.** Same as `createAgentQueue`: a partial result
|
|
2280
|
-
*
|
|
2506
|
+
* throws by default (the run's fail-fast engages), `partial: true` resolves it; the
|
|
2281
2507
|
* handler threads `controller.signal` into `registry.build`, so a runner abort / a
|
|
2282
2508
|
* per-attempt timeout cancels the agent.
|
|
2283
2509
|
*
|
|
@@ -2305,11 +2531,11 @@ export declare function createAgentRunner(options: AgentRunnerOptions): RunnerIn
|
|
|
2305
2531
|
* to the configured default when none match.
|
|
2306
2532
|
*
|
|
2307
2533
|
* @remarks
|
|
2308
|
-
* `rules` are evaluated in order — the
|
|
2309
|
-
* rule
|
|
2534
|
+
* `rules` are evaluated in order — the first whose `match` is true decides (a matched
|
|
2535
|
+
* rule allows unless its `allowed` is explicitly `false`). When no rule matches, the
|
|
2310
2536
|
* `fallback` decides; it defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }`
|
|
2311
|
-
* (allow-unmatched — a rules list of denials acts as a
|
|
2312
|
-
* `allowed: false` `fallback` to flip the gate to deny-by-default (an
|
|
2537
|
+
* (allow-unmatched — a rules list of denials acts as a denylist). Pass an
|
|
2538
|
+
* `allowed: false` `fallback` to flip the gate to deny-by-default (an allowlist). Wire
|
|
2313
2539
|
* the result into `createAgent` through `AgentOptions.authority`: a denied call is fed back
|
|
2314
2540
|
* to the model as a denial `ToolResult` (not executed, no budget cost), so the model
|
|
2315
2541
|
* can react. Synchronous — `evaluate` returns the verdict directly.
|
|
@@ -2339,7 +2565,7 @@ export declare function createAuthority(options?: AuthorityOptions): AuthorityIn
|
|
|
2339
2565
|
* Write and read are decoupled, so the producer never waits for a consumer: an agent's eager
|
|
2340
2566
|
* pump writes each chunk into one, which is why a run's `result` settles whether or not the
|
|
2341
2567
|
* live events are drained. A value pushed at an already-parked consumer is delivered, buffered
|
|
2342
|
-
* values are yielded before the end is reported, and the
|
|
2568
|
+
* values are yielded before the end is reported, and the first failure wins.
|
|
2343
2569
|
*
|
|
2344
2570
|
* @typeParam T - The value type the channel carries
|
|
2345
2571
|
* @returns A fresh, empty {@link ChannelInterface}
|
|
@@ -2360,16 +2586,16 @@ export declare function createChannel<T>(): ChannelInterface<T>;
|
|
|
2360
2586
|
|
|
2361
2587
|
/**
|
|
2362
2588
|
* Creates a conversation — a {@link ConversationInterface} grouping messages above a flat
|
|
2363
|
-
* message store it
|
|
2589
|
+
* message store it owns directly, with compaction into summarized sections, a regenerated
|
|
2364
2590
|
* rollup `summary`, on-demand `rehydrate`, and substring `search`, driven by a
|
|
2365
2591
|
* provider-agnostic {@link ConversationSummaryHandler} seam.
|
|
2366
2592
|
*
|
|
2367
2593
|
* @remarks
|
|
2368
2594
|
* Append turns through the conversation's own `add` (the live tail it owns); `view()` is the model input
|
|
2369
2595
|
* (each section as a summary message, then the live tail). `compact()` folds the older live
|
|
2370
|
-
* messages into a summarized {@link Section} and regenerates the rollup — it
|
|
2596
|
+
* messages into a summarized {@link Section} and regenerates the rollup — it requires
|
|
2371
2597
|
* a `summarize` (omitted ⇒ `compact()` throws a `ConversationError`); `keep` retains a recent
|
|
2372
|
-
* tail (default `DEFAULT_CONVERSATION_KEEP` — fold
|
|
2598
|
+
* tail (default `DEFAULT_CONVERSATION_KEEP` — fold all). `rehydrate(id)` / `search(query)` read
|
|
2373
2599
|
* the retained originals. Observable (`emitter` — `compact` / `summary` / `rehydrate`), wired
|
|
2374
2600
|
* through the reserved `on` option; the emitter isolates a listener throw and routes it to
|
|
2375
2601
|
* its `error` handler (the `error` option), so it can never corrupt a compaction.
|
|
@@ -2377,41 +2603,61 @@ export declare function createChannel<T>(): ChannelInterface<T>;
|
|
|
2377
2603
|
* @param options - Optional `id` / `on` hooks + the `summarize` seam + `keep` (see {@link ConversationOptions})
|
|
2378
2604
|
* @returns A working {@link ConversationInterface}
|
|
2379
2605
|
*
|
|
2380
|
-
* @example
|
|
2606
|
+
* @example Conversations & compaction
|
|
2381
2607
|
* ```ts
|
|
2382
2608
|
* import type { ProviderInterface } from '@orkestrel/agent'
|
|
2383
2609
|
* import { createConversation } from '@orkestrel/agent'
|
|
2384
2610
|
*
|
|
2385
2611
|
* declare const provider: ProviderInterface // any concrete implementation supplied by the host app
|
|
2612
|
+
* // The summarizer seam — built from the provider by the runtime; core stays provider-agnostic.
|
|
2613
|
+
* // Append the instruction as the FINAL user turn: a chat model emits nothing when the prompt
|
|
2614
|
+
* // ends on an assistant turn, so a leading-system instruction is unreliable.
|
|
2386
2615
|
* const conversation = createConversation({
|
|
2387
|
-
* // Append the instruction as the FINAL user turn — a chat model emits nothing when the
|
|
2388
|
-
* // prompt ends on an assistant turn, so a leading-system instruction is unreliable.
|
|
2389
2616
|
* summarize: async (messages) =>
|
|
2390
|
-
* (
|
|
2617
|
+
* (
|
|
2618
|
+
* await provider.generate(
|
|
2619
|
+
* [
|
|
2620
|
+
* ...messages,
|
|
2621
|
+
* { id: 's', role: 'user', content: 'Summarize the conversation so far concisely.' },
|
|
2622
|
+
* ],
|
|
2623
|
+
* AbortSignal.timeout(30_000),
|
|
2624
|
+
* )
|
|
2625
|
+
* ).content,
|
|
2626
|
+
* keep: 2, // retain the two most recent turns verbatim on each compaction
|
|
2391
2627
|
* })
|
|
2392
|
-
* conversation.add(
|
|
2393
|
-
*
|
|
2628
|
+
* conversation.add([
|
|
2629
|
+
* { role: 'user', content: 'My name is Ada.' },
|
|
2630
|
+
* { role: 'assistant', content: 'Nice to meet you, Ada.' },
|
|
2631
|
+
* { role: 'user', content: 'What did I say my name was?' },
|
|
2632
|
+
* ])
|
|
2633
|
+
*
|
|
2634
|
+
* const section = await conversation.compact() // folds the older turns → a summarized section
|
|
2635
|
+
* conversation.view() // [<section summary message>, ...the retained recent tail] — the model input
|
|
2636
|
+
* conversation.summary // the regenerated rollup (a summary-of-summaries over all sections)
|
|
2637
|
+
* conversation.search('ada') // case-insensitive across sections' originals + the live tail
|
|
2638
|
+
* section && conversation.rehydrate(section.id) // the section's full original messages (a pure read)
|
|
2394
2639
|
* ```
|
|
2395
2640
|
*/
|
|
2396
2641
|
export declare function createConversation(options?: ConversationOptions): ConversationInterface;
|
|
2397
2642
|
|
|
2398
2643
|
/**
|
|
2399
2644
|
* Creates a conversation registry — a {@link ConversationManagerInterface} holding
|
|
2400
|
-
* {@link ConversationInterface}s keyed by their `id
|
|
2645
|
+
* {@link ConversationInterface}s keyed by their `id`, in insertion order, with an active pointer:
|
|
2401
2646
|
* the id-keyed store over the conversation layer plus the `active` / `switch` seam the context
|
|
2402
|
-
* renders.
|
|
2647
|
+
* renders. `add` auto-activates the first conversation and flows the registry's default
|
|
2648
|
+
* `summarize` / `keep` into every conversation it creates.
|
|
2403
2649
|
*
|
|
2404
2650
|
* @remarks
|
|
2405
2651
|
* Starts empty; `add(input?)` mints a {@link ConversationInterface} (its `id` from the input
|
|
2406
2652
|
* or a random UUID), flowing the manager's default `summarize` / `keep` in unless the input
|
|
2407
2653
|
* overrides them, and stores it (an already-present `id` overwrites — last write wins) — and
|
|
2408
|
-
*
|
|
2654
|
+
* auto-activates the first one (a registry with conversations always has one `active`); a later
|
|
2409
2655
|
* `add` leaves `active` unchanged. `switch(id)` re-points `active` (an unknown `id` returns
|
|
2410
2656
|
* `undefined`, leaving `active` unchanged — lenient, never throws); `conversation(id)` /
|
|
2411
2657
|
* `conversations()` look up; `remove` (one or a batch) reports `true` only when every supplied id
|
|
2412
|
-
* was removed
|
|
2658
|
+
* was removed and clears `active` if it was a removed one; `clear` empties it and clears `active`.
|
|
2413
2659
|
* Event-free
|
|
2414
|
-
* (each conversation owns its own observable `emitter`). A conversation created with
|
|
2660
|
+
* (each conversation owns its own observable `emitter`). A conversation created with neither a
|
|
2415
2661
|
* manager default nor a per-`add` `summarize` cannot `compact` (it throws a `ConversationError`).
|
|
2416
2662
|
*
|
|
2417
2663
|
* @param options - Optional default `summarize` / `keep` (see {@link ConversationManagerOptions})
|
|
@@ -2429,23 +2675,24 @@ export declare function createConversation(options?: ConversationOptions): Conve
|
|
|
2429
2675
|
export declare function createConversationManager(options?: ConversationManagerOptions): ConversationManagerInterface;
|
|
2430
2676
|
|
|
2431
2677
|
/**
|
|
2432
|
-
* Creates a {@link DatabaseConversationStore} over any {@link DriverInterface}
|
|
2433
|
-
* driver-pluggable backing for the conversation persistence
|
|
2678
|
+
* Creates a {@link DatabaseConversationStore} over any {@link DriverInterface}, defaulting to
|
|
2679
|
+
* `createMemoryDriver()` — the durable, driver-pluggable backing for the conversation persistence
|
|
2680
|
+
* seam, holding each snapshot as one opaque JSON column and standing as the opt-in twin of
|
|
2434
2681
|
* {@link createMemoryConversationStore}. The exact twin of
|
|
2435
2682
|
* {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore}.
|
|
2436
2683
|
*
|
|
2437
2684
|
* @remarks
|
|
2438
2685
|
* Builds a one-table database (`conversations`, keyed by `id`) over the supplied driver, the snapshot
|
|
2439
|
-
* held as
|
|
2686
|
+
* held as one opaque JSON column — the column map is `{ id; snapshot }` where `snapshot` is a
|
|
2440
2687
|
* `rawShape` (a JSON blob), exactly as
|
|
2441
2688
|
* {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore} stores its snapshot. The
|
|
2442
|
-
* snapshot is already a
|
|
2443
|
-
*
|
|
2444
|
-
* {@link import('./validators.js').isConversationSnapshot}). The `driver`
|
|
2445
|
-
* {@link createMemoryDriver}, so the store
|
|
2689
|
+
* snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is lossless
|
|
2690
|
+
* and keeps the row type flat (the column reads back as `unknown`, narrowed on `get` by
|
|
2691
|
+
* {@link import('./validators.js').isConversationSnapshot}). The `driver` defaults to
|
|
2692
|
+
* {@link createMemoryDriver}, so the store also works in memory out of the box; pass a server
|
|
2446
2693
|
* `createJSONDriver` / `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —
|
|
2447
2694
|
* the durability is the driver's job, the store engine is shared. It swaps in behind
|
|
2448
|
-
* {@link ConversationStoreInterface}
|
|
2695
|
+
* {@link ConversationStoreInterface} without touching the manager or the conversation.
|
|
2449
2696
|
*
|
|
2450
2697
|
* @param driver - The storage backend the snapshots persist to (defaults to {@link createMemoryDriver})
|
|
2451
2698
|
* @returns A {@link ConversationStoreInterface} over the driver
|
|
@@ -2491,7 +2738,7 @@ export declare function createInstruction(input: InstructionInput): InstructionI
|
|
|
2491
2738
|
* immutable instructions keyed by `name`, listed by descending `priority`.
|
|
2492
2739
|
*
|
|
2493
2740
|
* @remarks
|
|
2494
|
-
* Starts empty; `add` (one or a batch)
|
|
2741
|
+
* Starts empty; `add` (one or a batch) mints each `id` and overwrites a same-name
|
|
2495
2742
|
* instruction (last write wins); `instructions()` lists them sorted by descending
|
|
2496
2743
|
* `priority` (stable for ties); `open` / `render` are the build contract a richer
|
|
2497
2744
|
* context renders an instructions block with; `remove` (one or a batch) reports `true` only
|
|
@@ -2519,7 +2766,7 @@ export declare function createInstructionManager(options?: InstructionManagerOpt
|
|
|
2519
2766
|
/**
|
|
2520
2767
|
* Creates the in-memory conversation store — a {@link ConversationStoreInterface} backed by a
|
|
2521
2768
|
* process-lifetime `Map` of {@link import('./types.js').ConversationSnapshot}s keyed by conversation
|
|
2522
|
-
* id, the
|
|
2769
|
+
* id, the default backing for the durable {@link ConversationManagerInterface.open} /
|
|
2523
2770
|
* {@link ConversationManagerInterface.save} seam. The exact twin of
|
|
2524
2771
|
* {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.
|
|
2525
2772
|
*
|
|
@@ -2527,10 +2774,10 @@ export declare function createInstructionManager(options?: InstructionManagerOpt
|
|
|
2527
2774
|
* A plain `Map` (the snapshot is already pure JSON, so no encoding is needed for the memory tier),
|
|
2528
2775
|
* the structural twin of {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.
|
|
2529
2776
|
* `get` / `set` / `delete` are async (the
|
|
2530
|
-
* same shape a durable backend fits);
|
|
2777
|
+
* same shape a durable backend fits); unlike a session store there is no idle-TTL / eviction — a
|
|
2531
2778
|
* persisted conversation lives until an explicit `delete`. Its driver-pluggable twin is
|
|
2532
2779
|
* {@link createDatabaseConversationStore} (the snapshot as one opaque JSON column over a `databases`
|
|
2533
|
-
* table) — for a
|
|
2780
|
+
* table) — for a durable store pass it a JSON / SQLite / IndexedDB driver, and it swaps in without
|
|
2534
2781
|
* touching the manager or the conversation. Hydration stays a manager concern: read a snapshot back
|
|
2535
2782
|
* and rebuild the live conversation through the `snapshot` option (re-supplying the live
|
|
2536
2783
|
* `summarize` / `keep`).
|
|
@@ -2550,14 +2797,85 @@ export declare function createInstructionManager(options?: InstructionManagerOpt
|
|
|
2550
2797
|
*/
|
|
2551
2798
|
export declare function createMemoryConversationStore(): ConversationStoreInterface;
|
|
2552
2799
|
|
|
2800
|
+
/**
|
|
2801
|
+
* Creates an authorized relay handler that validates a bounded JSON request before streaming.
|
|
2802
|
+
*
|
|
2803
|
+
* @remarks
|
|
2804
|
+
* Answers with the `401` status when authorization refuses or throws, the `400`
|
|
2805
|
+
* status when the body is missing, unreadable, or invalid, the `413` status when
|
|
2806
|
+
* the body fills its byte budget or the inbound read is aborted, and the `502`
|
|
2807
|
+
* status when the upstream provider call cannot be constructed. Refusals carry no body.
|
|
2808
|
+
*
|
|
2809
|
+
* @param options - The upstream provider, authorization decision, and optional byte budget
|
|
2810
|
+
* @returns A fetch-standard handler suitable for a router
|
|
2811
|
+
* @example Mounting the relay on your server
|
|
2812
|
+
* ```ts
|
|
2813
|
+
* import type { ProviderInterface } from '@orkestrel/agent'
|
|
2814
|
+
* import { createRelay } from '@orkestrel/agent'
|
|
2815
|
+
* import { createDispatcher } from '@orkestrel/router'
|
|
2816
|
+
* import { createServer } from '@orkestrel/server'
|
|
2817
|
+
*
|
|
2818
|
+
* declare const upstream: ProviderInterface // the server-side provider holding the credential
|
|
2819
|
+
* declare const bearer: string
|
|
2820
|
+
*
|
|
2821
|
+
* const handler = createRelay({
|
|
2822
|
+
* provider: upstream,
|
|
2823
|
+
* authorize: (request) => request.headers.get('authorization') === `Bearer ${bearer}`,
|
|
2824
|
+
* })
|
|
2825
|
+
* const dispatcher = createDispatcher({
|
|
2826
|
+
* routes: [{ method: 'POST', path: '/relay', handler }],
|
|
2827
|
+
* })
|
|
2828
|
+
*
|
|
2829
|
+
* export function serve(request: Request): Promise<Response> {
|
|
2830
|
+
* return dispatcher.handle(request, undefined)
|
|
2831
|
+
* }
|
|
2832
|
+
*
|
|
2833
|
+
* const server = createServer({ dispatcher, state: () => undefined })
|
|
2834
|
+
* await server.start()
|
|
2835
|
+
* process.on('SIGTERM', () => server.stop()) // signal cancellation, drain, then close the listener
|
|
2836
|
+
* ```
|
|
2837
|
+
*/
|
|
2838
|
+
export declare function createRelay(options: RelayOptions): RelayHandler;
|
|
2839
|
+
|
|
2840
|
+
/**
|
|
2841
|
+
* Creates a provider that carries calls through a relay endpoint.
|
|
2842
|
+
*
|
|
2843
|
+
* @remarks
|
|
2844
|
+
* This is the browser end alone. {@link createRelay} mounts the server end, and its example
|
|
2845
|
+
* is the server half this one pairs with.
|
|
2846
|
+
*
|
|
2847
|
+
* @param options - The endpoint, parser factory, and HTTP call configuration
|
|
2848
|
+
* @returns The concrete relay provider
|
|
2849
|
+
* @example Reaching the relay from the browser
|
|
2850
|
+
* ```ts
|
|
2851
|
+
* import type { ProviderInterface } from '@orkestrel/agent'
|
|
2852
|
+
* import { createRelayProvider } from '@orkestrel/agent'
|
|
2853
|
+
* import { createAbort } from '@orkestrel/abort'
|
|
2854
|
+
* // The browser application supplies this parser dependency.
|
|
2855
|
+
* import { createNDJSONParser } from '@orkestrel/ndjson'
|
|
2856
|
+
*
|
|
2857
|
+
* declare const bearer: string
|
|
2858
|
+
* const abort = createAbort()
|
|
2859
|
+
* const messages = [{ id: '1', role: 'user', content: 'Say hello.' }] as const
|
|
2860
|
+
*
|
|
2861
|
+
* const browser: ProviderInterface = createRelayProvider({
|
|
2862
|
+
* url: 'https://app.example/relay',
|
|
2863
|
+
* parser: createNDJSONParser,
|
|
2864
|
+
* headers: () => ({ authorization: `Bearer ${bearer}` }),
|
|
2865
|
+
* })
|
|
2866
|
+
* const result = await browser.generate(messages, abort.signal) // a ProviderResult like a local provider's
|
|
2867
|
+
* ```
|
|
2868
|
+
*/
|
|
2869
|
+
export declare function createRelayProvider(options: RelayProviderOptions): RelayProvider;
|
|
2870
|
+
|
|
2553
2871
|
/**
|
|
2554
2872
|
* Creates a named scope — an immutable {@link ScopeInterface} from its `name` and its
|
|
2555
2873
|
* per-category allow-lists, the `id` minted at construction.
|
|
2556
2874
|
*
|
|
2557
2875
|
* @remarks
|
|
2558
|
-
* Each list is
|
|
2559
|
-
*
|
|
2560
|
-
* tighter child by set-
|
|
2876
|
+
* Each list is three-way: `undefined` ⇒ no constraint on that category (all pass), `[]` ⇒
|
|
2877
|
+
* none pass, a non-empty list ⇒ only the listed keys pass. `narrow(config)` composes a
|
|
2878
|
+
* tighter child by set-intersection (an `undefined` side imposing no constraint). Stored
|
|
2561
2879
|
* immutable — never mutated after creation (`narrow` returns a new scope).
|
|
2562
2880
|
*
|
|
2563
2881
|
* @param input - `name` (required) and the optional `instructions` / `tools` / `files`
|
|
@@ -2601,18 +2919,19 @@ export declare function createScope(input: ScopeInput): ScopeInterface;
|
|
|
2601
2919
|
export declare function createScopeManager(options?: ScopeManagerOptions): ScopeManagerInterface;
|
|
2602
2920
|
|
|
2603
2921
|
/**
|
|
2604
|
-
* Creates a stream-stateful `<think>` separator — a {@link ThinkSplitterInterface} that
|
|
2605
|
-
* splits a thinking model's in-content `<think>…</think>` reasoning spans away from
|
|
2606
|
-
*
|
|
2607
|
-
*
|
|
2922
|
+
* Creates a fresh stream-stateful `<think>` separator — a {@link ThinkSplitterInterface} that
|
|
2923
|
+
* splits a thinking model's in-content `<think>…</think>` reasoning spans away from the answer,
|
|
2924
|
+
* delta by delta, so a provider yields clean content alone and surfaces the accumulated
|
|
2925
|
+
* reasoning as {@link import('./types.js').ProviderResult.thinking}. One splitter serves one
|
|
2926
|
+
* stream.
|
|
2608
2927
|
*
|
|
2609
2928
|
* @remarks
|
|
2610
2929
|
* Feed each raw wire delta through `split(delta)` (it returns the clean content to
|
|
2611
2930
|
* surface — possibly `''` mid-think) and settle the stream end with `flush()` (a held
|
|
2612
|
-
* partial open tag that never completed returns as final content; an
|
|
2613
|
-
* span lands on `thinking`). Tags split
|
|
2931
|
+
* partial open tag that never completed returns as final content; an unclosed think
|
|
2932
|
+
* span lands on `thinking`). Tags split across deltas are held back until
|
|
2614
2933
|
* disambiguated, multiple spans accumulate in order, and a nested-looking `<think>`
|
|
2615
|
-
* inside an open span is thinking text. One splitter serves
|
|
2934
|
+
* inside an open span is thinking text. One splitter serves one stream — create
|
|
2616
2935
|
* a fresh one per provider call.
|
|
2617
2936
|
*
|
|
2618
2937
|
* @returns A fresh {@link ThinkSplitterInterface} (state empty, outside any span)
|
|
@@ -2631,37 +2950,39 @@ export declare function createThinkSplitter(): ThinkSplitterInterface;
|
|
|
2631
2950
|
|
|
2632
2951
|
/**
|
|
2633
2952
|
* Backs a {@link ConversationStoreInterface} with one table of the `databases` layer — a
|
|
2634
|
-
* conversation's durable state
|
|
2635
|
-
*
|
|
2636
|
-
* {@link
|
|
2953
|
+
* conversation's durable state is a row holding the snapshot as one opaque JSON column, narrowed
|
|
2954
|
+
* back on `get` by {@link import('../../validators.js').isConversationSnapshot}, so persistence
|
|
2955
|
+
* reduces to keyed point-access (`get` / `set` / `delete`) over a {@link TableInterface}. The
|
|
2956
|
+
* driver-pluggable twin of the plain-`Map`
|
|
2957
|
+
* {@link import('./MemoryConversationStore.js').MemoryConversationStore}, and the exact twin of
|
|
2637
2958
|
* {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}.
|
|
2638
2959
|
*
|
|
2639
2960
|
* @remarks
|
|
2640
2961
|
* The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
|
|
2641
2962
|
* JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
|
|
2642
|
-
* IndexedDB backend swaps in
|
|
2963
|
+
* IndexedDB backend swaps in without touching the
|
|
2643
2964
|
* {@link import('../ConversationManager.js').ConversationManager} or the
|
|
2644
2965
|
* {@link import('../Conversation.js').Conversation} — the same seam as
|
|
2645
2966
|
* {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}. The
|
|
2646
2967
|
* driver defaults to memory ({@link import('../../factories.js').createDatabaseConversationStore}
|
|
2647
|
-
* passes `createMemoryDriver()`), so it
|
|
2968
|
+
* passes `createMemoryDriver()`), so it also works in memory out of the box; you opt into the
|
|
2648
2969
|
* durable plumbing by passing a JSON / SQLite / IndexedDB driver.
|
|
2649
2970
|
*
|
|
2650
|
-
* The {@link ConversationSnapshot} is stored as
|
|
2971
|
+
* The {@link ConversationSnapshot} is stored as one opaque JSON column — the table is a row of
|
|
2651
2972
|
* `{ id; snapshot }` ({@link ConversationSnapshotRow}), the snapshot the whole JSON blob (a
|
|
2652
2973
|
* `rawShape` column the factory builds) — exactly as `DatabaseWorkspaceStore` stores its snapshot.
|
|
2653
|
-
* The snapshot is already a
|
|
2654
|
-
* lossless
|
|
2974
|
+
* The snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is
|
|
2975
|
+
* lossless and keeps the row type flat (`snapshot` reads back as `unknown`).
|
|
2655
2976
|
*
|
|
2656
|
-
* - **`set(snapshot)` upserts under the snapshot's
|
|
2977
|
+
* - **`set(snapshot)` upserts under the snapshot's own `id`** (no separate id param) — it writes
|
|
2657
2978
|
* the row `{ id: snapshot.id, snapshot }`.
|
|
2658
2979
|
* - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to
|
|
2659
2980
|
* a {@link ConversationSnapshot} ({@link import('../../validators.js').isConversationSnapshot} — the
|
|
2660
2981
|
* total guard for an untrusted storage read), or `undefined` if none is stored.
|
|
2661
2982
|
* - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
2662
2983
|
*
|
|
2663
|
-
*
|
|
2664
|
-
* explicit `delete`. The public surface is
|
|
2984
|
+
* Unlike a session store there is no idle-TTL / eviction — a persisted conversation lives until an
|
|
2985
|
+
* explicit `delete`. The public surface is exactly `get` / `set` / `delete` — no extra members (the
|
|
2665
2986
|
* method bijection with {@link ConversationStoreInterface}). Hydration stays a caller concern: a
|
|
2666
2987
|
* {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds
|
|
2667
2988
|
* the live conversation through the `snapshot` option (its `open` / `save`).
|
|
@@ -2690,39 +3011,51 @@ export declare class DatabaseConversationStore implements ConversationStoreInter
|
|
|
2690
3011
|
constructor(table: TableInterface<ConversationSnapshotRow>);
|
|
2691
3012
|
/** Resolves the persisted snapshot for `id`, narrowing the opaque JSON column back to a `ConversationSnapshot`. */
|
|
2692
3013
|
get(id: string): Promise<ConversationSnapshot | undefined>;
|
|
2693
|
-
/** Inserts or replaces under the snapshot's
|
|
3014
|
+
/** Inserts or replaces under the snapshot's own `id` (no separate id param) — the row is `{ id, snapshot }`. */
|
|
2694
3015
|
set(snapshot: ConversationSnapshot): Promise<void>;
|
|
2695
3016
|
/** Drops a snapshot by id; an absent id is a no-op (no throw). */
|
|
2696
3017
|
delete(id: string): Promise<void>;
|
|
2697
3018
|
}
|
|
2698
3019
|
|
|
2699
3020
|
/**
|
|
2700
|
-
* Caps an {@link AgentInterface} turn's tool iterations by default —
|
|
2701
|
-
*
|
|
2702
|
-
*
|
|
2703
|
-
* `AgentOptions.limit`.
|
|
3021
|
+
* Caps an {@link AgentInterface} turn's tool iterations by default — `10` context → provider →
|
|
3022
|
+
* tools cycles before the loop stops, so a model that keeps requesting tools can never loop
|
|
3023
|
+
* forever. Overridable per agent through `AgentOptions.limit`.
|
|
2704
3024
|
*/
|
|
2705
3025
|
export declare const DEFAULT_AGENT_LIMIT = 10;
|
|
2706
3026
|
|
|
2707
3027
|
/**
|
|
2708
3028
|
* Names the zone an {@link AuthorityInterface}'s default fallback {@link AuthorityDecision}
|
|
2709
|
-
* carries — the classification for a tool call that matched no rule. Paired with
|
|
2710
|
-
* default `allowed: true` fallback, an unmatched call is allowed under this zone, so a
|
|
2711
|
-
* rules list of denials acts as a denylist; a caller wanting deny-by-default supplies
|
|
2712
|
-
*
|
|
3029
|
+
* carries — `'default'`, the classification for a tool call that matched no rule. Paired with
|
|
3030
|
+
* the default `allowed: true` fallback, an unmatched call is allowed under this zone, so a
|
|
3031
|
+
* rules list of denials acts as a denylist; a caller wanting deny-by-default supplies an
|
|
3032
|
+
* `allowed: false` `fallback` of their own (see `AuthorityOptions`).
|
|
2713
3033
|
*/
|
|
2714
3034
|
export declare const DEFAULT_AUTHORITY_ZONE = "default";
|
|
2715
3035
|
|
|
2716
3036
|
/**
|
|
2717
3037
|
* Sets the default number of recent live messages a {@link ConversationInterface}'s `compact()`
|
|
2718
|
-
*
|
|
2719
|
-
*
|
|
2720
|
-
*
|
|
2721
|
-
*
|
|
2722
|
-
*
|
|
3038
|
+
* retains verbatim — `0`, so a manual `compact()` folds every current live message into one
|
|
3039
|
+
* summarized section and keeps no tail. A caller retains a recent tail by passing `keep` (on
|
|
3040
|
+
* {@link ConversationOptions}, {@link ConversationManagerOptions}, or per-fold through
|
|
3041
|
+
* {@link CompactOptions}), folding only the older `count - keep` messages and leaving the most
|
|
3042
|
+
* recent `keep` live for the next turn. Overridable everywhere `keep` is accepted.
|
|
2723
3043
|
*/
|
|
2724
3044
|
export declare const DEFAULT_CONVERSATION_KEEP = 0;
|
|
2725
3045
|
|
|
3046
|
+
/**
|
|
3047
|
+
* Holds the default provider deadline in milliseconds — `120_000`, the wall-clock bound a call
|
|
3048
|
+
* runs under when `AgentProviderInput.timeout` is omitted, folded with the caller's signal so
|
|
3049
|
+
* whichever trips first cancels the call.
|
|
3050
|
+
*/
|
|
3051
|
+
export declare const DEFAULT_PROVIDER_TIMEOUT = 120000;
|
|
3052
|
+
|
|
3053
|
+
/**
|
|
3054
|
+
* Holds the default relay request limit in bytes — `1_048_576`, the byte budget a relay applies
|
|
3055
|
+
* to an inbound body when `RelayOptions.limit` is omitted, refusing a body that reaches it.
|
|
3056
|
+
*/
|
|
3057
|
+
export declare const DEFAULT_RELAY_LIMIT = 1048576;
|
|
3058
|
+
|
|
2726
3059
|
/**
|
|
2727
3060
|
* Synthesizes the denial {@link ToolResult} an authority-blocked call is fed back with — the
|
|
2728
3061
|
* call's `id` / `name` keyed back, carrying a denial `error` instead of a value.
|
|
@@ -2745,16 +3078,19 @@ export declare const DEFAULT_CONVERSATION_KEEP = 0;
|
|
|
2745
3078
|
export declare function denyCall(call: ToolCall, reason: string | undefined): ToolResult;
|
|
2746
3079
|
|
|
2747
3080
|
/**
|
|
2748
|
-
* Estimates the context-token footprint of a batch of messages —
|
|
2749
|
-
*
|
|
2750
|
-
*
|
|
3081
|
+
* Estimates the context-token footprint of a batch of messages — each message's content plus
|
|
3082
|
+
* {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD}, a tool-call JSON estimate, and
|
|
3083
|
+
* {@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} for each attached image. The default
|
|
3084
|
+
* `consumer` estimator for an agent's context budget (the
|
|
3085
|
+
* {@link import('./types.js').AgentOptions} `window`), total and never throwing, and a
|
|
3086
|
+
* deliberate provider-agnostic approximation rather than an exact tokenizer count.
|
|
2751
3087
|
*
|
|
2752
3088
|
* @remarks
|
|
2753
3089
|
* Sums, per message, {@link estimateTokens} over its `content` (the `ceil(length / 4)` char
|
|
2754
|
-
* heuristic)
|
|
2755
|
-
* role/framing overhead)
|
|
2756
|
-
* `calls`
|
|
2757
|
-
* deliberately-approximate per-image cost — a base64 length is
|
|
3090
|
+
* heuristic) plus {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (a fixed per-message
|
|
3091
|
+
* role/framing overhead) plus, when present, {@link estimateTokens} over its JSON-stringified
|
|
3092
|
+
* `calls` plus `images.length * `{@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} (a coarse,
|
|
3093
|
+
* deliberately-approximate per-image cost — a base64 length is not a token proxy). Deterministic
|
|
2758
3094
|
* and provider-free — the same messages always yield the same estimate, with an empty batch `0`.
|
|
2759
3095
|
* It is the fully-swappable default an agent's auto-compaction context budget charges each
|
|
2760
3096
|
* turn's new messages through; a caller wanting a sharper count supplies its own `consumer` to
|
|
@@ -2775,15 +3111,15 @@ export declare function denyCall(call: ToolCall, reason: string | undefined): To
|
|
|
2775
3111
|
export declare function estimateMessages(messages: readonly Message[]): number;
|
|
2776
3112
|
|
|
2777
3113
|
/**
|
|
2778
|
-
* Estimates the context-token footprint of a string — the deterministic
|
|
2779
|
-
* {@link estimateMessages} sums over a conversation's messages (the default
|
|
2780
|
-
* estimator).
|
|
3114
|
+
* Estimates the context-token footprint of a string — the deterministic `ceil(length / 4)`
|
|
3115
|
+
* character heuristic {@link estimateMessages} sums over a conversation's messages (the default
|
|
3116
|
+
* context-budget estimator).
|
|
2781
3117
|
*
|
|
2782
3118
|
* @remarks
|
|
2783
3119
|
* Approximates `ceil(length / 4)` (≈ four characters per token — the rough average for
|
|
2784
3120
|
* English text), so the same input always yields the same estimate (no model round-trip).
|
|
2785
3121
|
* Empty text is `0`. This is a planning heuristic for reasoning about how much a turn's
|
|
2786
|
-
* messages cost the next request,
|
|
3122
|
+
* messages cost the next request, not an exact tokenizer count — it never calls a provider,
|
|
2787
3123
|
* so the agent layer stays provider-agnostic and synchronous where it can be.
|
|
2788
3124
|
*
|
|
2789
3125
|
* @param text - The text to estimate (a section summary, a message's content)
|
|
@@ -2799,15 +3135,16 @@ export declare function estimateMessages(messages: readonly Message[]): number;
|
|
|
2799
3135
|
export declare function estimateTokens(text: string): number;
|
|
2800
3136
|
|
|
2801
3137
|
/**
|
|
2802
|
-
* Filters a list of items by a {@link import('./types.js').ScopeInterface} allow-list of
|
|
2803
|
-
*
|
|
2804
|
-
*
|
|
3138
|
+
* Filters a list of items by a {@link import('./types.js').ScopeInterface} allow-list of keys —
|
|
3139
|
+
* `undefined` passes everything, `[]` passes nothing, and a non-empty list passes the listed keys
|
|
3140
|
+
* alone, order preserved. The pure, total set-membership primitive the context's build step and
|
|
3141
|
+
* the agent loop's tool-advertise step apply a scope through.
|
|
2805
3142
|
*
|
|
2806
3143
|
* @remarks
|
|
2807
3144
|
* Three-way by the allow-list's shape, so a `Scope` category cleanly expresses "all /
|
|
2808
3145
|
* none / only these":
|
|
2809
|
-
* - `undefined` ⇒
|
|
2810
|
-
* - `[]` (empty) ⇒
|
|
3146
|
+
* - `undefined` ⇒ no constraint — every item passes (returned unchanged).
|
|
3147
|
+
* - `[]` (empty) ⇒ none pass (no key is in an empty set).
|
|
2811
3148
|
* - a non-empty list ⇒ only items whose `key(item)` is in the list pass.
|
|
2812
3149
|
*
|
|
2813
3150
|
* Order-preserving (it filters `items` in place order, never reorders) and total — never
|
|
@@ -2858,11 +3195,12 @@ export declare function handleAgentQueueJob(registry: AgentRegistryInterface, pa
|
|
|
2858
3195
|
export declare function handleAgentRunnerJob(registry: AgentRegistryInterface, partial: boolean, controller: ControllerInterface<AgentJobInput, AgentResult>): Promise<AgentResult>;
|
|
2859
3196
|
|
|
2860
3197
|
/**
|
|
2861
|
-
* Names the coarse, deliberately
|
|
2862
|
-
* charges for each attached image
|
|
3198
|
+
* Names the coarse, deliberately approximate per-image token cost
|
|
3199
|
+
* {@link import('./helpers.js').estimateMessages} charges for each attached image — `512`, because
|
|
3200
|
+
* a base64 payload's length is no reliable token proxy.
|
|
2863
3201
|
*
|
|
2864
3202
|
* @remarks
|
|
2865
|
-
* A base64 image payload's
|
|
3203
|
+
* A base64 image payload's length is not a reliable token proxy (a vision model's actual image
|
|
2866
3204
|
* token cost depends on resolution / tiling, not byte size), so this is a fixed, coarse
|
|
2867
3205
|
* per-image estimate rather than a derivation from `image.length` — a planning heuristic, not an
|
|
2868
3206
|
* exact count.
|
|
@@ -2870,15 +3208,15 @@ export declare function handleAgentRunnerJob(registry: AgentRegistryInterface, p
|
|
|
2870
3208
|
export declare const IMAGE_TOKEN_ESTIMATE = 512;
|
|
2871
3209
|
|
|
2872
3210
|
/**
|
|
2873
|
-
* Represents an immutable named directive —
|
|
2874
|
-
*
|
|
2875
|
-
*
|
|
3211
|
+
* Represents an immutable named directive — an {@link InstructionInterface} assembled once from
|
|
3212
|
+
* its input (`name` / `content`, an optional `priority` defaulting to `0`), the `id` minted at
|
|
3213
|
+
* construction.
|
|
2876
3214
|
*
|
|
2877
3215
|
* @remarks
|
|
2878
3216
|
* A thin immutable value object (mirroring {@link import('@orkestrel/tool').Tool}): the
|
|
2879
3217
|
* constructor mints a fresh `id` (`crypto.randomUUID()`), copies the input's `name` /
|
|
2880
3218
|
* `content`, resolves `priority` to the input's value or `0`, and carries the input's
|
|
2881
|
-
* per-item `override`
|
|
3219
|
+
* per-item `override` only when supplied (assigned when present, mirroring a
|
|
2882
3220
|
* message's `images` / `calls` present-when-given convention — kept absent otherwise).
|
|
2883
3221
|
* Never mutated after construction. An
|
|
2884
3222
|
* {@link import('./InstructionManager.js').InstructionManager} keys it by `name` and
|
|
@@ -2910,7 +3248,7 @@ export declare interface InstructionInput {
|
|
|
2910
3248
|
/** Weights the ordering (higher renders first); defaults to `0` when omitted. */
|
|
2911
3249
|
readonly priority?: number;
|
|
2912
3250
|
/**
|
|
2913
|
-
* Holds a fully-rendered override of
|
|
3251
|
+
* Holds a fully-rendered override of this instruction's prompt text — the most-specific
|
|
2914
3252
|
* level of the {@link import('./AgentContext.js').AgentContext} build cascade (beats a
|
|
2915
3253
|
* manager-options / provider / built-in format for this item). Round-tripped onto the
|
|
2916
3254
|
* stored {@link InstructionInterface} when given (present-when-supplied, like `images`).
|
|
@@ -2937,8 +3275,8 @@ export declare interface InstructionInterface {
|
|
|
2937
3275
|
readonly priority: number;
|
|
2938
3276
|
/**
|
|
2939
3277
|
* Holds a fully-rendered per-item override of this instruction's prompt text — the
|
|
2940
|
-
*
|
|
2941
|
-
* cascade, beating every format level for
|
|
3278
|
+
* most-specific level of the {@link import('./AgentContext.js').AgentContext} build
|
|
3279
|
+
* cascade, beating every format level for this item. Present only when supplied on the
|
|
2942
3280
|
* {@link InstructionInput} (round-tripped through the manager, like a message's
|
|
2943
3281
|
* `images`); absent ⇒ the cascade decides.
|
|
2944
3282
|
*/
|
|
@@ -2946,28 +3284,29 @@ export declare interface InstructionInterface {
|
|
|
2946
3284
|
}
|
|
2947
3285
|
|
|
2948
3286
|
/**
|
|
2949
|
-
* Registers the immutable {@link Instruction}s a richer context assembles a directives
|
|
2950
|
-
*
|
|
3287
|
+
* Registers the immutable {@link Instruction}s a richer context assembles a directives block
|
|
3288
|
+
* from — keyed by `name` so a re-`add` overwrites, last write wins, and listed by descending
|
|
3289
|
+
* `priority`, carrying the `open` / `render` build contract and an observable `emitter`.
|
|
2951
3290
|
*
|
|
2952
3291
|
* @remarks
|
|
2953
3292
|
* - **Registry.** Instructions live in an insertion-ordered `Map` keyed by `name`;
|
|
2954
|
-
* `add` takes one {@link InstructionInput} or a batch,
|
|
2955
|
-
* `id`, and a re-`add` of the same name
|
|
2956
|
-
* map size, `instruction(name)` looks one up, and `instructions()` lists them
|
|
3293
|
+
* `add` takes one {@link InstructionInput} or a batch, mints each instruction's
|
|
3294
|
+
* `id`, and a re-`add` of the same name overwrites it (last write wins). `count` is the
|
|
3295
|
+
* map size, `instruction(name)` looks one up, and `instructions()` lists them sorted by
|
|
2957
3296
|
* descending `priority` (a stable sort, so equal priorities keep insertion order).
|
|
2958
3297
|
* - **Build contract (with the manager-options override).** `open` is the section
|
|
2959
3298
|
* header a context renders the instructions under; `render(instruction)` renders one
|
|
2960
|
-
* instruction (its `content`). Each
|
|
3299
|
+
* instruction (its `content`). Each encapsulates the cascade's `[options-override →
|
|
2961
3300
|
* built-in]` half: when `InstructionManagerOptions.format` supplies an `open` /
|
|
2962
|
-
* `render`, `open` / `render` return
|
|
3301
|
+
* `render`, `open` / `render` return it, else the built-in — so a richer context
|
|
2963
3302
|
* reads one consistent pair and layers the provider default + per-item override on top
|
|
2964
3303
|
* (see {@link import('../AgentContext.js').AgentContext}). The per-item
|
|
2965
3304
|
* {@link InstructionInput.override} is round-tripped onto the stored instruction.
|
|
2966
|
-
* - **Removal.** `remove` drops one by name, or a batch — `true` only when
|
|
3305
|
+
* - **Removal.** `remove` drops one by name, or a batch — `true` only when every supplied
|
|
2967
3306
|
* name was removed; `clear` empties the registry.
|
|
2968
3307
|
* - **Observable.** The owned {@link emitter} ({@link InstructionManagerEventMap})
|
|
2969
3308
|
* carries `add` (the created instruction) / `remove` (the name) / `clear` for
|
|
2970
|
-
* fire-and-forget observers. Every event is emitted directly, strictly
|
|
3309
|
+
* fire-and-forget observers. Every event is emitted directly, strictly after the map
|
|
2971
3310
|
* mutation completes; the emitter isolates a listener throw and routes it to its `error`
|
|
2972
3311
|
* handler (the `error` option), so a buggy observer can never corrupt a mutation.
|
|
2973
3312
|
*
|
|
@@ -3020,9 +3359,9 @@ export declare type InstructionManagerEventMap = {
|
|
|
3020
3359
|
};
|
|
3021
3360
|
|
|
3022
3361
|
/**
|
|
3023
|
-
* Registers {@link InstructionInterface}s keyed by `name` — `add` (one or a batch)
|
|
3024
|
-
*
|
|
3025
|
-
*
|
|
3362
|
+
* Registers {@link InstructionInterface}s keyed by `name` — `add` (one or a batch) mints each `id`
|
|
3363
|
+
* and overwrites a same-name instruction, last write wins, while `instructions()` lists them sorted
|
|
3364
|
+
* by descending `priority` and stable for ties.
|
|
3026
3365
|
*
|
|
3027
3366
|
* @remarks
|
|
3028
3367
|
* - **Build contract.** `open` is the section header a richer context renders
|
|
@@ -3040,22 +3379,32 @@ export declare interface InstructionManagerInterface {
|
|
|
3040
3379
|
readonly open: string;
|
|
3041
3380
|
/**
|
|
3042
3381
|
* Holds the manager-options format override (the {@link InstructionManagerOptions.format}
|
|
3043
|
-
* supplied at construction), or `undefined` when none — the
|
|
3382
|
+
* supplied at construction), or `undefined` when none — the manager-options level of the
|
|
3044
3383
|
* {@link import('./AgentContext.js').AgentContext} build cascade, exposed so `build()`
|
|
3045
|
-
* can interleave the provider default
|
|
3384
|
+
* can interleave the provider default beneath it (`open` / `render` already
|
|
3046
3385
|
* encapsulate the `[override → built-in]` half for standalone use). A `readonly` data
|
|
3047
3386
|
* member, not a method.
|
|
3048
3387
|
*/
|
|
3049
3388
|
readonly format: ContextSectionFormat<InstructionInterface> | undefined;
|
|
3389
|
+
/**
|
|
3390
|
+
* Adds one {@link InstructionInput}, or a batch — mints each `id`; a re-`add` of the same
|
|
3391
|
+
* name overwrites it, last write wins.
|
|
3392
|
+
*/
|
|
3050
3393
|
add(input: InstructionInput): InstructionInterface;
|
|
3051
3394
|
add(inputs: readonly InstructionInput[]): readonly InstructionInterface[];
|
|
3395
|
+
/** Looks up one instruction by name (`undefined` when absent). */
|
|
3052
3396
|
instruction(name: string): InstructionInterface | undefined;
|
|
3053
3397
|
/** Lists every instruction, sorted by descending `priority` (stable for equal priorities). */
|
|
3054
3398
|
instructions(): readonly InstructionInterface[];
|
|
3055
3399
|
/** Renders one instruction for the prompt — its `content`. */
|
|
3056
3400
|
render(instruction: InstructionInterface): string;
|
|
3401
|
+
/**
|
|
3402
|
+
* Removes one instruction by name, or a batch — `true` only when every supplied name was
|
|
3403
|
+
* removed.
|
|
3404
|
+
*/
|
|
3057
3405
|
remove(name: string): boolean;
|
|
3058
3406
|
remove(names: readonly string[]): boolean;
|
|
3407
|
+
/** Removes every instruction. */
|
|
3059
3408
|
clear(): void;
|
|
3060
3409
|
}
|
|
3061
3410
|
|
|
@@ -3066,10 +3415,10 @@ export declare interface InstructionManagerInterface {
|
|
|
3066
3415
|
* @remarks
|
|
3067
3416
|
* `on` is the reserved listener key: initial listeners for the manager's
|
|
3068
3417
|
* {@link InstructionManagerEventMap}, wired at construction. `format` is the
|
|
3069
|
-
*
|
|
3070
|
-
* cascade — a {@link ContextSectionFormat} the manager consults
|
|
3418
|
+
* manager-options level of the {@link import('./AgentContext.js').AgentContext} build
|
|
3419
|
+
* cascade — a {@link ContextSectionFormat} the manager consults first in its own
|
|
3071
3420
|
* `open` / `render` (falling back to the built-in when a member is omitted), so it
|
|
3072
|
-
*
|
|
3421
|
+
* beats the provider default and the built-in, while a per-item
|
|
3073
3422
|
* {@link InstructionInput.override} still beats it. Omitted ⇒ the built-in framing applies.
|
|
3074
3423
|
*/
|
|
3075
3424
|
export declare interface InstructionManagerOptions {
|
|
@@ -3081,12 +3430,12 @@ export declare interface InstructionManagerOptions {
|
|
|
3081
3430
|
}
|
|
3082
3431
|
|
|
3083
3432
|
/**
|
|
3084
|
-
* Intersects two scope category lists under the "`undefined` is the universal set" rule —
|
|
3085
|
-
* primitive a scope narrows through.
|
|
3433
|
+
* Intersects two scope category lists under the "`undefined` is the universal set" rule — a
|
|
3434
|
+
* fresh copy that can only tighten, and the primitive a scope narrows through.
|
|
3086
3435
|
*
|
|
3087
3436
|
* @remarks
|
|
3088
|
-
* Pure and total, and it can only
|
|
3089
|
-
* constraint); `undefined` ∩ a list is a
|
|
3437
|
+
* Pure and total, and it can only tighten: `undefined` ∩ `undefined` is `undefined` (still no
|
|
3438
|
+
* constraint); `undefined` ∩ a list is a copy of that list (the `undefined` side imposes
|
|
3090
3439
|
* nothing); a list ∩ a list keeps the child keys the parent also allows, so a parent-excluded
|
|
3091
3440
|
* key can never be re-admitted. Every returned list is a fresh copy, so a later mutation of
|
|
3092
3441
|
* either input cannot leak into the result.
|
|
@@ -3105,7 +3454,15 @@ export declare interface InstructionManagerOptions {
|
|
|
3105
3454
|
export declare function intersectKeys(parent: readonly string[] | undefined, child: readonly string[] | undefined): readonly string[] | undefined;
|
|
3106
3455
|
|
|
3107
3456
|
/**
|
|
3108
|
-
*
|
|
3457
|
+
* Names the status a relay answers for a body that is missing, unreadable, or rejected by
|
|
3458
|
+
* `providerRequestContract` — `400`, carried with no body and reaching the browser as a
|
|
3459
|
+
* `ProviderError` with the `HTTP` code.
|
|
3460
|
+
*/
|
|
3461
|
+
export declare const INVALID_RELAY_STATUS = 400;
|
|
3462
|
+
|
|
3463
|
+
/**
|
|
3464
|
+
* Narrows an unknown caught value to an {@link AgentError} through `instanceof`, so a `catch`
|
|
3465
|
+
* can branch on its `code`.
|
|
3109
3466
|
*
|
|
3110
3467
|
* @param value - The value to test (typically a `catch` binding)
|
|
3111
3468
|
* @returns True if `value` is an {@link AgentError}; false otherwise
|
|
@@ -3122,7 +3479,8 @@ export declare function intersectKeys(parent: readonly string[] | undefined, chi
|
|
|
3122
3479
|
export declare function isAgentError(value: unknown): value is AgentError;
|
|
3123
3480
|
|
|
3124
3481
|
/**
|
|
3125
|
-
* Narrows an unknown caught value to an {@link AgentJobError}
|
|
3482
|
+
* Narrows an unknown caught value to an {@link AgentJobError} through `instanceof`, so a
|
|
3483
|
+
* `catch` can recover its `partial` result.
|
|
3126
3484
|
*
|
|
3127
3485
|
* @param value - The value to test (typically a `catch` binding or a rejected enqueue)
|
|
3128
3486
|
* @returns True if `value` is an {@link AgentJobError}; false otherwise
|
|
@@ -3139,7 +3497,8 @@ export declare function isAgentError(value: unknown): value is AgentError;
|
|
|
3139
3497
|
export declare function isAgentJobError(value: unknown): value is AgentJobError;
|
|
3140
3498
|
|
|
3141
3499
|
/**
|
|
3142
|
-
* Narrows an unknown caught value to a {@link ConversationError}
|
|
3500
|
+
* Narrows an unknown caught value to a {@link ConversationError} through `instanceof`, so a
|
|
3501
|
+
* `catch` can branch on its `code`.
|
|
3143
3502
|
*
|
|
3144
3503
|
* @param value - The value to test (typically a `catch` binding)
|
|
3145
3504
|
* @returns True if `value` is a {@link ConversationError}; false otherwise
|
|
@@ -3156,19 +3515,20 @@ export declare function isAgentJobError(value: unknown): value is AgentJobError;
|
|
|
3156
3515
|
export declare function isConversationError(value: unknown): value is ConversationError;
|
|
3157
3516
|
|
|
3158
3517
|
/**
|
|
3159
|
-
* Narrows an `unknown` to a {@link ConversationSnapshot} —
|
|
3160
|
-
*
|
|
3518
|
+
* Narrows an `unknown` to a {@link ConversationSnapshot} — a `string` `id`, an optional `string`
|
|
3519
|
+
* `summary`, and valid `sections` and `messages` arrays; the total boundary guard for an
|
|
3520
|
+
* untrusted snapshot read (a storage row a
|
|
3161
3521
|
* {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore}
|
|
3162
|
-
* reads back from its opaque JSON column, a snapshot loaded from disk). The
|
|
3163
|
-
* {@link import('@orkestrel/workspace').isWorkspaceSnapshot}.
|
|
3522
|
+
* reads back from its opaque JSON column, a snapshot loaded from disk), never throwing. The exact
|
|
3523
|
+
* analogue of {@link import('@orkestrel/workspace').isWorkspaceSnapshot}.
|
|
3164
3524
|
*
|
|
3165
3525
|
* @remarks
|
|
3166
|
-
* A total guard (it
|
|
3167
|
-
*
|
|
3168
|
-
* `undefined` until the first compaction), a `sections` array
|
|
3169
|
-
* {@link Section} ({@link isSection}), and a `messages` array
|
|
3526
|
+
* A total guard (it never throws — adversarial input returns `false`). It checks the snapshot's
|
|
3527
|
+
* shape: a `string` `id`, an optional `string` `summary` (present-or-absent — the rollup is
|
|
3528
|
+
* `undefined` until the first compaction), a `sections` array every element of which is a valid
|
|
3529
|
+
* {@link Section} ({@link isSection}), and a `messages` array every element of which is a
|
|
3170
3530
|
* valid {@link Message} ({@link isMessage}) — enough to safely impose the
|
|
3171
|
-
* {@link ConversationSnapshot} type at a storage boundary
|
|
3531
|
+
* {@link ConversationSnapshot} type at a storage boundary without a cast. The structural twin of
|
|
3172
3532
|
* {@link import('@orkestrel/workspace').isWorkspaceSnapshot}. A malformed blob (a non-record, a missing / non-string `id`, a
|
|
3173
3533
|
* non-string `summary` when present, a non-array `sections` / `messages`, or any malformed
|
|
3174
3534
|
* element) resolves `false`, so a
|
|
@@ -3189,39 +3549,27 @@ export declare function isConversationError(value: unknown): value is Conversati
|
|
|
3189
3549
|
export declare function isConversationSnapshot(value: unknown): value is ConversationSnapshot;
|
|
3190
3550
|
|
|
3191
3551
|
/**
|
|
3192
|
-
* Checks whether
|
|
3193
|
-
* the {@link isConversationSnapshot} read-boundary narrow (a total guard over an untrusted storage
|
|
3194
|
-
* read, never an assertion). The conversation analogue of
|
|
3195
|
-
* {@link import('@orkestrel/workspace').isFile}.
|
|
3552
|
+
* Checks whether a value satisfies the domain conversation-message contract.
|
|
3196
3553
|
*
|
|
3197
3554
|
* @remarks
|
|
3198
|
-
*
|
|
3199
|
-
*
|
|
3200
|
-
*
|
|
3201
|
-
* {@link import('@orkestrel/tool').ToolCall} ({@link isToolCall} — the
|
|
3202
|
-
* fail-closed deepening: a tampered `calls` element rejects the message, so the snapshot
|
|
3203
|
-
* reads back as absent rather than replaying a malformed call) and an `images` that is an array
|
|
3204
|
-
* (an absent optional passes). The `role` is left as a broad `string` here (an open
|
|
3205
|
-
* {@link import('./types.js').MessageRole}, so any storage-read role string is accepted
|
|
3206
|
-
* defensively rather than rejected against the current literal set). Enough to safely impose the
|
|
3207
|
-
* {@link Message} type at
|
|
3208
|
-
* a storage boundary WITHOUT a cast.
|
|
3209
|
-
*
|
|
3210
|
-
* @param value - The value to test (one element of a snapshot's `messages` / a section's `messages`)
|
|
3211
|
-
* @returns True if `value` has the structural shape of a {@link Message}; false otherwise
|
|
3555
|
+
* Roles belong to MessageRole and image elements are strings. Tool arguments may
|
|
3556
|
+
* carry non-JSON values, as the domain type permits; the message wire contract is
|
|
3557
|
+
* narrower. Unreadable fields and hostile inputs return false.
|
|
3212
3558
|
*
|
|
3559
|
+
* @param value - The unknown message candidate
|
|
3560
|
+
* @returns True if the domain message fields are valid; false otherwise
|
|
3213
3561
|
* @example
|
|
3214
3562
|
* ```ts
|
|
3215
3563
|
* isMessage({ id: '1', role: 'user', content: 'hi' }) // true
|
|
3216
|
-
* isMessage({ id: '1', role: '
|
|
3217
|
-
* isMessage({ id: '1', role: 'user' }) // false
|
|
3218
|
-
* isMessage({ id: '1', role: 'assistant', content: '', calls: [null] }) // false (malformed call)
|
|
3564
|
+
* isMessage({ id: '1', role: 'other', content: '' }) // false
|
|
3565
|
+
* isMessage({ id: '1', role: 'user', content: '', images: [1] }) // false
|
|
3219
3566
|
* ```
|
|
3220
3567
|
*/
|
|
3221
3568
|
export declare function isMessage(value: unknown): value is Message;
|
|
3222
3569
|
|
|
3223
3570
|
/**
|
|
3224
|
-
* Narrows an unknown caught value to a {@link ProviderAbortError}
|
|
3571
|
+
* Narrows an unknown caught value to a {@link ProviderAbortError} through `instanceof`, so a
|
|
3572
|
+
* `catch` can recover its `partial` result.
|
|
3225
3573
|
*
|
|
3226
3574
|
* @param value - The value to test (typically a `catch` binding)
|
|
3227
3575
|
* @returns True if `value` is a {@link ProviderAbortError}; false otherwise
|
|
@@ -3238,15 +3586,28 @@ export declare function isMessage(value: unknown): value is Message;
|
|
|
3238
3586
|
export declare function isProviderAbortError(value: unknown): value is ProviderAbortError;
|
|
3239
3587
|
|
|
3240
3588
|
/**
|
|
3241
|
-
*
|
|
3242
|
-
*
|
|
3243
|
-
*
|
|
3589
|
+
* Narrows a caught value to the provider failure class through instanceof.
|
|
3590
|
+
*
|
|
3591
|
+
* @param value - The caught value
|
|
3592
|
+
* @returns True if the value is a provider failure; false otherwise
|
|
3593
|
+
* @example
|
|
3594
|
+
* ```ts
|
|
3595
|
+
* isProviderError(new ProviderError('HTTP', 'unavailable', { status: 503 })) // true
|
|
3596
|
+
* ```
|
|
3597
|
+
*/
|
|
3598
|
+
export declare function isProviderError(value: unknown): value is ProviderError;
|
|
3599
|
+
|
|
3600
|
+
/**
|
|
3601
|
+
* Checks whether an `unknown` is structurally a {@link Section} record — a `string` `id` and
|
|
3602
|
+
* `summary` beside a `messages` array of valid {@link Message}s, the per-section step of the
|
|
3603
|
+
* {@link isConversationSnapshot} read-boundary narrow. Total, never throwing, and never an
|
|
3604
|
+
* assertion.
|
|
3244
3605
|
*
|
|
3245
3606
|
* @remarks
|
|
3246
|
-
* A total guard (it
|
|
3247
|
-
*
|
|
3607
|
+
* A total guard (it never throws — adversarial input returns `false`). It checks the section's
|
|
3608
|
+
* shape: a record with a `string` `id`, a `string` `summary`, and a `messages` array every element
|
|
3248
3609
|
* of which is a valid {@link Message} record ({@link isMessage}). Enough to safely impose
|
|
3249
|
-
* the {@link Section} type at a storage boundary
|
|
3610
|
+
* the {@link Section} type at a storage boundary without a cast.
|
|
3250
3611
|
*
|
|
3251
3612
|
* @param value - The value to test (one element of a snapshot's `sections` array)
|
|
3252
3613
|
* @returns True if `value` has the structural shape of a {@link Section}; false otherwise
|
|
@@ -3277,33 +3638,42 @@ export declare function isSection(value: unknown): value is Section;
|
|
|
3277
3638
|
* @example
|
|
3278
3639
|
* ```ts
|
|
3279
3640
|
* joinThinking(undefined, 'first') // 'first'
|
|
3641
|
+
* joinThinking('', 'x') // 'x'
|
|
3280
3642
|
* joinThinking('first', 'second') // 'first\n\nsecond'
|
|
3281
3643
|
* ```
|
|
3282
3644
|
*/
|
|
3283
3645
|
export declare function joinThinking(running: string | undefined, next: string): string;
|
|
3284
3646
|
|
|
3647
|
+
/**
|
|
3648
|
+
* Bounds the decoded error excerpt's input in bytes — `2048`, the leading bytes of a non-OK
|
|
3649
|
+
* response body handed to the decoder before the read cancels the remainder, so a `ProviderError`
|
|
3650
|
+
* message never carries a longer excerpt.
|
|
3651
|
+
*/
|
|
3652
|
+
export declare const MAX_ERROR_BODY_LENGTH = 2048;
|
|
3653
|
+
|
|
3285
3654
|
/**
|
|
3286
3655
|
* Implements the {@link ConversationStoreInterface} in memory — a process-lifetime `Map` of
|
|
3287
|
-
* {@link ConversationSnapshot}s keyed by conversation id, the
|
|
3288
|
-
* {@link import('../../factories.js').createMemoryConversationStore} builds
|
|
3656
|
+
* {@link ConversationSnapshot}s keyed by conversation id, the default store
|
|
3657
|
+
* {@link import('../../factories.js').createMemoryConversationStore} builds and the default
|
|
3658
|
+
* backing for `open` / `save`. The exact twin of
|
|
3289
3659
|
* {@link import('@orkestrel/workspace').MemoryWorkspaceStore}.
|
|
3290
3660
|
*
|
|
3291
3661
|
* @remarks
|
|
3292
3662
|
* A plain `Map<string, ConversationSnapshot>` — the snapshot is already pure,
|
|
3293
3663
|
* self-contained JSON, so no encoding is needed for the memory tier. Like the
|
|
3294
3664
|
* {@link import('@orkestrel/workspace').MemoryWorkspaceStore} it twins,
|
|
3295
|
-
* there is
|
|
3296
|
-
* durable backend (JSON / SQLite / IndexedDB) swaps in through the
|
|
3665
|
+
* there is no idle-TTL and no eviction: a persisted conversation lives until an explicit `delete`. A
|
|
3666
|
+
* durable backend (JSON / SQLite / IndexedDB) swaps in through the same interface without touching
|
|
3297
3667
|
* the {@link import('../ConversationManager.js').ConversationManager} or the
|
|
3298
3668
|
* {@link import('../Conversation.js').Conversation} — its driver-pluggable twin is
|
|
3299
3669
|
* {@link import('./DatabaseConversationStore.js').DatabaseConversationStore} (the snapshot as one
|
|
3300
3670
|
* opaque JSON column).
|
|
3301
3671
|
*
|
|
3302
3672
|
* - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.
|
|
3303
|
-
* - **`set` inserts / replaces under the snapshot's
|
|
3673
|
+
* - **`set` inserts / replaces under the snapshot's own `id`** (no separate id param).
|
|
3304
3674
|
* - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
3305
3675
|
*
|
|
3306
|
-
* The public surface is
|
|
3676
|
+
* The public surface is exactly `get` / `set` / `delete` — no extra members (the method
|
|
3307
3677
|
* bijection with {@link ConversationStoreInterface}). Hydration is a caller concern: a
|
|
3308
3678
|
* {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds
|
|
3309
3679
|
* the live conversation through the `snapshot` option (its `open` / `save`).
|
|
@@ -3322,8 +3692,27 @@ export declare function joinThinking(running: string | undefined, next: string):
|
|
|
3322
3692
|
*/
|
|
3323
3693
|
export declare class MemoryConversationStore implements ConversationStoreInterface {
|
|
3324
3694
|
#private;
|
|
3695
|
+
/**
|
|
3696
|
+
* Resolves the persisted snapshot for `id`, or `undefined` if none is stored.
|
|
3697
|
+
*
|
|
3698
|
+
* @param id - The conversation id to resolve (a {@link ConversationSnapshot.id})
|
|
3699
|
+
* @returns The persisted snapshot, or `undefined` if absent
|
|
3700
|
+
*/
|
|
3325
3701
|
get(id: string): Promise<ConversationSnapshot | undefined>;
|
|
3702
|
+
/**
|
|
3703
|
+
* Inserts or replaces a snapshot under its own `snapshot.id` (no separate id param —
|
|
3704
|
+
* mirroring {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`).
|
|
3705
|
+
*
|
|
3706
|
+
* @param snapshot - The snapshot to store (keyed by its `id`)
|
|
3707
|
+
* @returns A promise that resolves after the snapshot is stored
|
|
3708
|
+
*/
|
|
3326
3709
|
set(snapshot: ConversationSnapshot): Promise<void>;
|
|
3710
|
+
/**
|
|
3711
|
+
* Drops a snapshot by id; an absent id is a no-op (no throw).
|
|
3712
|
+
*
|
|
3713
|
+
* @param id - The conversation id to drop
|
|
3714
|
+
* @returns A promise that resolves after the snapshot is dropped
|
|
3715
|
+
*/
|
|
3327
3716
|
delete(id: string): Promise<void>;
|
|
3328
3717
|
}
|
|
3329
3718
|
|
|
@@ -3352,13 +3741,30 @@ export declare interface Message {
|
|
|
3352
3741
|
}
|
|
3353
3742
|
|
|
3354
3743
|
/**
|
|
3355
|
-
* Estimates the per-message role
|
|
3356
|
-
* adds on top of a message's content estimate —
|
|
3357
|
-
* conversation turn carries (its role tag, delimiters) that
|
|
3358
|
-
* content-only heuristic does not otherwise
|
|
3744
|
+
* Estimates the per-message role and framing overhead {@link import('./helpers.js').estimateMessages}
|
|
3745
|
+
* adds on top of a message's content estimate — `4` tokens for the fixed wire framing every
|
|
3746
|
+
* conversation turn carries (its role tag, its delimiters) that
|
|
3747
|
+
* {@link import('./helpers.js').estimateTokens}'s content-only heuristic does not otherwise
|
|
3748
|
+
* capture.
|
|
3359
3749
|
*/
|
|
3360
3750
|
export declare const MESSAGE_TOKEN_OVERHEAD = 4;
|
|
3361
3751
|
|
|
3752
|
+
/** Validates and projects conversation messages at a JSON wire boundary. */
|
|
3753
|
+
export declare const messageContract: ContractInterface<Readonly<{
|
|
3754
|
+
id: string;
|
|
3755
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
3756
|
+
content: string;
|
|
3757
|
+
} & {
|
|
3758
|
+
calls?: readonly Readonly<{
|
|
3759
|
+
id: string;
|
|
3760
|
+
name: string;
|
|
3761
|
+
arguments: {
|
|
3762
|
+
readonly [k: string]: JSONValue;
|
|
3763
|
+
};
|
|
3764
|
+
} & {}>[];
|
|
3765
|
+
images?: readonly string[];
|
|
3766
|
+
}>>;
|
|
3767
|
+
|
|
3362
3768
|
/**
|
|
3363
3769
|
* Carries the minimal data needed to author a {@link Message} — the `id` is
|
|
3364
3770
|
* assigned by the layer that stores it, so a caller supplies only role / content
|
|
@@ -3376,64 +3782,103 @@ export declare interface MessageInput {
|
|
|
3376
3782
|
}
|
|
3377
3783
|
|
|
3378
3784
|
/**
|
|
3379
|
-
* Stores immutable {@link Message}s in insertion order
|
|
3785
|
+
* Stores immutable {@link Message}s in insertion order and mints each `id` on `add` — the
|
|
3786
|
+
* message-store contract {@link AgentContextInterface.messages} is typed to, which the active
|
|
3787
|
+
* {@link ConversationInterface} satisfies structurally.
|
|
3380
3788
|
*
|
|
3381
3789
|
* @remarks
|
|
3382
3790
|
* - **Store.** Messages live in insertion order; `count` is how many are stored.
|
|
3383
|
-
* `add` takes one {@link MessageInput} or a batch and
|
|
3791
|
+
* `add` takes one {@link MessageInput} or a batch and mints each message's
|
|
3384
3792
|
* `id` (a random UUID), returning the created message(s). A stored message is
|
|
3385
3793
|
* immutable — created once from its input, never mutated.
|
|
3386
3794
|
* - **Lookup.** `message(id)` resolves one by id (`undefined` when absent);
|
|
3387
3795
|
* `messages()` lists every message in insertion order.
|
|
3388
|
-
* - **Removal.** `remove` drops one by id, or a batch — `true` only when
|
|
3796
|
+
* - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id
|
|
3389
3797
|
* was removed; `clear` empties the store.
|
|
3390
3798
|
* - **Event-free.** A purely data store — no Emitter, no events.
|
|
3391
3799
|
*/
|
|
3392
3800
|
export declare interface MessageManagerInterface {
|
|
3393
3801
|
readonly count: number;
|
|
3802
|
+
/**
|
|
3803
|
+
* Stores one {@link MessageInput}, or a batch — mints each message's `id` and returns the
|
|
3804
|
+
* created message or messages; a stored message is immutable.
|
|
3805
|
+
*/
|
|
3394
3806
|
add(input: MessageInput): Message;
|
|
3395
3807
|
add(inputs: readonly MessageInput[]): readonly Message[];
|
|
3808
|
+
/** Looks up one stored message by id (`undefined` when absent). */
|
|
3396
3809
|
message(id: string): Message | undefined;
|
|
3810
|
+
/** Lists every stored message, in insertion order. */
|
|
3397
3811
|
messages(): readonly Message[];
|
|
3812
|
+
/**
|
|
3813
|
+
* Removes one message by id, or a batch — `true` only when every supplied id was removed.
|
|
3814
|
+
*/
|
|
3398
3815
|
remove(id: string): boolean;
|
|
3399
3816
|
remove(ids: readonly string[]): boolean;
|
|
3817
|
+
/** Removes every stored message. */
|
|
3400
3818
|
clear(): void;
|
|
3401
3819
|
}
|
|
3402
3820
|
|
|
3403
3821
|
/** Names the role a {@link Message} plays in a conversation turn. */
|
|
3404
3822
|
export declare type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
3405
3823
|
|
|
3824
|
+
/**
|
|
3825
|
+
* Describes a conversation message's JSON wire projection.
|
|
3826
|
+
*
|
|
3827
|
+
* @remarks
|
|
3828
|
+
* The wire is strictly narrower than Message: non-JSON call arguments are refused,
|
|
3829
|
+
* and caller context is refused by the guard or dropped by the parser.
|
|
3830
|
+
*/
|
|
3831
|
+
export declare const messageShape: ObjectShape< {
|
|
3832
|
+
id: StringShape;
|
|
3833
|
+
role: LiteralShape<readonly ["system", "user", "assistant", "tool"]>;
|
|
3834
|
+
content: StringShape;
|
|
3835
|
+
calls: OptionalShape<ArrayShape<ObjectShape< {
|
|
3836
|
+
id: StringShape;
|
|
3837
|
+
name: StringShape;
|
|
3838
|
+
arguments: ObjectShape<Record<never, never>, JSONShape>;
|
|
3839
|
+
}, boolean | ContractShape>>>;
|
|
3840
|
+
images: OptionalShape<ArrayShape<StringShape>>;
|
|
3841
|
+
}, boolean | ContractShape>;
|
|
3842
|
+
|
|
3843
|
+
/**
|
|
3844
|
+
* Names the status a relay answers for a request body at or above its byte budget — `413`,
|
|
3845
|
+
* carried with no body and answered for an aborted inbound read as well.
|
|
3846
|
+
*/
|
|
3847
|
+
export declare const OVERSIZED_RELAY_STATUS = 413;
|
|
3848
|
+
|
|
3406
3849
|
/**
|
|
3407
3850
|
* Reports a provider stream cancelled mid-flight by its bound signal — thrown by a
|
|
3408
|
-
* {@link ProviderInterface}'s `stream`, carrying the {@link ProviderResult} assembled
|
|
3409
|
-
*
|
|
3851
|
+
* {@link ProviderInterface}'s `stream`, carrying the {@link ProviderResult} assembled from
|
|
3852
|
+
* whatever streamed before the cancel and the machine-readable `code` `'ABORT'`.
|
|
3410
3853
|
*
|
|
3411
3854
|
* @remarks
|
|
3412
3855
|
* Lets a caller recover the partial content (and any tool calls / usage seen so far)
|
|
3413
3856
|
* on cancellation: `catch` the throw, narrow with {@link isProviderAbortError}, and
|
|
3414
3857
|
* read `partial`. `code` is the machine-readable condition (`'ABORT'` — the only one this
|
|
3415
|
-
* error reports), so a `catch` branches on it rather than on the message string.
|
|
3858
|
+
* error reports), so a `catch` branches on it rather than on the message string. `cause`
|
|
3859
|
+
* holds the failure the cancel superseded when a throw raced the abort — the wire decoder's
|
|
3860
|
+
* {@link ProviderError}, say — and is undefined when the cancel was the only failure.
|
|
3416
3861
|
*/
|
|
3417
3862
|
export declare class ProviderAbortError extends Error {
|
|
3418
3863
|
/** Names the machine-readable condition — `'ABORT'`: a stream cancelled mid-flight. */
|
|
3419
3864
|
readonly code: "ABORT";
|
|
3420
3865
|
readonly partial: ProviderResult;
|
|
3421
|
-
constructor(partial: ProviderResult);
|
|
3866
|
+
constructor(partial: ProviderResult, options?: ErrorOptions);
|
|
3422
3867
|
}
|
|
3423
3868
|
|
|
3424
3869
|
/**
|
|
3425
|
-
* Represents one streamed delta a {@link ProviderInterface}'s `stream` yields — a
|
|
3426
|
-
*
|
|
3427
|
-
*
|
|
3870
|
+
* Represents one streamed delta a {@link ProviderInterface}'s `stream` yields — a unit tagged by
|
|
3871
|
+
* the channel it belongs to, so the agent loop can re-surface answer content and live reasoning
|
|
3872
|
+
* separately as it pumps.
|
|
3428
3873
|
*
|
|
3429
3874
|
* @remarks
|
|
3430
3875
|
* The discriminant `channel` names the axis that varies: a
|
|
3431
|
-
* `'content'` delta is a chunk of the assistant
|
|
3876
|
+
* `'content'` delta is a chunk of the assistant answer (the deltas that accumulate into
|
|
3432
3877
|
* {@link ProviderResult.content}); a `'thinking'` delta is a chunk of the model's
|
|
3433
|
-
*
|
|
3434
|
-
* `message.thinking` wire channel), surfaced
|
|
3878
|
+
* reasoning the provider separated from the answer (the daemon's native
|
|
3879
|
+
* `message.thinking` wire channel), surfaced live so a consumer can stream it into a
|
|
3435
3880
|
* collapsible without waiting for the assembled result. `text` is the delta's literal
|
|
3436
|
-
* text. Thinking
|
|
3881
|
+
* text. Thinking never re-enters the conversation — it is display/audit metadata, exactly
|
|
3437
3882
|
* as {@link ProviderResult.thinking} (the authoritative final accumulation) is.
|
|
3438
3883
|
*/
|
|
3439
3884
|
export declare type ProviderDelta = {
|
|
@@ -3445,10 +3890,51 @@ export declare type ProviderDelta = {
|
|
|
3445
3890
|
};
|
|
3446
3891
|
|
|
3447
3892
|
/**
|
|
3448
|
-
*
|
|
3449
|
-
*
|
|
3450
|
-
*
|
|
3451
|
-
*
|
|
3893
|
+
* Reports a coded provider failure with its HTTP status and underlying cause when available.
|
|
3894
|
+
*
|
|
3895
|
+
* @remarks
|
|
3896
|
+
* The provider base throws this error for a non-OK HTTP response, a missing response
|
|
3897
|
+
* body, or a missing settled result when strict assembly is enabled. Concrete wire
|
|
3898
|
+
* decoders also use it for malformed records and relayed provider failures.
|
|
3899
|
+
* `status` is present only for an `HTTP` failure; other codes leave it undefined.
|
|
3900
|
+
*/
|
|
3901
|
+
export declare class ProviderError extends Error {
|
|
3902
|
+
/** Names the machine-readable condition — `'HTTP'`: a non-OK response, including a relay refusing an oversized request with 413; `'PROTOCOL'`: a missing response body, a malformed wire record, or a strict stream with no settled result; `'PROVIDER'`: an upstream failure carried by a relay error record. */
|
|
3903
|
+
readonly code: ProviderErrorCode;
|
|
3904
|
+
/** Holds the response status for an HTTP failure, or undefined for other codes. */
|
|
3905
|
+
readonly status: number | undefined;
|
|
3906
|
+
constructor(code: ProviderErrorCode, message: string, options?: ProviderErrorOptions);
|
|
3907
|
+
}
|
|
3908
|
+
|
|
3909
|
+
/** Names the machine-readable provider failure conditions. */
|
|
3910
|
+
export declare type ProviderErrorCode =
|
|
3911
|
+
/** Reports a non-OK HTTP response, including a relay request rejected with status 413. */
|
|
3912
|
+
'HTTP'
|
|
3913
|
+
/** Reports a missing body, malformed wire record, or missing required settled result. */
|
|
3914
|
+
| 'PROTOCOL'
|
|
3915
|
+
/** Reports an upstream provider failure carried by a relay error record. */
|
|
3916
|
+
| 'PROVIDER';
|
|
3917
|
+
|
|
3918
|
+
/** Carries a provider failure's HTTP status and underlying cause. */
|
|
3919
|
+
export declare interface ProviderErrorOptions {
|
|
3920
|
+
readonly status?: number;
|
|
3921
|
+
readonly cause?: unknown;
|
|
3922
|
+
}
|
|
3923
|
+
|
|
3924
|
+
/** Holds the decoded contribution of a wire record to a provider turn. */
|
|
3925
|
+
export declare interface ProviderIncrement {
|
|
3926
|
+
readonly content: string;
|
|
3927
|
+
readonly thinking: string;
|
|
3928
|
+
readonly tools: readonly ToolCall[];
|
|
3929
|
+
readonly usage?: TokenUsage;
|
|
3930
|
+
readonly result?: ProviderResult;
|
|
3931
|
+
}
|
|
3932
|
+
|
|
3933
|
+
/**
|
|
3934
|
+
* Defines the pluggable LLM inference boundary — the one contract every agent chunk depends on. A
|
|
3935
|
+
* provider turns a conversation (plus optional tools) into either a single assembled {@link
|
|
3936
|
+
* ProviderResult} (`generate`) or a stream of {@link ProviderDelta}s that returns the assembled
|
|
3937
|
+
* result (`stream`).
|
|
3452
3938
|
*
|
|
3453
3939
|
* @remarks
|
|
3454
3940
|
* - `id` is a stable per-instance trace label; `name` identifies the backend
|
|
@@ -3464,9 +3950,9 @@ export declare interface ProviderInterface {
|
|
|
3464
3950
|
readonly id: string;
|
|
3465
3951
|
readonly name: string;
|
|
3466
3952
|
/**
|
|
3467
|
-
* Holds the model's preferred context framing, by section kind — an
|
|
3953
|
+
* Holds the model's preferred context framing, by section kind — an optional
|
|
3468
3954
|
* {@link ContextFormat} an {@link import('./AgentContext.js').AgentContext}
|
|
3469
|
-
* applies as the
|
|
3955
|
+
* applies as the provider-default level of its build cascade (beating the managers'
|
|
3470
3956
|
* built-in framing, beaten by a manager-options or per-item override). Omitted ⇒ the
|
|
3471
3957
|
* provider is framing-agnostic and the managers' built-in defaults apply unchanged.
|
|
3472
3958
|
*/
|
|
@@ -3482,14 +3968,14 @@ export declare interface ProviderInterface {
|
|
|
3482
3968
|
*/
|
|
3483
3969
|
generate(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): Promise<ProviderResult>;
|
|
3484
3970
|
/**
|
|
3485
|
-
* Streams one turn — yields
|
|
3486
|
-
*
|
|
3487
|
-
*
|
|
3488
|
-
* stream
|
|
3971
|
+
* Streams one turn — yields channel-tagged `content` / `thinking` {@link ProviderDelta}s as
|
|
3972
|
+
* they arrive and returns the assembled {@link ProviderResult} (the concatenated content,
|
|
3973
|
+
* any separated reasoning, any tool calls, and any usage) when the stream completes. A
|
|
3974
|
+
* mid-stream abort throws a `ProviderAbortError` carrying the partial result.
|
|
3489
3975
|
*
|
|
3490
3976
|
* @remarks
|
|
3491
|
-
*
|
|
3492
|
-
*
|
|
3977
|
+
* The `partial` holds whatever streamed before the cancel, so a caller can recover the
|
|
3978
|
+
* partial content.
|
|
3493
3979
|
*
|
|
3494
3980
|
* @param messages - The conversation so far
|
|
3495
3981
|
* @param signal - Bounds the request; an abort throws `ProviderAbortError`
|
|
@@ -3500,15 +3986,110 @@ export declare interface ProviderInterface {
|
|
|
3500
3986
|
stream(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): AsyncGenerator<ProviderDelta, ProviderResult>;
|
|
3501
3987
|
}
|
|
3502
3988
|
|
|
3989
|
+
/**
|
|
3990
|
+
* Configures a provider's deadline, transport, headers, and context framing.
|
|
3991
|
+
*
|
|
3992
|
+
* @remarks
|
|
3993
|
+
* `timeout` is an integer duration in milliseconds. Default: 120_000.
|
|
3994
|
+
* `fetch` defaults to the global transport bound to its global receiver.
|
|
3995
|
+
* `headers` runs for each request inside its deadline and receives the combined caller
|
|
3996
|
+
* and deadline signal so token requests can share that bound. It overrides the JSON
|
|
3997
|
+
* content type only when it returns that header. `format` is exposed to context assembly.
|
|
3998
|
+
*/
|
|
3999
|
+
export declare interface ProviderOptions {
|
|
4000
|
+
readonly timeout?: number;
|
|
4001
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
4002
|
+
readonly headers?: (signal: AbortSignal) => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>;
|
|
4003
|
+
readonly format?: ContextFormat;
|
|
4004
|
+
}
|
|
4005
|
+
|
|
4006
|
+
/** Defines the structural framing seam supplied by a concrete provider. */
|
|
4007
|
+
export declare interface ProviderParserInterface<TRecord = Readonly<Record<string, unknown>>> {
|
|
4008
|
+
/** Parses a decoded chunk into complete records. */
|
|
4009
|
+
parse(chunk: string): readonly TRecord[];
|
|
4010
|
+
/** Clears retained framing state. */
|
|
4011
|
+
clear(): void;
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4014
|
+
/** Carries the conversation and per-call configuration sent to a provider. */
|
|
4015
|
+
export declare interface ProviderRequest {
|
|
4016
|
+
readonly messages: readonly Message[];
|
|
4017
|
+
readonly tools?: readonly ToolDefinition[];
|
|
4018
|
+
readonly options?: ProviderStreamOptions;
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
/** Validates and projects provider requests at a JSON wire boundary. */
|
|
4022
|
+
export declare const providerRequestContract: ContractInterface<Readonly<{
|
|
4023
|
+
messages: readonly Readonly<{
|
|
4024
|
+
id: string;
|
|
4025
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
4026
|
+
content: string;
|
|
4027
|
+
} & {
|
|
4028
|
+
calls?: readonly Readonly<{
|
|
4029
|
+
id: string;
|
|
4030
|
+
name: string;
|
|
4031
|
+
arguments: {
|
|
4032
|
+
readonly [k: string]: JSONValue;
|
|
4033
|
+
};
|
|
4034
|
+
} & {}>[];
|
|
4035
|
+
images?: readonly string[];
|
|
4036
|
+
}>[];
|
|
4037
|
+
} & {
|
|
4038
|
+
tools?: readonly Readonly<{
|
|
4039
|
+
name: string;
|
|
4040
|
+
} & {
|
|
4041
|
+
description?: string;
|
|
4042
|
+
parameters?: {
|
|
4043
|
+
readonly [k: string]: JSONValue;
|
|
4044
|
+
};
|
|
4045
|
+
}>[];
|
|
4046
|
+
options?: Readonly<{} & {
|
|
4047
|
+
think?: boolean;
|
|
4048
|
+
schema?: {
|
|
4049
|
+
readonly [k: string]: JSONValue;
|
|
4050
|
+
};
|
|
4051
|
+
}>;
|
|
4052
|
+
}>>;
|
|
4053
|
+
|
|
4054
|
+
/**
|
|
4055
|
+
* Describes a provider request's JSON wire projection.
|
|
4056
|
+
*
|
|
4057
|
+
* @remarks
|
|
4058
|
+
* The wire is strictly narrower than ProviderRequest: non-JSON arguments, parameters,
|
|
4059
|
+
* or schema members are refused, and caller context is refused or dropped.
|
|
4060
|
+
*/
|
|
4061
|
+
export declare const providerRequestShape: ObjectShape< {
|
|
4062
|
+
messages: ArrayShape<ObjectShape< {
|
|
4063
|
+
id: StringShape;
|
|
4064
|
+
role: LiteralShape<readonly ["system", "user", "assistant", "tool"]>;
|
|
4065
|
+
content: StringShape;
|
|
4066
|
+
calls: OptionalShape<ArrayShape<ObjectShape< {
|
|
4067
|
+
id: StringShape;
|
|
4068
|
+
name: StringShape;
|
|
4069
|
+
arguments: ObjectShape<Record<never, never>, JSONShape>;
|
|
4070
|
+
}, boolean | ContractShape>>>;
|
|
4071
|
+
images: OptionalShape<ArrayShape<StringShape>>;
|
|
4072
|
+
}, boolean | ContractShape>>;
|
|
4073
|
+
tools: OptionalShape<ArrayShape<ObjectShape< {
|
|
4074
|
+
name: StringShape;
|
|
4075
|
+
description: OptionalShape<StringShape>;
|
|
4076
|
+
parameters: OptionalShape<ObjectShape<Record<never, never>, JSONShape>>;
|
|
4077
|
+
}, boolean | ContractShape>>>;
|
|
4078
|
+
options: OptionalShape<ObjectShape< {
|
|
4079
|
+
think: OptionalShape<BooleanShape>;
|
|
4080
|
+
schema: OptionalShape<ObjectShape<Record<never, never>, JSONShape>>;
|
|
4081
|
+
}, boolean | ContractShape>>;
|
|
4082
|
+
}, boolean | ContractShape>;
|
|
4083
|
+
|
|
3503
4084
|
/**
|
|
3504
4085
|
* Holds a single inference turn's structured outcome — the assembled assistant content,
|
|
3505
4086
|
* any reasoning the provider separated from it, any tool calls the model requested,
|
|
3506
4087
|
* and the token usage it reported.
|
|
3507
4088
|
*
|
|
3508
4089
|
* @remarks
|
|
3509
|
-
* `thinking` is present only when the turn produced reasoning the provider
|
|
3510
|
-
*
|
|
3511
|
-
* emitted, or a wire-side reasoning field) — `content` is always the
|
|
4090
|
+
* `thinking` is present only when the turn produced reasoning the provider split
|
|
4091
|
+
* away from the answer (an in-content `<think>…</think>` span a thinking model
|
|
4092
|
+
* emitted, or a wire-side reasoning field) — `content` is always the clean answer,
|
|
3512
4093
|
* and the thinking never re-enters the conversation (it is display/audit metadata,
|
|
3513
4094
|
* not prompt text). `tools` is present only when the model wants tool calls (an
|
|
3514
4095
|
* empty array is never surfaced — its absence means "no calls"). `usage` is present
|
|
@@ -3525,19 +4106,60 @@ export declare interface ProviderResult {
|
|
|
3525
4106
|
readonly usage?: TokenUsage;
|
|
3526
4107
|
}
|
|
3527
4108
|
|
|
4109
|
+
/** Validates and projects provider results at a JSON wire boundary. */
|
|
4110
|
+
export declare const providerResultContract: ContractInterface<Readonly<{
|
|
4111
|
+
content: string;
|
|
4112
|
+
} & {
|
|
4113
|
+
thinking?: string;
|
|
4114
|
+
tools?: readonly Readonly<{
|
|
4115
|
+
id: string;
|
|
4116
|
+
name: string;
|
|
4117
|
+
arguments: {
|
|
4118
|
+
readonly [k: string]: JSONValue;
|
|
4119
|
+
};
|
|
4120
|
+
} & {}>[];
|
|
4121
|
+
usage?: Readonly<{
|
|
4122
|
+
prompt: number;
|
|
4123
|
+
completion: number;
|
|
4124
|
+
total: number;
|
|
4125
|
+
} & {}>;
|
|
4126
|
+
}>>;
|
|
4127
|
+
|
|
4128
|
+
/**
|
|
4129
|
+
* Describes a provider result's JSON wire projection.
|
|
4130
|
+
*
|
|
4131
|
+
* @remarks
|
|
4132
|
+
* The wire is strictly narrower than ProviderResult: non-JSON call arguments are
|
|
4133
|
+
* refused, and caller context is refused or dropped.
|
|
4134
|
+
*/
|
|
4135
|
+
export declare const providerResultShape: ObjectShape< {
|
|
4136
|
+
content: StringShape;
|
|
4137
|
+
thinking: OptionalShape<StringShape>;
|
|
4138
|
+
tools: OptionalShape<ArrayShape<ObjectShape< {
|
|
4139
|
+
id: StringShape;
|
|
4140
|
+
name: StringShape;
|
|
4141
|
+
arguments: ObjectShape<Record<never, never>, JSONShape>;
|
|
4142
|
+
}, boolean | ContractShape>>>;
|
|
4143
|
+
usage: OptionalShape<ObjectShape< {
|
|
4144
|
+
prompt: NumberShape;
|
|
4145
|
+
completion: NumberShape;
|
|
4146
|
+
total: NumberShape;
|
|
4147
|
+
}, boolean | ContractShape>>;
|
|
4148
|
+
}, boolean | ContractShape>;
|
|
4149
|
+
|
|
3528
4150
|
/**
|
|
3529
4151
|
* Carries the per-call options threaded into a {@link ProviderInterface}'s `generate` / `stream` —
|
|
3530
|
-
* the bag a caller passes to influence
|
|
3531
|
-
*
|
|
4152
|
+
* the bag a caller passes to influence one inference call without reconfiguring the provider
|
|
4153
|
+
* instance.
|
|
3532
4154
|
*
|
|
3533
4155
|
* @remarks
|
|
3534
|
-
* `think`
|
|
4156
|
+
* `think` overrides the provider's constructed reasoning preference for this call: `true`
|
|
3535
4157
|
* asks the backend to separate reasoning natively (a thinking model returns it on its
|
|
3536
4158
|
* `message.thinking` channel, surfaced as `'thinking'` {@link ProviderDelta}s + the final
|
|
3537
4159
|
* {@link ProviderResult.thinking}); `false` suppresses it. `schema`, when given, asks the
|
|
3538
4160
|
* backend to constrain its response to the given JSON-Schema shape (the same open
|
|
3539
4161
|
* JSON-Schema record {@link ToolDefinition.parameters} already carries) — a structured-output
|
|
3540
|
-
* request for
|
|
4162
|
+
* request for this call only. Both omitted ⇒ the provider's own defaults apply (the
|
|
3541
4163
|
* constructor value / no schema constraint), so the contract stays backward-safe — a caller
|
|
3542
4164
|
* that passes no options behaves exactly as before.
|
|
3543
4165
|
*/
|
|
@@ -3549,9 +4171,302 @@ export declare interface ProviderStreamOptions {
|
|
|
3549
4171
|
}
|
|
3550
4172
|
|
|
3551
4173
|
/**
|
|
3552
|
-
*
|
|
3553
|
-
*
|
|
3554
|
-
*
|
|
4174
|
+
* Decodes UTF-8 chunks with a final flush and releases the stream on every exit.
|
|
4175
|
+
*
|
|
4176
|
+
* @param body - The readable byte stream
|
|
4177
|
+
* @param signal - The optional cancellation bound; abort ends iteration without further chunks
|
|
4178
|
+
* @returns Decoded text chunks, including a held decoder tail
|
|
4179
|
+
* @example
|
|
4180
|
+
* ```ts
|
|
4181
|
+
* const body = new Response('answer').body
|
|
4182
|
+
* if (body !== null) for await (const chunk of readChunks(body)) render(chunk)
|
|
4183
|
+
* ```
|
|
4184
|
+
*/
|
|
4185
|
+
export declare function readChunks(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<string>;
|
|
4186
|
+
|
|
4187
|
+
/**
|
|
4188
|
+
* Reads a UTF-8 prefix of a byte stream and cancels its remainder.
|
|
4189
|
+
*
|
|
4190
|
+
* @remarks
|
|
4191
|
+
* The `limit` parameter bounds bytes passed to the decoder, including a partial final
|
|
4192
|
+
* character. An omitted limit reads to completion. A source may deliver a chunk larger
|
|
4193
|
+
* than the remaining limit; its unused bytes are discarded without decoding.
|
|
4194
|
+
* The read can overshoot by one source chunk. An abort leaves completion false.
|
|
4195
|
+
*
|
|
4196
|
+
* @param body - The readable byte stream
|
|
4197
|
+
* @param limit - The maximum byte prefix, or undefined for the complete stream
|
|
4198
|
+
* @param signal - The optional cancellation bound; abort returns the decoded prefix
|
|
4199
|
+
* @returns The decoded prefix and whether EOF occurred within the byte budget
|
|
4200
|
+
* @example
|
|
4201
|
+
* ```ts
|
|
4202
|
+
* import { readText } from '@orkestrel/agent'
|
|
4203
|
+
*
|
|
4204
|
+
* const body = new Response('answer').body
|
|
4205
|
+
* if (body !== null) await readText(body, 3) // { text: 'ans', complete: false }
|
|
4206
|
+
* ```
|
|
4207
|
+
*/
|
|
4208
|
+
export declare function readText(body: ReadableStream<Uint8Array>, limit?: number, signal?: AbortSignal): Promise<TextRead>;
|
|
4209
|
+
|
|
4210
|
+
/**
|
|
4211
|
+
* Names the relay's newline-delimited JSON content type — `'application/x-ndjson; charset=utf-8'`,
|
|
4212
|
+
* the header a relay response carries beside `cache-control: no-store`.
|
|
4213
|
+
*/
|
|
4214
|
+
export declare const RELAY_CONTENT_TYPE = "application/x-ndjson; charset=utf-8";
|
|
4215
|
+
|
|
4216
|
+
/**
|
|
4217
|
+
* Names the public message for an unexpected upstream relay failure — `'relay provider failed'`,
|
|
4218
|
+
* the fixed text every `error` frame carries, so an upstream failure's own message never reaches
|
|
4219
|
+
* the browser.
|
|
4220
|
+
*/
|
|
4221
|
+
export declare const RELAY_PROVIDER_MESSAGE = "relay provider failed";
|
|
4222
|
+
|
|
4223
|
+
/** Carries a relay delta, settled result, remote abort, or remote failure. */
|
|
4224
|
+
export declare type RelayFrame = ProviderDelta | {
|
|
4225
|
+
readonly channel: 'result';
|
|
4226
|
+
readonly result: ProviderResult;
|
|
4227
|
+
} | {
|
|
4228
|
+
readonly channel: 'abort';
|
|
4229
|
+
readonly partial: ProviderResult;
|
|
4230
|
+
} | {
|
|
4231
|
+
readonly channel: 'error';
|
|
4232
|
+
readonly message: string;
|
|
4233
|
+
};
|
|
4234
|
+
|
|
4235
|
+
/** Validates and projects channel-discriminated relay frames at a JSON wire boundary. */
|
|
4236
|
+
export declare const relayFrameContract: ContractInterface<Readonly<{
|
|
4237
|
+
channel: "content" | "thinking";
|
|
4238
|
+
text: string;
|
|
4239
|
+
} & {}> | Readonly<{
|
|
4240
|
+
channel: "result";
|
|
4241
|
+
result: Readonly<{
|
|
4242
|
+
content: string;
|
|
4243
|
+
} & {
|
|
4244
|
+
thinking?: string;
|
|
4245
|
+
tools?: readonly Readonly<{
|
|
4246
|
+
id: string;
|
|
4247
|
+
name: string;
|
|
4248
|
+
arguments: {
|
|
4249
|
+
readonly [k: string]: JSONValue;
|
|
4250
|
+
};
|
|
4251
|
+
} & {}>[];
|
|
4252
|
+
usage?: Readonly<{
|
|
4253
|
+
prompt: number;
|
|
4254
|
+
completion: number;
|
|
4255
|
+
total: number;
|
|
4256
|
+
} & {}>;
|
|
4257
|
+
}>;
|
|
4258
|
+
} & {}> | Readonly<{
|
|
4259
|
+
channel: "abort";
|
|
4260
|
+
partial: Readonly<{
|
|
4261
|
+
content: string;
|
|
4262
|
+
} & {
|
|
4263
|
+
thinking?: string;
|
|
4264
|
+
tools?: readonly Readonly<{
|
|
4265
|
+
id: string;
|
|
4266
|
+
name: string;
|
|
4267
|
+
arguments: {
|
|
4268
|
+
readonly [k: string]: JSONValue;
|
|
4269
|
+
};
|
|
4270
|
+
} & {}>[];
|
|
4271
|
+
usage?: Readonly<{
|
|
4272
|
+
prompt: number;
|
|
4273
|
+
completion: number;
|
|
4274
|
+
total: number;
|
|
4275
|
+
} & {}>;
|
|
4276
|
+
}>;
|
|
4277
|
+
} & {}> | Readonly<{
|
|
4278
|
+
channel: "error";
|
|
4279
|
+
message: string;
|
|
4280
|
+
} & {}>>;
|
|
4281
|
+
|
|
4282
|
+
/**
|
|
4283
|
+
* Describes the channel-discriminated JSON relay wire projection.
|
|
4284
|
+
*
|
|
4285
|
+
* @remarks
|
|
4286
|
+
* The wire is strictly narrower than RelayFrame through its result and partial
|
|
4287
|
+
* fields: non-JSON arguments are refused, and caller context is refused or dropped.
|
|
4288
|
+
*/
|
|
4289
|
+
export declare const relayFrameShape: UnionShape<readonly [ObjectShape< {
|
|
4290
|
+
channel: LiteralShape<readonly ["content", "thinking"]>;
|
|
4291
|
+
text: StringShape;
|
|
4292
|
+
}, boolean | ContractShape>, ObjectShape< {
|
|
4293
|
+
channel: LiteralShape<readonly ["result"]>;
|
|
4294
|
+
result: ObjectShape< {
|
|
4295
|
+
content: StringShape;
|
|
4296
|
+
thinking: OptionalShape<StringShape>;
|
|
4297
|
+
tools: OptionalShape<ArrayShape<ObjectShape< {
|
|
4298
|
+
id: StringShape;
|
|
4299
|
+
name: StringShape;
|
|
4300
|
+
arguments: ObjectShape<Record<never, never>, JSONShape>;
|
|
4301
|
+
}, boolean | ContractShape>>>;
|
|
4302
|
+
usage: OptionalShape<ObjectShape< {
|
|
4303
|
+
prompt: NumberShape;
|
|
4304
|
+
completion: NumberShape;
|
|
4305
|
+
total: NumberShape;
|
|
4306
|
+
}, boolean | ContractShape>>;
|
|
4307
|
+
}, boolean | ContractShape>;
|
|
4308
|
+
}, boolean | ContractShape>, ObjectShape< {
|
|
4309
|
+
channel: LiteralShape<readonly ["abort"]>;
|
|
4310
|
+
partial: ObjectShape< {
|
|
4311
|
+
content: StringShape;
|
|
4312
|
+
thinking: OptionalShape<StringShape>;
|
|
4313
|
+
tools: OptionalShape<ArrayShape<ObjectShape< {
|
|
4314
|
+
id: StringShape;
|
|
4315
|
+
name: StringShape;
|
|
4316
|
+
arguments: ObjectShape<Record<never, never>, JSONShape>;
|
|
4317
|
+
}, boolean | ContractShape>>>;
|
|
4318
|
+
usage: OptionalShape<ObjectShape< {
|
|
4319
|
+
prompt: NumberShape;
|
|
4320
|
+
completion: NumberShape;
|
|
4321
|
+
total: NumberShape;
|
|
4322
|
+
}, boolean | ContractShape>>;
|
|
4323
|
+
}, boolean | ContractShape>;
|
|
4324
|
+
}, boolean | ContractShape>, ObjectShape< {
|
|
4325
|
+
channel: LiteralShape<readonly ["error"]>;
|
|
4326
|
+
message: StringShape;
|
|
4327
|
+
}, boolean | ContractShape>]>;
|
|
4328
|
+
|
|
4329
|
+
/** Defines a host-independent relay request handler. */
|
|
4330
|
+
export declare type RelayHandler = (request: Request) => Promise<Response>;
|
|
4331
|
+
|
|
4332
|
+
/** Configures the upstream provider, mandatory authorization, and request byte limit. */
|
|
4333
|
+
export declare interface RelayOptions {
|
|
4334
|
+
readonly provider: ProviderInterface;
|
|
4335
|
+
/**
|
|
4336
|
+
* Authorizes the request before its body is read.
|
|
4337
|
+
*
|
|
4338
|
+
* @remarks
|
|
4339
|
+
* The hook must not consume the request body; a body-reading hook locks the stream
|
|
4340
|
+
* and the handler answers with the `400` status. The relay performs no origin or
|
|
4341
|
+
* method check. An application trusting an ambient credential such as a cookie
|
|
4342
|
+
* must compose origin and CSRF middleware before the handler to prevent cross-site calls.
|
|
4343
|
+
*/
|
|
4344
|
+
readonly authorize: (request: Request) => boolean | Promise<boolean>;
|
|
4345
|
+
/**
|
|
4346
|
+
* Bounds the request body in bytes; the handler answers with the `413` status
|
|
4347
|
+
* for a body at or above the limit.
|
|
4348
|
+
*/
|
|
4349
|
+
readonly limit?: number;
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4352
|
+
/**
|
|
4353
|
+
* Carries provider calls over an authenticated NDJSON relay endpoint.
|
|
4354
|
+
*
|
|
4355
|
+
* @remarks
|
|
4356
|
+
* The `ToolCall.caller` member never crosses the hop. The wire body is an owned snapshot of
|
|
4357
|
+
* the projection read through property descriptors, so a serializer reachable only through a
|
|
4358
|
+
* `get` trap or a prototype is never consulted; an own function-valued property such as a
|
|
4359
|
+
* `toJSON` method is a value outside JSON and is refused before fetching, with the clone's
|
|
4360
|
+
* failure as the refusal's `cause`. A remote abort reconstructs a `ProviderAbortError` instance
|
|
4361
|
+
* without aborting the
|
|
4362
|
+
* local signal; the `Agent` runtime treats that instance as an error unless its own bound
|
|
4363
|
+
* signal is aborted.
|
|
4364
|
+
* Content is preserved verbatim, including literal thinking tags.
|
|
4365
|
+
* A refusal reaches the browser as a `ProviderError` instance with the `HTTP` code and status.
|
|
4366
|
+
* This is the browser end alone; {@link createRelay} mounts the server end, and
|
|
4367
|
+
* {@link createRelayProvider}'s example is the browser half of that pair.
|
|
4368
|
+
*
|
|
4369
|
+
* @example
|
|
4370
|
+
* ```ts
|
|
4371
|
+
* import type { ProviderResult } from '@orkestrel/agent'
|
|
4372
|
+
* import { RelayProvider } from '@orkestrel/agent'
|
|
4373
|
+
* // The browser application supplies this parser dependency.
|
|
4374
|
+
* import { createNDJSONParser } from '@orkestrel/ndjson'
|
|
4375
|
+
*
|
|
4376
|
+
* export function ask(bearer: string, signal: AbortSignal): Promise<ProviderResult> {
|
|
4377
|
+
* const browser = new RelayProvider({
|
|
4378
|
+
* url: 'https://relay.example/relay',
|
|
4379
|
+
* parser: createNDJSONParser,
|
|
4380
|
+
* headers: () => ({ authorization: `Bearer ${bearer}` }),
|
|
4381
|
+
* })
|
|
4382
|
+
* return browser.generate([{ id: 'ask', role: 'user', content: 'ping' }], signal)
|
|
4383
|
+
* }
|
|
4384
|
+
* ```
|
|
4385
|
+
*/
|
|
4386
|
+
export declare class RelayProvider extends AgentProvider {
|
|
4387
|
+
#private;
|
|
4388
|
+
constructor(options: RelayProviderOptions);
|
|
4389
|
+
/** Identifies the relay backend. */
|
|
4390
|
+
readonly name = "relay";
|
|
4391
|
+
/** Creates fresh framing state for each response. */
|
|
4392
|
+
frame(): ProviderParserInterface;
|
|
4393
|
+
/**
|
|
4394
|
+
* Projects declared request fields and refuses values the JSON wire cannot carry.
|
|
4395
|
+
*
|
|
4396
|
+
* @remarks
|
|
4397
|
+
* The snapshot is taken from property descriptors, so a custom serializer a projected
|
|
4398
|
+
* value carries is ignored rather than consulted and cannot reach the wire.
|
|
4399
|
+
*
|
|
4400
|
+
* @param request - The domain conversation and call configuration
|
|
4401
|
+
* @returns The validated wire request with caller context omitted
|
|
4402
|
+
* @throws {ProviderError} Thrown when the snapshot cannot be taken — a hostile read or a
|
|
4403
|
+
* value outside JSON — carrying that failure as its `cause`, and when the snapshot the
|
|
4404
|
+
* projection produced is not a valid wire request
|
|
4405
|
+
*/
|
|
4406
|
+
body(request: ProviderRequest): object;
|
|
4407
|
+
/**
|
|
4408
|
+
* Validates a relay frame and translates its channel into the shared stream engine.
|
|
4409
|
+
*
|
|
4410
|
+
* @param record - The framed wire record
|
|
4411
|
+
* @returns A delta contribution or authoritative result
|
|
4412
|
+
* @throws {ProviderAbortError} Thrown for a remote abort carrying its partial
|
|
4413
|
+
* @throws {ProviderError} Thrown for a malformed frame or remote provider failure
|
|
4414
|
+
*/
|
|
4415
|
+
read(record: Readonly<Record<string, unknown>>): ProviderIncrement;
|
|
4416
|
+
/**
|
|
4417
|
+
* Recovers an unterminated final frame by completing its NDJSON line.
|
|
4418
|
+
*
|
|
4419
|
+
* @param parser - The call's retained framing state
|
|
4420
|
+
* @returns Records completed by the final newline
|
|
4421
|
+
*/
|
|
4422
|
+
finish(parser: ProviderParserInterface): ReadonlyArray<Readonly<Record<string, unknown>>>;
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4425
|
+
/** Configures a relay destination and its fresh structural parser factory. */
|
|
4426
|
+
export declare interface RelayProviderOptions extends ProviderOptions {
|
|
4427
|
+
readonly url: string;
|
|
4428
|
+
/** Creates a fresh parser for each relay response stream. */
|
|
4429
|
+
readonly parser: () => ProviderParserInterface;
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4432
|
+
/**
|
|
4433
|
+
* Streams a provider call as validated NDJSON frames under response backpressure.
|
|
4434
|
+
*
|
|
4435
|
+
* @remarks
|
|
4436
|
+
* Cancellation aborts upstream before returning its iterator. Request listeners are
|
|
4437
|
+
* released on settlement. Unexpected provider failures carry a fixed public message.
|
|
4438
|
+
* An inbound abort leaves the response body neither closed nor errored — a server runtime
|
|
4439
|
+
* cancels that body when the client disconnects — so a consumer that aborts the inbound
|
|
4440
|
+
* signal itself must cancel the body rather than keep reading it.
|
|
4441
|
+
*
|
|
4442
|
+
* @example
|
|
4443
|
+
* ```ts
|
|
4444
|
+
* import type { ProviderInterface } from '@orkestrel/agent'
|
|
4445
|
+
* import { RelayStream } from '@orkestrel/agent'
|
|
4446
|
+
*
|
|
4447
|
+
* export function respond(provider: ProviderInterface, signal: AbortSignal): Response {
|
|
4448
|
+
* return new RelayStream({ provider, request: { messages: [] }, signal }).response
|
|
4449
|
+
* }
|
|
4450
|
+
* ```
|
|
4451
|
+
*/
|
|
4452
|
+
export declare class RelayStream {
|
|
4453
|
+
#private;
|
|
4454
|
+
constructor(options: RelayStreamOptions);
|
|
4455
|
+
/** Exposes the pull-driven response for the provider call. */
|
|
4456
|
+
get response(): Response;
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4459
|
+
/** Carries the upstream call and cancellation bound of a relay response stream. */
|
|
4460
|
+
export declare interface RelayStreamOptions {
|
|
4461
|
+
readonly provider: ProviderInterface;
|
|
4462
|
+
readonly request: ProviderRequest;
|
|
4463
|
+
readonly signal: AbortSignal;
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
/**
|
|
4467
|
+
* Renders a path-addressed text body as a fenced reference block — a `File: <path>` label line
|
|
4468
|
+
* over a language-tagged fence, the framing an
|
|
4469
|
+
* {@link import('./AgentContext.js').AgentContext}'s active-workspace text-file render emits.
|
|
3555
4470
|
*
|
|
3556
4471
|
* @remarks
|
|
3557
4472
|
* Produces `` File: <path>\n```<language>\n<content>\n``` `` — the `File:` label line, then a
|
|
@@ -3577,10 +4492,10 @@ export declare function renderFencedFile(path: string, language: string, content
|
|
|
3577
4492
|
|
|
3578
4493
|
/**
|
|
3579
4494
|
* Renders one context section — the resolved `open`, each item's rendering, and the resolved
|
|
3580
|
-
* `close` when one exists, blank-line joined.
|
|
4495
|
+
* `close` when one exists, blank-line joined; `undefined` when the section has no items.
|
|
3581
4496
|
*
|
|
3582
4497
|
* @remarks
|
|
3583
|
-
* Pure and total. A section with
|
|
4498
|
+
* Pure and total. A section with no items renders nothing (`undefined`), so an empty or fully
|
|
3584
4499
|
* scoped-out manager stays silent — its `open` / `close` never appear without items. `close`
|
|
3585
4500
|
* is the only optional slot: an unset one (there is no built-in close) drops the
|
|
3586
4501
|
* trailing line.
|
|
@@ -3602,13 +4517,13 @@ export declare function renderFencedFile(path: string, language: string, content
|
|
|
3602
4517
|
export declare function renderSection<T>(open: string, items: readonly T[], render: (item: T) => string, close: string | undefined): string | undefined;
|
|
3603
4518
|
|
|
3604
4519
|
/**
|
|
3605
|
-
* Resolves one section's
|
|
3606
|
-
* provider default.
|
|
4520
|
+
* Resolves one section's close text through the format cascade — manager-options override >
|
|
4521
|
+
* provider default; `undefined` when neither sets one, because there is no built-in close.
|
|
3607
4522
|
*
|
|
3608
4523
|
* @remarks
|
|
3609
|
-
* Pure and total. There is
|
|
4524
|
+
* Pure and total. There is no built-in close, so a section with neither level set returns
|
|
3610
4525
|
* `undefined` and {@link renderSection} appends no closing line. Paired with
|
|
3611
|
-
* {@link resolveOpen}, one level can
|
|
4526
|
+
* {@link resolveOpen}, one level can wrap the whole group.
|
|
3612
4527
|
*
|
|
3613
4528
|
* @typeParam T - The section item the manager renders
|
|
3614
4529
|
* @param manager - The section source (its `format` override)
|
|
@@ -3624,14 +4539,14 @@ export declare function renderSection<T>(open: string, items: readonly T[], rend
|
|
|
3624
4539
|
export declare function resolveClose<T>(manager: ContextSectionSourceInterface<T>, provider: ContextSectionFormat<T> | undefined): string | undefined;
|
|
3625
4540
|
|
|
3626
4541
|
/**
|
|
3627
|
-
* Resolves
|
|
3628
|
-
*
|
|
4542
|
+
* Resolves one item's rendering through the format cascade — item override > manager-options
|
|
4543
|
+
* override > provider default > built-in rendering.
|
|
3629
4544
|
*
|
|
3630
4545
|
* @remarks
|
|
3631
4546
|
* Pure and total. The item's own `override` is the most-specific level (a fully-rendered
|
|
3632
4547
|
* string for that item alone). A manager's `render(item)` already encapsulates
|
|
3633
4548
|
* `[options-override → built-in]`, so it is reached only when no higher level applies — and
|
|
3634
|
-
* there it
|
|
4549
|
+
* there it is the built-in rendering.
|
|
3635
4550
|
*
|
|
3636
4551
|
* @typeParam T - The section item being rendered (it may carry its own `override`)
|
|
3637
4552
|
* @param manager - The section source (its `format` override + its built-in `render`)
|
|
@@ -3651,13 +4566,13 @@ export declare function resolveItem<T extends {
|
|
|
3651
4566
|
}>(manager: ContextSectionSourceInterface<T>, provider: ContextSectionFormat<T> | undefined, item: T): string;
|
|
3652
4567
|
|
|
3653
4568
|
/**
|
|
3654
|
-
* Resolves one section's
|
|
4569
|
+
* Resolves one section's open text through the format cascade — manager-options override >
|
|
3655
4570
|
* provider default > built-in header.
|
|
3656
4571
|
*
|
|
3657
4572
|
* @remarks
|
|
3658
|
-
* Pure and total. The leading text has
|
|
4573
|
+
* Pure and total. The leading text has no per-item level. A manager's `open` already
|
|
3659
4574
|
* encapsulates `[options-override → built-in]`, so it is reached only when neither the
|
|
3660
|
-
* override's `open` nor the provider's `open` applies — and there it
|
|
4575
|
+
* override's `open` nor the provider's `open` applies — and there it is the built-in header.
|
|
3661
4576
|
*
|
|
3662
4577
|
* @typeParam T - The section item the manager renders
|
|
3663
4578
|
* @param manager - The section source (its `format` override + its built-in `open`)
|
|
@@ -3674,15 +4589,15 @@ export declare function resolveOpen<T>(manager: ContextSectionSourceInterface<T>
|
|
|
3674
4589
|
|
|
3675
4590
|
/**
|
|
3676
4591
|
* Holds the immutable per-run outcome an {@link AgentInterface}'s loop settles on — the value its
|
|
3677
|
-
* run
|
|
3678
|
-
*
|
|
4592
|
+
* run returns, assembled from there into the {@link AgentResult} its `stream`'s `result` promise
|
|
4593
|
+
* resolves.
|
|
3679
4594
|
*
|
|
3680
4595
|
* @remarks
|
|
3681
4596
|
* Computed inside one run (so concurrent runs never share state) and returned once, when the
|
|
3682
4597
|
* loop settles: `content` is the streamed assistant text, `thinking` the reasoning the
|
|
3683
4598
|
* provider calls separated from it ({@link ProviderResult.thinking}, joined across calls —
|
|
3684
4599
|
* `undefined` when none surfaced), `usage` the summed {@link TokenUsage} (present only when
|
|
3685
|
-
* a provider call reported it), `partial` is `true` when a cancel committed the run early
|
|
4600
|
+
* a provider call reported it), `partial` is `true` when a cancel committed the run early or
|
|
3686
4601
|
* when the loop exhausted its `limit` with unresolved tool intent, and `exhausted` is `true`
|
|
3687
4602
|
* in that second case specifically (a distinct, non-cancel cause the {@link AgentEventMap}
|
|
3688
4603
|
* `exhaust` event observes). It is the settled outcome one run returns, before the agent folds
|
|
@@ -3697,7 +4612,8 @@ export declare interface RunOutcome {
|
|
|
3697
4612
|
}
|
|
3698
4613
|
|
|
3699
4614
|
/**
|
|
3700
|
-
* Sanitizes one reported token count into a safe non-negative integer
|
|
4615
|
+
* Sanitizes one reported token count into a safe non-negative integer — a non-finite or
|
|
4616
|
+
* non-positive value becomes `0`, and a positive fractional value floors down.
|
|
3701
4617
|
*
|
|
3702
4618
|
* @param value - The token count to sanitize
|
|
3703
4619
|
* @returns The floored count, or `0` when the value is non-finite or non-positive
|
|
@@ -3725,23 +4641,25 @@ export declare function sanitizeToken(value: number): number;
|
|
|
3725
4641
|
export declare function sanitizeUsage(usage: TokenUsage): TokenUsage;
|
|
3726
4642
|
|
|
3727
4643
|
/**
|
|
3728
|
-
* Represents a named, immutable filter over a richer context's items — an optional
|
|
3729
|
-
*
|
|
3730
|
-
*
|
|
4644
|
+
* Represents a named, immutable filter over a richer context's items — an optional allow-list per
|
|
4645
|
+
* category (`instructions` / `tools` / `files`), each keyed by that category's identity (an
|
|
4646
|
+
* instruction's `name`, a tool's `name`, a workspace file's `path`) and read as an allow-list:
|
|
4647
|
+
* `undefined` lets everything pass, `[]` lets nothing pass, and a non-empty list passes the listed
|
|
4648
|
+
* keys alone. `narrow` composes a tighter child by set intersection.
|
|
3731
4649
|
*
|
|
3732
4650
|
* @remarks
|
|
3733
|
-
* - **A category list is three-way.** `undefined` ⇒
|
|
3734
|
-
* pass); `[]` ⇒
|
|
4651
|
+
* - **A category list is three-way.** `undefined` ⇒ no constraint on that category (all
|
|
4652
|
+
* pass); `[]` ⇒ none pass; a non-empty list ⇒ only the listed keys pass. The build
|
|
3735
4653
|
* step / loop apply this through `filterAllowList`.
|
|
3736
|
-
* - **Immutable.** The `id` is minted at construction; every supplied list is
|
|
4654
|
+
* - **Immutable.** The `id` is minted at construction; every supplied list is copied in
|
|
3737
4655
|
* (so a later mutation of the caller's array can't leak in), and the lists are
|
|
3738
|
-
* `readonly`. A `Scope` is never mutated after construction — `narrow` returns a
|
|
4656
|
+
* `readonly`. A `Scope` is never mutated after construction — `narrow` returns a new
|
|
3739
4657
|
* one rather than altering this one.
|
|
3740
|
-
* - **`narrow` is set-
|
|
3741
|
-
* per category is the intersection of
|
|
4658
|
+
* - **`narrow` is set-intersection (immutable composition).** A child scope's visible set
|
|
4659
|
+
* per category is the intersection of this scope's list and the config's list — but
|
|
3742
4660
|
* `undefined` means "no constraint", so it acts as the universal set: intersecting
|
|
3743
4661
|
* `undefined` with a list yields the list, and `undefined` with `undefined` stays
|
|
3744
|
-
* `undefined`. Narrowing can only
|
|
4662
|
+
* `undefined`. Narrowing can only tighten, never widen — a key excluded by a parent
|
|
3745
4663
|
* can never be re-admitted by a child.
|
|
3746
4664
|
*
|
|
3747
4665
|
* @example
|
|
@@ -3765,16 +4683,17 @@ export declare class Scope implements ScopeInterface {
|
|
|
3765
4683
|
}
|
|
3766
4684
|
|
|
3767
4685
|
/**
|
|
3768
|
-
* Lists the per-category allow-lists a {@link ScopeInterface} carries — an optional
|
|
3769
|
-
*
|
|
3770
|
-
*
|
|
3771
|
-
* `
|
|
4686
|
+
* Lists the per-category allow-lists a {@link ScopeInterface} carries — an optional `readonly
|
|
4687
|
+
* string[]` for `instructions`, for `tools`, and for `files`, each keyed by that category's
|
|
4688
|
+
* identity (an instruction's `name`, a tool's `name`, a workspace file's `path`) and read as an
|
|
4689
|
+
* allow-list: `undefined` lets everything pass, `[]` lets nothing pass, and a non-empty list passes
|
|
4690
|
+
* the listed keys alone.
|
|
3772
4691
|
*
|
|
3773
4692
|
* @remarks
|
|
3774
|
-
* Each list is
|
|
3775
|
-
* ⇒
|
|
4693
|
+
* Each list is three-way (see {@link import('./helpers.js').filterAllowList}): `undefined`
|
|
4694
|
+
* ⇒ no constraint on that category (all pass); `[]` ⇒ none pass; a non-empty list ⇒ only
|
|
3776
4695
|
* the listed keys pass. It is the shape both a {@link ScopeInput} and `Scope.narrow`
|
|
3777
|
-
* accept (a `name`-less narrowing config). `files` filters the
|
|
4696
|
+
* accept (a `name`-less narrowing config). `files` filters the active workspace's rendered
|
|
3778
4697
|
* files (by `path`) in {@link AgentContextInterface.build} — both the text files folded into
|
|
3779
4698
|
* the system block and the image files attached to the last user message.
|
|
3780
4699
|
*/
|
|
@@ -3784,7 +4703,7 @@ export declare interface ScopeFilter {
|
|
|
3784
4703
|
/** Lists the allowed tool `name`s (`undefined` ⇒ all, `[]` ⇒ none, else only-listed). */
|
|
3785
4704
|
readonly tools?: readonly string[];
|
|
3786
4705
|
/**
|
|
3787
|
-
* Lists the allowed
|
|
4706
|
+
* Lists the allowed active-workspace file `path`s (`undefined` ⇒ all, `[]` ⇒ none, else only-listed) —
|
|
3788
4707
|
* the filter {@link AgentContextInterface.build} applies to the active workspace's
|
|
3789
4708
|
* {@link import('@orkestrel/workspace').WorkspaceInterface.files} before rendering them (text → the system block, image →
|
|
3790
4709
|
* the last user message).
|
|
@@ -3801,33 +4720,35 @@ export declare interface ScopeInput extends ScopeFilter {
|
|
|
3801
4720
|
}
|
|
3802
4721
|
|
|
3803
4722
|
/**
|
|
3804
|
-
* Represents a named, immutable filter over a richer context's items — the per-category
|
|
3805
|
-
*
|
|
3806
|
-
*
|
|
4723
|
+
* Represents a named, immutable filter over a richer context's items — the per-category allow-lists
|
|
4724
|
+
* ({@link ScopeFilter}) plus an `id` / `name`, and a `narrow` that composes a tighter child by set
|
|
4725
|
+
* intersection.
|
|
3807
4726
|
*
|
|
3808
4727
|
* @remarks
|
|
3809
4728
|
* Each list is three-way (`undefined` ⇒ all, `[]` ⇒ none, else only-listed). `narrow`
|
|
3810
|
-
* returns a
|
|
4729
|
+
* returns a new scope whose per-category visible set is the intersection of this scope's
|
|
3811
4730
|
* list and the config's — with `undefined` treated as the universal set (no constraint),
|
|
3812
4731
|
* so `undefined ∩ list = list` and `undefined ∩ undefined = undefined`. Narrowing can
|
|
3813
|
-
* only
|
|
4732
|
+
* only tighten (a parent-excluded key never returns); the scope itself is never mutated.
|
|
3814
4733
|
*/
|
|
3815
4734
|
export declare interface ScopeInterface extends ScopeFilter {
|
|
3816
4735
|
readonly id: string;
|
|
3817
4736
|
readonly name: string;
|
|
3818
4737
|
/**
|
|
3819
|
-
* Composes a tighter child scope —
|
|
3820
|
-
*
|
|
4738
|
+
* Composes a tighter child scope — each category is the set intersection of this scope's
|
|
4739
|
+
* list and `config`'s (an `undefined` side imposing no constraint), returned as a new
|
|
4740
|
+
* scope that leaves this one unchanged.
|
|
3821
4741
|
*
|
|
3822
4742
|
* @param config - The narrowing allow-lists (a `name`-less {@link ScopeFilter})
|
|
3823
|
-
* @returns A
|
|
4743
|
+
* @returns A new, tighter {@link ScopeInterface} (this one is left unchanged)
|
|
3824
4744
|
*/
|
|
3825
4745
|
narrow(config: ScopeFilter): ScopeInterface;
|
|
3826
4746
|
}
|
|
3827
4747
|
|
|
3828
4748
|
/**
|
|
3829
|
-
* Registers the named filters a richer context reuses — immutable {@link Scope}s keyed by
|
|
3830
|
-
*
|
|
4749
|
+
* Registers the named filters a richer context reuses — immutable {@link Scope}s keyed by their
|
|
4750
|
+
* minted `id`, in insertion order, where `create` always mints and stores rather than overwriting,
|
|
4751
|
+
* and an observable `emitter` reports each change.
|
|
3831
4752
|
*
|
|
3832
4753
|
* @remarks
|
|
3833
4754
|
* - **Registry.** Scopes live in an insertion-ordered `Map` keyed by their minted `id`;
|
|
@@ -3836,11 +4757,11 @@ export declare interface ScopeInterface extends ScopeFilter {
|
|
|
3836
4757
|
* one up, and `scopes()` lists them in insertion order. (Unlike the name-keyed
|
|
3837
4758
|
* instruction registry, a scope's key is its minted `id`, so two scopes may share a
|
|
3838
4759
|
* `name`; `create` therefore always adds — it never overwrites.)
|
|
3839
|
-
* - **Removal.** `remove` drops one by id, or a batch — `true` only when
|
|
4760
|
+
* - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id
|
|
3840
4761
|
* was removed; `clear` empties the registry.
|
|
3841
4762
|
* - **Observable.** The owned {@link emitter} ({@link ScopeManagerEventMap}) carries
|
|
3842
4763
|
* `create` (the created scope) / `remove` (the id) / `clear`. Every event is emitted
|
|
3843
|
-
* directly, strictly
|
|
4764
|
+
* directly, strictly after the map mutation completes; the emitter isolates a listener
|
|
3844
4765
|
* throw and routes it to its `error` handler (the `error` option), so a buggy observer can
|
|
3845
4766
|
* never corrupt a mutation.
|
|
3846
4767
|
*
|
|
@@ -3900,12 +4821,19 @@ export declare type ScopeManagerEventMap = {
|
|
|
3900
4821
|
export declare interface ScopeManagerInterface {
|
|
3901
4822
|
readonly emitter: EmitterInterface<ScopeManagerEventMap>;
|
|
3902
4823
|
readonly count: number;
|
|
4824
|
+
/**
|
|
4825
|
+
* Mints a scope from a {@link ScopeInput} (an `id` plus the per-category allow-lists) and
|
|
4826
|
+
* stores it — always adds, never overwrites.
|
|
4827
|
+
*/
|
|
3903
4828
|
create(input: ScopeInput): ScopeInterface;
|
|
4829
|
+
/** Looks up one scope by id (`undefined` when absent). */
|
|
3904
4830
|
scope(id: string): ScopeInterface | undefined;
|
|
3905
4831
|
/** Lists every scope, in insertion order. */
|
|
3906
4832
|
scopes(): readonly ScopeInterface[];
|
|
4833
|
+
/** Removes one scope by id, or a batch — `true` only when every supplied id was removed. */
|
|
3907
4834
|
remove(id: string): boolean;
|
|
3908
4835
|
remove(ids: readonly string[]): boolean;
|
|
4836
|
+
/** Removes every scope. */
|
|
3909
4837
|
clear(): void;
|
|
3910
4838
|
}
|
|
3911
4839
|
|
|
@@ -3925,9 +4853,9 @@ export declare interface ScopeManagerOptions {
|
|
|
3925
4853
|
*
|
|
3926
4854
|
* @remarks
|
|
3927
4855
|
* `summary` is the model-written digest of this slice (through the
|
|
3928
|
-
* {@link ConversationSummaryHandler}); `messages` are the folded
|
|
4856
|
+
* {@link ConversationSummaryHandler}); `messages` are the folded originals, retained in full so
|
|
3929
4857
|
* `rehydrate` can pull them back and `search` can scan them (compaction shrinks the model
|
|
3930
|
-
*
|
|
4858
|
+
* input, never discards history).
|
|
3931
4859
|
*/
|
|
3932
4860
|
export declare interface Section {
|
|
3933
4861
|
readonly id: string;
|
|
@@ -3938,15 +4866,17 @@ export declare interface Section {
|
|
|
3938
4866
|
}
|
|
3939
4867
|
|
|
3940
4868
|
/**
|
|
3941
|
-
* Runs one rehydrated agent and applies the partial-as-configurable-failure policy —
|
|
3942
|
-
*
|
|
3943
|
-
*
|
|
4869
|
+
* Runs one rehydrated agent and applies the partial-as-configurable-failure policy — a partial
|
|
4870
|
+
* run throws an {@link import('./errors.js').AgentJobError} unless the `partial` policy allows
|
|
4871
|
+
* it, and a natural finish resolves. The shared job-handler step `createAgentQueue` and
|
|
4872
|
+
* `createAgentRunner` both settle each job through, so the policy can never diverge between
|
|
4873
|
+
* them.
|
|
3944
4874
|
*
|
|
3945
4875
|
* @remarks
|
|
3946
|
-
* A turn that committed
|
|
3947
|
-
*
|
|
3948
|
-
* (the Queue's retries + a Runner's fail-fast then engage); the `partial` policy
|
|
3949
|
-
* it as success instead. A natural finish
|
|
4876
|
+
* A turn that committed partial (a cancel — abort / budget / timeout) is by default a
|
|
4877
|
+
* failure, so it throws an {@link import('./errors.js').AgentJobError} carrying the partial
|
|
4878
|
+
* (the Queue's retries + a Runner's fail-fast then engage); the `partial` policy resolves
|
|
4879
|
+
* it as success instead. A natural finish always resolves with its result.
|
|
3950
4880
|
*
|
|
3951
4881
|
* @param agent - The rehydrated {@link AgentInterface} to run to its {@link AgentResult}
|
|
3952
4882
|
* @param partial - The partial policy. If `true`, a partial result resolves as success; if
|
|
@@ -3969,7 +4899,7 @@ export declare function settleAgentJob(agent: AgentInterface, partial: boolean):
|
|
|
3969
4899
|
* @remarks
|
|
3970
4900
|
* Iterate `events` to consume the live `T` chunks as they arrive; `await result` for
|
|
3971
4901
|
* the eventual `R` outcome (it resolves once `events` completes). `abort(reason)`
|
|
3972
|
-
* cancels the in-flight operation — for an agent turn the `result` then
|
|
4902
|
+
* cancels the in-flight operation — for an agent turn the `result` then resolves
|
|
3973
4903
|
* (with a partial outcome), since a cancel is not an error.
|
|
3974
4904
|
*
|
|
3975
4905
|
* @typeParam T - The live event type the stream yields
|
|
@@ -4008,40 +4938,51 @@ export declare interface StreamInterface<T, R> {
|
|
|
4008
4938
|
*/
|
|
4009
4939
|
export declare function sumUsage(running: TokenUsage | undefined, next: TokenUsage): TokenUsage;
|
|
4010
4940
|
|
|
4941
|
+
/** Carries a decoded stream prefix and whether the stream ended within its byte budget. */
|
|
4942
|
+
export declare interface TextRead {
|
|
4943
|
+
readonly text: string;
|
|
4944
|
+
/**
|
|
4945
|
+
* Reports true only when a read observes the `done` flag before exhausting the
|
|
4946
|
+
* byte budget; an abort reports false.
|
|
4947
|
+
*/
|
|
4948
|
+
readonly complete: boolean;
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4011
4951
|
/**
|
|
4012
|
-
* Names the closing tag that ends a {@link THINK_OPEN} reasoning span
|
|
4013
|
-
* (the model was cut off mid-reasoning) is treated as thinking to its end
|
|
4014
|
-
* {@link import('./types.js').ThinkSplitterInterface.flush} settles it.
|
|
4952
|
+
* Names the closing tag that ends a {@link THINK_OPEN} reasoning span — `'</think>'`. A span the
|
|
4953
|
+
* stream never closes (the model was cut off mid-reasoning) is treated as thinking to its end,
|
|
4954
|
+
* and {@link import('./types.js').ThinkSplitterInterface.flush} settles it.
|
|
4015
4955
|
*/
|
|
4016
4956
|
export declare const THINK_CLOSE = "</think>";
|
|
4017
4957
|
|
|
4018
4958
|
/**
|
|
4019
4959
|
* Names the opening tag a {@link import('./ThinkSplitter.js').ThinkSplitter} recognizes as the start of
|
|
4020
|
-
* an in-content reasoning span — the de-facto wire convention thinking models
|
|
4021
|
-
* family) emit their chain-of-thought under when a daemon renders it inline
|
|
4022
|
-
* separate wire field. Paired with {@link THINK_CLOSE}.
|
|
4960
|
+
* an in-content reasoning span — `'<think>'`, the de-facto wire convention thinking models
|
|
4961
|
+
* (qwen3, DeepSeek-R1 family) emit their chain-of-thought under when a daemon renders it inline
|
|
4962
|
+
* instead of on a separate wire field. Paired with {@link THINK_CLOSE}.
|
|
4023
4963
|
*/
|
|
4024
4964
|
export declare const THINK_OPEN = "<think>";
|
|
4025
4965
|
|
|
4026
4966
|
/**
|
|
4027
|
-
* Feeds raw content deltas through a tiny stream-stateful state machine that routes
|
|
4028
|
-
*
|
|
4029
|
-
*
|
|
4030
|
-
* {@link import('./types.js').ProviderResult.thinking}.
|
|
4967
|
+
* Feeds raw content deltas through a tiny stream-stateful state machine that routes everything
|
|
4968
|
+
* inside a `<think>…</think>` span to `thinking` and returns everything outside it as clean
|
|
4969
|
+
* content, so a provider yields the answer alone and surfaces the reasoning as
|
|
4970
|
+
* {@link import('./types.js').ProviderResult.thinking}. A tag split across deltas is held until
|
|
4971
|
+
* disambiguated, `flush()` settles the stream end, and one splitter serves one stream.
|
|
4031
4972
|
*
|
|
4032
4973
|
* @remarks
|
|
4033
4974
|
* - **Cross-chunk tags.** A tag may arrive split across wire deltas (`'<thi'` then
|
|
4034
|
-
* `'nk>'`): any suffix of the pending text that is a strict
|
|
4035
|
-
* scanned for is
|
|
4975
|
+
* `'nk>'`): any suffix of the pending text that is a strict prefix of a tag being
|
|
4976
|
+
* scanned for is held back (neither surfaced nor routed) until the next delta — or
|
|
4036
4977
|
* `flush()` — disambiguates it. A held tag prefix that never completes is real
|
|
4037
4978
|
* content; a held close-tag prefix inside a span is thinking.
|
|
4038
|
-
* - **The
|
|
4039
|
-
*
|
|
4040
|
-
*
|
|
4041
|
-
* close therefore
|
|
4979
|
+
* - **The implicit leading open (the qwen3-template shape).** Some chat templates
|
|
4980
|
+
* pre-seed `<think>` into the prompt scaffold, so the wire stream begins
|
|
4981
|
+
* mid-reasoning and only a bare `</think>` appears. Before any tag event, a bare
|
|
4982
|
+
* close therefore reclassifies everything surfaced so far (plus the pre-close
|
|
4042
4983
|
* pending) as thinking — `content` is corrected retroactively (the already-returned
|
|
4043
4984
|
* prefix cannot be recalled, so `content` is the authoritative accumulation). The
|
|
4044
|
-
* rule is
|
|
4985
|
+
* rule is one-shot: after any tag event a bare `</think>` is plain text.
|
|
4045
4986
|
* - **Multiple spans** accumulate onto `thinking` in stream order. A nested-looking
|
|
4046
4987
|
* `<think>` inside an open span is thinking text (no nesting is tracked — the
|
|
4047
4988
|
* first `</think>` closes the span), matching how the models emit it.
|
|
@@ -4069,59 +5010,94 @@ export declare class ThinkSplitter implements ThinkSplitterInterface {
|
|
|
4069
5010
|
}
|
|
4070
5011
|
|
|
4071
5012
|
/**
|
|
4072
|
-
* Splits a thinking model's in-content `<think>…</think>` reasoning spans away from the
|
|
4073
|
-
*
|
|
4074
|
-
*
|
|
5013
|
+
* Splits a thinking model's in-content `<think>…</think>` reasoning spans away from the answer,
|
|
5014
|
+
* delta by delta with per-stream state, so a provider yields clean content alone and surfaces the
|
|
5015
|
+
* reasoning as {@link ProviderResult.thinking}.
|
|
4075
5016
|
*
|
|
4076
5017
|
* @remarks
|
|
4077
|
-
* - **Stateful across deltas.** A tag may arrive
|
|
5018
|
+
* - **Stateful across deltas.** A tag may arrive split across wire chunks (`'<thi'`
|
|
4078
5019
|
* ending one delta, `'nk>'` opening the next) — `split` holds any ambiguous tail
|
|
4079
5020
|
* back until the next delta (or `flush`) disambiguates it, so a partial tag is
|
|
4080
5021
|
* never leaked as content and never mis-eaten as thinking.
|
|
4081
|
-
* - **`split(delta)`** feeds one raw content delta and returns the
|
|
5022
|
+
* - **`split(delta)`** feeds one raw content delta and returns the clean content to
|
|
4082
5023
|
* surface for it (possibly `''` — for example mid-think). Text inside a
|
|
4083
5024
|
* `<think>…</think>` span accumulates on `thinking`; multiple spans accumulate in
|
|
4084
5025
|
* order; a nested-looking `<think>` inside an open span is thinking text (no
|
|
4085
5026
|
* nesting — the first `</think>` closes).
|
|
4086
|
-
* - **The
|
|
4087
|
-
*
|
|
4088
|
-
*
|
|
4089
|
-
* bare close therefore
|
|
5027
|
+
* - **The implicit leading open (the qwen3-template shape).** Some chat templates
|
|
5028
|
+
* pre-seed `<think>` into the prompt scaffold, so the wire stream begins
|
|
5029
|
+
* mid-reasoning and only a bare `</think>` ever appears. Before any tag event, a
|
|
5030
|
+
* bare close therefore reclassifies everything surfaced so far (plus the pre-close
|
|
4090
5031
|
* pending) as thinking — `content` is corrected retroactively, while the already
|
|
4091
5032
|
* `split`-returned prefix cannot be recalled (the one shape where the per-delta
|
|
4092
|
-
* returns over-report; `content` stays authoritative). The rule is
|
|
5033
|
+
* returns over-report; `content` stays authoritative). The rule is one-shot: after
|
|
4093
5034
|
* any tag event a bare `</think>` is plain text (prose quoting the tag stays text).
|
|
4094
|
-
* - **`flush()`** settles the stream end: an
|
|
5035
|
+
* - **`flush()`** settles the stream end: an unclosed `<think>` tail (the model was
|
|
4095
5036
|
* cut off mid-reasoning) lands on `thinking`; a held partial tag that never
|
|
4096
5037
|
* completed (`'<thi'` then EOF) is returned as the final clean-content delta —
|
|
4097
5038
|
* it was real text after all.
|
|
4098
5039
|
* - **`content` / `thinking`** are the authoritative accumulations so far (read them
|
|
4099
|
-
* after the stream — or mid-stream for a cancel's partial); `content` is the
|
|
5040
|
+
* after the stream — or mid-stream for a cancel's partial); `content` is the one
|
|
4100
5041
|
* exact clean-content source (the per-delta returns match it except across an
|
|
4101
|
-
* implicit-open reclassification). One splitter serves
|
|
5042
|
+
* implicit-open reclassification). One splitter serves one stream; create a fresh
|
|
4102
5043
|
* one per call ({@link import('./factories.js').createThinkSplitter}).
|
|
4103
5044
|
*/
|
|
4104
5045
|
export declare interface ThinkSplitterInterface {
|
|
4105
|
-
/** Holds the
|
|
5046
|
+
/** Holds the authoritative clean content accumulated so far (corrected across an implicit-open reclassification). */
|
|
4106
5047
|
readonly content: string;
|
|
4107
5048
|
/** Holds the reasoning text accumulated from every `<think>…</think>` span so far. */
|
|
4108
5049
|
readonly thinking: string;
|
|
4109
|
-
/**
|
|
5050
|
+
/**
|
|
5051
|
+
* Feeds one raw delta and returns the clean, non-think content to surface for it (possibly
|
|
5052
|
+
* `''`) — a tag split across deltas is held until disambiguated, never leaked as content
|
|
5053
|
+
* and never mis-eaten as thinking.
|
|
5054
|
+
*/
|
|
4110
5055
|
split(delta: string): string;
|
|
4111
|
-
/**
|
|
5056
|
+
/**
|
|
5057
|
+
* Settles the stream end — a held partial tag that never completed returns as the final
|
|
5058
|
+
* content delta, and an unclosed think span's tail lands on `thinking`.
|
|
5059
|
+
*/
|
|
4112
5060
|
flush(): string;
|
|
4113
5061
|
}
|
|
4114
5062
|
|
|
5063
|
+
/**
|
|
5064
|
+
* Describes a tool call's JSON wire projection.
|
|
5065
|
+
*
|
|
5066
|
+
* @remarks
|
|
5067
|
+
* The wire is strictly narrower than the domain: non-JSON arguments are refused.
|
|
5068
|
+
* ToolCall.caller is not in this shape and never crosses a wire. The guard refuses
|
|
5069
|
+
* that extra member; the contract parser drops it.
|
|
5070
|
+
*/
|
|
5071
|
+
export declare const toolCallShape: ObjectShape< {
|
|
5072
|
+
id: StringShape;
|
|
5073
|
+
name: StringShape;
|
|
5074
|
+
arguments: ObjectShape<Record<never, never>, JSONShape>;
|
|
5075
|
+
}, boolean | ContractShape>;
|
|
5076
|
+
|
|
5077
|
+
/**
|
|
5078
|
+
* Names the status a relay answers when the `authorize` callback returns anything but `true` or throws —
|
|
5079
|
+
* `401`, carried with no body and reaching the browser as a `ProviderError` with the `HTTP` code.
|
|
5080
|
+
*/
|
|
5081
|
+
export declare const UNAUTHORIZED_RELAY_STATUS = 401;
|
|
5082
|
+
|
|
5083
|
+
/**
|
|
5084
|
+
* Names the status a relay answers when the upstream provider call cannot be constructed — `502`,
|
|
5085
|
+
* carried with no body after `provider.stream` was entered and threw before returning its
|
|
5086
|
+
* iterator.
|
|
5087
|
+
*/
|
|
5088
|
+
export declare const UPSTREAM_RELAY_STATUS = 502;
|
|
5089
|
+
|
|
4115
5090
|
/**
|
|
4116
5091
|
* Names the section header {@link import('./AgentContext.js').AgentContext}'s `build()` renders the
|
|
4117
|
-
*
|
|
4118
|
-
* system message
|
|
5092
|
+
* active workspace's text files under — `'## Workspace'`, the leading line of the dedicated
|
|
5093
|
+
* workspace block in the system message and the carrier-split counterpart to the documents and
|
|
5094
|
+
* images section headers.
|
|
4119
5095
|
*
|
|
4120
5096
|
* @remarks
|
|
4121
|
-
* `build()`
|
|
5097
|
+
* `build()` owns the workspace render (a `Workspace` / `WorkspaceManager` stays file-focused — no
|
|
4122
5098
|
* `open` / `format` getters), so this header lives here as the agents module's one
|
|
4123
5099
|
* workspace-section framing constant rather than on a manager. Each workspace text file renders
|
|
4124
|
-
* beneath it as a fenced `` File: <path>\n```<language>\n<text>\n``` `` block — the
|
|
5100
|
+
* beneath it as a fenced `` File: <path>\n```<language>\n<text>\n``` `` block — the same framing
|
|
4125
5101
|
* the documents section uses — placed immediately after the documents section in the system block.
|
|
4126
5102
|
*/
|
|
4127
5103
|
export declare const WORKSPACE_SECTION_HEADER = "## Workspace";
|