@agno-hq/chat-react 0.3.3 → 0.3.4

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.
Files changed (33) hide show
  1. package/README.md +46 -0
  2. package/dist/chat/index.cjs +90 -86
  3. package/dist/chat/index.d.cts +55 -43
  4. package/dist/chat/index.d.ts +55 -43
  5. package/dist/chat/index.js +2 -2
  6. package/dist/{chunk-RE7ZT73K.js → chunk-5QKU7OPE.js} +2 -2
  7. package/dist/{chunk-RE7ZT73K.js.map → chunk-5QKU7OPE.js.map} +1 -1
  8. package/dist/{chunk-6V2YIPHF.js → chunk-BCVKAMSO.js} +22 -4
  9. package/dist/chunk-BCVKAMSO.js.map +1 -0
  10. package/dist/{chunk-3IEYJIYJ.cjs → chunk-ESV52ERB.cjs} +620 -318
  11. package/dist/chunk-ESV52ERB.cjs.map +1 -0
  12. package/dist/{chunk-2WM3CCFE.cjs → chunk-HBSF434L.cjs} +2 -2
  13. package/dist/{chunk-2WM3CCFE.cjs.map → chunk-HBSF434L.cjs.map} +1 -1
  14. package/dist/{chunk-E4CFQ457.js → chunk-OGDPK4Z3.js} +586 -285
  15. package/dist/chunk-OGDPK4Z3.js.map +1 -0
  16. package/dist/{chunk-55HQJGLP.cjs → chunk-Y34YRC5T.cjs} +22 -3
  17. package/dist/chunk-Y34YRC5T.cjs.map +1 -0
  18. package/dist/{client-DUyVqxU9.d.cts → client-Dwk6ThnW.d.cts} +24 -12
  19. package/dist/{client-DUyVqxU9.d.ts → client-Dwk6ThnW.d.ts} +24 -12
  20. package/dist/core/index.cjs +23 -23
  21. package/dist/core/index.d.cts +2 -2
  22. package/dist/core/index.d.ts +2 -2
  23. package/dist/core/index.js +2 -2
  24. package/dist/index.cjs +113 -109
  25. package/dist/index.d.cts +2 -2
  26. package/dist/index.d.ts +2 -2
  27. package/dist/index.js +3 -3
  28. package/dist/styles.css +22 -15
  29. package/package.json +11 -9
  30. package/dist/chunk-3IEYJIYJ.cjs.map +0 -1
  31. package/dist/chunk-55HQJGLP.cjs.map +0 -1
  32. package/dist/chunk-6V2YIPHF.js.map +0 -1
  33. package/dist/chunk-E4CFQ457.js.map +0 -1
@@ -1,10 +1,176 @@
1
- import { AgnoClient, activityLabel, isSubRunEvent, applySubRunEvent, isStepEvent, applyStepEvent, isStartedEvent, isToolEvent, toolsFromEvent, mergeTool, isContentEvent, applyContentEvent, isReasoningStepEvent, isReasoningCompletedEvent, isFollowupsCompletedEvent, isPausedEvent, isCompletedEvent, isCancelledEvent, isErrorEvent, sessionRunsToMessages, isToolCompletedEvent } from './chunk-6V2YIPHF.js';
1
+ import { AgnoClient, activityLabel, isSubRunEvent, applySubRunEvent, isStepEvent, applyStepEvent, isStartedEvent, isToolEvent, toolsFromEvent, mergeTool, isContentEvent, applyContentEvent, isReasoningStepEvent, reasoningStepsFromEvent, isReasoningCompletedEvent, isFollowupsCompletedEvent, isPausedEvent, isCompletedEvent, isCancelledEvent, isErrorEvent, sessionRunsToMessages, isToolCompletedEvent } from './chunk-BCVKAMSO.js';
2
2
  import React8, { createContext, useMemo, useState, useRef, useEffect, useCallback, useContext, useId, isValidElement, cloneElement, useLayoutEffect, useReducer } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { createPortal } from 'react-dom';
5
- import { ChevronDown as ChevronDown$1, ArrowUp as ArrowUp$1, Paperclip as Paperclip$1, File, FileType2, FileAudio as FileAudio$1, FileVideo as FileVideo$1, Wrench as Wrench$1, BookOpen as BookOpen$1, Globe as Globe$1, Link, Brain as Brain$1, Box as Box$1, Plus as Plus$1, Check as Check$1, Copy as Copy$1, X, MemoryStick, RefreshCcw, Activity, Trash2, MessageSquare, LoaderCircle, Square } from 'lucide-react';
5
+ import { ChevronDown as ChevronDown$1, ArrowUp as ArrowUp$1, Paperclip as Paperclip$1, File, FileType2, FileAudio as FileAudio$1, FileVideo as FileVideo$1, Wrench as Wrench$1, BookOpen as BookOpen$1, Globe as Globe$1, Link as Link$1, Brain as Brain$1, Box as Box$1, Plus as Plus$1, Check as Check$1, Copy as Copy$1, X, MemoryStick, RefreshCcw, Activity, Trash2, MessageSquare, LoaderCircle, Square } from 'lucide-react';
6
6
  import { Streamdown } from 'streamdown';
7
7
 
8
+ function useRunView(initialMessages = []) {
9
+ const [view, setView] = useState({
10
+ messages: initialMessages,
11
+ events: [],
12
+ status: "idle",
13
+ activity: null,
14
+ error: null
15
+ });
16
+ const viewRef = useRef(view);
17
+ const update = useCallback((key, action) => {
18
+ const value = typeof action === "function" ? action(viewRef.current[key]) : action;
19
+ if (Object.is(value, viewRef.current[key])) return;
20
+ viewRef.current = { ...viewRef.current, [key]: value };
21
+ setView(viewRef.current);
22
+ }, []);
23
+ const setters = useMemo(() => ({
24
+ setMessages: (action) => update("messages", action),
25
+ setEvents: (action) => update("events", action),
26
+ setStatus: (action) => update("status", action),
27
+ setActivity: (action) => update("activity", action),
28
+ setError: (action) => update("error", action)
29
+ }), [update]);
30
+ return { ...view, ...setters, viewRef };
31
+ }
32
+
33
+ // src/chat/streaming/bufferTextEvents.ts
34
+ var DEFAULT_STREAMING_OPTIONS = Object.freeze({
35
+ enabled: true,
36
+ flushIntervalMs: 150,
37
+ maxBufferEvents: 100,
38
+ maxBufferChars: 16384
39
+ });
40
+ var MAX_TIMEOUT_MS = 2147483647;
41
+ var RICH_FIELDS = [
42
+ "tool",
43
+ "tools",
44
+ "response_audio",
45
+ "images",
46
+ "videos",
47
+ "audio",
48
+ "image",
49
+ "references",
50
+ "citations",
51
+ "extra_data"
52
+ ];
53
+ function isPlainText(event) {
54
+ return (event.event === "RunContent" || event.event === "TeamRunContent") && typeof event.content === "string" && event.content.length > 0 && RICH_FIELDS.every((key) => event[key] == null);
55
+ }
56
+ function isContinuationOf(previous, next) {
57
+ const keys = /* @__PURE__ */ new Set([...Object.keys(previous), ...Object.keys(next)]);
58
+ for (const key of keys) {
59
+ if (key === "content") continue;
60
+ const before = previous[key];
61
+ const after = next[key];
62
+ if (key === "event_index" && typeof before === "number" && typeof after === "number") {
63
+ if (after <= before) return false;
64
+ continue;
65
+ }
66
+ if (!Object.is(before, after)) return false;
67
+ }
68
+ return true;
69
+ }
70
+ function boundedNumber(value, fallback, min) {
71
+ return value !== void 0 && Number.isFinite(value) && value >= min ? Math.min(Math.floor(value), MAX_TIMEOUT_MS) : fallback;
72
+ }
73
+ function bufferTextEvents(deliver, options = {}) {
74
+ const defaults = DEFAULT_STREAMING_OPTIONS;
75
+ const interval = boundedNumber(
76
+ options.flushIntervalMs,
77
+ defaults.flushIntervalMs,
78
+ 0
79
+ );
80
+ const maxEvents = boundedNumber(
81
+ options.maxBufferEvents,
82
+ defaults.maxBufferEvents,
83
+ 1
84
+ );
85
+ const maxChars = boundedNumber(
86
+ options.maxBufferChars,
87
+ defaults.maxBufferChars,
88
+ 1
89
+ );
90
+ const enabled = (options.enabled ?? defaults.enabled) && interval > 0;
91
+ let events = [];
92
+ let chunks = [];
93
+ let chars = 0;
94
+ let hasText = false;
95
+ let disposed = false;
96
+ let timer;
97
+ const isHidden = () => typeof document !== "undefined" && document.visibilityState === "hidden";
98
+ const onVisibilityChange = () => {
99
+ if (isHidden()) flush();
100
+ };
101
+ const stopObserving = () => {
102
+ if (typeof document !== "undefined")
103
+ document.removeEventListener("visibilitychange", onVisibilityChange);
104
+ };
105
+ const cancelScheduled = () => {
106
+ stopObserving();
107
+ clearTimeout(timer);
108
+ timer = void 0;
109
+ };
110
+ const flush = () => {
111
+ cancelScheduled();
112
+ const batch = { events, chunks };
113
+ events = [];
114
+ chunks = [];
115
+ chars = 0;
116
+ if (!disposed && (batch.events.length || batch.chunks.length))
117
+ deliver(batch);
118
+ };
119
+ const schedule = () => {
120
+ if (timer !== void 0 || disposed) return;
121
+ if (isHidden()) return flush();
122
+ if (typeof document !== "undefined")
123
+ document.addEventListener("visibilitychange", onVisibilityChange);
124
+ timer = setTimeout(() => {
125
+ timer = void 0;
126
+ flush();
127
+ }, interval);
128
+ };
129
+ const deliverNow = (event) => {
130
+ if (!disposed) deliver({ events: [event], chunks: [event] });
131
+ };
132
+ const append = (event) => {
133
+ const last = chunks[chunks.length - 1];
134
+ if (last && isContinuationOf(last, event)) {
135
+ chunks[chunks.length - 1] = {
136
+ ...event,
137
+ content: String(last.content) + event.content
138
+ };
139
+ } else {
140
+ chunks.push(event);
141
+ }
142
+ events.push(event);
143
+ chars += String(event.content).length;
144
+ };
145
+ return {
146
+ push(event) {
147
+ if (disposed) return;
148
+ if (!enabled || !isPlainText(event)) {
149
+ flush();
150
+ hasText = false;
151
+ deliverNow(event);
152
+ return;
153
+ }
154
+ if (!hasText) {
155
+ hasText = true;
156
+ deliverNow(event);
157
+ return;
158
+ }
159
+ append(event);
160
+ if (events.length >= maxEvents || chars >= maxChars) flush();
161
+ else schedule();
162
+ },
163
+ flush,
164
+ dispose() {
165
+ disposed = true;
166
+ cancelScheduled();
167
+ events = [];
168
+ chunks = [];
169
+ }
170
+ };
171
+ }
172
+
173
+ // src/chat/useAgnoChat.ts
8
174
  var messageCounter = 0;
