@dudousxd/nestjs-agent-core 0.34.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -69,200 +69,6 @@ declare function readElicitationInput(raw: unknown): ElicitationInput | undefine
69
69
  */
70
70
  declare function readElicitationQuestions(input: unknown): ElicitationQuestion[];
71
71
 
72
- /**
73
- * Asking the USER a structured question, and waiting for the answer.
74
- *
75
- * `awaitApproval` collects a yes/no about work already proposed; this collects the scope BEFORE the
76
- * work. Two surfaces produce it — a configured intake (`AgentLoopDeps.intake`) and the model-callable
77
- * `ask` tool (`AgentLoopDeps.ask`) — and they deliberately produce the SAME {@link
78
- * ElicitationRequest}, persist through the same tool-call row, and resume through the same
79
- * `tool:<runId>:<callId>` signal. A consumer cannot tell which one asked, and should not have to.
80
- */
81
-
82
- /** One choice a question offers. */
83
- interface ElicitationOption {
84
- /** Stable identifier submitted back. Never shown to the user. */
85
- value: string;
86
- /** What the user reads. */
87
- label: string;
88
- /**
89
- * A single character a UI may bind as a keyboard shortcut for this option. Advisory — nothing in
90
- * the library reads it, and a client is free to render its own.
91
- */
92
- hotkey?: string;
93
- }
94
- /** One question in a set. */
95
- interface ElicitationQuestion {
96
- /** Unique within its request; the key answers come back under. */
97
- id: string;
98
- prompt: string;
99
- /** A line of help under the prompt. */
100
- description?: string;
101
- /**
102
- * The choices. Required unless {@link input} asks for a typed value — then optional, and a UI may
103
- * offer them as suggestions. An `input` of type `select` still picks from these.
104
- */
105
- options?: ElicitationOption[];
106
- /**
107
- * Ask for a typed value (a number, a date, a sentence…) instead of — or, for `select`, on top of —
108
- * a pick from `options`. The answer is still a `string[]`, in the type's canonical form; see
109
- * `elicitation-input.ts`.
110
- */
111
- input?: ElicitationInput;
112
- /** More than one option may be chosen. Omit → single choice. */
113
- multiple?: boolean;
114
- /**
115
- * The options already picked for the user. The claim this whole surface makes is that confirming
116
- * is enough, so a question with no defaults is a question the user must stop and think about —
117
- * which is the case the design is trying to avoid. Empty/omitted is allowed and means exactly
118
- * that: submitting without answering leaves this question unanswered.
119
- */
120
- defaults?: string[];
121
- /** Accept values that are not among `options` (a typed-in answer). Omit → options only. */
122
- allowFreeText?: boolean;
123
- }
124
- /**
125
- * A question set awaiting a human. Identical in shape whether an `@Agent`'s configured intake or
126
- * the model's `ask` tool authored it — `source` records which, for audit, not for control flow.
127
- *
128
- * `questions.length` is known when the request is written, which is what lets a client render
129
- * "Question 1 of 3" without guessing whether a fourth is coming.
130
- */
131
- interface ElicitationRequest {
132
- /** The tool-call id this request is persisted under, and the signal it is answered through. */
133
- id: string;
134
- source: 'intake' | 'ask';
135
- /** What the assistant says above the form. */
136
- preamble?: string;
137
- questions: ElicitationQuestion[];
138
- }
139
- /** What a human sent back for an {@link ElicitationRequest}. */
140
- interface ElicitationReply {
141
- /**
142
- * questionId → chosen values. A question whose id is ABSENT takes the request's own `defaults` —
143
- * that is what makes "just submit" mean "yes, your pre-picked answers". A present-but-empty array
144
- * is an explicit "none of these" and does NOT fall back.
145
- */
146
- answers: Record<string, string[]>;
147
- /**
148
- * The user declined to answer and told the agent to proceed on its own assumptions. Distinct from
149
- * confirming the defaults even though the resulting values are the same: one is a decision the
150
- * user made, the other is one they refused to make, and only the first is evidence of intent.
151
- */
152
- skipped?: boolean;
153
- /** Opaque ref of WHO answered, when it wasn't the run's own actor. */
154
- answeredByRef?: string;
155
- /**
156
- * The surface the answer came through — `'web'`, `'slack'`, `'console'`, … — the counterpart of
157
- * an approval's `decidedVia`.
158
- */
159
- answeredVia?: string;
160
- }
161
- /** A settled elicitation: what the agent proceeds on, and how it got there. */
162
- interface ElicitationOutcome {
163
- /** One entry per question, in request order — always present, so a caller never re-applies defaults. */
164
- answers: Record<string, string[]>;
165
- skipped: boolean;
166
- /** Question ids filled from the request's `defaults` rather than by the human. */
167
- defaulted: string[];
168
- /**
169
- * Who answered (or skipped) — the reply's `answeredByRef`, which a host may make a display name.
170
- * The counterpart of an approval's `decidedBy`. Absent when the reply did not say.
171
- */
172
- answeredBy?: string;
173
- /** The surface it came through (`'web'`, `'slack'`, …) — an approval's `decidedVia`. */
174
- answeredVia?: string;
175
- }
176
- /**
177
- * Read whatever the human channel delivered as an {@link ElicitationReply}.
178
- *
179
- * A question set is persisted as an `action` tool call in `pending_approval` — that is what puts it
180
- * in the approvals inbox a deployment already has, instead of needing one of its own. The cost of
181
- * that choice is that the thing which comes back may be a {@link Decision} someone pressed
182
- * Approve/Reject on rather than a set of answers, and a `Decision` carries no `answers` at all.
183
- *
184
- * Approve means every question keeps its own pre-picked `defaults`, which is exactly what "just
185
- * submit" already means on this surface; Reject is the same declining-to-answer a skip is. Neither
186
- * reading is a guess — a yes/no channel cannot say more than that, and saying it here is what lets
187
- * one inbox settle both kinds of pending work.
188
- *
189
- * Returns the reply UNCHANGED when it already carries answers, so the common path allocates nothing
190
- * and a caller can identity-compare.
191
- */
192
- declare function normalizeElicitationReply(reply: ElicitationReply | Decision): ElicitationReply;
193
- /**
194
- * Settle a reply against the request it answers: fill every unanswered question from its own
195
- * `defaults`, drop submitted values that aren't on offer, and collapse a single-choice question to
196
- * one value.
197
- *
198
- * PURE, and deliberately so. Both of its inputs are already journaled by the time the loop calls it
199
- * — the request came from module config or from an `llm:<i>` checkpoint, the reply from the signal
200
- * checkpoint — so every process replaying the turn reaches the same values without a checkpoint of
201
- * its own. Resolving defaults in the HTTP layer instead would put them behind a store read that a
202
- * replay would have to repeat.
203
- */
204
- declare function resolveElicitation(request: ElicitationRequest, raw: ElicitationReply | Decision): ElicitationOutcome;
205
- /**
206
- * What a settled elicitation looks like to everyone downstream: the model reading it back as a tool
207
- * result, the thread reader rendering it, the auditor asking what the agent was told to do. One
208
- * shape for both surfaces — nothing here records which of them asked.
209
- */
210
- interface ElicitationResult extends ElicitationOutcome {
211
- /** The questions against the chosen LABELS, so a reader (and a model) can act on it. */
212
- summary: string;
213
- }
214
- /** {@link resolveElicitation} plus its human-readable rendering. Pure, for the same reason. */
215
- declare function settleElicitation(request: ElicitationRequest, reply: ElicitationReply | Decision): ElicitationResult;
216
- /**
217
- * The answers as the model reads them: the question's own prompt against the chosen options' LABELS,
218
- * not their opaque `value`s — a model shown `{"scope":["b"]}` has been told nothing.
219
- */
220
- declare function renderElicitationAnswers(request: ElicitationRequest, outcome: ElicitationOutcome): string;
221
- /** The reserved tool name the model calls to ask the user something. */
222
- declare const ASK_TOOL_NAME = "ask";
223
- /** What the model must supply when it calls `ask`. */
224
- interface AskToolInput {
225
- preamble?: string;
226
- questions: ElicitationQuestion[];
227
- }
228
- /** How many questions one `ask` may carry. A form the user has to scroll is a form they skip. */
229
- declare const MAX_ASK_QUESTIONS = 5;
230
- /**
231
- * The `ask` tool's input schema, hand-written rather than borrowed from a validation library: core
232
- * depends on no validator, and the schema has to carry a JSON Schema a provider can constrain
233
- * generation against. It publishes one through the Standard JSON Schema extension
234
- * (`~standard.jsonSchema.input`), which is the path the AI SDK adapter already recognises for
235
- * Valibot / ArkType / Zod 4.
236
- */
237
- declare const askInputSchema: StandardSchemaV1<unknown, AskToolInput>;
238
- /**
239
- * What the model is told the `ask` tool is for. Written to discourage the two failure modes that
240
- * make a clarifying question worse than a guess: asking about something the conversation already
241
- * settled, and asking without saying what you would have done.
242
- */
243
- declare const ASK_TOOL_DESCRIPTION = "Ask the user to settle the scope of the work before you do it. Use it when a reasonable person would produce a materially different result depending on the answer \u2014 not to confirm something the conversation already says. Every question must pre-pick the answer you would choose, so the user can confirm instead of deciding. The user may decline, in which case you proceed on those pre-picked answers.";
244
- /**
245
- * The `ask` tool as the model sees it. NOT a `ToolSpec` and never registered: `ask` has no handler,
246
- * because the loop settles it against a human instead of invoking anything. Keeping it out of the
247
- * `ToolRegistry` is also what keeps the kind decision off a process-local lookup — see
248
- * `claimToolCall`.
249
- */
250
- declare function askToolDefinition(): ToolDefinition;
251
- /** A question set an `@Agent` asks before it starts working. See `AgentLoopDeps.intake`. */
252
- interface AgentIntake {
253
- questions: ElicitationQuestion[];
254
- /** What the assistant says above the form. Omit → {@link DEFAULT_INTAKE_PREAMBLE}. */
255
- preamble?: string;
256
- /**
257
- * `'thread-start'` (default) asks once, on the first turn of a thread; `'every-turn'` asks before
258
- * every turn. Both are decided from what `load:thread` recorded about the thread when the turn
259
- * began, never from anything this process happens to know — by the time a replay reaches the
260
- * question, the thread already holds the assistant message the first attempt wrote.
261
- */
262
- when?: 'thread-start' | 'every-turn';
263
- }
264
- declare const DEFAULT_INTAKE_PREAMBLE = "A few questions before I start. I have pre-picked what I would choose, so confirming is enough.";
265
-
266
72
  /**
267
73
  * What a store knows about a tool call, read back when its message carries no result for it — see
268
74
  * {@link import('./spi/agent-store.js').AgentStore.toolCallOutcomes}.
@@ -297,269 +103,18 @@ declare function danglingToolCallIds(messages: readonly ModelMessage[]): string[
297
103
  */
