@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,8 +1,8 @@
1
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';
2
- import React7, { createContext, useMemo, useState, useRef, useEffect, useCallback, useContext, useId, isValidElement, cloneElement, useLayoutEffect, useReducer } from 'react';
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 { Square, 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 } 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, 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
8
  var messageCounter = 0;
@@ -656,9 +656,7 @@ var Pulse = icon(Activity);
656
656
  var Trash = icon(Trash2);
657
657
  var ChatBubble = icon(MessageSquare);
658
658
  var Spinner = icon(LoaderCircle, 12);
659
- function Stop({ size = 16, className }) {
660
- return /* @__PURE__ */ jsx(Square, { size, className, fill: "currentColor", strokeWidth: 0 });
661
- }
659
+ var Stop = icon(Square, 10.67);
662
660
  function AgnoMark({ size = 24, className }) {
663
661
  return /* @__PURE__ */ jsxs(
664
662
  "svg",
@@ -1094,15 +1092,18 @@ function ChatInput({
1094
1092
  }
1095
1093
  )
1096
1094
  ] });
1097
- const primary = isBusy && stop ? /* @__PURE__ */ jsx(
1098
- "button",
1099
- {
1100
- type: "button",
1101
- className: cx("agno-btn", "agno-btn--destructive", "agno-btn--icon", cn.stopButton),
1102
- onClick: stop,
1103
- "aria-label": "Stop",
1104
- children: /* @__PURE__ */ jsx(Stop, { size: iconSize })
1105
- }
1095
+ const primary = isBusy && stop ? (
1096
+ // The same button the arrow sends from, with AgentOS's square-stop in it.
1097
+ /* @__PURE__ */ jsx(
1098
+ "button",
1099
+ {
1100
+ type: "button",
1101
+ className: cx("agno-btn", "agno-btn--icon", cn.stopButton),
1102
+ onClick: stop,
1103
+ "aria-label": "Stop",
1104
+ children: /* @__PURE__ */ jsx(Stop, {})
1105
+ }
1106
+ )
1106
1107
  ) : /* @__PURE__ */ jsx(
1107
1108
  "button",
1108
1109
  {
@@ -1392,11 +1393,14 @@ function sourceHost(url) {
1392
1393
  }
1393
1394
  }
1394
1395
  function faviconUrl(url) {
1395
- if (!url) return void 0;
1396
+ return faviconFallbacks(url)[0];
1397
+ }
1398
+ function faviconFallbacks(url) {
1399
+ if (!url) return [];
1396
1400
  try {
1397
- return new URL("/favicon.ico", url).href;
1401
+ return ["/favicon.ico", "/favicon.svg"].map((path) => new URL(path, url).href);
1398
1402
  } catch {
1399
- return void 0;
1403
+ return [];
1400
1404
  }
1401
1405
  }
1402
1406
  function displayUrl(url) {
@@ -1648,10 +1652,11 @@ function Favicon({
1648
1652
  size = 14,
1649
1653
  className
1650
1654
  }) {
1651
- const src = faviconUrl(url);
1652
- const [failed, setFailed] = useState(false);
1653
- useEffect(() => setFailed(false), [src]);
1654
- if (kind === "document" || !src || failed) {
1655
+ const candidates = useMemo(() => faviconFallbacks(url), [url]);
1656
+ const [attempt, setAttempt] = useState(0);
1657
+ const src = candidates[attempt];
1658
+ useEffect(() => setAttempt(0), [url]);
1659
+ if (kind === "document" || !src) {
1655
1660
  const Glyph2 = kind === "document" ? BookOpen : Globe;
1656
1661
  return /* @__PURE__ */ jsx("span", { className: cx("agno-favicon", "agno-favicon--glyph", className), "aria-hidden": true, children: /* @__PURE__ */ jsx(Glyph2, { size }) });
1657
1662
  }
@@ -1665,7 +1670,7 @@ function Favicon({
1665
1670
  height: size,
1666
1671
  loading: "lazy",
1667
1672
  decoding: "async",
1668
- onError: () => setFailed(true),
1673
+ onError: () => setAttempt((n) => n + 1),
1669
1674
  "aria-hidden": true
1670
1675
  }
1671
1676
  );
@@ -1796,45 +1801,6 @@ function HoverPreview({
1796
1801
  }
1797
1802
  );
1798
1803
  }
1799
- function el(tag, className) {
1800
- return function Element({ node: _node, className: _theirs, ...rest }) {
1801
- return React7.createElement(tag, { className, ...rest });
1802
- };
1803
- }
1804
- function sourceForUrl(url, sources) {
1805
- return url ? sources.find((s) => s.url === url) : void 0;
1806
- }
1807
- function citationForLink(label2, href, ctx) {
1808
- if (!/^\d+$/.test(label2.trim())) return void 0;
1809
- return sourceForUrl(href, ctx.sources) ?? ctx.sources.find((s) => s.index === Number(label2.trim()));
1810
- }
1811
- function labelOf(children) {
1812
- if (typeof children === "string") return children;
1813
- if (Array.isArray(children) && children.length === 1 && typeof children[0] === "string") {
1814
- return children[0];
1815
- }
1816
- return "";
1817
- }
1818
- function CitationMarker({
1819
- source,
1820
- className,
1821
- Link
1822
- }) {
1823
- const props = {
1824
- className: cx("agno-cite", className),
1825
- href: source.url ?? `#${source.anchorId}`,
1826
- "aria-label": `Source ${source.index}: ${source.title}`
1827
- };
1828
- return /* @__PURE__ */ jsx(HoverPreview, { source, className: "agno-cite__wrap", children: Link && source.url ? /* @__PURE__ */ jsx(Link, { ...props, children: source.index }) : /* @__PURE__ */ jsx(
1829
- "a",
1830
- {
1831
- ...props,
1832
- target: source.url ? "_blank" : void 0,
1833
- rel: source.url ? "noreferrer noopener" : void 0,
1834
- children: source.index
1835
- }
1836
- ) });
1837
- }
1838
1804
  var COPIED_FOR = 1600;
1839
1805
  var CLIPBOARD_TIMEOUT = 400;
1840
1806
  async function writeClipboard(text) {
@@ -1860,7 +1826,7 @@ async function writeClipboard(text) {
1860
1826
  return false;
1861
1827
  }
1862
1828
  }
1863
- function CopyButton({ text, className }) {
1829
+ function CopyButton({ text, label: label2 = "Copy", size = 14, className }) {
1864
1830
  const [copied, setCopied] = useState(false);
1865
1831
  useEffect(() => {
1866
1832
  if (!copied) return;
@@ -1868,30 +1834,70 @@ function CopyButton({ text, className }) {
1868
1834
  return () => clearTimeout(timer);
1869
1835
  }, [copied]);
1870
1836
  const copy = async () => {
1871
- if (await writeClipboard(text())) setCopied(true);
1837
+ if (await writeClipboard(typeof text === "function" ? text() : text)) setCopied(true);
1872
1838
  };
1839
+ const name = copied ? "Copied" : label2;
1873
1840
  return /* @__PURE__ */ jsx(
1874
1841
  "button",
1875
1842
  {
1876
1843
  type: "button",
1877
- className: cx("agno-md-copy", copied && "is-copied", className),
1844
+ className: cx("agno-copy", copied && "is-copied", className),
1878
1845
  onClick: copy,
1879
- "aria-label": copied ? "Copied" : "Copy code",
1880
- title: copied ? "Copied" : "Copy code",
1881
- children: copied ? /* @__PURE__ */ jsx(Check, { size: 13 }) : /* @__PURE__ */ jsx(Copy, { size: 13 })
1846
+ "aria-label": name,
1847
+ title: name,
1848
+ children: copied ? /* @__PURE__ */ jsx(Check, { size }) : /* @__PURE__ */ jsx(Copy, { size })
1882
1849
  }
1883
1850
  );
1884
1851
  }
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
+ }
1885
1891
  function textOf(children) {
1886
1892
  if (typeof children === "string") return children;
1887
1893
  if (typeof children === "number") return String(children);
1888
1894
  if (Array.isArray(children)) return children.map(textOf).join("");
1889
- if (React7.isValidElement(children)) return textOf(children.props.children);
1895
+ if (React8.isValidElement(children)) return textOf(children.props.children);
1890
1896
  return "";
1891
1897
  }
1892
1898
  function fencedCode(children) {
1893
1899
  const child = Array.isArray(children) ? children[0] : children;
1894
- if (!React7.isValidElement(child)) {
1900
+ if (!React8.isValidElement(child)) {
1895
1901
  return { code: textOf(children) };
1896
1902
  }
1897
1903
  const language = /(?:^|\s)language-([^\s]+)/.exec(child.props.className ?? "")?.[1];
@@ -1912,9 +1918,9 @@ function CodeBlock({
1912
1918
  return /* @__PURE__ */ jsxs("div", { className: "agno-md-code-block", "data-language": label2, children: [
1913
1919
  /* @__PURE__ */ jsxs("div", { className: "agno-md-code-head", children: [
1914
1920
  /* @__PURE__ */ jsx("span", { className: "agno-md-code-lang", children: label2 }),
1915
- codeCopy && /* @__PURE__ */ jsx(CopyButton, { className: copyClass, text: () => code })
1921
+ codeCopy && /* @__PURE__ */ jsx(CopyButton, { className: cx("agno-md-copy", copyClass), text: () => code, label: "Copy code", size: 13 })
1916
1922
  ] }),
1917
- /* @__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(React7.Fragment, { children: [
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: [
1918
1924
  /* @__PURE__ */ jsx("span", { className: "agno-md-line", children: tokens.map((token, j) => /* @__PURE__ */ jsx("span", { style: token.htmlStyle, children: token.content }, j)) }),
1919
1925
  i < lines.length - 1 && "\n"
1920
1926
  ] }, i)) }) })
@@ -2574,6 +2580,20 @@ function Citations({
2574
2580
  ] })
2575
2581
  ] });