9
175
  var nextId = () => `m${Date.now().toString(36)}-${(messageCounter++).toString(36)}`;
10
176
  var nowSeconds = () => Math.floor(Date.now() / 1e3);
@@ -14,12 +180,20 @@ function useAgnoChat(options) {
14
180
  if (options.client) return options.client;
15
181
  return new AgnoClient({ baseUrl: options.baseUrl ?? "", headers: options.headers });
16
182
  }, [options.client, options.baseUrl, JSON.stringify(options.headers)]);
17
- const [messages, setMessages] = useState(options.initialMessages ?? []);
18
- const [events, setEvents] = useState([]);
19
- const [currentEvent, setCurrentEvent] = useState(null);
20
- const [status, setStatus] = useState("idle");
21
- const [activity, setActivity] = useState(null);
22
- const [error, setError] = useState(null);
183
+ const {
184
+ messages,
185
+ events,
186
+ status,
187
+ activity,
188
+ error,
189
+ viewRef,
190
+ setMessages,
191
+ setEvents,
192
+ setStatus,
193
+ setActivity,
194
+ setError
195
+ } = useRunView(options.initialMessages);
196
+ const currentEvent = events[events.length - 1] ?? null;
23
197
  const [sessionId, setSessionId] = useState(options.sessionId);
24
198
  const [sessions, setSessions] = useState([]);
25
199
  const [sessionsLoading, setSessionsLoading] = useState(false);
@@ -29,10 +203,14 @@ function useAgnoChat(options) {
29
203
  const backgroundRef = useRef(/* @__PURE__ */ new Map());
30
204
  const activeMsgIdRef = useRef(null);
31
205
  const runIdRef = useRef(void 0);
206
+ const streamingRef = useRef(options.streaming);
32
207
  const entityRef = useRef(entity);
33
208
  const sessionIdRef = useRef(options.sessionId);
34
209
  const pendingSessionNameRef = useRef(void 0);
35
210
  const bumpedSessionRef = useRef(void 0);
211
+ useEffect(() => {
212
+ streamingRef.current = options.streaming;
213
+ }, [options.streaming]);
36
214
  useEffect(() => {
37
215
  entityRef.current = entity;
38
216
  }, [entity]);
@@ -52,44 +230,37 @@ function useAgnoChat(options) {
52
230
  return [entry, ...rest];
53
231
  });
54
232
  }, []);
55
- const viewRef = useRef({ messages, events, status, activity, error });
56
- useEffect(() => {
57
- viewRef.current = { messages, events, status, activity, error };
58
- });
59
233
  const writeMessages = useCallback(
60
234
  (chan, fn) => {
61
235
  const park = chan?.park;
62
236
  if (park) park.messages = fn(park.messages);
63
237
  else setMessages(fn);
64
238
  },
65
- []
239
+ [setMessages]
66
240
  );