298
104
  declare function settleDanglingToolCalls(messages: ModelMessage[], outcomes?: readonly ToolCallOutcome[]): ModelMessage[];
299
105
 
300
- /**
301
- * The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.
302
- *
303
- * The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one
304
- * `JSON.stringify(event)\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an
305
- * SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk
306
- * protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same
307
- * rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the
308
- * client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).
309
- *
310
- * Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
311
- * the adapter owns model-parts → event, the transport owns event → UI-chunk.
312
- *
313
- * The vocabulary is also a CONTRACT for runners that are not this library's loop: anything that
314
- * writes these frames (one JSON object per SSE `data:` line) gets the React transport, transcript
315
- * model and hooks for free. Two rules keep it evolvable:
316
- * - every frame is a JSON object with a string `kind`; a reader MUST tolerate kinds it does not
317
- * know (the React transport forwards them as `data-<kind>` parts rather than dropping them);
318
- * - fields are only ever added, and new fields are optional.
319
- */
320
-
321
- /**
322
- * A component the server pushed into the conversation: generative UI that is NOT a tool call's
323
- * rendering. It is addressed by `component` (a key in the client's own component registry), never
324
- * by a tool name, so a runner can emit one from anywhere — a tool body, a post-processing step, a
325
- * sandboxed agent that renders through its own protocol.
326
- *
327
- * `id` is the component's identity within the message: a second frame with the same `id` REPLACES
328
- * the first (streaming props into a chart, flipping a card from "loading" to "ready"), it never
329
- * adds a second component.
330
- */
331
- interface AgentUiComponent {
332
- id: string;
333
- /** Registry key the client resolves to its own renderer, e.g. `data-table`. */
334
- component: string;
335
- props: Record<string, unknown>;
336
- /** Schema version of `props`, so a client can keep rendering components persisted by an older server. */
337
- version?: number;
106
+ interface CreateThreadInput {
107
+ actor: Actor;
108
+ transient?: boolean;
109
+ title?: string;
338
110
  /**
339
- * The tool call that pushed the component (`ctx.emitUi`), when one did. Lets a client place it
340
- * with that call — a reloaded message puts it right after the call's tool part, where the live
341
- * stream showed it. Absent for a component pushed outside a tool.
111
+ * Create the thread under THIS id instead of a generated one — for a caller whose protocol names
112
+ * the conversation itself (AG-UI's `threadId`, at most 255 characters). OPTIONAL to honour: a
113
+ * store that ignores it still creates a thread, under an id of its own, and the caller reads the
114
+ * id off the result. A store that honours it rejects an id already taken (soft-deleted threads
115
+ * included).
342
116
  */
343
- toolCallId?: string;
344
- }
345
- /**
346
- * Who has to settle an action tool call, and until when. Metadata only: the call itself is still
347
- * settled through the tool-call approve/reject routes, by its `toolCallId`.
348
- */
349
- interface AgentApprovalRequest {
350
- /** The tool call awaiting the decision — the `id` of a call already announced on this stream. */
351
- id: string;
352
- /**
353
- * Who may decide. Open vocabulary the host defines — `'requester'` (the person chatting),
354
- * `'admin'`, a role name, a team. A client uses it to say "waiting on an admin" instead of
355
- * offering buttons the viewer cannot use.
356
- */
357
- approver: string;
358
- /** ISO-8601 instant after which the request lapses. Absent → it never expires. */
359
- expiresAt?: string;
360
- /** Why this call needs a person, in words for that person. */
361
- reason?: string;
362
- }
363
- /**
364
- * How an approval settled — the other half of {@link AgentApprovalRequest}, under the same `id`.
365
- * Metadata again: the call's own outcome still arrives as `tool-output` (approved and ran),
366
- * `tool-output-error` (approved and failed) or `tool-output-denied` (rejected or expired).
367
- */
368
- interface AgentApprovalSettlement {
369
- id: string;
370
- status: 'approved' | 'rejected' | 'expired';
371
- /** Repeated from the request, for a call approved without one being streamed (a remembered approval). */
372
- approver?: string;
373
- /** Opaque ref of who decided. Absent on an expiry. */
374
- decidedBy?: string;
375
- /** The surface the decision came through: `'web'`, `'slack'`, `'remembered'`, … */
376
- decidedVia?: string;
377
- /** The approval also covers later calls of this tool in this thread. */
378
- remember?: boolean;
379
- /** What the person said when declining. */
380
- reason?: string;
381
- }
382
- type AgentStreamEvent = {
383
- kind: 'step-start';
384
- }
385
- /**
386
- * Closes the step opened by the matching `step-start`. Carries the model call's token usage and
387
- * `costUsd` (an estimate from the bound pricing store, or `null` when unpriced/unbound — never a
388
- * fabricated `0`) so a live client can render running cost without waiting for a thread re-fetch.
389
- */
390
- | {
391
- kind: 'step-finish';
392
- usage?: MessageUsage;
393
- costUsd?: number | null;
394
- /**
395
- * How long the model spent thinking in this step, in ms — the same number persisted as
396
- * `StoredMessage.reasoningMs`, so a live thread and a reloaded one read the same duration.
397
- * Absent when the step had no reasoning.
398
- */
399
- reasoningMs?: number;
400
- } | {
401
- kind: 'text';
402
- text: string;
403
- } | {
404
- kind: 'reasoning';
405
- text: string;
406
- }
407
- /**
408
- * `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool.
409
- *
410
- * `parentId` nests this call under another call on the same stream: the inner calls a code-mode
411
- * `execute` makes, the tools a delegated sub-agent runs. The parent must be announced first. A
412
- * call's parent is fixed by its first frame that names one; later frames may omit it.
413
- */
414
- | {
415
- kind: 'tool-input-start';
416
- id: string;
417
- name: string;
418
- toolKind: 'read' | 'action';
419
- parentId?: string;
420
- } | {
421
- kind: 'tool-input-delta';
422
- id: string;
423
- delta: string;
424
- } | {
425
- kind: 'tool-input-available';
426
- id: string;
427
- name: string;
428
- input: unknown;
429
- toolKind: 'read' | 'action';
430
- /** Same as on `tool-input-start`, for a runner that announces a call without streaming its input. */
431
- parentId?: string;
432
- } | {
433
- kind: 'tool-output';
434
- id: string;
435
- output: unknown;
436
- } | {
437
- kind: 'tool-output-error';
438
- id: string;
439
- error: string;
440
- }
441
- /**
442
- * A person was asked to approve an action tool and declined it. Its own frame, NOT
443
- * `tool-output-error`: a refusal is a decision with a known outcome — nothing ran — while a
444
- * failure is an outcome nobody chose and whose effects are unknown. Rendering them the same way
445
- * tells an operator their own "no" was a malfunction. Maps onto the SDK's `output-denied` tool
446
- * part state, which a client reads without knowing any tool's name.
447
- */
448
- | {
449
- kind: 'tool-output-denied';
450
- id: string;
451
- reason?: string;
452
- }
453
- /**
454
- * The run has put a question set to the user and is parked until someone answers it (or skips).
455
- * Written by the LOOP for both elicitation surfaces — the configured intake and the model's `ask`
456
- * tool — so a client renders one form either way rather than learning to recognise a tool name.
457
- * The matching `tool-output` frame, under the same `id`, carries the settled answers.
458
- */
459
- | {
460
- kind: 'elicitation';
461
- id: string;
462
- request: ElicitationRequest;
463
- }
464
- /**
465
- * An action tool call (already announced by `tool-input-start`/`tool-input-available` under the
466
- * same `id`) is parked on a person. Optional: a client still treats an `action` call stuck at
467
- * its input as pending — this frame adds WHO has to decide and UNTIL WHEN, and moves the call
468
- * into the AI SDK's native `approval-requested` state.
469
- */
470
- | ({
471
- kind: 'approval-requested';
472
- } & AgentApprovalRequest)
473
- /**
474
- * A parked action call was decided (or lapsed). Optional, like `approval-requested`: it adds WHO
475
- * decided, THROUGH WHAT and whether the approval is REMEMBERED; the outcome itself rides the
476
- * call's own output frame. See {@link AgentApprovalSettlement}.
477
- */
478
- | ({
479
- kind: 'approval-settled';
480
- } & AgentApprovalSettlement)
481
- /**
482
- * Server-pushed generative UI, positioned in the message where it arrives. Not tied to a tool
483
- * call. See {@link AgentUiComponent}.
484
- */
485
- | ({
486
- kind: 'ui';
487
- } & AgentUiComponent)
488
- /**
489
- * The thread's title was set or changed while this run streamed (typically derived from the
490
- * first exchange). Thread-level, not message content: a client updates its header/sidebar and
491
- * does not render it in the transcript.
492
- */
493
- | {
494
- kind: 'title';
495
- title: string;
496
- }
497
- /**
498
- * Host-defined facts about the message being streamed (the model that answered, how long it took,
499
- * the error it ended with), merged into the client message's `metadata`. The persisted
500
- * counterpart is `StoredMessage.metadata`, so a reload reads the same values. The library's own
501
- * loop never writes it; a runner that is not this library's loop uses it for what its store keeps
502
- * per message.
503
- */
504
- | {
505
- kind: 'message-metadata';
506
- metadata: Record<string, unknown>;
507
- }
508
- /**
509
- * Someone stopped this run. The stream's LAST frame, written by the runner that settled the
510
- * cancel, immediately before a normal `end()` — never a `fail()`, because a cancel is not an
511
- * error and a client that retries on a failed stream must not retry this.
512
- *
513
- * A run that simply ends wrote everything it had; one that ends after this frame did not, and the
514
- * difference is the whole point: without it a reader cannot tell a truncated answer from a
515
- * complete one. Consumers that predate the frame ignore it and see the `end()` they always saw.
516
- */
517
- | {
518
- kind: 'cancelled';
519
- }
520
- /**
521
- * The thread's message queue changed — a snapshot of the whole queue, never a delta, so a client
522
- * that missed one frame is corrected by the next. Written into the stream of the run that is
523
- * holding the thread: when someone queues, edits, reorders or removes a waiting message, and, just
524
- * before this run's own terminal frame, with what happens next — `started` names the queued
525
- * message that became the next turn and that turn's run id (attach to it with
526
- * `GET <base>/chat/:runId/stream`), `queue.paused` says why nothing starts.
527
- */
528
- | {
529
- kind: 'queue';
530
- queue: ChatQueueState;
531
- started?: {
532
- messageId: string;
533
- runId: string;
534
- };
535
- };
536
- /** Encode one event as an NDJSON line (`{...}\n`) for {@link SinkWriter.write}. */
537
- declare function encodeStreamEvent(event: AgentStreamEvent): Uint8Array;
538
- /**
539
- * Read one NDJSON line back, or `null` when the line is not a stream event at all.
540
- *
541
- * `null` covers a genuinely opaque chunk, not just malformed JSON: the sink is a byte channel, so a
542
- * model provider is free to write anything into it and some write bare text. A caller that has to
543
- * CLASSIFY a chunk — the output gate, which may only forward what it can prove is not the answer —
544
- * treats an unreadable frame as unclassifiable rather than guessing.
545
- */
546
- declare function decodeStreamEvent(line: string): AgentStreamEvent | null;
547
- /**
548
- * The `code` of a failed run's `event: error` frame — what a client branches on, and translates.
549
- * `quota_exceeded`, `output_rejected` and `structured_output_invalid` are outcomes the library words
550
- * itself (their `message` is safe to show as it is); the rest are crashes, whose `message` is a
551
- * generic sentence in production. Open-ended on purpose: a host's own runner may send other codes.
552
- */
553
- type AgentStreamErrorCode = 'quota_exceeded' | 'output_rejected' | 'structured_output_invalid'
554
- /** The durable runtime refused a checkpoint position: the run's journal and its code disagree. */
555
- | 'replay_diverged'
556
- /** A model call ended without producing anything. */
557
- | 'model_no_output' | 'run_failed';
558
-
559
- interface CreateThreadInput {
560
- actor: Actor;
561
- transient?: boolean;
562
- title?: string;
117
+ id?: string;
563
118
  }
564
119
  interface AppendMessageInput {
565
120
  threadId: string;
@@ -1939,118 +1494,462 @@ interface AgentAttachmentConfig {
1939
1494
  }
1940
1495
 
1941
1496
  /**
1942
- * Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
1943
- * on {@link AiToolCtx.actor} — read `ctx.actor.id` / `ctx.actor.tenantRef` (single source of truth;
1944
- * no denormalized copies).
1497
+ * Asking the USER a structured question, and waiting for the answer.
1498
+ *
1499
+ * `awaitApproval` collects a yes/no about work already proposed; this collects the scope BEFORE the
1500
+ * work. Two surfaces produce it — a configured intake (`AgentLoopDeps.intake`) and the model-callable
1501
+ * `ask` tool (`AgentLoopDeps.ask`) — and they deliberately produce the SAME {@link
1502
+ * ElicitationRequest}, persist through the same tool-call row, and resume through the same
1503
+ * `tool:<runId>:<callId>` signal. A consumer cannot tell which one asked, and should not have to.
1945
1504
  */
1946
- interface AiToolCtx {
1947
- actor: Actor;
1948
- threadId: string;
1949
- runId: string;
1950
- requestId: string;
1951
- /**
1952
- * The id of the tool call this invocation serves. Absent where a tool is invoked outside a turn
1953
- * (the MCP server, a direct `registry.invoke`).
1954
- */
1955
- toolCallId?: string;
1505
+
1506
+ /** One choice a question offers. */
1507
+ interface ElicitationOption {
1508
+ /** Stable identifier submitted back. Never shown to the user. */
1509
+ value: string;
1510
+ /** What the user reads. */
1511
+ label: string;
1956
1512
  /**
1957
- * `<runId>:<toolCallId>` — the same value for every execution of THIS call, and for no other.
1958
- *
1959
- * A tool's side effect and the checkpoint that records it are two writes. Under the durable
1960
- * runner a worker that dies between them leaves a call the journal does not know ran, and the
1961
- * runtime's recovery runs it again; an in-step transient retry (a deadlock, a lock-wait timeout)
1962
- * re-invokes it too. The library cannot make your write atomic with its journal — so it hands you
1963
- * the key that makes the second attempt recognisable: pass it to whatever you call as its
1964
- * idempotency key (a payment provider's `Idempotency-Key`, a unique column on the row you insert,
1965
- * a workflow's `id`), and a re-execution lands on the first one's result instead of doing it
1966
- * twice. Stable across replays and across pods: the run id is the run's own, and the call id
1967
- * comes out of the journaled model step.
1968
- *
1969
- * Absent where a tool is invoked outside a turn (the MCP server, a direct `registry.invoke`).
1513
+ * A single character a UI may bind as a keyboard shortcut for this option. Advisory — nothing in
1514
+ * the library reads it, and a client is free to render its own.
1970
1515
  */
1971
- idempotencyKey?: string;
1972
- /** The name of the agent running this turn — provenance a tool can scope on (e.g. capability sets). */
1973
- agentName?: string;
1974
- pageContext?: PageContext;
1975
- /** Optional host handle (e.g. an ORM EntityManager) the app threads through options. */
1976
- host?: unknown;
1977
- /**
1978
- * Push a component into the assistant message: streamed live as a `ui` frame and persisted on
1979
- * the message, so a reload shows it where the live stream did. Resolves to the component's id.
1980
- *
1981
- * `id` defaults to `<toolCallId>:ui:<n>` (the n-th push without an `id` in this invocation), so a retried or
1982
- * re-executed call REPLACES what it pushed before instead of adding a second copy; pass your own
1983
- * `id` to update one component across pushes (streaming rows into a table). `props` must be
1984
- * JSON; it is snapshotted when pushed.
1985
- *
1986
- * Replay-safe under the durable runner: the pushed components ride the tool step's journaled
1987
- * result, so a replay neither streams nor persists them again.
1988
- *
1989
- * Always present. On a surface with no conversation to push into (the MCP server, a direct
1990
- * `registry.invoke` without one) it is a no-op that still resolves to an id, so a tool calls
1991
- * `ctx.emitUi(…)` unconditionally.
1992
- */
1993
- emitUi(component: string, props: Record<string, unknown>, options?: {
1994
- id?: string;
1995
- version?: number;
1996
- }): Promise<{
1997
- id: string;
1998
- }>;
1516
+ hotkey?: string;
1999
1517
  }
2000
- /** A tool implementation. `I` is the parsed (Zod-validated) input. */
2001
- interface ToolHandler<I = unknown> {
2002
- execute(input: I, ctx: AiToolCtx): Promise<unknown>;
1518
+ /** One question in a set. */
1519
+ interface ElicitationQuestion {
1520
+ /** Unique within its request; the key answers come back under. */
1521
+ id: string;
1522
+ prompt: string;
1523
+ /** A line of help under the prompt. */
1524
+ description?: string;
2003
1525
  /**
2004
- * Whether this tool exists in this deployment at all — evaluated per turn, BEFORE the roles
2005
- * policy, so a `false` here means the model is never shown the tool rather than being shown one
2006
- * it will be refused. Omit → always enabled.
2007
- *
2008
- * This is the seam for a feature flag or a licensing tier: the handler is an ordinary provider,
2009
- * so it can read injected config (`this.config.featureX`) that a decorator, evaluated at import
2010
- * time, cannot. Answering "does this capability exist here?"; `roles`/`RolesPolicy` answers the
2011
- * separate question "may THIS actor use it?", and both still run.
2012
- *
2013
- * Prefer this over conditionally registering the provider: registration happens while the
2014
- * `@Module` metadata is built, which in most apps is before configuration is loaded.
1526
+ * The choices. Required unless {@link input} asks for a typed value — then optional, and a UI may
1527
+ * offer them as suggestions. An `input` of type `select` still picks from these.
2015
1528
  */
2016
- isEnabled?(): boolean | Promise<boolean>;
1529
+ options?: ElicitationOption[];
2017
1530
  /**
2018
- * Whether THIS actor may use the tool, decided per turn. Omit → the role gate alone decides.
2019
- *
2020
- * The three existing gates all answer the question somewhere else: `roles` is static data,
2021
- * `RolesPolicy` is one app-wide rule for every tool, and an agent's `tools` allow-list is fixed
2022
- * when the agent is declared. This one lives on the tool and runs with DI, so it can ask the
2023
- * questions only the tool knows to ask — is this user's org on the plan that includes it, does
2024
- * this actor own the base being queried, is the per-user override in the DB set today.
2025
- *
2026
- * Runs AFTER {@link isEnabled} and the `RolesPolicy`, and all of them must pass. Applied both
2027
- * when the turn's tool list is built (a denied actor is never shown it) and again on invoke.
1531
+ * Ask for a typed value (a number, a date, a sentence…) instead of — or, for `select`, on top of —
1532
+ * a pick from `options`. The answer is still a `string[]`, in the type's canonical form; see
1533
+ * `elicitation-input.ts`.
2028
1534
  */
2029
- canUse?(actor: Actor): boolean | Promise<boolean>;
1535
+ input?: ElicitationInput;
1536
+ /** More than one option may be chosen. Omit → single choice. */
1537
+ multiple?: boolean;
2030
1538
  /**
2031
- * What the model is told about this tool for THIS turn — a description and/or input schema that
2032
- * depend on who is asking (a per-tenant component catalog, a per-plan list of options). Called
2033
- * when the turn's tool list is built, after every gate has passed; whatever it returns replaces
2034
- * the registered spec's `description` / `inputSchema` in the definition the model sees. Omit, or
2035
- * return `undefined`, to use the registered spec as is.
2036
- *
2037
- * It shapes what the model is SHOWN only: the registry still validates a call against the
2038
- * registered `inputSchema`, so a tool whose accepted input varies per turn registers a permissive
2039
- * schema and validates in `execute`.
1539
+ * The options already picked for the user. The claim this whole surface makes is that confirming
1540
+ * is enough, so a question with no defaults is a question the user must stop and think about —
1541
+ * which is the case the design is trying to avoid. Empty/omitted is allowed and means exactly
1542
+ * that: submitting without answering leaves this question unanswered.
2040
1543
  */
2041
- describe?(scope: ToolDescribeScope): ToolDescription | undefined | Promise<ToolDescription | undefined>;
1544
+ defaults?: string[];
1545
+ /** Accept values that are not among `options` (a typed-in answer). Omit → options only. */
1546
+ allowFreeText?: boolean;
2042
1547
  }
2043
- /** Who a turn's tool list is being built for — what {@link ToolHandler.describe} can vary on. */
2044
- interface ToolDescribeScope {
2045
- actor: Actor;
2046
- /** Absent where the list is built outside a conversation (the MCP server's `tools/list`). */
2047
- threadId?: string;
2048
- agentName?: string;
1548
+ /**
1549
+ * A question set awaiting a human. Identical in shape whether an `@Agent`'s configured intake or
1550
+ * the model's `ask` tool authored it — `source` records which, for audit, not for control flow.
1551
+ *
1552
+ * `questions.length` is known when the request is written, which is what lets a client render
1553
+ * "Question 1 of 3" without guessing whether a fourth is coming.
1554
+ */
1555
+ interface ElicitationRequest {
1556
+ /** The tool-call id this request is persisted under, and the signal it is answered through. */
1557
+ id: string;
1558
+ source: 'intake' | 'ask';
1559
+ /** What the assistant says above the form. */
1560
+ preamble?: string;
1561
+ questions: ElicitationQuestion[];
2049
1562
  }
2050
- /** A per-turn override of a tool's model-facing definition ({@link ToolHandler.describe}). */
2051
- interface ToolDescription {
2052
- description?: string;
2053
- inputSchema?: StandardSchemaV1;
1563
+ /** What a human sent back for an {@link ElicitationRequest}. */
1564
+ interface ElicitationReply {
1565
+ /**
1566
+ * questionId → chosen values. A question whose id is ABSENT takes the request's own `defaults` —
1567
+ * that is what makes "just submit" mean "yes, your pre-picked answers". A present-but-empty array
1568
+ * is an explicit "none of these" and does NOT fall back.
1569
+ */
1570
+ answers: Record<string, string[]>;
1571
+ /**
1572
+ * The user declined to answer and told the agent to proceed on its own assumptions. Distinct from
1573
+ * confirming the defaults even though the resulting values are the same: one is a decision the
1574
+ * user made, the other is one they refused to make, and only the first is evidence of intent.
1575
+ */
1576
+ skipped?: boolean;
1577
+ /** Opaque ref of WHO answered, when it wasn't the run's own actor. */
1578
+ answeredByRef?: string;
1579
+ /**
1580
+ * The surface the answer came through — `'web'`, `'slack'`, `'console'`, … — the counterpart of
1581
+ * an approval's `decidedVia`.
1582
+ */
1583
+ answeredVia?: string;
1584
+ }
1585
+ /** A settled elicitation: what the agent proceeds on, and how it got there. */
1586
+ interface ElicitationOutcome {
1587
+ /** One entry per question, in request order — always present, so a caller never re-applies defaults. */
1588
+ answers: Record<string, string[]>;
1589
+ skipped: boolean;
1590
+ /** Question ids filled from the request's `defaults` rather than by the human. */
1591
+ defaulted: string[];
1592
+ /**
1593
+ * Who answered (or skipped) — the reply's `answeredByRef`, which a host may make a display name.
1594
+ * The counterpart of an approval's `decidedBy`. Absent when the reply did not say.
1595
+ */
1596
+ answeredBy?: string;
1597
+ /** The surface it came through (`'web'`, `'slack'`, …) — an approval's `decidedVia`. */
1598
+ answeredVia?: string;
1599
+ }
1600
+ /**
1601
+ * Read whatever the human channel delivered as an {@link ElicitationReply}.
1602
+ *
1603
+ * A question set is persisted as an `action` tool call in `pending_approval` — that is what puts it
1604
+ * in the approvals inbox a deployment already has, instead of needing one of its own. The cost of
1605
+ * that choice is that the thing which comes back may be a {@link Decision} someone pressed
1606
+ * Approve/Reject on rather than a set of answers, and a `Decision` carries no `answers` at all.
1607
+ *
1608
+ * Approve means every question keeps its own pre-picked `defaults`, which is exactly what "just
1609
+ * submit" already means on this surface; Reject is the same declining-to-answer a skip is. Neither
1610
+ * reading is a guess — a yes/no channel cannot say more than that, and saying it here is what lets
1611
+ * one inbox settle both kinds of pending work.
1612
+ *
1613
+ * Returns the reply UNCHANGED when it already carries answers, so the common path allocates nothing
1614
+ * and a caller can identity-compare.
1615
+ */
1616
+ declare function normalizeElicitationReply(reply: ElicitationReply | Decision): ElicitationReply;
1617
+ /**
1618
+ * Settle a reply against the request it answers: fill every unanswered question from its own
1619
+ * `defaults`, drop submitted values that aren't on offer, and collapse a single-choice question to
1620
+ * one value.
1621
+ *
1622
+ * PURE, and deliberately so. Both of its inputs are already journaled by the time the loop calls it
1623
+ * — the request came from module config or from an `llm:<i>` checkpoint, the reply from the signal
1624
+ * checkpoint — so every process replaying the turn reaches the same values without a checkpoint of
1625
+ * its own. Resolving defaults in the HTTP layer instead would put them behind a store read that a
1626
+ * replay would have to repeat.
1627
+ */
1628
+ declare function resolveElicitation(request: ElicitationRequest, raw: ElicitationReply | Decision): ElicitationOutcome;
1629
+ /**
1630
+ * What a settled elicitation looks like to everyone downstream: the model reading it back as a tool
1631
+ * result, the thread reader rendering it, the auditor asking what the agent was told to do. One
1632
+ * shape for both surfaces — nothing here records which of them asked.
1633
+ */
1634
+ interface ElicitationResult extends ElicitationOutcome {
1635
+ /** The questions against the chosen LABELS, so a reader (and a model) can act on it. */
1636
+ summary: string;
2054
1637
  }
1638
+ /** {@link resolveElicitation} plus its human-readable rendering. Pure, for the same reason. */
1639
+ declare function settleElicitation(request: ElicitationRequest, reply: ElicitationReply | Decision): ElicitationResult;
1640
+ /**
1641
+ * The answers as the model reads them: the question's own prompt against the chosen options' LABELS,
1642
+ * not their opaque `value`s — a model shown `{"scope":["b"]}` has been told nothing.
1643
+ */
1644
+ declare function renderElicitationAnswers(request: ElicitationRequest, outcome: ElicitationOutcome): string;
1645
+ /** The reserved tool name the model calls to ask the user something. */
1646
+ declare const ASK_TOOL_NAME = "ask";
1647
+ /** What the model must supply when it calls `ask`. */
1648
+ interface AskToolInput {
1649
+ preamble?: string;
1650
+ questions: ElicitationQuestion[];
1651
+ }
1652
+ /** How many questions one `ask` may carry. A form the user has to scroll is a form they skip. */
1653
+ declare const MAX_ASK_QUESTIONS = 5;
1654
+ /**
1655
+ * The `ask` tool's input schema, hand-written rather than borrowed from a validation library: core
1656
+ * depends on no validator, and the schema has to carry a JSON Schema a provider can constrain
1657
+ * generation against. It publishes one through the Standard JSON Schema extension
1658
+ * (`~standard.jsonSchema.input`), which is the path the AI SDK adapter already recognises for
1659
+ * Valibot / ArkType / Zod 4.
1660
+ */
1661
+ declare const askInputSchema: StandardSchemaV1<unknown, AskToolInput>;
1662
+ /**
1663
+ * What the model is told the `ask` tool is for. Written to discourage the two failure modes that
1664
+ * make a clarifying question worse than a guess: asking about something the conversation already
1665
+ * settled, and asking without saying what you would have done.
1666
+ */
1667
+ declare const ASK_TOOL_DESCRIPTION = "Ask the user to settle the scope of the work before you do it. Use it when a reasonable person would produce a materially different result depending on the answer \u2014 not to confirm something the conversation already says. Every question must pre-pick the answer you would choose, so the user can confirm instead of deciding. The user may decline, in which case you proceed on those pre-picked answers.";
1668
+ /**
1669
+ * The `ask` tool as the model sees it. NOT a `ToolSpec` and never registered: `ask` has no handler,
1670
+ * because the loop settles it against a human instead of invoking anything. Keeping it out of the
1671
+ * `ToolRegistry` is also what keeps the kind decision off a process-local lookup — see
1672
+ * `claimToolCall`.
1673
+ */
1674
+ declare function askToolDefinition(): ToolDefinition;
1675
+ /** A question set an `@Agent` asks before it starts working. See `AgentLoopDeps.intake`. */
1676
+ interface AgentIntake {
1677
+ questions: ElicitationQuestion[];
1678
+ /** What the assistant says above the form. Omit → {@link DEFAULT_INTAKE_PREAMBLE}. */
1679
+ preamble?: string;
1680
+ /**
1681
+ * `'thread-start'` (default) asks once, on the first turn of a thread; `'every-turn'` asks before
1682
+ * every turn. Both are decided from what `load:thread` recorded about the thread when the turn
1683
+ * began, never from anything this process happens to know — by the time a replay reaches the
1684
+ * question, the thread already holds the assistant message the first attempt wrote.
1685
+ */
1686
+ when?: 'thread-start' | 'every-turn';
1687
+ }
1688
+ declare const DEFAULT_INTAKE_PREAMBLE = "A few questions before I start. I have pre-picked what I would choose, so confirming is enough.";
1689
+
1690
+ /**
1691
+ * The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.
1692
+ *
1693
+ * The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one
1694
+ * `JSON.stringify(event)\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an
1695
+ * SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk
1696
+ * protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same
1697
+ * rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the
1698
+ * client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).
1699
+ *
1700
+ * Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
1701
+ * the adapter owns model-parts → event, the transport owns event → UI-chunk.
1702
+ *
1703
+ * The vocabulary is also a CONTRACT for runners that are not this library's loop: anything that
1704
+ * writes these frames (one JSON object per SSE `data:` line) gets the React transport, transcript
1705
+ * model and hooks for free. Two rules keep it evolvable:
1706
+ * - every frame is a JSON object with a string `kind`; a reader MUST tolerate kinds it does not
1707
+ * know (the React transport forwards them as `data-<kind>` parts rather than dropping them);
1708
+ * - fields are only ever added, and new fields are optional.
1709
+ */
1710
+
1711
+ /**
1712
+ * A component the server pushed into the conversation: generative UI that is NOT a tool call's
1713
+ * rendering. It is addressed by `component` (a key in the client's own component registry), never
1714
+ * by a tool name, so a runner can emit one from anywhere — a tool body, a post-processing step, a
1715
+ * sandboxed agent that renders through its own protocol.
1716
+ *
1717
+ * `id` is the component's identity within the message: a second frame with the same `id` REPLACES
1718
+ * the first (streaming props into a chart, flipping a card from "loading" to "ready"), it never
1719
+ * adds a second component.
1720
+ */
1721
+ interface AgentUiComponent {
1722
+ id: string;
1723
+ /** Registry key the client resolves to its own renderer, e.g. `data-table`. */
1724
+ component: string;
1725
+ props: Record<string, unknown>;
1726
+ /** Schema version of `props`, so a client can keep rendering components persisted by an older server. */
1727
+ version?: number;
1728
+ /**
1729
+ * The tool call that pushed the component (`ctx.emitUi`), when one did. Lets a client place it
1730
+ * with that call — a reloaded message puts it right after the call's tool part, where the live
1731
+ * stream showed it. Absent for a component pushed outside a tool.
1732
+ */
1733
+ toolCallId?: string;
1734
+ }
1735
+ /**
1736
+ * Who has to settle an action tool call, and until when. Metadata only: the call itself is still
1737
+ * settled through the tool-call approve/reject routes, by its `toolCallId`.
1738
+ */
1739
+ interface AgentApprovalRequest {
1740
+ /** The tool call awaiting the decision — the `id` of a call already announced on this stream. */
1741
+ id: string;
1742
+ /**
1743
+ * Who may decide. Open vocabulary the host defines — `'requester'` (the person chatting),
1744
+ * `'admin'`, a role name, a team. A client uses it to say "waiting on an admin" instead of
1745
+ * offering buttons the viewer cannot use.
1746
+ */
1747
+ approver: string;
1748
+ /** ISO-8601 instant after which the request lapses. Absent → it never expires. */
1749
+ expiresAt?: string;
1750
+ /** Why this call needs a person, in words for that person. */
1751
+ reason?: string;
1752
+ }
1753
+ /**
1754
+ * How an approval settled — the other half of {@link AgentApprovalRequest}, under the same `id`.
1755
+ * Metadata again: the call's own outcome still arrives as `tool-output` (approved and ran),
1756
+ * `tool-output-error` (approved and failed) or `tool-output-denied` (rejected or expired).
1757
+ */
1758
+ interface AgentApprovalSettlement {
1759
+ id: string;
1760
+ status: 'approved' | 'rejected' | 'expired';
1761
+ /** Repeated from the request, for a call approved without one being streamed (a remembered approval). */
1762
+ approver?: string;
1763
+ /** Opaque ref of who decided. Absent on an expiry. */
1764
+ decidedBy?: string;
1765
+ /** The surface the decision came through: `'web'`, `'slack'`, `'remembered'`, … */
1766
+ decidedVia?: string;
1767
+ /** The approval also covers later calls of this tool in this thread. */
1768
+ remember?: boolean;
1769
+ /** What the person said when declining. */
1770
+ reason?: string;
1771
+ }
1772
+ type AgentStreamEvent = {
1773
+ kind: 'step-start';
1774
+ }
1775
+ /**
1776
+ * Closes the step opened by the matching `step-start`. Carries the model call's token usage and
1777
+ * `costUsd` (an estimate from the bound pricing store, or `null` when unpriced/unbound — never a
1778
+ * fabricated `0`) so a live client can render running cost without waiting for a thread re-fetch.
1779
+ */
1780
+ | {
1781
+ kind: 'step-finish';
1782
+ usage?: MessageUsage;
1783
+ costUsd?: number | null;
1784
+ /**
1785
+ * How long the model spent thinking in this step, in ms — the same number persisted as
1786
+ * `StoredMessage.reasoningMs`, so a live thread and a reloaded one read the same duration.
1787
+ * Absent when the step had no reasoning.
1788
+ */
1789
+ reasoningMs?: number;
1790
+ /**
1791
+ * The model the step ran on: the one the provider reported, else the configured `modelId`.
1792
+ * What a per-model usage report keys on (the AG-UI producer's `RUN_FINISHED.usage`). Absent
1793
+ * when neither is known; a reader that does not know the field ignores it.
1794
+ */
1795
+ model?: string;
1796
+ } | {
1797
+ kind: 'text';
1798
+ text: string;
1799
+ } | {
1800
+ kind: 'reasoning';
1801
+ text: string;
1802
+ }
1803
+ /**
1804
+ * `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool.
1805
+ *
1806
+ * `parentId` nests this call under another call on the same stream: the inner calls a code-mode
1807
+ * `execute` makes, the tools a delegated sub-agent runs. The parent must be announced first. A
1808
+ * call's parent is fixed by its first frame that names one; later frames may omit it.
1809
+ */
1810
+ | {
1811
+ kind: 'tool-input-start';
1812
+ id: string;
1813
+ name: string;
1814
+ toolKind: 'read' | 'action';
1815
+ parentId?: string;
1816
+ } | {
1817
+ kind: 'tool-input-delta';
1818
+ id: string;
1819
+ delta: string;
1820
+ } | {
1821
+ kind: 'tool-input-available';
1822
+ id: string;
1823
+ name: string;
1824
+ input: unknown;
1825
+ toolKind: 'read' | 'action';
1826
+ /** Same as on `tool-input-start`, for a runner that announces a call without streaming its input. */
1827
+ parentId?: string;
1828
+ } | {
1829
+ kind: 'tool-output';
1830
+ id: string;
1831
+ output: unknown;
1832
+ } | {
1833
+ kind: 'tool-output-error';
1834
+ id: string;
1835
+ error: string;
1836
+ }
1837
+ /**
1838
+ * A person was asked to approve an action tool and declined it. Its own frame, NOT
1839
+ * `tool-output-error`: a refusal is a decision with a known outcome — nothing ran — while a
1840
+ * failure is an outcome nobody chose and whose effects are unknown. Rendering them the same way
1841
+ * tells an operator their own "no" was a malfunction. Maps onto the SDK's `output-denied` tool
1842
+ * part state, which a client reads without knowing any tool's name.
1843
+ */
1844
+ | {
1845
+ kind: 'tool-output-denied';
1846
+ id: string;
1847
+ reason?: string;
1848
+ }
1849
+ /**
1850
+ * The run has put a question set to the user and is parked until someone answers it (or skips).
1851
+ * Written by the LOOP for both elicitation surfaces — the configured intake and the model's `ask`
1852
+ * tool — so a client renders one form either way rather than learning to recognise a tool name.
1853
+ * The matching `tool-output` frame, under the same `id`, carries the settled answers.
1854
+ */
1855
+ | {
1856
+ kind: 'elicitation';
1857
+ id: string;
1858
+ request: ElicitationRequest;
1859
+ }
1860
+ /**
1861
+ * An action tool call (already announced by `tool-input-start`/`tool-input-available` under the
1862
+ * same `id`) is parked on a person. Optional: a client still treats an `action` call stuck at
1863
+ * its input as pending — this frame adds WHO has to decide and UNTIL WHEN, and moves the call
1864
+ * into the AI SDK's native `approval-requested` state.
1865
+ */
1866
+ | ({
1867
+ kind: 'approval-requested';
1868
+ } & AgentApprovalRequest)
1869
+ /**
1870
+ * A parked action call was decided (or lapsed). Optional, like `approval-requested`: it adds WHO
1871
+ * decided, THROUGH WHAT and whether the approval is REMEMBERED; the outcome itself rides the
1872
+ * call's own output frame. See {@link AgentApprovalSettlement}.
1873
+ */
1874
+ | ({
1875
+ kind: 'approval-settled';
1876
+ } & AgentApprovalSettlement)
1877
+ /**
1878
+ * Server-pushed generative UI, positioned in the message where it arrives. Not tied to a tool
1879
+ * call. See {@link AgentUiComponent}.
1880
+ */
1881
+ | ({
1882
+ kind: 'ui';
1883
+ } & AgentUiComponent)
1884
+ /**
1885
+ * The thread's title was set or changed while this run streamed (typically derived from the
1886
+ * first exchange). Thread-level, not message content: a client updates its header/sidebar and
1887
+ * does not render it in the transcript.
1888
+ */
1889
+ | {
1890
+ kind: 'title';
1891
+ title: string;
1892
+ }
1893
+ /**
1894
+ * Host-defined facts about the message being streamed (the model that answered, how long it took,
1895
+ * the error it ended with), merged into the client message's `metadata`. The persisted
1896
+ * counterpart is `StoredMessage.metadata`, so a reload reads the same values. The library's own
1897
+ * loop never writes it; a runner that is not this library's loop uses it for what its store keeps
1898
+ * per message.
1899
+ */
1900
+ | {
1901
+ kind: 'message-metadata';
1902
+ metadata: Record<string, unknown>;
1903
+ }
1904
+ /**
1905
+ * Someone stopped this run. The stream's LAST frame, written by the runner that settled the
1906
+ * cancel, immediately before a normal `end()` — never a `fail()`, because a cancel is not an
1907
+ * error and a client that retries on a failed stream must not retry this.
1908
+ *
1909
+ * A run that simply ends wrote everything it had; one that ends after this frame did not, and the
1910
+ * difference is the whole point: without it a reader cannot tell a truncated answer from a
1911
+ * complete one. Consumers that predate the frame ignore it and see the `end()` they always saw.
1912
+ */
1913
+ | {
1914
+ kind: 'cancelled';
1915
+ }
1916
+ /**
1917
+ * The thread's message queue changed — a snapshot of the whole queue, never a delta, so a client
1918
+ * that missed one frame is corrected by the next. Written into the stream of the run that is
1919
+ * holding the thread: when someone queues, edits, reorders or removes a waiting message, and, just
1920
+ * before this run's own terminal frame, with what happens next — `started` names the queued
1921
+ * message that became the next turn and that turn's run id (attach to it with
1922
+ * `GET <base>/chat/:runId/stream`), `queue.paused` says why nothing starts.
1923
+ */
1924
+ | {
1925
+ kind: 'queue';
1926
+ queue: ChatQueueState;
1927
+ started?: {
1928
+ messageId: string;
1929
+ runId: string;
1930
+ };
1931
+ };
1932
+ /** Encode one event as an NDJSON line (`{...}\n`) for {@link SinkWriter.write}. */
1933
+ declare function encodeStreamEvent(event: AgentStreamEvent): Uint8Array;
1934
+ /**
1935
+ * Read one NDJSON line back, or `null` when the line is not a stream event at all.
1936
+ *
1937
+ * `null` covers a genuinely opaque chunk, not just malformed JSON: the sink is a byte channel, so a
1938
+ * model provider is free to write anything into it and some write bare text. A caller that has to
1939
+ * CLASSIFY a chunk — the output gate, which may only forward what it can prove is not the answer —
1940
+ * treats an unreadable frame as unclassifiable rather than guessing.
1941
+ */
1942
+ declare function decodeStreamEvent(line: string): AgentStreamEvent | null;
1943
+ /**
1944
+ * The `code` of a failed run's `event: error` frame — what a client branches on, and translates.
1945
+ * `quota_exceeded`, `output_rejected` and `structured_output_invalid` are outcomes the library words
1946
+ * itself (their `message` is safe to show as it is); the rest are crashes, whose `message` is a
1947
+ * generic sentence in production. Open-ended on purpose: a host's own runner may send other codes.
1948
+ */
1949
+ type AgentStreamErrorCode = 'quota_exceeded' | 'output_rejected' | 'structured_output_invalid'
1950
+ /** The durable runtime refused a checkpoint position: the run's journal and its code disagree. */
1951
+ | 'replay_diverged'
1952
+ /** A model call ended without producing anything. */
1953
+ | 'model_no_output' | 'run_failed';
2055
1954
 
2056
- export { ASK_TOOL_DESCRIPTION as $, type Actor as A, type ThreadDetail as B, type ChatQueueStore as C, type DetachedDelivery as D, type ElicitationRequest as E, type ToolCallApprovalState as F, type EnqueueMessageInput as G, type HumanReply as H, type QueuedMessage as I, type QueuedMessagePatch as J, type QueuePause as K, type LlmStepEnvelope as L, type ModelMessage as M, type AppendMessageInput as N, type ToolResult as O, type PageContext as P, type QuotaState as Q, type RecordRunStartInput as R, type StoredMessage as S, type ToolSpec as T, type UpdateThreadInput as U, type MessageFeedback as V, type RecordToolCallInput as W, type ToolCallOutcome as X, type UpdateToolCallInput as Y, type RecordUsageInput as Z, ALL_AGENTS as _, type ToolHandler as a, releaseThreadRun as a$, ASK_TOOL_NAME as a0, type AgentApprovalRequest as a1, type AgentApprovalSettlement as a2, type AgentAttachmentConfig as a3, type AgentCatalogEntry as a4, type AgentClientConfig as a5, type AgentHistoryWindow as a6, type AgentStreamErrorCode as a7, type AskToolInput as a8, type ChatQueueState as a9, type ThreadTurnReader as aA, type ToolCallApprovalStatus as aB, type ToolCatalogEntry as aC, type ToolConfirmation as aD, type ToolDescription as aE, type ToolPresentationTone as aF, type ToolResultField as aG, type ToolResultView as aH, type ToolStepCtx as aI, type ToolTransientRetryNumbers as aJ, type ToolTransientRetryOptions as aK, UNFINISHED_TOOL_CALL as aL, type UsagePurpose as aM, askInputSchema as aN, askToolDefinition as aO, danglingToolCallIds as aP, decodeStreamEvent as aQ, encodeStreamEvent as aR, invokeWithTransientRetry as aS, isChatQueueStore as aT, isTransientToolError as aU, isTypedQuestion as aV, normalizeElicitationReply as aW, questionOptions as aX, queuedMessageView as aY, readElicitationInput as aZ, readElicitationQuestions as a_, DEFAULT_INTAKE_PREAMBLE as aa, DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS as ab, DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS as ac, ELICITATION_INPUT_TYPES as ad, type ElicitationInput as ae, type ElicitationInputType as af, type ElicitationOption as ag, type ElicitationOutcome as ah, type ElicitationQuestion as ai, type ElicitationReply as aj, type ElicitationResult as ak, type HistoryPolicyContext as al, type HistorySelection as am, type HistorySummary as an, type InvokeWithTransientRetryOptions as ao, MAX_ASK_QUESTIONS as ap, type MessageFeedbackValue as aq, type MessageRole as ar, type PromptContext as as, type QueuePauseReason as at, type QueuedMessageView as au, type QuotaView as av, RUN_ENDED_BEFORE_TOOL_CALL as aw, type RecordRunEndInput as ax, type ThreadTurnPage as ay, type ThreadTurnQuery as az, type ToolPresentation as b, renderElicitationAnswers as b0, resolveElicitation as b1, resolveToolTransientRetryNumbers as b2, settleDanglingToolCalls as b3, settleElicitation as b4, validateElicitationAnswer as b5, validateElicitationValue as b6, type ToolDefinition as c, type ToolCallRequest as d, type MessageUsage as e, type AgentUiComponent as f, type AiToolCtx as g, type AgentStreamEvent as h, type AgentRunInput as i, type MessageAttachment as j, type ToolKind as k, type ToolCallStatus as l, type ToolCallApproval as m, type HistoryPolicy as n, type AgentDefinition as o, type AgentStore as p, type AgentDelegation as q, type ToolDescribeScope as r, type PromptBuilder as s, type PromptContributor as t, type ToolTransientRetrySetting as u, type AgentIntake as v, type Decision as w, type ToolStepEnvelope as x, type CreateThreadInput as y, type ThreadSummary as z };
1955
+ export { type AgentApprovalSettlement as $, type AgentStreamEvent as A, type QueuedMessage as B, type ChatQueueStore as C, type DetachedDelivery as D, type ElicitationRequest as E, type QueuedMessagePatch as F, type QueuePause as G, type HumanReply as H, type AppendMessageInput as I, type ToolResult as J, type MessageFeedback as K, type LlmStepEnvelope as L, type ModelMessage as M, type RecordToolCallInput as N, type ToolCallOutcome as O, type PageContext as P, type QuotaState as Q, type RecordRunStartInput as R, type StoredMessage as S, type ToolSpec as T, type UpdateThreadInput as U, type UpdateToolCallInput as V, type RecordUsageInput as W, ALL_AGENTS as X, ASK_TOOL_DESCRIPTION as Y, ASK_TOOL_NAME as Z, type AgentApprovalRequest as _, type Actor as a, settleDanglingToolCalls as a$, type AgentAttachmentConfig as a0, type AgentCatalogEntry as a1, type AgentClientConfig as a2, type AgentHistoryWindow as a3, type AgentStreamErrorCode as a4, type AskToolInput as a5, type ChatQueueState as a6, DEFAULT_INTAKE_PREAMBLE as a7, DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS as a8, DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS as a9, type ToolConfirmation as aA, type ToolPresentationTone as aB, type ToolResultField as aC, type ToolResultView as aD, type ToolStepCtx as aE, type ToolTransientRetryNumbers as aF, type ToolTransientRetryOptions as aG, UNFINISHED_TOOL_CALL as aH, type UsagePurpose as aI, askInputSchema as aJ, askToolDefinition as aK, danglingToolCallIds as aL, decodeStreamEvent as aM, encodeStreamEvent as aN, invokeWithTransientRetry as aO, isChatQueueStore as aP, isTransientToolError as aQ, isTypedQuestion as aR, normalizeElicitationReply as aS, questionOptions as aT, queuedMessageView as aU, readElicitationInput as aV, readElicitationQuestions as aW, releaseThreadRun as aX, renderElicitationAnswers as aY, resolveElicitation as aZ, resolveToolTransientRetryNumbers as a_, ELICITATION_INPUT_TYPES as aa, type ElicitationInput as ab, type ElicitationInputType as ac, type ElicitationOption as ad, type ElicitationOutcome as ae, type ElicitationQuestion as af, type ElicitationReply as ag, type ElicitationResult as ah, type HistoryPolicyContext as ai, type HistorySelection as aj, type HistorySummary as ak, type InvokeWithTransientRetryOptions as al, MAX_ASK_QUESTIONS as am, type MessageFeedbackValue as an, type MessageRole as ao, type PromptContext as ap, type QueuePauseReason as aq, type QueuedMessageView as ar, type QuotaView as as, RUN_ENDED_BEFORE_TOOL_CALL as at, type RecordRunEndInput as au, type ThreadTurnPage as av, type ThreadTurnQuery as aw, type ThreadTurnReader as ax, type ToolCallApprovalStatus as ay, type ToolCatalogEntry as az, type ToolPresentation as b, settleElicitation as b0, validateElicitationAnswer as b1, validateElicitationValue as b2, type ToolDefinition as c, type ToolCallRequest as d, type MessageUsage as e, type AgentUiComponent as f, type AgentRunInput as g, type MessageAttachment as h, type ToolKind as i, type ToolCallStatus as j, type ToolCallApproval as k, type HistoryPolicy as l, type AgentDefinition as m, type AgentStore as n, type AgentDelegation as o, type PromptBuilder as p, type PromptContributor as q, type ToolTransientRetrySetting as r, type AgentIntake as s, type Decision as t, type ToolStepEnvelope as u, type CreateThreadInput as v, type ThreadSummary as w, type ThreadDetail as x, type ToolCallApprovalState as y, type EnqueueMessageInput as z };