@dudousxd/nestjs-agent-core 0.33.0 → 0.35.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.
@@ -0,0 +1,479 @@
1
+ import { A as AgentStreamEvent } from '../stream-events-CgWqAI-1.cjs';
2
+ import '@standard-schema/spec';
3
+
4
+ /**
5
+ * The slice of AG-UI 1.0 (https://docs.ag-ui.com/spec/1.0) this producer writes and reads. Typed by
6
+ * hand rather than imported: the agent package takes no dependency on an AG-UI SDK, and the wire
7
+ * shape is pinned by the protocol's own JSON Schema, which the tests validate every emitted event
8
+ * against (`src/ag-ui/fixtures/schema-1.0.json`).
9
+ *
10
+ * Optional members are OMITTED when there is nothing to say, never `null` — the protocol's
11
+ * "absent means absent" rule.
12
+ */
13
+ /** The protocol version this producer declares on `RUN_STARTED`. */
14
+ declare const AG_UI_PROTOCOL_VERSION = "1.0";
15
+ type AgUiMetadata = Record<string, unknown>;
16
+ /** One provider-and-model's token usage, in the protocol's single accounting. */
17
+ interface AgUiTokenUsage {
18
+ provider?: string;
19
+ model?: string;
20
+ /** Every prompt token, cached or not. */
21
+ inputTokens?: number;
22
+ /** Every generated token, reasoning included. */
23
+ outputTokens?: number;
24
+ totalTokens?: number;
25
+ /** Part of `outputTokens`. */
26
+ reasoningTokens?: number;
27
+ /** Cache reads — part of `inputTokens`. */
28
+ cachedInputTokens?: number;
29
+ /** Cache writes — part of `inputTokens`, disjoint from the reads. */
30
+ cacheWriteInputTokens?: number;
31
+ }
32
+ /** What an interrupted run is waiting for; a resume entry answers it by `id`. */
33
+ interface AgUiInterrupt {
34
+ id: string;
35
+ /** Open string. This producer writes `tool_approval` and `input_required`. */
36
+ reason: string;
37
+ message?: string;
38
+ toolCallId?: string;
39
+ responseSchema?: Record<string, unknown>;
40
+ expiresAt?: string;
41
+ metadata?: AgUiMetadata;
42
+ }
43
+ type AgUiRunOutcome = {
44
+ type: 'success';
45
+ pendingToolCallIds?: string[];
46
+ } | {
47
+ type: 'interrupt';
48
+ interrupts: AgUiInterrupt[];
49
+ } | {
50
+ type: 'cancelled';
51
+ };
52
+ interface Base {
53
+ metadata?: AgUiMetadata;
54
+ }
55
+ type AgUiEvent = (Base & {
56
+ type: 'RUN_STARTED';
57
+ threadId: string;
58
+ runId: string;
59
+ protocolVersion?: string;
60
+ }) | (Base & {
61
+ type: 'RUN_FINISHED';
62
+ threadId: string;
63
+ runId: string;
64
+ outcome?: AgUiRunOutcome;
65
+ usage?: AgUiTokenUsage[];
66
+ }) | (Base & {
67
+ type: 'RUN_ERROR';
68
+ message: string;
69
+ code?: string;
70
+ usage?: AgUiTokenUsage[];
71
+ }) | (Base & {
72
+ type: 'STEP_STARTED';
73
+ stepName: string;
74
+ }) | (Base & {
75
+ type: 'STEP_FINISHED';
76
+ stepName: string;
77
+ }) | (Base & {
78
+ type: 'TEXT_MESSAGE_START';
79
+ messageId: string;
80
+ role: 'assistant';
81
+ }) | (Base & {
82
+ type: 'TEXT_MESSAGE_CONTENT';
83
+ messageId: string;
84
+ delta: string;
85
+ }) | (Base & {
86
+ type: 'TEXT_MESSAGE_END';
87
+ messageId: string;
88
+ }) | (Base & {
89
+ type: 'REASONING_START';
90
+ messageId: string;
91
+ }) | (Base & {
92
+ type: 'REASONING_MESSAGE_START';
93
+ messageId: string;
94
+ role: 'reasoning';
95
+ }) | (Base & {
96
+ type: 'REASONING_MESSAGE_CONTENT';
97
+ messageId: string;
98
+ delta: string;
99
+ }) | (Base & {
100
+ type: 'REASONING_MESSAGE_END';
101
+ messageId: string;
102
+ }) | (Base & {
103
+ type: 'REASONING_END';
104
+ messageId: string;
105
+ }) | (Base & {
106
+ type: 'TOOL_CALL_START';
107
+ toolCallId: string;
108
+ toolCallName: string;
109
+ parentMessageId?: string;
110
+ }) | (Base & {
111
+ type: 'TOOL_CALL_ARGS';
112
+ toolCallId: string;
113
+ delta: string;
114
+ }) | (Base & {
115
+ type: 'TOOL_CALL_END';
116
+ toolCallId: string;
117
+ }) | (Base & {
118
+ type: 'TOOL_CALL_RESULT';
119
+ messageId: string;
120
+ toolCallId: string;
121
+ content: string;
122
+ role: 'tool';
123
+ }) | (Base & {
124
+ type: 'CUSTOM';
125
+ name: string;
126
+ value: unknown;
127
+ });
128
+ /** Where a media part's bytes are. Closed set: an unknown `type` is malformed input. */
129
+ type AgUiPartSource = {
130
+ type: 'data';
131
+ value: string;
132
+ mimeType: string;
133
+ } | {
134
+ type: 'url';
135
+ value: string;
136
+ mimeType?: string;
137
+ } | {
138
+ type: 'file';
139
+ value: string;
140
+ provider?: string;
141
+ mimeType?: string;
142
+ };
143
+ type AgUiContentPart = {
144
+ type: 'text';
145
+ text: string;
146
+ id?: string;
147
+ metadata?: unknown;
148
+ } | {
149
+ type: 'image' | 'audio' | 'video' | 'document';
150
+ source: AgUiPartSource;
151
+ id?: string;
152
+ metadata?: unknown;
153
+ };
154
+ interface AgUiMessage {
155
+ id: string;
156
+ role: string;
157
+ content?: string | AgUiContentPart[];
158
+ [key: string]: unknown;
159
+ }
160
+ interface AgUiResumeEntry {
161
+ interruptId: string;
162
+ status: 'resolved' | 'cancelled';
163
+ payload?: unknown;
164
+ metadata?: AgUiMetadata;
165
+ }
166
+ interface AgUiContext {
167
+ description: string;
168
+ value: string;
169
+ }
170
+ /** `RunAgentInput`: the one message that travels from the application to the agent. */
171
+ interface AgUiRunInput {
172
+ threadId: string;
173
+ runId: string;
174
+ protocolVersion?: string;
175
+ parentRunId?: string;
176
+ state?: unknown;
177
+ messages: AgUiMessage[];
178
+ tools?: unknown[];
179
+ context?: AgUiContext[];
180
+ forwardedProps?: unknown;
181
+ resume?: AgUiResumeEntry[];
182
+ }
183
+ /**
184
+ * The names of the `CUSTOM` events this producer writes for what AG-UI does not model. Prefixed, as
185
+ * the protocol asks of invented names; a consumer that does not know one ignores it.
186
+ */
187
+ declare const AG_UI_CUSTOM: {
188
+ /** `{ runId, threadId }` — the library's own ids for the run behind this stream (cancel, re-attach). */
189
+ readonly run: "agora.run";
190
+ /** A generative-UI component (`AgentUiComponent`); a repeat `id` replaces. */
191
+ readonly ui: "agora.ui";
192
+ readonly title: "agora.title";
193
+ readonly queue: "agora.queue";
194
+ /** The approval request as the native protocol carries it, for a consumer that renders it live. */
195
+ readonly approvalRequested: "agora.approval-requested";
196
+ readonly approvalSettled: "agora.approval-settled";
197
+ /** The whole question set of an elicitation (`ElicitationRequest`). */
198
+ readonly elicitation: "agora.elicitation";
199
+ /** `{ usage, costUsd, reasoningMs }` of one model step. */
200
+ readonly stepUsage: "agora.step-usage";
201
+ /** `{ message }` — input material this producer could not use and dropped. */
202
+ readonly warning: "agora.warning";
203
+ };
204
+ /**
205
+ * What the encoder reads: one frame of a run's stream, in the shared vocabulary
206
+ * ({@link AgentStreamEvent}) — plus the terminal failure, which the NestJS sink throws and the
207
+ * Adonis sink writes as a frame, and three optional facts a sink may know about a parked call:
208
+ * - `runId` — the run that is PARKED, when it is not the one whose stream this is (a delegated
209
+ * sub-agent forwards its frames into its ancestor's stream). Absent → the stream's own run.
210
+ * - `toolName`, `input` — the call being approved. Absent → read off the call's announcement.
211
+ *
212
+ * Framework-free on purpose: both servers project their own sink onto this and share one encoder.
213
+ */
214
+ type AgUiSourceFrame = Exclude<AgentStreamEvent, {
215
+ kind: 'approval-requested';
216
+ } | {
217
+ kind: 'elicitation';
218
+ } | {
219
+ kind: 'ui';
220
+ }> | (Extract<AgentStreamEvent, {
221
+ kind: 'approval-requested';
222
+ }> & {
223
+ runId?: string;
224
+ toolName?: string;
225
+ input?: unknown;
226
+ }) | (Extract<AgentStreamEvent, {
227
+ kind: 'elicitation';
228
+ }> & {
229
+ runId?: string;
230
+ })
231
+ /** A component with no `id` is numbered by its position in the stream (`ui:<n>`). */
232
+ | (Omit<Extract<AgentStreamEvent, {
233
+ kind: 'ui';
234
+ }>, 'id' | 'props'> & {
235
+ id?: string;
236
+ props: unknown;
237
+ })
238
+ /** The run failed: the AG-UI run ends with `RUN_ERROR`, and nothing follows it. */
239
+ | {
240
+ kind: 'error';
241
+ code: string;
242
+ message: string;
243
+ };
244
+
245
+ interface AgUiEncoderOptions {
246
+ /** The ids the consumer sent on `RunAgentInput`: every boundary event echoes them. */
247
+ threadId: string;
248
+ runId: string;
249
+ /** The library run whose stream is being projected (it mints interrupt ids and the `agora.run` event). */
250
+ streamRunId: string;
251
+ /** The library's thread id, when it differs from what the consumer calls the thread. */
252
+ streamThreadId?: string;
253
+ /**
254
+ * Frames of the library run's stream that an earlier AG-UI run already delivered (a resume). They
255
+ * are fed to the encoder like any other — it has to know what they opened — but produce no events.
256
+ */
257
+ skip?: number;
258
+ /**
259
+ * Tool calls a resuming request just answered. The run has not necessarily said so yet — a parked
260
+ * run takes a moment to wake — so without this the encoder would read them as still waiting and
261
+ * report the interrupt again before the answer had any effect.
262
+ */
263
+ answered?: readonly string[];
264
+ /** Model id for the usage entry when the step frames carry none. */
265
+ model?: string;
266
+ }
267
+ /**
268
+ * Projects one library run's stream ({@link AgUiSourceFrame}s, in buffer order) onto AG-UI 1.0 events.
269
+ *
270
+ * A pure state machine: the same frames always give the same events, which is what lets a resuming
271
+ * request — served by any replica — replay the run's buffer, skip what the interrupted AG-UI run
272
+ * already delivered, and continue. It writes nothing itself; {@link agUiEvents} drives it and
273
+ * decides when the run has stopped to ask.
274
+ *
275
+ * What maps where:
276
+ * - `text` → `TEXT_MESSAGE_*` (one message per stretch of text);
277
+ * - `reasoning` → a reasoning span with one reasoning message;
278
+ * - `step-start`/`step-finish` → `STEP_STARTED`/`STEP_FINISHED`, the step's usage folded into the
279
+ * run's `usage`;
280
+ * - `tool-input-*` → `TOOL_CALL_START`/`ARGS`/`END`; `tool-output*` → `TOOL_CALL_RESULT`;
281
+ * - an approval or a question set the run parks on → an `Interrupt` on the closing `RUN_FINISHED`;
282
+ * - `cancelled` → the cancelled outcome; an error frame → `RUN_ERROR`;
283
+ * - generative UI, title, queue and the native approval/elicitation frames → `CUSTOM` events named
284
+ * in {@link AG_UI_CUSTOM}, for what AG-UI has no event for.
285
+ *
286
+ * Not mapped: sub-agent attribution (`subagentRunId`) — a delegated agent's frames are projected
287
+ * flat, as the protocol allows of a producer that does not attribute.
288
+ */
289
+ declare class AgUiEncoder {
290
+ private readonly options;
291
+ private position;
292
+ private started;
293
+ private closed;
294
+ private cancelled;
295
+ private crossed;
296
+ private messageSeq;
297
+ private stepSeq;
298
+ private openText;
299
+ private openReasoning;
300
+ /** The last text message of the current step: a tool call attaches to it. */
301
+ private stepMessage;
302
+ private readonly openSteps;
303
+ private readonly calls;
304
+ private readonly pending;
305
+ private readonly usage;
306
+ constructor(options: AgUiEncoderOptions);
307
+ /** How many frames of the library stream this encoder has consumed. */
308
+ get consumed(): number;
309
+ /** The run is waiting on at least one approval or question set nobody has settled yet. */
310
+ get waiting(): boolean;
311
+ /**
312
+ * Is anything still in flight that is NOT waiting on a person — a tool call announced and neither
313
+ * answered nor parked? While there is, more frames are coming without anyone's help.
314
+ */
315
+ get busy(): boolean;
316
+ /** `RUN_STARTED`, and the library's own ids for the run. Call once, before the first frame. */
317
+ start(): AgUiEvent[];
318
+ /** The AG-UI events the next frame of the library stream stands for (possibly none). */
319
+ encode(frame: AgUiSourceFrame): AgUiEvent[];
320
+ /**
321
+ * The replayed frames are behind us: from here on events are written. The AG-UI run that delivered
322
+ * them closed everything it had open before it finished, so this run starts with nothing open, and
323
+ * what the resuming request answered is no longer waiting.
324
+ */
325
+ private crossBoundary;
326
+ private get replaying();
327
+ private project;
328
+ /**
329
+ * The events that end the AG-UI run: whatever is still open is closed first, then `RUN_FINISHED`
330
+ * with how it ended — interrupted when the run is waiting on someone, cancelled when it was
331
+ * stopped, success otherwise. Nothing after a `RUN_ERROR`. `ended` says the library run's stream
332
+ * itself ended, rather than this reader having stopped following it.
333
+ */
334
+ finish(ended?: boolean): AgUiEvent[];
335
+ private interrupts;
336
+ private custom;
337
+ private nextMessageId;
338
+ private textDelta;
339
+ private reasoningDelta;
340
+ private closeText;
341
+ private closeReasoning;
342
+ private closeStreams;
343
+ private callStart;
344
+ private result;
345
+ private addUsage;
346
+ private usageEntries;
347
+ }
348
+
349
+ /**
350
+ * An interrupt's id carries everything a resuming request needs, so the producer keeps NOTHING
351
+ * between the run that stopped to ask and the run that answers — the statelessness AG-UI lets a
352
+ * producer have, and what lets any replica serve the resume.
353
+ *
354
+ * It names the library run the human is answering (`parked` — a delegated sub-agent parks its OWN
355
+ * run), the run whose stream carries the work (`stream`), the tool call, and how many of that
356
+ * stream's frames the interrupted AG-UI run already delivered (`position`), which is where the
357
+ * resuming run picks the stream up.
358
+ *
359
+ * It is an address, not a credential: the resume route checks the caller owns the run exactly as
360
+ * the native approve/answer routes do.
361
+ */
362
+ interface InterruptAddress {
363
+ kind: 'approval' | 'elicitation';
364
+ /** The run to settle the call on. */
365
+ parked: string;
366
+ /** The run whose buffered stream the resume re-attaches to. */
367
+ stream: string;
368
+ toolCallId: string;
369
+ /** Frames of `stream` already delivered when the run was reported interrupted. */
370
+ position: number;
371
+ }
372
+ declare function encodeInterruptId(address: InterruptAddress): string;
373
+ /** The address an id names, or `null` for an id this producer did not mint. */
374
+ declare function decodeInterruptId(id: unknown): InterruptAddress | null;
375
+
376
+ /**
377
+ * Read a request body as a `RunAgentInput`, or say why it is not one.
378
+ *
379
+ * Only what this producer acts on is checked, and a KNOWN member with a value the schema rejects is
380
+ * malformed (the run never starts). A member it does not recognise is not an error — the protocol's
381
+ * asymmetry: a newer consumer's input must not bounce off an older producer.
382
+ */
383
+ declare function parseRunInput(body: unknown): AgUiRunInput | string;
384
+ /** A media part carried inline, ready to be staged as an attachment. */
385
+ interface InlineMedia {
386
+ kind: 'image' | 'audio' | 'video' | 'document';
387
+ contentType: string;
388
+ data: Buffer;
389
+ filename: string;
390
+ }
391
+ interface UserTurn {
392
+ /** The text of the message the run answers. */
393
+ text: string;
394
+ media: InlineMedia[];
395
+ /** Why a part was not used, one sentence each — reported, never fatal. */
396
+ dropped: string[];
397
+ }
398
+ /**
399
+ * The turn a run answers: the LAST user message of the input. The library keeps each thread's
400
+ * history itself, so the earlier messages the consumer restates are not read back in — what the
401
+ * agent resumes from is what it stored.
402
+ *
403
+ * Multimodal parts: text parts are the message's text; a media part carried inline (`data`) becomes
404
+ * an attachment. A part by `url` or by provider `file` handle is dropped and said so — this producer
405
+ * hands the model only bytes it staged itself, never an address a caller supplied.
406
+ */
407
+ declare function readUserTurn(messages: readonly AgUiMessage[]): UserTurn | null;
408
+ /** `context` entries as the library's page context carries them, or `undefined` for none. */
409
+ declare function readContext(context: readonly AgUiContext[] | undefined): AgUiContext[] | undefined;
410
+ /**
411
+ * What the library reads from `forwardedProps` — the consumer's channel for what AG-UI does not
412
+ * model: which agent, which model, which persona, and the page context the tools see.
413
+ */
414
+ interface ForwardedOptions {
415
+ agent?: string;
416
+ model?: string;
417
+ persona?: string;
418
+ pageContext?: Record<string, unknown>;
419
+ }
420
+ declare function readForwardedProps(forwarded: unknown): ForwardedOptions;
421
+ /** One resume entry this producer can act on. */
422
+ interface ResumeDecision {
423
+ address: InterruptAddress;
424
+ entry: AgUiResumeEntry;
425
+ }
426
+ interface ResumePlan {
427
+ decisions: ResumeDecision[];
428
+ /** Entries naming an interrupt this producer did not raise: skipped with a warning, never fatal. */
429
+ unrecognised: string[];
430
+ }
431
+ /**
432
+ * Sort a resume list into what it answers. Every recognised entry must continue the SAME library
433
+ * run from the SAME point — they are the interrupts of one `RUN_FINISHED` — and a list that does not
434
+ * is malformed (a string says why).
435
+ */
436
+ declare function planResume(resume: readonly AgUiResumeEntry[]): ResumePlan | string;
437
+ /** `{ approved, reason?, remember? }` out of an approval's resume payload. A bare boolean is accepted. */
438
+ declare function readApprovalPayload(payload: unknown): {
439
+ approved: boolean;
440
+ reason?: string;
441
+ remember?: boolean;
442
+ } | null;
443
+ /** `questionId → string[]` out of an elicitation's resume payload (`{ answers }` or the map itself). */
444
+ declare function readAnswersPayload(payload: unknown): Record<string, string[]> | null;
445
+
446
+ interface AgUiStreamOptions extends AgUiEncoderOptions {
447
+ /**
448
+ * How long the library stream may stay silent, while the run waits on a person AND has other work
449
+ * announced, before the AG-UI run is reported interrupted. Default 750 ms.
450
+ *
451
+ * Only that mixed case needs a clock. A run whose every open tool call is waiting on someone is
452
+ * reported at once; a run waiting on no one is never cut short.
453
+ */
454
+ quietMs?: number;
455
+ /** Events to write right after `RUN_STARTED` (warnings about input that was dropped). */
456
+ preamble?: AgUiEvent[];
457
+ }
458
+ /**
459
+ * One AG-UI run over a library run's stream.
460
+ *
461
+ * AG-UI has no mid-run channel from the consumer: a run that needs an approval or an answer does not
462
+ * wait with the connection open — it ENDS, saying what it waits for, and a later run carries the
463
+ * answers. The library run underneath does wait (parked, durably when the runner is durable). So this
464
+ * stops reading when the run is waiting on someone and nothing else is moving, closes the AG-UI run
465
+ * with the interrupt outcome, and leaves the library run parked for the resume to pick up.
466
+ */
467
+ declare function agUiEvents(frames: AsyncIterable<AgUiSourceFrame>, options: AgUiStreamOptions): AsyncGenerator<AgUiEvent>;
468
+ /** One AG-UI event as an SSE frame: a single `data:` line, LF-terminated, as the binding pins. */
469
+ declare function agUiSse(event: AgUiEvent): string;
470
+ /**
471
+ * A byte sink's stream (NDJSON {@link AgentStreamEvent}s, one per line, as the NestJS sinks carry
472
+ * it) as the frames the encoder reads. A line that is not a stream event is bare model text — the
473
+ * sink is a byte channel and a provider may write raw text into it. A run that failed ends the
474
+ * sink with an {@link AgentStreamError}, which becomes the terminal `error` frame; anything else
475
+ * thrown is rethrown, for the caller to report.
476
+ */
477
+ declare function agUiFramesFromNdjson(chunks: AsyncIterable<Uint8Array>): AsyncGenerator<AgUiSourceFrame>;
478
+
479
+ export { AG_UI_CUSTOM, AG_UI_PROTOCOL_VERSION, type AgUiContentPart, type AgUiContext, AgUiEncoder, type AgUiEncoderOptions, type AgUiEvent, type AgUiInterrupt, type AgUiMessage, type AgUiMetadata, type AgUiPartSource, type AgUiResumeEntry, type AgUiRunInput, type AgUiRunOutcome, type AgUiSourceFrame, type AgUiStreamOptions, type AgUiTokenUsage, type ForwardedOptions, type InlineMedia, type InterruptAddress, type ResumeDecision, type ResumePlan, type UserTurn, agUiEvents, agUiFramesFromNdjson, agUiSse, decodeInterruptId, encodeInterruptId, parseRunInput, planResume, readAnswersPayload, readApprovalPayload, readContext, readForwardedProps, readUserTurn };