67
- const writeEvents = useCallback((chan, e) => {
68
- const park = chan?.park;
69
- if (park) park.events = [...park.events, e];
70
- else {
71
- setEvents((prev) => [...prev, e]);
72
- setCurrentEvent(e);
73
- }
74
- }, []);
241
+ const writeEvents = useCallback((chan, incoming) => {
242
+ const park = chan.park;
243
+ if (park) park.events = [...park.events, ...incoming];
244
+ else setEvents((previous) => [...previous, ...incoming]);
245
+ }, [setEvents]);
75
246
  const writeStatus = useCallback((chan, status2) => {
76
247
  const park = chan?.park;
77
248
  if (park) park.status = status2;
78
249
  else setStatus(status2);
79
- }, []);
250
+ }, [setStatus]);
80
251
  const writeActivity = useCallback((chan, activity2) => {
81
252
  const park = chan?.park;
82
253
  if (park) park.activity = activity2;
83
254
  else setActivity(activity2);
84
- }, []);
255
+ }, [setActivity]);
85
256
  const writeError = useCallback((chan, message) => {
86
257
  const park = chan?.park;
87
258
  if (park) park.error = message;
88
259
  else setError(message);
89
- }, []);
260
+ }, [setError]);
90
261
  const patchActive = useCallback(
91
262
  (chan, patch) => {
92
- const id = chan?.park ? chan.park.activeMsgId : activeMsgIdRef.current;
263
+ const id = chan ? chan.messageId : activeMsgIdRef.current;
93
264
  if (!id) return;
94
265
  writeMessages(chan, (prev) => prev.map((m) => m.id === id ? patch(m) : m));
95
266
  },
@@ -97,9 +268,6 @@ function useAgnoChat(options) {
97
268
  );
98
269
  const applyEvent = useCallback(
99
270
  (chan, e) => {
100
- writeEvents(chan, e);
101
- patchActive(chan, (m) => ({ ...m, events: [...m.events ?? [], e] }));
102
- onEvent?.(e);
103
271
  const label2 = activityLabel(e);
104
272
  if (label2) writeActivity(chan, label2);
105
273
  if (e.session_id && !chan?.park && e.session_id !== sessionIdRef.current) {
@@ -118,7 +286,7 @@ function useAgnoChat(options) {
118
286
  else runIdRef.current = e.run_id;
119
287
  }
120
288
  if (isSubRunEvent(e)) {
121
- const kind = entityRef.current?.type === "workflow" ? "executor" : "member";
289
+ const kind = (chan?.entityType ?? entityRef.current?.type) === "workflow" ? "executor" : "member";
122
290
  patchActive(chan, (m) => applySubRunEvent(m, e, kind));
123
291
  return;
124
292
  }
@@ -151,7 +319,7 @@ function useAgnoChat(options) {
151
319
  return;
152
320
  }
153
321
  if (isReasoningStepEvent(e)) {
154
- const incoming = e.reasoning_steps ?? e.extra_data?.reasoning_steps ?? [];
322
+ const incoming = reasoningStepsFromEvent(e);
155
323
  if (incoming.length) {
156
324
  patchActive(chan, (m) => ({
157
325
  ...m,
@@ -161,8 +329,8 @@ function useAgnoChat(options) {
161
329
  return;
162
330
  }
163
331
  if (isReasoningCompletedEvent(e)) {
164
- const steps = e.reasoning_steps ?? e.extra_data?.reasoning_steps;
165
- if (steps?.length) patchActive(chan, (m) => ({ ...m, reasoning_steps: steps }));
332
+ const steps = reasoningStepsFromEvent(e);
333
+ if (steps.length) patchActive(chan, (m) => ({ ...m, reasoning_steps: steps }));
166
334
  return;
167
335
  }
168
336
  if (isFollowupsCompletedEvent(e)) {
@@ -178,7 +346,7 @@ function useAgnoChat(options) {
178
346
  patchActive(chan, (m) => {
179
347
  let tool_calls = m.tool_calls ?? [];
180
348
  for (const t of pausedTools2) tool_calls = mergeTool(tool_calls, t);
181
- return { ...m, status: "paused", streaming: false, requirements, tool_calls };
349
+ return { ...m, status: "paused", streaming: false, requirements, step_requirements: e.step_requirements ?? m.step_requirements, tool_calls };
182
350
  });
183
351
  return;
184
352
  }
@@ -217,13 +385,11 @@ function useAgnoChat(options) {
217
385
  }
218
386
  },
219
387
  [
220
- onEvent,
221
388
  onSessionId,
222
389
  patchActive,
223
390
  upsertSession,
224
391
  writeActivity,
225
392
  writeError,
226
- writeEvents,
227
393
  writeStatus
228
394
  ]
229
395
  );
@@ -261,12 +427,11 @@ function useAgnoChat(options) {
261
427
  bumpedSessionRef.current = park.bumped;
262
428
  setMessages(park.messages);
263
429
  setEvents(park.events);
264
- setCurrentEvent(park.events[park.events.length - 1] ?? null);
265
430
  setStatus(park.status);
266
431
  setActivity(park.activity);
267
432
  setError(park.error);
268
433
  return true;
269
- }, []);
434
+ }, [setMessages, setEvents, setStatus, setActivity, setError]);
270
435
  const releaseCurrentRun = useCallback(() => {
271
436
  const chan = channelRef.current;
272
437
  if (!chan || chan.park) return;
@@ -282,29 +447,64 @@ function useAgnoChat(options) {
282
447
  const drive = useCallback(
283
448
  async (starter) => {
284
449
  const controller = new AbortController();
285
- const chan = { controller, park: null };
450
+ let finished = false;
451
+ const isCurrent = () => !controller.signal.aborted && (channelRef.current === chan || Boolean(chan.park && backgroundRef.current.get(chan.park.sessionId) === chan));
452
+ const chan = {
453
+ controller,
454
+ park: null,
455
+ messageId: activeMsgIdRef.current,
456
+ entityType: entityRef.current?.type,
457
+ buffer: bufferTextEvents(({ events: incoming, chunks }) => {
458
+ if (!isCurrent()) return;
459
+ if (incoming.length) {
460
+ writeEvents(chan, incoming);
461
+ patchActive(chan, (m) => ({ ...m, events: [...m.events ?? [], ...incoming] }));
462
+ }
463
+ for (const chunk of chunks) applyEvent(chan, chunk);
464
+ }, streamingRef.current)
465
+ };
466
+ controller.signal.addEventListener("abort", () => chan.buffer.dispose(), { once: true });
286
467
  channelRef.current = chan;
287
468
  abortRef.current = controller;
288
- setError(null);
289
- setStatus("streaming");
290
- await starter({
291
- signal: controller.signal,
292
- // `chan.park` is read at call time, so events follow the run when the
293
- // user navigates away mid-stream.
294
- onEvent: (e) => applyEvent(chan, e),
295
- onError: (err) => {
296
- patchActive(chan, (m) => ({ ...m, streaming: false, status: "error", error: err.message }));
297
- writeError(chan, err.message);
298
- writeStatus(chan, "error");
299
- },
300
- onComplete: () => {
301
- writeActivity(chan, null);
302
- patchActive(chan, (m) => m.streaming ? { ...m, streaming: false } : m);
303
- const park = chan.park;
304
- if (park) park.status = park.status === "streaming" ? "completed" : park.status;
305
- else setStatus((s) => s === "streaming" ? "completed" : s);
306
- }
307
- });
469
+ writeError(chan, null);
470
+ writeStatus(chan, "streaming");
471
+ const complete = () => {
472
+ if (finished || !isCurrent()) return;
473
+ chan.buffer.flush();
474
+ finished = true;
475
+ chan.buffer.dispose();
476
+ writeActivity(chan, null);
477
+ patchActive(chan, (m) => m.streaming ? { ...m, streaming: false, status: "completed" } : m);
478
+ const status2 = chan.park?.status ?? viewRef.current.status;
479
+ if (status2 === "streaming") writeStatus(chan, "completed");
480
+ };
481
+ const fail = (err) => {
482
+ if (finished || !isCurrent()) return;
483
+ chan.buffer.flush();
484
+ finished = true;
485
+ chan.buffer.dispose();
486
+ patchActive(chan, (m) => ({ ...m, streaming: false, status: "error", error: err.message }));
487
+ writeActivity(chan, null);
488
+ writeError(chan, err.message);
489
+ writeStatus(chan, "error");
490
+ };
491
+ try {
492
+ await starter({
493
+ signal: controller.signal,
494
+ onEvent: (e) => {
495
+ if (finished || !isCurrent()) return;
496
+ onEvent?.(e);
497
+ if (isCurrent()) chan.buffer.push(e);
498
+ },
499
+ onError: fail,
500
+ onComplete: complete
501
+ });
502
+ complete();
503
+ } catch (error2) {
504
+ fail(error2 instanceof Error ? error2 : new Error(String(error2)));
505
+ } finally {
506
+ chan.buffer.dispose();
507
+ }
308
508
  if (chan.park) {
309
509
  const { sessionId: sessionId2 } = chan.park;
310
510
  setBackgroundRunning((prev) => prev.filter((s) => s !== sessionId2));
@@ -313,7 +513,7 @@ function useAgnoChat(options) {
313
513
  abortRef.current = null;
314
514
  }
315
515
  },
316
- [applyEvent, patchActive, writeActivity, writeError, writeStatus]
516
+ [applyEvent, onEvent, patchActive, writeActivity, writeError, writeEvents, writeStatus]
317
517
  );
318
518
  const sendMessage = useCallback(
319
519
  async (message, sendOptions) => {
@@ -342,7 +542,6 @@ function useAgnoChat(options) {
342
542
  };
343
543
  activeMsgIdRef.current = agentMsg.id;
344
544
  setEvents([]);
345
- setCurrentEvent(null);
346
545
  setMessages((prev) => [...prev, userMsg, agentMsg]);
347
546
  await drive(
348
547
  (cb) => client.run({
@@ -356,7 +555,7 @@ function useAgnoChat(options) {
356
555
  })
357
556
  );
358
557
  },
359
- [client, drive, userId]
558
+ [client, drive, setEvents, setMessages, userId]
360
559
  );
361
560
  const continueRun = useCallback(
362
561
  async (resolution) => {
@@ -366,7 +565,7 @@ function useAgnoChat(options) {
366
565
  setError("No paused run to continue.");
367
566
  return;
368
567
  }
369
- patchActive(null, (m) => ({ ...m, streaming: true, status: "streaming", requirements: void 0 }));
568
+ patchActive(null, (m) => ({ ...m, streaming: true, status: "streaming", requirements: void 0, step_requirements: void 0 }));
370
569
  await drive(
371
570
  (cb) => client.continueRun({
372
571
  type: ent.type,
@@ -375,6 +574,7 @@ function useAgnoChat(options) {
375
574
  sessionId: sessionIdRef.current,
376
575
  userId,
377
576
  tools: resolution.tools,
577
+ requirements: resolution.requirements,
378
578
  stepRequirements: resolution.stepRequirements,
379
579
  ...cb
380
580
  })
@@ -393,8 +593,12 @@ function useAgnoChat(options) {
393
593
  const respondToConfirmation = useCallback(
394
594
  async (approve) => {
395
595
  const ent = entityRef.current;
596
+ if (ent?.type === "team" && activeMessage?.requirements?.length) {
597
+ await continueRun({ requirements: activeMessage.requirements.map((r) => ({ ...r, confirmation: approve })) });
598
+ return;
599
+ }
396
600
  if (ent?.type === "workflow") {
397
- const reqs = (activeMessage?.requirements ?? []).map((r) => ({ ...r, confirmation: approve }));
601
+ const reqs = activeMessage?.step_requirements?.length ? activeMessage.step_requirements.map((r) => ({ ...r, confirmed: approve })) : (activeMessage?.requirements ?? []).map((r) => ({ ...r, confirmation: approve }));
398
602
  await continueRun({ stepRequirements: reqs });
399
603
  return;
400
604
  }
@@ -406,6 +610,17 @@ function useAgnoChat(options) {
406
610
  const submitUserInput = useCallback(
407
611
  async (values) => {
408
612
  const ent = entityRef.current;
613
+ if (ent?.type === "team" && activeMessage?.requirements?.length) {
614
+ const requirements = activeMessage.requirements.map((r) => ({
615
+ ...r,
616
+ user_input_schema: (r.user_input_schema ?? r.tool_execution?.user_input_schema ?? []).map((f) => ({
617
+ ...f,
618
+ value: f.name in values ? values[f.name] : f.value
619
+ }))
620
+ }));
621
+ await continueRun({ requirements });
622
+ return;
623
+ }
409
624
  if (ent?.type === "workflow") {
410
625
  const reqs = (activeMessage?.requirements ?? []).map((r) => ({
411
626
  ...r,
@@ -430,15 +645,16 @@ function useAgnoChat(options) {
430
645
  [activeMessage, continueRun, pausedTools]
431
646
  );
432
647
  const cancel = useCallback(async () => {
648
+ channelRef.current?.buffer.flush();
433
649
  abortRef.current?.abort();
434
650
  channelRef.current = null;
435
651
  const ent = entityRef.current;
436
652
  const runId = runIdRef.current;
437
- setStatus("cancelled");
438
- setActivity(null);
653
+ writeStatus(null, "cancelled");
654
+ writeActivity(null, null);
439
655
  patchActive(null, (m) => m.streaming ? { ...m, streaming: false, status: "cancelled" } : m);
440
656
  if (ent && runId) await client.cancelRun(ent.type, ent.id, runId, sessionIdRef.current);
441
- }, [client, patchActive]);
657
+ }, [client, patchActive, writeActivity, writeStatus]);
442
658
  const refreshSessions = useCallback(async () => {
443
659
  const ent = entityRef.current;
444
660
  if (!ent) {
@@ -458,6 +674,14 @@ function useAgnoChat(options) {
458
674
  setSessionsLoading(false);
459
675
  }
460
676
  }, [client]);
677
+ const clearRunView = useCallback(() => {
678
+ activeMsgIdRef.current = null;
679
+ runIdRef.current = void 0;
680
+ setEvents([]);
681
+ setStatus("idle");
682
+ setActivity(null);
683
+ setError(null);
684
+ }, [setEvents, setStatus, setActivity, setError]);
461
685
  const loadSession = useCallback(
462
686
  async (id) => {
463
687
  const ent = entityRef.current;
@@ -468,13 +692,7 @@ function useAgnoChat(options) {
468
692
  setSessionId(id);
469
693
  onSessionId?.(id);
470
694
  if (resumeRun(id)) return;
471
- activeMsgIdRef.current = null;
472
- runIdRef.current = void 0;
473
- setEvents([]);
474
- setCurrentEvent(null);
475
- setStatus("idle");
476
- setActivity(null);
477
- setError(null);
695
+ clearRunView();
478
696
  try {
479
697
  const runs = await client.getSessionRuns(ent.type, id, ent.db_id);
480
698
  setMessages(sessionRunsToMessages(runs));
@@ -482,7 +700,7 @@ function useAgnoChat(options) {
482
700
  setError(err instanceof Error ? err.message : String(err));
483
701
  }
484
702
  },
485
- [client, onSessionId, releaseCurrentRun, resumeRun]
703
+ [client, clearRunView, onSessionId, releaseCurrentRun, resumeRun, setMessages]
486
704
  );
487
705
  const deleteSession = useCallback(
488
706
  async (id) => {
@@ -497,29 +715,27 @@ function useAgnoChat(options) {
497
715
  }
498
716
  setSessions((prev) => prev.filter((s) => s.session_id !== id));
499
717
  if (sessionIdRef.current === id) {
718
+ channelRef.current?.controller.abort();
719
+ channelRef.current = null;
720
+ abortRef.current = null;
721
+ clearRunView();
500
722
  sessionIdRef.current = void 0;
501
723
  setSessionId(void 0);
502
724
  setMessages([]);
503
725
  }
504
726
  }
505
727
  },
506
- [client]
728
+ [client, clearRunView, setMessages]
507
729
  );
508
730
  const reset = useCallback(() => {
509
731
  releaseCurrentRun();
510
- activeMsgIdRef.current = null;
511
- runIdRef.current = void 0;
732
+ clearRunView();
512
733
  sessionIdRef.current = void 0;
513
734
  pendingSessionNameRef.current = void 0;
514
735
  bumpedSessionRef.current = void 0;
515
736
  setMessages([]);
516
- setEvents([]);
517
- setCurrentEvent(null);
518
- setStatus("idle");
519
- setActivity(null);
520
- setError(null);
521
737
  setSessionId(void 0);
522
- }, [releaseCurrentRun]);
738
+ }, [clearRunView, releaseCurrentRun, setMessages]);
523
739
  useEffect(() => {
524
740
  const background = backgroundRef.current;
525
741
  return () => {
@@ -643,7 +859,7 @@ var FileVideo = icon(FileVideo$1);
643
859
  var Wrench = icon(Wrench$1);
644
860
  var BookOpen = icon(BookOpen$1);
645
861
  var Globe = icon(Globe$1);
646
- var LinkIcon = icon(Link);
862
+ var LinkIcon = icon(Link$1);
647
863
  var Brain = icon(Brain$1);
648
864
  var Box = icon(Box$1);
649
865
  var Plus = icon(Plus$1);
@@ -1220,6 +1436,16 @@ function Followups({
1220
1436
  }
1221
1437
  var isBoolField = (f) => f.field_type === "bool" || f.field_type === "boolean";
1222
1438
  function buildAsks(message, entityType) {
1439
+ if (entityType === "workflow" && message.step_requirements?.length) {
1440
+ return message.step_requirements.map((r) => ({
1441
+ id: r.step_id,
1442
+ name: r.step_name,
1443
+ needsConfirmation: Boolean(r.requires_confirmation) && r.confirmed == null,
1444
+ fields: [],
1445
+ stepRequirement: r,
1446
+ unsupported: !r.requires_confirmation || Boolean(r.requires_user_input || r.requires_route_selection || r.requires_output_review)
1447
+ }));
1448
+ }
1223
1449
  const fromTools = (message.tool_calls ?? []).filter((t) => t.requires_confirmation || t.requires_user_input).map((t) => ({
1224
1450
  id: t.tool_call_id ?? `${t.tool_name}`,
1225
1451
  name: t.tool_name,
@@ -1232,11 +1458,11 @@ function buildAsks(message, entityType) {
1232
1458
  id: r.id,
1233
1459
  name: r.tool_execution?.tool_name,
1234
1460
  args: r.tool_execution?.tool_args,
1235
- needsConfirmation: Boolean(r.tool_execution?.requires_confirmation) || r.confirmation == null,
1461
+ needsConfirmation: entityType === "workflow" ? Boolean(r.tool_execution?.requires_confirmation) || r.confirmation == null : Boolean(r.tool_execution?.requires_confirmation) && r.confirmation == null,
1236
1462
  fields: r.user_input_schema ?? r.tool_execution?.user_input_schema ?? [],
1237
1463
  requirement: r
1238
1464
  }));
1239
- if (entityType === "workflow") return fromReqs.length ? fromReqs : fromTools;
1465
+ if (entityType === "workflow" || entityType === "team") return fromReqs.length ? fromReqs : fromTools;
1240
1466
  return fromTools.length ? fromTools : fromReqs;
1241
1467
  }
1242
1468
  function HumanInput({
@@ -1255,11 +1481,26 @@ function HumanInput({
1255
1481
  const setValue = (id, name, value) => setValues((v) => ({ ...v, [id]: { ...v[id] ?? {}, [name]: value } }));
1256
1482
  const valueFor = (ask, field) => values[ask.id]?.[field.name] ?? field.value ?? (isBoolField(field) ? false : "");
1257
1483
  const fillFields = (ask) => ask.fields.map((f) => ({ ...f, value: valueFor(ask, f) }));
1258
- const ready = asks.every((a) => !a.needsConfirmation || choices[a.id]);
1484
+ const ready = asks.every((a) => !a.unsupported && (!a.needsConfirmation || choices[a.id]));
1259
1485
  const submit = () => {
1486
+ if (entityType === "team" && asks.every((a) => a.requirement)) {
1487
+ const requirements = asks.map((a) => ({
1488
+ ...a.requirement,
1489
+ ...a.needsConfirmation ? { confirmation: choices[a.id] === "confirm" } : {},
1490
+ ...a.fields.length ? { user_input_schema: fillFields(a) } : {},
1491
+ ...reasons[a.id] ? { confirmation_note: reasons[a.id] } : {}
1492
+ }));
1493
+ onResolve({ requirements });
1494
+ return;
1495
+ }
1260
1496
  if (entityType === "workflow") {
1261
1497
  const stepRequirements = asks.map((a) => {
1262
1498
  const approved = a.needsConfirmation ? choices[a.id] === "confirm" : true;
1499
+ if (a.stepRequirement) return {
1500
+ ...a.stepRequirement,
1501
+ confirmed: approved,
1502
+ ...reasons[a.id] ? { rejection_feedback: reasons[a.id] } : {}
1503
+ };
1263
1504
  return {
1264
1505
  id: a.id,
1265
1506
  confirmation: approved,
@@ -1272,7 +1513,7 @@ function HumanInput({
1272
1513
  return;
1273
1514
  }
1274
1515
  const tools = asks.map((a) => {
1275
- const base = a.tool ?? { tool_call_id: a.id, tool_name: a.name };
1516
+ const base = a.tool ?? a.requirement?.tool_execution ?? { tool_call_id: a.id, tool_name: a.name };
1276
1517
  const approved = a.needsConfirmation ? choices[a.id] === "confirm" : true;
1277
1518
  return {
1278
1519
  ...base,
@@ -1285,6 +1526,7 @@ function HumanInput({
1285
1526
  };
1286
1527
  return /* @__PURE__ */ jsxs("div", { className: cx("agno-hitl", className), children: [
1287
1528
  /* @__PURE__ */ jsx("div", { className: "agno-hitl__title", children: "Your input is needed" }),
1529
+ asks.some((a) => a.unsupported) && /* @__PURE__ */ jsx("div", { className: "agno-hitl__notice", role: "status", children: "This workflow needs an input type this chat does not support yet." }),
1288
1530
  asks.map((ask) => {
1289
1531
  const choice = choices[ask.id];
1290
1532
  const hasArgs = ask.args && Object.keys(ask.args).length > 0;
@@ -1529,73 +1771,6 @@ var SourcesProvider = SourcesContext.Provider;
1529
1771
  function useSources() {
1530
1772
  return useContext(SourcesContext);
1531
1773
  }
1532
- var THEMES = { light: "github-light", dark: "monokai" };
1533
- var highlighter;
1534
- var booting;
1535
- var loading = /* @__PURE__ */ new Map();
1536
- var loaded = /* @__PURE__ */ new Set();
1537
- var unsupported = /* @__PURE__ */ new Set();
1538
- async function boot() {
1539
- if (highlighter) return highlighter;
1540
- booting ?? (booting = (async () => {
1541
- const [{ createHighlighterCore }, { createJavaScriptRegexEngine }, { bundledThemes }] = await Promise.all([import('shiki/core'), import('shiki/engine/javascript'), import('shiki/themes')]);
1542
- highlighter = await createHighlighterCore({
1543
- themes: [bundledThemes[THEMES.light], bundledThemes[THEMES.dark]],
1544
- langs: [],
1545
- // No WASM: the JS engine keeps this a plain import. `forgiving` skips
1546
- // the odd grammar rule it can't translate rather than failing the block.
1547
- engine: createJavaScriptRegexEngine({ forgiving: true })
1548
- });
1549
- return highlighter;
1550
- })());
1551
- return booting;
1552
- }
1553
- function ensureLanguage(lang) {
1554
- let pending = loading.get(lang);
1555
- if (!pending) {
1556
- pending = (async () => {
1557
- const [core, { bundledLanguages }] = await Promise.all([boot(), import('shiki/langs')]);
1558
- const grammar = bundledLanguages[lang];
1559
- if (!grammar) {
1560
- unsupported.add(lang);
1561
- return;
1562
- }
1563
- await core.loadLanguage(grammar);
1564
- loaded.add(lang);
1565
- })().catch(() => {
1566
- unsupported.add(lang);
1567
- });
1568
- loading.set(lang, pending);
1569
- }
1570
- return pending;
1571
- }
1572
- function normalizeLanguage(language) {
1573
- const lang = language?.trim().toLowerCase();
1574
- return lang || void 0;
1575
- }
1576
- function useHighlight(code, language) {
1577
- const [, rerender] = useReducer((n) => n + 1, 0);
1578
- const lang = normalizeLanguage(language);
1579
- const ready = Boolean(lang && loaded.has(lang));
1580
- useEffect(() => {
1581
- if (!lang || ready || unsupported.has(lang)) return;
1582
- let cancelled = false;
1583
- void ensureLanguage(lang).then(() => {
1584
- if (!cancelled) rerender();
1585
- });
1586
- return () => {
1587
- cancelled = true;
1588
- };
1589
- }, [lang, ready]);
1590
- return useMemo(() => {
1591
- if (!lang || !ready || !highlighter) return null;
1592
- try {
1593
- return highlighter.codeToTokens(code, { lang, themes: THEMES, defaultColor: false }).tokens;
1594
- } catch {
1595
- return null;
1596
- }
1597
- }, [code, lang, ready]);
1598
- }
1599
1774
  var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
1600
1775
  var caches = /* @__PURE__ */ new WeakMap();
1601
1776
  var inflight = /* @__PURE__ */ new WeakMap();
@@ -1801,6 +1976,100 @@ function HoverPreview({
1801
1976
  }
1802
1977
  );
1803
1978
  }
1979
+ function sourceForUrl(url, sources) {
1980
+ return url ? sources.find((source) => source.url === url) : void 0;
1981
+ }
1982
+ function citationForLink(label2, href, ctx) {
1983
+ if (!/^\d+$/.test(label2.trim())) return void 0;
1984
+ return sourceForUrl(href, ctx.sources) ?? ctx.sources.find((source) => source.index === Number(label2.trim()));
1985
+ }
1986
+ function CitationMarker({
1987
+ source,
1988
+ className,
1989
+ Link: Link2
1990
+ }) {
1991
+ const props = {
1992
+ className: cx("agno-cite", className),
1993
+ href: source.url ?? `#${source.anchorId}`,
1994
+ "aria-label": `Source ${source.index}: ${source.title}`
1995
+ };
1996
+ return /* @__PURE__ */ jsx(HoverPreview, { source, className: "agno-cite__wrap", children: Link2 && source.url ? /* @__PURE__ */ jsx(Link2, { ...props, children: source.index }) : /* @__PURE__ */ jsx(
1997
+ "a",
1998
+ {
1999
+ ...props,
2000
+ target: source.url ? "_blank" : void 0,
2001
+ rel: source.url ? "noreferrer noopener" : void 0,
2002
+ children: source.index
2003
+ }
2004
+ ) });
2005
+ }
2006
+ var THEMES = { light: "github-light", dark: "monokai" };
2007
+ var highlighter;
2008
+ var booting;
2009
+ var loading = /* @__PURE__ */ new Map();
2010
+ var loaded = /* @__PURE__ */ new Set();
2011
+ var unsupported = /* @__PURE__ */ new Set();
2012
+ async function boot() {
2013
+ if (highlighter) return highlighter;
2014
+ booting ?? (booting = (async () => {
2015
+ const [{ createHighlighterCore }, { createJavaScriptRegexEngine }, { bundledThemes }] = await Promise.all([import('shiki/core'), import('shiki/engine/javascript'), import('shiki/themes')]);
2016
+ highlighter = await createHighlighterCore({
2017
+ themes: [bundledThemes[THEMES.light], bundledThemes[THEMES.dark]],
2018
+ langs: [],
2019
+ // No WASM: the JS engine keeps this a plain import. `forgiving` skips
2020
+ // the odd grammar rule it can't translate rather than failing the block.
2021
+ engine: createJavaScriptRegexEngine({ forgiving: true })
2022
+ });
2023
+ return highlighter;
2024
+ })());
2025
+ return booting;
2026
+ }
2027
+ function ensureLanguage(lang) {
2028
+ let pending = loading.get(lang);
2029
+ if (!pending) {
2030
+ pending = (async () => {
2031
+ const [core, { bundledLanguages }] = await Promise.all([boot(), import('shiki/langs')]);
2032
+ const grammar = bundledLanguages[lang];
2033
+ if (!grammar) {
2034
+ unsupported.add(lang);
2035
+ return;
2036
+ }
2037
+ await core.loadLanguage(grammar);
2038
+ loaded.add(lang);
2039
+ })().catch(() => {
2040
+ unsupported.add(lang);
2041
+ });
2042
+ loading.set(lang, pending);
2043
+ }
2044
+ return pending;
2045
+ }
2046
+ function normalizeLanguage(language) {
2047
+ const lang = language?.trim().toLowerCase();
2048
+ return lang || void 0;
2049
+ }
2050
+ function useHighlight(code, language) {
2051
+ const [, rerender] = useReducer((n) => n + 1, 0);
2052
+ const lang = normalizeLanguage(language);
2053
+ const ready = Boolean(lang && loaded.has(lang));
2054
+ useEffect(() => {
2055
+ if (!lang || ready || unsupported.has(lang)) return;
2056
+ let cancelled = false;
2057
+ void ensureLanguage(lang).then(() => {
2058
+ if (!cancelled) rerender();
2059
+ });
2060
+ return () => {
2061
+ cancelled = true;
2062
+ };
2063
+ }, [lang, ready]);
2064
+ return useMemo(() => {
2065
+ if (!lang || !ready || !highlighter) return null;
2066
+ try {
2067
+ return highlighter.codeToTokens(code, { lang, themes: THEMES, defaultColor: false }).tokens;
2068
+ } catch {
2069
+ return null;
2070
+ }
2071
+ }, [code, lang, ready]);
2072
+ }
1804
2073
  var COPIED_FOR = 1600;
1805
2074
  var CLIPBOARD_TIMEOUT = 400;
1806
2075
  async function writeClipboard(text) {
@@ -1849,58 +2118,24 @@ function CopyButton({ text, label: label2 = "Copy", size = 14, className }) {
1849
2118
  }
1850
2119
  );
1851
2120
  }
1852
- function el(tag, className) {
1853
- return function Element({ node: _node, className: _theirs, ...rest }) {
1854
- return React8.createElement(tag, { className, ...rest });
1855
- };
1856
- }
1857
- function sourceForUrl(url, sources) {
1858
- return url ? sources.find((s) => s.url === url) : void 0;
1859
- }
1860
- function citationForLink(label2, href, ctx) {
1861
- if (!/^\d+$/.test(label2.trim())) return void 0;
1862
- return sourceForUrl(href, ctx.sources) ?? ctx.sources.find((s) => s.index === Number(label2.trim()));
1863
- }
1864
- function labelOf(children) {
1865
- if (typeof children === "string") return children;
1866
- if (Array.isArray(children) && children.length === 1 && typeof children[0] === "string") {
1867
- return children[0];
1868
- }
1869
- return "";
1870
- }
1871
- function CitationMarker({
1872
- source,
1873
- className,
1874
- Link
1875
- }) {
1876
- const props = {
1877
- className: cx("agno-cite", className),
1878
- href: source.url ?? `#${source.anchorId}`,
1879
- "aria-label": `Source ${source.index}: ${source.title}`
1880
- };
1881
- return /* @__PURE__ */ jsx(HoverPreview, { source, className: "agno-cite__wrap", children: Link && source.url ? /* @__PURE__ */ jsx(Link, { ...props, children: source.index }) : /* @__PURE__ */ jsx(
1882
- "a",
1883
- {
1884
- ...props,
1885
- target: source.url ? "_blank" : void 0,
1886
- rel: source.url ? "noreferrer noopener" : void 0,
1887
- children: source.index
1888
- }
1889
- ) });
1890
- }
1891
2121
  function textOf(children) {
1892
2122
  if (typeof children === "string") return children;
1893
2123
  if (typeof children === "number") return String(children);
1894
2124
  if (Array.isArray(children)) return children.map(textOf).join("");
1895
- if (React8.isValidElement(children)) return textOf(children.props.children);
2125
+ if (React8.isValidElement(children))
2126
+ return textOf(children.props.children);
1896
2127
  return "";
1897
2128
  }
1898
2129
  function fencedCode(children) {
1899
2130
  const child = Array.isArray(children) ? children[0] : children;
1900
- if (!React8.isValidElement(child)) {
2131
+ if (!React8.isValidElement(
2132
+ child
2133
+ )) {
1901
2134
  return { code: textOf(children) };
1902
2135
  }
1903
- const language = /(?:^|\s)language-([^\s]+)/.exec(child.props.className ?? "")?.[1];
2136
+ const language = /(?:^|\s)language-([^\s]+)/.exec(
2137
+ child.props.className ?? ""
2138
+ )?.[1];
1904
2139
  return { language, code: textOf(child.props.children).replace(/\n$/, "") };
1905
2140
  }
1906
2141
  function plainLines(code) {
@@ -1909,93 +2144,159 @@ function plainLines(code) {
1909
2144
  function CodeBlock({
1910
2145
  children,
1911
2146
  copyClass,
1912
- codeCopy
2147
+ codeCopy,
2148
+ streaming
1913
2149
  }) {
1914
2150
  const { language, code } = useMemo(() => fencedCode(children), [children]);
1915
- const highlighted = useHighlight(code, language);
1916
- const lines = highlighted ?? plainLines(code);
2151
+ const highlighted = useHighlight(streaming ? "" : code, language);
2152
+ const lines = streaming ? plainLines(code) : highlighted ?? plainLines(code);
1917
2153
  const label2 = normalizeLanguage(language) ?? "text";
1918
2154
  return /* @__PURE__ */ jsxs("div", { className: "agno-md-code-block", "data-language": label2, children: [
1919
2155
  /* @__PURE__ */ jsxs("div", { className: "agno-md-code-head", children: [
1920
2156
  /* @__PURE__ */ jsx("span", { className: "agno-md-code-lang", children: label2 }),
1921
- codeCopy && /* @__PURE__ */ jsx(CopyButton, { className: cx("agno-md-copy", copyClass), text: () => code, label: "Copy code", size: 13 })
2157
+ codeCopy && /* @__PURE__ */ jsx(
2158
+ CopyButton,
2159
+ {
2160
+ className: cx("agno-md-copy", copyClass),
2161
+ text: () => code,
2162
+ label: "Copy code",
2163
+ size: 13
2164
+ }
2165
+ )
1922
2166
  ] }),
1923
- /* @__PURE__ */ jsx("pre", { className: "agno-md-pre", style: { "--agno-code-gutter": `${String(lines.length).length}ch` }, children: /* @__PURE__ */ jsx("code", { className: language ? `language-${language}` : void 0, children: lines.map((tokens, i) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
1924
- /* @__PURE__ */ jsx("span", { className: "agno-md-line", children: tokens.map((token, j) => /* @__PURE__ */ jsx("span", { style: token.htmlStyle, children: token.content }, j)) }),
1925
- i < lines.length - 1 && "\n"
1926
- ] }, i)) }) })
2167
+ /* @__PURE__ */ jsx(
2168
+ "pre",
2169
+ {
2170
+ className: "agno-md-pre",
2171
+ style: {
2172
+ "--agno-code-gutter": `${String(lines.length).length}ch`
2173
+ },
2174
+ children: /* @__PURE__ */ jsx("code", { className: language ? `language-${language}` : void 0, children: lines.map((tokens, i) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
2175
+ /* @__PURE__ */ jsx("span", { className: "agno-md-line", children: tokens.map((token, j) => /* @__PURE__ */ jsx(
2176
+ "span",
2177
+ {
2178
+ style: token.htmlStyle,
2179
+ children: token.content
2180
+ },
2181
+ j
2182
+ )) }),
2183
+ i < lines.length - 1 && "\n"
2184
+ ] }, i)) })
2185
+ }
2186
+ )
1927
2187
  ] });
1928
2188
  }
1929
- function elementsFor(ctx) {
1930
- const Link = function Link2({
2189
+ var InlineRenderContext = createContext({
2190
+ sources: [],
2191
+ canResolve: false,
2192
+ codeCopy: true
2193
+ });
2194
+ function el(tag, className) {
2195
+ return function Element({
1931
2196
  node: _node,
1932
2197
  className: _theirs,
1933
- href,
1934
- children,
1935
2198
  ...rest
1936
2199
  }) {
1937
- const cited = citationForLink(labelOf(children), href, ctx);
1938
- if (cited) return /* @__PURE__ */ jsx(CitationMarker, { source: cited, className: ctx.markerClass, Link: ctx.Link });
1939
- const link = ctx.Link && href ? /* @__PURE__ */ jsx(ctx.Link, { href, ...rest, children }) : /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noreferrer noopener", ...rest, children });
1940
- const source = sourceForUrl(href, ctx.sources);
1941
- if (!href || !/^https?:\/\//i.test(href) || !source && !ctx.canResolve) return link;
2200
+ return React8.createElement(tag, { className, ...rest });
2201
+ };
2202
+ }
2203
+ function Link({
2204
+ node: _node,
2205
+ className: _theirs,
2206
+ href,
2207
+ children,
2208
+ ...rest
2209
+ }) {
2210
+ const ctx = useContext(InlineRenderContext);
2211
+ const cited = citationForLink(textOf(children), href, ctx);
2212
+ if (cited)
1942
2213
  return /* @__PURE__ */ jsx(
1943
- HoverPreview,
2214
+ CitationMarker,
1944
2215
  {
1945
- source: source ?? {
1946
- index: 0,
1947
- anchorId: "",
1948
- kind: "url",
1949
- url: href,
1950
- title: labelOf(children) || sourceHost(href) || href
1951
- },
1952
- children: link
2216
+ source: cited,
2217
+ className: ctx.markerClass,
2218
+ Link: ctx.Link
1953
2219
  }
1954
2220
  );
1955
- };
1956
- const Code = function Code2({ node: _node, className, ...rest }) {
1957
- const fenced = typeof className === "string" && className.includes("language-");
1958
- return /* @__PURE__ */ jsx("code", { className: fenced ? className : "agno-md-code", ...rest });
1959
- };
1960
- return {
1961
- a: Link,
1962
- code: Code,
1963
- p: el("p", "agno-md-p"),
1964
- // Streamdown renders `**bold**` as a Tailwind-classed <span>, which is not
1965
- // bold anywhere Tailwind isn't. These stay real elements, styled by the
1966
- // browser and read correctly by a screen reader.
1967
- strong: el("strong"),
1968
- em: el("em"),
1969
- del: el("del"),
1970
- sub: el("sub"),
1971
- sup: el("sup"),
1972
- h1: el("h2", "agno-md-heading"),
1973
- h2: el("h3", "agno-md-heading"),
1974
- h3: el("h4", "agno-md-heading"),
1975
- h4: el("h5", "agno-md-heading"),
1976
- h5: el("h6", "agno-md-heading"),
1977
- h6: el("h6", "agno-md-heading"),
1978
- ul: el("ul", "agno-md-list"),
1979
- ol: el("ol", "agno-md-list"),
1980
- li: el("li"),
1981
- pre: function Pre({ children }) {
1982
- return /* @__PURE__ */ jsx(CodeBlock, { copyClass: ctx.copyClass, codeCopy: ctx.codeCopy, children });
1983
- },
1984
- blockquote: el("blockquote", "agno-md-quote"),
1985
- hr: el("hr", "agno-md-rule"),
1986
- table: function Table({ node: _node, className: _theirs, ...rest }) {
1987
- return /* @__PURE__ */ jsx("div", { className: "agno-md-table-wrap", children: /* @__PURE__ */ jsx("table", { className: "agno-md-table", ...rest }) });
1988
- },
1989
- thead: el("thead"),
1990
- tbody: el("tbody"),
1991
- tr: el("tr"),
1992
- th: el("th"),
1993
- td: el("td"),
1994
- img: function Image({ node: _node, className: _theirs, ...rest }) {
1995
- return /* @__PURE__ */ jsx("img", { className: "agno-md-img", ...rest });
2221
+ const link = ctx.Link && href ? /* @__PURE__ */ jsx(ctx.Link, { href, ...rest, children }) : /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noreferrer noopener", ...rest, children });
2222
+ const source = sourceForUrl(href, ctx.sources);
2223
+ if (!href || !/^https?:\/\//i.test(href) || !source && !ctx.canResolve)
2224
+ return link;
2225
+ return /* @__PURE__ */ jsx(
2226
+ HoverPreview,
2227
+ {
2228
+ source: source ?? {
2229
+ index: 0,
2230
+ anchorId: "",
2231
+ kind: "url",
2232
+ url: href,
2233
+ title: textOf(children) || sourceHost(href) || href
2234
+ },
2235
+ children: link
1996
2236
  }
1997
- };
2237
+ );
2238
+ }
2239
+ function Code({ node: _node, className, ...rest }) {
2240
+ const fenced = typeof className === "string" && className.includes("language-");
2241
+ return /* @__PURE__ */ jsx("code", { className: fenced ? className : "agno-md-code", ...rest });
1998
2242
  }
2243
+ function Pre({ children }) {
2244
+ const ctx = useContext(InlineRenderContext);
2245
+ return /* @__PURE__ */ jsx(
2246
+ CodeBlock,
2247
+ {
2248
+ copyClass: ctx.copyClass,
2249
+ codeCopy: ctx.codeCopy,
2250
+ streaming: ctx.streaming,
2251
+ children
2252
+ }
2253
+ );
2254
+ }
2255
+ function Table({ node: _node, className: _theirs, ...rest }) {
2256
+ return /* @__PURE__ */ jsx("div", { className: "agno-md-table-wrap", children: /* @__PURE__ */ jsx("table", { className: "agno-md-table", ...rest }) });
2257
+ }
2258
+ function Image({ node: _node, className: _theirs, ...rest }) {
2259
+ return /* @__PURE__ */ jsx("img", { className: "agno-md-img", ...rest });
2260
+ }
2261
+ var MARKDOWN_COMPONENTS = {
2262
+ a: Link,
2263
+ code: Code,
2264
+ p: el("p", "agno-md-p"),
2265
+ // Streamdown renders `**bold**` as a Tailwind-classed <span>, which is not
2266
+ // bold anywhere Tailwind isn't. These stay real elements, styled by the
2267
+ // browser and read correctly by a screen reader.
2268
+ strong: el("strong"),
2269
+ em: el("em"),
2270
+ del: el("del"),
2271
+ sub: el("sub"),
2272
+ sup: el("sup"),
2273
+ h1: el("h2", "agno-md-heading"),
2274
+ h2: el("h3", "agno-md-heading"),
2275
+ h3: el("h4", "agno-md-heading"),
2276
+ h4: el("h5", "agno-md-heading"),
2277
+ h5: el("h6", "agno-md-heading"),
2278
+ h6: el("h6", "agno-md-heading"),
2279
+ ul: el("ul", "agno-md-list"),
2280
+ ol: el("ol", "agno-md-list"),
2281
+ li: el("li"),
2282
+ pre: Pre,
2283
+ blockquote: el("blockquote", "agno-md-quote"),
2284
+ hr: el("hr", "agno-md-rule"),
2285
+ table: Table,
2286
+ thead: el("thead"),
2287
+ tbody: el("tbody"),
2288
+ tr: el("tr"),
2289
+ th: el("th"),
2290
+ td: el("td"),
2291
+ img: Image
2292
+ };
2293
+ var STREAMING_MOTION = {
2294
+ animation: "fadeIn",
2295
+ duration: 400,
2296
+ easing: "ease-out",
2297
+ sep: "word",
2298
+ stagger: 0
2299
+ };
1999
2300
  function Markdown({
2000
2301
  content,
2001
2302
  className,
@@ -2012,30 +2313,33 @@ function Markdown({
2012
2313
  const providerLink = useLinkComponent();
2013
2314
  const cited = sources ?? fromMessage;
2014
2315
  const copy = codeCopy ?? fromProvider ?? true;
2015
- const Link = linkComponent ?? providerLink;
2016
- const components = useMemo(
2017
- () => elementsFor({
2316
+ const Link2 = linkComponent ?? providerLink;
2317
+ const inlineContext = useMemo(
2318
+ () => ({
2018
2319
  sources: cited,
2019
2320
  canResolve,
2020
2321
  markerClass: cn.citationMarker,
2021
2322
  copyClass: cn.copyButton,
2022
2323
  codeCopy: copy,
2023
- Link
2324
+ Link: Link2,
2325
+ streaming
2024
2326
  }),
2025
- [cited, canResolve, cn.citationMarker, cn.copyButton, copy, Link]
2327
+ [cited, canResolve, cn.citationMarker, cn.copyButton, copy, Link2, streaming]
2026
2328
  );
2027
2329
  const text = useMemo(() => linkCitations(content, cited), [content, cited]);
2028
- return /* @__PURE__ */ jsx(
2330
+ return /* @__PURE__ */ jsx(InlineRenderContext.Provider, { value: inlineContext, children: /* @__PURE__ */ jsx(
2029
2331
  Streamdown,
2030
2332
  {
2031
2333
  className: cx("agno-md", className),
2032
- components,
2334
+ components: MARKDOWN_COMPONENTS,
2033
2335
  mode: streaming ? "streaming" : "static",
2034
2336
  parseIncompleteMarkdown: streaming !== false,
2337
+ animated: streaming ? STREAMING_MOTION : false,
2338
+ isAnimating: Boolean(streaming),
2035
2339
  ...options,
2036
2340
  children: text
2037
2341
  }
2038
- );
2342
+ ) });
2039
2343
  }
2040
2344
  function statusOf(tool) {
2041
2345
  if (tool.tool_call_error) return { label: "error", cls: "error" };
@@ -2157,7 +2461,7 @@ function stepsFromEvents(message, { hideReasoning, hideTools }) {
2157
2461
  const key = `reasoning:${e.run_id ?? "run"}`;
2158
2462
  const at = indexOf.get(key);
2159
2463
  const previous = at != null ? steps[at].steps : [];
2160
- const incoming = e.reasoning_steps ?? e.extra_data?.reasoning_steps ?? [];
2464
+ const incoming = reasoningStepsFromEvent(e);
2161
2465
  const completed = isReasoningCompletedEvent(e);
2162
2466
  put(key, {
2163
2467
  kind: "reasoning",
@@ -2433,7 +2737,7 @@ function SourceCard({
2433
2737
  className
2434
2738
  }) {
2435
2739
  const cn = useResolvedClassNames();
2436
- const Link = useLinkComponent();
2740
+ const Link2 = useLinkComponent();
2437
2741
  const { preview } = useLinkPreview(source.url, false);
2438
2742
  const body = /* @__PURE__ */ jsxs(Fragment, { children: [
2439
2743
  /* @__PURE__ */ jsx(
@@ -2449,8 +2753,8 @@ function SourceCard({
2449
2753
  source.url && /* @__PURE__ */ jsx(LinkIcon, { className: "agno-source__link" })
2450
2754
  ] });
2451
2755
  const classes = cx("agno-source", `agno-source--${source.kind}`, cn.sourceCard, className);
2452
- if (source.url && Link) {
2453
- return /* @__PURE__ */ jsx(Link, { id: source.anchorId, className: classes, href: source.url, title: source.url, children: body });
2756
+ if (source.url && Link2) {
2757
+ return /* @__PURE__ */ jsx(Link2, { id: source.anchorId, className: classes, href: source.url, title: source.url, children: body });
2454
2758
  }
2455
2759
  return source.url ? /* @__PURE__ */ jsx(
2456
2760
  "a",
@@ -2683,10 +2987,7 @@ function Message({
2683
2987
  classNames: cn
2684
2988
  }
2685
2989
  ),
2686
- content ? /* @__PURE__ */ jsxs("div", { className: cx("agno-msg__content", cn.messageContent), children: [
2687
- renderMarkdown ? renderMarkdown(content) : /* @__PURE__ */ jsx(Markdown, { content, className: cn.markdown, streaming: message.streaming }),
2688
- message.streaming && /* @__PURE__ */ jsx("span", { className: "agno-msg__caret", "aria-hidden": true })
2689
- ] }) : isAgent && message.streaming && hasActivity && /* @__PURE__ */ jsxs("div", { className: "agno-msg__activity", role: "status", "aria-live": "polite", children: [
2990
+ content ? /* @__PURE__ */ jsx("div", { className: cx("agno-msg__content", cn.messageContent), children: renderMarkdown ? renderMarkdown(content) : /* @__PURE__ */ jsx(Markdown, { content, className: cn.markdown, streaming: message.streaming }) }) : isAgent && message.streaming && hasActivity && /* @__PURE__ */ jsxs("div", { className: "agno-msg__activity", role: "status", "aria-live": "polite", children: [
2690
2991
  /* @__PURE__ */ jsx(GridLoader, {}),
2691
2992
  /* @__PURE__ */ jsx("span", { className: "agno-msg__activity-label", children: activity ?? "Working..." })
2692
2993
  ] }),
@@ -3208,7 +3509,7 @@ function AgnoChat(props) {
3208
3509
  };
3209
3510
  }, [client, props.entity, props.entities, props.showEntityPicker]);
3210
3511
  const entity = props.entity ?? selected;
3211
- const chat = useAgnoChat({ client, entity, userId: props.userId });
3512
+ const chat = useAgnoChat({ client, entity, userId: props.userId, streaming: props.streaming });
3212
3513
  const { refreshSessions } = chat;
3213
3514
  useEffect(() => {
3214
3515
  if (props.showSessions && entity) refreshSessions();
@@ -3520,6 +3821,6 @@ function EventLog({
3520
3821
  ] });
3521
3822
  }
3522
3823
 
3523
- export { AgnoChat, AgnoMark, ArrowUp, BehindTheScenes, BookOpen, Box, Brain, ChatBubble, ChatInput, ChatLauncher, ChatProvider, ChatWindow, Check, ChevronDown, Citations, Close, Copy, CopyButton, EntityBadge, EntitySelector, EventLog, Favicon, FileAudio, FileIcon, FilePreview, FileType, FileVideo, Followups, Globe, GridLoader, HoverPreview, HumanInput, LinkIcon, LinkPreviewCard, Markdown, MemberResponses, Memory, Message, MessageActions, MessageList, Multimedia, Paperclip, Plus, Pulse, QuickPrompts, Reasoning, Rerun, SessionList, SourceCard, SourcesProvider, Spinner, StatusIndicator, Stop, TeamGlyph, ToolCalls, Trash, WorkflowSteps, Wrench, admitFiles, behindTheScenesItems, behindTheScenesLabel, collectSources, cx, displayUrl, faviconFallbacks, faviconUrl, fileAccepted, getProviderIcon, hasBehindTheScenes, linkCitations, normalizeFollowups, quickPromptLabel, quickPromptText, sourceHost, sourcesFromMarkdown, useAgnoChat, useChatContext, useLinkComponent, useLinkPreview, useOptionalChatContext, useResolvedChat, useResolvedClassNames, useSources, withoutSourcesLine, writeClipboard };
3524
- //# sourceMappingURL=chunk-E4CFQ457.js.map
3525
- //# sourceMappingURL=chunk-E4CFQ457.js.map
3824
+ export { AgnoChat, AgnoMark, ArrowUp, BehindTheScenes, BookOpen, Box, Brain, ChatBubble, ChatInput, ChatLauncher, ChatProvider, ChatWindow, Check, ChevronDown, Citations, Close, Copy, CopyButton, DEFAULT_STREAMING_OPTIONS, EntityBadge, EntitySelector, EventLog, Favicon, FileAudio, FileIcon, FilePreview, FileType, FileVideo, Followups, Globe, GridLoader, HoverPreview, HumanInput, LinkIcon, LinkPreviewCard, Markdown, MemberResponses, Memory, Message, MessageActions, MessageList, Multimedia, Paperclip, Plus, Pulse, QuickPrompts, Reasoning, Rerun, SessionList, SourceCard, SourcesProvider, Spinner, StatusIndicator, Stop, TeamGlyph, ToolCalls, Trash, WorkflowSteps, Wrench, admitFiles, behindTheScenesItems, behindTheScenesLabel, collectSources, cx, displayUrl, faviconFallbacks, faviconUrl, fileAccepted, getProviderIcon, hasBehindTheScenes, linkCitations, normalizeFollowups, quickPromptLabel, quickPromptText, sourceHost, sourcesFromMarkdown, useAgnoChat, useChatContext, useLinkComponent, useLinkPreview, useOptionalChatContext, useResolvedChat, useResolvedClassNames, useSources, withoutSourcesLine, writeClipboard };
3825
+ //# sourceMappingURL=chunk-OGDPK4Z3.js.map
3826
+ //# sourceMappingURL=chunk-OGDPK4Z3.js.map