@agno-hq/chat-react 0.3.1 → 0.3.3

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.
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunk55HQJGLP_cjs = require('./chunk-55HQJGLP.cjs');
4
- var React7 = require('react');
4
+ var React8 = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var reactDom = require('react-dom');
7
7
  var lucideReact = require('lucide-react');
@@ -9,43 +9,43 @@ var streamdown = require('streamdown');
9
9
 
10
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
11
 
12
- var React7__default = /*#__PURE__*/_interopDefault(React7);
12
+ var React8__default = /*#__PURE__*/_interopDefault(React8);
13
13
 
14
14
  var messageCounter = 0;
15
15
  var nextId = () => `m${Date.now().toString(36)}-${(messageCounter++).toString(36)}`;
16
16
  var nowSeconds = () => Math.floor(Date.now() / 1e3);
17
17
  function useAgnoChat(options) {
18
18
  const { entity, userId, onEvent, onSessionId } = options;
19
- const client = React7.useMemo(() => {
19
+ const client = React8.useMemo(() => {
20
20
  if (options.client) return options.client;
21
21
  return new chunk55HQJGLP_cjs.AgnoClient({ baseUrl: options.baseUrl ?? "", headers: options.headers });
22
22
  }, [options.client, options.baseUrl, JSON.stringify(options.headers)]);
23
- const [messages, setMessages] = React7.useState(options.initialMessages ?? []);
24
- const [events, setEvents] = React7.useState([]);
25
- const [currentEvent, setCurrentEvent] = React7.useState(null);
26
- const [status, setStatus] = React7.useState("idle");
27
- const [activity, setActivity] = React7.useState(null);
28
- const [error, setError] = React7.useState(null);
29
- const [sessionId, setSessionId] = React7.useState(options.sessionId);
30
- const [sessions, setSessions] = React7.useState([]);
31
- const [sessionsLoading, setSessionsLoading] = React7.useState(false);
32
- const [backgroundRunning, setBackgroundRunning] = React7.useState([]);
33
- const abortRef = React7.useRef(null);
34
- const channelRef = React7.useRef(null);
35
- const backgroundRef = React7.useRef(/* @__PURE__ */ new Map());
36
- const activeMsgIdRef = React7.useRef(null);
37
- const runIdRef = React7.useRef(void 0);
38
- const entityRef = React7.useRef(entity);
39
- const sessionIdRef = React7.useRef(options.sessionId);
40
- const pendingSessionNameRef = React7.useRef(void 0);
41
- const bumpedSessionRef = React7.useRef(void 0);
42
- React7.useEffect(() => {
23
+ const [messages, setMessages] = React8.useState(options.initialMessages ?? []);
24
+ const [events, setEvents] = React8.useState([]);
25
+ const [currentEvent, setCurrentEvent] = React8.useState(null);
26
+ const [status, setStatus] = React8.useState("idle");
27
+ const [activity, setActivity] = React8.useState(null);
28
+ const [error, setError] = React8.useState(null);
29
+ const [sessionId, setSessionId] = React8.useState(options.sessionId);
30
+ const [sessions, setSessions] = React8.useState([]);
31
+ const [sessionsLoading, setSessionsLoading] = React8.useState(false);
32
+ const [backgroundRunning, setBackgroundRunning] = React8.useState([]);
33
+ const abortRef = React8.useRef(null);
34
+ const channelRef = React8.useRef(null);
35
+ const backgroundRef = React8.useRef(/* @__PURE__ */ new Map());
36
+ const activeMsgIdRef = React8.useRef(null);
37
+ const runIdRef = React8.useRef(void 0);
38
+ const entityRef = React8.useRef(entity);
39
+ const sessionIdRef = React8.useRef(options.sessionId);
40
+ const pendingSessionNameRef = React8.useRef(void 0);
41
+ const bumpedSessionRef = React8.useRef(void 0);
42
+ React8.useEffect(() => {
43
43
  entityRef.current = entity;
44
44
  }, [entity]);
45
- React7.useEffect(() => {
45
+ React8.useEffect(() => {
46
46
  sessionIdRef.current = sessionId;
47
47
  }, [sessionId]);
48
- const upsertSession = React7.useCallback((id, createdAt) => {
48
+ const upsertSession = React8.useCallback((id, createdAt) => {
49
49
  setSessions((prev) => {
50
50
  const existing = prev.find((s) => s.session_id === id);
51
51
  const rest = prev.filter((s) => s.session_id !== id);
@@ -58,11 +58,11 @@ function useAgnoChat(options) {
58
58
  return [entry, ...rest];
59
59
  });
60
60
  }, []);
61
- const viewRef = React7.useRef({ messages, events, status, activity, error });
62
- React7.useEffect(() => {
61
+ const viewRef = React8.useRef({ messages, events, status, activity, error });
62
+ React8.useEffect(() => {
63
63
  viewRef.current = { messages, events, status, activity, error };
64
64
  });
65
- const writeMessages = React7.useCallback(
65
+ const writeMessages = React8.useCallback(
66
66
  (chan, fn) => {
67
67
  const park = chan?.park;
68
68
  if (park) park.messages = fn(park.messages);
@@ -70,7 +70,7 @@ function useAgnoChat(options) {
70
70
  },
71
71
  []
72
72
  );
73
- const writeEvents = React7.useCallback((chan, e) => {
73
+ const writeEvents = React8.useCallback((chan, e) => {
74
74
  const park = chan?.park;
75
75
  if (park) park.events = [...park.events, e];
76
76
  else {
@@ -78,22 +78,22 @@ function useAgnoChat(options) {
78
78
  setCurrentEvent(e);
79
79
  }
80
80
  }, []);
81
- const writeStatus = React7.useCallback((chan, status2) => {
81
+ const writeStatus = React8.useCallback((chan, status2) => {
82
82
  const park = chan?.park;
83
83
  if (park) park.status = status2;
84
84
  else setStatus(status2);
85
85
  }, []);
86
- const writeActivity = React7.useCallback((chan, activity2) => {
86
+ const writeActivity = React8.useCallback((chan, activity2) => {
87
87
  const park = chan?.park;
88
88
  if (park) park.activity = activity2;
89
89
  else setActivity(activity2);
90
90
  }, []);
91
- const writeError = React7.useCallback((chan, message) => {
91
+ const writeError = React8.useCallback((chan, message) => {
92
92
  const park = chan?.park;
93
93
  if (park) park.error = message;
94
94
  else setError(message);
95
95
  }, []);
96
- const patchActive = React7.useCallback(
96
+ const patchActive = React8.useCallback(
97
97
  (chan, patch) => {
98
98
  const id = chan?.park ? chan.park.activeMsgId : activeMsgIdRef.current;
99
99
  if (!id) return;
@@ -101,7 +101,7 @@ function useAgnoChat(options) {
101
101
  },
102
102
  [writeMessages]
103
103
  );
104
- const applyEvent = React7.useCallback(
104
+ const applyEvent = React8.useCallback(
105
105
  (chan, e) => {
106
106
  writeEvents(chan, e);
107
107
  patchActive(chan, (m) => ({ ...m, events: [...m.events ?? [], e] }));
@@ -233,7 +233,7 @@ function useAgnoChat(options) {
233
233
  writeStatus
234
234
  ]
235
235
  );
236
- const parkRun = React7.useCallback((chan, sessionId2) => {
236
+ const parkRun = React8.useCallback((chan, sessionId2) => {
237
237
  const view = viewRef.current;
238
238
  chan.park = {
239
239
  sessionId: sessionId2,
@@ -253,7 +253,7 @@ function useAgnoChat(options) {
253
253
  activeMsgIdRef.current = null;
254
254
  runIdRef.current = void 0;
255
255
  }, []);
256
- const resumeRun = React7.useCallback((sessionId2) => {
256
+ const resumeRun = React8.useCallback((sessionId2) => {
257
257
  const chan = backgroundRef.current.get(sessionId2);
258
258
  const park = chan?.park;
259
259
  if (!chan || !park) return false;
@@ -273,7 +273,7 @@ function useAgnoChat(options) {
273
273
  setError(park.error);
274
274
  return true;
275
275
  }, []);
276
- const releaseCurrentRun = React7.useCallback(() => {
276
+ const releaseCurrentRun = React8.useCallback(() => {
277
277
  const chan = channelRef.current;
278
278
  if (!chan || chan.park) return;
279
279
  const from = sessionIdRef.current;
@@ -285,7 +285,7 @@ function useAgnoChat(options) {
285
285
  abortRef.current = null;
286
286
  }
287
287
  }, [parkRun]);
288
- const drive = React7.useCallback(
288
+ const drive = React8.useCallback(
289
289
  async (starter) => {
290
290
  const controller = new AbortController();
291
291
  const chan = { controller, park: null };
@@ -321,7 +321,7 @@ function useAgnoChat(options) {
321
321
  },
322
322
  [applyEvent, patchActive, writeActivity, writeError, writeStatus]
323
323
  );
324
- const sendMessage = React7.useCallback(
324
+ const sendMessage = React8.useCallback(
325
325
  async (message, sendOptions) => {
326
326
  const ent = entityRef.current;
327
327
  if (!ent) {
@@ -364,7 +364,7 @@ function useAgnoChat(options) {
364
364
  },
365
365
  [client, drive, userId]
366
366
  );
367
- const continueRun = React7.useCallback(
367
+ const continueRun = React8.useCallback(
368
368
  async (resolution) => {
369
369
  const ent = entityRef.current;
370
370
  const runId = runIdRef.current;
@@ -388,15 +388,15 @@ function useAgnoChat(options) {
388
388
  },
389
389
  [client, drive, patchActive, userId]
390
390
  );
391
- const activeMessage = React7.useMemo(
391
+ const activeMessage = React8.useMemo(
392
392
  () => messages.find((m) => m.id === activeMsgIdRef.current) ?? null,
393
393
  [messages]
394
394
  );
395
- const pausedTools = React7.useMemo(
395
+ const pausedTools = React8.useMemo(
396
396
  () => (activeMessage?.tool_calls ?? []).filter((t) => t.requires_confirmation || t.requires_user_input),
397
397
  [activeMessage]
398
398
  );
399
- const respondToConfirmation = React7.useCallback(
399
+ const respondToConfirmation = React8.useCallback(
400
400
  async (approve) => {
401
401
  const ent = entityRef.current;
402
402
  if (ent?.type === "workflow") {
@@ -409,7 +409,7 @@ function useAgnoChat(options) {
409
409
  },
410
410
  [activeMessage, continueRun, pausedTools]
411
411
  );
412
- const submitUserInput = React7.useCallback(
412
+ const submitUserInput = React8.useCallback(
413
413
  async (values) => {
414
414
  const ent = entityRef.current;
415
415
  if (ent?.type === "workflow") {
@@ -435,7 +435,7 @@ function useAgnoChat(options) {
435
435
  },
436
436
  [activeMessage, continueRun, pausedTools]
437
437
  );
438
- const cancel = React7.useCallback(async () => {
438
+ const cancel = React8.useCallback(async () => {
439
439
  abortRef.current?.abort();
440
440
  channelRef.current = null;
441
441
  const ent = entityRef.current;
@@ -445,7 +445,7 @@ function useAgnoChat(options) {
445
445
  patchActive(null, (m) => m.streaming ? { ...m, streaming: false, status: "cancelled" } : m);
446
446
  if (ent && runId) await client.cancelRun(ent.type, ent.id, runId, sessionIdRef.current);
447
447
  }, [client, patchActive]);
448
- const refreshSessions = React7.useCallback(async () => {
448
+ const refreshSessions = React8.useCallback(async () => {
449
449
  const ent = entityRef.current;
450
450
  if (!ent) {
451
451
  setSessions([]);
@@ -464,7 +464,7 @@ function useAgnoChat(options) {
464
464
  setSessionsLoading(false);
465
465
  }
466
466
  }, [client]);
467
- const loadSession = React7.useCallback(
467
+ const loadSession = React8.useCallback(
468
468
  async (id) => {
469
469
  const ent = entityRef.current;
470
470
  if (!ent) return;
@@ -490,7 +490,7 @@ function useAgnoChat(options) {
490
490
  },
491
491
  [client, onSessionId, releaseCurrentRun, resumeRun]
492
492
  );
493
- const deleteSession = React7.useCallback(
493
+ const deleteSession = React8.useCallback(
494
494
  async (id) => {
495
495
  const ent = entityRef.current;
496
496
  const ok = await client.deleteSession(id, ent?.db_id);
@@ -511,7 +511,7 @@ function useAgnoChat(options) {
511
511
  },
512
512
  [client]
513
513
  );
514
- const reset = React7.useCallback(() => {
514
+ const reset = React8.useCallback(() => {
515
515
  releaseCurrentRun();
516
516
  activeMsgIdRef.current = null;
517
517
  runIdRef.current = void 0;
@@ -526,7 +526,7 @@ function useAgnoChat(options) {
526
526
  setError(null);
527
527
  setSessionId(void 0);
528
528
  }, [releaseCurrentRun]);
529
- React7.useEffect(() => {
529
+ React8.useEffect(() => {
530
530
  const background = backgroundRef.current;
531
531
  return () => {
532
532
  abortRef.current?.abort();
@@ -534,7 +534,7 @@ function useAgnoChat(options) {
534
534
  background.clear();
535
535
  };
536
536
  }, []);
537
- const streamingMessage = React7.useMemo(
537
+ const streamingMessage = React8.useMemo(
538
538
  () => messages.find((m) => m.role === "agent" && m.streaming) ?? null,
539
539
  [messages]
540
540
  );
@@ -576,7 +576,7 @@ function cx(...parts) {
576
576
  const out = parts.filter(Boolean).join(" ");
577
577
  return out || void 0;
578
578
  }
579
- var ChatContext = React7.createContext(null);
579
+ var ChatContext = React8.createContext(null);
580
580
  function ChatProvider({
581
581
  children,
582
582
  classNames,
@@ -593,7 +593,7 @@ function ChatProvider({
593
593
  }) {
594
594
  const internal = useAgnoChat(externalChat ? { entity: null } : options);
595
595
  const chat = externalChat ?? internal;
596
- const value = React7.useMemo(
596
+ const value = React8.useMemo(
597
597
  () => ({ chat, classNames: classNames ?? {}, renderMarkdown, resolveLinkPreview, codeCopy, linkComponent }),
598
598
  [chat, classNames, renderMarkdown, resolveLinkPreview, codeCopy, linkComponent]
599
599
  );
@@ -608,12 +608,12 @@ function ChatProvider({
608
608
  ) : children });
609
609
  }
610
610
  function useChatContext() {
611
- const value = React7.useContext(ChatContext);
611
+ const value = React8.useContext(ChatContext);
612
612
  if (!value) throw new Error("useChatContext must be used inside a <ChatProvider>");
613
613
  return value;
614
614
  }
615
615
  function useOptionalChatContext() {
616
- return React7.useContext(ChatContext);
616
+ return React8.useContext(ChatContext);
617
617
  }
618
618
  function useResolvedChat(explicit) {
619
619
  const ctx = useOptionalChatContext();
@@ -633,7 +633,7 @@ function useLinkComponent() {
633
633
  }
634
634
  function useResolvedClassNames(explicit) {
635
635
  const ctx = useOptionalChatContext();
636
- return React7.useMemo(() => ({ ...ctx?.classNames, ...explicit }), [ctx?.classNames, explicit]);
636
+ return React8.useMemo(() => ({ ...ctx?.classNames, ...explicit }), [ctx?.classNames, explicit]);
637
637
  }
638
638
  var STROKE = 1.5;
639
639
  var icon = (Component, defaultSize = 16) => function Icon({ size = defaultSize, className }) {
@@ -662,9 +662,7 @@ var Pulse = icon(lucideReact.Activity);
662
662
  var Trash = icon(lucideReact.Trash2);
663
663
  var ChatBubble = icon(lucideReact.MessageSquare);
664
664
  var Spinner = icon(lucideReact.LoaderCircle, 12);
665
- function Stop({ size = 16, className }) {
666
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { size, className, fill: "currentColor", strokeWidth: 0 });
667
- }
665
+ var Stop = icon(lucideReact.Square, 10.67);
668
666
  function AgnoMark({ size = 24, className }) {
669
667
  return /* @__PURE__ */ jsxRuntime.jsxs(
670
668
  "svg",
@@ -780,19 +778,19 @@ function ChatLauncher({
780
778
  portal = true,
781
779
  className
782
780
  }) {
783
- const [uncontrolledOpen, setUncontrolledOpen] = React7.useState(defaultOpen);
781
+ const [uncontrolledOpen, setUncontrolledOpen] = React8.useState(defaultOpen);
784
782
  const isOpen = open ?? uncontrolledOpen;
785
- const opened = React7.useRef(isOpen);
783
+ const opened = React8.useRef(isOpen);
786
784
  if (isOpen) opened.current = true;
787
785
  const mounted = keepMounted ? opened.current : isOpen;
788
- const setOpen = React7.useCallback(
786
+ const setOpen = React8.useCallback(
789
787
  (next) => {
790
788
  if (open === void 0) setUncontrolledOpen(next);
791
789
  onOpenChange?.(next);
792
790
  },
793
791
  [open, onOpenChange]
794
792
  );
795
- React7.useEffect(() => {
793
+ React8.useEffect(() => {
796
794
  if (!isOpen || !closeOnEscape) return;
797
795
  const onKeyDown = (e) => {
798
796
  if (e.key === "Escape") setOpen(false);
@@ -800,7 +798,7 @@ function ChatLauncher({
800
798
  document.addEventListener("keydown", onKeyDown);
801
799
  return () => document.removeEventListener("keydown", onKeyDown);
802
800
  }, [isOpen, closeOnEscape, setOpen]);
803
- React7.useEffect(() => {
801
+ React8.useEffect(() => {
804
802
  if (!isOpen || panel !== "fullscreen") return;
805
803
  const previous = document.body.style.overflow;
806
804
  document.body.style.overflow = "hidden";
@@ -808,8 +806,8 @@ function ChatLauncher({
808
806
  document.body.style.overflow = previous;
809
807
  };
810
808
  }, [isOpen, panel]);
811
- const [canPortal, setCanPortal] = React7.useState(false);
812
- React7.useEffect(() => setCanPortal(true), []);
809
+ const [canPortal, setCanPortal] = React8.useState(false);
810
+ React8.useEffect(() => setCanPortal(true), []);
813
811
  const classes = [
814
812
  "agno-launcher",
815
813
  `agno-launcher--${position}`,
@@ -865,8 +863,8 @@ function kindOf(file) {
865
863
  }
866
864
  function Item({ file, onRemove }) {
867
865
  const isImage = file.type.startsWith("image/");
868
- const [url, setUrl] = React7.useState(null);
869
- React7.useEffect(() => {
866
+ const [url, setUrl] = React8.useState(null);
867
+ React8.useEffect(() => {
870
868
  if (!isImage) return;
871
869
  const objectUrl = URL.createObjectURL(file);
872
870
  setUrl(objectUrl);
@@ -970,24 +968,24 @@ function ChatInput({
970
968
  }) {
971
969
  const ctx = useOptionalChatContext();
972
970
  const cn = useResolvedClassNames(classNames);
973
- const [internal, setInternal] = React7.useState("");
971
+ const [internal, setInternal] = React8.useState("");
974
972
  const value = controlled ?? internal;
975
973
  const setValue = (next) => {
976
974
  if (controlled === void 0) setInternal(next);
977
975
  onValueChange?.(next);
978
976
  };
979
- const [files, setFilesState] = React7.useState([]);
980
- const filesRef = React7.useRef([]);
977
+ const [files, setFilesState] = React8.useState([]);
978
+ const filesRef = React8.useRef([]);
981
979
  const setFiles = (next) => {
982
980
  filesRef.current = next;
983
981
  setFilesState(next);
984
982
  };
985
- const [fileError, setFileError] = React7.useState(null);
986
- const [dragging, setDragging] = React7.useState(false);
987
- const dragDepth = React7.useRef(0);
988
- const fileRef = React7.useRef(null);
989
- const textareaRef = React7.useRef(null);
990
- const setTextareaRef = React7.useCallback(
983
+ const [fileError, setFileError] = React8.useState(null);
984
+ const [dragging, setDragging] = React8.useState(false);
985
+ const dragDepth = React8.useRef(0);
986
+ const fileRef = React8.useRef(null);
987
+ const textareaRef = React8.useRef(null);
988
+ const setTextareaRef = React8.useCallback(
991
989
  (el2) => {
992
990
  textareaRef.current = el2;
993
991
  if (typeof externalRef === "function") externalRef(el2);
@@ -995,14 +993,14 @@ function ChatInput({
995
993
  },
996
994
  [externalRef]
997
995
  );
998
- const adjustHeight = React7.useCallback(() => {
996
+ const adjustHeight = React8.useCallback(() => {
999
997
  const el2 = textareaRef.current;
1000
998
  if (!el2 || renderTextarea) return;
1001
999
  const { min, max } = compact ? BOUNDS.compact : BOUNDS.dock;
1002
1000
  el2.style.height = `${min}px`;
1003
1001
  el2.style.height = `${Math.min(Math.max(el2.scrollHeight, min), max)}px`;
1004
1002
  }, [renderTextarea, compact]);
1005
- React7.useEffect(adjustHeight, [value, adjustHeight]);
1003
+ React8.useEffect(adjustHeight, [value, adjustHeight]);
1006
1004
  const send = onSend ?? ((message, attached) => void ctx?.chat.sendMessage(message, attached ? { files: attached } : void 0));
1007
1005
  const stop = onStop ?? (ctx ? () => void ctx.chat.cancel() : void 0);
1008
1006
  const isBusy = busy ?? ctx?.chat.isStreaming ?? false;
@@ -1100,15 +1098,18 @@ function ChatInput({
1100
1098
  }
1101
1099
  )
1102
1100
  ] });
1103
- const primary = isBusy && stop ? /* @__PURE__ */ jsxRuntime.jsx(
1104
- "button",
1105
- {
1106
- type: "button",
1107
- className: cx("agno-btn", "agno-btn--destructive", "agno-btn--icon", cn.stopButton),
1108
- onClick: stop,
1109
- "aria-label": "Stop",
1110
- children: /* @__PURE__ */ jsxRuntime.jsx(Stop, { size: iconSize })
1111
- }
1101
+ const primary = isBusy && stop ? (
1102
+ // The same button the arrow sends from, with AgentOS's square-stop in it.
1103
+ /* @__PURE__ */ jsxRuntime.jsx(
1104
+ "button",
1105
+ {
1106
+ type: "button",
1107
+ className: cx("agno-btn", "agno-btn--icon", cn.stopButton),
1108
+ onClick: stop,
1109
+ "aria-label": "Stop",
1110
+ children: /* @__PURE__ */ jsxRuntime.jsx(Stop, {})
1111
+ }
1112
+ )
1112
1113
  ) : /* @__PURE__ */ jsxRuntime.jsx(
1113
1114
  "button",
1114
1115
  {
@@ -1251,11 +1252,11 @@ function HumanInput({
1251
1252
  onResolve,
1252
1253
  className
1253
1254
  }) {
1254
- const asks = React7.useMemo(() => buildAsks(message, entityType), [message, entityType]);
1255
- const [choices, setChoices] = React7.useState({});
1256
- const [values, setValues] = React7.useState({});
1257
- const [reasons, setReasons] = React7.useState({});
1258
- const [openArgs, setOpenArgs] = React7.useState({});
1255
+ const asks = React8.useMemo(() => buildAsks(message, entityType), [message, entityType]);
1256
+ const [choices, setChoices] = React8.useState({});
1257
+ const [values, setValues] = React8.useState({});
1258
+ const [reasons, setReasons] = React8.useState({});
1259
+ const [openArgs, setOpenArgs] = React8.useState({});
1259
1260
  if (asks.length === 0) return null;
1260
1261
  const setValue = (id, name, value) => setValues((v) => ({ ...v, [id]: { ...v[id] ?? {}, [name]: value } }));
1261
1262
  const valueFor = (ask, field) => values[ask.id]?.[field.name] ?? field.value ?? (isBoolField(field) ? false : "");
@@ -1398,11 +1399,14 @@ function sourceHost(url) {
1398
1399
  }
1399
1400
  }
1400
1401
  function faviconUrl(url) {
1401
- if (!url) return void 0;
1402
+ return faviconFallbacks(url)[0];
1403
+ }
1404
+ function faviconFallbacks(url) {
1405
+ if (!url) return [];
1402
1406
  try {
1403
- return new URL("/favicon.ico", url).href;
1407
+ return ["/favicon.ico", "/favicon.svg"].map((path) => new URL(path, url).href);
1404
1408
  } catch {
1405
- return void 0;
1409
+ return [];
1406
1410
  }
1407
1411
  }
1408
1412
  function displayUrl(url) {
@@ -1526,10 +1530,10 @@ function linkCitations(content, sources) {
1526
1530
  );
1527
1531
  }).join("");
1528
1532
  }
1529
- var SourcesContext = React7.createContext([]);
1533
+ var SourcesContext = React8.createContext([]);
1530
1534
  var SourcesProvider = SourcesContext.Provider;
1531
1535
  function useSources() {
1532
- return React7.useContext(SourcesContext);
1536
+ return React8.useContext(SourcesContext);
1533
1537
  }
1534
1538
  var THEMES = { light: "github-light", dark: "monokai" };
1535
1539
  var highlighter;
@@ -1576,10 +1580,10 @@ function normalizeLanguage(language) {
1576
1580
  return lang || void 0;
1577
1581
  }
1578
1582
  function useHighlight(code, language) {
1579
- const [, rerender] = React7.useReducer((n) => n + 1, 0);
1583
+ const [, rerender] = React8.useReducer((n) => n + 1, 0);
1580
1584
  const lang = normalizeLanguage(language);
1581
1585
  const ready = Boolean(lang && loaded.has(lang));
1582
- React7.useEffect(() => {
1586
+ React8.useEffect(() => {
1583
1587
  if (!lang || ready || unsupported.has(lang)) return;
1584
1588
  let cancelled = false;
1585
1589
  void ensureLanguage(lang).then(() => {
@@ -1589,7 +1593,7 @@ function useHighlight(code, language) {
1589
1593
  cancelled = true;
1590
1594
  };
1591
1595
  }, [lang, ready]);
1592
- return React7.useMemo(() => {
1596
+ return React8.useMemo(() => {
1593
1597
  if (!lang || !ready || !highlighter) return null;
1594
1598
  try {
1595
1599
  return highlighter.codeToTokens(code, { lang, themes: THEMES, defaultColor: false }).tokens;
@@ -1598,7 +1602,7 @@ function useHighlight(code, language) {
1598
1602
  }
1599
1603
  }, [code, lang, ready]);
1600
1604
  }
1601
- var useIsomorphicLayoutEffect = typeof window === "undefined" ? React7.useEffect : React7.useLayoutEffect;
1605
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? React8.useEffect : React8.useLayoutEffect;
1602
1606
  var caches = /* @__PURE__ */ new WeakMap();
1603
1607
  var inflight = /* @__PURE__ */ new WeakMap();
1604
1608
  function cacheFor(store, key) {
@@ -1615,9 +1619,9 @@ function useLinkPreviewResolver() {
1615
1619
  function useLinkPreview(url, enabled) {
1616
1620
  const resolve = useLinkPreviewResolver();
1617
1621
  const cached = url && resolve ? cacheFor(caches, resolve).get(url) : void 0;
1618
- const [preview, setPreview] = React7.useState(cached ?? null);
1619
- const [loading2, setLoading] = React7.useState(false);
1620
- React7.useEffect(() => {
1622
+ const [preview, setPreview] = React8.useState(cached ?? null);
1623
+ const [loading2, setLoading] = React8.useState(false);
1624
+ React8.useEffect(() => {
1621
1625
  if (!enabled || !url || !resolve) return;
1622
1626
  const store = cacheFor(caches, resolve);
1623
1627
  if (store.has(url)) {
@@ -1654,10 +1658,11 @@ function Favicon({
1654
1658
  size = 14,
1655
1659
  className
1656
1660
  }) {
1657
- const src = faviconUrl(url);
1658
- const [failed, setFailed] = React7.useState(false);
1659
- React7.useEffect(() => setFailed(false), [src]);
1660
- if (kind === "document" || !src || failed) {
1661
+ const candidates = React8.useMemo(() => faviconFallbacks(url), [url]);
1662
+ const [attempt, setAttempt] = React8.useState(0);
1663
+ const src = candidates[attempt];
1664
+ React8.useEffect(() => setAttempt(0), [url]);
1665
+ if (kind === "document" || !src) {
1661
1666
  const Glyph2 = kind === "document" ? BookOpen : Globe;
1662
1667
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx("agno-favicon", "agno-favicon--glyph", className), "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(Glyph2, { size }) });
1663
1668
  }
@@ -1671,7 +1676,7 @@ function Favicon({
1671
1676
  height: size,
1672
1677
  loading: "lazy",
1673
1678
  decoding: "async",
1674
- onError: () => setFailed(true),
1679
+ onError: () => setAttempt((n) => n + 1),
1675
1680
  "aria-hidden": true
1676
1681
  }
1677
1682
  );
@@ -1700,7 +1705,7 @@ var GAP = 8;
1700
1705
  var OPEN_DELAY = 140;
1701
1706
  var CLOSE_DELAY = 120;
1702
1707
  function usePlacement(anchor, open, { width = PREVIEW_WIDTH, align = "center" } = {}) {
1703
- const [placement, setPlacement] = React7.useState(null);
1708
+ const [placement, setPlacement] = React8.useState(null);
1704
1709
  useIsomorphicLayoutEffect(() => {
1705
1710
  if (!open || !anchor) return;
1706
1711
  const place = () => {
@@ -1730,15 +1735,15 @@ function HoverPreview({
1730
1735
  disabled,
1731
1736
  className
1732
1737
  }) {
1733
- const [open, setOpen] = React7.useState(false);
1734
- const [awake, setAwake] = React7.useState(false);
1735
- const [anchor, setAnchor] = React7.useState(null);
1736
- const timer = React7.useRef(null);
1737
- const id = React7.useId();
1738
+ const [open, setOpen] = React8.useState(false);
1739
+ const [awake, setAwake] = React8.useState(false);
1740
+ const [anchor, setAnchor] = React8.useState(null);
1741
+ const timer = React8.useRef(null);
1742
+ const id = React8.useId();
1738
1743
  const cn = useResolvedClassNames();
1739
1744
  const { preview, loading: loading2 } = useLinkPreview(source.url, awake);
1740
1745
  const placement = usePlacement(anchor, open);
1741
- const schedule = React7.useCallback((next) => {
1746
+ const schedule = React8.useCallback((next) => {
1742
1747
  if (timer.current) clearTimeout(timer.current);
1743
1748
  timer.current = setTimeout(
1744
1749
  () => {
@@ -1748,13 +1753,13 @@ function HoverPreview({
1748
1753
  next ? OPEN_DELAY : CLOSE_DELAY
1749
1754
  );
1750
1755
  }, []);
1751
- React7.useEffect(
1756
+ React8.useEffect(
1752
1757
  () => () => {
1753
1758
  if (timer.current) clearTimeout(timer.current);
1754
1759
  },
1755
1760
  []
1756
1761
  );
1757
- React7.useEffect(() => {
1762
+ React8.useEffect(() => {
1758
1763
  if (!open) return;
1759
1764
  const onKey = (e) => {
1760
1765
  if (e.key === "Escape") setOpen(false);
@@ -1762,10 +1767,10 @@ function HoverPreview({
1762
1767
  document.addEventListener("keydown", onKey);
1763
1768
  return () => document.removeEventListener("keydown", onKey);
1764
1769
  }, [open]);
1765
- const [mounted, setMounted] = React7.useState(false);
1766
- React7.useEffect(() => setMounted(true), []);
1770
+ const [mounted, setMounted] = React8.useState(false);
1771
+ React8.useEffect(() => setMounted(true), []);
1767
1772
  if (disabled) return children;
1768
- const trigger = React7.isValidElement(children) ? React7.cloneElement(children, {
1773
+ const trigger = React8.isValidElement(children) ? React8.cloneElement(children, {
1769
1774
  "aria-describedby": open ? id : void 0
1770
1775
  }) : children;
1771
1776
  const light = anchor?.closest(".agno-light") ? "agno-light" : void 0;
@@ -1802,45 +1807,6 @@ function HoverPreview({
1802
1807
  }
1803
1808
  );
1804
1809
  }
1805
- function el(tag, className) {
1806
- return function Element({ node: _node, className: _theirs, ...rest }) {
1807
- return React7__default.default.createElement(tag, { className, ...rest });
1808
- };
1809
- }
1810
- function sourceForUrl(url, sources) {
1811
- return url ? sources.find((s) => s.url === url) : void 0;
1812
- }
1813
- function citationForLink(label2, href, ctx) {
1814
- if (!/^\d+$/.test(label2.trim())) return void 0;
1815
- return sourceForUrl(href, ctx.sources) ?? ctx.sources.find((s) => s.index === Number(label2.trim()));
1816
- }
1817
- function labelOf(children) {
1818
- if (typeof children === "string") return children;
1819
- if (Array.isArray(children) && children.length === 1 && typeof children[0] === "string") {
1820
- return children[0];
1821
- }
1822
- return "";
1823
- }
1824
- function CitationMarker({
1825
- source,
1826
- className,
1827
- Link
1828
- }) {
1829
- const props = {
1830
- className: cx("agno-cite", className),
1831
- href: source.url ?? `#${source.anchorId}`,
1832
- "aria-label": `Source ${source.index}: ${source.title}`
1833
- };
1834
- return /* @__PURE__ */ jsxRuntime.jsx(HoverPreview, { source, className: "agno-cite__wrap", children: Link && source.url ? /* @__PURE__ */ jsxRuntime.jsx(Link, { ...props, children: source.index }) : /* @__PURE__ */ jsxRuntime.jsx(
1835
- "a",
1836
- {
1837
- ...props,
1838
- target: source.url ? "_blank" : void 0,
1839
- rel: source.url ? "noreferrer noopener" : void 0,
1840
- children: source.index
1841
- }
1842
- ) });
1843
- }
1844
1810
  var COPIED_FOR = 1600;
1845
1811
  var CLIPBOARD_TIMEOUT = 400;
1846
1812
  async function writeClipboard(text) {
@@ -1866,38 +1832,78 @@ async function writeClipboard(text) {
1866
1832
  return false;
1867
1833
  }
1868
1834
  }
1869
- function CopyButton({ text, className }) {
1870
- const [copied, setCopied] = React7.useState(false);
1871
- React7.useEffect(() => {
1835
+ function CopyButton({ text, label: label2 = "Copy", size = 14, className }) {
1836
+ const [copied, setCopied] = React8.useState(false);
1837
+ React8.useEffect(() => {
1872
1838
  if (!copied) return;
1873
1839
  const timer = setTimeout(() => setCopied(false), COPIED_FOR);
1874
1840
  return () => clearTimeout(timer);
1875
1841
  }, [copied]);
1876
1842
  const copy = async () => {
1877
- if (await writeClipboard(text())) setCopied(true);
1843
+ if (await writeClipboard(typeof text === "function" ? text() : text)) setCopied(true);
1878
1844
  };
1845
+ const name = copied ? "Copied" : label2;
1879
1846
  return /* @__PURE__ */ jsxRuntime.jsx(
1880
1847
  "button",
1881
1848
  {
1882
1849
  type: "button",
1883
- className: cx("agno-md-copy", copied && "is-copied", className),
1850
+ className: cx("agno-copy", copied && "is-copied", className),
1884
1851
  onClick: copy,
1885
- "aria-label": copied ? "Copied" : "Copy code",
1886
- title: copied ? "Copied" : "Copy code",
1887
- children: copied ? /* @__PURE__ */ jsxRuntime.jsx(Check, { size: 13 }) : /* @__PURE__ */ jsxRuntime.jsx(Copy, { size: 13 })
1852
+ "aria-label": name,
1853
+ title: name,
1854
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(Check, { size }) : /* @__PURE__ */ jsxRuntime.jsx(Copy, { size })
1888
1855
  }
1889
1856
  );
1890
1857
  }
1858
+ function el(tag, className) {
1859
+ return function Element({ node: _node, className: _theirs, ...rest }) {
1860
+ return React8__default.default.createElement(tag, { className, ...rest });
1861
+ };
1862
+ }
1863
+ function sourceForUrl(url, sources) {
1864
+ return url ? sources.find((s) => s.url === url) : void 0;
1865
+ }
1866
+ function citationForLink(label2, href, ctx) {
1867
+ if (!/^\d+$/.test(label2.trim())) return void 0;
1868
+ return sourceForUrl(href, ctx.sources) ?? ctx.sources.find((s) => s.index === Number(label2.trim()));
1869
+ }
1870
+ function labelOf(children) {
1871
+ if (typeof children === "string") return children;
1872
+ if (Array.isArray(children) && children.length === 1 && typeof children[0] === "string") {
1873
+ return children[0];
1874
+ }
1875
+ return "";
1876
+ }
1877
+ function CitationMarker({
1878
+ source,
1879
+ className,
1880
+ Link
1881
+ }) {
1882
+ const props = {
1883
+ className: cx("agno-cite", className),
1884
+ href: source.url ?? `#${source.anchorId}`,
1885
+ "aria-label": `Source ${source.index}: ${source.title}`
1886
+ };
1887
+ return /* @__PURE__ */ jsxRuntime.jsx(HoverPreview, { source, className: "agno-cite__wrap", children: Link && source.url ? /* @__PURE__ */ jsxRuntime.jsx(Link, { ...props, children: source.index }) : /* @__PURE__ */ jsxRuntime.jsx(
1888
+ "a",
1889
+ {
1890
+ ...props,
1891
+ target: source.url ? "_blank" : void 0,
1892
+ rel: source.url ? "noreferrer noopener" : void 0,
1893
+ children: source.index
1894
+ }
1895
+ ) });
1896
+ }
1891
1897
  function textOf(children) {
1892
1898
  if (typeof children === "string") return children;
1893
1899
  if (typeof children === "number") return String(children);
1894
1900
  if (Array.isArray(children)) return children.map(textOf).join("");
1895
- if (React7__default.default.isValidElement(children)) return textOf(children.props.children);
1901
+ if (React8__default.default.isValidElement(children)) return textOf(children.props.children);
1896
1902
  return "";
1897
1903
  }
1898
1904
  function fencedCode(children) {
1899
1905
  const child = Array.isArray(children) ? children[0] : children;
1900
- if (!React7__default.default.isValidElement(child)) {
1906
+ if (!React8__default.default.isValidElement(child)) {
1901
1907
  return { code: textOf(children) };
1902
1908
  }
1903
1909
  const language = /(?:^|\s)language-([^\s]+)/.exec(child.props.className ?? "")?.[1];
@@ -1911,16 +1917,16 @@ function CodeBlock({
1911
1917
  copyClass,
1912
1918
  codeCopy
1913
1919
  }) {
1914
- const { language, code } = React7.useMemo(() => fencedCode(children), [children]);
1920
+ const { language, code } = React8.useMemo(() => fencedCode(children), [children]);
1915
1921
  const highlighted = useHighlight(code, language);
1916
1922
  const lines = highlighted ?? plainLines(code);
1917
1923
  const label2 = normalizeLanguage(language) ?? "text";
1918
1924
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-md-code-block", "data-language": label2, children: [
1919
1925
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-md-code-head", children: [
1920
1926
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-md-code-lang", children: label2 }),
1921
- codeCopy && /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { className: copyClass, text: () => code })
1927
+ codeCopy && /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { className: cx("agno-md-copy", copyClass), text: () => code, label: "Copy code", size: 13 })
1922
1928
  ] }),
1923
- /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "agno-md-pre", style: { "--agno-code-gutter": `${String(lines.length).length}ch` }, children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: language ? `language-${language}` : void 0, children: lines.map((tokens, i) => /* @__PURE__ */ jsxRuntime.jsxs(React7__default.default.Fragment, { children: [
1929
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "agno-md-pre", style: { "--agno-code-gutter": `${String(lines.length).length}ch` }, children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: language ? `language-${language}` : void 0, children: lines.map((tokens, i) => /* @__PURE__ */ jsxRuntime.jsxs(React8__default.default.Fragment, { children: [
1924
1930
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-md-line", children: tokens.map((token, j) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: token.htmlStyle, children: token.content }, j)) }),
1925
1931
  i < lines.length - 1 && "\n"
1926
1932
  ] }, i)) }) })
@@ -2013,7 +2019,7 @@ function Markdown({
2013
2019
  const cited = sources ?? fromMessage;
2014
2020
  const copy = codeCopy ?? fromProvider ?? true;
2015
2021
  const Link = linkComponent ?? providerLink;
2016
- const components = React7.useMemo(
2022
+ const components = React8.useMemo(
2017
2023
  () => elementsFor({
2018
2024
  sources: cited,
2019
2025
  canResolve,
@@ -2024,7 +2030,7 @@ function Markdown({
2024
2030
  }),
2025
2031
  [cited, canResolve, cn.citationMarker, cn.copyButton, copy, Link]
2026
2032
  );
2027
- const text = React7.useMemo(() => linkCitations(content, cited), [content, cited]);
2033
+ const text = React8.useMemo(() => linkCitations(content, cited), [content, cited]);
2028
2034
  return /* @__PURE__ */ jsxRuntime.jsx(
2029
2035
  streamdown.Streamdown,
2030
2036
  {
@@ -2048,7 +2054,7 @@ function hasDetail(tool) {
2048
2054
  return Boolean(tool.tool_args && Object.keys(tool.tool_args).length) || tool.result != null;
2049
2055
  }
2050
2056
  function ToolCalls({ tools }) {
2051
- const [openIndex, setOpenIndex] = React7.useState(null);
2057
+ const [openIndex, setOpenIndex] = React8.useState(null);
2052
2058
  if (!tools || tools.length === 0) return null;
2053
2059
  const open = openIndex != null ? tools[openIndex] : void 0;
2054
2060
  const openStatus = open ? statusOf(open) : void 0;
@@ -2285,7 +2291,7 @@ function Step({
2285
2291
  busy,
2286
2292
  children
2287
2293
  }) {
2288
- const [open, setOpen] = React7.useState(false);
2294
+ const [open, setOpen] = React8.useState(false);
2289
2295
  if (!children) {
2290
2296
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-bts__step", children: [
2291
2297
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-bts__step-label", children: label2 }),
@@ -2330,7 +2336,7 @@ function BehindTheScenes({
2330
2336
  className,
2331
2337
  classNames
2332
2338
  }) {
2333
- const [open, setOpen] = React7.useState(defaultOpen);
2339
+ const [open, setOpen] = React8.useState(defaultOpen);
2334
2340
  const items = behindTheScenesItems(message, { hideReasoning, hideTools });
2335
2341
  if (items.length === 0) return null;
2336
2342
  const label2 = behindTheScenesLabel(message, streaming, activity);
@@ -2467,22 +2473,22 @@ function SourceCard({
2467
2473
  }
2468
2474
  var LIST_WIDTH = 240;
2469
2475
  function SourcesOverflow({ sources }) {
2470
- const [open, setOpen] = React7.useState(false);
2471
- const [anchor, setAnchor] = React7.useState(null);
2472
- const timer = React7.useRef(null);
2473
- const id = React7.useId();
2476
+ const [open, setOpen] = React8.useState(false);
2477
+ const [anchor, setAnchor] = React8.useState(null);
2478
+ const timer = React8.useRef(null);
2479
+ const id = React8.useId();
2474
2480
  const placement = usePlacement(anchor, open, { width: LIST_WIDTH, align: "start" });
2475
- const schedule = React7.useCallback((next) => {
2481
+ const schedule = React8.useCallback((next) => {
2476
2482
  if (timer.current) clearTimeout(timer.current);
2477
2483
  timer.current = setTimeout(() => setOpen(next), next ? OPEN_DELAY : CLOSE_DELAY);
2478
2484
  }, []);
2479
- React7.useEffect(
2485
+ React8.useEffect(
2480
2486
  () => () => {
2481
2487
  if (timer.current) clearTimeout(timer.current);
2482
2488
  },
2483
2489
  []
2484
2490
  );
2485
- React7.useEffect(() => {
2491
+ React8.useEffect(() => {
2486
2492
  if (!open) return;
2487
2493
  const onKey = (e) => {
2488
2494
  if (e.key === "Escape") setOpen(false);
@@ -2490,8 +2496,8 @@ function SourcesOverflow({ sources }) {
2490
2496
  document.addEventListener("keydown", onKey);
2491
2497
  return () => document.removeEventListener("keydown", onKey);
2492
2498
  }, [open]);
2493
- const [mounted, setMounted] = React7.useState(false);
2494
- React7.useEffect(() => setMounted(true), []);
2499
+ const [mounted, setMounted] = React8.useState(false);
2500
+ React8.useEffect(() => setMounted(true), []);
2495
2501
  const light = anchor?.closest(".agno-light") ? "agno-light" : void 0;
2496
2502
  return /* @__PURE__ */ jsxRuntime.jsxs(
2497
2503
  "span",
@@ -2563,8 +2569,8 @@ function Citations({
2563
2569
  classNames
2564
2570
  }) {
2565
2571
  const cn = useResolvedClassNames(classNames);
2566
- const uid = React7.useId();
2567
- const sources = React7.useMemo(
2572
+ const uid = React8.useId();
2573
+ const sources = React8.useMemo(
2568
2574
  () => given ?? collectSources(references, citations, uid),
2569
2575
  [given, references, citations, uid]
2570
2576
  );
@@ -2580,6 +2586,20 @@ function Citations({
2580
2586
  ] })
2581
2587
  ] });
2582
2588
  }
2589
+ function MessageActions({
2590
+ message,
2591
+ hideCopy,
2592
+ children,
2593
+ className,
2594
+ classNames
2595
+ }) {
2596
+ const cn = useResolvedClassNames(classNames);
2597
+ if (hideCopy && !children) return null;
2598
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("agno-msg__actions", cn.messageActions, className), role: "toolbar", "aria-label": "Message actions", children: [
2599
+ !hideCopy && /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { className: cx("agno-msg__action", cn.messageCopyButton), text: message.content, label: "Copy message" }),
2600
+ children
2601
+ ] });
2602
+ }
2583
2603
  function audioSrc(a) {
2584
2604
  if (a.url) return a.url;
2585
2605
  if (a.base64_audio) return `data:${a.mime_type ?? "audio/mpeg"};base64,${a.base64_audio}`;
@@ -2620,20 +2640,23 @@ function Message({
2620
2640
  hideReasoning,
2621
2641
  hideTools,
2622
2642
  hideSources,
2643
+ hideActions,
2644
+ actions,
2623
2645
  onFollowup
2624
2646
  }) {
2625
2647
  const cn = useResolvedClassNames(classNames);
2626
- const uid = React7.useId();
2627
- const sources = React7.useMemo(() => {
2648
+ const uid = React8.useId();
2649
+ const sources = React8.useMemo(() => {
2628
2650
  const cited = collectSources(message.references, message.citations, uid);
2629
2651
  return cited.length ? cited : sourcesFromMarkdown(message.content, uid);
2630
2652
  }, [message.references, message.citations, message.content, uid]);
2631
2653
  const isUser = message.role === "user";
2632
2654
  const isAgent = message.role === "agent";
2633
- const showSources = isAgent && !hideSources && sources.length > 0;
2634
- const content = React7.useMemo(
2635
- () => showSources && message.content ? withoutSourcesLine(message.content) : message.content,
2636
- [message.content, showSources]
2655
+ const hasSources = isAgent && !hideSources && sources.length > 0;
2656
+ const showSources = hasSources && !message.streaming;
2657
+ const content = React8.useMemo(
2658
+ () => hasSources && message.content ? withoutSourcesLine(message.content) : message.content,
2659
+ [message.content, hasSources]
2637
2660
  );
2638
2661
  const hasActivity = !message.content && !hasBehindTheScenes(message, { hideReasoning, hideTools });
2639
2662
  const kind = isUser ? "user" : isAgent ? entityType : "system";
@@ -2685,7 +2708,8 @@ function Message({
2685
2708
  showSources && /* @__PURE__ */ jsxRuntime.jsx(Citations, { sources, classNames: cn }),
2686
2709
  isAgent && onFollowup && !message.streaming && /* @__PURE__ */ jsxRuntime.jsx(Followups, { items: message.followups, onSelect: onFollowup, classNames: cn }),
2687
2710
  message.error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-msg__error", children: message.error }),
2688
- children
2711
+ children,
2712
+ isAgent && !hideActions && !message.streaming && message.content && /* @__PURE__ */ jsxRuntime.jsx(MessageActions, { message, classNames: cn, children: actions })
2689
2713
  ] }) })
2690
2714
  ]
2691
2715
  }
@@ -2712,10 +2736,10 @@ function MessageList({
2712
2736
  const runActivity = activity !== void 0 ? activity : ctx?.chat.activity;
2713
2737
  const markdown = renderMarkdown ?? ctx?.renderMarkdown;
2714
2738
  const kind = entityType ?? ctx?.chat.entityType;
2715
- const endRef = React7.useRef(null);
2716
- const stick = React7.useRef(true);
2717
- const userScrolled = React7.useRef(false);
2718
- const containerRef = React7.useRef(null);
2739
+ const endRef = React8.useRef(null);
2740
+ const stick = React8.useRef(true);
2741
+ const userScrolled = React8.useRef(false);
2742
+ const containerRef = React8.useRef(null);
2719
2743
  const markUserScroll = () => {
2720
2744
  userScrolled.current = true;
2721
2745
  };
@@ -2727,7 +2751,7 @@ function MessageList({
2727
2751
  else if (userScrolled.current) stick.current = false;
2728
2752
  userScrolled.current = false;
2729
2753
  };
2730
- React7.useEffect(() => {
2754
+ React8.useEffect(() => {
2731
2755
  if (stick.current) endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
2732
2756
  }, [items, runActivity, runStatus]);
2733
2757
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2745,7 +2769,7 @@ function MessageList({
2745
2769
  items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx("agno-list__empty", cn.empty), children: emptyState ?? "Start the conversation." }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-list__inner", children: [
2746
2770
  items.map((m) => {
2747
2771
  const live = m.streaming && runStatus === "streaming" ? runActivity : void 0;
2748
- return renderMessage ? /* @__PURE__ */ jsxRuntime.jsx(React7__default.default.Fragment, { children: renderMessage(m, live) }, m.id) : /* @__PURE__ */ jsxRuntime.jsx(
2772
+ return renderMessage ? /* @__PURE__ */ jsxRuntime.jsx(React8__default.default.Fragment, { children: renderMessage(m, live) }, m.id) : /* @__PURE__ */ jsxRuntime.jsx(
2749
2773
  Message,
2750
2774
  {
2751
2775
  message: m,
@@ -3016,10 +3040,10 @@ function EntitySelector({
3016
3040
  classNames
3017
3041
  }) {
3018
3042
  const cn = useResolvedClassNames(classNames);
3019
- const [open, setOpen] = React7.useState(false);
3020
- const rootRef = React7.useRef(null);
3043
+ const [open, setOpen] = React8.useState(false);
3044
+ const rootRef = React8.useRef(null);
3021
3045
  const key = (e) => `${e.type}:${e.id}`;
3022
- React7.useEffect(() => {
3046
+ React8.useEffect(() => {
3023
3047
  if (!open) return;
3024
3048
  const onDocClick = (e) => {
3025
3049
  if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
@@ -3168,14 +3192,14 @@ function SessionList({
3168
3192
  ] });
3169
3193
  }
3170
3194
  function AgnoChat(props) {
3171
- const client = React7.useMemo(
3195
+ const client = React8.useMemo(
3172
3196
  () => props.client ?? new chunk55HQJGLP_cjs.AgnoClient({ baseUrl: props.baseUrl ?? "", headers: props.headers }),
3173
3197
  [props.client, props.baseUrl, props.headers]
3174
3198
  );
3175
- const [discovered, setDiscovered] = React7.useState(props.entities ?? []);
3176
- const [selected, setSelected] = React7.useState(props.defaultEntity ?? null);
3177
- const [discoveryDone, setDiscoveryDone] = React7.useState(Boolean(props.entity || props.entities));
3178
- React7.useEffect(() => {
3199
+ const [discovered, setDiscovered] = React8.useState(props.entities ?? []);
3200
+ const [selected, setSelected] = React8.useState(props.defaultEntity ?? null);
3201
+ const [discoveryDone, setDiscoveryDone] = React8.useState(Boolean(props.entity || props.entities));
3202
+ React8.useEffect(() => {
3179
3203
  if (props.entity && !props.showEntityPicker || props.entities) return;
3180
3204
  let cancelled = false;
3181
3205
  setDiscoveryDone(false);
@@ -3192,10 +3216,10 @@ function AgnoChat(props) {
3192
3216
  const entity = props.entity ?? selected;
3193
3217
  const chat = useAgnoChat({ client, entity, userId: props.userId });
3194
3218
  const { refreshSessions } = chat;
3195
- React7.useEffect(() => {
3219
+ React8.useEffect(() => {
3196
3220
  if (props.showSessions && entity) refreshSessions();
3197
3221
  }, [props.showSessions, entity?.type, entity?.id, refreshSessions]);
3198
- React7.useEffect(() => {
3222
+ React8.useEffect(() => {
3199
3223
  if (props.showSessions && entity && chat.status === "completed") refreshSessions();
3200
3224
  }, [chat.status]);
3201
3225
  const onSelect = (e) => {
@@ -3210,7 +3234,7 @@ function AgnoChat(props) {
3210
3234
  const noEntities = !props.entity && discoveryDone && entities.length === 0;
3211
3235
  const launcher = props.mode === "launcher";
3212
3236
  const fullscreen = props.panel === "fullscreen";
3213
- const [selfOpen, setSelfOpen] = React7.useState(props.defaultOpen ?? false);
3237
+ const [selfOpen, setSelfOpen] = React8.useState(props.defaultOpen ?? false);
3214
3238
  const isOpen = props.open ?? selfOpen;
3215
3239
  const setOpen = (next) => {
3216
3240
  if (props.open === void 0) setSelfOpen(next);
@@ -3335,7 +3359,7 @@ function Reasoning({
3335
3359
  steps,
3336
3360
  defaultOpen = false
3337
3361
  }) {
3338
- const [open, setOpen] = React7.useState(defaultOpen);
3362
+ const [open, setOpen] = React8.useState(defaultOpen);
3339
3363
  if (!steps || steps.length === 0) return null;
3340
3364
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-reasoning", children: [
3341
3365
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3381,7 +3405,7 @@ function statusDot(status) {
3381
3405
  return "running";
3382
3406
  }
3383
3407
  function MemberCard({ member, renderMarkdown }) {
3384
- const [open, setOpen] = React7.useState(true);
3408
+ const [open, setOpen] = React8.useState(true);
3385
3409
  const label2 = member.kind === "executor" ? "Step executor" : "Member";
3386
3410
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-member", children: [
3387
3411
  /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "agno-member__head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -3413,7 +3437,7 @@ function MemberResponses({
3413
3437
  ] });
3414
3438
  }
3415
3439
  function StepRow({ step, renderMarkdown }) {
3416
- const [open, setOpen] = React7.useState(false);
3440
+ const [open, setOpen] = React8.useState(false);
3417
3441
  const hasBody = Boolean(step.content || step.error);
3418
3442
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `agno-step agno-step--${step.status}`, children: [
3419
3443
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3483,9 +3507,9 @@ function EventLog({
3483
3507
  autoScroll = true,
3484
3508
  maxHeight = 240
3485
3509
  }) {
3486
- const ref = React7.useRef(null);
3487
- const rows = React7.useMemo(() => fold(events), [events]);
3488
- React7.useEffect(() => {
3510
+ const ref = React8.useRef(null);
3511
+ const rows = React8.useMemo(() => fold(events), [events]);
3512
+ React8.useEffect(() => {
3489
3513
  if (autoScroll && ref.current) ref.current.scrollTop = ref.current.scrollHeight;
3490
3514
  }, [rows, autoScroll]);
3491
3515
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-eventlog", ref, style: { maxHeight }, children: [
@@ -3519,6 +3543,7 @@ exports.ChevronDown = ChevronDown;
3519
3543
  exports.Citations = Citations;
3520
3544
  exports.Close = Close;
3521
3545
  exports.Copy = Copy;
3546
+ exports.CopyButton = CopyButton;
3522
3547
  exports.EntityBadge = EntityBadge;
3523
3548
  exports.EntitySelector = EntitySelector;
3524
3549
  exports.EventLog = EventLog;
@@ -3539,6 +3564,7 @@ exports.Markdown = Markdown;
3539
3564
  exports.MemberResponses = MemberResponses;
3540
3565
  exports.Memory = Memory;
3541
3566
  exports.Message = Message;
3567
+ exports.MessageActions = MessageActions;
3542
3568
  exports.MessageList = MessageList;
3543
3569
  exports.Multimedia = Multimedia;
3544
3570
  exports.Paperclip = Paperclip;
@@ -3564,6 +3590,7 @@ exports.behindTheScenesLabel = behindTheScenesLabel;
3564
3590
  exports.collectSources = collectSources;
3565
3591
  exports.cx = cx;
3566
3592
  exports.displayUrl = displayUrl;
3593
+ exports.faviconFallbacks = faviconFallbacks;
3567
3594
  exports.faviconUrl = faviconUrl;
3568
3595
  exports.fileAccepted = fileAccepted;
3569
3596
  exports.getProviderIcon = getProviderIcon;
@@ -3584,5 +3611,5 @@ exports.useResolvedClassNames = useResolvedClassNames;
3584
3611
  exports.useSources = useSources;
3585
3612
  exports.withoutSourcesLine = withoutSourcesLine;
3586
3613
  exports.writeClipboard = writeClipboard;
3587
- //# sourceMappingURL=chunk-JEPFGKHH.cjs.map
3588
- //# sourceMappingURL=chunk-JEPFGKHH.cjs.map
3614
+ //# sourceMappingURL=chunk-3IEYJIYJ.cjs.map
3615
+ //# sourceMappingURL=chunk-3IEYJIYJ.cjs.map