@varo-ui/ai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +249 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +984 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +52 -0
- package/src/agent-stream.ts +284 -0
- package/src/event-channel.ts +49 -0
- package/src/event-parser.ts +159 -0
- package/src/index.ts +8 -0
- package/src/markdown-view.ts +227 -0
- package/src/markdown.ts +58 -0
- package/src/sse.ts +161 -0
- package/src/text-stream.ts +202 -0
- package/src/type-guards.ts +3 -0
- package/src/types.ts +222 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
import { createSmoothMarkdownStream } from "markstream-core";
|
|
2
|
+
import { getMarkdown, isUnsafeHtmlUrl, parseMarkdownToStructure } from "stream-markdown-parser";
|
|
3
|
+
//#region src/text-stream.ts
|
|
4
|
+
function splitGraphemes(value) {
|
|
5
|
+
const intlRuntime = Intl;
|
|
6
|
+
if (typeof intlRuntime !== "object" || intlRuntime === null || !("Segmenter" in intlRuntime) || typeof intlRuntime.Segmenter !== "function") return Array.from(value);
|
|
7
|
+
const Segmenter = intlRuntime.Segmenter;
|
|
8
|
+
return Array.from(new Segmenter(void 0, { granularity: "grapheme" }).segment(value), (item) => item.segment);
|
|
9
|
+
}
|
|
10
|
+
function clamp(value, min, max) {
|
|
11
|
+
return Math.min(max, Math.max(min, value));
|
|
12
|
+
}
|
|
13
|
+
function createTimerTextStream(options = {}) {
|
|
14
|
+
const minCharsPerSecond = Math.max(1, options.minCharsPerSecond ?? 40);
|
|
15
|
+
const maxCharsPerSecond = Math.max(minCharsPerSecond, options.maxCharsPerSecond ?? 800);
|
|
16
|
+
const targetLatencyMs = Math.max(50, options.targetLatencyMs ?? 700);
|
|
17
|
+
const maxCommitFps = Math.max(1, Math.min(30, options.maxCommitFps ?? 20));
|
|
18
|
+
const maxCharsPerCommit = Math.max(1, options.maxCharsPerCommit ?? 64);
|
|
19
|
+
const catchUpThreshold = Math.max(1, options.catchUpThreshold ?? 320);
|
|
20
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
21
|
+
const pending = [];
|
|
22
|
+
let pendingOffset = 0;
|
|
23
|
+
let source = "";
|
|
24
|
+
let visible = "";
|
|
25
|
+
let done = false;
|
|
26
|
+
let paused = false;
|
|
27
|
+
let destroyed = false;
|
|
28
|
+
let timer;
|
|
29
|
+
let lastTick = Date.now();
|
|
30
|
+
let budget = 0;
|
|
31
|
+
function pendingCount() {
|
|
32
|
+
return pending.length - pendingOffset;
|
|
33
|
+
}
|
|
34
|
+
function snapshot() {
|
|
35
|
+
const pendingChars = pendingCount();
|
|
36
|
+
return {
|
|
37
|
+
caughtUp: pendingChars === 0,
|
|
38
|
+
done,
|
|
39
|
+
final: done && pendingChars === 0,
|
|
40
|
+
paused,
|
|
41
|
+
pendingChars,
|
|
42
|
+
source,
|
|
43
|
+
visible
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function emit() {
|
|
47
|
+
listeners.forEach((listener) => listener());
|
|
48
|
+
}
|
|
49
|
+
function compactPending() {
|
|
50
|
+
if (pendingOffset < 1024 || pendingOffset * 2 < pending.length) return;
|
|
51
|
+
pending.splice(0, pendingOffset);
|
|
52
|
+
pendingOffset = 0;
|
|
53
|
+
}
|
|
54
|
+
function schedule() {
|
|
55
|
+
if (destroyed || paused || timer || pendingCount() === 0) return;
|
|
56
|
+
timer = setTimeout(tick, Math.ceil(1e3 / maxCommitFps));
|
|
57
|
+
}
|
|
58
|
+
function tick() {
|
|
59
|
+
timer = void 0;
|
|
60
|
+
if (destroyed || paused) return;
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
const deltaMs = Math.max(1, now - lastTick);
|
|
63
|
+
lastTick = now;
|
|
64
|
+
const backlog = pendingCount();
|
|
65
|
+
if (backlog === 0) {
|
|
66
|
+
emit();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const cps = clamp(backlog * 1e3 / targetLatencyMs * (backlog >= catchUpThreshold ? 1.8 : 1), minCharsPerSecond, maxCharsPerSecond);
|
|
70
|
+
budget += cps * deltaMs / 1e3;
|
|
71
|
+
const commitCount = Math.min(backlog, maxCharsPerCommit, Math.max(1, Math.floor(budget)));
|
|
72
|
+
budget = Math.max(0, budget - commitCount);
|
|
73
|
+
visible += pending.slice(pendingOffset, pendingOffset + commitCount).join("");
|
|
74
|
+
pendingOffset += commitCount;
|
|
75
|
+
compactPending();
|
|
76
|
+
emit();
|
|
77
|
+
schedule();
|
|
78
|
+
}
|
|
79
|
+
function cancelTimer() {
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
timer = void 0;
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
destroy() {
|
|
85
|
+
if (destroyed) return;
|
|
86
|
+
destroyed = true;
|
|
87
|
+
cancelTimer();
|
|
88
|
+
pending.length = 0;
|
|
89
|
+
listeners.clear();
|
|
90
|
+
},
|
|
91
|
+
enqueue(chunk) {
|
|
92
|
+
if (destroyed || !chunk) return;
|
|
93
|
+
if (done) done = false;
|
|
94
|
+
source += chunk;
|
|
95
|
+
pending.push(...splitGraphemes(chunk));
|
|
96
|
+
lastTick = Date.now();
|
|
97
|
+
emit();
|
|
98
|
+
schedule();
|
|
99
|
+
},
|
|
100
|
+
finish(finishOptions = {}) {
|
|
101
|
+
if (destroyed) return;
|
|
102
|
+
done = true;
|
|
103
|
+
if (finishOptions.flush) {
|
|
104
|
+
visible = source;
|
|
105
|
+
pending.length = 0;
|
|
106
|
+
pendingOffset = 0;
|
|
107
|
+
cancelTimer();
|
|
108
|
+
}
|
|
109
|
+
emit();
|
|
110
|
+
schedule();
|
|
111
|
+
},
|
|
112
|
+
flush() {
|
|
113
|
+
if (destroyed) return;
|
|
114
|
+
visible = source;
|
|
115
|
+
pending.length = 0;
|
|
116
|
+
pendingOffset = 0;
|
|
117
|
+
budget = 0;
|
|
118
|
+
cancelTimer();
|
|
119
|
+
emit();
|
|
120
|
+
},
|
|
121
|
+
getSnapshot: snapshot,
|
|
122
|
+
pause() {
|
|
123
|
+
if (destroyed || paused) return;
|
|
124
|
+
paused = true;
|
|
125
|
+
cancelTimer();
|
|
126
|
+
emit();
|
|
127
|
+
},
|
|
128
|
+
reset(content = "") {
|
|
129
|
+
cancelTimer();
|
|
130
|
+
source = content;
|
|
131
|
+
visible = content;
|
|
132
|
+
pending.length = 0;
|
|
133
|
+
pendingOffset = 0;
|
|
134
|
+
done = false;
|
|
135
|
+
paused = false;
|
|
136
|
+
budget = 0;
|
|
137
|
+
lastTick = Date.now();
|
|
138
|
+
emit();
|
|
139
|
+
},
|
|
140
|
+
resume() {
|
|
141
|
+
if (destroyed || !paused) return;
|
|
142
|
+
paused = false;
|
|
143
|
+
lastTick = Date.now();
|
|
144
|
+
emit();
|
|
145
|
+
schedule();
|
|
146
|
+
},
|
|
147
|
+
subscribe(listener) {
|
|
148
|
+
if (destroyed) return () => {};
|
|
149
|
+
listeners.add(listener);
|
|
150
|
+
return () => listeners.delete(listener);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function createTextStream(options = {}) {
|
|
155
|
+
if (typeof requestAnimationFrame !== "function" || typeof cancelAnimationFrame !== "function") return createTimerTextStream(options);
|
|
156
|
+
const controller = createSmoothMarkdownStream(options);
|
|
157
|
+
return {
|
|
158
|
+
destroy: controller.destroy,
|
|
159
|
+
enqueue: controller.enqueue,
|
|
160
|
+
finish: controller.finish,
|
|
161
|
+
flush: controller.flush,
|
|
162
|
+
getSnapshot: controller.getSnapshot,
|
|
163
|
+
pause: controller.pause,
|
|
164
|
+
reset: controller.reset,
|
|
165
|
+
resume: controller.resume,
|
|
166
|
+
subscribe: controller.subscribe
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/agent-stream.ts
|
|
171
|
+
function initialSnapshot() {
|
|
172
|
+
return {
|
|
173
|
+
data: [],
|
|
174
|
+
eventCount: 0,
|
|
175
|
+
reasoning: [],
|
|
176
|
+
status: "idle",
|
|
177
|
+
tools: []
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function createAgentStreamController(options = {}) {
|
|
181
|
+
const text = createTextStream(options.text);
|
|
182
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
183
|
+
let snapshot = initialSnapshot();
|
|
184
|
+
let destroyed = false;
|
|
185
|
+
let cancelled = false;
|
|
186
|
+
let transportDone = false;
|
|
187
|
+
let connecting = false;
|
|
188
|
+
let cancelActiveConnect;
|
|
189
|
+
function emit() {
|
|
190
|
+
listeners.forEach((listener) => listener());
|
|
191
|
+
}
|
|
192
|
+
function setSnapshot(update) {
|
|
193
|
+
snapshot = {
|
|
194
|
+
...snapshot,
|
|
195
|
+
...update
|
|
196
|
+
};
|
|
197
|
+
emit();
|
|
198
|
+
}
|
|
199
|
+
function updateReasoning(id, update) {
|
|
200
|
+
setSnapshot({ reasoning: snapshot.reasoning.map((part) => part.id === id ? {
|
|
201
|
+
...part,
|
|
202
|
+
...update
|
|
203
|
+
} : part) });
|
|
204
|
+
}
|
|
205
|
+
function updateTool(id, update) {
|
|
206
|
+
setSnapshot({ tools: snapshot.tools.map((part) => part.id === id ? {
|
|
207
|
+
...part,
|
|
208
|
+
...update
|
|
209
|
+
} : part) });
|
|
210
|
+
}
|
|
211
|
+
function finalStatus() {
|
|
212
|
+
const textSnapshot = text.getSnapshot();
|
|
213
|
+
if (!transportDone || !textSnapshot.final) return;
|
|
214
|
+
setSnapshot({ status: snapshot.error ? "failed" : cancelled ? "cancelled" : "completed" });
|
|
215
|
+
}
|
|
216
|
+
const unsubscribeText = text.subscribe(() => {
|
|
217
|
+
if (destroyed || !snapshot.message) return;
|
|
218
|
+
const textSnapshot = text.getSnapshot();
|
|
219
|
+
snapshot = {
|
|
220
|
+
...snapshot,
|
|
221
|
+
message: {
|
|
222
|
+
...snapshot.message,
|
|
223
|
+
final: textSnapshot.final,
|
|
224
|
+
source: textSnapshot.source,
|
|
225
|
+
visible: textSnapshot.visible
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
emit();
|
|
229
|
+
finalStatus();
|
|
230
|
+
});
|
|
231
|
+
function push(event) {
|
|
232
|
+
if (destroyed || cancelled) return;
|
|
233
|
+
snapshot = {
|
|
234
|
+
...snapshot,
|
|
235
|
+
eventCount: snapshot.eventCount + 1
|
|
236
|
+
};
|
|
237
|
+
switch (event.type) {
|
|
238
|
+
case "message.start":
|
|
239
|
+
transportDone = false;
|
|
240
|
+
text.reset();
|
|
241
|
+
setSnapshot({
|
|
242
|
+
error: void 0,
|
|
243
|
+
message: {
|
|
244
|
+
final: false,
|
|
245
|
+
id: event.messageId,
|
|
246
|
+
role: event.role,
|
|
247
|
+
source: "",
|
|
248
|
+
visible: ""
|
|
249
|
+
},
|
|
250
|
+
status: "streaming"
|
|
251
|
+
});
|
|
252
|
+
break;
|
|
253
|
+
case "text.delta":
|
|
254
|
+
if (snapshot.message?.id === event.messageId) text.enqueue(event.delta);
|
|
255
|
+
break;
|
|
256
|
+
case "message.end":
|
|
257
|
+
if (snapshot.message?.id === event.messageId) text.finish();
|
|
258
|
+
break;
|
|
259
|
+
case "reasoning.start":
|
|
260
|
+
setSnapshot({ reasoning: [...snapshot.reasoning, {
|
|
261
|
+
content: "",
|
|
262
|
+
id: event.id,
|
|
263
|
+
status: "running",
|
|
264
|
+
title: event.title
|
|
265
|
+
}] });
|
|
266
|
+
break;
|
|
267
|
+
case "reasoning.delta": {
|
|
268
|
+
const part = snapshot.reasoning.find((item) => item.id === event.id);
|
|
269
|
+
if (part) updateReasoning(event.id, { content: `${part.content}${event.delta}` });
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
case "reasoning.end":
|
|
273
|
+
updateReasoning(event.id, {
|
|
274
|
+
durationMs: event.durationMs,
|
|
275
|
+
status: "completed"
|
|
276
|
+
});
|
|
277
|
+
break;
|
|
278
|
+
case "tool.start":
|
|
279
|
+
setSnapshot({ tools: [...snapshot.tools, {
|
|
280
|
+
id: event.id,
|
|
281
|
+
input: event.input,
|
|
282
|
+
name: event.name,
|
|
283
|
+
status: "running",
|
|
284
|
+
summary: event.summary
|
|
285
|
+
}] });
|
|
286
|
+
break;
|
|
287
|
+
case "tool.update":
|
|
288
|
+
updateTool(event.id, { summary: event.summary });
|
|
289
|
+
break;
|
|
290
|
+
case "tool.result":
|
|
291
|
+
updateTool(event.id, {
|
|
292
|
+
output: event.output,
|
|
293
|
+
status: "completed",
|
|
294
|
+
summary: event.summary
|
|
295
|
+
});
|
|
296
|
+
break;
|
|
297
|
+
case "tool.error":
|
|
298
|
+
updateTool(event.id, {
|
|
299
|
+
error: event.error,
|
|
300
|
+
status: "failed"
|
|
301
|
+
});
|
|
302
|
+
break;
|
|
303
|
+
case "approval.required":
|
|
304
|
+
setSnapshot({
|
|
305
|
+
approval: {
|
|
306
|
+
choices: event.choices ?? [],
|
|
307
|
+
description: event.description,
|
|
308
|
+
id: event.id,
|
|
309
|
+
status: "waiting",
|
|
310
|
+
title: event.title
|
|
311
|
+
},
|
|
312
|
+
status: "waiting"
|
|
313
|
+
});
|
|
314
|
+
break;
|
|
315
|
+
case "approval.resolved":
|
|
316
|
+
if (snapshot.approval?.id === event.id) setSnapshot({
|
|
317
|
+
approval: {
|
|
318
|
+
...snapshot.approval,
|
|
319
|
+
resolvedValue: event.value,
|
|
320
|
+
status: "completed"
|
|
321
|
+
},
|
|
322
|
+
status: "streaming"
|
|
323
|
+
});
|
|
324
|
+
break;
|
|
325
|
+
case "data":
|
|
326
|
+
setSnapshot({ data: [...snapshot.data, {
|
|
327
|
+
name: event.name,
|
|
328
|
+
value: event.value
|
|
329
|
+
}] });
|
|
330
|
+
break;
|
|
331
|
+
case "error":
|
|
332
|
+
transportDone = true;
|
|
333
|
+
text.finish({ flush: true });
|
|
334
|
+
setSnapshot({
|
|
335
|
+
error: event,
|
|
336
|
+
status: "failed"
|
|
337
|
+
});
|
|
338
|
+
break;
|
|
339
|
+
case "done":
|
|
340
|
+
transportDone = true;
|
|
341
|
+
text.finish();
|
|
342
|
+
setSnapshot({ usage: event.usage });
|
|
343
|
+
if (!snapshot.message) setSnapshot({ status: "completed" });
|
|
344
|
+
finalStatus();
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
async function waitForTerminal() {
|
|
349
|
+
if (snapshot.status === "completed" || snapshot.status === "failed" || snapshot.status === "cancelled") return snapshot;
|
|
350
|
+
return await new Promise((resolve) => {
|
|
351
|
+
const unsubscribe = subscribe(() => {
|
|
352
|
+
if (snapshot.status !== "completed" && snapshot.status !== "failed" && snapshot.status !== "cancelled") return;
|
|
353
|
+
unsubscribe();
|
|
354
|
+
resolve(snapshot);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
function subscribe(listener) {
|
|
359
|
+
if (destroyed) return () => {};
|
|
360
|
+
listeners.add(listener);
|
|
361
|
+
return () => listeners.delete(listener);
|
|
362
|
+
}
|
|
363
|
+
function reset() {
|
|
364
|
+
text.reset();
|
|
365
|
+
snapshot = initialSnapshot();
|
|
366
|
+
cancelled = false;
|
|
367
|
+
transportDone = false;
|
|
368
|
+
emit();
|
|
369
|
+
}
|
|
370
|
+
function cancel(reason = "Cancelled") {
|
|
371
|
+
if (destroyed || cancelled) return;
|
|
372
|
+
cancelled = true;
|
|
373
|
+
transportDone = true;
|
|
374
|
+
text.finish({ flush: true });
|
|
375
|
+
setSnapshot({
|
|
376
|
+
error: {
|
|
377
|
+
code: "cancelled",
|
|
378
|
+
message: reason,
|
|
379
|
+
retryable: true,
|
|
380
|
+
type: "error"
|
|
381
|
+
},
|
|
382
|
+
status: "cancelled"
|
|
383
|
+
});
|
|
384
|
+
cancelActiveConnect?.();
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
cancel,
|
|
388
|
+
async connect(events) {
|
|
389
|
+
if (connecting) throw new Error("Agent stream controller is already connected");
|
|
390
|
+
connecting = true;
|
|
391
|
+
reset();
|
|
392
|
+
const iterator = events[Symbol.asyncIterator]();
|
|
393
|
+
let resolveCancellation;
|
|
394
|
+
const cancellation = new Promise((resolve) => {
|
|
395
|
+
resolveCancellation = resolve;
|
|
396
|
+
});
|
|
397
|
+
cancelActiveConnect = resolveCancellation;
|
|
398
|
+
try {
|
|
399
|
+
try {
|
|
400
|
+
while (!cancelled && !destroyed) {
|
|
401
|
+
const outcome = await Promise.race([iterator.next().then((result) => ({
|
|
402
|
+
kind: "event",
|
|
403
|
+
result
|
|
404
|
+
})), cancellation.then(() => ({ kind: "cancelled" }))]);
|
|
405
|
+
if (outcome.kind === "cancelled" || outcome.result.done) break;
|
|
406
|
+
push(outcome.result.value);
|
|
407
|
+
}
|
|
408
|
+
if (!transportDone && !cancelled && !destroyed) push({ type: "done" });
|
|
409
|
+
} catch (error) {
|
|
410
|
+
push({
|
|
411
|
+
message: error instanceof Error ? error.message : String(error),
|
|
412
|
+
retryable: true,
|
|
413
|
+
type: "error"
|
|
414
|
+
});
|
|
415
|
+
} finally {
|
|
416
|
+
if (cancelled || destroyed) iterator.return?.();
|
|
417
|
+
}
|
|
418
|
+
return await waitForTerminal();
|
|
419
|
+
} finally {
|
|
420
|
+
connecting = false;
|
|
421
|
+
cancelActiveConnect = void 0;
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
destroy() {
|
|
425
|
+
if (destroyed) return;
|
|
426
|
+
cancel("Agent stream controller destroyed");
|
|
427
|
+
destroyed = true;
|
|
428
|
+
unsubscribeText();
|
|
429
|
+
text.destroy();
|
|
430
|
+
listeners.clear();
|
|
431
|
+
},
|
|
432
|
+
getSnapshot() {
|
|
433
|
+
return snapshot;
|
|
434
|
+
},
|
|
435
|
+
push,
|
|
436
|
+
reset,
|
|
437
|
+
subscribe
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region src/event-channel.ts
|
|
442
|
+
function createAgentEventChannel() {
|
|
443
|
+
const queue = [];
|
|
444
|
+
let ended = false;
|
|
445
|
+
let failure;
|
|
446
|
+
let wake;
|
|
447
|
+
async function* iterate() {
|
|
448
|
+
while (!ended || queue.length > 0) {
|
|
449
|
+
if (failure) throw failure;
|
|
450
|
+
const event = queue.shift();
|
|
451
|
+
if (event) {
|
|
452
|
+
yield event;
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
await new Promise((resolve) => {
|
|
456
|
+
wake = resolve;
|
|
457
|
+
});
|
|
458
|
+
wake = void 0;
|
|
459
|
+
}
|
|
460
|
+
if (failure) throw failure;
|
|
461
|
+
}
|
|
462
|
+
function notify() {
|
|
463
|
+
wake?.();
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
end() {
|
|
467
|
+
ended = true;
|
|
468
|
+
notify();
|
|
469
|
+
},
|
|
470
|
+
fail(error) {
|
|
471
|
+
failure = error instanceof Error ? error : new Error(String(error));
|
|
472
|
+
ended = true;
|
|
473
|
+
notify();
|
|
474
|
+
},
|
|
475
|
+
push(event) {
|
|
476
|
+
if (ended) return;
|
|
477
|
+
queue.push(event);
|
|
478
|
+
notify();
|
|
479
|
+
},
|
|
480
|
+
source: { [Symbol.asyncIterator]: iterate }
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
//#endregion
|
|
484
|
+
//#region src/type-guards.ts
|
|
485
|
+
function isUnknownRecord(value) {
|
|
486
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
487
|
+
}
|
|
488
|
+
//#endregion
|
|
489
|
+
//#region src/event-parser.ts
|
|
490
|
+
function requiredString(value, key) {
|
|
491
|
+
const field = value[key];
|
|
492
|
+
if (typeof field !== "string" || field.length === 0) throw new TypeError(`Agent stream event field "${key}" must be a non-empty string`);
|
|
493
|
+
return field;
|
|
494
|
+
}
|
|
495
|
+
function optionalString(value, key) {
|
|
496
|
+
const field = value[key];
|
|
497
|
+
if (field === void 0) return void 0;
|
|
498
|
+
if (typeof field !== "string") throw new TypeError(`Agent stream event field "${key}" must be a string`);
|
|
499
|
+
return field;
|
|
500
|
+
}
|
|
501
|
+
function optionalBoolean(value, key) {
|
|
502
|
+
const field = value[key];
|
|
503
|
+
if (field === void 0) return void 0;
|
|
504
|
+
if (typeof field !== "boolean") throw new TypeError(`Agent stream event field "${key}" must be a boolean`);
|
|
505
|
+
return field;
|
|
506
|
+
}
|
|
507
|
+
function optionalNumber(value, key) {
|
|
508
|
+
const field = value[key];
|
|
509
|
+
if (field === void 0) return void 0;
|
|
510
|
+
if (typeof field !== "number" || !Number.isFinite(field)) throw new TypeError(`Agent stream event field "${key}" must be a finite number`);
|
|
511
|
+
return field;
|
|
512
|
+
}
|
|
513
|
+
function parseChoices(value) {
|
|
514
|
+
if (value === void 0) return void 0;
|
|
515
|
+
if (!Array.isArray(value)) throw new TypeError("Agent approval choices must be an array");
|
|
516
|
+
return value.map((choice) => {
|
|
517
|
+
if (!isUnknownRecord(choice)) throw new TypeError("Agent approval choice must be an object");
|
|
518
|
+
return {
|
|
519
|
+
description: optionalString(choice, "description"),
|
|
520
|
+
disabled: optionalBoolean(choice, "disabled"),
|
|
521
|
+
label: requiredString(choice, "label"),
|
|
522
|
+
value: requiredString(choice, "value")
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
function parseAgentStreamEvent(value) {
|
|
527
|
+
if (!isUnknownRecord(value) || typeof value.type !== "string") throw new TypeError("Agent stream event must be an object with a string type");
|
|
528
|
+
switch (value.type) {
|
|
529
|
+
case "message.start": {
|
|
530
|
+
const role = requiredString(value, "role");
|
|
531
|
+
if (role !== "assistant" && role !== "system" && role !== "user") throw new TypeError(`Unsupported agent message role: ${role}`);
|
|
532
|
+
return {
|
|
533
|
+
messageId: requiredString(value, "messageId"),
|
|
534
|
+
role,
|
|
535
|
+
type: value.type
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
case "text.delta": return {
|
|
539
|
+
delta: requiredString(value, "delta"),
|
|
540
|
+
messageId: requiredString(value, "messageId"),
|
|
541
|
+
type: value.type
|
|
542
|
+
};
|
|
543
|
+
case "message.end": return {
|
|
544
|
+
messageId: requiredString(value, "messageId"),
|
|
545
|
+
type: value.type
|
|
546
|
+
};
|
|
547
|
+
case "reasoning.start": return {
|
|
548
|
+
id: requiredString(value, "id"),
|
|
549
|
+
title: requiredString(value, "title"),
|
|
550
|
+
type: value.type
|
|
551
|
+
};
|
|
552
|
+
case "reasoning.delta": return {
|
|
553
|
+
delta: requiredString(value, "delta"),
|
|
554
|
+
id: requiredString(value, "id"),
|
|
555
|
+
type: value.type
|
|
556
|
+
};
|
|
557
|
+
case "reasoning.end": return {
|
|
558
|
+
durationMs: optionalNumber(value, "durationMs"),
|
|
559
|
+
id: requiredString(value, "id"),
|
|
560
|
+
type: value.type
|
|
561
|
+
};
|
|
562
|
+
case "tool.start": return {
|
|
563
|
+
id: requiredString(value, "id"),
|
|
564
|
+
input: value.input,
|
|
565
|
+
name: requiredString(value, "name"),
|
|
566
|
+
summary: optionalString(value, "summary"),
|
|
567
|
+
type: value.type
|
|
568
|
+
};
|
|
569
|
+
case "tool.update": return {
|
|
570
|
+
id: requiredString(value, "id"),
|
|
571
|
+
summary: optionalString(value, "summary"),
|
|
572
|
+
type: value.type
|
|
573
|
+
};
|
|
574
|
+
case "tool.result": return {
|
|
575
|
+
id: requiredString(value, "id"),
|
|
576
|
+
output: value.output,
|
|
577
|
+
summary: optionalString(value, "summary"),
|
|
578
|
+
type: value.type
|
|
579
|
+
};
|
|
580
|
+
case "tool.error": return {
|
|
581
|
+
error: requiredString(value, "error"),
|
|
582
|
+
id: requiredString(value, "id"),
|
|
583
|
+
type: value.type
|
|
584
|
+
};
|
|
585
|
+
case "approval.required": return {
|
|
586
|
+
choices: parseChoices(value.choices),
|
|
587
|
+
description: optionalString(value, "description"),
|
|
588
|
+
id: requiredString(value, "id"),
|
|
589
|
+
title: requiredString(value, "title"),
|
|
590
|
+
type: value.type
|
|
591
|
+
};
|
|
592
|
+
case "approval.resolved": return {
|
|
593
|
+
id: requiredString(value, "id"),
|
|
594
|
+
type: value.type,
|
|
595
|
+
value: requiredString(value, "value")
|
|
596
|
+
};
|
|
597
|
+
case "data":
|
|
598
|
+
if (!("value" in value)) throw new TypeError("Agent data event must include a value field");
|
|
599
|
+
return {
|
|
600
|
+
name: requiredString(value, "name"),
|
|
601
|
+
type: value.type,
|
|
602
|
+
value: value.value
|
|
603
|
+
};
|
|
604
|
+
case "error": return {
|
|
605
|
+
code: optionalString(value, "code"),
|
|
606
|
+
message: requiredString(value, "message"),
|
|
607
|
+
retryable: optionalBoolean(value, "retryable"),
|
|
608
|
+
type: value.type
|
|
609
|
+
};
|
|
610
|
+
case "done": {
|
|
611
|
+
const usage = value.usage;
|
|
612
|
+
if (usage !== void 0 && !isUnknownRecord(usage)) throw new TypeError("Agent done usage must be an object");
|
|
613
|
+
return {
|
|
614
|
+
type: value.type,
|
|
615
|
+
usage: usage ? {
|
|
616
|
+
inputTokens: optionalNumber(usage, "inputTokens"),
|
|
617
|
+
outputTokens: optionalNumber(usage, "outputTokens")
|
|
618
|
+
} : void 0
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
default: throw new TypeError(`Unsupported agent stream event type: ${value.type}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
//#endregion
|
|
625
|
+
//#region src/markdown.ts
|
|
626
|
+
let parserId = 0;
|
|
627
|
+
function createStreamingMarkdownParser(options = {}) {
|
|
628
|
+
parserId += 1;
|
|
629
|
+
const validateLink = options.validateLink ?? ((url) => !isUnsafeHtmlUrl(url));
|
|
630
|
+
const markdown = getMarkdown(`varo-agent-${parserId}`, {
|
|
631
|
+
customHtmlTags: options.customHtmlTags,
|
|
632
|
+
enableMath: options.enableMath ?? true,
|
|
633
|
+
markdownItOptions: {
|
|
634
|
+
breaks: true,
|
|
635
|
+
html: false,
|
|
636
|
+
linkify: true,
|
|
637
|
+
...options.markdownItOptions,
|
|
638
|
+
validateLink
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
return {
|
|
642
|
+
parse(content, parseOptions = {}) {
|
|
643
|
+
return parseMarkdownToStructure(content, markdown, {
|
|
644
|
+
customHtmlTags: options.customHtmlTags,
|
|
645
|
+
final: parseOptions.final ?? false,
|
|
646
|
+
includeSourceMap: options.includeSourceMap ?? false,
|
|
647
|
+
reuseStableTopLevelNodes: true,
|
|
648
|
+
streamParse: "auto",
|
|
649
|
+
validateLink
|
|
650
|
+
});
|
|
651
|
+
},
|
|
652
|
+
reset() {
|
|
653
|
+
markdown.stream?.reset?.();
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
//#endregion
|
|
658
|
+
//#region src/markdown-view.ts
|
|
659
|
+
function stringValue(value, fallback = "") {
|
|
660
|
+
return typeof value === "string" ? value : fallback;
|
|
661
|
+
}
|
|
662
|
+
function booleanValue(value) {
|
|
663
|
+
return typeof value === "boolean" ? value : void 0;
|
|
664
|
+
}
|
|
665
|
+
function numberValue(value) {
|
|
666
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
667
|
+
}
|
|
668
|
+
function alignValue(value) {
|
|
669
|
+
return value === "center" || value === "left" || value === "right" ? value : void 0;
|
|
670
|
+
}
|
|
671
|
+
function nodeField(node, key) {
|
|
672
|
+
return key in node ? Reflect.get(node, key) : void 0;
|
|
673
|
+
}
|
|
674
|
+
function normalizeUnknownNode(value) {
|
|
675
|
+
if (!isUnknownRecord(value) || typeof value.type !== "string" || typeof value.raw !== "string") return void 0;
|
|
676
|
+
return normalizeMarkdownNode(value);
|
|
677
|
+
}
|
|
678
|
+
function normalizeChildren(value) {
|
|
679
|
+
if (!Array.isArray(value)) return [];
|
|
680
|
+
const result = [];
|
|
681
|
+
value.forEach((item) => {
|
|
682
|
+
const normalized = normalizeUnknownNode(item);
|
|
683
|
+
if (normalized) result.push(normalized);
|
|
684
|
+
});
|
|
685
|
+
return result;
|
|
686
|
+
}
|
|
687
|
+
function textNode(text) {
|
|
688
|
+
return {
|
|
689
|
+
kind: "text",
|
|
690
|
+
text
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function normalizeMarkdownNode(node) {
|
|
694
|
+
const fallback = stringValue(node.raw);
|
|
695
|
+
switch (node.type) {
|
|
696
|
+
case "text": return textNode(stringValue(node.content, fallback));
|
|
697
|
+
case "heading": return {
|
|
698
|
+
children: normalizeChildren(node.children),
|
|
699
|
+
kind: "heading",
|
|
700
|
+
level: numberValue(nodeField(node, "level")) ?? 2,
|
|
701
|
+
text: stringValue(nodeField(node, "text"))
|
|
702
|
+
};
|
|
703
|
+
case "paragraph":
|
|
704
|
+
case "inline": return {
|
|
705
|
+
children: normalizeChildren(node.children),
|
|
706
|
+
kind: "paragraph"
|
|
707
|
+
};
|
|
708
|
+
case "list": return {
|
|
709
|
+
children: normalizeChildren(nodeField(node, "items")),
|
|
710
|
+
kind: "list",
|
|
711
|
+
ordered: booleanValue(nodeField(node, "ordered")) ?? false,
|
|
712
|
+
start: numberValue(nodeField(node, "start"))
|
|
713
|
+
};
|
|
714
|
+
case "list_item": return {
|
|
715
|
+
children: normalizeChildren(node.children),
|
|
716
|
+
kind: "list-item"
|
|
717
|
+
};
|
|
718
|
+
case "code_block": return {
|
|
719
|
+
kind: "code-block",
|
|
720
|
+
language: stringValue(nodeField(node, "language")),
|
|
721
|
+
loading: booleanValue(node.loading),
|
|
722
|
+
text: stringValue(node.code, fallback)
|
|
723
|
+
};
|
|
724
|
+
case "inline_code": return {
|
|
725
|
+
kind: "inline-code",
|
|
726
|
+
text: stringValue(node.code, fallback)
|
|
727
|
+
};
|
|
728
|
+
case "link": return {
|
|
729
|
+
children: normalizeChildren(node.children),
|
|
730
|
+
href: stringValue(nodeField(node, "href")),
|
|
731
|
+
kind: "link",
|
|
732
|
+
text: stringValue(nodeField(node, "text")),
|
|
733
|
+
title: stringValue(nodeField(node, "title"))
|
|
734
|
+
};
|
|
735
|
+
case "image": return {
|
|
736
|
+
alt: stringValue(nodeField(node, "alt")),
|
|
737
|
+
href: stringValue(nodeField(node, "src")),
|
|
738
|
+
kind: "image",
|
|
739
|
+
title: stringValue(nodeField(node, "title"))
|
|
740
|
+
};
|
|
741
|
+
case "thematic_break": return { kind: "thematic-break" };
|
|
742
|
+
case "blockquote": return {
|
|
743
|
+
children: normalizeChildren(node.children),
|
|
744
|
+
kind: "blockquote"
|
|
745
|
+
};
|
|
746
|
+
case "table": {
|
|
747
|
+
const header = nodeField(node, "header");
|
|
748
|
+
const rows = nodeField(node, "rows");
|
|
749
|
+
return {
|
|
750
|
+
children: normalizeChildren(Array.isArray(rows) ? [header, ...rows] : [header]),
|
|
751
|
+
kind: "table"
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
case "table_row": return {
|
|
755
|
+
children: normalizeChildren(nodeField(node, "cells")),
|
|
756
|
+
kind: "table-row"
|
|
757
|
+
};
|
|
758
|
+
case "table_cell": return {
|
|
759
|
+
align: alignValue(nodeField(node, "align")),
|
|
760
|
+
children: normalizeChildren(node.children),
|
|
761
|
+
header: booleanValue(nodeField(node, "header")),
|
|
762
|
+
kind: "table-cell"
|
|
763
|
+
};
|
|
764
|
+
case "strong": return {
|
|
765
|
+
children: normalizeChildren(node.children),
|
|
766
|
+
kind: "strong"
|
|
767
|
+
};
|
|
768
|
+
case "emphasis": return {
|
|
769
|
+
children: normalizeChildren(node.children),
|
|
770
|
+
kind: "emphasis"
|
|
771
|
+
};
|
|
772
|
+
case "strikethrough": return {
|
|
773
|
+
children: normalizeChildren(node.children),
|
|
774
|
+
kind: "strikethrough"
|
|
775
|
+
};
|
|
776
|
+
case "highlight": return {
|
|
777
|
+
children: normalizeChildren(node.children),
|
|
778
|
+
kind: "highlight"
|
|
779
|
+
};
|
|
780
|
+
case "insert": return {
|
|
781
|
+
children: normalizeChildren(node.children),
|
|
782
|
+
kind: "insert"
|
|
783
|
+
};
|
|
784
|
+
case "subscript": return {
|
|
785
|
+
children: normalizeChildren(node.children),
|
|
786
|
+
kind: "subscript"
|
|
787
|
+
};
|
|
788
|
+
case "superscript": return {
|
|
789
|
+
children: normalizeChildren(node.children),
|
|
790
|
+
kind: "superscript"
|
|
791
|
+
};
|
|
792
|
+
case "checkbox":
|
|
793
|
+
case "checkbox_input": return {
|
|
794
|
+
checked: booleanValue(nodeField(node, "checked")),
|
|
795
|
+
kind: "checkbox"
|
|
796
|
+
};
|
|
797
|
+
case "emoji": return textNode(stringValue(nodeField(node, "markup"), fallback));
|
|
798
|
+
case "definition_list": return {
|
|
799
|
+
children: normalizeChildren(nodeField(node, "items")),
|
|
800
|
+
kind: "definition-list"
|
|
801
|
+
};
|
|
802
|
+
case "definition_item": return {
|
|
803
|
+
children: [{
|
|
804
|
+
children: normalizeChildren(nodeField(node, "term")),
|
|
805
|
+
header: true,
|
|
806
|
+
kind: "definition"
|
|
807
|
+
}, {
|
|
808
|
+
children: normalizeChildren(nodeField(node, "definition")),
|
|
809
|
+
kind: "definition"
|
|
810
|
+
}],
|
|
811
|
+
kind: "definition"
|
|
812
|
+
};
|
|
813
|
+
case "footnote": return {
|
|
814
|
+
children: normalizeChildren(node.children),
|
|
815
|
+
kind: "footnote",
|
|
816
|
+
title: stringValue(nodeField(node, "id"))
|
|
817
|
+
};
|
|
818
|
+
case "footnote_reference":
|
|
819
|
+
case "reference": return {
|
|
820
|
+
kind: "footnote",
|
|
821
|
+
text: stringValue(nodeField(node, "id"))
|
|
822
|
+
};
|
|
823
|
+
case "admonition": return {
|
|
824
|
+
children: normalizeChildren(node.children),
|
|
825
|
+
kind: "admonition",
|
|
826
|
+
text: stringValue(nodeField(node, "kind")),
|
|
827
|
+
title: stringValue(nodeField(node, "title"))
|
|
828
|
+
};
|
|
829
|
+
case "vmr_container": return {
|
|
830
|
+
children: normalizeChildren(node.children),
|
|
831
|
+
kind: "admonition",
|
|
832
|
+
loading: booleanValue(node.loading),
|
|
833
|
+
title: stringValue(nodeField(node, "name"))
|
|
834
|
+
};
|
|
835
|
+
case "hardbreak": return { kind: "hardbreak" };
|
|
836
|
+
case "math_inline": return {
|
|
837
|
+
kind: "math-inline",
|
|
838
|
+
text: stringValue(node.content, fallback)
|
|
839
|
+
};
|
|
840
|
+
case "math_block": return {
|
|
841
|
+
kind: "math-block",
|
|
842
|
+
text: stringValue(node.content, fallback)
|
|
843
|
+
};
|
|
844
|
+
case "html_block":
|
|
845
|
+
case "html_inline": return textNode(stringValue(node.content, fallback));
|
|
846
|
+
default: return textNode(fallback);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
function normalizeMarkdownNodes(nodes) {
|
|
850
|
+
return nodes.map(normalizeMarkdownNode);
|
|
851
|
+
}
|
|
852
|
+
//#endregion
|
|
853
|
+
//#region src/sse.ts
|
|
854
|
+
function createFallbackUtf8Decoder() {
|
|
855
|
+
let carry = /* @__PURE__ */ new Uint8Array(0);
|
|
856
|
+
return { decode(chunk, final = false) {
|
|
857
|
+
const bytes = new Uint8Array(carry.length + chunk.length);
|
|
858
|
+
bytes.set(carry);
|
|
859
|
+
bytes.set(chunk, carry.length);
|
|
860
|
+
let cursor = 0;
|
|
861
|
+
let result = "";
|
|
862
|
+
while (cursor < bytes.length) {
|
|
863
|
+
const first = bytes[cursor];
|
|
864
|
+
if (first < 128) {
|
|
865
|
+
result += String.fromCodePoint(first);
|
|
866
|
+
cursor += 1;
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
const size = first >= 240 ? 4 : first >= 224 ? 3 : first >= 192 ? 2 : 1;
|
|
870
|
+
if (size === 1) {
|
|
871
|
+
result += "�";
|
|
872
|
+
cursor += 1;
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
if (cursor + size > bytes.length) break;
|
|
876
|
+
let codePoint = first & (size === 2 ? 31 : size === 3 ? 15 : 7);
|
|
877
|
+
let valid = true;
|
|
878
|
+
for (let index = 1; index < size; index += 1) {
|
|
879
|
+
const continuation = bytes[cursor + index];
|
|
880
|
+
if ((continuation & 192) !== 128) {
|
|
881
|
+
valid = false;
|
|
882
|
+
break;
|
|
883
|
+
}
|
|
884
|
+
codePoint = codePoint << 6 | continuation & 63;
|
|
885
|
+
}
|
|
886
|
+
if (!valid || codePoint > 1114111) {
|
|
887
|
+
result += "�";
|
|
888
|
+
cursor += 1;
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
result += String.fromCodePoint(codePoint);
|
|
892
|
+
cursor += size;
|
|
893
|
+
}
|
|
894
|
+
carry = bytes.slice(cursor);
|
|
895
|
+
if (final && carry.length > 0) {
|
|
896
|
+
result += "�";
|
|
897
|
+
carry = /* @__PURE__ */ new Uint8Array(0);
|
|
898
|
+
}
|
|
899
|
+
return result;
|
|
900
|
+
} };
|
|
901
|
+
}
|
|
902
|
+
function createUtf8Decoder() {
|
|
903
|
+
if (typeof TextDecoder === "function") {
|
|
904
|
+
const decoder = new TextDecoder();
|
|
905
|
+
return { decode(chunk, final = false) {
|
|
906
|
+
return decoder.decode(chunk, { stream: !final });
|
|
907
|
+
} };
|
|
908
|
+
}
|
|
909
|
+
return createFallbackUtf8Decoder();
|
|
910
|
+
}
|
|
911
|
+
function toBytes(chunk) {
|
|
912
|
+
return chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
|
|
913
|
+
}
|
|
914
|
+
function createAgentSseEventSource() {
|
|
915
|
+
const channel = createAgentEventChannel();
|
|
916
|
+
const decoder = createUtf8Decoder();
|
|
917
|
+
const dataLines = [];
|
|
918
|
+
let textBuffer = "";
|
|
919
|
+
let ended = false;
|
|
920
|
+
function dispatch() {
|
|
921
|
+
if (dataLines.length === 0 || ended) return;
|
|
922
|
+
const payload = dataLines.join("\n");
|
|
923
|
+
dataLines.length = 0;
|
|
924
|
+
if (payload === "[DONE]") {
|
|
925
|
+
channel.push({ type: "done" });
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
try {
|
|
929
|
+
channel.push(parseAgentStreamEvent(JSON.parse(payload)));
|
|
930
|
+
} catch (error) {
|
|
931
|
+
ended = true;
|
|
932
|
+
channel.fail(error);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
function processLine(line) {
|
|
936
|
+
const normalized = line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
937
|
+
if (normalized.length === 0) {
|
|
938
|
+
dispatch();
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (normalized.startsWith(":")) return;
|
|
942
|
+
if (normalized === "data") {
|
|
943
|
+
dataLines.push("");
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
if (normalized.startsWith("data:")) {
|
|
947
|
+
const value = normalized.slice(5);
|
|
948
|
+
dataLines.push(value.startsWith(" ") ? value.slice(1) : value);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
function appendText(value) {
|
|
952
|
+
textBuffer += value;
|
|
953
|
+
let lineEnd = textBuffer.indexOf("\n");
|
|
954
|
+
while (lineEnd >= 0) {
|
|
955
|
+
processLine(textBuffer.slice(0, lineEnd));
|
|
956
|
+
textBuffer = textBuffer.slice(lineEnd + 1);
|
|
957
|
+
lineEnd = textBuffer.indexOf("\n");
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return {
|
|
961
|
+
end() {
|
|
962
|
+
if (ended) return;
|
|
963
|
+
appendText(decoder.decode(/* @__PURE__ */ new Uint8Array(0), true));
|
|
964
|
+
if (textBuffer.length > 0) processLine(textBuffer);
|
|
965
|
+
dispatch();
|
|
966
|
+
ended = true;
|
|
967
|
+
channel.end();
|
|
968
|
+
},
|
|
969
|
+
fail(error) {
|
|
970
|
+
if (ended) return;
|
|
971
|
+
ended = true;
|
|
972
|
+
channel.fail(error);
|
|
973
|
+
},
|
|
974
|
+
feed(chunk) {
|
|
975
|
+
if (ended) return;
|
|
976
|
+
appendText(typeof chunk === "string" ? chunk : decoder.decode(toBytes(chunk)));
|
|
977
|
+
},
|
|
978
|
+
source: channel.source
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
//#endregion
|
|
982
|
+
export { createAgentEventChannel, createAgentSseEventSource, createAgentStreamController, createStreamingMarkdownParser, createTextStream, normalizeMarkdownNode, normalizeMarkdownNodes, parseAgentStreamEvent };
|
|
983
|
+
|
|
984
|
+
//# sourceMappingURL=index.mjs.map
|