@agno-hq/chat-react 0.3.0 → 0.3.2

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,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkROFIOWGX_cjs = require('./chunk-ROFIOWGX.cjs');
3
+ var chunk55HQJGLP_cjs = require('./chunk-55HQJGLP.cjs');
4
4
  var React7 = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var reactDom = require('react-dom');
@@ -18,7 +18,7 @@ function useAgnoChat(options) {
18
18
  const { entity, userId, onEvent, onSessionId } = options;
19
19
  const client = React7.useMemo(() => {
20
20
  if (options.client) return options.client;
21
- return new chunkROFIOWGX_cjs.AgnoClient({ baseUrl: options.baseUrl ?? "", headers: options.headers });
21
+ return new chunk55HQJGLP_cjs.AgnoClient({ baseUrl: options.baseUrl ?? "", headers: options.headers });
22
22
  }, [options.client, options.baseUrl, JSON.stringify(options.headers)]);
23
23
  const [messages, setMessages] = React7.useState(options.initialMessages ?? []);
24
24
  const [events, setEvents] = React7.useState([]);
@@ -106,7 +106,7 @@ function useAgnoChat(options) {
106
106
  writeEvents(chan, e);
107
107
  patchActive(chan, (m) => ({ ...m, events: [...m.events ?? [], e] }));
108
108
  onEvent?.(e);
109
- const label2 = chunkROFIOWGX_cjs.activityLabel(e);
109
+ const label2 = chunk55HQJGLP_cjs.activityLabel(e);
110
110
  if (label2) writeActivity(chan, label2);
111
111
  if (e.session_id && !chan?.park && e.session_id !== sessionIdRef.current) {
112
112
  sessionIdRef.current = e.session_id;
@@ -123,16 +123,16 @@ function useAgnoChat(options) {
123
123
  if (chan?.park) chan.park.runId = e.run_id;
124
124
  else runIdRef.current = e.run_id;
125
125
  }
126
- if (chunkROFIOWGX_cjs.isSubRunEvent(e)) {
126
+ if (chunk55HQJGLP_cjs.isSubRunEvent(e)) {
127
127
  const kind = entityRef.current?.type === "workflow" ? "executor" : "member";
128
- patchActive(chan, (m) => chunkROFIOWGX_cjs.applySubRunEvent(m, e, kind));
128
+ patchActive(chan, (m) => chunk55HQJGLP_cjs.applySubRunEvent(m, e, kind));
129
129
  return;
130
130
  }
131
- if (chunkROFIOWGX_cjs.isStepEvent(e)) {
132
- patchActive(chan, (m) => chunkROFIOWGX_cjs.applyStepEvent(m, e));
131
+ if (chunk55HQJGLP_cjs.isStepEvent(e)) {
132
+ patchActive(chan, (m) => chunk55HQJGLP_cjs.applyStepEvent(m, e));
133
133
  return;
134
134
  }
135
- if (chunkROFIOWGX_cjs.isStartedEvent(e)) {
135
+ if (chunk55HQJGLP_cjs.isStartedEvent(e)) {
136
136
  patchActive(chan, (m) => ({
137
137
  ...m,
138
138
  run_id: e.run_id ?? m.run_id,
@@ -141,22 +141,22 @@ function useAgnoChat(options) {
141
141
  }));
142
142
  return;
143
143
  }
144
- if (chunkROFIOWGX_cjs.isToolEvent(e)) {
145
- const incoming = chunkROFIOWGX_cjs.toolsFromEvent(e);
144
+ if (chunk55HQJGLP_cjs.isToolEvent(e)) {
145
+ const incoming = chunk55HQJGLP_cjs.toolsFromEvent(e);
146
146
  if (incoming.length) {
147
147
  patchActive(chan, (m) => {
148
148
  let tool_calls = m.tool_calls ?? [];
149
- for (const t of incoming) tool_calls = chunkROFIOWGX_cjs.mergeTool(tool_calls, t);
149
+ for (const t of incoming) tool_calls = chunk55HQJGLP_cjs.mergeTool(tool_calls, t);
150
150
  return { ...m, tool_calls };
151
151
  });
152
152
  }
153
153
  return;
154
154
  }
155
- if (chunkROFIOWGX_cjs.isContentEvent(e)) {
156
- patchActive(chan, (m) => chunkROFIOWGX_cjs.applyContentEvent(m, e));
155
+ if (chunk55HQJGLP_cjs.isContentEvent(e)) {
156
+ patchActive(chan, (m) => chunk55HQJGLP_cjs.applyContentEvent(m, e));
157
157
  return;
158
158
  }
159
- if (chunkROFIOWGX_cjs.isReasoningStepEvent(e)) {
159
+ if (chunk55HQJGLP_cjs.isReasoningStepEvent(e)) {
160
160
  const incoming = e.reasoning_steps ?? e.extra_data?.reasoning_steps ?? [];
161
161
  if (incoming.length) {
162
162
  patchActive(chan, (m) => ({
@@ -166,36 +166,36 @@ function useAgnoChat(options) {
166
166
  }
167
167
  return;
168
168
  }
169
- if (chunkROFIOWGX_cjs.isReasoningCompletedEvent(e)) {
169
+ if (chunk55HQJGLP_cjs.isReasoningCompletedEvent(e)) {
170
170
  const steps = e.reasoning_steps ?? e.extra_data?.reasoning_steps;
171
171
  if (steps?.length) patchActive(chan, (m) => ({ ...m, reasoning_steps: steps }));
172
172
  return;
173
173
  }
174
- if (chunkROFIOWGX_cjs.isFollowupsCompletedEvent(e)) {
174
+ if (chunk55HQJGLP_cjs.isFollowupsCompletedEvent(e)) {
175
175
  const followups = e.followups;
176
176
  if (followups?.length) patchActive(chan, (m) => ({ ...m, followups }));
177
177
  return;
178
178
  }
179
- if (chunkROFIOWGX_cjs.isPausedEvent(e)) {
179
+ if (chunk55HQJGLP_cjs.isPausedEvent(e)) {
180
180
  const requirements = e.requirements ?? [];
181
- const pausedTools2 = chunkROFIOWGX_cjs.toolsFromEvent(e);
181
+ const pausedTools2 = chunk55HQJGLP_cjs.toolsFromEvent(e);
182
182
  writeStatus(chan, "paused");
183
183
  writeActivity(chan, "Waiting for input");
184
184
  patchActive(chan, (m) => {
185
185
  let tool_calls = m.tool_calls ?? [];
186
- for (const t of pausedTools2) tool_calls = chunkROFIOWGX_cjs.mergeTool(tool_calls, t);
186
+ for (const t of pausedTools2) tool_calls = chunk55HQJGLP_cjs.mergeTool(tool_calls, t);
187
187
  return { ...m, status: "paused", streaming: false, requirements, tool_calls };
188
188
  });
189
189
  return;
190
190
  }
191
- if (chunkROFIOWGX_cjs.isCompletedEvent(e)) {
191
+ if (chunk55HQJGLP_cjs.isCompletedEvent(e)) {
192
192
  patchActive(chan, (m) => {
193
193
  const next = { ...m, streaming: false, status: "completed" };
194
194
  if (typeof e.content === "string" && e.content) next.content = e.content;
195
- const tools = chunkROFIOWGX_cjs.toolsFromEvent(e);
195
+ const tools = chunk55HQJGLP_cjs.toolsFromEvent(e);
196
196
  if (tools.length) {
197
197
  let tc = m.tool_calls ?? [];
198
- for (const t of tools) tc = chunkROFIOWGX_cjs.mergeTool(tc, t);
198
+ for (const t of tools) tc = chunk55HQJGLP_cjs.mergeTool(tc, t);
199
199
  next.tool_calls = tc;
200
200
  }
201
201
  if (e.reasoning_steps?.length) next.reasoning_steps = e.reasoning_steps;
@@ -209,12 +209,12 @@ function useAgnoChat(options) {
209
209
  });
210
210
  return;
211
211
  }
212
- if (chunkROFIOWGX_cjs.isCancelledEvent(e)) {
212
+ if (chunk55HQJGLP_cjs.isCancelledEvent(e)) {
213
213
  patchActive(chan, (m) => ({ ...m, streaming: false, status: "cancelled" }));
214
214
  writeStatus(chan, "cancelled");
215
215
  return;
216
216
  }
217
- if (chunkROFIOWGX_cjs.isErrorEvent(e)) {
217
+ if (chunk55HQJGLP_cjs.isErrorEvent(e)) {
218
218
  const msg = typeof e.content === "string" ? e.content : e.error || "Error during run";
219
219
  patchActive(chan, (m) => ({ ...m, streaming: false, status: "error", error: msg }));
220
220
  writeError(chan, msg);
@@ -483,7 +483,7 @@ function useAgnoChat(options) {
483
483
  setError(null);
484
484
  try {
485
485
  const runs = await client.getSessionRuns(ent.type, id, ent.db_id);
486
- setMessages(chunkROFIOWGX_cjs.sessionRunsToMessages(runs));
486
+ setMessages(chunk55HQJGLP_cjs.sessionRunsToMessages(runs));
487
487
  } catch (err) {
488
488
  setError(err instanceof Error ? err.message : String(err));
489
489
  }
@@ -583,6 +583,7 @@ function ChatProvider({
583
583
  renderMarkdown,
584
584
  resolveLinkPreview,
585
585
  codeCopy,
586
+ linkComponent,
586
587
  chat: externalChat,
587
588
  as,
588
589
  className,
@@ -593,8 +594,8 @@ function ChatProvider({
593
594
  const internal = useAgnoChat(externalChat ? { entity: null } : options);
594
595
  const chat = externalChat ?? internal;
595
596
  const value = React7.useMemo(
596
- () => ({ chat, classNames: classNames ?? {}, renderMarkdown, resolveLinkPreview, codeCopy }),
597
- [chat, classNames, renderMarkdown, resolveLinkPreview, codeCopy]
597
+ () => ({ chat, classNames: classNames ?? {}, renderMarkdown, resolveLinkPreview, codeCopy, linkComponent }),
598
+ [chat, classNames, renderMarkdown, resolveLinkPreview, codeCopy, linkComponent]
598
599
  );
599
600
  const Wrapper = as === false ? null : as ?? "div";
600
601
  return /* @__PURE__ */ jsxRuntime.jsx(ChatContext.Provider, { value, children: Wrapper ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -627,6 +628,9 @@ function useResolvedChat(explicit) {
627
628
  function useCodeCopy() {
628
629
  return useOptionalChatContext()?.codeCopy;
629
630
  }
631
+ function useLinkComponent() {
632
+ return useOptionalChatContext()?.linkComponent;
633
+ }
630
634
  function useResolvedClassNames(explicit) {
631
635
  const ctx = useOptionalChatContext();
632
636
  return React7.useMemo(() => ({ ...ctx?.classNames, ...explicit }), [ctx?.classNames, explicit]);
@@ -639,11 +643,13 @@ var ChevronDown = icon(lucideReact.ChevronDown);
639
643
  var ArrowUp = icon(lucideReact.ArrowUp);
640
644
  var Paperclip = icon(lucideReact.Paperclip);
641
645
  var FileIcon = icon(lucideReact.File);
646
+ var FileType = icon(lucideReact.FileType2);
642
647
  var FileAudio = icon(lucideReact.FileAudio);
643
648
  var FileVideo = icon(lucideReact.FileVideo);
644
649
  var Wrench = icon(lucideReact.Wrench);
645
650
  var BookOpen = icon(lucideReact.BookOpen);
646
651
  var Globe = icon(lucideReact.Globe);
652
+ var LinkIcon = icon(lucideReact.Link);
647
653
  var Brain = icon(lucideReact.Brain);
648
654
  var Box = icon(lucideReact.Box);
649
655
  var Plus = icon(lucideReact.Plus);
@@ -656,9 +662,7 @@ var Pulse = icon(lucideReact.Activity);
656
662
  var Trash = icon(lucideReact.Trash2);
657
663
  var ChatBubble = icon(lucideReact.MessageSquare);
658
664
  var Spinner = icon(lucideReact.LoaderCircle, 12);
659
- function Stop({ size = 16, className }) {
660
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { size, className, fill: "currentColor", strokeWidth: 0 });
661
- }
665
+ var Stop = icon(lucideReact.Square, 10.67);
662
666
  function AgnoMark({ size = 24, className }) {
663
667
  return /* @__PURE__ */ jsxRuntime.jsxs(
664
668
  "svg",
@@ -846,7 +850,16 @@ function ChatLauncher({
846
850
  function markFor(type) {
847
851
  if (type.startsWith("audio/")) return FileAudio;
848
852
  if (type.startsWith("video/")) return FileVideo;
849
- return FileIcon;
853
+ return FileType;
854
+ }
855
+ function formatSize(bytes) {
856
+ return bytes >= 1024 * 1024 ? `${Math.round(bytes / (1024 * 1024) * 10) / 10}MB` : `${Math.max(1, Math.round(bytes / 1024))}KB`;
857
+ }
858
+ function kindOf(file) {
859
+ const dot = file.name.lastIndexOf(".");
860
+ if (dot > 0 && dot < file.name.length - 1) return file.name.slice(dot + 1);
861
+ const subtype = file.type.split("/")[1];
862
+ return subtype || "file";
850
863
  }
851
864
  function Item({ file, onRemove }) {
852
865
  const isImage = file.type.startsWith("image/");
@@ -861,15 +874,19 @@ function Item({ file, onRemove }) {
861
874
  };
862
875
  }, [file, isImage]);
863
876
  const Mark = markFor(file.type);
864
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-file", children: [
865
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "agno-file__remove", onClick: onRemove, "aria-label": `Remove ${file.name}`, children: /* @__PURE__ */ jsxRuntime.jsx(Close, { size: 12 }) }),
866
- isImage && url ? /* @__PURE__ */ jsxRuntime.jsx("img", { className: "agno-file__thumb", src: url, alt: file.name }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-file__card", children: [
877
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("agno-file", isImage && url ? "agno-file--image" : "agno-file--card"), children: [
878
+ isImage && url ? /* @__PURE__ */ jsxRuntime.jsx("img", { className: "agno-file__thumb", src: url, alt: file.name }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
867
879
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-file__mark", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { size: 16 }) }),
868
880
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "agno-file__meta", children: [
869
881
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-file__name", title: file.name, children: file.name }),
870
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-file__type", children: file.type || "file" })
882
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "agno-file__type", children: [
883
+ kindOf(file),
884
+ " \u2022 ",
885
+ formatSize(file.size)
886
+ ] })
871
887
  ] })
872
- ] })
888
+ ] }),
889
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "agno-file__remove", onClick: onRemove, "aria-label": `Remove ${file.name}`, children: /* @__PURE__ */ jsxRuntime.jsx(Close, { size: 12 }) })
873
890
  ] });
874
891
  }
875
892
  function FilePreview({ files, onRemove, onClear, className }) {
@@ -879,20 +896,51 @@ function FilePreview({ files, onRemove, onClear, className }) {
879
896
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "agno-files__count", children: [
880
897
  files.length,
881
898
  " ",
882
- files.length > 1 ? "files" : "file",
883
- " attached"
899
+ files.length > 1 ? "attachments" : "attachment"
884
900
  ] }),
885
901
  onClear && /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "agno-files__clear", onClick: onClear, children: [
886
- /* @__PURE__ */ jsxRuntime.jsx(Close, { size: 12 }),
887
- "clear ",
888
- files.length > 1 ? "all" : ""
902
+ /* @__PURE__ */ jsxRuntime.jsx(Close, { size: 14 }),
903
+ "clear all"
889
904
  ] })
890
905
  ] }),
891
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-files__row", children: files.map((file, i) => /* @__PURE__ */ jsxRuntime.jsx(Item, { file, onRemove: () => onRemove(i) }, `${file.name}-${file.lastModified}-${i}`)) })
906
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-files__strip", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-files__row", children: files.map((file, i) => /* @__PURE__ */ jsxRuntime.jsx(Item, { file, onRemove: () => onRemove(i) }, `${file.name}-${file.lastModified}-${i}`)) }) })
892
907
  ] });
893
908
  }
894
- var MIN_HEIGHT = 31;
895
- var MAX_HEIGHT = 213;
909
+ var BOUNDS = {
910
+ dock: { min: 31, max: 213 },
911
+ compact: { min: 24, max: 120 }
912
+ };
913
+ function fileAccepted(file, accept) {
914
+ if (!accept) return true;
915
+ const name = file.name.toLowerCase();
916
+ const type = file.type.toLowerCase();
917
+ return accept.split(",").map((rule) => rule.trim().toLowerCase()).filter(Boolean).some((rule) => {
918
+ if (rule.startsWith(".")) return name.endsWith(rule);
919
+ if (rule.endsWith("/*")) return type.startsWith(rule.slice(0, -1));
920
+ return type === rule;
921
+ });
922
+ }
923
+ function admitFiles(current, incoming, limits) {
924
+ const { accept, maxFiles, maxFileSize, maxTotalSize } = limits;
925
+ const files = [...current];
926
+ let total = current.reduce((sum, f) => sum + f.size, 0);
927
+ let error = null;
928
+ const refuse = (reason) => {
929
+ error ?? (error = reason);
930
+ };
931
+ for (const file of incoming) {
932
+ if (!fileAccepted(file, accept)) refuse("Cannot add this file type");
933
+ else if (maxFileSize != null && file.size > maxFileSize) refuse(`Cannot add files over ${formatSize(maxFileSize)}`);
934
+ else if (maxFiles != null && files.length >= maxFiles) refuse(`Cannot add more than ${maxFiles} attachments`);
935
+ else if (maxTotalSize != null && total + file.size > maxTotalSize) refuse("Cannot add more files");
936
+ else {
937
+ files.push(file);
938
+ total += file.size;
939
+ }
940
+ }
941
+ return { files, error };
942
+ }
943
+ var hasFiles = (e) => Array.from(e.dataTransfer.types).includes("Files");
896
944
  function ChatInput({
897
945
  onSend,
898
946
  onStop,
@@ -900,6 +948,19 @@ function ChatInput({
900
948
  busy,
901
949
  placeholder,
902
950
  allowFiles = false,
951
+ compact = false,
952
+ accept,
953
+ maxFiles,
954
+ maxFileSize,
955
+ maxTotalSize,
956
+ value: controlled,
957
+ onValueChange,
958
+ textareaRef: externalRef,
959
+ textareaProps,
960
+ renderTextarea,
961
+ above,
962
+ below,
963
+ dropLabel = "Drop files to attach",
903
964
  leading,
904
965
  trailing,
905
966
  className,
@@ -907,109 +968,216 @@ function ChatInput({
907
968
  }) {
908
969
  const ctx = useOptionalChatContext();
909
970
  const cn = useResolvedClassNames(classNames);
910
- const [value, setValue] = React7.useState("");
911
- const [files, setFiles] = React7.useState([]);
971
+ const [internal, setInternal] = React7.useState("");
972
+ const value = controlled ?? internal;
973
+ const setValue = (next) => {
974
+ if (controlled === void 0) setInternal(next);
975
+ onValueChange?.(next);
976
+ };
977
+ const [files, setFilesState] = React7.useState([]);
978
+ const filesRef = React7.useRef([]);
979
+ const setFiles = (next) => {
980
+ filesRef.current = next;
981
+ setFilesState(next);
982
+ };
983
+ const [fileError, setFileError] = React7.useState(null);
984
+ const [dragging, setDragging] = React7.useState(false);
985
+ const dragDepth = React7.useRef(0);
912
986
  const fileRef = React7.useRef(null);
913
987
  const textareaRef = React7.useRef(null);
988
+ const setTextareaRef = React7.useCallback(
989
+ (el2) => {
990
+ textareaRef.current = el2;
991
+ if (typeof externalRef === "function") externalRef(el2);
992
+ else if (externalRef) externalRef.current = el2;
993
+ },
994
+ [externalRef]
995
+ );
914
996
  const adjustHeight = React7.useCallback(() => {
915
997
  const el2 = textareaRef.current;
916
- if (!el2) return;
917
- el2.style.height = `${MIN_HEIGHT}px`;
918
- el2.style.height = `${Math.min(Math.max(el2.scrollHeight, MIN_HEIGHT), MAX_HEIGHT)}px`;
919
- }, []);
998
+ if (!el2 || renderTextarea) return;
999
+ const { min, max } = compact ? BOUNDS.compact : BOUNDS.dock;
1000
+ el2.style.height = `${min}px`;
1001
+ el2.style.height = `${Math.min(Math.max(el2.scrollHeight, min), max)}px`;
1002
+ }, [renderTextarea, compact]);
920
1003
  React7.useEffect(adjustHeight, [value, adjustHeight]);
921
1004
  const send = onSend ?? ((message, attached) => void ctx?.chat.sendMessage(message, attached ? { files: attached } : void 0));
922
1005
  const stop = onStop ?? (ctx ? () => void ctx.chat.cancel() : void 0);
923
1006
  const isBusy = busy ?? ctx?.chat.isStreaming ?? false;
924
1007
  const isDisabled = disabled ?? ctx?.chat.isPaused ?? false;
925
- const submit = () => {
1008
+ const limits = { accept, maxFiles, maxFileSize, maxTotalSize };
1009
+ const addFiles = (incoming) => {
1010
+ if (!incoming.length) return;
1011
+ const next = admitFiles(filesRef.current, incoming, limits);
1012
+ setFiles(next.files);
1013
+ setFileError(next.error);
1014
+ if (fileRef.current) fileRef.current.value = "";
1015
+ };
1016
+ const submit = async () => {
926
1017
  const text = value.trim();
927
1018
  if (!text && files.length === 0) return;
928
- send(text, files.length ? files : void 0);
1019
+ const sent = files.length ? files : void 0;
1020
+ const result = await send(text, sent);
1021
+ if (result === false) return;
929
1022
  setValue("");
930
1023
  setFiles([]);
1024
+ setFileError(null);
931
1025
  };
932
1026
  const canSend = !isDisabled && !isBusy && (Boolean(value.trim()) || files.length > 0);
933
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx("agno-input", cn.input, className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-input__dock", children: [
1027
+ const onKeyDown = (e) => {
1028
+ textareaProps?.onKeyDown?.(e);
1029
+ if (e.defaultPrevented) return;
1030
+ if (e.key === "Enter" && !e.nativeEvent.isComposing && !e.shiftKey) {
1031
+ e.preventDefault();
1032
+ if (canSend) void submit();
1033
+ }
1034
+ };
1035
+ const onDragEnter = (e) => {
1036
+ if (!allowFiles || !hasFiles(e)) return;
1037
+ e.preventDefault();
1038
+ dragDepth.current += 1;
1039
+ setDragging(true);
1040
+ };
1041
+ const onDragOver = (e) => {
1042
+ if (!allowFiles || !hasFiles(e)) return;
1043
+ e.preventDefault();
1044
+ e.dataTransfer.dropEffect = "copy";
1045
+ };
1046
+ const onDragLeave = (e) => {
1047
+ if (!allowFiles || dragDepth.current === 0) return;
1048
+ e.preventDefault();
1049
+ dragDepth.current = Math.max(0, dragDepth.current - 1);
1050
+ if (dragDepth.current === 0) setDragging(false);
1051
+ };
1052
+ const onDrop = (e) => {
1053
+ if (!allowFiles || !hasFiles(e)) return;
1054
+ e.preventDefault();
1055
+ dragDepth.current = 0;
1056
+ setDragging(false);
1057
+ addFiles(Array.from(e.dataTransfer.files));
1058
+ textareaRef.current?.focus();
1059
+ };
1060
+ const fieldProps = {
1061
+ rows: 1,
1062
+ ...textareaProps,
1063
+ ref: setTextareaRef,
1064
+ className: cx("agno-input__textarea", cn.textarea, textareaProps?.className),
1065
+ value,
1066
+ placeholder: placeholder ?? (isBusy ? "Running..." : "Ask anything..."),
1067
+ disabled: isDisabled,
1068
+ onChange: (e) => {
1069
+ setValue(e.target.value);
1070
+ textareaProps?.onChange?.(e);
1071
+ },
1072
+ onKeyDown
1073
+ };
1074
+ const iconSize = compact ? 14 : 16;
1075
+ const field = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-input__field", children: renderTextarea ? renderTextarea(fieldProps) : /* @__PURE__ */ jsxRuntime.jsx("textarea", { ...fieldProps }) });
1076
+ const attach = allowFiles && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
934
1077
  /* @__PURE__ */ jsxRuntime.jsx(
935
- FilePreview,
1078
+ "button",
936
1079
  {
937
- files,
938
- onRemove: (i) => setFiles((prev) => prev.filter((_, j) => j !== i)),
939
- onClear: () => setFiles([]),
940
- className: cn.files
1080
+ type: "button",
1081
+ className: cx("agno-btn", compact ? "agno-btn--ghost" : "agno-btn--outline", "agno-btn--icon", cn.attachButton),
1082
+ onClick: () => fileRef.current?.click(),
1083
+ disabled: isDisabled,
1084
+ "aria-label": files.length ? `Attach files; ${files.length} attached` : "Attach files",
1085
+ title: files.length ? files.map((f) => f.name).join(", ") : void 0,
1086
+ children: /* @__PURE__ */ jsxRuntime.jsx(Paperclip, { size: iconSize })
941
1087
  }
942
1088
  ),
943
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-input__field", children: /* @__PURE__ */ jsxRuntime.jsx(
944
- "textarea",
1089
+ /* @__PURE__ */ jsxRuntime.jsx(
1090
+ "input",
945
1091
  {
946
- ref: textareaRef,
947
- className: cx("agno-input__textarea", cn.textarea),
948
- value,
949
- placeholder: placeholder ?? (isBusy ? "Running..." : "Ask anything..."),
950
- disabled: isDisabled,
951
- rows: 1,
952
- onChange: (e) => setValue(e.target.value),
953
- onKeyDown: (e) => {
954
- if (e.key === "Enter" && !e.nativeEvent.isComposing && !e.shiftKey) {
955
- e.preventDefault();
956
- if (canSend) submit();
957
- }
958
- }
1092
+ ref: fileRef,
1093
+ type: "file",
1094
+ multiple: true,
1095
+ hidden: true,
1096
+ accept,
1097
+ onChange: (e) => addFiles(Array.from(e.target.files ?? []))
959
1098
  }
960
- ) }),
961
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("agno-input__row", cn.inputRow), children: [
962
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-input__actions", children: [
963
- leading,
964
- allowFiles && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
965
- /* @__PURE__ */ jsxRuntime.jsx(
966
- "button",
967
- {
968
- type: "button",
969
- className: cx("agno-btn", "agno-btn--outline", "agno-btn--icon", cn.attachButton),
970
- onClick: () => fileRef.current?.click(),
971
- disabled: isDisabled,
972
- "aria-label": "Attach files",
973
- children: /* @__PURE__ */ jsxRuntime.jsx(Paperclip, { size: 16 })
974
- }
975
- ),
976
- /* @__PURE__ */ jsxRuntime.jsx(
977
- "input",
978
- {
979
- ref: fileRef,
980
- type: "file",
981
- multiple: true,
982
- hidden: true,
983
- onChange: (e) => setFiles((prev) => [...prev, ...Array.from(e.target.files ?? [])])
984
- }
985
- )
986
- ] })
987
- ] }),
988
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-input__actions", children: [
989
- trailing,
990
- isBusy && stop ? /* @__PURE__ */ jsxRuntime.jsx(
991
- "button",
992
- {
993
- type: "button",
994
- className: cx("agno-btn", "agno-btn--destructive", "agno-btn--icon", cn.stopButton),
995
- onClick: stop,
996
- "aria-label": "Stop",
997
- children: /* @__PURE__ */ jsxRuntime.jsx(Stop, { size: 16 })
998
- }
999
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1000
- "button",
1099
+ )
1100
+ ] });
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
+ )
1113
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1114
+ "button",
1115
+ {
1116
+ type: "button",
1117
+ className: cx("agno-btn", "agno-btn--icon", cn.sendButton),
1118
+ onClick: () => void submit(),
1119
+ disabled: !canSend,
1120
+ "aria-label": "Send",
1121
+ children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUp, { size: iconSize })
1122
+ }
1123
+ );
1124
+ return /* @__PURE__ */ jsxRuntime.jsx(
1125
+ "div",
1126
+ {
1127
+ className: cx("agno-input", compact && "agno-input--compact", cn.input, className),
1128
+ "data-dragging": dragging ? "true" : void 0,
1129
+ onDragEnter,
1130
+ onDragOver,
1131
+ onDragLeave,
1132
+ onDrop,
1133
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-input__dock", children: [
1134
+ dragging && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("agno-input__drop", cn.dropOverlay), "aria-hidden": true, children: [
1135
+ /* @__PURE__ */ jsxRuntime.jsx(Paperclip, { size: 16 }),
1136
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: dropLabel })
1137
+ ] }),
1138
+ above,
1139
+ /* @__PURE__ */ jsxRuntime.jsx(
1140
+ FilePreview,
1001
1141
  {
1002
- type: "button",
1003
- className: cx("agno-btn", "agno-btn--icon", cn.sendButton),
1004
- onClick: submit,
1005
- disabled: !canSend,
1006
- "aria-label": "Send",
1007
- children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUp, { size: 16 })
1142
+ files,
1143
+ onRemove: (i) => {
1144
+ setFiles(filesRef.current.filter((_, j) => j !== i));
1145
+ setFileError(null);
1146
+ },
1147
+ onClear: () => {
1148
+ setFiles([]);
1149
+ setFileError(null);
1150
+ },
1151
+ className: cn.files
1008
1152
  }
