@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.
- package/dist/ag-ui/index.cjs +1064 -0
- package/dist/ag-ui/index.cjs.map +1 -0
- package/dist/ag-ui/index.d.cts +479 -0
- package/dist/ag-ui/index.d.ts +479 -0
- package/dist/ag-ui/index.js +1025 -0
- package/dist/ag-ui/index.js.map +1 -0
- package/dist/genui/index.d.cts +2 -1
- package/dist/genui/index.d.ts +2 -1
- package/dist/guardrails/index.d.cts +3 -2
- package/dist/guardrails/index.d.ts +3 -2
- package/dist/index.cjs +42 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -7
- package/dist/index.d.ts +43 -7
- package/dist/index.js +40 -3
- package/dist/index.js.map +1 -1
- package/dist/{processors-CtrfAA0B.d.ts → processors-C0snQzZJ.d.cts} +1 -1
- package/dist/{processors-Bm2DniQ8.d.cts → processors-D5110pit.d.ts} +1 -1
- package/dist/{tool-C128TFWw.d.cts → stream-events-CgWqAI-1.d.cts} +455 -556
- package/dist/{tool-C128TFWw.d.ts → stream-events-CgWqAI-1.d.ts} +455 -556
- package/dist/tool-DklsS3JX.d.ts +119 -0
- package/dist/tool-DuJ-_qXM.d.cts +119 -0
- package/package.json +14 -1
|
@@ -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
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1943
|
-
*
|
|
1944
|
-
* no
|
|
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
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
/**
|
|
1952
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
/**
|
|
2001
|
-
interface
|
|
2002
|
-
|
|
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
|
-
*
|
|
2005
|
-
*
|
|
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
|
-
|
|
1529
|
+
options?: ElicitationOption[];
|
|
2017
1530
|
/**
|
|
2018
|
-
*
|
|
2019
|
-
*
|
|
2020
|
-
*
|
|
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
|
-
|
|
1535
|
+
input?: ElicitationInput;
|
|
1536
|
+
/** More than one option may be chosen. Omit → single choice. */
|
|
1537
|
+
multiple?: boolean;
|
|
2030
1538
|
/**
|
|
2031
|
-
*
|
|
2032
|
-
*
|
|
2033
|
-
*
|
|
2034
|
-
*
|
|
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
|
-
|
|
1544
|
+
defaults?: string[];
|
|
1545
|
+
/** Accept values that are not among `options` (a typed-in answer). Omit → options only. */
|
|
1546
|
+
allowFreeText?: boolean;
|
|
2042
1547
|
}
|
|
2043
|
-
/**
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
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
|
-
/**
|
|
2051
|
-
interface
|
|
2052
|
-
|
|
2053
|
-
|
|
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 {
|
|
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 };
|