@dudousxd/nestjs-agent-core 0.34.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1064 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/ag-ui/index.ts
22
+ var ag_ui_exports = {};
23
+ __export(ag_ui_exports, {
24
+ AG_UI_CUSTOM: () => AG_UI_CUSTOM,
25
+ AG_UI_PROTOCOL_VERSION: () => AG_UI_PROTOCOL_VERSION,
26
+ AgUiEncoder: () => AgUiEncoder,
27
+ agUiEvents: () => agUiEvents,
28
+ agUiFramesFromNdjson: () => agUiFramesFromNdjson,
29
+ agUiSse: () => agUiSse,
30
+ decodeInterruptId: () => decodeInterruptId,
31
+ encodeInterruptId: () => encodeInterruptId,
32
+ parseRunInput: () => parseRunInput,
33
+ planResume: () => planResume,
34
+ readAnswersPayload: () => readAnswersPayload,
35
+ readApprovalPayload: () => readApprovalPayload,
36
+ readContext: () => readContext,
37
+ readForwardedProps: () => readForwardedProps,
38
+ readUserTurn: () => readUserTurn
39
+ });
40
+ module.exports = __toCommonJS(ag_ui_exports);
41
+
42
+ // src/ag-ui/interrupt-id.ts
43
+ var PREFIX = "agora_";
44
+ function encodeInterruptId(address) {
45
+ const compact = [
46
+ address.kind === "approval" ? "a" : "e",
47
+ address.parked,
48
+ address.stream,
49
+ address.toolCallId,
50
+ address.position
51
+ ];
52
+ return PREFIX + Buffer.from(JSON.stringify(compact), "utf8").toString("base64url");
53
+ }
54
+ __name(encodeInterruptId, "encodeInterruptId");
55
+ function decodeInterruptId(id) {
56
+ if (typeof id !== "string" || !id.startsWith(PREFIX)) return null;
57
+ try {
58
+ const parsed = JSON.parse(Buffer.from(id.slice(PREFIX.length), "base64url").toString("utf8"));
59
+ if (!Array.isArray(parsed) || parsed.length !== 5) return null;
60
+ const [kind, parked, stream, toolCallId, position] = parsed;
61
+ if (kind !== "a" && kind !== "e" || typeof parked !== "string" || typeof stream !== "string" || typeof toolCallId !== "string" || typeof position !== "number" || !Number.isSafeInteger(position) || position < 0) {
62
+ return null;
63
+ }
64
+ return {
65
+ kind: kind === "a" ? "approval" : "elicitation",
66
+ parked,
67
+ stream,
68
+ toolCallId,
69
+ position
70
+ };
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+ __name(decodeInterruptId, "decodeInterruptId");
76
+
77
+ // src/ag-ui/types.ts
78
+ var AG_UI_PROTOCOL_VERSION = "1.0";
79
+ var AG_UI_CUSTOM = {
80
+ /** `{ runId, threadId }` — the library's own ids for the run behind this stream (cancel, re-attach). */
81
+ run: "agora.run",
82
+ /** A generative-UI component (`AgentUiComponent`); a repeat `id` replaces. */
83
+ ui: "agora.ui",
84
+ title: "agora.title",
85
+ queue: "agora.queue",
86
+ /** The approval request as the native protocol carries it, for a consumer that renders it live. */
87
+ approvalRequested: "agora.approval-requested",
88
+ approvalSettled: "agora.approval-settled",
89
+ /** The whole question set of an elicitation (`ElicitationRequest`). */
90
+ elicitation: "agora.elicitation",
91
+ /** `{ usage, costUsd, reasoningMs }` of one model step. */
92
+ stepUsage: "agora.step-usage",
93
+ /** `{ message }` — input material this producer could not use and dropped. */
94
+ warning: "agora.warning"
95
+ };
96
+
97
+ // src/ag-ui/encoder.ts
98
+ var APPROVAL_SCHEMA = {
99
+ type: "object",
100
+ properties: {
101
+ approved: {
102
+ type: "boolean"
103
+ },
104
+ reason: {
105
+ type: "string"
106
+ },
107
+ remember: {
108
+ type: "boolean"
109
+ }
110
+ },
111
+ required: [
112
+ "approved"
113
+ ]
114
+ };
115
+ function elicitationSchema(request) {
116
+ const properties = {};
117
+ for (const question of request.questions) {
118
+ const options = question.options?.map((option) => option.value);
119
+ properties[question.id] = {
120
+ type: "array",
121
+ title: question.prompt,
122
+ ...question.description !== void 0 ? {
123
+ description: question.description
124
+ } : {},
125
+ items: options !== void 0 && options.length > 0 && question.allowFreeText !== true ? {
126
+ type: "string",
127
+ enum: options
128
+ } : {
129
+ type: "string"
130
+ },
131
+ ...question.multiple === true ? {} : {
132
+ maxItems: 1
133
+ },
134
+ ...question.defaults !== void 0 ? {
135
+ default: question.defaults
136
+ } : {}
137
+ };
138
+ }
139
+ return {
140
+ type: "object",
141
+ properties: {
142
+ answers: {
143
+ type: "object",
144
+ properties
145
+ }
146
+ },
147
+ required: [
148
+ "answers"
149
+ ]
150
+ };
151
+ }
152
+ __name(elicitationSchema, "elicitationSchema");
153
+ function text(value) {
154
+ if (typeof value === "string") return value;
155
+ const json = JSON.stringify(value);
156
+ return json === void 0 ? "" : json;
157
+ }
158
+ __name(text, "text");
159
+ var AgUiEncoder = class {
160
+ static {
161
+ __name(this, "AgUiEncoder");
162
+ }
163
+ options;
164
+ position = 0;
165
+ started = false;
166
+ closed = false;
167
+ cancelled = false;
168
+ crossed = false;
169
+ messageSeq = 0;
170
+ stepSeq = 0;
171
+ openText;
172
+ openReasoning;
173
+ /** The last text message of the current step: a tool call attaches to it. */
174
+ stepMessage;
175
+ openSteps = [];
176
+ calls = /* @__PURE__ */ new Map();
177
+ pending = /* @__PURE__ */ new Map();
178
+ usage = /* @__PURE__ */ new Map();
179
+ constructor(options) {
180
+ this.options = options;
181
+ }
182
+ /** How many frames of the library stream this encoder has consumed. */
183
+ get consumed() {
184
+ return this.position;
185
+ }
186
+ /** The run is waiting on at least one approval or question set nobody has settled yet. */
187
+ get waiting() {
188
+ return this.pending.size > 0;
189
+ }
190
+ /**
191
+ * Is anything still in flight that is NOT waiting on a person — a tool call announced and neither
192
+ * answered nor parked? While there is, more frames are coming without anyone's help.
193
+ */
194
+ get busy() {
195
+ for (const [id, call] of this.calls) {
196
+ if (!call.answered && !this.pending.has(id)) return true;
197
+ }
198
+ return false;
199
+ }
200
+ /** `RUN_STARTED`, and the library's own ids for the run. Call once, before the first frame. */
201
+ start() {
202
+ if (this.started) return [];
203
+ this.started = true;
204
+ return [
205
+ {
206
+ type: "RUN_STARTED",
207
+ threadId: this.options.threadId,
208
+ runId: this.options.runId,
209
+ protocolVersion: AG_UI_PROTOCOL_VERSION
210
+ },
211
+ {
212
+ type: "CUSTOM",
213
+ name: AG_UI_CUSTOM.run,
214
+ value: {
215
+ runId: this.options.streamRunId,
216
+ threadId: this.options.streamThreadId ?? this.options.threadId
217
+ }
218
+ }
219
+ ];
220
+ }
221
+ /** The AG-UI events the next frame of the library stream stands for (possibly none). */
222
+ encode(frame) {
223
+ const position = this.position;
224
+ this.position += 1;
225
+ if (this.closed) return [];
226
+ const skip = this.options.skip ?? 0;
227
+ if (!this.crossed && position >= skip) this.crossBoundary();
228
+ const events = this.project(frame, position);
229
+ if (position < skip) {
230
+ if (this.position >= skip) this.crossBoundary();
231
+ return [];
232
+ }
233
+ return events;
234
+ }
235
+ /**
236
+ * The replayed frames are behind us: from here on events are written. The AG-UI run that delivered
237
+ * them closed everything it had open before it finished, so this run starts with nothing open, and
238
+ * what the resuming request answered is no longer waiting.
239
+ */
240
+ crossBoundary() {
241
+ this.crossed = true;
242
+ this.openText = void 0;
243
+ this.openReasoning = void 0;
244
+ this.stepMessage = void 0;
245
+ this.openSteps.length = 0;
246
+ for (const call of this.calls.values()) {
247
+ call.started = false;
248
+ call.ended = true;
249
+ }
250
+ for (const id of this.options.answered ?? []) this.pending.delete(id);
251
+ }
252
+ get replaying() {
253
+ return this.position <= (this.options.skip ?? 0);
254
+ }
255
+ project(event, position) {
256
+ switch (event.kind) {
257
+ case "error": {
258
+ this.closed = true;
259
+ const usage = this.usageEntries();
260
+ return [
261
+ {
262
+ type: "RUN_ERROR",
263
+ message: event.message,
264
+ code: event.code,
265
+ ...usage.length > 0 ? {
266
+ usage
267
+ } : {}
268
+ }
269
+ ];
270
+ }
271
+ case "ui":
272
+ return [
273
+ this.custom(AG_UI_CUSTOM.ui, {
274
+ id: event.id ?? `ui:${position}`,
275
+ component: event.component,
276
+ props: event.props,
277
+ ...event.version !== void 0 ? {
278
+ version: event.version
279
+ } : {},
280
+ ...event.toolCallId !== void 0 ? {
281
+ toolCallId: event.toolCallId
282
+ } : {}
283
+ })
284
+ ];
285
+ case "approval-requested": {
286
+ const call = this.calls.get(event.id);
287
+ const parked = event.runId ?? this.options.streamRunId;
288
+ const toolName = event.toolName ?? call?.name ?? "";
289
+ const input = event.input ?? call?.input ?? null;
290
+ this.pending.set(event.id, {
291
+ kind: "approval",
292
+ parked,
293
+ toolCallId: event.id,
294
+ interrupt: {
295
+ reason: "tool_approval",
296
+ message: event.reason ?? (toolName.length > 0 ? `Approve ${toolName}?` : "Approve?"),
297
+ toolCallId: event.id,
298
+ responseSchema: APPROVAL_SCHEMA,
299
+ ...event.expiresAt !== void 0 ? {
300
+ expiresAt: event.expiresAt
301
+ } : {},
302
+ metadata: {
303
+ "agora.toolName": toolName,
304
+ "agora.input": input,
305
+ "agora.approver": event.approver
306
+ }
307
+ }
308
+ });
309
+ return [
310
+ this.custom(AG_UI_CUSTOM.approvalRequested, {
311
+ id: event.id,
312
+ runId: parked,
313
+ toolName,
314
+ input,
315
+ approver: event.approver,
316
+ ...event.expiresAt !== void 0 ? {
317
+ expiresAt: event.expiresAt
318
+ } : {},
319
+ ...event.reason !== void 0 ? {
320
+ reason: event.reason
321
+ } : {}
322
+ })
323
+ ];
324
+ }
325
+ case "elicitation": {
326
+ const parked = event.runId ?? this.options.streamRunId;
327
+ this.pending.set(event.id, {
328
+ kind: "elicitation",
329
+ parked,
330
+ toolCallId: event.id,
331
+ interrupt: {
332
+ reason: "input_required",
333
+ message: event.request.preamble ?? event.request.questions[0]?.prompt ?? "Input required",
334
+ // An intake's question set belongs to no tool call the stream announced.
335
+ ...this.calls.has(event.id) ? {
336
+ toolCallId: event.id
337
+ } : {},
338
+ responseSchema: elicitationSchema(event.request),
339
+ metadata: {
340
+ "agora.request": event.request
341
+ }
342
+ }
343
+ });
344
+ return [
345
+ this.custom(AG_UI_CUSTOM.elicitation, {
346
+ runId: parked,
347
+ request: event.request
348
+ })
349
+ ];
350
+ }
351
+ case "text":
352
+ return event.text.length > 0 ? this.textDelta(event.text) : [];
353
+ case "reasoning":
354
+ return event.text.length > 0 ? this.reasoningDelta(event.text) : [];
355
+ case "step-start": {
356
+ this.stepSeq += 1;
357
+ const stepName = `step-${this.stepSeq}`;
358
+ this.openSteps.push(stepName);
359
+ this.stepMessage = void 0;
360
+ return [
361
+ ...this.closeStreams(),
362
+ {
363
+ type: "STEP_STARTED",
364
+ stepName
365
+ }
366
+ ];
367
+ }
368
+ case "step-finish": {
369
+ const out = this.closeStreams();
370
+ if (!this.replaying) this.addUsage(event.usage, event.model);
371
+ const stepName = this.openSteps.pop();
372
+ if (stepName !== void 0) out.push({
373
+ type: "STEP_FINISHED",
374
+ stepName
375
+ });
376
+ if (event.usage !== void 0 || event.costUsd !== void 0) {
377
+ out.push(this.custom(AG_UI_CUSTOM.stepUsage, {
378
+ ...event.usage !== void 0 ? {
379
+ usage: event.usage
380
+ } : {},
381
+ ...event.costUsd !== void 0 ? {
382
+ costUsd: event.costUsd
383
+ } : {},
384
+ ...event.reasoningMs !== void 0 ? {
385
+ reasoningMs: event.reasoningMs
386
+ } : {}
387
+ }));
388
+ }
389
+ return out;
390
+ }
391
+ case "tool-input-start": {
392
+ if (this.calls.has(event.id)) return [];
393
+ const out = this.closeStreams();
394
+ this.calls.set(event.id, {
395
+ name: event.name,
396
+ started: true,
397
+ ended: false,
398
+ sawDelta: false,
399
+ answered: false
400
+ });
401
+ out.push(this.callStart(event.id, event.name));
402
+ return out;
403
+ }
404
+ case "tool-input-delta": {
405
+ const call = this.calls.get(event.id);
406
+ if (call === void 0 || call.ended || event.delta.length === 0) return [];
407
+ call.sawDelta = true;
408
+ return [
409
+ {
410
+ type: "TOOL_CALL_ARGS",
411
+ toolCallId: event.id,
412
+ delta: event.delta
413
+ }
414
+ ];
415
+ }
416
+ case "tool-input-available": {
417
+ const known = this.calls.get(event.id);
418
+ if (known?.ended === true) return [];
419
+ const out = this.closeStreams();
420
+ const call = known ?? {
421
+ name: event.name,
422
+ started: false,
423
+ ended: false,
424
+ sawDelta: false,
425
+ answered: false
426
+ };
427
+ if (!call.started) {
428
+ call.started = true;
429
+ out.push(this.callStart(event.id, event.name));
430
+ }
431
+ if (!call.sawDelta) {
432
+ out.push({
433
+ type: "TOOL_CALL_ARGS",
434
+ toolCallId: event.id,
435
+ delta: text(event.input ?? {})
436
+ });
437
+ }
438
+ call.ended = true;
439
+ call.input = event.input;
440
+ this.calls.set(event.id, call);
441
+ out.push({
442
+ type: "TOOL_CALL_END",
443
+ toolCallId: event.id
444
+ });
445
+ return out;
446
+ }
447
+ case "tool-output":
448
+ return this.result(event.id, text(event.output));
449
+ case "tool-output-error":
450
+ return this.result(event.id, event.error, {
451
+ "agora.outcome": "error"
452
+ });
453
+ case "tool-output-denied":
454
+ return this.result(event.id, event.reason ?? "denied", {
455
+ "agora.outcome": "denied"
456
+ });
457
+ case "approval-settled":
458
+ this.pending.delete(event.id);
459
+ return [
460
+ this.custom(AG_UI_CUSTOM.approvalSettled, event)
461
+ ];
462
+ case "title":
463
+ return [
464
+ this.custom(AG_UI_CUSTOM.title, {
465
+ title: event.title
466
+ })
467
+ ];
468
+ case "queue":
469
+ return [
470
+ this.custom(AG_UI_CUSTOM.queue, {
471
+ queue: event.queue,
472
+ ...event.started !== void 0 ? {
473
+ started: event.started
474
+ } : {}
475
+ })
476
+ ];
477
+ case "cancelled":
478
+ this.cancelled = true;
479
+ return [];
480
+ default:
481
+ return [];
482
+ }
483
+ }
484
+ /**
485
+ * The events that end the AG-UI run: whatever is still open is closed first, then `RUN_FINISHED`
486
+ * with how it ended — interrupted when the run is waiting on someone, cancelled when it was
487
+ * stopped, success otherwise. Nothing after a `RUN_ERROR`. `ended` says the library run's stream
488
+ * itself ended, rather than this reader having stopped following it.
489
+ */
490
+ finish(ended = false) {
491
+ if (this.closed) return [];
492
+ this.closed = true;
493
+ if (!this.crossed) this.crossBoundary();
494
+ if (ended) this.pending.clear();
495
+ const out = this.start();
496
+ out.push(...this.closeStreams());
497
+ for (const [id, call] of this.calls) {
498
+ if (call.started && !call.ended) {
499
+ call.ended = true;
500
+ out.push({
501
+ type: "TOOL_CALL_END",
502
+ toolCallId: id
503
+ });
504
+ }
505
+ }
506
+ while (this.openSteps.length > 0) {
507
+ out.push({
508
+ type: "STEP_FINISHED",
509
+ stepName: this.openSteps.pop()
510
+ });
511
+ }
512
+ const usage = this.usageEntries();
513
+ const interrupts = this.cancelled ? [] : this.interrupts();
514
+ out.push({
515
+ type: "RUN_FINISHED",
516
+ threadId: this.options.threadId,
517
+ runId: this.options.runId,
518
+ ...this.cancelled ? {
519
+ outcome: {
520
+ type: "cancelled"
521
+ }
522
+ } : interrupts.length > 0 ? {
523
+ outcome: {
524
+ type: "interrupt",
525
+ interrupts
526
+ }
527
+ } : {},
528
+ ...usage.length > 0 ? {
529
+ usage
530
+ } : {}
531
+ });
532
+ return out;
533
+ }
534
+ interrupts() {
535
+ return [
536
+ ...this.pending.values()
537
+ ].map((entry) => ({
538
+ id: encodeInterruptId({
539
+ kind: entry.kind,
540
+ parked: entry.parked,
541
+ stream: this.options.streamRunId,
542
+ toolCallId: entry.toolCallId,
543
+ position: this.position
544
+ }),
545
+ ...entry.interrupt
546
+ }));
547
+ }
548
+ custom(name, value) {
549
+ return {
550
+ type: "CUSTOM",
551
+ name,
552
+ value
553
+ };
554
+ }
555
+ nextMessageId() {
556
+ this.messageSeq += 1;
557
+ return `${this.options.runId}:m${this.messageSeq}`;
558
+ }
559
+ textDelta(delta) {
560
+ const out = [];
561
+ if (this.openReasoning !== void 0) out.push(...this.closeReasoning());
562
+ if (this.openText === void 0) {
563
+ this.openText = this.nextMessageId();
564
+ this.stepMessage = this.openText;
565
+ out.push({
566
+ type: "TEXT_MESSAGE_START",
567
+ messageId: this.openText,
568
+ role: "assistant"
569
+ });
570
+ }
571
+ out.push({
572
+ type: "TEXT_MESSAGE_CONTENT",
573
+ messageId: this.openText,
574
+ delta
575
+ });
576
+ return out;
577
+ }
578
+ reasoningDelta(delta) {
579
+ const out = [];
580
+ if (this.openText !== void 0) out.push(...this.closeText());
581
+ if (this.openReasoning === void 0) {
582
+ this.openReasoning = this.nextMessageId();
583
+ out.push({
584
+ type: "REASONING_START",
585
+ messageId: this.openReasoning
586
+ }, {
587
+ type: "REASONING_MESSAGE_START",
588
+ messageId: this.openReasoning,
589
+ role: "reasoning"
590
+ });
591
+ }
592
+ out.push({
593
+ type: "REASONING_MESSAGE_CONTENT",
594
+ messageId: this.openReasoning,
595
+ delta
596
+ });
597
+ return out;
598
+ }
599
+ closeText() {
600
+ if (this.openText === void 0) return [];
601
+ const messageId = this.openText;
602
+ this.openText = void 0;
603
+ return [
604
+ {
605
+ type: "TEXT_MESSAGE_END",
606
+ messageId
607
+ }
608
+ ];
609
+ }
610
+ closeReasoning() {
611
+ if (this.openReasoning === void 0) return [];
612
+ const messageId = this.openReasoning;
613
+ this.openReasoning = void 0;
614
+ return [
615
+ {
616
+ type: "REASONING_MESSAGE_END",
617
+ messageId
618
+ },
619
+ {
620
+ type: "REASONING_END",
621
+ messageId
622
+ }
623
+ ];
624
+ }
625
+ closeStreams() {
626
+ return [
627
+ ...this.closeReasoning(),
628
+ ...this.closeText()
629
+ ];
630
+ }
631
+ callStart(id, name) {
632
+ return {
633
+ type: "TOOL_CALL_START",
634
+ toolCallId: id,
635
+ toolCallName: name,
636
+ ...this.stepMessage !== void 0 ? {
637
+ parentMessageId: this.stepMessage
638
+ } : {}
639
+ };
640
+ }
641
+ result(id, content, metadata) {
642
+ const call = this.calls.get(id);
643
+ if (call !== void 0) call.answered = true;
644
+ else {
645
+ this.calls.set(id, {
646
+ name: "",
647
+ started: false,
648
+ ended: true,
649
+ sawDelta: false,
650
+ answered: true
651
+ });
652
+ }
653
+ this.pending.delete(id);
654
+ return [
655
+ ...this.closeStreams(),
656
+ {
657
+ type: "TOOL_CALL_RESULT",
658
+ messageId: `${this.options.runId}:tool:${id}`,
659
+ toolCallId: id,
660
+ content,
661
+ role: "tool",
662
+ ...metadata !== void 0 ? {
663
+ metadata
664
+ } : {}
665
+ }
666
+ ];
667
+ }
668
+ addUsage(usage, model) {
669
+ if (usage === void 0) return;
670
+ const name = typeof model === "string" && model.length > 0 ? model : this.options.model;
671
+ const key = name ?? "";
672
+ const entry = this.usage.get(key) ?? (name !== void 0 ? {
673
+ model: name
674
+ } : {});
675
+ entry.inputTokens = (entry.inputTokens ?? 0) + usage.inputTokens;
676
+ entry.outputTokens = (entry.outputTokens ?? 0) + usage.outputTokens;
677
+ entry.totalTokens = entry.inputTokens + entry.outputTokens;
678
+ if (usage.cacheReadTokens !== void 0) {
679
+ entry.cachedInputTokens = (entry.cachedInputTokens ?? 0) + usage.cacheReadTokens;
680
+ }
681
+ if (usage.cacheWriteTokens !== void 0) {
682
+ entry.cacheWriteInputTokens = (entry.cacheWriteInputTokens ?? 0) + usage.cacheWriteTokens;
683
+ }
684
+ if (usage.reasoningTokens !== void 0) {
685
+ entry.reasoningTokens = (entry.reasoningTokens ?? 0) + usage.reasoningTokens;
686
+ }
687
+ this.usage.set(key, entry);
688
+ }
689
+ usageEntries() {
690
+ return [
691
+ ...this.usage.values()
692
+ ];
693
+ }
694
+ };
695
+
696
+ // src/ag-ui/input.ts
697
+ function isRecord(value) {
698
+ return typeof value === "object" && value !== null && !Array.isArray(value);
699
+ }
700
+ __name(isRecord, "isRecord");
701
+ function parseRunInput(body) {
702
+ if (!isRecord(body)) return "the body must be a RunAgentInput object";
703
+ if (typeof body.threadId !== "string" || body.threadId.length === 0) {
704
+ return "threadId must be a non-empty string";
705
+ }
706
+ if (body.threadId.length > 255) return "threadId must be at most 255 characters";
707
+ if (typeof body.runId !== "string" || body.runId.length === 0) {
708
+ return "runId must be a non-empty string";
709
+ }
710
+ if (!Array.isArray(body.messages)) return "messages must be an array";
711
+ for (const message of body.messages) {
712
+ if (!isRecord(message) || typeof message.role !== "string") {
713
+ return "each message must be an object with a role";
714
+ }
715
+ }
716
+ if (body.resume !== void 0) {
717
+ if (!Array.isArray(body.resume)) return "resume must be an array";
718
+ for (const entry of body.resume) {
719
+ if (!isRecord(entry) || typeof entry.interruptId !== "string" || entry.status !== "resolved" && entry.status !== "cancelled") {
720
+ return "each resume entry needs an interruptId and a status of 'resolved' or 'cancelled'";
721
+ }
722
+ }
723
+ }
724
+ if (body.context !== void 0 && !Array.isArray(body.context)) {
725
+ return "context must be an array";
726
+ }
727
+ return body;
728
+ }
729
+ __name(parseRunInput, "parseRunInput");
730
+ var EXTENSIONS = {
731
+ "image/png": "png",
732
+ "image/jpeg": "jpg",
733
+ "image/gif": "gif",
734
+ "image/webp": "webp",
735
+ "application/pdf": "pdf",
736
+ "text/plain": "txt"
737
+ };
738
+ function filenameOf(part, index, contentType) {
739
+ const metadata = part.metadata;
740
+ if (isRecord(metadata)) {
741
+ for (const key of [
742
+ "filename",
743
+ "name",
744
+ "title"
745
+ ]) {
746
+ const value = metadata[key];
747
+ if (typeof value === "string" && value.trim().length > 0) return value.trim().slice(0, 200);
748
+ }
749
+ }
750
+ const extension = EXTENSIONS[contentType];
751
+ return `${part.type}-${index + 1}${extension !== void 0 ? `.${extension}` : ""}`;
752
+ }
753
+ __name(filenameOf, "filenameOf");
754
+ function readUserTurn(messages) {
755
+ let last;
756
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
757
+ if (messages[index]?.role === "user") {
758
+ last = messages[index];
759
+ break;
760
+ }
761
+ }
762
+ if (last === void 0) return null;
763
+ if (typeof last.content === "string") return {
764
+ text: last.content,
765
+ media: [],
766
+ dropped: []
767
+ };
768
+ if (!Array.isArray(last.content)) return {
769
+ text: "",
770
+ media: [],
771
+ dropped: []
772
+ };
773
+ const texts = [];
774
+ const media = [];
775
+ const dropped = [];
776
+ last.content.forEach((part, index) => {
777
+ if (!isRecord(part)) return;
778
+ if (part.type === "text") {
779
+ if (typeof part.text === "string") texts.push(part.text);
780
+ return;
781
+ }
782
+ if (part.type !== "image" && part.type !== "audio" && part.type !== "video" && part.type !== "document") {
783
+ return;
784
+ }
785
+ const source = part.source;
786
+ if (!isRecord(source) || source.type !== "data") {
787
+ const how = isRecord(source) && typeof source.type === "string" ? source.type : "unknown";
788
+ dropped.push(`The ${part.type} part ${index + 1} was not used: only inline data is accepted, not a ${how} source.`);
789
+ return;
790
+ }
791
+ if (typeof source.value !== "string" || typeof source.mimeType !== "string") {
792
+ dropped.push(`The ${part.type} part ${index + 1} was not used: its inline data is malformed.`);
793
+ return;
794
+ }
795
+ const data = Buffer.from(source.value, "base64");
796
+ if (data.length === 0) {
797
+ dropped.push(`The ${part.type} part ${index + 1} was not used: it carries no bytes.`);
798
+ return;
799
+ }
800
+ const contentType = source.mimeType.toLowerCase();
801
+ media.push({
802
+ kind: part.type,
803
+ contentType,
804
+ data,
805
+ filename: filenameOf(part, index, contentType)
806
+ });
807
+ });
808
+ return {
809
+ text: texts.join("\n"),
810
+ media,
811
+ dropped
812
+ };
813
+ }
814
+ __name(readUserTurn, "readUserTurn");
815
+ function readContext(context) {
816
+ if (context === void 0) return void 0;
817
+ const entries = context.filter((entry) => isRecord(entry) && typeof entry.description === "string" && typeof entry.value === "string");
818
+ return entries.length > 0 ? entries : void 0;
819
+ }
820
+ __name(readContext, "readContext");
821
+ function readForwardedProps(forwarded) {
822
+ if (!isRecord(forwarded)) return {};
823
+ const pick = /* @__PURE__ */ __name((key) => {
824
+ const value = forwarded[key];
825
+ return typeof value === "string" && value.length > 0 ? value : void 0;
826
+ }, "pick");
827
+ const agent = pick("agent");
828
+ const model = pick("model");
829
+ const persona = pick("persona");
830
+ return {
831
+ ...agent !== void 0 ? {
832
+ agent
833
+ } : {},
834
+ ...model !== void 0 ? {
835
+ model
836
+ } : {},
837
+ ...persona !== void 0 ? {
838
+ persona
839
+ } : {},
840
+ ...isRecord(forwarded.pageContext) ? {
841
+ pageContext: forwarded.pageContext
842
+ } : {}
843
+ };
844
+ }
845
+ __name(readForwardedProps, "readForwardedProps");
846
+ function planResume(resume) {
847
+ const decisions = [];
848
+ const unrecognised = [];
849
+ for (const entry of resume) {
850
+ const address = decodeInterruptId(entry.interruptId);
851
+ if (address === null) {
852
+ unrecognised.push(entry.interruptId);
853
+ continue;
854
+ }
855
+ decisions.push({
856
+ address,
857
+ entry
858
+ });
859
+ }
860
+ const first = decisions[0];
861
+ if (first === void 0) return {
862
+ decisions,
863
+ unrecognised
864
+ };
865
+ for (const { address } of decisions) {
866
+ if (address.stream !== first.address.stream || address.position !== first.address.position) {
867
+ return "the resume entries answer interrupts of different runs";
868
+ }
869
+ }
870
+ const seen = /* @__PURE__ */ new Set();
871
+ for (const { address } of decisions) {
872
+ if (seen.has(address.toolCallId)) return "an interrupt is answered twice";
873
+ seen.add(address.toolCallId);
874
+ }
875
+ return {
876
+ decisions,
877
+ unrecognised
878
+ };
879
+ }
880
+ __name(planResume, "planResume");
881
+ function readApprovalPayload(payload) {
882
+ if (typeof payload === "boolean") return {
883
+ approved: payload
884
+ };
885
+ if (!isRecord(payload) || typeof payload.approved !== "boolean") return null;
886
+ return {
887
+ approved: payload.approved,
888
+ ...typeof payload.reason === "string" ? {
889
+ reason: payload.reason
890
+ } : {},
891
+ ...typeof payload.remember === "boolean" ? {
892
+ remember: payload.remember
893
+ } : {}
894
+ };
895
+ }
896
+ __name(readApprovalPayload, "readApprovalPayload");
897
+ function readAnswersPayload(payload) {
898
+ const source = isRecord(payload) && isRecord(payload.answers) ? payload.answers : payload;
899
+ if (!isRecord(source)) return null;
900
+ const answers = {};
901
+ for (const [key, value] of Object.entries(source)) {
902
+ if (typeof value === "string") answers[key] = [
903
+ value
904
+ ];
905
+ else if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
906
+ answers[key] = value;
907
+ } else return null;
908
+ }
909
+ return answers;
910
+ }
911
+ __name(readAnswersPayload, "readAnswersPayload");
912
+
913
+ // src/spi/token-stream-sink.ts
914
+ var AgentStreamError = class extends Error {
915
+ static {
916
+ __name(this, "AgentStreamError");
917
+ }
918
+ code;
919
+ constructor(error) {
920
+ super(error.message);
921
+ this.name = "AgentStreamError";
922
+ this.code = error.code;
923
+ }
924
+ };
925
+
926
+ // src/stream-events.ts
927
+ var encoder = new TextEncoder();
928
+ function decodeStreamEvent(line) {
929
+ try {
930
+ const parsed = JSON.parse(line);
931
+ if (typeof parsed === "object" && parsed !== null && typeof parsed.kind === "string") {
932
+ return parsed;
933
+ }
934
+ } catch {
935
+ }
936
+ return null;
937
+ }
938
+ __name(decodeStreamEvent, "decodeStreamEvent");
939
+
940
+ // src/ag-ui/stream.ts
941
+ var DEFAULT_QUIET_MS = 750;
942
+ var GRACE_MS = 50;
943
+ async function* agUiEvents(frames, options) {
944
+ const encoder2 = new AgUiEncoder(options);
945
+ const quietMs = options.quietMs ?? DEFAULT_QUIET_MS;
946
+ yield* encoder2.start();
947
+ yield* options.preamble ?? [];
948
+ const iterator = frames[Symbol.asyncIterator]();
949
+ let upcoming;
950
+ let ended = false;
951
+ try {
952
+ for (; ; ) {
953
+ upcoming ??= iterator.next();
954
+ const caughtUp = encoder2.consumed >= (options.skip ?? 0);
955
+ let next;
956
+ if (caughtUp && encoder2.waiting) {
957
+ next = await raceQuiet(upcoming, encoder2.busy ? quietMs : Math.min(quietMs, GRACE_MS));
958
+ } else {
959
+ next = await upcoming;
960
+ }
961
+ if (next === "quiet") break;
962
+ upcoming = void 0;
963
+ if (next.done === true) {
964
+ ended = true;
965
+ break;
966
+ }
967
+ yield* encoder2.encode(next.value);
968
+ }
969
+ } finally {
970
+ void iterator.return?.();
971
+ }
972
+ yield* encoder2.finish(ended);
973
+ }
974
+ __name(agUiEvents, "agUiEvents");
975
+ function raceQuiet(upcoming, ms) {
976
+ return new Promise((resolve, reject) => {
977
+ const timer = setTimeout(() => resolve("quiet"), ms);
978
+ upcoming.then((result) => {
979
+ clearTimeout(timer);
980
+ resolve(result);
981
+ }, (error) => {
982
+ clearTimeout(timer);
983
+ reject(error);
984
+ });
985
+ });
986
+ }
987
+ __name(raceQuiet, "raceQuiet");
988
+ function agUiSse(event) {
989
+ return `data: ${JSON.stringify(event)}
990
+
991
+ `;
992
+ }
993
+ __name(agUiSse, "agUiSse");
994
+ async function* agUiFramesFromNdjson(chunks) {
995
+ const decoder = new TextDecoder();
996
+ let buffer = "";
997
+ const read = /* @__PURE__ */ __name((line) => {
998
+ const event = decodeStreamEvent(line);
999
+ if (event !== null) return [
1000
+ event
1001
+ ];
1002
+ const at = line.indexOf('{"kind":');
1003
+ const tail = at > 0 ? decodeStreamEvent(line.slice(at)) : null;
1004
+ if (tail !== null) return [
1005
+ {
1006
+ kind: "text",
1007
+ text: line.slice(0, at)
1008
+ },
1009
+ tail
1010
+ ];
1011
+ return [
1012
+ {
1013
+ kind: "text",
1014
+ text: line
1015
+ }
1016
+ ];
1017
+ }, "read");
1018
+ try {
1019
+ for await (const chunk of chunks) {
1020
+ buffer += decoder.decode(chunk, {
1021
+ stream: true
1022
+ });
1023
+ let newline = buffer.indexOf("\n");
1024
+ while (newline !== -1) {
1025
+ const line = buffer.slice(0, newline);
1026
+ buffer = buffer.slice(newline + 1);
1027
+ if (line.length > 0) yield* read(line);
1028
+ newline = buffer.indexOf("\n");
1029
+ }
1030
+ }
1031
+ buffer += decoder.decode();
1032
+ if (buffer.length > 0) yield* read(buffer);
1033
+ } catch (error) {
1034
+ if (error instanceof AgentStreamError) {
1035
+ yield {
1036
+ kind: "error",
1037
+ code: error.code,
1038
+ message: error.message
1039
+ };
1040
+ return;
1041
+ }
1042
+ throw error;
1043
+ }
1044
+ }
1045
+ __name(agUiFramesFromNdjson, "agUiFramesFromNdjson");
1046
+ // Annotate the CommonJS export names for ESM import in node:
1047
+ 0 && (module.exports = {
1048
+ AG_UI_CUSTOM,
1049
+ AG_UI_PROTOCOL_VERSION,
1050
+ AgUiEncoder,
1051
+ agUiEvents,
1052
+ agUiFramesFromNdjson,
1053
+ agUiSse,
1054
+ decodeInterruptId,
1055
+ encodeInterruptId,
1056
+ parseRunInput,
1057
+ planResume,
1058
+ readAnswersPayload,
1059
+ readApprovalPayload,
1060
+ readContext,
1061
+ readForwardedProps,
1062
+ readUserTurn
1063
+ });
1064
+ //# sourceMappingURL=index.cjs.map