1009
- )
1153
+ ),
1154
+ fileError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx("agno-input__error", cn.fileError), role: "alert", children: fileError }),
1155
+ compact ? (
1156
+ // One line: the field, then every control beside it.
1157
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("agno-input__row", cn.inputRow), children: [
1158
+ leading,
1159
+ field,
1160
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-input__actions", children: [
1161
+ attach,
1162
+ trailing,
1163
+ primary
1164
+ ] })
1165
+ ] })
1166
+ ) : field,
1167
+ below,
1168
+ !compact && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("agno-input__row", cn.inputRow), children: [
1169
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-input__actions", children: [
1170
+ leading,
1171
+ attach
1172
+ ] }),
1173
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-input__actions", children: [
1174
+ trailing,
1175
+ primary
1176
+ ] })
1177
+ ] })
1010
1178
  ] })
1011
- ] })
1012
- ] }) });
1179
+ }
1180
+ );
1013
1181
  }
1014
1182
  function normalizeFollowups(items) {
1015
1183
  if (!items?.length) return [];
@@ -1532,20 +1700,15 @@ var PREVIEW_WIDTH = 320;
1532
1700
  var GAP = 8;
1533
1701
  var OPEN_DELAY = 140;
1534
1702
  var CLOSE_DELAY = 120;
1535
- function usePlacement(anchor, open) {
1703
+ function usePlacement(anchor, open, { width = PREVIEW_WIDTH, align = "center" } = {}) {
1536
1704
  const [placement, setPlacement] = React7.useState(null);
1537
1705
  useIsomorphicLayoutEffect(() => {
1538
1706
  if (!open || !anchor) return;
1539
1707
  const place = () => {
1540
1708
  const rect = anchor.getBoundingClientRect();
1541
1709
  const side = rect.top > 220 ? "top" : "bottom";
1542
- const left = Math.max(
1543
- GAP,
1544
- Math.min(
1545
- rect.left + rect.width / 2 - PREVIEW_WIDTH / 2,
1546
- window.innerWidth - PREVIEW_WIDTH - GAP
1547
- )
1548
- );
1710
+ const wanted = align === "center" ? rect.left + rect.width / 2 - width / 2 : rect.left;
1711
+ const left = Math.max(GAP, Math.min(wanted, window.innerWidth - width - GAP));
1549
1712
  setPlacement({
1550
1713
  top: side === "top" ? rect.top - GAP : rect.bottom + GAP,
1551
1714
  left,
@@ -1559,7 +1722,7 @@ function usePlacement(anchor, open) {
1559
1722
  window.removeEventListener("scroll", place, true);
1560
1723
  window.removeEventListener("resize", place);
1561
1724
  };
1562
- }, [anchor, open]);
1725
+ }, [anchor, open, width, align]);
1563
1726
  return placement;
1564
1727
  }
1565
1728
  function HoverPreview({
@@ -1661,16 +1824,20 @@ function labelOf(children) {
1661
1824
  }
1662
1825
  function CitationMarker({
1663
1826
  source,
1664
- className
1827
+ className,
1828
+ Link
1665
1829
  }) {
1666
- return /* @__PURE__ */ jsxRuntime.jsx(HoverPreview, { source, className: "agno-cite__wrap", children: /* @__PURE__ */ jsxRuntime.jsx(
1830
+ const props = {
1831
+ className: cx("agno-cite", className),
1832
+ href: source.url ?? `#${source.anchorId}`,
1833
+ "aria-label": `Source ${source.index}: ${source.title}`
1834
+ };
1835
+ 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(
1667
1836
  "a",
1668
1837
  {
1669
- className: cx("agno-cite", className),
1670
- href: source.url ?? `#${source.anchorId}`,
1838
+ ...props,
1671
1839
  target: source.url ? "_blank" : void 0,
1672
1840
  rel: source.url ? "noreferrer noopener" : void 0,
1673
- "aria-label": `Source ${source.index}: ${source.title}`,
1674
1841
  children: source.index
1675
1842
  }
1676
1843
  ) });
@@ -1769,8 +1936,8 @@ function elementsFor(ctx) {
1769
1936
  ...rest
1770
1937
  }) {
1771
1938
  const cited = citationForLink(labelOf(children), href, ctx);
1772
- if (cited) return /* @__PURE__ */ jsxRuntime.jsx(CitationMarker, { source: cited, className: ctx.markerClass });
1773
- const link = /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noreferrer noopener", ...rest, children });
1939
+ if (cited) return /* @__PURE__ */ jsxRuntime.jsx(CitationMarker, { source: cited, className: ctx.markerClass, Link: ctx.Link });
1940
+ const link = ctx.Link && href ? /* @__PURE__ */ jsxRuntime.jsx(ctx.Link, { href, ...rest, children }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noreferrer noopener", ...rest, children });
1774
1941
  const source = sourceForUrl(href, ctx.sources);
1775
1942
  if (!href || !/^https?:\/\//i.test(href) || !source && !ctx.canResolve) return link;
1776
1943
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1836,23 +2003,27 @@ function Markdown({
1836
2003
  sources,
1837
2004
  streaming,
1838
2005
  codeCopy,
2006
+ linkComponent,
1839
2007
  options
1840
2008
  }) {
1841
2009
  const fromMessage = useSources();
1842
2010
  const cn = useResolvedClassNames();
1843
2011
  const canResolve = Boolean(useLinkPreviewResolver());
1844
2012
  const fromProvider = useCodeCopy();
2013
+ const providerLink = useLinkComponent();
1845
2014
  const cited = sources ?? fromMessage;
1846
2015
  const copy = codeCopy ?? fromProvider ?? true;
2016
+ const Link = linkComponent ?? providerLink;
1847
2017
  const components = React7.useMemo(
1848
2018
  () => elementsFor({
1849
2019
  sources: cited,
1850
2020
  canResolve,
1851
2021
  markerClass: cn.citationMarker,
1852
2022
  copyClass: cn.copyButton,
1853
- codeCopy: copy
2023
+ codeCopy: copy,
2024
+ Link
1854
2025
  }),
1855
- [cited, canResolve, cn.citationMarker, cn.copyButton, copy]
2026
+ [cited, canResolve, cn.citationMarker, cn.copyButton, copy, Link]
1856
2027
  );
1857
2028
  const text = React7.useMemo(() => linkCitations(content, cited), [content, cited]);
1858
2029
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1936,7 +2107,7 @@ function isNoiseEvent(e) {
1936
2107
  }
1937
2108
  var isMemoryEvent = (e) => eventName(e).includes("MemoryUpdate");
1938
2109
  var isMemoryCompleted = (e) => eventName(e).includes("MemoryUpdateCompleted");
1939
- var isReasoningEvent = (e) => chunkROFIOWGX_cjs.isReasoningStepEvent(e) || chunkROFIOWGX_cjs.isReasoningCompletedEvent(e) || eventName(e).includes("ReasoningStarted");
2110
+ var isReasoningEvent = (e) => chunk55HQJGLP_cjs.isReasoningStepEvent(e) || chunk55HQJGLP_cjs.isReasoningCompletedEvent(e) || eventName(e).includes("ReasoningStarted");
1940
2111
  function formatDuration(seconds) {
1941
2112
  return seconds < 10 ? `${seconds.toFixed(1)}s` : `${Math.round(seconds)}s`;
1942
2113
  }
@@ -1970,14 +2141,14 @@ function stepsFromEvents(message, { hideReasoning, hideTools }) {
1970
2141
  if (member) put(`member:${runId}`, { kind: "member", id: `member-${runId}`, member });
1971
2142
  continue;
1972
2143
  }
1973
- if (chunkROFIOWGX_cjs.isToolEvent(e)) {
2144
+ if (chunk55HQJGLP_cjs.isToolEvent(e)) {
1974
2145
  if (hideTools) continue;
1975
- for (const tool of chunkROFIOWGX_cjs.toolsFromEvent(e)) {
2146
+ for (const tool of chunk55HQJGLP_cjs.toolsFromEvent(e)) {
1976
2147
  const key = `tool:${tool.tool_call_id ?? tool.tool_name}`;
1977
2148
  const at = indexOf.get(key);
1978
2149
  const previous = at != null ? steps[at].tool : void 0;
1979
2150
  const merged = { ...previous, ...tool };
1980
- if (!chunkROFIOWGX_cjs.isToolCompletedEvent(e) && previous?.result != null) merged.result = previous.result;
2151
+ if (!chunk55HQJGLP_cjs.isToolCompletedEvent(e) && previous?.result != null) merged.result = previous.result;
1981
2152
  put(key, { kind: "tool", id: key, tool: merged });
1982
2153
  }
1983
2154
  continue;
@@ -1988,7 +2159,7 @@ function stepsFromEvents(message, { hideReasoning, hideTools }) {
1988
2159
  const at = indexOf.get(key);
1989
2160
  const previous = at != null ? steps[at].steps : [];
1990
2161
  const incoming = e.reasoning_steps ?? e.extra_data?.reasoning_steps ?? [];
1991
- const completed = chunkROFIOWGX_cjs.isReasoningCompletedEvent(e);
2162
+ const completed = chunk55HQJGLP_cjs.isReasoningCompletedEvent(e);
1992
2163
  put(key, {
1993
2164
  kind: "reasoning",
1994
2165
  id: key,
@@ -2023,7 +2194,7 @@ function stepsFromEvents(message, { hideReasoning, hideTools }) {
2023
2194
  label: "Run Continued",
2024
2195
  icon: "continued"
2025
2196
  });
2026
- } else if (chunkROFIOWGX_cjs.isCompletedEvent(e)) {
2197
+ } else if (chunk55HQJGLP_cjs.isCompletedEvent(e)) {
2027
2198
  put(`completed:${runKey}`, {
2028
2199
  kind: "status",
2029
2200
  id: `completed-${runKey}`,
@@ -2031,16 +2202,16 @@ function stepsFromEvents(message, { hideReasoning, hideTools }) {
2031
2202
  detail: durationOf(e),
2032
2203
  icon: "run"
2033
2204
  });
2034
- } else if (chunkROFIOWGX_cjs.isPausedEvent(e)) {
2205
+ } else if (chunk55HQJGLP_cjs.isPausedEvent(e)) {
2035
2206
  put(`paused:${runKey}`, { kind: "status", id: `paused-${runKey}`, label: "Run Paused", icon: "run" });
2036
- } else if (chunkROFIOWGX_cjs.isCancelledEvent(e)) {
2207
+ } else if (chunk55HQJGLP_cjs.isCancelledEvent(e)) {
2037
2208
  put(`cancelled:${runKey}`, {
2038
2209
  kind: "status",
2039
2210
  id: `cancelled-${runKey}`,
2040
2211
  label: "Run Cancelled",
2041
2212
  icon: "run"
2042
2213
  });
2043
- } else if (chunkROFIOWGX_cjs.isErrorEvent(e)) {
2214
+ } else if (chunk55HQJGLP_cjs.isErrorEvent(e)) {
2044
2215
  const detail = typeof e.content === "string" ? e.content : e.error;
2045
2216
  put(`error:${runKey}`, { kind: "status", id: `error-${runKey}`, label: detail || "Run Error", icon: "run" });
2046
2217
  }
@@ -2088,7 +2259,7 @@ function runDuration(message) {
2088
2259
  function liveActivity(message) {
2089
2260
  const events = message.events ?? [];
2090
2261
  for (let i = events.length - 1; i >= 0; i--) {
2091
- const label2 = chunkROFIOWGX_cjs.activityLabel(events[i]);
2262
+ const label2 = chunk55HQJGLP_cjs.activityLabel(events[i]);
2092
2263
  if (label2) return label2;
2093
2264
  }
2094
2265
  return message.activity ?? null;
@@ -2263,12 +2434,25 @@ function SourceCard({
2263
2434
  className
2264
2435
  }) {
2265
2436
  const cn = useResolvedClassNames();
2437
+ const Link = useLinkComponent();
2266
2438
  const { preview } = useLinkPreview(source.url, false);
2267
2439
  const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2268
- /* @__PURE__ */ jsxRuntime.jsx(Favicon, { url: preview?.favicon ?? source.url, kind: source.kind }),
2269
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-source__title", children: preview?.title ?? source.title })
2440
+ /* @__PURE__ */ jsxRuntime.jsx(
2441
+ Favicon,
2442
+ {
2443
+ className: "agno-source__icon",
2444
+ url: preview?.favicon ?? source.url,
2445
+ kind: source.kind,
2446
+ size: 24
2447
+ }
2448
+ ),
2449
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-source__title", children: preview?.title ?? source.title }),
2450
+ source.url && /* @__PURE__ */ jsxRuntime.jsx(LinkIcon, { className: "agno-source__link" })
2270
2451
  ] });
2271
2452
  const classes = cx("agno-source", `agno-source--${source.kind}`, cn.sourceCard, className);
2453
+ if (source.url && Link) {
2454
+ return /* @__PURE__ */ jsxRuntime.jsx(Link, { id: source.anchorId, className: classes, href: source.url, title: source.url, children: body });
2455
+ }
2272
2456
  return source.url ? /* @__PURE__ */ jsxRuntime.jsx(
2273
2457
  "a",
2274
2458
  {
@@ -2282,33 +2466,118 @@ function SourceCard({
2282
2466
  }
2283
2467
  ) : /* @__PURE__ */ jsxRuntime.jsx("div", { id: source.anchorId, className: classes, children: body });
2284
2468
  }
2469
+ var LIST_WIDTH = 240;
2470
+ function SourcesOverflow({ sources }) {
2471
+ const [open, setOpen] = React7.useState(false);
2472
+ const [anchor, setAnchor] = React7.useState(null);
2473
+ const timer = React7.useRef(null);
2474
+ const id = React7.useId();
2475
+ const placement = usePlacement(anchor, open, { width: LIST_WIDTH, align: "start" });
2476
+ const schedule = React7.useCallback((next) => {
2477
+ if (timer.current) clearTimeout(timer.current);
2478
+ timer.current = setTimeout(() => setOpen(next), next ? OPEN_DELAY : CLOSE_DELAY);
2479
+ }, []);
2480
+ React7.useEffect(
2481
+ () => () => {
2482
+ if (timer.current) clearTimeout(timer.current);
2483
+ },
2484
+ []
2485
+ );
2486
+ React7.useEffect(() => {
2487
+ if (!open) return;
2488
+ const onKey = (e) => {
2489
+ if (e.key === "Escape") setOpen(false);
2490
+ };
2491
+ document.addEventListener("keydown", onKey);
2492
+ return () => document.removeEventListener("keydown", onKey);
2493
+ }, [open]);
2494
+ const [mounted, setMounted] = React7.useState(false);
2495
+ React7.useEffect(() => setMounted(true), []);
2496
+ const light = anchor?.closest(".agno-light") ? "agno-light" : void 0;
2497
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2498
+ "span",
2499
+ {
2500
+ className: "agno-sources__overflow",
2501
+ ref: setAnchor,
2502
+ onMouseEnter: () => schedule(true),
2503
+ onMouseLeave: () => schedule(false),
2504
+ children: [
2505
+ /* @__PURE__ */ jsxRuntime.jsxs(
2506
+ "button",
2507
+ {
2508
+ type: "button",
2509
+ className: "agno-sources__more",
2510
+ "aria-label": `${sources.length} more sources`,
2511
+ "aria-expanded": open,
2512
+ "aria-controls": open ? id : void 0,
2513
+ onClick: () => setOpen((v) => !v),
2514
+ onFocus: () => setOpen(true),
2515
+ onBlur: () => schedule(false),
2516
+ children: [
2517
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "agno-sources__stack", "aria-hidden": true, children: sources.slice(0, 3).map((source) => /* @__PURE__ */ jsxRuntime.jsx(
2518
+ Favicon,
2519
+ {
2520
+ className: "agno-sources__stack-icon",
2521
+ url: source.url,
2522
+ kind: source.kind,
2523
+ size: 24
2524
+ },
2525
+ source.anchorId
2526
+ )) }),
2527
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "agno-sources__more-label", children: [
2528
+ "+",
2529
+ sources.length,
2530
+ " more"
2531
+ ] })
2532
+ ]
2533
+ }
2534
+ ),
2535
+ mounted && open && placement && reactDom.createPortal(
2536
+ /* @__PURE__ */ jsxRuntime.jsx(
2537
+ "div",
2538
+ {
2539
+ id,
2540
+ role: "group",
2541
+ "aria-label": "More sources",
2542
+ className: cx("agno-sources__list", `agno-sources__list--${placement.side}`, light),
2543
+ style: { top: placement.top, left: placement.left, width: LIST_WIDTH },
2544
+ onMouseEnter: () => schedule(true),
2545
+ onMouseLeave: () => schedule(false),
2546
+ onFocus: () => schedule(true),
2547
+ onBlur: () => schedule(false),
2548
+ children: sources.map((source) => /* @__PURE__ */ jsxRuntime.jsx(SourceCard, { source, className: "agno-source--row" }, source.anchorId))
2549
+ }
2550
+ ),
2551
+ document.body
2552
+ )
2553
+ ]
2554
+ }
2555
+ );
2556
+ }
2285
2557
  function Citations({
2286
2558
  references,
2287
2559
  citations,
2288
2560
  sources: given,
2289
- title = "Sources",
2290
- max = 4,
2561
+ title = "Sources used",
2562
+ max = 3,
2291
2563
  className,
2292
2564
  classNames
2293
2565
  }) {
2294
2566
  const cn = useResolvedClassNames(classNames);
2295
2567
  const uid = React7.useId();
2296
- const [expanded, setExpanded] = React7.useState(false);
2297
2568
  const sources = React7.useMemo(
2298
2569
  () => given ?? collectSources(references, citations, uid),
2299
2570
  [given, references, citations, uid]
2300
2571
  );
2301
2572
  if (sources.length === 0) return null;
2302
- const limit = max > 0 && !expanded ? max : sources.length;
2573
+ const limit = max > 0 ? max : sources.length;
2303
2574
  const visible = sources.slice(0, limit);
2304
- const hidden = sources.length - visible.length;
2575
+ const hidden = sources.slice(limit);
2305
2576
  return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: cx("agno-sources", cn.citations, className), "aria-label": title, children: [
2306
2577
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-sources__head", children: title }),
2307
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "agno-sources__grid", children: visible.map((source) => /* @__PURE__ */ jsxRuntime.jsx(SourceCard, { source }, source.anchorId)) }),
2308
- hidden > 0 && /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "agno-sources__more", onClick: () => setExpanded(true), children: [
2309
- "Show ",
2310
- hidden,
2311
- " more"
2578
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "agno-sources__grid", children: [
2579
+ visible.map((source) => /* @__PURE__ */ jsxRuntime.jsx(SourceCard, { source }, source.anchorId)),
2580
+ hidden.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(SourcesOverflow, { sources: hidden })
2312
2581
  ] })
2313
2582
  ] });
2314
2583
  }
@@ -2362,10 +2631,11 @@ function Message({
2362
2631
  }, [message.references, message.citations, message.content, uid]);
2363
2632
  const isUser = message.role === "user";
2364
2633
  const isAgent = message.role === "agent";
2365
- const showSources = isAgent && !hideSources && sources.length > 0;
2634
+ const hasSources = isAgent && !hideSources && sources.length > 0;
2635
+ const showSources = hasSources && !message.streaming;
2366
2636
  const content = React7.useMemo(
2367
- () => showSources && message.content ? withoutSourcesLine(message.content) : message.content,
2368
- [message.content, showSources]
2637
+ () => hasSources && message.content ? withoutSourcesLine(message.content) : message.content,
2638
+ [message.content, hasSources]
2369
2639
  );
2370
2640
  const hasActivity = !message.content && !hasBehindTheScenes(message, { hideReasoning, hideTools });
2371
2641
  const kind = isUser ? "user" : isAgent ? entityType : "system";
@@ -2524,6 +2794,7 @@ function ChatWindow({
2524
2794
  userInitials,
2525
2795
  emptyState,
2526
2796
  allowFiles,
2797
+ compactInput,
2527
2798
  disabled,
2528
2799
  renderMarkdown,
2529
2800
  showErrors,
@@ -2532,6 +2803,7 @@ function ChatWindow({
2532
2803
  hideFollowups,
2533
2804
  onFollowup,
2534
2805
  followupsTitle,
2806
+ renderMessage,
2535
2807
  header,
2536
2808
  composer,
2537
2809
  className,
@@ -2558,6 +2830,7 @@ function ChatWindow({
2558
2830
  renderMarkdown: markdown,
2559
2831
  classNames: cn,
2560
2832
  emptyState,
2833
+ renderMessage,
2561
2834
  footer: pausedMessage ? /* @__PURE__ */ jsxRuntime.jsx(
2562
2835
  HumanInput,
2563
2836
  {
@@ -2600,6 +2873,7 @@ function ChatWindow({
2600
2873
  disabled: disabled || chat.isPaused,
2601
2874
  placeholder,
2602
2875
  allowFiles,
2876
+ compact: compactInput,
2603
2877
  classNames: cn
2604
2878
  }
2605
2879
  )
@@ -2897,7 +3171,7 @@ function SessionList({
2897
3171
  }
2898
3172
  function AgnoChat(props) {
2899
3173
  const client = React7.useMemo(
2900
- () => props.client ?? new chunkROFIOWGX_cjs.AgnoClient({ baseUrl: props.baseUrl ?? "", headers: props.headers }),
3174
+ () => props.client ?? new chunk55HQJGLP_cjs.AgnoClient({ baseUrl: props.baseUrl ?? "", headers: props.headers }),
2901
3175
  [props.client, props.baseUrl, props.headers]
2902
3176
  );
2903
3177
  const [discovered, setDiscovered] = React7.useState(props.entities ?? []);
@@ -2988,6 +3262,7 @@ function AgnoChat(props) {
2988
3262
  chat,
2989
3263
  placeholder: props.placeholder,
2990
3264
  allowFiles: props.allowFiles ?? true,
3265
+ compactInput: props.compactInput,
2991
3266
  disabled: !entity,
2992
3267
  renderMarkdown: props.renderMarkdown,
2993
3268
  showErrors: props.showErrors,
@@ -3005,6 +3280,7 @@ function AgnoChat(props) {
3005
3280
  disabled: !entity || chat.isPaused,
3006
3281
  placeholder: props.placeholder,
3007
3282
  allowFiles: props.allowFiles ?? true,
3283
+ compact: props.compactInput,
3008
3284
  classNames: cn,
3009
3285
  trailing: showPicker ? /* @__PURE__ */ jsxRuntime.jsx(
3010
3286
  EntitySelector,
@@ -3033,6 +3309,7 @@ function AgnoChat(props) {
3033
3309
  renderMarkdown: props.renderMarkdown,
3034
3310
  resolveLinkPreview: props.resolveLinkPreview,
3035
3311
  codeCopy: props.codeCopy,
3312
+ linkComponent: props.linkComponent,
3036
3313
  as: false,
3037
3314
  children: root
3038
3315
  }
@@ -3199,7 +3476,7 @@ function fold(events) {
3199
3476
  last.created_at = e.created_at ?? last.created_at;
3200
3477
  continue;
3201
3478
  }
3202
- rows.push({ event: name, source, count: 1, created_at: e.created_at, detail: chunkROFIOWGX_cjs.activityLabel(e) });
3479
+ rows.push({ event: name, source, count: 1, created_at: e.created_at, detail: chunk55HQJGLP_cjs.activityLabel(e) });
3203
3480
  }
3204
3481
  return rows;
3205
3482
  }
@@ -3251,12 +3528,14 @@ exports.Favicon = Favicon;
3251
3528
  exports.FileAudio = FileAudio;
3252
3529
  exports.FileIcon = FileIcon;
3253
3530
  exports.FilePreview = FilePreview;
3531
+ exports.FileType = FileType;
3254
3532
  exports.FileVideo = FileVideo;
3255
3533
  exports.Followups = Followups;
3256
3534
  exports.Globe = Globe;
3257
3535
  exports.GridLoader = GridLoader;
3258
3536
  exports.HoverPreview = HoverPreview;
3259
3537
  exports.HumanInput = HumanInput;
3538
+ exports.LinkIcon = LinkIcon;
3260
3539
  exports.LinkPreviewCard = LinkPreviewCard;
3261
3540
  exports.Markdown = Markdown;
3262
3541
  exports.MemberResponses = MemberResponses;
@@ -3281,12 +3560,14 @@ exports.ToolCalls = ToolCalls;
3281
3560
  exports.Trash = Trash;
3282
3561
  exports.WorkflowSteps = WorkflowSteps;
3283
3562
  exports.Wrench = Wrench;
3563
+ exports.admitFiles = admitFiles;
3284
3564
  exports.behindTheScenesItems = behindTheScenesItems;
3285
3565
  exports.behindTheScenesLabel = behindTheScenesLabel;
3286
3566
  exports.collectSources = collectSources;
3287
3567
  exports.cx = cx;
3288
3568
  exports.displayUrl = displayUrl;
3289
3569
  exports.faviconUrl = faviconUrl;
3570
+ exports.fileAccepted = fileAccepted;
3290
3571
  exports.getProviderIcon = getProviderIcon;
3291
3572
  exports.hasBehindTheScenes = hasBehindTheScenes;
3292
3573
  exports.linkCitations = linkCitations;
@@ -3297,6 +3578,7 @@ exports.sourceHost = sourceHost;
3297
3578
  exports.sourcesFromMarkdown = sourcesFromMarkdown;
3298
3579
  exports.useAgnoChat = useAgnoChat;
3299
3580
  exports.useChatContext = useChatContext;
3581
+ exports.useLinkComponent = useLinkComponent;
3300
3582
  exports.useLinkPreview = useLinkPreview;
3301
3583
  exports.useOptionalChatContext = useOptionalChatContext;
3302
3584
  exports.useResolvedChat = useResolvedChat;
@@ -3304,5 +3586,5 @@ exports.useResolvedClassNames = useResolvedClassNames;
3304
3586
  exports.useSources = useSources;
3305
3587
  exports.withoutSourcesLine = withoutSourcesLine;
3306
3588
  exports.writeClipboard = writeClipboard;
3307
- //# sourceMappingURL=chunk-ERCKKOF4.cjs.map
3308
- //# sourceMappingURL=chunk-ERCKKOF4.cjs.map
3589
+ //# sourceMappingURL=chunk-Q73XHL35.cjs.map
3590
+ //# sourceMappingURL=chunk-Q73XHL35.cjs.map