@dudousxd/nestjs-agent-core 0.15.5 → 0.17.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/README.md +68 -0
- package/dist/guardrails/index.cjs +2519 -0
- package/dist/guardrails/index.cjs.map +1 -0
- package/dist/guardrails/index.d.cts +660 -0
- package/dist/guardrails/index.d.ts +660 -0
- package/dist/guardrails/index.js +2445 -0
- package/dist/guardrails/index.js.map +1 -0
- package/dist/index.cjs +27 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -1013
- package/dist/index.d.ts +81 -1013
- package/dist/index.js +25 -25
- package/dist/index.js.map +1 -1
- package/dist/tool-CL9oEytW.d.cts +1014 -0
- package/dist/tool-CL9oEytW.d.ts +1014 -0
- package/package.json +14 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,812 +1,8 @@
|
|
|
1
|
+
import { M as ModelMessage, a as ToolDefinition, b as ToolCallRequest, c as MessageUsage, E as ElicitationRequest, A as Actor, d as ThreadSummary, e as ThreadDetail, S as StoredMessage, f as ToolResult, g as MessageAttachment, h as ToolCallStatus, U as UsagePurpose, i as ToolSpec, Q as QuotaState, j as AgentRunInput, H as HumanReply, T as ToolHandler, k as HistoryPolicy, O as OutputProcessor, P as ProcessorContext, I as InputProcessor, l as ProcessedPrompt, m as ModelAnswer, n as PageContext, o as AgentDefinition, p as AgentDelegation, D as DetachedDelivery, q as AiToolCtx, r as PromptBuilder, s as PromptContributor, t as ToolTransientRetrySetting, u as AgentIntake, v as Decision, L as LlmStepEnvelope, w as ToolStepEnvelope } from './tool-CL9oEytW.js';
|
|
2
|
+
export { x as ASK_TOOL_DESCRIPTION, y as ASK_TOOL_NAME, z as AgentCatalogEntry, B as AgentHistoryWindow, C as AskToolInput, F as DEFAULT_INCREMENTAL_LOOKBACK_CHARS, G as DEFAULT_INTAKE_PREAMBLE, J as DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS, K as DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS, N as ElicitationOption, R as ElicitationOutcome, V as ElicitationQuestion, W as ElicitationReply, X as ElicitationResult, Y as HistoryPolicyContext, Z as HistorySelection, _ as HistorySummary, $ as IncrementalGating, a0 as InvokeWithTransientRetryOptions, a1 as MAX_ASK_QUESTIONS, a2 as MessageRole, a3 as OutputRejectedError, a4 as OutputVerdict, a5 as ProcessorFailedError, a6 as PromptContext, a7 as QuotaView, a8 as ToolKind, a9 as ToolStepCtx, aa as ToolTransientRetryNumbers, ab as ToolTransientRetryOptions, ac as askInputSchema, ad as askToolDefinition, ae as invokeWithTransientRetry, af as isTransientToolError, ag as normalizeElicitationReply, ah as renderElicitationAnswers, ai as resolveElicitation, aj as resolveToolTransientRetryNumbers, ak as settleElicitation } from './tool-CL9oEytW.js';
|
|
1
3
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
4
|
import { ChannelRegistry } from '@dudousxd/nestjs-diagnostics';
|
|
3
5
|
|
|
4
|
-
/**
|
|
5
|
-
* Asking the USER a structured question, and waiting for the answer.
|
|
6
|
-
*
|
|
7
|
-
* `awaitApproval` collects a yes/no about work already proposed; this collects the scope BEFORE the
|
|
8
|
-
* work. Two surfaces produce it — a configured intake (`AgentLoopDeps.intake`) and the model-callable
|
|
9
|
-
* `ask` tool (`AgentLoopDeps.ask`) — and they deliberately produce the SAME {@link
|
|
10
|
-
* ElicitationRequest}, persist through the same tool-call row, and resume through the same
|
|
11
|
-
* `tool:<runId>:<callId>` signal. A consumer cannot tell which one asked, and should not have to.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/** One choice a question offers. */
|
|
15
|
-
interface ElicitationOption {
|
|
16
|
-
/** Stable identifier submitted back. Never shown to the user. */
|
|
17
|
-
value: string;
|
|
18
|
-
/** What the user reads. */
|
|
19
|
-
label: string;
|
|
20
|
-
/**
|
|
21
|
-
* A single character a UI may bind as a keyboard shortcut for this option. Advisory — nothing in
|
|
22
|
-
* the library reads it, and a client is free to render its own.
|
|
23
|
-
*/
|
|
24
|
-
hotkey?: string;
|
|
25
|
-
}
|
|
26
|
-
/** One question in a set. */
|
|
27
|
-
interface ElicitationQuestion {
|
|
28
|
-
/** Unique within its request; the key answers come back under. */
|
|
29
|
-
id: string;
|
|
30
|
-
prompt: string;
|
|
31
|
-
options: ElicitationOption[];
|
|
32
|
-
/** More than one option may be chosen. Omit → single choice. */
|
|
33
|
-
multiple?: boolean;
|
|
34
|
-
/**
|
|
35
|
-
* The options already picked for the user. The claim this whole surface makes is that confirming
|
|
36
|
-
* is enough, so a question with no defaults is a question the user must stop and think about —
|
|
37
|
-
* which is the case the design is trying to avoid. Empty/omitted is allowed and means exactly
|
|
38
|
-
* that: submitting without answering leaves this question unanswered.
|
|
39
|
-
*/
|
|
40
|
-
defaults?: string[];
|
|
41
|
-
/** Accept values that are not among `options` (a typed-in answer). Omit → options only. */
|
|
42
|
-
allowFreeText?: boolean;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* A question set awaiting a human. Identical in shape whether an `@Agent`'s configured intake or
|
|
46
|
-
* the model's `ask` tool authored it — `source` records which, for audit, not for control flow.
|
|
47
|
-
*
|
|
48
|
-
* `questions.length` is known when the request is written, which is what lets a client render
|
|
49
|
-
* "Question 1 of 3" without guessing whether a fourth is coming.
|
|
50
|
-
*/
|
|
51
|
-
interface ElicitationRequest {
|
|
52
|
-
/** The tool-call id this request is persisted under, and the signal it is answered through. */
|
|
53
|
-
id: string;
|
|
54
|
-
source: 'intake' | 'ask';
|
|
55
|
-
/** What the assistant says above the form. */
|
|
56
|
-
preamble?: string;
|
|
57
|
-
questions: ElicitationQuestion[];
|
|
58
|
-
}
|
|
59
|
-
/** What a human sent back for an {@link ElicitationRequest}. */
|
|
60
|
-
interface ElicitationReply {
|
|
61
|
-
/**
|
|
62
|
-
* questionId → chosen values. A question whose id is ABSENT takes the request's own `defaults` —
|
|
63
|
-
* that is what makes "just submit" mean "yes, your pre-picked answers". A present-but-empty array
|
|
64
|
-
* is an explicit "none of these" and does NOT fall back.
|
|
65
|
-
*/
|
|
66
|
-
answers: Record<string, string[]>;
|
|
67
|
-
/**
|
|
68
|
-
* The user declined to answer and told the agent to proceed on its own assumptions. Distinct from
|
|
69
|
-
* confirming the defaults even though the resulting values are the same: one is a decision the
|
|
70
|
-
* user made, the other is one they refused to make, and only the first is evidence of intent.
|
|
71
|
-
*/
|
|
72
|
-
skipped?: boolean;
|
|
73
|
-
/** Opaque ref of WHO answered, when it wasn't the run's own actor. */
|
|
74
|
-
answeredByRef?: string;
|
|
75
|
-
}
|
|
76
|
-
/** A settled elicitation: what the agent proceeds on, and how it got there. */
|
|
77
|
-
interface ElicitationOutcome {
|
|
78
|
-
/** One entry per question, in request order — always present, so a caller never re-applies defaults. */
|
|
79
|
-
answers: Record<string, string[]>;
|
|
80
|
-
skipped: boolean;
|
|
81
|
-
/** Question ids filled from the request's `defaults` rather than by the human. */
|
|
82
|
-
defaulted: string[];
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Read whatever the human channel delivered as an {@link ElicitationReply}.
|
|
86
|
-
*
|
|
87
|
-
* A question set is persisted as an `action` tool call in `pending_approval` — that is what puts it
|
|
88
|
-
* in the approvals inbox a deployment already has, instead of needing one of its own. The cost of
|
|
89
|
-
* that choice is that the thing which comes back may be a {@link Decision} someone pressed
|
|
90
|
-
* Approve/Reject on rather than a set of answers, and a `Decision` carries no `answers` at all.
|
|
91
|
-
*
|
|
92
|
-
* Approve means every question keeps its own pre-picked `defaults`, which is exactly what "just
|
|
93
|
-
* submit" already means on this surface; Reject is the same declining-to-answer a skip is. Neither
|
|
94
|
-
* reading is a guess — a yes/no channel cannot say more than that, and saying it here is what lets
|
|
95
|
-
* one inbox settle both kinds of pending work.
|
|
96
|
-
*
|
|
97
|
-
* Returns the reply UNCHANGED when it already carries answers, so the common path allocates nothing
|
|
98
|
-
* and a caller can identity-compare.
|
|
99
|
-
*/
|
|
100
|
-
declare function normalizeElicitationReply(reply: ElicitationReply | Decision): ElicitationReply;
|
|
101
|
-
/**
|
|
102
|
-
* Settle a reply against the request it answers: fill every unanswered question from its own
|
|
103
|
-
* `defaults`, drop submitted values that aren't on offer, and collapse a single-choice question to
|
|
104
|
-
* one value.
|
|
105
|
-
*
|
|
106
|
-
* PURE, and deliberately so. Both of its inputs are already journaled by the time the loop calls it
|
|
107
|
-
* — the request came from module config or from an `llm:<i>` checkpoint, the reply from the signal
|
|
108
|
-
* checkpoint — so every process replaying the turn reaches the same values without a checkpoint of
|
|
109
|
-
* its own. Resolving defaults in the HTTP layer instead would put them behind a store read that a
|
|
110
|
-
* replay would have to repeat.
|
|
111
|
-
*/
|
|
112
|
-
declare function resolveElicitation(request: ElicitationRequest, raw: ElicitationReply | Decision): ElicitationOutcome;
|
|
113
|
-
/**
|
|
114
|
-
* What a settled elicitation looks like to everyone downstream: the model reading it back as a tool
|
|
115
|
-
* result, the thread reader rendering it, the auditor asking what the agent was told to do. One
|
|
116
|
-
* shape for both surfaces — nothing here records which of them asked.
|
|
117
|
-
*/
|
|
118
|
-
interface ElicitationResult extends ElicitationOutcome {
|
|
119
|
-
/** The questions against the chosen LABELS, so a reader (and a model) can act on it. */
|
|
120
|
-
summary: string;
|
|
121
|
-
}
|
|
122
|
-
/** {@link resolveElicitation} plus its human-readable rendering. Pure, for the same reason. */
|
|
123
|
-
declare function settleElicitation(request: ElicitationRequest, reply: ElicitationReply | Decision): ElicitationResult;
|
|
124
|
-
/**
|
|
125
|
-
* The answers as the model reads them: the question's own prompt against the chosen options' LABELS,
|
|
126
|
-
* not their opaque `value`s — a model shown `{"scope":["b"]}` has been told nothing.
|
|
127
|
-
*/
|
|
128
|
-
declare function renderElicitationAnswers(request: ElicitationRequest, outcome: ElicitationOutcome): string;
|
|
129
|
-
/** The reserved tool name the model calls to ask the user something. */
|
|
130
|
-
declare const ASK_TOOL_NAME = "ask";
|
|
131
|
-
/** What the model must supply when it calls `ask`. */
|
|
132
|
-
interface AskToolInput {
|
|
133
|
-
preamble?: string;
|
|
134
|
-
questions: ElicitationQuestion[];
|
|
135
|
-
}
|
|
136
|
-
/** How many questions one `ask` may carry. A form the user has to scroll is a form they skip. */
|
|
137
|
-
declare const MAX_ASK_QUESTIONS = 5;
|
|
138
|
-
/**
|
|
139
|
-
* The `ask` tool's input schema, hand-written rather than borrowed from a validation library: core
|
|
140
|
-
* depends on no validator, and the schema has to carry a JSON Schema a provider can constrain
|
|
141
|
-
* generation against. It publishes one through the Standard JSON Schema extension
|
|
142
|
-
* (`~standard.jsonSchema.input`), which is the path the AI SDK adapter already recognises for
|
|
143
|
-
* Valibot / ArkType / Zod 4.
|
|
144
|
-
*/
|
|
145
|
-
declare const askInputSchema: StandardSchemaV1<unknown, AskToolInput>;
|
|
146
|
-
/**
|
|
147
|
-
* What the model is told the `ask` tool is for. Written to discourage the two failure modes that
|
|
148
|
-
* make a clarifying question worse than a guess: asking about something the conversation already
|
|
149
|
-
* settled, and asking without saying what you would have done.
|
|
150
|
-
*/
|
|
151
|
-
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.";
|
|
152
|
-
/**
|
|
153
|
-
* The `ask` tool as the model sees it. NOT a `ToolSpec` and never registered: `ask` has no handler,
|
|
154
|
-
* because the loop settles it against a human instead of invoking anything. Keeping it out of the
|
|
155
|
-
* `ToolRegistry` is also what keeps the kind decision off a process-local lookup — see
|
|
156
|
-
* `claimToolCall`.
|
|
157
|
-
*/
|
|
158
|
-
declare function askToolDefinition(): ToolDefinition;
|
|
159
|
-
/** A question set an `@Agent` asks before it starts working. See `AgentLoopDeps.intake`. */
|
|
160
|
-
interface AgentIntake {
|
|
161
|
-
questions: ElicitationQuestion[];
|
|
162
|
-
/** What the assistant says above the form. Omit → {@link DEFAULT_INTAKE_PREAMBLE}. */
|
|
163
|
-
preamble?: string;
|
|
164
|
-
/**
|
|
165
|
-
* `'thread-start'` (default) asks once, on the first turn of a thread; `'every-turn'` asks before
|
|
166
|
-
* every turn. Both are decided from what `load:thread` recorded about the thread when the turn
|
|
167
|
-
* began, never from anything this process happens to know — by the time a replay reaches the
|
|
168
|
-
* question, the thread already holds the assistant message the first attempt wrote.
|
|
169
|
-
*/
|
|
170
|
-
when?: 'thread-start' | 'every-turn';
|
|
171
|
-
}
|
|
172
|
-
declare const DEFAULT_INTAKE_PREAMBLE = "A few questions before I start. I have pre-picked what I would choose, so confirming is enough.";
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* The ceiling on how much of a thread rides into a turn. Without one, `runAgentLoop` maps EVERY
|
|
176
|
-
* message the store returns into the model's messages, so a long-lived thread grows until the
|
|
177
|
-
* provider rejects the request — and every turn before that one pays for the whole transcript.
|
|
178
|
-
* `@dudousxd/nestjs-agent-core` ships `windowHistory` as the built-in; anything satisfying this SPI
|
|
179
|
-
* works. Wire it as `AgentLoopDeps.historyPolicy`, or via `AgentModule.forRoot({ history })` /
|
|
180
|
-
* `@Agent({ history })`.
|
|
181
|
-
*/
|
|
182
|
-
|
|
183
|
-
/** Whose history this is — enough for a policy to size the window per agent or per actor. */
|
|
184
|
-
interface HistoryPolicyContext {
|
|
185
|
-
threadId: string;
|
|
186
|
-
actor: Actor;
|
|
187
|
-
/** The agent running this turn. Undefined → the default agent. */
|
|
188
|
-
agentName?: string;
|
|
189
|
-
}
|
|
190
|
-
/** How a policy split the thread: what rides into the turn, and what the ceiling left out. */
|
|
191
|
-
interface HistorySelection {
|
|
192
|
-
/** Sent to the model, oldest-first. */
|
|
193
|
-
keep: ModelMessage[];
|
|
194
|
-
/** Left out, oldest-first. Folded into a leading summary when the policy implements `summarize`. */
|
|
195
|
-
drop: ModelMessage[];
|
|
196
|
-
}
|
|
197
|
-
/** A stand-in for the messages a window left out, plus what producing it cost. */
|
|
198
|
-
interface HistorySummary {
|
|
199
|
-
/** Prose the loop folds into the window as a leading `system` message. */
|
|
200
|
-
text: string;
|
|
201
|
-
/**
|
|
202
|
-
* What the summarizer spent, when it called a model. Recorded as a `history_summary` usage row, so
|
|
203
|
-
* a ceiling on context cost cannot itself become spend nothing accounts for. Omit for a summarizer
|
|
204
|
-
* that calls no model (a rollup of tool names, a digest the app already stored).
|
|
205
|
-
*/
|
|
206
|
-
usage?: MessageUsage;
|
|
207
|
-
/** Accounting label for the model that produced it; falls back to `AgentLoopDeps.modelId`. */
|
|
208
|
-
modelId?: string;
|
|
209
|
-
}
|
|
210
|
-
interface HistoryPolicy {
|
|
211
|
-
/**
|
|
212
|
-
* The most messages {@link select} can ever keep, where the ceiling can be stated as a row count.
|
|
213
|
-
*
|
|
214
|
-
* A hint the loop hands to the store, which then reads that many of the thread's newest rows
|
|
215
|
-
* rather than its whole transcript (see `ThreadTurnReader`). Declaring it is a PROMISE about
|
|
216
|
-
* `select`: that it keeps at most this many messages, and that they are the NEWEST ones — so a
|
|
217
|
-
* window of this size is indistinguishable, to `select`, from the full transcript. A policy that
|
|
218
|
-
* can keep more than this, or can keep something older than the newest `maxMessages`, must omit it
|
|
219
|
-
* rather than select over rows the store was never asked for.
|
|
220
|
-
*
|
|
221
|
-
* Omit where the ceiling is not a row count at all — a token budget alone cannot name one, since
|
|
222
|
-
* one message can be four tokens or forty thousand. Omitting costs only the bound on the READ; the
|
|
223
|
-
* prompt is identical either way.
|
|
224
|
-
*/
|
|
225
|
-
readonly maxMessages?: number;
|
|
226
|
-
/**
|
|
227
|
-
* Decide what the model sees.
|
|
228
|
-
*
|
|
229
|
-
* MUST be a pure function of `messages`. The loop calls it INSIDE the `load:thread` checkpoint and
|
|
230
|
-
* records its result there, so the ceiling bounds the journal as well as the prompt: what the
|
|
231
|
-
* checkpoint holds is the selection rather than the store's whole `ThreadDetail`, on a payload
|
|
232
|
-
* every replay re-reads. It still adds no position of its own — a policy cannot change the name or
|
|
233
|
-
* position of a single existing checkpoint.
|
|
234
|
-
*
|
|
235
|
-
* Read a clock, a feature flag or a database here and the resumed run windows differently from the
|
|
236
|
-
* one that suspended: the model gets a different prompt, and any step whose existence depends on
|
|
237
|
-
* the split lands at a position the history has no room for. Anything non-deterministic belongs in
|
|
238
|
-
* {@link summarize}, which has a checkpoint of its own.
|
|
239
|
-
*
|
|
240
|
-
* The newest message must always be in `keep` — dropping it leaves the turn with nothing to answer.
|
|
241
|
-
*/
|
|
242
|
-
select(messages: ModelMessage[], ctx: HistoryPolicyContext): HistorySelection;
|
|
243
|
-
/**
|
|
244
|
-
* Fold the dropped messages into prose the model reads in their place, prepended to the window as
|
|
245
|
-
* a `system` message. Optional — without it, dropped messages are simply gone, and `load:thread`
|
|
246
|
-
* does not record them either: a summarizer is the only thing that ever reads them back.
|
|
247
|
-
*
|
|
248
|
-
* Runs inside the loop's `history:summarize` checkpoint, so it may call a model or hit the
|
|
249
|
-
* network: the first attempt's result is journaled and every replay reads it back instead of
|
|
250
|
-
* re-summarizing. It runs once per RUN (not per model step), and only when `select` actually
|
|
251
|
-
* dropped something.
|
|
252
|
-
*/
|
|
253
|
-
summarize?(dropped: ModelMessage[], ctx: HistoryPolicyContext): Promise<HistorySummary>;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* The window an agent asks for declaratively — `AgentModule.forRoot({ history })` and
|
|
257
|
-
* `@Agent({ history })`. Plain data, so it can live in a decorator's metadata; the NestJS layer
|
|
258
|
-
* turns it into a `windowHistory` policy. A consumer needing anything the window can't express
|
|
259
|
-
* supplies a {@link HistoryPolicy} instead.
|
|
260
|
-
*/
|
|
261
|
-
interface AgentHistoryWindow {
|
|
262
|
-
/** Keep at most this many of the newest messages. */
|
|
263
|
-
maxMessages?: number;
|
|
264
|
-
/** Keep the newest messages whose estimated tokens fit this budget. */
|
|
265
|
-
maxTokens?: number;
|
|
266
|
-
/** Fold what the window left out into a leading summary — one extra model call per run. */
|
|
267
|
-
summarize?: boolean;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Transient tool-error classification + the retry loop that wraps a tool's own invocation. A
|
|
272
|
-
* classified-transient error (a DB deadlock, a lock-wait timeout, a serialization failure) means
|
|
273
|
-
* the server rolled the tool's work back — retrying THAT class is safe, unlike a tool's general
|
|
274
|
-
* business failure, which stays a one-shot outcome (no durable step retries: a tool may not be
|
|
275
|
-
* idempotent). See `runAgentLoop`'s `tool:<call.id>` step body and `AgentRunSteps.tool` — both wrap
|
|
276
|
-
* `registry.invoke(...)` with {@link invokeWithTransientRetry} so a retry never becomes a new
|
|
277
|
-
* checkpoint; history still shows exactly one step per tool call.
|
|
278
|
-
*/
|
|
279
|
-
/**
|
|
280
|
-
* Default transient-tool-error classifier: true for a recognized MySQL/Postgres/SQLite
|
|
281
|
-
* lock-contention shape (by driver `code`/`errno`/`sqlState`, or a matching message), checked on
|
|
282
|
-
* the error itself and one level of `cause` (drivers commonly wrap the original error). A plain
|
|
283
|
-
* `Error` with none of these markers — any other business failure — is `false`.
|
|
284
|
-
*/
|
|
285
|
-
declare function isTransientToolError(error: unknown): boolean;
|
|
286
|
-
/** Total attempts (initial try + retries) when `toolTransientRetry` doesn't set `attempts`. */
|
|
287
|
-
declare const DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;
|
|
288
|
-
/** Backoff base in ms — the wait between attempt N and N+1 is `backoffMs * N`. */
|
|
289
|
-
declare const DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;
|
|
290
|
-
/** The host-configurable half of the policy — everything except the (non-wire-safe) `classify` fn. */
|
|
291
|
-
interface ToolTransientRetryOptions {
|
|
292
|
-
/** Total attempts (initial try + retries). Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS}. */
|
|
293
|
-
attempts?: number;
|
|
294
|
-
/** Backoff base in ms. Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS}. */
|
|
295
|
-
backoffMs?: number;
|
|
296
|
-
/** Overrides the default classifier — widen or narrow which errors are treated as transient. */
|
|
297
|
-
classify?: (error: unknown) => boolean;
|
|
298
|
-
}
|
|
299
|
-
/** `false` disables transient retry entirely — a tool's own thrown error surfaces immediately. */
|
|
300
|
-
type ToolTransientRetrySetting = ToolTransientRetryOptions | false;
|
|
301
|
-
/** Just the wire-safe (numeric) half of a resolved policy — what a dispatched envelope carries. */
|
|
302
|
-
interface ToolTransientRetryNumbers {
|
|
303
|
-
attempts: number;
|
|
304
|
-
backoffMs: number;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Resolves the numeric half of `toolTransientRetry` for the dispatched wire envelope: `false` when
|
|
308
|
-
* explicitly disabled, else concrete `{ attempts, backoffMs }` (defaults filled in) — never
|
|
309
|
-
* `undefined`, so the dispatched handler always gets a definite answer instead of re-deriving its
|
|
310
|
-
* own default. The `classify` function never rides this — it isn't wire-safe; the dispatched
|
|
311
|
-
* handler resolves its own `classify` from its local module options (see `AgentRunSteps.tool`).
|
|
312
|
-
*/
|
|
313
|
-
declare function resolveToolTransientRetryNumbers(setting: ToolTransientRetrySetting | undefined): ToolTransientRetryNumbers | false;
|
|
314
|
-
interface InvokeWithTransientRetryOptions {
|
|
315
|
-
/**
|
|
316
|
-
* Widens what counts as a control-flow signal (durable suspend / continue-as-new) so a retry never
|
|
317
|
-
* swallows one — same rule the loop's tool catch applies. An ADDITION to the built-in marker check
|
|
318
|
-
* ({@link isControlFlowSignal}), which already covers every signal the durable runtimes raise;
|
|
319
|
-
* supply this only for a runner whose signals carry no marker.
|
|
320
|
-
*/
|
|
321
|
-
isControlFlowError?: (error: unknown) => boolean;
|
|
322
|
-
/**
|
|
323
|
-
* Called before each wait-and-retry, with the 1-based ordinal of the attempt that just failed and
|
|
324
|
-
* the error it threw. The call site uses this to emit the `tool.retry` diagnostics point event —
|
|
325
|
-
* `invokeWithTransientRetry` itself carries no tool identity (name/callId), only the thunk.
|
|
326
|
-
*/
|
|
327
|
-
onRetry?: (attempt: number, error: unknown) => void;
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Retries `fn` in place — never a new durable step/checkpoint, just repeated attempts inside
|
|
331
|
-
* whichever step body already wraps this call. `setting: false` runs `fn` once, unwrapped (no
|
|
332
|
-
* classify/backoff bookkeeping at all). Otherwise: try; on a thrown error, rethrow immediately if
|
|
333
|
-
* it's a recognized control-flow signal, else if the (possibly custom) classifier calls it
|
|
334
|
-
* transient AND attempts remain, wait `backoffMs * attemptNumber` and retry; otherwise rethrow the
|
|
335
|
-
* error as-is.
|
|
336
|
-
*/
|
|
337
|
-
declare function invokeWithTransientRetry<T>(fn: () => Promise<T>, setting: ToolTransientRetrySetting, options?: InvokeWithTransientRetryOptions): Promise<T>;
|
|
338
|
-
|
|
339
|
-
/** Who is driving the turn. Roles + tenant come from the host app (nestjs-context/authz). */
|
|
340
|
-
interface Actor {
|
|
341
|
-
id: string;
|
|
342
|
-
/** The caller's roles. Tool authorization is a set intersection against a tool's `roles`. */
|
|
343
|
-
roles?: string[];
|
|
344
|
-
tenantRef?: string;
|
|
345
|
-
}
|
|
346
|
-
type ToolKind = 'read' | 'action' | 'agent' | 'ask' | 'skill' | 'memory';
|
|
347
|
-
/**
|
|
348
|
-
* One agent->agent edge on {@link AgentDefinition.delegatesTo}. A bare name is the awaited
|
|
349
|
-
* delegation that has always existed; the object form is how an author says this one runs in the
|
|
350
|
-
* background.
|
|
351
|
-
*/
|
|
352
|
-
type AgentDelegation = string | {
|
|
353
|
-
agent: string;
|
|
354
|
-
detached?: boolean;
|
|
355
|
-
};
|
|
356
|
-
/**
|
|
357
|
-
* Where a detached sub-agent run posts its answer: the thread that delegated it, and the
|
|
358
|
-
* `agent`-kind tool call that started it. Carried on the child run's own {@link AgentRunInput},
|
|
359
|
-
* because by the time the child finishes the parent turn is over and nothing is holding the
|
|
360
|
-
* address.
|
|
361
|
-
*/
|
|
362
|
-
interface DetachedDelivery {
|
|
363
|
-
threadId: string;
|
|
364
|
-
toolCallId: string;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Declared shape of a tool.
|
|
368
|
-
* - `read` auto-executes.
|
|
369
|
-
* - `action` never auto-executes — requires HITL approval.
|
|
370
|
-
* - `agent` delegates to another named agent (durable: a child workflow; inline: a nested loop),
|
|
371
|
-
* handled at the loop level — NOT via a handler. Carries `targetAgent`.
|
|
372
|
-
* - `ask` puts a question set to the user and waits for the answers (see `elicitation.ts`).
|
|
373
|
-
* Handled at the loop level and never registered, so no `ToolSpec` carries this kind:
|
|
374
|
-
* the only tool that has it is the built-in `ask`, whose definition the loop supplies.
|
|
375
|
-
* - `skill` reads one of the procedures offered in the turn's `<skills>` catalog (see `skills.ts`).
|
|
376
|
-
* Auto-executes like a read and performs nothing, but is served by the LOOP from the
|
|
377
|
-
* catalog the journal holds rather than by a registered handler — so, like `ask`, no
|
|
378
|
-
* `ToolSpec` carries this kind.
|
|
379
|
-
* - `memory` records one fact about the actor for later turns (see `memory.ts`). Served by the LOOP
|
|
380
|
-
* and never registered, like `skill`. It WRITES, but auto-executes rather than asking
|
|
381
|
-
* for approval: an agent may only ever write the scope of the actor it is running for,
|
|
382
|
-
* so the blast radius of a bad one is the prompt of the person who was talking, and the
|
|
383
|
-
* remedy is the read-back that lets them delete it.
|
|
384
|
-
*/
|
|
385
|
-
interface ToolSpec {
|
|
386
|
-
name: string;
|
|
387
|
-
kind: ToolKind;
|
|
388
|
-
description: string;
|
|
389
|
-
/**
|
|
390
|
-
* Input schema as a [Standard Schema](https://standardschema.dev) — validation-agnostic, so
|
|
391
|
-
* Zod, Valibot, or ArkType all work. The loop validates input via `~standard.validate` before
|
|
392
|
-
* running the handler, and providers convert it to the model's tool-parameter JSON schema.
|
|
393
|
-
*/
|
|
394
|
-
inputSchema: StandardSchemaV1;
|
|
395
|
-
/** For `kind: 'agent'` — the name of the agent to delegate to. */
|
|
396
|
-
targetAgent?: string;
|
|
397
|
-
/**
|
|
398
|
-
* For `kind: 'agent'` — start the delegation and let the calling turn END, instead of holding it
|
|
399
|
-
* open until the delegate answers. The call's result is a {@link DetachedDelegationReceipt}, and
|
|
400
|
-
* the answer arrives later as its own message in the same thread (see
|
|
401
|
-
* {@link AgentRunInput.deliverTo}).
|
|
402
|
-
*
|
|
403
|
-
* Authored per EDGE, never chosen by the model: a model that can decide to detach can decide to
|
|
404
|
-
* detach the one thing the user is sitting there waiting for, and it has no way to know which that
|
|
405
|
-
* is. The person wiring `A -> B` does.
|
|
406
|
-
*
|
|
407
|
-
* Settled into the call's `persist:toolcall` checkpoint alongside `targetAgent`, so every replay
|
|
408
|
-
* reads the branch back rather than re-deciding it against a registry that may have changed.
|
|
409
|
-
*/
|
|
410
|
-
detached?: boolean;
|
|
411
|
-
/** Roles allowed to invoke. Undefined → defaults applied by RolesPolicy (e.g. ADMIN-only). */
|
|
412
|
-
roles?: string[];
|
|
413
|
-
/**
|
|
414
|
-
* Whether the tool exists in this deployment. `false` (or a predicate returning `false`) drops it
|
|
415
|
-
* before the role filter, so it is never offered to the model and cannot be invoked. Undefined →
|
|
416
|
-
* enabled.
|
|
417
|
-
*
|
|
418
|
-
* A predicate is re-evaluated every turn, so a flag flipped at runtime takes effect on the next
|
|
419
|
-
* message with nothing re-registered. For availability that depends on injected services, put
|
|
420
|
-
* `isEnabled()` on the handler instead — a spec is data, a handler is a provider.
|
|
421
|
-
*/
|
|
422
|
-
enabled?: boolean | (() => boolean | Promise<boolean>);
|
|
423
|
-
/**
|
|
424
|
-
* An authorization ability name (e.g. 'cache.purge'). Consumed by an ability-aware RolesPolicy
|
|
425
|
-
* such as the `@dudousxd/nestjs-agent-authz` Gate adapter. Apps that don't use authz ignore it
|
|
426
|
-
* and rely on `roles` instead — both live on the same SPI, so neither is required.
|
|
427
|
-
*/
|
|
428
|
-
ability?: string;
|
|
429
|
-
}
|
|
430
|
-
/** What the model is told a tool looks like (no handler, no host types). */
|
|
431
|
-
interface ToolDefinition {
|
|
432
|
-
name: string;
|
|
433
|
-
kind: ToolKind;
|
|
434
|
-
description: string;
|
|
435
|
-
inputSchema: StandardSchemaV1;
|
|
436
|
-
}
|
|
437
|
-
/** A tool call the model asked for during a turn. */
|
|
438
|
-
interface ToolCallRequest {
|
|
439
|
-
id: string;
|
|
440
|
-
name: string;
|
|
441
|
-
input: unknown;
|
|
442
|
-
/**
|
|
443
|
-
* The tool's declared kind (`ToolSpec.kind`), stamped where the tool was OFFERED — inside the llm
|
|
444
|
-
* checkpoint, by the process that built the definition list the model chose from. It travels with
|
|
445
|
-
* the call from there, so thread-read consumers know a call's kind without hardcoding a tool-name
|
|
446
|
-
* allowlist, and the approval branch does not depend on which process replays the turn.
|
|
447
|
-
* Undefined only for a call that predates the stamp, or one no registry could resolve
|
|
448
|
-
* (defensively treated as `read` wherever a definite value is required).
|
|
449
|
-
*/
|
|
450
|
-
kind?: ToolKind;
|
|
451
|
-
}
|
|
452
|
-
/** Result of running a tool. */
|
|
453
|
-
interface ToolResult {
|
|
454
|
-
/**
|
|
455
|
-
* A person declined this action, so the tool never ran. Set INSTEAD of a failure, and read by
|
|
456
|
-
* every consumer that has to tell the two apart — the stream frame, the replayed transcript. The
|
|
457
|
-
* `error` field still carries what the MODEL is told, because that is the channel a model reads a
|
|
458
|
-
* tool's outcome on; this flag is what everything else reads.
|
|
459
|
-
*/
|
|
460
|
-
denied?: true;
|
|
461
|
-
id: string;
|
|
462
|
-
name: string;
|
|
463
|
-
output: unknown;
|
|
464
|
-
error?: string;
|
|
465
|
-
}
|
|
466
|
-
interface MessageUsage {
|
|
467
|
-
/**
|
|
468
|
-
* Total input (prompt) tokens for the turn — the whole input side, cached and uncached alike.
|
|
469
|
-
* `cacheWriteTokens` + `cacheReadTokens` are subsets of this count, not additions to it, so
|
|
470
|
-
* token totals and quota never change when a breakdown is present.
|
|
471
|
-
*/
|
|
472
|
-
inputTokens: number;
|
|
473
|
-
/** Total output (completion) tokens for the turn; `reasoningTokens` is a subset of this. */
|
|
474
|
-
outputTokens: number;
|
|
475
|
-
/**
|
|
476
|
-
* How many of `inputTokens` were written to the prompt cache this turn (billed at a premium,
|
|
477
|
-
* ~1.25× base input). Undefined when the provider doesn't report caching. Refines the cost
|
|
478
|
-
* estimate only — priced by the pricing row's cache-write rate (falling back to the input rate).
|
|
479
|
-
*/
|
|
480
|
-
cacheWriteTokens?: number;
|
|
481
|
-
/**
|
|
482
|
-
* How many of `inputTokens` were served from the prompt cache this turn (billed at a discount,
|
|
483
|
-
* ~0.1× base input). Undefined when the provider doesn't report caching.
|
|
484
|
-
*/
|
|
485
|
-
cacheReadTokens?: number;
|
|
486
|
-
/**
|
|
487
|
-
* How many of `outputTokens` the model spent on reasoning/thinking. Observability only — reasoning
|
|
488
|
-
* tokens are billed at the output rate, so they don't change the cost estimate. Undefined for
|
|
489
|
-
* non-reasoning models or providers that don't report it.
|
|
490
|
-
*/
|
|
491
|
-
reasoningTokens?: number;
|
|
492
|
-
/**
|
|
493
|
-
* This turn's USD cost: the provider's own reported figure when it has one, else an estimate from
|
|
494
|
-
* the bound `AgentPricingStore` (cached once per run — see `AgentLoopDeps.pricingStore`), else
|
|
495
|
-
* `null` when no pricing store is bound or the model has no price row. Never `0` for an unpriced
|
|
496
|
-
* model — a real $0 turn and "we don't know" must stay distinguishable.
|
|
497
|
-
*/
|
|
498
|
-
costUsd?: number | null;
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* What a usage row was spent ON. `chat` is a model step of the turn itself; `follow_ups` is the
|
|
502
|
-
* extra call that proposes follow-up questions; `history_summary` is the extra call a
|
|
503
|
-
* {@link import('./spi/history-policy.js').HistoryPolicy} makes to fold windowed-out messages into a
|
|
504
|
-
* summary — so bounding context cost never becomes spend nothing accounts for; `structured_output`
|
|
505
|
-
* is the formatting pass that restates a finished answer as `AgentLoopDeps.outputSchema` requires.
|
|
506
|
-
*/
|
|
507
|
-
type UsagePurpose = 'chat' | 'follow_ups' | 'history_summary' | 'structured_output';
|
|
508
|
-
interface QuotaState {
|
|
509
|
-
usedTokens: number;
|
|
510
|
-
limitTokens: number;
|
|
511
|
-
withinLimit: boolean;
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* The read-model the quota-today endpoint returns to a client — a superset of {@link QuotaState}
|
|
515
|
-
* for rendering a usage badge. `limitTokens` is `null` when no quota is configured (unlimited, so
|
|
516
|
-
* `withinLimit` is always true); `costUsd` is the day's summed provider-reported USD spend (`0`
|
|
517
|
-
* when only tokens were reported).
|
|
518
|
-
*/
|
|
519
|
-
interface QuotaView {
|
|
520
|
-
usedTokens: number;
|
|
521
|
-
limitTokens: number | null;
|
|
522
|
-
withinLimit: boolean;
|
|
523
|
-
costUsd: number;
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* Anything a human sends back into a parked run: a {@link Decision} on an action tool, or an
|
|
527
|
-
* `ElicitationReply` answering a question set. Both travel the same `tool:<runId>:<toolCallId>`
|
|
528
|
-
* signal, so the runner that delivers them does not need to know which it is carrying.
|
|
529
|
-
*/
|
|
530
|
-
type HumanReply = Decision | ElicitationReply;
|
|
531
|
-
/** A human decision on a pending action tool call. */
|
|
532
|
-
interface Decision {
|
|
533
|
-
approved: boolean;
|
|
534
|
-
reason?: string;
|
|
535
|
-
/**
|
|
536
|
-
* Opaque ref of WHO decided (e.g. a console admin). When absent, the run's own actor decided
|
|
537
|
-
* (the chat flow).
|
|
538
|
-
*/
|
|
539
|
-
executedByRef?: string;
|
|
540
|
-
}
|
|
541
|
-
type MessageRole = 'user' | 'assistant' | 'system';
|
|
542
|
-
/**
|
|
543
|
-
* A file a user attached to a message so a vision-capable model sees it natively (an image, a PDF).
|
|
544
|
-
* The lib stays provider-agnostic: it passes {@link MessageAttachment.url} straight through as the
|
|
545
|
-
* model's image/file part data — making that URL reachable by the provider (presigned S3, a proxy)
|
|
546
|
-
* is the consumer's job. The lib never fetches bytes or talks to a store.
|
|
547
|
-
*/
|
|
548
|
-
interface MessageAttachment {
|
|
549
|
-
/** Stable id of the stored media object in the consumer's media store. Provenance + replay key. */
|
|
550
|
-
mediaId: string;
|
|
551
|
-
/** A URL the model provider can fetch the bytes from at turn time. */
|
|
552
|
-
url: string;
|
|
553
|
-
/** MIME type — routes the part: `image/*` → image part, otherwise → file part. */
|
|
554
|
-
contentType: string;
|
|
555
|
-
/** Original filename, for display and the file part's filename. */
|
|
556
|
-
name: string;
|
|
557
|
-
}
|
|
558
|
-
/** A neutral chat message exchanged with the model. */
|
|
559
|
-
interface ModelMessage {
|
|
560
|
-
role: MessageRole;
|
|
561
|
-
content: string;
|
|
562
|
-
toolCalls?: ToolCallRequest[];
|
|
563
|
-
toolResults?: ToolResult[];
|
|
564
|
-
/** User-message attachments (image/PDF), rendered as native model content parts by the adapter. */
|
|
565
|
-
attachments?: MessageAttachment[];
|
|
566
|
-
}
|
|
567
|
-
interface PageContext {
|
|
568
|
-
kind?: string;
|
|
569
|
-
[key: string]: unknown;
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Inputs a {@link PromptBuilder} or {@link PromptContributor} may use to compose the system prompt
|
|
573
|
-
* for a turn. Resolved once per turn from stable inputs (actor / agent / pageContext) so it stays
|
|
574
|
-
* replay-safe.
|
|
575
|
-
*/
|
|
576
|
-
interface PromptContext {
|
|
577
|
-
actor: Actor;
|
|
578
|
-
/** The selected agent's name. */
|
|
579
|
-
agentName: string;
|
|
580
|
-
pageContext?: PageContext;
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* An agent's base system prompt. Return a string (optionally async) built from the turn's context —
|
|
584
|
-
* e.g. injecting the actor, the current page, or a data-shape description. Set on an `@Agent` class
|
|
585
|
-
* via a `@SystemPrompt()` method (or a flat string).
|
|
586
|
-
*/
|
|
587
|
-
type PromptBuilder = (ctx: PromptContext) => string | Promise<string>;
|
|
588
|
-
/**
|
|
589
|
-
* A cross-agent system-prompt contributor. Returns an ordered section to APPEND to the composed
|
|
590
|
-
* prompt (after the agent's base), or `null` to contribute nothing this turn — so conditional
|
|
591
|
-
* sections (base-scope, a mentions legend, schema hints) stay clean when they don't apply.
|
|
592
|
-
* Registered app-wide via `@SystemPromptContributor()`; the loop runs every contributor in order.
|
|
593
|
-
*/
|
|
594
|
-
type PromptContributor = (ctx: PromptContext) => string | null | Promise<string | null>;
|
|
595
|
-
/** Everything needed to run one agent turn. */
|
|
596
|
-
interface AgentRunInput {
|
|
597
|
-
threadId: string;
|
|
598
|
-
actor: Actor;
|
|
599
|
-
/** The latest user message text. */
|
|
600
|
-
userText: string;
|
|
601
|
-
/** Files attached to the latest user message (image/PDF). Persisted with it and sent to the model. */
|
|
602
|
-
attachments?: MessageAttachment[];
|
|
603
|
-
pageContext?: PageContext;
|
|
604
|
-
/** YYYY-MM-DD stamped by the runner so quota/day stays deterministic under durable replay. */
|
|
605
|
-
day?: string;
|
|
606
|
-
/** Which named agent runs this turn. Omitted → the default/single agent. */
|
|
607
|
-
agentName?: string;
|
|
608
|
-
/**
|
|
609
|
-
* How many agent→agent delegations deep this run already is (0 for a top-level turn). The runner
|
|
610
|
-
* increments it for each child run; the loop refuses to delegate past its depth ceiling.
|
|
611
|
-
*/
|
|
612
|
-
delegationDepth?: number;
|
|
613
|
-
/**
|
|
614
|
-
* The named agents already on this delegation chain, root first — what {@link delegationDepth}
|
|
615
|
-
* counts, spelled out. The runner appends its own agent's name for each child it starts.
|
|
616
|
-
*
|
|
617
|
-
* A count can only say a chain is LONG. This says whether it is going in circles, and how often:
|
|
618
|
-
* an agent that appears here is one the chain has already passed through, so a delegation back to
|
|
619
|
-
* it is a cycle by inspection rather than by proxy. A run whose runner does not supply it falls
|
|
620
|
-
* back to the depth ceiling alone.
|
|
621
|
-
*/
|
|
622
|
-
delegationPath?: readonly string[];
|
|
623
|
-
/**
|
|
624
|
-
* When set, this run streams into ANOTHER run's sink instead of its own. A sub-agent run carries
|
|
625
|
-
* its top-level ancestor's runId here so its tokens (and its pending action-tool frames) land in
|
|
626
|
-
* the live stream the human is already watching — the only way a human can see, and therefore
|
|
627
|
-
* approve, a sub-agent's HITL action. Propagated unchanged down the delegation chain.
|
|
628
|
-
*/
|
|
629
|
-
sinkRunId?: string;
|
|
630
|
-
/**
|
|
631
|
-
* Set on a DETACHED sub-agent run: the thread and tool call this run answers into when it
|
|
632
|
-
* finishes. Its presence is also what makes a run detached from the inside — it has no ancestor
|
|
633
|
-
* sink to stream into, so nothing else distinguishes it from a top-level turn.
|
|
634
|
-
*/
|
|
635
|
-
deliverTo?: DetachedDelivery;
|
|
636
|
-
/**
|
|
637
|
-
* The run that started this one (a delegation's parent). Recorded with the run so a governance
|
|
638
|
-
* surface can roll a delegation's cost up to the turn that asked for it; a detached child is
|
|
639
|
-
* otherwise a row with nothing pointing at it.
|
|
640
|
-
*/
|
|
641
|
-
parentRunId?: string;
|
|
642
|
-
/**
|
|
643
|
-
* Re-run the last exchange instead of adding a new message: the loop truncates everything after
|
|
644
|
-
* the thread's last user message and re-answers it (no `userText` is appended). Used by a
|
|
645
|
-
* "regenerate" button. `userText` is ignored when set.
|
|
646
|
-
*/
|
|
647
|
-
regenerate?: boolean;
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* A named agent: its prompt, the tools it may use, and who it can hand off to. This is the
|
|
651
|
-
* internal record the loop and `AgentDepsFactory` consume; in an app it is authored as an
|
|
652
|
-
* `@Agent`-decorated class and populated into the `AgentRegistry` by discovery (name, base prompt
|
|
653
|
-
* from `@SystemPrompt`, tool allow-list, handoff targets). An orchestrator hands off to others via
|
|
654
|
-
* `ctx.handoff(OtherAgent)`. Model/store/sink/governance are shared from the module.
|
|
655
|
-
*/
|
|
656
|
-
interface AgentDefinition {
|
|
657
|
-
name: string;
|
|
658
|
-
/** Human-readable summary from `@Agent({ description })`. Surfaced by the `GET agents` catalog. */
|
|
659
|
-
description?: string;
|
|
660
|
-
/** Base prompt for this agent. A flat string, or a {@link PromptBuilder} resolved per turn. */
|
|
661
|
-
systemPrompt?: string | PromptBuilder;
|
|
662
|
-
/** Allow-list of tool names this agent may use (subset of all registered tools). */
|
|
663
|
-
tools?: string[];
|
|
664
|
-
/**
|
|
665
|
-
* Other agents this agent may hand off to (auto-registered as `agent`-kind tools). A bare name
|
|
666
|
-
* is the awaited form; `{ agent, detached: true }` starts the delegate and lets this agent's turn
|
|
667
|
-
* finish without its answer — see {@link ToolSpec.detached}.
|
|
668
|
-
*/
|
|
669
|
-
delegatesTo?: AgentDelegation[];
|
|
670
|
-
modelId?: string;
|
|
671
|
-
maxSteps?: number;
|
|
672
|
-
/**
|
|
673
|
-
* How deep delegation may nest below this agent. Undefined → {@link MAX_DELEGATION_DEPTH}.
|
|
674
|
-
*
|
|
675
|
-
* Bounds the CHAIN, not the fan-out: how many agents a turn delegates to is the model's.
|
|
676
|
-
*/
|
|
677
|
-
maxDelegationDepth?: number;
|
|
678
|
-
/**
|
|
679
|
-
* How many times one agent may appear on a single delegation chain.
|
|
680
|
-
* Undefined → {@link DEFAULT_MAX_AGENT_APPEARANCES}.
|
|
681
|
-
*/
|
|
682
|
-
maxAgentAppearances?: number;
|
|
683
|
-
/**
|
|
684
|
-
* This agent's own ceiling on how much of a thread rides into its turn, overriding the
|
|
685
|
-
* module-wide one. A persona that reasons over a long back-and-forth and one that answers a single
|
|
686
|
-
* question from a page context want very different windows.
|
|
687
|
-
*/
|
|
688
|
-
history?: AgentHistoryWindow;
|
|
689
|
-
/**
|
|
690
|
-
* Constrain this agent's final answer to a schema. A live schema INSTANCE, so it is resolved from
|
|
691
|
-
* DI on whichever process runs the turn and never travels on `AgentRunInput` — a Standard Schema
|
|
692
|
-
* cannot survive the JSON hop into a durable workflow, which is why there is no per-request
|
|
693
|
-
* override on the HTTP surface.
|
|
694
|
-
*/
|
|
695
|
-
outputSchema?: StandardSchemaV1;
|
|
696
|
-
/**
|
|
697
|
-
* Extra model calls allowed to fix an answer that failed {@link outputSchema}. Undefined → 1.
|
|
698
|
-
*/
|
|
699
|
-
outputRepairAttempts?: number;
|
|
700
|
-
/**
|
|
701
|
-
* Questions this agent puts to the user BEFORE it starts working. Authored, so the turn pays no
|
|
702
|
-
* model call to produce them and a client knows the total up front. Undefined → no intake.
|
|
703
|
-
*/
|
|
704
|
-
intake?: AgentIntake;
|
|
705
|
-
/**
|
|
706
|
-
* Whether this agent is offered the built-in `ask` tool. Undefined → the module-wide setting.
|
|
707
|
-
*/
|
|
708
|
-
ask?: boolean;
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* The read-model the `GET agents` endpoint returns to a client — the safe public subset of an
|
|
712
|
-
* {@link AgentDefinition} so a host can render a persona picker instead of hardcoding one.
|
|
713
|
-
*/
|
|
714
|
-
interface AgentCatalogEntry {
|
|
715
|
-
name: string;
|
|
716
|
-
description: string;
|
|
717
|
-
/** Whether this is the agent a turn uses when the caller names none. Omitted when not the default. */
|
|
718
|
-
isDefault?: boolean;
|
|
719
|
-
}
|
|
720
|
-
interface ThreadSummary {
|
|
721
|
-
id: string;
|
|
722
|
-
title: string;
|
|
723
|
-
transient: boolean;
|
|
724
|
-
createdAt: string;
|
|
725
|
-
updatedAt: string;
|
|
726
|
-
lastMessagePreview?: string;
|
|
727
|
-
/**
|
|
728
|
-
* The agent a `chat()` call on this thread uses when the caller doesn't name one explicitly.
|
|
729
|
-
* Optional — undefined for a store that doesn't implement `AgentStore.updateThread` (the only
|
|
730
|
-
* way to set it). The REST/service read-model normalizes this to `null` when absent.
|
|
731
|
-
*/
|
|
732
|
-
defaultAgent?: string | null;
|
|
733
|
-
/**
|
|
734
|
-
* The runId of a currently-running turn on this thread, or `null` if none is running. Optional —
|
|
735
|
-
* undefined for a store that doesn't implement `AgentStore.activeRunForThread`. The REST/service
|
|
736
|
-
* read-model normalizes this to `null` when absent, so a client can always do `?? null`.
|
|
737
|
-
*/
|
|
738
|
-
activeRunId?: string | null;
|
|
739
|
-
}
|
|
740
|
-
interface StoredMessage {
|
|
741
|
-
id: string;
|
|
742
|
-
role: MessageRole;
|
|
743
|
-
content: string;
|
|
744
|
-
/** Which agent produced this message (assistant messages) — provenance for replay / UI / telescope. */
|
|
745
|
-
agentName?: string;
|
|
746
|
-
toolCalls?: ToolCallRequest[];
|
|
747
|
-
toolResults?: ToolResult[];
|
|
748
|
-
/** Files the user attached to this message (image/PDF). Persisted with the message, replayed as-is. */
|
|
749
|
-
attachments?: MessageAttachment[];
|
|
750
|
-
followUps?: string[];
|
|
751
|
-
usage?: MessageUsage;
|
|
752
|
-
/** The run (turn) that produced this message; absent on a row written before this was recorded. */
|
|
753
|
-
runId?: string;
|
|
754
|
-
createdAt: string;
|
|
755
|
-
}
|
|
756
|
-
interface ThreadDetail extends ThreadSummary {
|
|
757
|
-
messages: StoredMessage[];
|
|
758
|
-
activeStreamId?: string;
|
|
759
|
-
}
|
|
760
|
-
type ToolCallStatus = 'auto_executed' | 'pending_approval' | 'executed' | 'rejected' | 'failed';
|
|
761
|
-
/**
|
|
762
|
-
* Serializable input for a dispatched model-turn step. Carries only data — the serving worker
|
|
763
|
-
* re-resolves the model/sink/registry from its own DI via AGENT_DEPS_FACTORY.forAgent(agentName).
|
|
764
|
-
*/
|
|
765
|
-
interface LlmStepEnvelope {
|
|
766
|
-
/** Undefined = default agent (same semantics as {@link AgentRunInput.agentName}). */
|
|
767
|
-
agentName?: string;
|
|
768
|
-
system: string;
|
|
769
|
-
messages: ModelMessage[];
|
|
770
|
-
/** The turn's actor — the handler re-derives tool definitions from it (definitionsFor). */
|
|
771
|
-
actor: Actor;
|
|
772
|
-
/**
|
|
773
|
-
* Hold this call's stream frames rather than writing them to the run's sink, and return them on
|
|
774
|
-
* the result. Set by the loop when an output processor has to see the whole answer before the
|
|
775
|
-
* subscriber does — the dispatched handler streams to a worker-side sink the loop cannot
|
|
776
|
-
* interpose on, so the instruction has to ride the envelope. Absent → stream live, as before.
|
|
777
|
-
*/
|
|
778
|
-
bufferOutput?: boolean;
|
|
779
|
-
}
|
|
780
|
-
/**
|
|
781
|
-
* The serializable subset of `AiToolCtx` — everything except `host` (re-attached handler-side
|
|
782
|
-
* from DI).
|
|
783
|
-
*/
|
|
784
|
-
interface ToolStepCtx {
|
|
785
|
-
actor: Actor;
|
|
786
|
-
threadId: string;
|
|
787
|
-
runId: string;
|
|
788
|
-
requestId: string;
|
|
789
|
-
agentName?: string;
|
|
790
|
-
pageContext?: PageContext;
|
|
791
|
-
}
|
|
792
|
-
/** Serializable input for a dispatched tool-execution step. */
|
|
793
|
-
interface ToolStepEnvelope {
|
|
794
|
-
toolName: string;
|
|
795
|
-
input: unknown;
|
|
796
|
-
ctx: ToolStepCtx;
|
|
797
|
-
/** Applied INSIDE the handler (`withToolTimeout`) — never as a durable step `timeoutMs`. */
|
|
798
|
-
timeoutMs?: number;
|
|
799
|
-
/**
|
|
800
|
-
* The numeric half of `toolTransientRetry` (resolved by the loop from `AgentLoopDeps`, always a
|
|
801
|
-
* definite value — `false` when disabled, else concrete `{ attempts, backoffMs }` with defaults
|
|
802
|
-
* already filled in) — never `undefined`, so the dispatched handler gets the SAME policy the
|
|
803
|
-
* loop would have used locally. The `classify` function is deliberately absent: it isn't
|
|
804
|
-
* wire-safe, so the handler resolves its own from its local module options (see
|
|
805
|
-
* `AgentRunSteps.tool`) instead of trying to serialize a function.
|
|
806
|
-
*/
|
|
807
|
-
transientRetry: ToolTransientRetryNumbers | false;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
6
|
/**
|
|
811
7
|
* Public, cross-lib-discoverable DI tokens.
|
|
812
8
|
*
|
|
@@ -879,54 +75,6 @@ declare const AGENT_MEMORY: unique symbol;
|
|
|
879
75
|
*/
|
|
880
76
|
declare const AGENT_SKILL_SOURCES: unique symbol;
|
|
881
77
|
|
|
882
|
-
/**
|
|
883
|
-
* Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
|
|
884
|
-
* on {@link AiToolCtx.actor} — read `ctx.actor.id` / `ctx.actor.tenantRef` (single source of truth;
|
|
885
|
-
* no denormalized copies).
|
|
886
|
-
*/
|
|
887
|
-
interface AiToolCtx {
|
|
888
|
-
actor: Actor;
|
|
889
|
-
threadId: string;
|
|
890
|
-
runId: string;
|
|
891
|
-
requestId: string;
|
|
892
|
-
/** The name of the agent running this turn — provenance a tool can scope on (e.g. capability sets). */
|
|
893
|
-
agentName?: string;
|
|
894
|
-
pageContext?: PageContext;
|
|
895
|
-
/** Optional host handle (e.g. an ORM EntityManager) the app threads through options. */
|
|
896
|
-
host?: unknown;
|
|
897
|
-
}
|
|
898
|
-
/** A tool implementation. `I` is the parsed (Zod-validated) input. */
|
|
899
|
-
interface ToolHandler<I = unknown> {
|
|
900
|
-
execute(input: I, ctx: AiToolCtx): Promise<unknown>;
|
|
901
|
-
/**
|
|
902
|
-
* Whether this tool exists in this deployment at all — evaluated per turn, BEFORE the roles
|
|
903
|
-
* policy, so a `false` here means the model is never shown the tool rather than being shown one
|
|
904
|
-
* it will be refused. Omit → always enabled.
|
|
905
|
-
*
|
|
906
|
-
* This is the seam for a feature flag or a licensing tier: the handler is an ordinary provider,
|
|
907
|
-
* so it can read injected config (`this.config.featureX`) that a decorator, evaluated at import
|
|
908
|
-
* time, cannot. Answering "does this capability exist here?"; `roles`/`RolesPolicy` answers the
|
|
909
|
-
* separate question "may THIS actor use it?", and both still run.
|
|
910
|
-
*
|
|
911
|
-
* Prefer this over conditionally registering the provider: registration happens while the
|
|
912
|
-
* `@Module` metadata is built, which in most apps is before configuration is loaded.
|
|
913
|
-
*/
|
|
914
|
-
isEnabled?(): boolean | Promise<boolean>;
|
|
915
|
-
/**
|
|
916
|
-
* Whether THIS actor may use the tool, decided per turn. Omit → the role gate alone decides.
|
|
917
|
-
*
|
|
918
|
-
* The three existing gates all answer the question somewhere else: `roles` is static data,
|
|
919
|
-
* `RolesPolicy` is one app-wide rule for every tool, and an agent's `tools` allow-list is fixed
|
|
920
|
-
* when the agent is declared. This one lives on the tool and runs with DI, so it can ask the
|
|
921
|
-
* questions only the tool knows to ask — is this user's org on the plan that includes it, does
|
|
922
|
-
* this actor own the base being queried, is the per-user override in the DB set today.
|
|
923
|
-
*
|
|
924
|
-
* Runs AFTER {@link isEnabled} and the `RolesPolicy`, and all of them must pass. Applied both
|
|
925
|
-
* when the turn's tool list is built (a denied actor is never shown it) and again on invoke.
|
|
926
|
-
*/
|
|
927
|
-
canUse?(actor: Actor): boolean | Promise<boolean>;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
78
|
/**
|
|
931
79
|
* The "data plane": live token transport, decoupled from the durable control plane.
|
|
932
80
|
*
|
|
@@ -1065,8 +213,51 @@ interface ModelProvider {
|
|
|
1065
213
|
*
|
|
1066
214
|
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
1067
215
|
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
216
|
+
*
|
|
217
|
+
* The vocabulary is also a CONTRACT for runners that are not this library's loop: anything that
|
|
218
|
+
* writes these frames (one JSON object per SSE `data:` line) gets the React transport, transcript
|
|
219
|
+
* model and hooks for free. Two rules keep it evolvable:
|
|
220
|
+
* - every frame is a JSON object with a string `kind`; a reader MUST tolerate kinds it does not
|
|
221
|
+
* know (the React transport forwards them as `data-<kind>` parts rather than dropping them);
|
|
222
|
+
* - fields are only ever added, and new fields are optional.
|
|
1068
223
|
*/
|
|
1069
224
|
|
|
225
|
+
/**
|
|
226
|
+
* A component the server pushed into the conversation: generative UI that is NOT a tool call's
|
|
227
|
+
* rendering. It is addressed by `component` (a key in the client's own component registry), never
|
|
228
|
+
* by a tool name, so a runner can emit one from anywhere — a tool body, a post-processing step, a
|
|
229
|
+
* sandboxed agent that renders through its own protocol.
|
|
230
|
+
*
|
|
231
|
+
* `id` is the component's identity within the message: a second frame with the same `id` REPLACES
|
|
232
|
+
* the first (streaming props into a chart, flipping a card from "loading" to "ready"), it never
|
|
233
|
+
* adds a second component.
|
|
234
|
+
*/
|
|
235
|
+
interface AgentUiComponent {
|
|
236
|
+
id: string;
|
|
237
|
+
/** Registry key the client resolves to its own renderer, e.g. `data-table`. */
|
|
238
|
+
component: string;
|
|
239
|
+
props: Record<string, unknown>;
|
|
240
|
+
/** Schema version of `props`, so a client can keep rendering components persisted by an older server. */
|
|
241
|
+
version?: number;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Who has to settle an action tool call, and until when. Metadata only: the call itself is still
|
|
245
|
+
* settled through the tool-call approve/reject routes, by its `toolCallId`.
|
|
246
|
+
*/
|
|
247
|
+
interface AgentApprovalRequest {
|
|
248
|
+
/** The tool call awaiting the decision — the `id` of a call already announced on this stream. */
|
|
249
|
+
id: string;
|
|
250
|
+
/**
|
|
251
|
+
* Who may decide. Open vocabulary the host defines — `'requester'` (the person chatting),
|
|
252
|
+
* `'admin'`, a role name, a team. A client uses it to say "waiting on an admin" instead of
|
|
253
|
+
* offering buttons the viewer cannot use.
|
|
254
|
+
*/
|
|
255
|
+
approver: string;
|
|
256
|
+
/** ISO-8601 instant after which the request lapses. Absent → it never expires. */
|
|
257
|
+
expiresAt?: string;
|
|
258
|
+
/** Why this call needs a person, in words for that person. */
|
|
259
|
+
reason?: string;
|
|
260
|
+
}
|
|
1070
261
|
type AgentStreamEvent = {
|
|
1071
262
|
kind: 'step-start';
|
|
1072
263
|
}
|
|
@@ -1086,12 +277,19 @@ type AgentStreamEvent = {
|
|
|
1086
277
|
kind: 'reasoning';
|
|
1087
278
|
text: string;
|
|
1088
279
|
}
|
|
1089
|
-
/**
|
|
280
|
+
/**
|
|
281
|
+
* `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool.
|
|
282
|
+
*
|
|
283
|
+
* `parentId` nests this call under another call on the same stream: the inner calls a code-mode
|
|
284
|
+
* `execute` makes, the tools a delegated sub-agent runs. The parent must be announced first. A
|
|
285
|
+
* call's parent is fixed by its first frame that names one; later frames may omit it.
|
|
286
|
+
*/
|
|
1090
287
|
| {
|
|
1091
288
|
kind: 'tool-input-start';
|
|
1092
289
|
id: string;
|
|
1093
290
|
name: string;
|
|
1094
291
|
toolKind: 'read' | 'action';
|
|
292
|
+
parentId?: string;
|
|
1095
293
|
} | {
|
|
1096
294
|
kind: 'tool-input-delta';
|
|
1097
295
|
id: string;
|
|
@@ -1102,6 +300,8 @@ type AgentStreamEvent = {
|
|
|
1102
300
|
name: string;
|
|
1103
301
|
input: unknown;
|
|
1104
302
|
toolKind: 'read' | 'action';
|
|
303
|
+
/** Same as on `tool-input-start`, for a runner that announces a call without streaming its input. */
|
|
304
|
+
parentId?: string;
|
|
1105
305
|
} | {
|
|
1106
306
|
kind: 'tool-output';
|
|
1107
307
|
id: string;
|
|
@@ -1134,6 +334,31 @@ type AgentStreamEvent = {
|
|
|
1134
334
|
id: string;
|
|
1135
335
|
request: ElicitationRequest;
|
|
1136
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* An action tool call (already announced by `tool-input-start`/`tool-input-available` under the
|
|
339
|
+
* same `id`) is parked on a person. Optional: a client still treats an `action` call stuck at
|
|
340
|
+
* its input as pending — this frame adds WHO has to decide and UNTIL WHEN, and moves the call
|
|
341
|
+
* into the AI SDK's native `approval-requested` state.
|
|
342
|
+
*/
|
|
343
|
+
| ({
|
|
344
|
+
kind: 'approval-requested';
|
|
345
|
+
} & AgentApprovalRequest)
|
|
346
|
+
/**
|
|
347
|
+
* Server-pushed generative UI, positioned in the message where it arrives. Not tied to a tool
|
|
348
|
+
* call. See {@link AgentUiComponent}.
|
|
349
|
+
*/
|
|
350
|
+
| ({
|
|
351
|
+
kind: 'ui';
|
|
352
|
+
} & AgentUiComponent)
|
|
353
|
+
/**
|
|
354
|
+
* The thread's title was set or changed while this run streamed (typically derived from the
|
|
355
|
+
* first exchange). Thread-level, not message content: a client updates its header/sidebar and
|
|
356
|
+
* does not render it in the transcript.
|
|
357
|
+
*/
|
|
358
|
+
| {
|
|
359
|
+
kind: 'title';
|
|
360
|
+
title: string;
|
|
361
|
+
}
|
|
1137
362
|
/**
|
|
1138
363
|
* Someone stopped this run. The stream's LAST frame, written by the runner that settled the
|
|
1139
364
|
* cancel, immediately before a normal `end()` — never a `fail()`, because a cancel is not an
|
|
@@ -1486,163 +711,6 @@ interface Retriever {
|
|
|
1486
711
|
retrieve(query: string, options?: RetrieveOptions): Promise<Passage[]>;
|
|
1487
712
|
}
|
|
1488
713
|
|
|
1489
|
-
/**
|
|
1490
|
-
* The two seams that see a turn's traffic to and from the model: an {@link InputProcessor} rewrites
|
|
1491
|
-
* the prompt on its way out, an {@link OutputProcessor} inspects the answer on its way back and may
|
|
1492
|
-
* redact, replace or refuse it. Wire them as `AgentLoopDeps.inputProcessors` /
|
|
1493
|
-
* `outputProcessors`, or via `AgentModule.forRoot({ inputProcessors, outputProcessors })`.
|
|
1494
|
-
*
|
|
1495
|
-
* WHAT THESE ARE NOT: a second way to decide what enters the context. `HistoryPolicy` owns
|
|
1496
|
-
* SELECTION — which of the thread's messages ride into the turn, and what stands in for the rest.
|
|
1497
|
-
* Processors run on whatever selection produced and own TRANSFORMATION — what those messages say.
|
|
1498
|
-
* The distinction is load-bearing rather than stylistic: selection is contractually pure and is what
|
|
1499
|
-
* the `load:thread` checkpoint records, so it bounds the journal as well as the prompt, while a
|
|
1500
|
-
* processor is allowed to call a model, runs in a checkpoint of its own per step, and rewrites a
|
|
1501
|
-
* DERIVED prompt that never becomes the thread's own memory of what was said. Splitting the same
|
|
1502
|
-
* decision across both means neither can be reasoned about alone, and the cheap one stops being the
|
|
1503
|
-
* whole answer to "why did this turn cost that much".
|
|
1504
|
-
*/
|
|
1505
|
-
|
|
1506
|
-
/** Which turn, and which model step of it, a processor is looking at. */
|
|
1507
|
-
interface ProcessorContext {
|
|
1508
|
-
threadId: string;
|
|
1509
|
-
actor: Actor;
|
|
1510
|
-
/** The agent running this turn. Undefined → the default agent. */
|
|
1511
|
-
agentName?: string;
|
|
1512
|
-
/** 0-based model step within the run — the same index the `llm:<step>` checkpoint carries. */
|
|
1513
|
-
step: number;
|
|
1514
|
-
}
|
|
1515
|
-
/** Everything the model is about to be sent, as the previous processor in the chain left it. */
|
|
1516
|
-
interface ProcessedPrompt {
|
|
1517
|
-
/** The composed system prompt (agent base + contributors + any injected retrieval block). */
|
|
1518
|
-
system: string;
|
|
1519
|
-
/** The turn's messages, oldest-first, already through the history ceiling. */
|
|
1520
|
-
messages: ModelMessage[];
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* Rewrites the prompt before each model call of a turn — masking identifiers, stamping a policy
|
|
1524
|
-
* preamble, collapsing an oversized tool result. Runs on EVERY step, not once per run, because the
|
|
1525
|
-
* transcript grows between steps: a redactor that only saw the opening prompt would wave through
|
|
1526
|
-
* whatever a tool result carried back.
|
|
1527
|
-
*
|
|
1528
|
-
* Runs inside the loop's `process:input:<step>` checkpoint and its result is journaled, so a
|
|
1529
|
-
* processor may call a model or hit the network — a resumed run reads back the prompt the suspended
|
|
1530
|
-
* attempt built rather than composing a different one.
|
|
1531
|
-
*/
|
|
1532
|
-
interface InputProcessor {
|
|
1533
|
-
/** Identifies this processor in a failure. Keep it stable — it is user-visible on an error. */
|
|
1534
|
-
readonly name: string;
|
|
1535
|
-
process(prompt: ProcessedPrompt, ctx: ProcessorContext): ProcessedPrompt | Promise<ProcessedPrompt>;
|
|
1536
|
-
}
|
|
1537
|
-
/** One model step's answer, as the previous processor in the chain left it. */
|
|
1538
|
-
interface ModelAnswer {
|
|
1539
|
-
/** The assembled assistant text for this step. */
|
|
1540
|
-
text: string;
|
|
1541
|
-
/** The tool calls the same step asked for. Read-only context — a processor cannot change them. */
|
|
1542
|
-
toolCalls: readonly ToolCallRequest[];
|
|
1543
|
-
}
|
|
1544
|
-
/**
|
|
1545
|
-
* What an {@link OutputProcessor} decided. `pass` hands the text to the next processor unchanged;
|
|
1546
|
-
* `replace` hands it on rewritten (a redaction is a replacement); `reject` ends the chain AND the
|
|
1547
|
-
* run — the text is never streamed, never persisted, and the caller gets an
|
|
1548
|
-
* {@link OutputRejectedError} rather than an answer.
|
|
1549
|
-
*/
|
|
1550
|
-
type OutputVerdict = {
|
|
1551
|
-
action: 'pass';
|
|
1552
|
-
} | {
|
|
1553
|
-
action: 'replace';
|
|
1554
|
-
text: string;
|
|
1555
|
-
} | {
|
|
1556
|
-
action: 'reject';
|
|
1557
|
-
reason: string;
|
|
1558
|
-
};
|
|
1559
|
-
/**
|
|
1560
|
-
* Characters an incremental gate keeps holding at the end of the transformed answer, when a
|
|
1561
|
-
* processor declares {@link IncrementalGating} without naming its own window. Wide enough for the
|
|
1562
|
-
* patterns a redactor is usually written against — an SSN, an email address, a card number — and
|
|
1563
|
-
* deliberately not wider: the window IS the answer's minimum latency tail, since those characters
|
|
1564
|
-
* are only released once the whole-answer pass runs.
|
|
1565
|
-
*/
|
|
1566
|
-
declare const DEFAULT_INCREMENTAL_LOOKBACK_CHARS = 64;
|
|
1567
|
-
/**
|
|
1568
|
-
* A processor's statement that its verdict on a PREFIX of an answer is worth acting on, which is
|
|
1569
|
-
* what lets the loop release that prefix to the reader instead of holding the whole answer.
|
|
1570
|
-
*
|
|
1571
|
-
* Declaring it is a promise about every prefix `P` of the final answer, and the loop takes it at
|
|
1572
|
-
* face value on the streaming path:
|
|
1573
|
-
*
|
|
1574
|
-
* 1. REJECTION IS PREFIX-DECIDABLE. The refusal this processor would return for the whole answer is
|
|
1575
|
-
* already returned for the first prefix that contains the reason. A refusal that only emerges
|
|
1576
|
-
* from the complete answer still fails the run, but by then the reader has seen a prefix — there
|
|
1577
|
-
* is no un-sending bytes, and that is the cost of opting in.
|
|
1578
|
-
* 2. REPLACEMENT IS PREFIX-STABLE UP TO THE WINDOW. Once a character of `process(P)`'s output is
|
|
1579
|
-
* more than {@link lookbackChars} from the end of that output, it never changes as `P` grows.
|
|
1580
|
-
*
|
|
1581
|
-
* A broken second promise is caught, not tolerated: the whole-answer pass stays authoritative, and
|
|
1582
|
-
* the loop raises a `ProcessorFailedError` when its result is not an extension of what the chain
|
|
1583
|
-
* already released. So a window too short for a pattern fails loudly rather than streaming the text
|
|
1584
|
-
* it was supposed to redact.
|
|
1585
|
-
*/
|
|
1586
|
-
interface IncrementalGating {
|
|
1587
|
-
/**
|
|
1588
|
-
* How many characters of this processor's own output stay held back. Undefined →
|
|
1589
|
-
* {@link DEFAULT_INCREMENTAL_LOOKBACK_CHARS}. Set it to the length of the longest pattern the
|
|
1590
|
-
* processor can act on — anything shorter is a run that fails on the pattern it was written for.
|
|
1591
|
-
*/
|
|
1592
|
-
readonly lookbackChars?: number;
|
|
1593
|
-
}
|
|
1594
|
-
/**
|
|
1595
|
-
* Inspects each model step's answer before anything downstream sees it — before it reaches the live
|
|
1596
|
-
* stream, before it is persisted, before it becomes the next step's context.
|
|
1597
|
-
*
|
|
1598
|
-
* Gating an answer and streaming it as it is generated are mutually exclusive, so registering ANY
|
|
1599
|
-
* output processor switches the turn's model call off the run's sink: nothing reaches the
|
|
1600
|
-
* subscriber until this chain has ruled on it — see `AgentLoopDeps.outputProcessors`. How much of
|
|
1601
|
-
* that costs the reader is what {@link incremental} decides.
|
|
1602
|
-
*
|
|
1603
|
-
* Runs inside the loop's `process:output:<step>` checkpoint (which also performs the release), so a
|
|
1604
|
-
* processor may call a model — a moderation pass is the motivating case — and a replay reads the
|
|
1605
|
-
* verdict back instead of re-deciding it.
|
|
1606
|
-
*/
|
|
1607
|
-
interface OutputProcessor {
|
|
1608
|
-
/** Identifies this processor in a rejection or a failure. User-visible; keep it stable. */
|
|
1609
|
-
readonly name: string;
|
|
1610
|
-
/**
|
|
1611
|
-
* Opt this processor into gating a PREFIX, so the turn keeps streaming — see
|
|
1612
|
-
* {@link IncrementalGating} for what declaring it promises. Undefined means the whole answer,
|
|
1613
|
-
* which is what a processor written against the complete text needs and therefore the only safe
|
|
1614
|
-
* default; a chain is incremental only when EVERY member of it declares this, so a neighbour can
|
|
1615
|
-
* never downgrade what another author was given.
|
|
1616
|
-
*/
|
|
1617
|
-
readonly incremental?: IncrementalGating;
|
|
1618
|
-
process(answer: ModelAnswer, ctx: ProcessorContext): OutputVerdict | Promise<OutputVerdict>;
|
|
1619
|
-
}
|
|
1620
|
-
/**
|
|
1621
|
-
* The run ended because an output processor refused the answer — NOT because the model failed. The
|
|
1622
|
-
* two must stay distinguishable: a model failure is worth retrying and worth paging someone about,
|
|
1623
|
-
* a refusal is the control doing its job. Both runners map this to the `output_rejected` stream
|
|
1624
|
-
* error code.
|
|
1625
|
-
*/
|
|
1626
|
-
declare class OutputRejectedError extends Error {
|
|
1627
|
-
/** {@link OutputProcessor.name} of the processor that refused. */
|
|
1628
|
-
readonly processor: string;
|
|
1629
|
-
/** The reason it gave, verbatim. */
|
|
1630
|
-
readonly reason: string;
|
|
1631
|
-
constructor(processor: string, reason: string);
|
|
1632
|
-
}
|
|
1633
|
-
/**
|
|
1634
|
-
* A processor threw. Wrapped so it can never be mistaken for the model call failing — the loop's
|
|
1635
|
-
* only other source of failure at that point in the turn — and so the failure names the processor
|
|
1636
|
-
* that produced it instead of surfacing a bare `TypeError` from someone else's code.
|
|
1637
|
-
*/
|
|
1638
|
-
declare class ProcessorFailedError extends Error {
|
|
1639
|
-
/** Which seam it was on, so a reader knows whether the prompt or the answer was in flight. */
|
|
1640
|
-
readonly phase: 'input' | 'output';
|
|
1641
|
-
/** The processor's `name`. */
|
|
1642
|
-
readonly processor: string;
|
|
1643
|
-
constructor(phase: 'input' | 'output', processor: string, cause: unknown);
|
|
1644
|
-
}
|
|
1645
|
-
|
|
1646
714
|
/**
|
|
1647
715
|
* Turns text into embedding vectors — the sibling of {@link import('./model-provider.js').ModelProvider}
|
|
1648
716
|
* for the retrieval side. Batched (`texts` → one vector each, same order) so ingestion can embed many
|
|
@@ -4211,4 +3279,4 @@ type AgentDiagnosticKey = `agent:${AgentDiagnosticEvent}`;
|
|
|
4211
3279
|
*/
|
|
4212
3280
|
declare function agentDiagnosticKey(event: AgentDiagnosticEvent): AgentDiagnosticKey;
|
|
4213
3281
|
|
|
4214
|
-
export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_DIAGNOSTIC_EVENTS, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MEMORY, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_SKILLS, AGENT_SKILL_SOURCES, AGENT_SPAN_EVENTS, AGENT_STORE, AGENT_TOOL_REGISTRY,
|
|
3282
|
+
export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_DIAGNOSTIC_EVENTS, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MEMORY, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_SKILLS, AGENT_SKILL_SOURCES, AGENT_SPAN_EVENTS, AGENT_STORE, AGENT_TOOL_REGISTRY, Actor, type ActorDirectory, type ActorResolver, type ActorSpendRow, type AgentApprovalPort, type AgentApprovalRequest, AgentDefinition, type AgentDelegated, AgentDelegation, type AgentDiagnosticEvent, type AgentDiagnosticKey, type AgentFollowUpsSpan, type AgentGovernanceQueries, AgentIntake, type AgentLlmTurnSpan, type AgentLoopDeps, type AgentLoopHooks, type AgentLoopResult, type AgentMemoryResolved, type AgentMemoryWritten, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrievalSpan, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentSkillsResolved, type AgentSpanEvent, type AgentStore, AgentStreamError, type AgentStreamEvent, type AgentStructuredOutputSpan, type AgentToolCallEvent, type AgentToolExecutionSpan, type AgentToolRetry, type AgentUiComponent, AiToolCtx, type AppendMessageInput, type ApprovalWhere, type AttachmentRef, type AttachmentStagingStore, type BufferedModelTurnResult, type BuildMemoryBlockInput, type CostUsage, type CreateThreadInput, type CurrentModelPrice, DEFAULT_HISTORY_SUMMARY_INSTRUCTION, DEFAULT_MAX_FACT_CHARS, DEFAULT_MAX_MEMORIES, DEFAULT_MAX_SKILLS, DEFAULT_REFUSAL_REASON, DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION, Decision, DefaultRolesPolicy, type DetachedDelegationOutcome, type DetachedDelegationReceipt, DetachedDelivery, type DetailThreadRef, ElicitationRequest, type EmbeddingProvider, type ForgetMemoryInput, type FrameBuffer, GLOBAL_SCOPE, type GovernancePage, type GovernancePageQuery, type GovernanceRange, type GovernanceRunDetail, type GovernanceThreadDetail, type GovernanceThreadDetailQuery, type GovernanceUsageInput, HistoryPolicy, HumanReply, type IncrementalGate, InputProcessor, type ListMemoriesInput, type ListSkillsInput, type ListStagedAttachmentsInput, LlmStepEnvelope, type LoadSkillInput, type MemoryAuthor, type MemoryConfig, type MemoryDigest, type MemoryDigestEntry, type MemoryFact, type MemoryForgetRequest, type MemoryOrigin, type MemoryProvider, type MemoryRecord, type MemoryVerdict, type MemoryWriteOutcome, type MemoryWriteRequest, MessageAttachment, MessageUsage, ModelAnswer, ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type OfferMemoriesInput, type OutputGateMode, type OutputGateResult, OutputProcessor, type OverriddenMemory, PageContext, type Passage, type PendingApprovalRow, ProcessedPrompt, ProcessorContext, PromptBuilder, PromptContributor, QuotaExceededError, QuotaState, type QuotaStore, REMEMBER_TOOL_DESCRIPTION, REMEMBER_TOOL_NAME, type RecentRunRow, type RecordRunEndInput, type RecordRunStartInput, type RecordToolCallInput, type RecordUsageInput, type RememberToolInput, type RerankOptions, type Reranker, type ResolveAttachmentInput, type ResolveMemoryDigestInput, type ResolvedDelegation, type RetrieveOptions, type Retriever, type RolesPolicy, type RunAgentBreakdownRow, RunCancelledError, type RunErrorBreakdownRow, type RunMetrics, type RunToolCallRow, type RunTrendPoint, type RunWhere, SKILL_TOOL_DESCRIPTION, SKILL_TOOL_NAME, type ScopeContext, type ScopeResolver, type SearchMemoriesInput, type SettledTask, type SinkWriter, type Skill, type SkillAuthor, type SkillCatalogEntry, type SkillContext, type SkillLoadOutcome, type SkillOffer, type SkillProvider, type SkillSummary, type SkillToolInput, type SkillWriteRequest, type SkillWriteVerdict, type SkillsConfig, type StageAttachmentInput, type StagedAttachment, type StoreMemoryInput, StoredMessage, type StreamError, type StructuredOutcome, StructuredOutputError, THREAD_DETAIL_CONTENT_CHARS, type ThreadActivityRow, ThreadDetail, type ThreadMessageRow, type ThreadMeta, type ThreadSpendRow, ThreadSummary, type ThreadTurnPage, type ThreadTurnQuery, type ThreadTurnReader, type ThreadUsageRollup, type ThreadWhere, type TokenStreamSink, type ToolCallActivityRow, ToolCallRequest, ToolCallStatus, type ToolCallWhere, ToolDefinition, ToolDisabledError, ToolForbiddenError, ToolHandler, ToolInputInvalidError, type ToolKindDeps, ToolNotFoundError, ToolRegistry, ToolResult, ToolSpec, type ToolStatRow, ToolStepEnvelope, ToolTransientRetrySetting, type UpdateThreadInput, type UpdateToolCallInput, UsagePurpose, type UsageTrendPoint, type WindowHistoryOptions, type WithMemoryToolInput, type WriteMemoryInput, actorScope, agentDiagnosticKey, agentFailureCode, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, buildMemoryBlock, buildSkillsBlock, canActorUseTool, compositeSkillProvider, createFrameBuffer, createIncrementalGate, dayBoundsUtc, decodeStreamEvent, defaultScopeResolver, detachedDelivered, detachedStarted, detachedUnsettled, encodeStreamEvent, estimateCost, estimateMessageTokens, extractJson, filterToolsByAllowList, filterToolsByCanUse, filterToolsByEnabled, filterToolsByRole, gateFollowUps, gateTail, isControlFlowSignal, isReplayIntegrityError, isToolEnabled, loadSkill, memoryForgetVerdict, memoryWriteVerdict, normalizeDelegation, offerMemories, offerSkills, publishAgentDelegated, publishAgentMemoryResolved, publishAgentMemoryWritten, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentSkillsResolved, publishAgentToolCall, publishAgentToolRetry, releaseGatedFrames, rememberInputSchema, rememberToolDefinition, repairInstruction, resolveGateLookback, resolveMemoryDigest, resolveOutputGateMode, resolveSkillCatalog, rollupThreadUsage, runAgentLoop, runInputProcessors, runOutputProcessors, seedModelPrices, settleAll, settleUnsettledDelegation, skillInputSchema, skillToolDefinition, skillWriteVerdict, stampToolKinds, staticSkillProvider, summarizeWithModel, tenantScope, traceLlmTurn, traceToolExecution, truncateDetailContent, validateStructured, windowHistory, withAskTool, withMemoryTool, withSkillTool, withToolTimeout, writeMemory };
|