2576
2582
  }
2583
+ function MessageActions({
2584
+ message,
2585
+ hideCopy,
2586
+ children,
2587
+ className,
2588
+ classNames
2589
+ }) {
2590
+ const cn = useResolvedClassNames(classNames);
2591
+ if (hideCopy && !children) return null;
2592
+ return /* @__PURE__ */ jsxs("div", { className: cx("agno-msg__actions", cn.messageActions, className), role: "toolbar", "aria-label": "Message actions", children: [
2593
+ !hideCopy && /* @__PURE__ */ jsx(CopyButton, { className: cx("agno-msg__action", cn.messageCopyButton), text: message.content, label: "Copy message" }),
2594
+ children
2595
+ ] });
2596
+ }
2577
2597
  function audioSrc(a) {
2578
2598
  if (a.url) return a.url;
2579
2599
  if (a.base64_audio) return `data:${a.mime_type ?? "audio/mpeg"};base64,${a.base64_audio}`;
@@ -2614,6 +2634,8 @@ function Message({
2614
2634
  hideReasoning,
2615
2635
  hideTools,
2616
2636
  hideSources,
2637
+ hideActions,
2638
+ actions,
2617
2639
  onFollowup
2618
2640
  }) {
2619
2641
  const cn = useResolvedClassNames(classNames);
@@ -2624,10 +2646,11 @@ function Message({
2624
2646
  }, [message.references, message.citations, message.content, uid]);
2625
2647
  const isUser = message.role === "user";
2626
2648
  const isAgent = message.role === "agent";
2627
- const showSources = isAgent && !hideSources && sources.length > 0;
2649
+ const hasSources = isAgent && !hideSources && sources.length > 0;
2650
+ const showSources = hasSources && !message.streaming;
2628
2651
  const content = useMemo(
2629
- () => showSources && message.content ? withoutSourcesLine(message.content) : message.content,
2630
- [message.content, showSources]
2652
+ () => hasSources && message.content ? withoutSourcesLine(message.content) : message.content,
2653
+ [message.content, hasSources]
2631
2654
  );
2632
2655
  const hasActivity = !message.content && !hasBehindTheScenes(message, { hideReasoning, hideTools });
2633
2656
  const kind = isUser ? "user" : isAgent ? entityType : "system";
@@ -2679,7 +2702,8 @@ function Message({
2679
2702
  showSources && /* @__PURE__ */ jsx(Citations, { sources, classNames: cn }),
2680
2703
  isAgent && onFollowup && !message.streaming && /* @__PURE__ */ jsx(Followups, { items: message.followups, onSelect: onFollowup, classNames: cn }),
2681
2704
  message.error && /* @__PURE__ */ jsx("div", { className: "agno-msg__error", children: message.error }),
2682
- children
2705
+ children,
2706
+ isAgent && !hideActions && !message.streaming && message.content && /* @__PURE__ */ jsx(MessageActions, { message, classNames: cn, children: actions })
2683
2707
  ] }) })
