veryfront 0.1.193 → 0.1.196

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,753 @@
1
+ import "../../_dnt.polyfills.js";
2
+ import { mergeToolInputDelta, parseToolInputObject } from "../agent/data-stream.js";
3
+ import type { ChatFinishReason, ChatStreamEvent } from "./protocol.js";
4
+ import { z } from "zod";
5
+
6
+ type JsonPatchOperation = {
7
+ op: "add" | "remove" | "replace" | "move" | "copy" | "test";
8
+ path: string;
9
+ from?: string;
10
+ value?: unknown;
11
+ };
12
+
13
+ type ParsedRenderableCustomChunk = Extract<
14
+ ChatStreamEvent,
15
+ { type: "source-url" | "source-document" | "file" }
16
+ >;
17
+
18
+ type ToolCallState = {
19
+ toolName: string;
20
+ argsText: string;
21
+ };
22
+
23
+ export type ParsedSseEvent = {
24
+ id: number | null;
25
+ event: string | null;
26
+ data: string;
27
+ };
28
+
29
+ export type AgUiDecodedEvent = {
30
+ eventId: number | null;
31
+ wireEvent: AgUiWireEvent;
32
+ chatEvents: ChatStreamEvent[];
33
+ };
34
+
35
+ export type AgUiDecodedChunk = {
36
+ events: AgUiDecodedEvent[];
37
+ remainder: string;
38
+ };
39
+
40
+ export type AgUiChatEventDecoderState = {
41
+ remainder: string;
42
+ lastEventId: number;
43
+ toolCalls: Map<string, ToolCallState>;
44
+ reasoningFallbackIndex: number;
45
+ activeFallbackReasoningPartId: string | null;
46
+ };
47
+
48
+ export const AgUiRunFinishedMetadataSchema = z.object({
49
+ provider: z.string().optional(),
50
+ model: z.string().optional(),
51
+ inputTokens: z.number().int().nonnegative().optional(),
52
+ outputTokens: z.number().int().nonnegative().optional(),
53
+ totalTokens: z.number().int().nonnegative().optional(),
54
+ cachedInputTokens: z.number().int().nonnegative().optional(),
55
+ reasoningTokens: z.number().int().nonnegative().optional(),
56
+ finishReason: z.string().optional(),
57
+ providerRequestId: z.string().optional(),
58
+ });
59
+
60
+ export const AgUiSnapshotToolCallSchema = z.object({
61
+ id: z.string().min(1),
62
+ type: z.literal("function"),
63
+ function: z.object({
64
+ name: z.string().min(1),
65
+ arguments: z.string(),
66
+ }),
67
+ encryptedValue: z.string().optional(),
68
+ });
69
+
70
+ const AgUiUserInputContentSchema = z.discriminatedUnion("type", [
71
+ z.object({
72
+ type: z.literal("text"),
73
+ text: z.string(),
74
+ }),
75
+ z.object({
76
+ type: z.literal("binary"),
77
+ mimeType: z.string(),
78
+ id: z.string().optional(),
79
+ url: z.string().optional(),
80
+ data: z.string().optional(),
81
+ filename: z.string().optional(),
82
+ }),
83
+ ]);
84
+
85
+ export const AgUiSnapshotMessageSchema = z.discriminatedUnion("role", [
86
+ z.object({
87
+ id: z.string(),
88
+ role: z.literal("assistant"),
89
+ content: z.string().optional(),
90
+ name: z.string().optional(),
91
+ encryptedValue: z.string().optional(),
92
+ toolCalls: z.array(AgUiSnapshotToolCallSchema).optional(),
93
+ }),
94
+ z.object({
95
+ id: z.string(),
96
+ role: z.literal("user"),
97
+ content: z.union([z.string(), z.array(AgUiUserInputContentSchema)]),
98
+ name: z.string().optional(),
99
+ encryptedValue: z.string().optional(),
100
+ }),
101
+ z.object({
102
+ id: z.string(),
103
+ role: z.literal("tool"),
104
+ toolCallId: z.string(),
105
+ content: z.string(),
106
+ error: z.string().optional(),
107
+ encryptedValue: z.string().optional(),
108
+ }),
109
+ z.object({
110
+ id: z.string(),
111
+ role: z.literal("reasoning"),
112
+ content: z.string(),
113
+ name: z.string().optional(),
114
+ encryptedValue: z.string().optional(),
115
+ }),
116
+ ]);
117
+
118
+ export const AgUiWireEventNameSchema = z.enum([
119
+ "RunStarted",
120
+ "Custom",
121
+ "TextMessageStart",
122
+ "TextMessageContent",
123
+ "TextMessageEnd",
124
+ "ToolCallStart",
125
+ "ToolCallArgs",
126
+ "ToolCallChunk",
127
+ "ToolCallEnd",
128
+ "ToolCallResult",
129
+ "StateSnapshot",
130
+ "MessagesSnapshot",
131
+ "ReasoningMessageStart",
132
+ "ReasoningMessageContent",
133
+ "ReasoningMessageEnd",
134
+ "StateDelta",
135
+ "RunFinished",
136
+ "RunError",
137
+ ]);
138
+
139
+ export const AgUiWireEventSchema = z.discriminatedUnion("eventName", [
140
+ z.object({
141
+ eventName: z.literal("RunStarted"),
142
+ payload: z.object({
143
+ runId: z.string().optional(),
144
+ threadId: z.string().optional(),
145
+ agentId: z.string().optional(),
146
+ }),
147
+ }),
148
+ z.object({
149
+ eventName: z.literal("Custom"),
150
+ payload: z.object({
151
+ name: z.string(),
152
+ value: z.unknown(),
153
+ }),
154
+ }),
155
+ z.object({
156
+ eventName: z.literal("TextMessageStart"),
157
+ payload: z.object({
158
+ messageId: z.string().min(1),
159
+ id: z.string().min(1).optional(),
160
+ contentId: z.string().min(1).optional(),
161
+ role: z.string().optional(),
162
+ }),
163
+ }),
164
+ z.object({
165
+ eventName: z.literal("TextMessageContent"),
166
+ payload: z.object({
167
+ messageId: z.string().min(1),
168
+ id: z.string().min(1).optional(),
169
+ contentId: z.string().min(1).optional(),
170
+ delta: z.string(),
171
+ }),
172
+ }),
173
+ z.object({
174
+ eventName: z.literal("TextMessageEnd"),
175
+ payload: z.object({
176
+ messageId: z.string().min(1),
177
+ id: z.string().min(1).optional(),
178
+ contentId: z.string().min(1).optional(),
179
+ }),
180
+ }),
181
+ z.object({
182
+ eventName: z.literal("ToolCallStart"),
183
+ payload: z.object({
184
+ toolCallId: z.string().min(1),
185
+ toolCallName: z.string().min(1),
186
+ }),
187
+ }),
188
+ z.object({
189
+ eventName: z.literal("ToolCallArgs"),
190
+ payload: z.object({
191
+ toolCallId: z.string().min(1),
192
+ delta: z.string(),
193
+ }),
194
+ }),
195
+ z.object({
196
+ eventName: z.literal("ToolCallChunk"),
197
+ payload: z.object({
198
+ toolCallId: z.string().min(1),
199
+ delta: z.string(),
200
+ }),
201
+ }),
202
+ z.object({
203
+ eventName: z.literal("ToolCallEnd"),
204
+ payload: z.object({
205
+ toolCallId: z.string().min(1),
206
+ }),
207
+ }),
208
+ z.object({
209
+ eventName: z.literal("ToolCallResult"),
210
+ payload: z.object({
211
+ messageId: z.string().min(1).optional(),
212
+ toolCallId: z.string().min(1),
213
+ content: z.unknown().optional(),
214
+ result: z.unknown().optional(),
215
+ role: z.literal("tool").optional(),
216
+ isError: z.boolean().optional(),
217
+ }),
218
+ }),
219
+ z.object({
220
+ eventName: z.literal("StateSnapshot"),
221
+ payload: z.object({
222
+ snapshot: z.record(z.string(), z.unknown()),
223
+ }),
224
+ }),
225
+ z.object({
226
+ eventName: z.literal("MessagesSnapshot"),
227
+ payload: z.object({
228
+ messages: z.array(AgUiSnapshotMessageSchema),
229
+ }),
230
+ }),
231
+ z.object({
232
+ eventName: z.literal("ReasoningMessageStart"),
233
+ payload: z.object({
234
+ id: z.string().optional(),
235
+ messageId: z.string().min(1).optional(),
236
+ role: z.string().optional(),
237
+ }),
238
+ }),
239
+ z.object({
240
+ eventName: z.literal("ReasoningMessageContent"),
241
+ payload: z.object({
242
+ id: z.string().optional(),
243
+ messageId: z.string().min(1).optional(),
244
+ delta: z.string(),
245
+ }),
246
+ }),
247
+ z.object({
248
+ eventName: z.literal("ReasoningMessageEnd"),
249
+ payload: z.object({
250
+ id: z.string().optional(),
251
+ messageId: z.string().min(1).optional(),
252
+ }),
253
+ }),
254
+ z.object({
255
+ eventName: z.literal("StateDelta"),
256
+ payload: z.object({
257
+ delta: z.union([
258
+ z.record(z.string(), z.unknown()),
259
+ z.array(
260
+ z.object({
261
+ op: z.enum(["add", "remove", "replace", "move", "copy", "test"]),
262
+ path: z.string().min(1),
263
+ from: z.string().min(1).optional(),
264
+ value: z.unknown().optional(),
265
+ }),
266
+ ),
267
+ ]),
268
+ }),
269
+ }),
270
+ z.object({
271
+ eventName: z.literal("RunFinished"),
272
+ payload: z.object({
273
+ metadata: AgUiRunFinishedMetadataSchema.optional(),
274
+ }),
275
+ }),
276
+ z.object({
277
+ eventName: z.literal("RunError"),
278
+ payload: z.object({
279
+ code: z.string().optional(),
280
+ message: z.string().optional(),
281
+ }),
282
+ }),
283
+ ]);
284
+
285
+ export type AgUiRunFinishedMetadata = z.infer<typeof AgUiRunFinishedMetadataSchema>;
286
+ export type AgUiSnapshotMessage = z.infer<typeof AgUiSnapshotMessageSchema>;
287
+ export type AgUiWireEventName = z.infer<typeof AgUiWireEventNameSchema>;
288
+ export type AgUiWireEvent = z.infer<typeof AgUiWireEventSchema>;
289
+
290
+ function isRecord(value: unknown): value is Record<string, unknown> {
291
+ return typeof value === "object" && value !== null && !Array.isArray(value);
292
+ }
293
+
294
+ function normalizeNewlines(value: string): string {
295
+ return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
296
+ }
297
+
298
+ function toRenderableCustomChunk(value: unknown): ParsedRenderableCustomChunk | null {
299
+ if (!isRecord(value) || typeof value.type !== "string") {
300
+ return null;
301
+ }
302
+
303
+ if (value.type === "source-url" && typeof value.url === "string") {
304
+ return {
305
+ type: "source-url",
306
+ sourceId: typeof value.sourceId === "string" && value.sourceId.length > 0
307
+ ? value.sourceId
308
+ : value.url,
309
+ url: value.url,
310
+ ...(typeof value.title === "string" ? { title: value.title } : {}),
311
+ };
312
+ }
313
+
314
+ if (
315
+ value.type === "source-document" &&
316
+ typeof value.sourceId === "string" &&
317
+ typeof value.mediaType === "string" &&
318
+ typeof value.title === "string"
319
+ ) {
320
+ return {
321
+ type: "source-document",
322
+ sourceId: value.sourceId,
323
+ mediaType: value.mediaType,
324
+ title: value.title,
325
+ ...(typeof value.filename === "string" ? { filename: value.filename } : {}),
326
+ };
327
+ }
328
+
329
+ if (
330
+ value.type === "file" && typeof value.url === "string" && typeof value.mediaType === "string"
331
+ ) {
332
+ return {
333
+ type: "file",
334
+ url: value.url,
335
+ mediaType: value.mediaType,
336
+ ...(typeof value.filename === "string" ? { filename: value.filename } : {}),
337
+ };
338
+ }
339
+
340
+ return null;
341
+ }
342
+
343
+ function parseSerializedToolResult(value: unknown): unknown {
344
+ if (typeof value !== "string") {
345
+ return value;
346
+ }
347
+
348
+ const trimmed = value.trim();
349
+ if (
350
+ !trimmed.startsWith("{") &&
351
+ !trimmed.startsWith("[") &&
352
+ trimmed !== "null" &&
353
+ trimmed !== "true" &&
354
+ trimmed !== "false" &&
355
+ !/^[-]?\d+(\.\d+)?$/.test(trimmed)
356
+ ) {
357
+ return value;
358
+ }
359
+
360
+ try {
361
+ return JSON.parse(trimmed);
362
+ } catch {
363
+ return value;
364
+ }
365
+ }
366
+
367
+ function formatToolErrorText(result: unknown): string {
368
+ if (typeof result === "string" && result.length > 0) {
369
+ return result;
370
+ }
371
+
372
+ if (isRecord(result)) {
373
+ if (typeof result.error === "string" && result.error.length > 0) {
374
+ return result.error;
375
+ }
376
+
377
+ if (typeof result.message === "string" && result.message.length > 0) {
378
+ return result.message;
379
+ }
380
+ }
381
+
382
+ return JSON.stringify(result ?? { error: "Tool execution failed" });
383
+ }
384
+
385
+ function mapFinishReason(reason: string | undefined): ChatFinishReason | undefined {
386
+ if (!reason) return undefined;
387
+
388
+ switch (reason.trim().toLowerCase()) {
389
+ case "stop":
390
+ case "end_turn":
391
+ case "stop_sequence":
392
+ return "stop";
393
+ case "length":
394
+ case "max_tokens":
395
+ return "length";
396
+ case "tool_calls":
397
+ case "tool_use":
398
+ return "tool-calls";
399
+ case "content_filter":
400
+ case "content-filter":
401
+ return "content-filter";
402
+ case "error":
403
+ return "error";
404
+ default:
405
+ return "other";
406
+ }
407
+ }
408
+
409
+ function getReasoningPartId(
410
+ state: AgUiChatEventDecoderState,
411
+ payload: { id?: string; messageId?: string },
412
+ phase: "start" | "content" | "end",
413
+ ): string {
414
+ if (typeof payload.id === "string" && payload.id.length > 0) {
415
+ return payload.id;
416
+ }
417
+
418
+ if (typeof payload.messageId === "string" && payload.messageId.length > 0) {
419
+ return `agui-reasoning:${payload.messageId}`;
420
+ }
421
+
422
+ if (state.activeFallbackReasoningPartId) {
423
+ const fallbackId = state.activeFallbackReasoningPartId;
424
+ if (phase === "end") {
425
+ state.activeFallbackReasoningPartId = null;
426
+ }
427
+ return fallbackId;
428
+ }
429
+
430
+ state.reasoningFallbackIndex += 1;
431
+ const fallbackId = `agui-reasoning:${state.reasoningFallbackIndex}`;
432
+ if (phase !== "end") {
433
+ state.activeFallbackReasoningPartId = fallbackId;
434
+ }
435
+ return fallbackId;
436
+ }
437
+
438
+ function splitSseFrames(value: string): { frames: string[]; remainder: string } {
439
+ const blocks = value.split("\n\n");
440
+ return {
441
+ frames: blocks.slice(0, -1),
442
+ remainder: blocks.at(-1) ?? "",
443
+ };
444
+ }
445
+
446
+ function isCommentOnlySseFrame(raw: string): boolean {
447
+ return raw
448
+ .split("\n")
449
+ .every((line) => line.trim().length === 0 || line.trimStart().startsWith(":"));
450
+ }
451
+
452
+ function parseAgUiWireEvent(frame: ParsedSseEvent): AgUiWireEvent | null {
453
+ if (frame.data === "[DONE]" || !frame.event || !frame.data) {
454
+ return null;
455
+ }
456
+
457
+ const eventName = AgUiWireEventNameSchema.safeParse(frame.event);
458
+ if (!eventName.success) {
459
+ return null;
460
+ }
461
+
462
+ let payload: unknown;
463
+ try {
464
+ payload = JSON.parse(frame.data);
465
+ } catch {
466
+ return null;
467
+ }
468
+
469
+ if (!isRecord(payload)) {
470
+ return null;
471
+ }
472
+
473
+ const parsed = AgUiWireEventSchema.safeParse({
474
+ eventName: eventName.data,
475
+ payload,
476
+ });
477
+
478
+ return parsed.success ? parsed.data : null;
479
+ }
480
+
481
+ function mapWireEventToChatEvents(
482
+ state: AgUiChatEventDecoderState,
483
+ wireEvent: AgUiWireEvent,
484
+ ): ChatStreamEvent[] {
485
+ switch (wireEvent.eventName) {
486
+ case "RunStarted":
487
+ return [{
488
+ type: "start",
489
+ messageMetadata: wireEvent.payload,
490
+ }];
491
+
492
+ case "TextMessageStart":
493
+ return [{
494
+ type: "text-start",
495
+ id: wireEvent.payload.messageId,
496
+ }];
497
+
498
+ case "TextMessageContent":
499
+ return [{
500
+ type: "text-delta",
501
+ id: wireEvent.payload.messageId,
502
+ delta: wireEvent.payload.delta,
503
+ }];
504
+
505
+ case "TextMessageEnd":
506
+ return [{
507
+ type: "text-end",
508
+ id: wireEvent.payload.messageId,
509
+ }];
510
+
511
+ case "ReasoningMessageStart":
512
+ return [{
513
+ type: "reasoning-start",
514
+ id: getReasoningPartId(state, wireEvent.payload, "start"),
515
+ }];
516
+
517
+ case "ReasoningMessageContent":
518
+ return [{
519
+ type: "reasoning-delta",
520
+ id: getReasoningPartId(state, wireEvent.payload, "content"),
521
+ delta: wireEvent.payload.delta,
522
+ }];
523
+
524
+ case "ReasoningMessageEnd":
525
+ return [{
526
+ type: "reasoning-end",
527
+ id: getReasoningPartId(state, wireEvent.payload, "end"),
528
+ }];
529
+
530
+ case "ToolCallStart":
531
+ state.toolCalls.set(wireEvent.payload.toolCallId, {
532
+ toolName: wireEvent.payload.toolCallName,
533
+ argsText: "",
534
+ });
535
+ return [{
536
+ type: "tool-input-start",
537
+ toolCallId: wireEvent.payload.toolCallId,
538
+ toolName: wireEvent.payload.toolCallName,
539
+ providerExecuted: true,
540
+ }];
541
+
542
+ case "ToolCallArgs":
543
+ case "ToolCallChunk": {
544
+ const toolCall = state.toolCalls.get(wireEvent.payload.toolCallId);
545
+ if (!toolCall) {
546
+ return [];
547
+ }
548
+
549
+ toolCall.argsText = mergeToolInputDelta(toolCall.argsText, wireEvent.payload.delta);
550
+ return [{
551
+ type: "tool-input-delta",
552
+ toolCallId: wireEvent.payload.toolCallId,
553
+ inputTextDelta: wireEvent.payload.delta,
554
+ }];
555
+ }
556
+
557
+ case "ToolCallEnd": {
558
+ const toolCall = state.toolCalls.get(wireEvent.payload.toolCallId);
559
+ if (!toolCall) {
560
+ return [];
561
+ }
562
+
563
+ return [{
564
+ type: "tool-input-available",
565
+ toolCallId: wireEvent.payload.toolCallId,
566
+ toolName: toolCall.toolName,
567
+ input: parseToolInputObject(toolCall.argsText),
568
+ providerExecuted: true,
569
+ }];
570
+ }
571
+
572
+ case "ToolCallResult": {
573
+ const toolCall = state.toolCalls.get(wireEvent.payload.toolCallId);
574
+ const parsedResult = parseSerializedToolResult(
575
+ wireEvent.payload.content ?? wireEvent.payload.result,
576
+ );
577
+
578
+ if (wireEvent.payload.isError) {
579
+ return [{
580
+ type: "tool-output-error",
581
+ toolCallId: wireEvent.payload.toolCallId,
582
+ errorText: formatToolErrorText(parsedResult),
583
+ providerExecuted: true,
584
+ }];
585
+ }
586
+
587
+ const events: ChatStreamEvent[] = [];
588
+ if (!toolCall) {
589
+ events.push({
590
+ type: "tool-input-available",
591
+ toolCallId: wireEvent.payload.toolCallId,
592
+ toolName: "tool",
593
+ input: {},
594
+ dynamic: true,
595
+ providerExecuted: true,
596
+ });
597
+ }
598
+
599
+ events.push({
600
+ type: "tool-output-available",
601
+ toolCallId: wireEvent.payload.toolCallId,
602
+ output: parsedResult,
603
+ providerExecuted: true,
604
+ });
605
+ return events;
606
+ }
607
+
608
+ case "StateSnapshot":
609
+ return [{ type: "data-state-snapshot", data: wireEvent.payload.snapshot }];
610
+
611
+ case "StateDelta":
612
+ return [{
613
+ type: "data-state-delta",
614
+ data: wireEvent.payload.delta as Record<string, unknown> | JsonPatchOperation[],
615
+ }];
616
+
617
+ case "MessagesSnapshot":
618
+ return [{ type: "data-messages-snapshot", data: wireEvent.payload.messages }];
619
+
620
+ case "Custom": {
621
+ const renderableChunk = toRenderableCustomChunk(wireEvent.payload.value);
622
+ if (renderableChunk) {
623
+ return [renderableChunk];
624
+ }
625
+
626
+ return [{
627
+ type: `data-${wireEvent.payload.name}`,
628
+ data: wireEvent.payload.value,
629
+ }];
630
+ }
631
+
632
+ case "RunFinished":
633
+ return [{
634
+ type: "finish",
635
+ ...(mapFinishReason(wireEvent.payload.metadata?.finishReason)
636
+ ? { finishReason: mapFinishReason(wireEvent.payload.metadata?.finishReason) }
637
+ : {}),
638
+ }];
639
+
640
+ case "RunError":
641
+ if (wireEvent.payload.code === "CANCELLED") {
642
+ return [{ type: "abort" }];
643
+ }
644
+
645
+ return [{
646
+ type: "error",
647
+ errorText: wireEvent.payload.message?.length
648
+ ? wireEvent.payload.message
649
+ : "Conversation agent run failed",
650
+ }];
651
+ }
652
+ }
653
+
654
+ export function parseSseEvent(raw: string): ParsedSseEvent {
655
+ let id: number | null = null;
656
+ let event: string | null = null;
657
+ const dataLines: string[] = [];
658
+
659
+ for (const line of raw.split("\n")) {
660
+ if (!line || line.startsWith(":")) {
661
+ continue;
662
+ }
663
+
664
+ if (line.startsWith("id:")) {
665
+ const parsed = Number(line.slice(3).trim());
666
+ if (Number.isFinite(parsed)) {
667
+ id = parsed;
668
+ }
669
+ continue;
670
+ }
671
+
672
+ if (line.startsWith("event:")) {
673
+ const value = line.slice(6).trim();
674
+ event = value.length > 0 ? value : null;
675
+ continue;
676
+ }
677
+
678
+ if (line.startsWith("data:")) {
679
+ const value = line.slice(5);
680
+ dataLines.push(value.startsWith(" ") ? value.slice(1) : value);
681
+ }
682
+ }
683
+
684
+ return { id, event, data: dataLines.join("\n") };
685
+ }
686
+
687
+ export function createAgUiChatEventDecoderState(
688
+ input: {
689
+ lastEventId?: number;
690
+ } = {},
691
+ ): AgUiChatEventDecoderState {
692
+ return {
693
+ remainder: "",
694
+ lastEventId: input.lastEventId ?? -1,
695
+ toolCalls: new Map<string, ToolCallState>(),
696
+ reasoningFallbackIndex: 0,
697
+ activeFallbackReasoningPartId: null,
698
+ };
699
+ }
700
+
701
+ export function decodeAgUiSseChunk(
702
+ state: AgUiChatEventDecoderState,
703
+ chunk: string,
704
+ ): AgUiDecodedChunk {
705
+ const normalized = `${state.remainder}${normalizeNewlines(chunk)}`;
706
+ const { frames, remainder } = splitSseFrames(normalized);
707
+ state.remainder = remainder;
708
+
709
+ const events: AgUiDecodedEvent[] = [];
710
+
711
+ for (const rawFrame of frames) {
712
+ if (isCommentOnlySseFrame(rawFrame)) {
713
+ continue;
714
+ }
715
+
716
+ const frame = parseSseEvent(rawFrame);
717
+ if (frame.id !== null) {
718
+ if (frame.id <= state.lastEventId) {
719
+ continue;
720
+ }
721
+ state.lastEventId = frame.id;
722
+ }
723
+
724
+ const wireEvent = parseAgUiWireEvent(frame);
725
+ if (!wireEvent) {
726
+ continue;
727
+ }
728
+
729
+ events.push({
730
+ eventId: frame.id,
731
+ wireEvent,
732
+ chatEvents: mapWireEventToChatEvents(state, wireEvent),
733
+ });
734
+ }
735
+
736
+ return {
737
+ events,
738
+ remainder: state.remainder,
739
+ };
740
+ }
741
+
742
+ export function flushAgUiSseChunk(state: AgUiChatEventDecoderState): AgUiDecodedChunk {
743
+ if (state.remainder.length === 0) {
744
+ return { events: [], remainder: "" };
745
+ }
746
+
747
+ const flushed = decodeAgUiSseChunk(state, "\n\n");
748
+ state.remainder = "";
749
+ return {
750
+ events: flushed.events,
751
+ remainder: "",
752
+ };
753
+ }