2684
2708
  ]
2685
2709
  }
@@ -2739,7 +2763,7 @@ function MessageList({
2739
2763
  items.length === 0 ? /* @__PURE__ */ jsx("div", { className: cx("agno-list__empty", cn.empty), children: emptyState ?? "Start the conversation." }) : /* @__PURE__ */ jsxs("div", { className: "agno-list__inner", children: [
2740
2764
  items.map((m) => {
2741
2765
  const live = m.streaming && runStatus === "streaming" ? runActivity : void 0;
2742
- return renderMessage ? /* @__PURE__ */ jsx(React7.Fragment, { children: renderMessage(m, live) }, m.id) : /* @__PURE__ */ jsx(
2766
+ return renderMessage ? /* @__PURE__ */ jsx(React8.Fragment, { children: renderMessage(m, live) }, m.id) : /* @__PURE__ */ jsx(
2743
2767
  Message,
2744
2768
  {
2745
2769
  message: m,
@@ -3496,6 +3520,6 @@ function EventLog({
3496
3520
  ] });
3497
3521
  }
3498
3522
 
3499
- export { AgnoChat, AgnoMark, ArrowUp, BehindTheScenes, BookOpen, Box, Brain, ChatBubble, ChatInput, ChatLauncher, ChatProvider, ChatWindow, Check, ChevronDown, Citations, Close, Copy, EntityBadge, EntitySelector, EventLog, Favicon, FileAudio, FileIcon, FilePreview, FileType, FileVideo, Followups, Globe, GridLoader, HoverPreview, HumanInput, LinkIcon, LinkPreviewCard, Markdown, MemberResponses, Memory, Message, 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, faviconUrl, fileAccepted, getProviderIcon, hasBehindTheScenes, linkCitations, normalizeFollowups, quickPromptLabel, quickPromptText, sourceHost, sourcesFromMarkdown, useAgnoChat, useChatContext, useLinkComponent, useLinkPreview, useOptionalChatContext, useResolvedChat, useResolvedClassNames, useSources, withoutSourcesLine, writeClipboard };
3500
- //# sourceMappingURL=chunk-BZC2674Z.js.map
3501
- //# sourceMappingURL=chunk-BZC2674Z.js.map
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