@agents24/chat-react 0.5.29 → 0.5.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +23 -1
  2. package/dist/chunk-INO5DSSJ.js +86 -0
  3. package/dist/chunk-INO5DSSJ.js.map +1 -0
  4. package/dist/registry/agents24-chat.json +249 -0
  5. package/dist/runtime/index.cjs +1 -1
  6. package/dist/runtime/index.cjs.map +1 -1
  7. package/dist/runtime/index.js +11 -78
  8. package/dist/runtime/index.js.map +1 -1
  9. package/dist/runtime/input-contract.d.ts +3 -1
  10. package/dist/scaffold/app.d.ts +2 -0
  11. package/dist/scaffold/components/chat/chat-composer.d.ts +2 -3
  12. package/dist/scaffold/components/chat/theme-menu.d.ts +1 -1
  13. package/dist/scaffold/components/theme-provider.d.ts +2 -1
  14. package/dist/scaffold/index.cjs +44 -102
  15. package/dist/scaffold/index.cjs.map +1 -1
  16. package/dist/scaffold/index.d.ts +2 -0
  17. package/dist/scaffold/index.js +41 -103
  18. package/dist/scaffold/index.js.map +1 -1
  19. package/dist/ui/agent-chat-composer.d.ts +7 -2
  20. package/dist/ui/index.cjs +688 -540
  21. package/dist/ui/index.cjs.map +1 -1
  22. package/dist/ui/index.d.ts +1 -0
  23. package/dist/ui/index.js +650 -541
  24. package/dist/ui/index.js.map +1 -1
  25. package/dist/ui/use-agent-chat-composer.d.ts +48 -0
  26. package/dist/ui/use-audio-recorder.d.ts +1 -1
  27. package/package.json +8 -4
  28. package/scaffold/inherit.css +4 -0
  29. package/scaffold/src/app.tsx +2 -0
  30. package/scaffold/src/chat.css +24 -0
  31. package/scaffold/src/components/chat/chat-composer.tsx +14 -97
  32. package/scaffold/src/components/chat/chat-shell.tsx +2 -1
  33. package/scaffold/src/components/chat/theme-menu.tsx +3 -1
  34. package/scaffold/src/components/theme-provider.tsx +10 -8
  35. package/scaffold/src/index.css +8 -8
  36. package/scaffold/src/index.tsx +5 -0
package/dist/ui/index.js CHANGED
@@ -2,10 +2,16 @@ import {
2
2
  getActiveStreamingTextPartId,
3
3
  useStreamingText
4
4
  } from "../chunk-5PWUQTLK.js";
5
+ import {
6
+ attachmentFileAccept,
7
+ inputMimeTypes,
8
+ normalizeAttachmentMimeType,
9
+ validateAgentChatSubmission
10
+ } from "../chunk-INO5DSSJ.js";
5
11
 
6
12
  // src/ui/agent-chat-composer.tsx
7
- import * as React3 from "react";
8
- import { ArrowUp, Loader2, Plus, Square } from "lucide-react";
13
+ import * as React6 from "react";
14
+ import { ArrowUp, Loader2, Mic, Plus, Square } from "lucide-react";
9
15
 
10
16
  // src/ui/adapters.ts
11
17
  import * as React from "react";
@@ -718,8 +724,11 @@ function ChatAttachmentRows({
718
724
  );
719
725
  }
720
726
 
727
+ // src/ui/use-agent-chat-composer.ts
728
+ import * as React4 from "react";
729
+
721
730
  // src/ui/composer-attachments.ts
722
- import { normalizeAttachmentMimeType } from "@agents24/client";
731
+ import { normalizeAttachmentMimeType as normalizeAttachmentMimeType2 } from "@agents24/client";
723
732
  var createId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `file-${Date.now()}-${Math.random().toString(36).slice(2)}`;
724
733
  function createAgentChatComposerFile(file) {
725
734
  return {
@@ -727,7 +736,7 @@ function createAgentChatComposerFile(file) {
727
736
  type: "file",
728
737
  url: URL.createObjectURL(file),
729
738
  filename: file.name || "attachment",
730
- mediaType: normalizeAttachmentMimeType(file.type, file.name),
739
+ mediaType: normalizeAttachmentMimeType2(file.type, file.name),
731
740
  source: file
732
741
  };
733
742
  }
@@ -779,8 +788,300 @@ function useChatComposerFocus({ textareaRef, disabled, focusKey, restoredDraft,
779
788
  return focus;
780
789
  }
781
790
 
782
- // src/ui/agent-chat-composer.tsx
791
+ // src/ui/use-audio-recorder.ts
792
+ import * as React3 from "react";
793
+ var RECORDING_CANDIDATES = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"];
794
+ function recordingExtension(mimeType) {
795
+ return mimeType.startsWith("audio/mp4") ? "m4a" : "webm";
796
+ }
797
+ function useAudioRecorder(onRecorded, options = {}) {
798
+ const mountedRef = React3.useRef(true);
799
+ const startingRef = React3.useRef(false);
800
+ const recorderRef = React3.useRef(null);
801
+ const streamRef = React3.useRef(null);
802
+ const onRecordedRef = React3.useRef(onRecorded);
803
+ const onStreamChangeRef = React3.useRef(options.onStreamChange);
804
+ onRecordedRef.current = onRecorded;
805
+ onStreamChangeRef.current = options.onStreamChange;
806
+ const [isRecording, setIsRecording] = React3.useState(false);
807
+ const [error, setError] = React3.useState(null);
808
+ const stop = React3.useCallback(() => {
809
+ if (recorderRef.current && recorderRef.current.state !== "inactive") recorderRef.current.stop();
810
+ }, []);
811
+ const start = React3.useCallback(async () => {
812
+ if (startingRef.current || recorderRef.current) return;
813
+ startingRef.current = true;
814
+ setError(null);
815
+ if (!navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
816
+ setError("Audio recording is not supported in this browser.");
817
+ startingRef.current = false;
818
+ return;
819
+ }
820
+ try {
821
+ const mimeType = RECORDING_CANDIDATES.find((candidate) => MediaRecorder.isTypeSupported(candidate));
822
+ if (!mimeType) {
823
+ setError("Audio recording is not supported in this browser.");
824
+ return;
825
+ }
826
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
827
+ if (!mountedRef.current) {
828
+ stream.getTracks().forEach((track) => track.stop());
829
+ return;
830
+ }
831
+ streamRef.current = stream;
832
+ onStreamChangeRef.current?.(stream);
833
+ const recorder = new MediaRecorder(stream, { mimeType });
834
+ const chunks = [];
835
+ recorder.ondataavailable = (event) => {
836
+ if (event.data.size) chunks.push(event.data);
837
+ };
838
+ recorder.onstop = () => {
839
+ const actualType = recorder.mimeType || "audio/webm";
840
+ if (mountedRef.current) onRecordedRef.current(new File([new Blob(chunks, { type: actualType })], `recording-${Date.now()}.${recordingExtension(actualType)}`, { type: actualType }));
841
+ stream.getTracks().forEach((track) => track.stop());
842
+ onStreamChangeRef.current?.(null);
843
+ recorderRef.current = null;
844
+ streamRef.current = null;
845
+ if (mountedRef.current) setIsRecording(false);
846
+ };
847
+ recorderRef.current = recorder;
848
+ streamRef.current = stream;
849
+ recorder.start();
850
+ setIsRecording(true);
851
+ } catch {
852
+ streamRef.current?.getTracks().forEach((track) => track.stop());
853
+ onStreamChangeRef.current?.(null);
854
+ streamRef.current = null;
855
+ recorderRef.current = null;
856
+ if (mountedRef.current) setError("Microphone access is unavailable.");
857
+ } finally {
858
+ startingRef.current = false;
859
+ }
860
+ }, []);
861
+ React3.useEffect(() => {
862
+ mountedRef.current = true;
863
+ return () => {
864
+ mountedRef.current = false;
865
+ if (recorderRef.current && recorderRef.current.state !== "inactive") recorderRef.current.stop();
866
+ streamRef.current?.getTracks().forEach((track) => track.stop());
867
+ onStreamChangeRef.current?.(null);
868
+ };
869
+ }, []);
870
+ return { error, isRecording, start, stop };
871
+ }
872
+
873
+ // src/ui/use-agent-chat-composer.ts
874
+ function useAgentChatComposer({
875
+ disabled = false,
876
+ isRunning = false,
877
+ isCancelling = false,
878
+ inputContract,
879
+ recordingEnabled,
880
+ focusKey,
881
+ restoredDraft,
882
+ textareaRef,
883
+ onSubmit
884
+ }) {
885
+ const [text, setDraftText] = React4.useState("");
886
+ const [files, setDraftFiles] = React4.useState([]);
887
+ const [isSubmitting, setIsSubmitting] = React4.useState(false);
888
+ const [attachmentError, setAttachmentError] = React4.useState(null);
889
+ const draftRef = React4.useRef({ text, files, revision: 0 });
890
+ const inFlightRef = React4.useRef([]);
891
+ const submittingRef = React4.useRef(false);
892
+ const mountedRef = React4.useRef(true);
893
+ const updateDraft = (nextText, nextFiles) => {
894
+ draftRef.current = { text: nextText, files: nextFiles, revision: draftRef.current.revision + 1 };
895
+ setDraftText(nextText);
896
+ setDraftFiles(nextFiles);
897
+ };
898
+ React4.useEffect(() => {
899
+ mountedRef.current = true;
900
+ return () => {
901
+ mountedRef.current = false;
902
+ revokeAgentChatComposerFiles(draftRef.current.files);
903
+ revokeAgentChatComposerFiles(inFlightRef.current);
904
+ };
905
+ }, []);
906
+ const focus = useChatComposerFocus({ textareaRef, disabled, focusKey, restoredDraft, onRestore: (draft) => {
907
+ revokeAgentChatComposerFiles(draftRef.current.files.filter((file) => !draft.files.includes(file)));
908
+ updateDraft(draft.text, draft.files);
909
+ } });
910
+ const accept = inputContract ? inputMimeTypes(inputContract) : null;
911
+ const addFiles = (selected) => {
912
+ const accepted = accept ? selected.filter((file) => accept.includes(normalizeAttachmentMimeType(file.type, file.name))) : selected;
913
+ setAttachmentError(accepted.length === selected.length ? null : "One or more selected file types are not supported by this Agent.");
914
+ updateDraft(draftRef.current.text, [...draftRef.current.files, ...accepted.map(createAgentChatComposerFile)]);
915
+ };
916
+ const recordedRef = React4.useRef(addFiles);
917
+ recordedRef.current = addFiles;
918
+ const recorder = useAudioRecorder((file) => {
919
+ if (mountedRef.current) recordedRef.current([file]);
920
+ });
921
+ const recordingAllowed = inputContract ? inputContract.modalities.audio.enabled && inputContract.modalities.audio.recording_enabled && recordingEnabled !== false : recordingEnabled === true;
922
+ const validationError = inputContract ? validateAgentChatSubmission(
923
+ inputContract,
924
+ text,
925
+ files.map((file) => ({ data: file.source || new Uint8Array(), mediaType: file.mediaType, name: file.filename, byteSize: file.source ? void 0 : file.byteSize }))
926
+ ) : null;
927
+ const canSubmit = !disabled && !isCancelling && !isSubmitting && !recorder.isRecording && !validationError && Boolean(text.trim() || files.length);
928
+ const submit = async () => {
929
+ if (!canSubmit || submittingRef.current) return;
930
+ const submitted = draftRef.current;
931
+ submittingRef.current = true;
932
+ inFlightRef.current = submitted.files;
933
+ setIsSubmitting(true);
934
+ updateDraft("", []);
935
+ const clearedRevision = draftRef.current.revision;
936
+ focus();
937
+ try {
938
+ await onSubmit({
939
+ text: submitted.text,
940
+ files: submitted.files,
941
+ attachmentIds: submitted.files.flatMap((file) => file.persistedAttachmentId ? [file.persistedAttachmentId] : [])
942
+ });
943
+ revokeAgentChatComposerFiles(submitted.files);
944
+ } catch {
945
+ if (mountedRef.current && draftRef.current.revision === clearedRevision) updateDraft(submitted.text, submitted.files);
946
+ else revokeAgentChatComposerFiles(submitted.files);
947
+ } finally {
948
+ inFlightRef.current = [];
949
+ submittingRef.current = false;
950
+ if (mountedRef.current) setIsSubmitting(false);
951
+ }
952
+ };
953
+ return {
954
+ text,
955
+ files,
956
+ isSubmitting,
957
+ canSubmit,
958
+ validationError,
959
+ attachmentError,
960
+ recordingAllowed,
961
+ recorder,
962
+ accept,
963
+ fileAccept: accept ? attachmentFileAccept(accept) : void 0,
964
+ allowAttachments: accept ? accept.length > 0 : true,
965
+ action: chatComposerAction({ hasDraft: Boolean(text.trim() || files.length), isRunning, isCancelling }),
966
+ setText: (value) => updateDraft(value, draftRef.current.files),
967
+ addFiles,
968
+ removeFile: (id) => {
969
+ revokeAgentChatComposerFiles(draftRef.current.files.filter((file) => file.id === id));
970
+ updateDraft(draftRef.current.text, draftRef.current.files.filter((file) => file.id !== id));
971
+ },
972
+ submit,
973
+ onKeyDown: (event) => {
974
+ if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
975
+ event.preventDefault();
976
+ void submit();
977
+ }
978
+ }
979
+ };
980
+ }
981
+
982
+ // src/ui/agent-chat-context-status.tsx
983
+ import * as React5 from "react";
783
984
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
985
+ var COMPACT_TOKENS = new Intl.NumberFormat("en-US", { notation: "compact" });
986
+ var PERCENT = new Intl.NumberFormat("en-US", {
987
+ style: "percent",
988
+ maximumFractionDigits: 1
989
+ });
990
+ var EXACT_SOURCES = /* @__PURE__ */ new Set(["exact", "provider_usage"]);
991
+ function contextStatusMetrics(contextWindow) {
992
+ const maximum = Number(contextWindow?.max_tokens || 0);
993
+ const input = Math.max(0, Number(contextWindow?.input_tokens || 0));
994
+ const admissionInput = Math.max(0, Number(contextWindow?.admission_input_tokens ?? input));
995
+ const usageRatio = Math.max(0, Math.min(1, Number(
996
+ contextWindow?.usage_ratio ?? input / maximum
997
+ )));
998
+ const admissionRatio = Math.max(0, Math.min(1, Number(
999
+ contextWindow?.admission_ratio ?? admissionInput / maximum
1000
+ )));
1001
+ return { maximum, input, admissionInput, usageRatio, admissionRatio };
1002
+ }
1003
+ function AgentChatContextStatus({
1004
+ className,
1005
+ contextWindow
1006
+ }) {
1007
+ const tooltipId = React5.useId();
1008
+ const [open, setOpen] = React5.useState(false);
1009
+ const { maximum, input, admissionInput, usageRatio, admissionRatio } = contextStatusMetrics(contextWindow);
1010
+ const percentage = Math.round(usageRatio * 100);
1011
+ const exact = EXACT_SOURCES.has(contextWindow?.source || "unknown");
1012
+ if (!Number.isFinite(maximum) || maximum <= 0) return null;
1013
+ return /* @__PURE__ */ jsxs(
1014
+ "div",
1015
+ {
1016
+ className: cn("a24-context-status", className),
1017
+ onBlurCapture: (event) => {
1018
+ if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
1019
+ },
1020
+ onFocusCapture: () => setOpen(true),
1021
+ onMouseEnter: () => setOpen(true),
1022
+ onMouseLeave: () => setOpen(false),
1023
+ children: [
1024
+ /* @__PURE__ */ jsxs(
1025
+ "button",
1026
+ {
1027
+ "aria-describedby": open ? tooltipId : void 0,
1028
+ "aria-label": `Context window ${percentage}% used`,
1029
+ className: "a24-context-status__trigger",
1030
+ onKeyDown: (event) => {
1031
+ if (event.key === "Escape") setOpen(false);
1032
+ },
1033
+ type: "button",
1034
+ children: [
1035
+ /* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", className: "a24-context-status__ring", viewBox: "0 0 24 24", children: [
1036
+ /* @__PURE__ */ jsx3("circle", { className: "a24-context-status__track", cx: "12", cy: "12", r: "10" }),
1037
+ /* @__PURE__ */ jsx3(
1038
+ "circle",
1039
+ {
1040
+ className: "a24-context-status__value",
1041
+ cx: "12",
1042
+ cy: "12",
1043
+ pathLength: "100",
1044
+ r: "10",
1045
+ strokeDasharray: `${percentage} 100`
1046
+ }
1047
+ )
1048
+ ] }),
1049
+ /* @__PURE__ */ jsxs("span", { children: [
1050
+ percentage,
1051
+ "%"
1052
+ ] })
1053
+ ]
1054
+ }
1055
+ ),
1056
+ open ? /* @__PURE__ */ jsxs("div", { className: "a24-context-status__popover", id: tooltipId, role: "tooltip", children: [
1057
+ /* @__PURE__ */ jsx3("span", { className: "a24-context-status__sr-only", children: "Context window" }),
1058
+ /* @__PURE__ */ jsxs("strong", { children: [
1059
+ PERCENT.format(usageRatio),
1060
+ " context used"
1061
+ ] }),
1062
+ /* @__PURE__ */ jsxs("span", { children: [
1063
+ exact ? "Input" : "Estimated input",
1064
+ ": ",
1065
+ COMPACT_TOKENS.format(input),
1066
+ " / ",
1067
+ COMPACT_TOKENS.format(maximum),
1068
+ " tokens"
1069
+ ] }),
1070
+ admissionInput !== input ? /* @__PURE__ */ jsxs("span", { children: [
1071
+ "Safety bound: ",
1072
+ COMPACT_TOKENS.format(admissionInput),
1073
+ " tokens (",
1074
+ PERCENT.format(admissionRatio),
1075
+ ")"
1076
+ ] }) : null
1077
+ ] }) : null
1078
+ ]
1079
+ }
1080
+ );
1081
+ }
1082
+
1083
+ // src/ui/agent-chat-composer.tsx
1084
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
784
1085
  function formatFileCount(files) {
785
1086
  if (files.length === 1) return files[0].filename;
786
1087
  return `${files.length} files`;
@@ -788,6 +1089,9 @@ function formatFileCount(files) {
788
1089
  var pillButtonClass = "inline-flex size-8 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-muted text-sm text-muted-foreground shadow-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
789
1090
  var submitButtonClass = "inline-flex size-9 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-primary text-sm text-primary-foreground shadow-none transition-[background-color,color,opacity,transform] duration-200 hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
790
1091
  function AgentChatComposer({
1092
+ inputContract,
1093
+ recordingEnabled,
1094
+ contextWindow,
791
1095
  accept,
792
1096
  allowAttachments = true,
793
1097
  attachmentLayout = "flow",
@@ -805,16 +1109,22 @@ function AgentChatComposer({
805
1109
  restoredDraft,
806
1110
  textareaRef
807
1111
  }) {
808
- const fileInputRef = React3.useRef(null);
809
- const filesRef = React3.useRef([]);
810
- const inFlightFilesRef = React3.useRef([]);
811
- const localTextareaRef = React3.useRef(null);
812
- const draftRevisionRef = React3.useRef(0);
813
- const [text, setText] = React3.useState("");
814
- const [files, setFiles] = React3.useState([]);
815
- const [isSubmitting, setIsSubmitting] = React3.useState(false);
1112
+ const fileInputRef = React6.useRef(null);
1113
+ const localTextareaRef = React6.useRef(null);
1114
+ const composer = useAgentChatComposer({
1115
+ inputContract,
1116
+ recordingEnabled,
1117
+ disabled,
1118
+ isRunning,
1119
+ isCancelling,
1120
+ focusKey,
1121
+ restoredDraft,
1122
+ textareaRef: localTextareaRef,
1123
+ onSubmit: (input) => onSubmit({ ...input, text: input.text.trim() })
1124
+ });
1125
+ const { text, files, setText, isSubmitting, canSubmit, action, submit } = composer;
816
1126
  const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
817
- const setTextareaRef = React3.useCallback(
1127
+ const setTextareaRef = React6.useCallback(
818
1128
  (node) => {
819
1129
  localTextareaRef.current = node;
820
1130
  if (typeof textareaRef === "function") {
@@ -825,27 +1135,10 @@ function AgentChatComposer({
825
1135
  },
826
1136
  [textareaRef]
827
1137
  );
828
- React3.useEffect(() => {
829
- filesRef.current = files;
1138
+ React6.useEffect(() => {
830
1139
  onAttachmentCountChange?.(files.length);
831
1140
  }, [files, onAttachmentCountChange]);
832
- React3.useEffect(() => () => {
833
- revokeAgentChatComposerFiles(filesRef.current);
834
- revokeAgentChatComposerFiles(inFlightFilesRef.current);
835
- }, []);
836
- const focusComposer = useChatComposerFocus({
837
- textareaRef: localTextareaRef,
838
- disabled,
839
- focusKey,
840
- restoredDraft,
841
- onRestore: (draft) => {
842
- draftRevisionRef.current += 1;
843
- revokeAgentChatComposerFiles(filesRef.current);
844
- setText(draft.text);
845
- setFiles(draft.files);
846
- }
847
- });
848
- React3.useLayoutEffect(() => {
1141
+ React6.useLayoutEffect(() => {
849
1142
  const textarea = localTextareaRef.current;
850
1143
  if (!textarea) return;
851
1144
  if (isExpanded) {
@@ -858,65 +1151,12 @@ function AgentChatComposer({
858
1151
  textarea.style.height = "";
859
1152
  textarea.style.overflowY = "hidden";
860
1153
  }, [isExpanded, text]);
861
- const canSubmit = !disabled && !isCancelling && !isSubmitting && (text.trim().length > 0 || files.length > 0);
862
- const action = chatComposerAction({ hasDraft: text.trim().length > 0 || files.length > 0, isRunning, isCancelling });
863
1154
  const handleFilesChange = (event) => {
864
- const selected = Array.from(event.target.files || []).map(createAgentChatComposerFile);
865
- if (selected.length > 0) {
866
- draftRevisionRef.current += 1;
867
- setFiles((current) => [...current, ...selected]);
868
- }
1155
+ composer.addFiles(Array.from(event.target.files || []));
869
1156
  event.currentTarget.value = "";
870
1157
  };
871
- const removeFile = (fileId) => {
872
- draftRevisionRef.current += 1;
873
- setFiles((current) => {
874
- const target = current.find((file) => file.id === fileId);
875
- if (target) revokeAgentChatComposerFiles([target]);
876
- return current.filter((file) => file.id !== fileId);
877
- });
878
- };
879
- const submit = async () => {
880
- if (!canSubmit) return;
881
- const submittedText = text.trim();
882
- const submittedFiles = files;
883
- const clearedRevision = draftRevisionRef.current + 1;
884
- draftRevisionRef.current = clearedRevision;
885
- inFlightFilesRef.current = submittedFiles;
886
- setIsSubmitting(true);
887
- setText("");
888
- setFiles([]);
889
- focusComposer();
890
- try {
891
- await onSubmit({
892
- text: submittedText,
893
- files: submittedFiles,
894
- attachmentIds: submittedFiles.flatMap((file) => file.persistedAttachmentId ? [file.persistedAttachmentId] : [])
895
- });
896
- revokeAgentChatComposerFiles(submittedFiles);
897
- inFlightFilesRef.current = [];
898
- } catch {
899
- if (draftRevisionRef.current === clearedRevision) {
900
- draftRevisionRef.current += 1;
901
- setText(submittedText);
902
- setFiles(submittedFiles);
903
- inFlightFilesRef.current = [];
904
- } else {
905
- revokeAgentChatComposerFiles(submittedFiles);
906
- inFlightFilesRef.current = [];
907
- }
908
- } finally {
909
- setIsSubmitting(false);
910
- }
911
- };
912
- const handleKeyDown = (event) => {
913
- if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
914
- event.preventDefault();
915
- void submit();
916
- }
917
- };
918
- return /* @__PURE__ */ jsxs("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), "data-agents24-chat-composer": "", children: [
919
- files.length > 0 ? /* @__PURE__ */ jsx3(
1158
+ return /* @__PURE__ */ jsxs2("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), "data-agents24-chat-composer": "", children: [
1159
+ files.length > 0 ? /* @__PURE__ */ jsx4(
920
1160
  "div",
921
1161
  {
922
1162
  "data-testid": "agent-chat-composer-attachments",
@@ -925,16 +1165,17 @@ function AgentChatComposer({
925
1165
  "a24-composer__attachments min-w-0 py-1",
926
1166
  attachmentLayout === "overlay" ? "absolute bottom-full left-0 right-0 mb-1.5 flex-nowrap overflow-x-auto overflow-y-hidden overscroll-x-contain px-2" : "mb-2 flex-wrap px-1"
927
1167
  ),
928
- children: /* @__PURE__ */ jsx3(
1168
+ children: /* @__PURE__ */ jsx4(
929
1169
  ChatAttachmentRows,
930
1170
  {
931
1171
  attachments: files,
932
- onRemove: (attachment) => attachment.id && removeFile(attachment.id)
1172
+ onRemove: (attachment) => attachment.id && composer.removeFile(attachment.id)
933
1173
  }
934
1174
  )
935
1175
  }
936
1176
  ) : null,
937
- /* @__PURE__ */ jsx3(
1177
+ composer.attachmentError || composer.recorder.error ? /* @__PURE__ */ jsx4("p", { role: "alert", children: composer.attachmentError || composer.recorder.error }) : null,
1178
+ /* @__PURE__ */ jsx4(
938
1179
  "div",
939
1180
  {
940
1181
  "data-expanded": isExpanded ? "" : void 0,
@@ -942,7 +1183,7 @@ function AgentChatComposer({
942
1183
  "a24-composer__surface relative w-full border border-input bg-background shadow-sm",
943
1184
  isExpanded ? "rounded-xl p-2 pb-1.5" : "rounded-xl px-2 py-[3px]"
944
1185
  ),
945
- children: /* @__PURE__ */ jsxs(
1186
+ children: /* @__PURE__ */ jsxs2(
946
1187
  "div",
947
1188
  {
948
1189
  className: "a24-composer__grid w-full",
@@ -954,12 +1195,12 @@ function AgentChatComposer({
954
1195
  gap: isExpanded ? "3px 10px" : "8px"
955
1196
  },
956
1197
  children: [
957
- /* @__PURE__ */ jsxs("div", { style: { gridArea: "plus" }, className: "a24-composer__attach-slot flex shrink-0 items-center justify-center", children: [
958
- /* @__PURE__ */ jsx3(
1198
+ /* @__PURE__ */ jsxs2("div", { style: { gridArea: "plus" }, className: "a24-composer__attach-slot flex shrink-0 items-center justify-center", children: [
1199
+ /* @__PURE__ */ jsx4(
959
1200
  "input",
960
1201
  {
961
1202
  ref: fileInputRef,
962
- accept,
1203
+ accept: composer.fileAccept ?? accept,
963
1204
  "aria-label": "Attach files",
964
1205
  className: "hidden",
965
1206
  multiple: true,
@@ -968,20 +1209,20 @@ function AgentChatComposer({
968
1209
  type: "file"
969
1210
  }
970
1211
  ),
971
- /* @__PURE__ */ jsx3(
1212
+ /* @__PURE__ */ jsx4(
972
1213
  "button",
973
1214
  {
974
1215
  "aria-label": "Attach files",
975
1216
  className: cn("a24-composer__attach", pillButtonClass),
976
- disabled: disabled || isSubmitting || !allowAttachments,
1217
+ disabled: disabled || isSubmitting || !allowAttachments || !composer.allowAttachments,
977
1218
  onClick: () => fileInputRef.current?.click(),
978
1219
  title: "Attach files",
979
1220
  type: "button",
980
- children: /* @__PURE__ */ jsx3(Plus, { className: "size-4" })
1221
+ children: /* @__PURE__ */ jsx4(Plus, { className: "size-4" })
981
1222
  }
982
1223
  )
983
1224
  ] }),
984
- /* @__PURE__ */ jsx3("div", { style: { gridArea: "textarea" }, className: "a24-composer__textarea-slot min-w-0 w-full", children: /* @__PURE__ */ jsx3(
1225
+ /* @__PURE__ */ jsx4("div", { style: { gridArea: "textarea" }, className: "a24-composer__textarea-slot min-w-0 w-full", children: /* @__PURE__ */ jsx4(
985
1226
  "textarea",
986
1227
  {
987
1228
  ref: setTextareaRef,
@@ -993,20 +1234,50 @@ function AgentChatComposer({
993
1234
  ),
994
1235
  disabled,
995
1236
  name: "message",
996
- onChange: (event) => {
997
- draftRevisionRef.current += 1;
998
- setText(event.target.value);
999
- },
1000
- onKeyDown: handleKeyDown,
1237
+ onChange: (event) => setText(event.target.value),
1238
+ onKeyDown: composer.onKeyDown,
1001
1239
  placeholder,
1002
1240
  rows: isExpanded ? 2 : 1,
1003
1241
  value: text
1004
1242
  }
1005
1243
  ) }),
1006
- isExpanded ? /* @__PURE__ */ jsx3("div", { style: { gridArea: "toolbar" }, className: "a24-composer__toolbar flex min-w-0 items-center gap-1.5", children: inputToolbarContent }) : null,
1007
- !isExpanded ? /* @__PURE__ */ jsx3("div", { style: { gridArea: "composer" }, className: "flex min-w-0 items-center gap-1.5" }) : null,
1008
- !isExpanded ? /* @__PURE__ */ jsx3("div", { style: { gridArea: "mic" }, className: "flex shrink-0 items-center justify-end" }) : null,
1009
- /* @__PURE__ */ jsx3("div", { style: { gridArea: "submit" }, className: "a24-composer__submit-slot flex shrink-0 items-center justify-end gap-1", children: /* @__PURE__ */ jsx3(
1244
+ isExpanded ? /* @__PURE__ */ jsxs2("div", { style: { gridArea: "toolbar" }, className: "a24-composer__toolbar flex min-w-0 items-center gap-1.5", children: [
1245
+ inputToolbarContent,
1246
+ /* @__PURE__ */ jsx4(AgentChatContextStatus, { contextWindow }),
1247
+ composer.recordingAllowed ? /* @__PURE__ */ jsx4(
1248
+ "button",
1249
+ {
1250
+ type: "button",
1251
+ className: pillButtonClass,
1252
+ "aria-label": composer.recorder.isRecording ? "Stop recording" : "Record audio",
1253
+ disabled: disabled || isRunning || isSubmitting,
1254
+ onClick: () => {
1255
+ if (composer.recorder.isRecording) composer.recorder.stop();
1256
+ else void composer.recorder.start();
1257
+ },
1258
+ children: composer.recorder.isRecording ? /* @__PURE__ */ jsx4(Square, {}) : /* @__PURE__ */ jsx4(Mic, {})
1259
+ }
1260
+ ) : null
1261
+ ] }) : null,
1262
+ !isExpanded ? /* @__PURE__ */ jsx4("div", { style: { gridArea: "composer" }, className: "flex min-w-0 items-center gap-1.5" }) : null,
1263
+ !isExpanded ? /* @__PURE__ */ jsxs2("div", { style: { gridArea: "mic" }, className: "flex shrink-0 items-center justify-end", children: [
1264
+ /* @__PURE__ */ jsx4(AgentChatContextStatus, { contextWindow }),
1265
+ composer.recordingAllowed ? /* @__PURE__ */ jsx4(
1266
+ "button",
1267
+ {
1268
+ type: "button",
1269
+ className: pillButtonClass,
1270
+ "aria-label": composer.recorder.isRecording ? "Stop recording" : "Record audio",
1271
+ disabled: disabled || isRunning || isSubmitting,
1272
+ onClick: () => {
1273
+ if (composer.recorder.isRecording) composer.recorder.stop();
1274
+ else void composer.recorder.start();
1275
+ },
1276
+ children: composer.recorder.isRecording ? /* @__PURE__ */ jsx4(Square, {}) : /* @__PURE__ */ jsx4(Mic, {})
1277
+ }
1278
+ ) : null
1279
+ ] }) : null,
1280
+ /* @__PURE__ */ jsx4("div", { style: { gridArea: "submit" }, className: "a24-composer__submit-slot flex shrink-0 items-center justify-end gap-1", children: /* @__PURE__ */ jsx4(
1010
1281
  "button",
1011
1282
  {
1012
1283
  "aria-label": isCancelling ? "Cancelling response" : action === "stop" ? "Stop generating" : files.length > 0 ? `Send ${formatFileCount(files)}` : isRunning ? "Queue message" : "Send message",
@@ -1016,9 +1287,9 @@ function AgentChatComposer({
1016
1287
  if (action === "stop") onStop?.();
1017
1288
  else void submit();
1018
1289
  },
1019
- title: action === "stop" ? "Stop" : isRunning ? "Queue message" : "Send",
1290
+ title: composer.validationError || (action === "stop" ? "Stop" : isRunning ? "Queue message" : "Send"),
1020
1291
  type: "button",
1021
- children: isCancelling ? /* @__PURE__ */ jsx3(Loader2, { className: "size-3.5 animate-spin" }) : action === "stop" ? /* @__PURE__ */ jsx3(Square, { className: "size-3.5 fill-current" }) : /* @__PURE__ */ jsx3(ArrowUp, { className: "size-4", strokeWidth: 2.5 })
1292
+ children: isCancelling ? /* @__PURE__ */ jsx4(Loader2, { className: "size-3.5 animate-spin" }) : action === "stop" ? /* @__PURE__ */ jsx4(Square, { className: "size-3.5 fill-current" }) : /* @__PURE__ */ jsx4(ArrowUp, { className: "size-4", strokeWidth: 2.5 })
1022
1293
  }
1023
1294
  ) })
1024
1295
  ]
@@ -1026,17 +1297,17 @@ function AgentChatComposer({
1026
1297
  )
1027
1298
  }
1028
1299
  ),
1029
- !isExpanded && inputToolbarContent ? /* @__PURE__ */ jsx3("div", { className: "a24-composer__toolbar a24-composer__toolbar--external mt-2 flex items-center gap-2 px-1", children: inputToolbarContent }) : null
1300
+ !isExpanded && inputToolbarContent ? /* @__PURE__ */ jsx4("div", { className: "a24-composer__toolbar a24-composer__toolbar--external mt-2 flex items-center gap-2 px-1", children: inputToolbarContent }) : null
1030
1301
  ] });
1031
1302
  }
1032
1303
 
1033
1304
  // src/ui/agent-chat-queue.tsx
1034
- import * as React4 from "react";
1305
+ import * as React7 from "react";
1035
1306
  import { CornerDownLeft, Ellipsis, Trash2 } from "lucide-react";
1036
- import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1307
+ import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1037
1308
  function QueueRow({ message, onRemove, onEdit }) {
1038
- const [busy, setBusy] = React4.useState(false);
1039
- const [error, setError] = React4.useState(null);
1309
+ const [busy, setBusy] = React7.useState(false);
1310
+ const [error, setError] = React7.useState(null);
1040
1311
  const editable = message.revision > 0 && (message.status === "queued" || message.status === "blocked");
1041
1312
  const act = async (operation) => {
1042
1313
  setBusy(true);
@@ -1049,14 +1320,14 @@ function QueueRow({ message, onRemove, onEdit }) {
1049
1320
  setBusy(false);
1050
1321
  }
1051
1322
  };
1052
- return /* @__PURE__ */ jsxs2("div", { "data-message-id": message.id, className: "a24-queue__row min-w-0 border-b border-border/40 last:border-b-0", children: [
1053
- /* @__PURE__ */ jsxs2("div", { className: "a24-queue__row-content flex min-h-9 items-center gap-2 px-3 text-sm", children: [
1054
- /* @__PURE__ */ jsx4(CornerDownLeft, { "aria-hidden": true, className: "size-4 shrink-0 text-muted-foreground" }),
1055
- /* @__PURE__ */ jsx4("span", { className: "a24-queue__text min-w-0 flex-1 truncate text-foreground", title: message.text, children: message.text || `${message.attachment_ids.length} attachment${message.attachment_ids.length === 1 ? "" : "s"}` }),
1056
- message.status === "blocked" ? /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-xs text-amber-700", children: "Needs attention" }) : null,
1057
- ["steer_pending", "delivering"].includes(message.status) ? /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-xs text-muted-foreground", children: "Steering\u2026" }) : null,
1058
- editable ? /* @__PURE__ */ jsxs2(Fragment, { children: [
1059
- /* @__PURE__ */ jsx4(
1323
+ return /* @__PURE__ */ jsxs3("div", { "data-message-id": message.id, className: "a24-queue__row min-w-0 border-b border-border/40 last:border-b-0", children: [
1324
+ /* @__PURE__ */ jsxs3("div", { className: "a24-queue__row-content flex min-h-9 items-center gap-2 px-3 text-sm", children: [
1325
+ /* @__PURE__ */ jsx5(CornerDownLeft, { "aria-hidden": true, className: "size-4 shrink-0 text-muted-foreground" }),
1326
+ /* @__PURE__ */ jsx5("span", { className: "a24-queue__text min-w-0 flex-1 truncate text-foreground", title: message.text, children: message.text || `${message.attachment_ids.length} attachment${message.attachment_ids.length === 1 ? "" : "s"}` }),
1327
+ message.status === "blocked" ? /* @__PURE__ */ jsx5("span", { className: "shrink-0 text-xs text-amber-700", children: "Needs attention" }) : null,
1328
+ ["steer_pending", "delivering"].includes(message.status) ? /* @__PURE__ */ jsx5("span", { className: "shrink-0 text-xs text-muted-foreground", children: "Steering\u2026" }) : null,
1329
+ editable ? /* @__PURE__ */ jsxs3(Fragment, { children: [
1330
+ /* @__PURE__ */ jsx5(
1060
1331
  "button",
1061
1332
  {
1062
1333
  type: "button",
@@ -1064,12 +1335,12 @@ function QueueRow({ message, onRemove, onEdit }) {
1064
1335
  disabled: busy,
1065
1336
  onClick: () => void act(() => onRemove(message)),
1066
1337
  className: "a24-queue__icon flex size-8 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground disabled:opacity-50",
1067
- children: /* @__PURE__ */ jsx4(Trash2, { "aria-hidden": true, className: "size-4" })
1338
+ children: /* @__PURE__ */ jsx5(Trash2, { "aria-hidden": true, className: "size-4" })
1068
1339
  }
1069
1340
  ),
1070
- /* @__PURE__ */ jsxs2("details", { className: "a24-queue__menu relative group/queue-menu", children: [
1071
- /* @__PURE__ */ jsx4("summary", { "aria-label": "Queued message options", className: "a24-queue__icon flex size-8 cursor-pointer list-none items-center justify-center text-muted-foreground hover:text-foreground [&::-webkit-details-marker]:hidden", children: /* @__PURE__ */ jsx4(Ellipsis, { "aria-hidden": true, className: "size-4" }) }),
1072
- /* @__PURE__ */ jsx4("div", { className: "a24-queue__menu-content mt-1 min-w-28 rounded-md border bg-background p-1", children: /* @__PURE__ */ jsx4(
1341
+ /* @__PURE__ */ jsxs3("details", { className: "a24-queue__menu relative group/queue-menu", children: [
1342
+ /* @__PURE__ */ jsx5("summary", { "aria-label": "Queued message options", className: "a24-queue__icon flex size-8 cursor-pointer list-none items-center justify-center text-muted-foreground hover:text-foreground [&::-webkit-details-marker]:hidden", children: /* @__PURE__ */ jsx5(Ellipsis, { "aria-hidden": true, className: "size-4" }) }),
1343
+ /* @__PURE__ */ jsx5("div", { className: "a24-queue__menu-content mt-1 min-w-28 rounded-md border bg-background p-1", children: /* @__PURE__ */ jsx5(
1073
1344
  "button",
1074
1345
  {
1075
1346
  type: "button",
@@ -1082,29 +1353,29 @@ function QueueRow({ message, onRemove, onEdit }) {
1082
1353
  ] })
1083
1354
  ] }) : null
1084
1355
  ] }),
1085
- error ? /* @__PURE__ */ jsx4("p", { role: "alert", className: "px-9 pb-2 text-xs text-destructive", children: error }) : null
1356
+ error ? /* @__PURE__ */ jsx5("p", { role: "alert", className: "px-9 pb-2 text-xs text-destructive", children: error }) : null
1086
1357
  ] });
1087
1358
  }
1088
1359
  function AgentChatQueue({ pending, queue, onRemove, onEdit, onResume, className }) {
1089
- const [resumeError, setResumeError] = React4.useState(null);
1360
+ const [resumeError, setResumeError] = React7.useState(null);
1090
1361
  if (!pending.length && !queue?.paused) return null;
1091
- return /* @__PURE__ */ jsxs2("section", { "aria-label": "Message queue", className: cn("a24-queue relative z-0 -mb-2 overflow-visible rounded-t-xl border border-b-0 border-border/50 bg-background pb-2", className), children: [
1092
- queue?.paused ? /* @__PURE__ */ jsxs2("div", { className: "flex min-h-9 items-center justify-between gap-2 px-3 text-xs text-muted-foreground", children: [
1093
- /* @__PURE__ */ jsx4("span", { children: "Queue paused" }),
1094
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: () => {
1362
+ return /* @__PURE__ */ jsxs3("section", { "aria-label": "Message queue", className: cn("a24-queue relative z-0 -mb-2 overflow-visible rounded-t-xl border border-b-0 border-border/50 bg-background pb-2", className), children: [
1363
+ queue?.paused ? /* @__PURE__ */ jsxs3("div", { className: "flex min-h-9 items-center justify-between gap-2 px-3 text-xs text-muted-foreground", children: [
1364
+ /* @__PURE__ */ jsx5("span", { children: "Queue paused" }),
1365
+ /* @__PURE__ */ jsx5("button", { type: "button", onClick: () => {
1095
1366
  void onResume().then(() => setResumeError(null)).catch((cause) => setResumeError(cause instanceof Error ? cause.message : "Could not resume queue"));
1096
1367
  }, className: "font-medium text-foreground hover:underline", children: "Resume queue" })
1097
1368
  ] }) : null,
1098
- resumeError ? /* @__PURE__ */ jsx4("p", { role: "alert", className: "px-3 pb-2 text-xs text-destructive", children: resumeError }) : null,
1099
- /* @__PURE__ */ jsx4("div", { className: "max-h-40 overflow-y-auto", children: pending.map((message) => /* @__PURE__ */ jsx4(QueueRow, { message, onRemove, onEdit }, message.client_submission_id || message.id)) })
1369
+ resumeError ? /* @__PURE__ */ jsx5("p", { role: "alert", className: "px-3 pb-2 text-xs text-destructive", children: resumeError }) : null,
1370
+ /* @__PURE__ */ jsx5("div", { className: "max-h-40 overflow-y-auto", children: pending.map((message) => /* @__PURE__ */ jsx5(QueueRow, { message, onRemove, onEdit }, message.client_submission_id || message.id)) })
1100
1371
  ] });
1101
1372
  }
1102
1373
 
1103
1374
  // src/ui/agent-chat-actions.tsx
1104
- import * as React5 from "react";
1375
+ import * as React8 from "react";
1105
1376
  import { Check, Copy, RefreshCcw, ThumbsDown, ThumbsUp } from "lucide-react";
1106
1377
  import { Popover } from "radix-ui";
1107
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1378
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1108
1379
  var FEEDBACK_REASONS = [
1109
1380
  ["incorrect", "Incorrect"],
1110
1381
  ["irrelevant", "Irrelevant"],
@@ -1115,8 +1386,8 @@ var FEEDBACK_REASONS = [
1115
1386
  ];
1116
1387
  var enteredCompletionRuns = /* @__PURE__ */ new Set();
1117
1388
  function useLiveCompletionRuns(runId, isRunning) {
1118
- const liveRuns = React5.useRef(/* @__PURE__ */ new Set());
1119
- React5.useEffect(() => {
1389
+ const liveRuns = React8.useRef(/* @__PURE__ */ new Set());
1390
+ React8.useEffect(() => {
1120
1391
  if (!runId || !isRunning) return;
1121
1392
  liveRuns.current.add(runId);
1122
1393
  if (liveRuns.current.size > 256) liveRuns.current.delete(liveRuns.current.values().next().value);
@@ -1124,10 +1395,10 @@ function useLiveCompletionRuns(runId, isRunning) {
1124
1395
  return (candidate) => Boolean(candidate && liveRuns.current.has(candidate));
1125
1396
  }
1126
1397
  function useCompletionActionEntrance(isComplete, runId, wasLive = false) {
1127
- const sawIncomplete = React5.useRef(!isComplete);
1128
- const entered = React5.useRef(false);
1398
+ const sawIncomplete = React8.useRef(!isComplete);
1399
+ const entered = React8.useRef(false);
1129
1400
  const shouldEnter = isComplete && !entered.current && (runId ? wasLive && !enteredCompletionRuns.has(runId) : sawIncomplete.current);
1130
- React5.useEffect(() => {
1401
+ React8.useEffect(() => {
1131
1402
  if (!isComplete) sawIncomplete.current = true;
1132
1403
  else if (shouldEnter) {
1133
1404
  entered.current = true;
@@ -1155,17 +1426,17 @@ function AgentChatDefaultActions({
1155
1426
  handlers,
1156
1427
  message
1157
1428
  }) {
1158
- const [feedbackOpen, setFeedbackOpen] = React5.useState(false);
1159
- const [feedbackTrigger, setFeedbackTrigger] = React5.useState(null);
1160
- const [reason, setReason] = React5.useState(handlers?.feedback?.reason ?? null);
1161
- const [comment, setComment] = React5.useState(handlers?.feedback?.comment ?? "");
1162
- const [optimisticCopied, setOptimisticCopied] = React5.useState(false);
1163
- const copyResetTimer = React5.useRef(null);
1164
- React5.useEffect(() => {
1429
+ const [feedbackOpen, setFeedbackOpen] = React8.useState(false);
1430
+ const [feedbackTrigger, setFeedbackTrigger] = React8.useState(null);
1431
+ const [reason, setReason] = React8.useState(handlers?.feedback?.reason ?? null);
1432
+ const [comment, setComment] = React8.useState(handlers?.feedback?.comment ?? "");
1433
+ const [optimisticCopied, setOptimisticCopied] = React8.useState(false);
1434
+ const copyResetTimer = React8.useRef(null);
1435
+ React8.useEffect(() => {
1165
1436
  setReason(handlers?.feedback?.reason ?? null);
1166
1437
  setComment(handlers?.feedback?.comment ?? "");
1167
1438
  }, [handlers?.feedback?.comment, handlers?.feedback?.reason]);
1168
- React5.useEffect(() => () => {
1439
+ React8.useEffect(() => () => {
1169
1440
  if (copyResetTimer.current !== null) window.clearTimeout(copyResetTimer.current);
1170
1441
  }, []);
1171
1442
  const copied = handlers?.copied ?? optimisticCopied;
@@ -1182,32 +1453,32 @@ function AgentChatDefaultActions({
1182
1453
  if (!handlers || message.isFinal === false) return null;
1183
1454
  if (message.role === "user") {
1184
1455
  const sentAt = formatSentAt(message.createdAt);
1185
- return /* @__PURE__ */ jsxs3(ChatMessageActions, { className: "a24-user-message-actions", children: [
1186
- sentAt ? /* @__PURE__ */ jsx5("time", { dateTime: sentAt.dateTime, children: sentAt.label }) : null,
1187
- handlers.onCopy ? /* @__PURE__ */ jsx5(
1456
+ return /* @__PURE__ */ jsxs4(ChatMessageActions, { className: "a24-user-message-actions", children: [
1457
+ sentAt ? /* @__PURE__ */ jsx6("time", { dateTime: sentAt.dateTime, children: sentAt.label }) : null,
1458
+ handlers.onCopy ? /* @__PURE__ */ jsx6(
1188
1459
  ChatMessageAction,
1189
1460
  {
1190
1461
  label: "Copy",
1191
1462
  onClick: copyMessage,
1192
1463
  tooltip: copied ? "Copied!" : "Copy to clipboard",
1193
1464
  className: "a24-user-message-copy",
1194
- children: copied ? /* @__PURE__ */ jsx5(Check, { className: "a24-user-message-copy__check text-green-600" }) : /* @__PURE__ */ jsx5(Copy, { className: "a24-user-message-copy__icon" })
1465
+ children: copied ? /* @__PURE__ */ jsx6(Check, { className: "a24-user-message-copy__check text-green-600" }) : /* @__PURE__ */ jsx6(Copy, { className: "a24-user-message-copy__icon" })
1195
1466
  }
1196
1467
  ) : null
1197
1468
  ] });
1198
1469
  }
1199
1470
  const canWriteFeedback = Boolean(message.runId && handlers.onSetFeedback);
1200
- return /* @__PURE__ */ jsxs3(ChatMessageActions, { className: animateCompletion ? "a24-chat-completion-actions" : void 0, children: [
1201
- handlers.onRetry ? /* @__PURE__ */ jsx5(
1471
+ return /* @__PURE__ */ jsxs4(ChatMessageActions, { className: animateCompletion ? "a24-chat-completion-actions" : void 0, children: [
1472
+ handlers.onRetry ? /* @__PURE__ */ jsx6(
1202
1473
  ChatMessageAction,
1203
1474
  {
1204
1475
  label: "Retry",
1205
1476
  onClick: () => void handlers.onRetry?.(message),
1206
1477
  tooltip: "Regenerate response",
1207
- children: /* @__PURE__ */ jsx5(RefreshCcw, { className: "size-4" })
1478
+ children: /* @__PURE__ */ jsx6(RefreshCcw, { className: "size-4" })
1208
1479
  }
1209
1480
  ) : null,
1210
- canWriteFeedback ? /* @__PURE__ */ jsx5(
1481
+ canWriteFeedback ? /* @__PURE__ */ jsx6(
1211
1482
  ChatMessageAction,
1212
1483
  {
1213
1484
  label: "Like",
@@ -1215,11 +1486,11 @@ function AgentChatDefaultActions({
1215
1486
  rating: handlers.feedback?.rating === "like" ? null : "like"
1216
1487
  }),
1217
1488
  tooltip: "Like this response",
1218
- children: /* @__PURE__ */ jsx5(ThumbsUp, { className: "size-4", fill: handlers.feedback?.rating === "like" ? "currentColor" : "none" })
1489
+ children: /* @__PURE__ */ jsx6(ThumbsUp, { className: "size-4", fill: handlers.feedback?.rating === "like" ? "currentColor" : "none" })
1219
1490
  }
1220
1491
  ) : null,
1221
- canWriteFeedback ? /* @__PURE__ */ jsxs3(Popover.Root, { onOpenChange: setFeedbackOpen, open: feedbackOpen, children: [
1222
- /* @__PURE__ */ jsx5(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx5(
1492
+ canWriteFeedback ? /* @__PURE__ */ jsxs4(Popover.Root, { onOpenChange: setFeedbackOpen, open: feedbackOpen, children: [
1493
+ /* @__PURE__ */ jsx6(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx6(
1223
1494
  ChatMessageAction,
1224
1495
  {
1225
1496
  label: "Dislike",
@@ -1231,14 +1502,14 @@ function AgentChatDefaultActions({
1231
1502
  },
1232
1503
  ref: setFeedbackTrigger,
1233
1504
  tooltip: "Dislike this response",
1234
- children: /* @__PURE__ */ jsx5(ThumbsDown, { className: "size-4", fill: handlers.feedback?.rating === "dislike" ? "currentColor" : "none" })
1505
+ children: /* @__PURE__ */ jsx6(ThumbsDown, { className: "size-4", fill: handlers.feedback?.rating === "dislike" ? "currentColor" : "none" })
1235
1506
  }
1236
1507
  ) }),
1237
- /* @__PURE__ */ jsx5(
1508
+ /* @__PURE__ */ jsx6(
1238
1509
  Popover.Portal,
1239
1510
  {
1240
1511
  container: feedbackTrigger?.closest("[data-agents24-theme-root]") ?? void 0,
1241
- children: /* @__PURE__ */ jsxs3(
1512
+ children: /* @__PURE__ */ jsxs4(
1242
1513
  Popover.Content,
1243
1514
  {
1244
1515
  align: "end",
@@ -1248,8 +1519,8 @@ function AgentChatDefaultActions({
1248
1519
  side: "top",
1249
1520
  sideOffset: 8,
1250
1521
  children: [
1251
- /* @__PURE__ */ jsx5("p", { className: "text-sm font-medium", children: "What could be better?" }),
1252
- /* @__PURE__ */ jsx5("div", { className: "mt-3 flex flex-wrap gap-1.5", children: FEEDBACK_REASONS.map(([value, label]) => /* @__PURE__ */ jsx5(
1522
+ /* @__PURE__ */ jsx6("p", { className: "text-sm font-medium", children: "What could be better?" }),
1523
+ /* @__PURE__ */ jsx6("div", { className: "mt-3 flex flex-wrap gap-1.5", children: FEEDBACK_REASONS.map(([value, label]) => /* @__PURE__ */ jsx6(
1253
1524
  "button",
1254
1525
  {
1255
1526
  "aria-pressed": reason === value,
@@ -1260,7 +1531,7 @@ function AgentChatDefaultActions({
1260
1531
  },
1261
1532
  value
1262
1533
  )) }),
1263
- /* @__PURE__ */ jsx5(
1534
+ /* @__PURE__ */ jsx6(
1264
1535
  "textarea",
1265
1536
  {
1266
1537
  "aria-label": "Optional feedback comment",
@@ -1271,8 +1542,8 @@ function AgentChatDefaultActions({
1271
1542
  value: comment
1272
1543
  }
1273
1544
  ),
1274
- /* @__PURE__ */ jsxs3("div", { className: "mt-3 flex items-center justify-between gap-2", children: [
1275
- /* @__PURE__ */ jsx5(
1545
+ /* @__PURE__ */ jsxs4("div", { className: "mt-3 flex items-center justify-between gap-2", children: [
1546
+ /* @__PURE__ */ jsx6(
1276
1547
  "button",
1277
1548
  {
1278
1549
  className: "rounded-md px-3 py-2 text-sm font-medium hover:bg-muted",
@@ -1283,7 +1554,7 @@ function AgentChatDefaultActions({
1283
1554
  children: "Remove feedback"
1284
1555
  }
1285
1556
  ),
1286
- /* @__PURE__ */ jsx5(
1557
+ /* @__PURE__ */ jsx6(
1287
1558
  "button",
1288
1559
  {
1289
1560
  className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90",
@@ -1302,27 +1573,27 @@ function AgentChatDefaultActions({
1302
1573
  )
1303
1574
  ] }) : null,
1304
1575
  additionalActions,
1305
- handlers.onCopy ? /* @__PURE__ */ jsx5(
1576
+ handlers.onCopy ? /* @__PURE__ */ jsx6(
1306
1577
  ChatMessageAction,
1307
1578
  {
1308
1579
  label: "Copy",
1309
1580
  onClick: copyMessage,
1310
1581
  tooltip: copied ? "Copied!" : "Copy to clipboard",
1311
- children: copied ? /* @__PURE__ */ jsx5(Check, { className: "size-4 text-green-600" }) : /* @__PURE__ */ jsx5(Copy, { className: "size-4" })
1582
+ children: copied ? /* @__PURE__ */ jsx6(Check, { className: "size-4 text-green-600" }) : /* @__PURE__ */ jsx6(Copy, { className: "size-4" })
1312
1583
  }
1313
1584
  ) : null
1314
1585
  ] });
1315
1586
  }
1316
1587
 
1317
1588
  // src/ui/agent-chat-message.tsx
1318
- import * as React10 from "react";
1589
+ import * as React13 from "react";
1319
1590
  import { ChevronDown as ChevronDown3, ChevronUp } from "lucide-react";
1320
1591
 
1321
1592
  // src/ui/agent-response-timeline.tsx
1322
- import * as React9 from "react";
1593
+ import * as React12 from "react";
1323
1594
 
1324
1595
  // src/ui/ask-user-interaction.tsx
1325
- import * as React6 from "react";
1596
+ import * as React9 from "react";
1326
1597
  import {
1327
1598
  ChevronDown,
1328
1599
  ChevronLeft,
@@ -1384,7 +1655,7 @@ function askUserAnswersFromDrafts(questions, drafts) {
1384
1655
  }
1385
1656
 
1386
1657
  // src/ui/ask-user-interaction.tsx
1387
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1658
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1388
1659
  function resolvedAnswerText(question, answer) {
1389
1660
  if (!answer) return ["No response recorded"];
1390
1661
  const labels = answer.selectedOptionIds.flatMap((optionId) => {
@@ -1398,7 +1669,7 @@ function ResolvedQuestions({
1398
1669
  buttonRef,
1399
1670
  part
1400
1671
  }) {
1401
- const [open, setOpen] = React6.useState(false);
1672
+ const [open, setOpen] = React9.useState(false);
1402
1673
  const count = part.questions.length;
1403
1674
  const answers = new Map(
1404
1675
  (part.resolution?.answers || []).map((answer) => [
@@ -1406,8 +1677,8 @@ function ResolvedQuestions({
1406
1677
  answer
1407
1678
  ])
1408
1679
  );
1409
- return /* @__PURE__ */ jsxs4("div", { className: "a24-ask-user a24-ask-user--resolved w-full", children: [
1410
- /* @__PURE__ */ jsxs4(
1680
+ return /* @__PURE__ */ jsxs5("div", { className: "a24-ask-user a24-ask-user--resolved w-full", children: [
1681
+ /* @__PURE__ */ jsxs5(
1411
1682
  "button",
1412
1683
  {
1413
1684
  "aria-expanded": open,
@@ -1416,13 +1687,13 @@ function ResolvedQuestions({
1416
1687
  ref: buttonRef,
1417
1688
  type: "button",
1418
1689
  children: [
1419
- /* @__PURE__ */ jsxs4("span", { children: [
1690
+ /* @__PURE__ */ jsxs5("span", { children: [
1420
1691
  "Asked ",
1421
1692
  count,
1422
1693
  " question",
1423
1694
  count === 1 ? "" : "s"
1424
1695
  ] }),
1425
- open ? /* @__PURE__ */ jsx6(ChevronDown, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsx6(
1696
+ open ? /* @__PURE__ */ jsx7(ChevronDown, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsx7(
1426
1697
  ChevronRight,
1427
1698
  {
1428
1699
  "aria-hidden": "true",
@@ -1432,12 +1703,12 @@ function ResolvedQuestions({
1432
1703
  ]
1433
1704
  }
1434
1705
  ),
1435
- open ? /* @__PURE__ */ jsx6("div", { className: "mt-2 space-y-3 ps-4", children: part.questions.map((question) => /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
1436
- /* @__PURE__ */ jsx6("div", { className: "text-sm font-medium text-foreground", children: question.question }),
1437
- /* @__PURE__ */ jsx6("div", { className: "mt-1 space-y-1 text-sm text-muted-foreground", children: resolvedAnswerText(
1706
+ open ? /* @__PURE__ */ jsx7("div", { className: "mt-2 space-y-3 ps-4", children: part.questions.map((question) => /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1707
+ /* @__PURE__ */ jsx7("div", { className: "text-sm font-medium text-foreground", children: question.question }),
1708
+ /* @__PURE__ */ jsx7("div", { className: "mt-1 space-y-1 text-sm text-muted-foreground", children: resolvedAnswerText(
1438
1709
  question,
1439
1710
  answers.get(question.id)
1440
- ).map((value, index) => /* @__PURE__ */ jsx6(
1711
+ ).map((value, index) => /* @__PURE__ */ jsx7(
1441
1712
  "div",
1442
1713
  {
1443
1714
  className: "whitespace-pre-wrap break-words",
@@ -1455,23 +1726,23 @@ function AskUserInteraction({
1455
1726
  part
1456
1727
  }) {
1457
1728
  const questions = part.questions;
1458
- const [step, setStep] = React6.useState(0);
1459
- const [drafts, setDrafts] = React6.useState(
1729
+ const [step, setStep] = React9.useState(0);
1730
+ const [drafts, setDrafts] = React9.useState(
1460
1731
  () => emptyAskUserDrafts(questions)
1461
1732
  );
1462
- const headingRef = React6.useRef(null);
1463
- const questionsRef = React6.useRef(questions);
1464
- const resolvedButtonRef = React6.useRef(null);
1465
- const wasResolvedRef = React6.useRef(part.status !== "pending");
1733
+ const headingRef = React9.useRef(null);
1734
+ const questionsRef = React9.useRef(questions);
1735
+ const resolvedButtonRef = React9.useRef(null);
1736
+ const wasResolvedRef = React9.useRef(part.status !== "pending");
1466
1737
  questionsRef.current = questions;
1467
- React6.useEffect(() => {
1738
+ React9.useEffect(() => {
1468
1739
  setStep(0);
1469
1740
  setDrafts(emptyAskUserDrafts(questionsRef.current));
1470
1741
  }, [part.interruptId]);
1471
- React6.useEffect(() => {
1742
+ React9.useEffect(() => {
1472
1743
  headingRef.current?.focus();
1473
1744
  }, [step]);
1474
- React6.useEffect(() => {
1745
+ React9.useEffect(() => {
1475
1746
  const isResolved = part.status !== "pending";
1476
1747
  if (isResolved && !wasResolvedRef.current) {
1477
1748
  resolvedButtonRef.current?.focus();
@@ -1479,11 +1750,11 @@ function AskUserInteraction({
1479
1750
  wasResolvedRef.current = isResolved;
1480
1751
  }, [part.status]);
1481
1752
  if (part.status !== "pending") {
1482
- return /* @__PURE__ */ jsx6(ResolvedQuestions, { buttonRef: resolvedButtonRef, part });
1753
+ return /* @__PURE__ */ jsx7(ResolvedQuestions, { buttonRef: resolvedButtonRef, part });
1483
1754
  }
1484
1755
  const question = questions[step];
1485
1756
  if (!question) {
1486
- return /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", role: "alert", children: "This question request is unavailable." });
1757
+ return /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", role: "alert", children: "This question request is unavailable." });
1487
1758
  }
1488
1759
  const draft = drafts[question.id] || {
1489
1760
  customText: "",
@@ -1517,9 +1788,9 @@ function AskUserInteraction({
1517
1788
  })
1518
1789
  );
1519
1790
  };
1520
- return /* @__PURE__ */ jsxs4("div", { className: "a24-ask-user space-y-3 rounded-xl border border-border/50 bg-background p-4 shadow-sm", children: [
1521
- /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 items-start justify-between gap-4", children: [
1522
- /* @__PURE__ */ jsx6(
1791
+ return /* @__PURE__ */ jsxs5("div", { className: "a24-ask-user space-y-3 rounded-xl border border-border/50 bg-background p-4 shadow-sm", children: [
1792
+ /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-start justify-between gap-4", children: [
1793
+ /* @__PURE__ */ jsx7(
1523
1794
  "h3",
1524
1795
  {
1525
1796
  className: "min-w-0 flex-1 text-base font-medium leading-6 text-foreground outline-none",
@@ -1528,8 +1799,8 @@ function AskUserInteraction({
1528
1799
  children: question.question
1529
1800
  }
1530
1801
  ),
1531
- /* @__PURE__ */ jsxs4("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: [
1532
- /* @__PURE__ */ jsx6(
1802
+ /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: [
1803
+ /* @__PURE__ */ jsx7(
1533
1804
  "button",
1534
1805
  {
1535
1806
  "aria-label": "Previous question",
@@ -1537,7 +1808,7 @@ function AskUserInteraction({
1537
1808
  disabled: isBusy || step === 0,
1538
1809
  onClick: () => setStep((current) => Math.max(0, current - 1)),
1539
1810
  type: "button",
1540
- children: /* @__PURE__ */ jsx6(
1811
+ children: /* @__PURE__ */ jsx7(
1541
1812
  ChevronLeft,
1542
1813
  {
1543
1814
  "aria-hidden": "true",
@@ -1546,7 +1817,7 @@ function AskUserInteraction({
1546
1817
  )
1547
1818
  }
1548
1819
  ),
1549
- /* @__PURE__ */ jsxs4(
1820
+ /* @__PURE__ */ jsxs5(
1550
1821
  "span",
1551
1822
  {
1552
1823
  "aria-label": `Question ${step + 1} of ${questions.length}`,
@@ -1558,7 +1829,7 @@ function AskUserInteraction({
1558
1829
  ]
1559
1830
  }
1560
1831
  ),
1561
- /* @__PURE__ */ jsx6(
1832
+ /* @__PURE__ */ jsx7(
1562
1833
  "button",
1563
1834
  {
1564
1835
  "aria-label": isLastQuestion ? "Submit answers" : "Next question",
@@ -1566,7 +1837,7 @@ function AskUserInteraction({
1566
1837
  disabled: isBusy || !onSubmit || !canMoveForward,
1567
1838
  onClick: () => completeStep(drafts),
1568
1839
  type: "button",
1569
- children: /* @__PURE__ */ jsx6(
1840
+ children: /* @__PURE__ */ jsx7(
1570
1841
  ChevronRight,
1571
1842
  {
1572
1843
  "aria-hidden": "true",
@@ -1577,10 +1848,10 @@ function AskUserInteraction({
1577
1848
  )
1578
1849
  ] })
1579
1850
  ] }),
1580
- /* @__PURE__ */ jsxs4("div", { className: "space-y-1", children: [
1851
+ /* @__PURE__ */ jsxs5("div", { className: "space-y-1", children: [
1581
1852
  question.options.map((option, index) => {
1582
1853
  const selected = draft.selectedOptionIds.includes(option.id);
1583
- return /* @__PURE__ */ jsxs4(
1854
+ return /* @__PURE__ */ jsxs5(
1584
1855
  "button",
1585
1856
  {
1586
1857
  "aria-pressed": selected,
@@ -1592,7 +1863,7 @@ function AskUserInteraction({
1592
1863
  onClick: () => selectOption(option.id),
1593
1864
  type: "button",
1594
1865
  children: [
1595
- /* @__PURE__ */ jsx6(
1866
+ /* @__PURE__ */ jsx7(
1596
1867
  "span",
1597
1868
  {
1598
1869
  className: cn(
@@ -1602,8 +1873,8 @@ function AskUserInteraction({
1602
1873
  children: index + 1
1603
1874
  }
1604
1875
  ),
1605
- /* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 font-medium text-foreground", children: option.label }),
1606
- /* @__PURE__ */ jsx6(
1876
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 font-medium text-foreground", children: option.label }),
1877
+ /* @__PURE__ */ jsx7(
1607
1878
  ChevronRight,
1608
1879
  {
1609
1880
  "aria-hidden": "true",
@@ -1615,9 +1886,9 @@ function AskUserInteraction({
1615
1886
  option.id
1616
1887
  );
1617
1888
  }),
1618
- /* @__PURE__ */ jsxs4("div", { className: "flex min-h-11 items-center gap-2 rounded-xl bg-muted px-2.5 py-1.5 focus-within:ring-1 focus-within:ring-ring", children: [
1619
- /* @__PURE__ */ jsx6("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-full border border-border/70 bg-background/70 text-muted-foreground", children: /* @__PURE__ */ jsx6(Pencil, { "aria-hidden": "true", className: "size-4" }) }),
1620
- /* @__PURE__ */ jsx6(
1889
+ /* @__PURE__ */ jsxs5("div", { className: "flex min-h-11 items-center gap-2 rounded-xl bg-muted px-2.5 py-1.5 focus-within:ring-1 focus-within:ring-ring", children: [
1890
+ /* @__PURE__ */ jsx7("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-full border border-border/70 bg-background/70 text-muted-foreground", children: /* @__PURE__ */ jsx7(Pencil, { "aria-hidden": "true", className: "size-4" }) }),
1891
+ /* @__PURE__ */ jsx7(
1621
1892
  "input",
1622
1893
  {
1623
1894
  "aria-label": "Other response",
@@ -1636,7 +1907,7 @@ function AskUserInteraction({
1636
1907
  value: draft.customText
1637
1908
  }
1638
1909
  ),
1639
- draft.customText.trim() ? /* @__PURE__ */ jsx6(
1910
+ draft.customText.trim() ? /* @__PURE__ */ jsx7(
1640
1911
  "button",
1641
1912
  {
1642
1913
  className: "h-8 shrink-0 rounded-full bg-foreground px-4 text-sm font-medium text-background transition-colors hover:opacity-85 disabled:opacity-50",
@@ -1648,12 +1919,12 @@ function AskUserInteraction({
1648
1919
  ) : null
1649
1920
  ] })
1650
1921
  ] }),
1651
- error ? /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", role: "alert", children: error }) : null
1922
+ error ? /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", role: "alert", children: error }) : null
1652
1923
  ] });
1653
1924
  }
1654
1925
 
1655
1926
  // src/ui/agent-chat-context-compression-row.tsx
1656
- import { jsx as jsx7 } from "react/jsx-runtime";
1927
+ import { jsx as jsx8 } from "react/jsx-runtime";
1657
1928
  function compressionPresentation(part) {
1658
1929
  if (part.status === "failed") {
1659
1930
  return { label: "Could not compact message history", status: "failed" };
@@ -1668,7 +1939,7 @@ function AgentChatContextCompressionRow({
1668
1939
  part
1669
1940
  }) {
1670
1941
  const presentation = compressionPresentation(part);
1671
- return /* @__PURE__ */ jsx7(
1942
+ return /* @__PURE__ */ jsx8(
1672
1943
  "div",
1673
1944
  {
1674
1945
  "aria-live": "polite",
@@ -1676,11 +1947,11 @@ function AgentChatContextCompressionRow({
1676
1947
  "data-agents24-context-compression": "",
1677
1948
  "data-status": part.status,
1678
1949
  role: "status",
1679
- children: /* @__PURE__ */ jsx7("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsx7("div", { className: cn(
1950
+ children: /* @__PURE__ */ jsx8("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsx8("div", { className: cn(
1680
1951
  "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--without-orb",
1681
1952
  presentation.status === "failed" && "a24-tool-trigger--error",
1682
1953
  presentation.status === "running" && "a24-tool-trigger--active"
1683
- ), children: /* @__PURE__ */ jsx7("span", { className: cn(
1954
+ ), children: /* @__PURE__ */ jsx8("span", { className: cn(
1684
1955
  "a24-tool-trigger__label",
1685
1956
  presentation.status === "running" && "a24-tool-shimmer"
1686
1957
  ), children: presentation.label }) }) })
@@ -1689,7 +1960,7 @@ function AgentChatContextCompressionRow({
1689
1960
  }
1690
1961
 
1691
1962
  // src/ui/message-response.tsx
1692
- import * as React7 from "react";
1963
+ import * as React10 from "react";
1693
1964
  import { defaultRehypePlugins, Streamdown } from "streamdown";
1694
1965
 
1695
1966
  // src/active-content.ts
@@ -1714,17 +1985,17 @@ function safeChatMarkdownHref(value) {
1714
1985
  }
1715
1986
 
1716
1987
  // src/ui/message-response.tsx
1717
- import { Fragment as Fragment2, jsx as jsx8 } from "react/jsx-runtime";
1988
+ import { Fragment as Fragment2, jsx as jsx9 } from "react/jsx-runtime";
1718
1989
  function SafeMarkdownLink({ children, href, ...props }) {
1719
1990
  const domProps = { ...props };
1720
1991
  delete domProps.node;
1721
1992
  const safeHref = safeChatMarkdownHref(href);
1722
- if (!safeHref) return /* @__PURE__ */ jsx8("span", { children });
1723
- if (safeHref.startsWith("#")) return /* @__PURE__ */ jsx8("a", { ...domProps, href: safeHref, children });
1724
- return /* @__PURE__ */ jsx8("a", { ...domProps, href: safeHref, rel: "noopener noreferrer", target: "_blank", children });
1993
+ if (!safeHref) return /* @__PURE__ */ jsx9("span", { children });
1994
+ if (safeHref.startsWith("#")) return /* @__PURE__ */ jsx9("a", { ...domProps, href: safeHref, children });
1995
+ return /* @__PURE__ */ jsx9("a", { ...domProps, href: safeHref, rel: "noopener noreferrer", target: "_blank", children });
1725
1996
  }
1726
1997
  function BlockedMarkdownImage({ alt }) {
1727
- return alt ? /* @__PURE__ */ jsx8("span", { "aria-label": `Image blocked: ${alt}`, role: "img", children: alt }) : null;
1998
+ return alt ? /* @__PURE__ */ jsx9("span", { "aria-label": `Image blocked: ${alt}`, role: "img", children: alt }) : null;
1728
1999
  }
1729
2000
  var BLOCK_MARKDOWN_TAGS = /* @__PURE__ */ new Set([
1730
2001
  "blockquote",
@@ -1745,7 +2016,7 @@ function isMultilineCodeNode(node) {
1745
2016
  return node?.tagName === "code" && node.position?.start?.line !== void 0 && node.position?.end?.line !== void 0 && node.position.start.line !== node.position.end.line;
1746
2017
  }
1747
2018
  function hasBlockMarkdownChild(child) {
1748
- if (!React7.isValidElement(child)) {
2019
+ if (!React10.isValidElement(child)) {
1749
2020
  return false;
1750
2021
  }
1751
2022
  if (typeof child.type === "string" && BLOCK_MARKDOWN_TAGS.has(child.type)) {
@@ -1755,7 +2026,7 @@ function hasBlockMarkdownChild(child) {
1755
2026
  if (BLOCK_MARKDOWN_TAGS.has(props.node?.tagName || "") || isMultilineCodeNode(props.node)) {
1756
2027
  return true;
1757
2028
  }
1758
- return React7.Children.toArray(props.children).some(hasBlockMarkdownChild);
2029
+ return React10.Children.toArray(props.children).some(hasBlockMarkdownChild);
1759
2030
  }
1760
2031
  function MessageMarkdownParagraph({
1761
2032
  children,
@@ -1763,17 +2034,17 @@ function MessageMarkdownParagraph({
1763
2034
  }) {
1764
2035
  const domProps = { ...props };
1765
2036
  delete domProps.node;
1766
- const childArray = React7.Children.toArray(children).filter(
2037
+ const childArray = React10.Children.toArray(children).filter(
1767
2038
  (child) => child !== null && child !== ""
1768
2039
  );
1769
- const isImageOnly = childArray.length === 1 && React7.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
2040
+ const isImageOnly = childArray.length === 1 && React10.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
1770
2041
  if (isImageOnly) {
1771
- return /* @__PURE__ */ jsx8(Fragment2, { children });
2042
+ return /* @__PURE__ */ jsx9(Fragment2, { children });
1772
2043
  }
1773
2044
  if (childArray.some(hasBlockMarkdownChild)) {
1774
- return /* @__PURE__ */ jsx8("div", { ...domProps, children });
2045
+ return /* @__PURE__ */ jsx9("div", { ...domProps, children });
1775
2046
  }
1776
- return /* @__PURE__ */ jsx8("p", { ...domProps, children });
2047
+ return /* @__PURE__ */ jsx9("p", { ...domProps, children });
1777
2048
  }
1778
2049
  var MESSAGE_RESPONSE_COMPONENTS = {
1779
2050
  a: SafeMarkdownLink,
@@ -1793,7 +2064,7 @@ var MESSAGE_RESPONSE_REHYPE_PLUGINS = [
1793
2064
  ]
1794
2065
  ] : []
1795
2066
  ];
1796
- var MessageResponse = React7.memo(
2067
+ var MessageResponse = React10.memo(
1797
2068
  ({
1798
2069
  children,
1799
2070
  className,
@@ -1811,11 +2082,11 @@ var MessageResponse = React7.memo(
1811
2082
  maxCatchupChars: 32,
1812
2083
  text
1813
2084
  });
1814
- const streamdownComponents = React7.useMemo(
2085
+ const streamdownComponents = React10.useMemo(
1815
2086
  () => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
1816
2087
  [components]
1817
2088
  );
1818
- return /* @__PURE__ */ jsx8(
2089
+ return /* @__PURE__ */ jsx9(
1819
2090
  Streamdown,
1820
2091
  {
1821
2092
  className: cn("a24-message-response", className),
@@ -1867,10 +2138,10 @@ function resolvedHitlLabel(part) {
1867
2138
  }
1868
2139
 
1869
2140
  // src/ui/tool-sessions.tsx
1870
- import * as React8 from "react";
2141
+ import * as React11 from "react";
1871
2142
  import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2 } from "lucide-react";
1872
2143
  import { ThinkingOrb } from "thinking-orbs";
1873
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
2144
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
1874
2145
  function toolSlotContext(isActive2, label, part, slots) {
1875
2146
  return {
1876
2147
  isActive: isActive2,
@@ -1888,7 +2159,7 @@ function ToolResourceAction({ context }) {
1888
2159
  const target = context.resourceTargets[0];
1889
2160
  if (!target) return null;
1890
2161
  const name = resourceTargetName(target);
1891
- return /* @__PURE__ */ jsx9(
2162
+ return /* @__PURE__ */ jsx10(
1892
2163
  "button",
1893
2164
  {
1894
2165
  "aria-label": `Open ${target.kind} ${target.path}`,
@@ -1902,8 +2173,8 @@ function ToolResourceAction({ context }) {
1902
2173
  );
1903
2174
  }
1904
2175
  function toolAccessory(context, slots) {
1905
- return /* @__PURE__ */ jsxs5(Fragment3, { children: [
1906
- slots?.onResourceAction ? /* @__PURE__ */ jsx9(ToolResourceAction, { context }) : null,
2176
+ return /* @__PURE__ */ jsxs6(Fragment3, { children: [
2177
+ slots?.onResourceAction ? /* @__PURE__ */ jsx10(ToolResourceAction, { context }) : null,
1907
2178
  slots?.renderToolAccessory?.(context)
1908
2179
  ] });
1909
2180
  }
@@ -1980,12 +2251,12 @@ function ToolActivityReel({
1980
2251
  }) {
1981
2252
  const initial = initialLabel && initialLabel !== label ? initialLabel : label;
1982
2253
  const parsedInitialShownAt = initialShownAt ? Date.parse(initialShownAt) : Number.NaN;
1983
- const [displayed, setDisplayed] = React8.useState(initial);
1984
- const [previous, setPrevious] = React8.useState(null);
1985
- const displayedRef = React8.useRef(initial);
1986
- const latestRef = React8.useRef(label);
1987
- const shownAtRef = React8.useRef(Number.isFinite(parsedInitialShownAt) ? parsedInitialShownAt : Date.now());
1988
- React8.useEffect(() => {
2254
+ const [displayed, setDisplayed] = React11.useState(initial);
2255
+ const [previous, setPrevious] = React11.useState(null);
2256
+ const displayedRef = React11.useRef(initial);
2257
+ const latestRef = React11.useRef(label);
2258
+ const shownAtRef = React11.useRef(Number.isFinite(parsedInitialShownAt) ? parsedInitialShownAt : Date.now());
2259
+ React11.useEffect(() => {
1989
2260
  latestRef.current = label;
1990
2261
  if (displayedRef.current === label) return;
1991
2262
  const showLatest = () => {
@@ -2005,39 +2276,39 @@ function ToolActivityReel({
2005
2276
  const timer = window.setTimeout(showLatest, remaining);
2006
2277
  return () => window.clearTimeout(timer);
2007
2278
  }, [label]);
2008
- React8.useEffect(() => {
2279
+ React11.useEffect(() => {
2009
2280
  if (!previous) return;
2010
2281
  const timer = window.setTimeout(() => setPrevious(null), 200);
2011
2282
  return () => window.clearTimeout(timer);
2012
2283
  }, [previous]);
2013
- return /* @__PURE__ */ jsxs5("span", { className: "a24-tool-reel", "aria-live": announce ? "polite" : "off", children: [
2014
- previous ? /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", className: "a24-tool-reel__previous", children: previous }) : null,
2015
- /* @__PURE__ */ jsx9("span", { className: previous ? "a24-tool-reel__current" : void 0, children: displayed })
2284
+ return /* @__PURE__ */ jsxs6("span", { className: "a24-tool-reel", "aria-live": announce ? "polite" : "off", children: [
2285
+ previous ? /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", className: "a24-tool-reel__previous", children: previous }) : null,
2286
+ /* @__PURE__ */ jsx10("span", { className: previous ? "a24-tool-reel__current" : void 0, children: displayed })
2016
2287
  ] });
2017
2288
  }
2018
2289
  function ToolActivityOrb({ label }) {
2019
- return /* @__PURE__ */ jsx9("span", { className: "a24-tool-orb", children: /* @__PURE__ */ jsx9(ThinkingOrb, { "aria-label": label || "Working", size: 20, speed: 0.8, state: "searching" }) });
2290
+ return /* @__PURE__ */ jsx10("span", { className: "a24-tool-orb", children: /* @__PURE__ */ jsx10(ThinkingOrb, { "aria-label": label || "Working", size: 20, speed: 0.8, state: "searching" }) });
2020
2291
  }
2021
2292
  function AgentChatActivityRow({
2022
2293
  label,
2023
2294
  modelTurnId,
2024
2295
  onSelect
2025
2296
  }) {
2026
- const content = /* @__PURE__ */ jsxs5(Fragment3, { children: [
2027
- /* @__PURE__ */ jsx9(ToolActivityOrb, { label }),
2028
- /* @__PURE__ */ jsx9("span", { className: "a24-tool-trigger__label a24-tool-shimmer", children: /* @__PURE__ */ jsx9(ToolActivityReel, { label }) })
2297
+ const content = /* @__PURE__ */ jsxs6(Fragment3, { children: [
2298
+ /* @__PURE__ */ jsx10(ToolActivityOrb, { label }),
2299
+ /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label a24-tool-shimmer", children: /* @__PURE__ */ jsx10(ToolActivityReel, { label }) })
2029
2300
  ] });
2030
- return /* @__PURE__ */ jsx9("div", { className: "a24-tool-trigger-row a24-tool-trigger-row--root", "data-agents24-model-turn": modelTurnId, role: "status", children: onSelect ? /* @__PURE__ */ jsx9("button", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", onClick: onSelect, type: "button", children: content }) : /* @__PURE__ */ jsx9("div", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", children: content }) });
2301
+ return /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger-row a24-tool-trigger-row--root", "data-agents24-model-turn": modelTurnId, role: "status", children: onSelect ? /* @__PURE__ */ jsx10("button", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", onClick: onSelect, type: "button", children: content }) : /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", children: content }) });
2031
2302
  }
2032
2303
  function AgentChatModelTurnRow({ part }) {
2033
- return /* @__PURE__ */ jsx9(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId });
2304
+ return /* @__PURE__ */ jsx10(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId });
2034
2305
  }
2035
2306
  function AgentChatNodeActivityRow({
2036
2307
  onSelect,
2037
2308
  part
2038
2309
  }) {
2039
- const [open, setOpen] = React8.useState(false);
2040
- const contentId = React8.useId();
2310
+ const [open, setOpen] = React11.useState(false);
2311
+ const contentId = React11.useId();
2041
2312
  const running = part.status === "running";
2042
2313
  const failed = part.status === "failed";
2043
2314
  const failureMessage = part.failure?.message || "The node could not complete the request.";
@@ -2048,18 +2319,18 @@ function AgentChatNodeActivityRow({
2048
2319
  running && "a24-tool-trigger--active",
2049
2320
  failed && "a24-tool-trigger--error"
2050
2321
  );
2051
- const label = running ? /* @__PURE__ */ jsx9("span", { className: "a24-tool-shimmer", children: /* @__PURE__ */ jsx9(ToolActivityReel, { label: part.label }) }) : part.label;
2322
+ const label = running ? /* @__PURE__ */ jsx10("span", { className: "a24-tool-shimmer", children: /* @__PURE__ */ jsx10(ToolActivityReel, { label: part.label }) }) : part.label;
2052
2323
  if (!failed) {
2053
- return /* @__PURE__ */ jsx9("div", { className: "a24-tool-trigger-row", role: "status", children: onSelect ? /* @__PURE__ */ jsxs5("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2054
- running ? /* @__PURE__ */ jsx9(ToolActivityOrb, { label: part.label }) : null,
2055
- /* @__PURE__ */ jsx9("span", { className: "a24-tool-trigger__label", children: label })
2056
- ] }) : /* @__PURE__ */ jsxs5("div", { className: triggerClassName, children: [
2057
- running ? /* @__PURE__ */ jsx9(ToolActivityOrb, { label: part.label }) : null,
2058
- /* @__PURE__ */ jsx9("span", { className: "a24-tool-trigger__label", children: label })
2324
+ return /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger-row", role: "status", children: onSelect ? /* @__PURE__ */ jsxs6("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2325
+ running ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: part.label }) : null,
2326
+ /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
2327
+ ] }) : /* @__PURE__ */ jsxs6("div", { className: triggerClassName, children: [
2328
+ running ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: part.label }) : null,
2329
+ /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
2059
2330
  ] }) });
2060
2331
  }
2061
- return /* @__PURE__ */ jsxs5("div", { className: "a24-tool-disclosure", children: [
2062
- /* @__PURE__ */ jsx9("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsxs5(
2332
+ return /* @__PURE__ */ jsxs6("div", { className: "a24-tool-disclosure", children: [
2333
+ /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsxs6(
2063
2334
  "button",
2064
2335
  {
2065
2336
  "aria-controls": contentId,
@@ -2071,12 +2342,12 @@ function AgentChatNodeActivityRow({
2071
2342
  },
2072
2343
  type: "button",
2073
2344
  children: [
2074
- /* @__PURE__ */ jsx9("span", { className: "a24-tool-trigger__label", children: label }),
2075
- open ? /* @__PURE__ */ jsx9(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx9(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2345
+ /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label }),
2346
+ open ? /* @__PURE__ */ jsx10(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx10(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2076
2347
  ]
2077
2348
  }
2078
2349
  ) }),
2079
- open ? /* @__PURE__ */ jsx9("div", { className: "a24-tool-detail a24-tool-detail--error", id: contentId, children: failureMessage }) : null
2350
+ open ? /* @__PURE__ */ jsx10("div", { className: "a24-tool-detail a24-tool-detail--error", id: contentId, children: failureMessage }) : null
2080
2351
  ] });
2081
2352
  }
2082
2353
  function toolRowLabel(part, separateResource = false) {
@@ -2102,25 +2373,25 @@ function ToolDisclosure({
2102
2373
  statusLabel,
2103
2374
  accessory
2104
2375
  }) {
2105
- const [open, setOpen] = React8.useState(false);
2106
- const contentId = React8.useId();
2107
- const expandable = React8.Children.toArray(children).length > 0;
2376
+ const [open, setOpen] = React11.useState(false);
2377
+ const contentId = React11.useId();
2378
+ const expandable = React11.Children.toArray(children).length > 0;
2108
2379
  if (!expandable) {
2109
2380
  const triggerClassName = cn("a24-tool-trigger", root && "a24-tool-trigger--root", root && !showOrb && "a24-tool-trigger--without-orb", error && "a24-tool-trigger--error", loading && "a24-tool-trigger--active");
2110
- return /* @__PURE__ */ jsxs5("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2111
- onSelect && part ? /* @__PURE__ */ jsxs5("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2112
- showOrb ? /* @__PURE__ */ jsx9(ToolActivityOrb, { label: statusLabel }) : null,
2113
- /* @__PURE__ */ jsx9("span", { className: "a24-tool-trigger__label", children: label })
2114
- ] }) : /* @__PURE__ */ jsxs5("div", { className: triggerClassName, children: [
2115
- showOrb ? /* @__PURE__ */ jsx9(ToolActivityOrb, { label: statusLabel }) : null,
2116
- /* @__PURE__ */ jsx9("span", { className: "a24-tool-trigger__label", children: label })
2381
+ return /* @__PURE__ */ jsxs6("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2382
+ onSelect && part ? /* @__PURE__ */ jsxs6("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2383
+ showOrb ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: statusLabel }) : null,
2384
+ /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
2385
+ ] }) : /* @__PURE__ */ jsxs6("div", { className: triggerClassName, children: [
2386
+ showOrb ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: statusLabel }) : null,
2387
+ /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
2117
2388
  ] }),
2118
2389
  accessory
2119
2390
  ] });
2120
2391
  }
2121
- return /* @__PURE__ */ jsxs5("div", { className: "a24-tool-disclosure", children: [
2122
- /* @__PURE__ */ jsxs5("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2123
- /* @__PURE__ */ jsxs5(
2392
+ return /* @__PURE__ */ jsxs6("div", { className: "a24-tool-disclosure", children: [
2393
+ /* @__PURE__ */ jsxs6("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2394
+ /* @__PURE__ */ jsxs6(
2124
2395
  "button",
2125
2396
  {
2126
2397
  "aria-controls": contentId,
@@ -2134,25 +2405,25 @@ function ToolDisclosure({
2134
2405
  },
2135
2406
  type: "button",
2136
2407
  children: [
2137
- showOrb ? /* @__PURE__ */ jsx9(ToolActivityOrb, { label: statusLabel }) : null,
2138
- /* @__PURE__ */ jsx9("span", { className: "a24-tool-trigger__label", children: label }),
2139
- open ? /* @__PURE__ */ jsx9(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx9(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2408
+ showOrb ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: statusLabel }) : null,
2409
+ /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label }),
2410
+ open ? /* @__PURE__ */ jsx10(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx10(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2140
2411
  ]
2141
2412
  }
2142
2413
  ),
2143
2414
  accessory
2144
2415
  ] }),
2145
- open ? /* @__PURE__ */ jsx9("div", { className: "a24-tool-disclosure__content", id: contentId, children }) : null
2416
+ open ? /* @__PURE__ */ jsx10("div", { className: "a24-tool-disclosure__content", id: contentId, children }) : null
2146
2417
  ] });
2147
2418
  }
2148
2419
  function ToolLabel({ active, label, part, slots }) {
2149
2420
  const rendered = slots?.renderToolLabel?.(toolSlotContext(active, label, part, slots)) ?? label;
2150
- return active ? /* @__PURE__ */ jsx9("span", { className: "a24-tool-shimmer", children: rendered }) : /* @__PURE__ */ jsx9(Fragment3, { children: rendered });
2421
+ return active ? /* @__PURE__ */ jsx10("span", { className: "a24-tool-shimmer", children: rendered }) : /* @__PURE__ */ jsx10(Fragment3, { children: rendered });
2151
2422
  }
2152
2423
  function ToolList({ children }) {
2153
- const listRef = React8.useRef(null);
2154
- const [fades, setFades] = React8.useState({ bottom: false, top: false });
2155
- const updateFades = React8.useCallback(() => {
2424
+ const listRef = React11.useRef(null);
2425
+ const [fades, setFades] = React11.useState({ bottom: false, top: false });
2426
+ const updateFades = React11.useCallback(() => {
2156
2427
  const list = listRef.current;
2157
2428
  if (!list) return;
2158
2429
  const next = {
@@ -2161,7 +2432,7 @@ function ToolList({ children }) {
2161
2432
  };
2162
2433
  setFades((current) => current.bottom === next.bottom && current.top === next.top ? current : next);
2163
2434
  }, []);
2164
- React8.useEffect(() => {
2435
+ React11.useEffect(() => {
2165
2436
  updateFades();
2166
2437
  const list = listRef.current;
2167
2438
  if (!list || typeof ResizeObserver === "undefined") return;
@@ -2169,13 +2440,13 @@ function ToolList({ children }) {
2169
2440
  observer.observe(list);
2170
2441
  return () => observer.disconnect();
2171
2442
  }, [children, updateFades]);
2172
- return /* @__PURE__ */ jsx9(
2443
+ return /* @__PURE__ */ jsx10(
2173
2444
  "div",
2174
2445
  {
2175
2446
  className: "a24-tool-list-frame",
2176
2447
  "data-scroll-fade-bottom": fades.bottom ? "" : void 0,
2177
2448
  "data-scroll-fade-top": fades.top ? "" : void 0,
2178
- children: /* @__PURE__ */ jsx9("div", { className: "a24-tool-list", onScroll: updateFades, ref: listRef, role: "list", children })
2449
+ children: /* @__PURE__ */ jsx10("div", { className: "a24-tool-list", onScroll: updateFades, ref: listRef, role: "list", children })
2179
2450
  }
2180
2451
  );
2181
2452
  }
@@ -2192,12 +2463,12 @@ function AgentChatToolRow({
2192
2463
  const detail = failed ? failureMessage : optionalText(part.presentation.detail);
2193
2464
  const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
2194
2465
  const context = toolSlotContext(active, toolRowLabel(part, Boolean(slots?.onResourceAction)), part, slots);
2195
- return /* @__PURE__ */ jsx9("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsxs5(
2466
+ return /* @__PURE__ */ jsx10("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsxs6(
2196
2467
  ToolDisclosure,
2197
2468
  {
2198
2469
  error: failed,
2199
2470
  accessory: toolAccessory(context, slots),
2200
- label: /* @__PURE__ */ jsx9(ToolLabel, { active, label: context.label, part, slots }),
2471
+ label: /* @__PURE__ */ jsx10(ToolLabel, { active, label: context.label, part, slots }),
2201
2472
  loading: active,
2202
2473
  onExpandedChange: slots?.onExpandedChange,
2203
2474
  onSelect: slots?.onToolSelect,
@@ -2206,7 +2477,7 @@ function AgentChatToolRow({
2206
2477
  showOrb: showOrb ?? active,
2207
2478
  statusLabel: active ? context.label : void 0,
2208
2479
  children: [
2209
- detail ? /* @__PURE__ */ jsx9("div", { className: cn("a24-tool-detail", failed && "a24-tool-detail--error"), children: detail }) : null,
2480
+ detail ? /* @__PURE__ */ jsx10("div", { className: cn("a24-tool-detail", failed && "a24-tool-detail--error"), children: detail }) : null,
2210
2481
  hostDetails
2211
2482
  ]
2212
2483
  }
@@ -2226,19 +2497,19 @@ function AgentChatToolSession({
2226
2497
  parts,
2227
2498
  slots
2228
2499
  }) {
2229
- const presentedLiveRef = React8.useRef(false);
2500
+ const presentedLiveRef = React11.useRef(false);
2230
2501
  if (isLive && isLatestActivity) presentedLiveRef.current = true;
2231
2502
  const activeIndex = parts.findLastIndex((part) => isActive(part, activeToolId));
2232
2503
  const running = activeIndex >= 0;
2233
- if (parts.length === 1 && !modelTurn && !leadingModelTurn) return /* @__PURE__ */ jsx9(AgentChatToolRow, { activeToolId, part: parts[0], slots });
2504
+ if (parts.length === 1 && !modelTurn && !leadingModelTurn) return /* @__PURE__ */ jsx10(AgentChatToolRow, { activeToolId, part: parts[0], slots });
2234
2505
  const visibleIndex = running ? activeIndex : parts.length - 1;
2235
2506
  const visiblePart = parts[visibleIndex];
2236
2507
  const planning = Boolean(modelTurn);
2237
2508
  const presentingActivity = isLatestActivity && (planning || running || isLive);
2238
2509
  const failed = isLatestActivity && (visiblePart.state === "output-error" || visiblePart.state === "cancelled");
2239
2510
  const label = planning ? "Planning next moves" : isLive && isLatestActivity ? toolRowLabel(visiblePart, true) : sessionLabel(parts, visiblePart, running);
2240
- const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx9("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx9(ToolActivityReel, { initialLabel: leadingModelTurn ? "Planning next moves" : void 0, initialShownAt: leadingModelTurn?.timestamp, label }) }) : label;
2241
- return /* @__PURE__ */ jsx9(
2511
+ const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx10("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx10(ToolActivityReel, { initialLabel: leadingModelTurn ? "Planning next moves" : void 0, initialShownAt: leadingModelTurn?.timestamp, label }) }) : label;
2512
+ return /* @__PURE__ */ jsx10(
2242
2513
  ToolDisclosure,
2243
2514
  {
2244
2515
  error: failed,
@@ -2250,7 +2521,7 @@ function AgentChatToolSession({
2250
2521
  root: true,
2251
2522
  showOrb: isLive && isLatestActivity,
2252
2523
  statusLabel: planning ? "Planning next moves" : label,
2253
- children: /* @__PURE__ */ jsx9(ToolList, { children: parts.map((part) => /* @__PURE__ */ jsx9("div", { role: "listitem", children: /* @__PURE__ */ jsx9(AgentChatToolRow, { activeToolId, part, root: false, showOrb: false, slots }) }, part.id)) })
2524
+ children: /* @__PURE__ */ jsx10(ToolList, { children: parts.map((part) => /* @__PURE__ */ jsx10("div", { role: "listitem", children: /* @__PURE__ */ jsx10(AgentChatToolRow, { activeToolId, part, root: false, showOrb: false, slots }) }, part.id)) })
2254
2525
  }
2255
2526
  );
2256
2527
  }
@@ -2271,7 +2542,7 @@ function subagentLabel(part) {
2271
2542
  return { label: `Agent ${name}, ran ${children.length} ${children.length === 1 ? "tool" : "tools"}`, running: false };
2272
2543
  }
2273
2544
  function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part, slots }) {
2274
- const presentedLiveRef = React8.useRef(false);
2545
+ const presentedLiveRef = React11.useRef(false);
2275
2546
  if (isLive && isLatestActivity) presentedLiveRef.current = true;
2276
2547
  const children = part.presentation.childTools || [];
2277
2548
  const state = subagentLabel(part);
@@ -2280,9 +2551,9 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2280
2551
  const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
2281
2552
  const failureMessage = part.failure?.message || null;
2282
2553
  const presentingActivity = isLatestActivity && state.running;
2283
- const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx9("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx9(ToolActivityReel, { label: state.label }) }) : state.label;
2554
+ const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx10("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx10(ToolActivityReel, { label: state.label }) }) : state.label;
2284
2555
  const context = toolSlotContext(presentingActivity, state.label, part, slots);
2285
- return /* @__PURE__ */ jsx9(
2556
+ return /* @__PURE__ */ jsx10(
2286
2557
  ToolDisclosure,
2287
2558
  {
2288
2559
  accessory: slots?.renderToolAccessory?.(context),
@@ -2295,12 +2566,12 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2295
2566
  root: true,
2296
2567
  showOrb: isLive && isLatestActivity,
2297
2568
  statusLabel: state.label,
2298
- children: /* @__PURE__ */ jsxs5(ToolList, { children: [
2299
- children.map((child) => /* @__PURE__ */ jsx9("div", { className: cn("a24-child-tool", child.status === "failed" && "a24-child-tool--error"), role: "listitem", children: slots?.renderChildTool?.(child, part) ?? /* @__PURE__ */ jsxs5(Fragment3, { children: [
2300
- /* @__PURE__ */ jsx9("span", { className: cn(isLive && isLatestActivity && child.status === "running" && "a24-tool-shimmer"), children: childLabel(child) }),
2301
- child.detail ? /* @__PURE__ */ jsx9("span", { className: "a24-child-tool__detail", children: child.detail }) : null
2569
+ children: /* @__PURE__ */ jsxs6(ToolList, { children: [
2570
+ children.map((child) => /* @__PURE__ */ jsx10("div", { className: cn("a24-child-tool", child.status === "failed" && "a24-child-tool--error"), role: "listitem", children: slots?.renderChildTool?.(child, part) ?? /* @__PURE__ */ jsxs6(Fragment3, { children: [
2571
+ /* @__PURE__ */ jsx10("span", { className: cn(isLive && isLatestActivity && child.status === "running" && "a24-tool-shimmer"), children: childLabel(child) }),
2572
+ child.detail ? /* @__PURE__ */ jsx10("span", { className: "a24-child-tool__detail", children: child.detail }) : null
2302
2573
  ] }) }, child.id)),
2303
- failureMessage ? /* @__PURE__ */ jsx9("div", { className: "a24-tool-detail a24-tool-detail--error", children: failureMessage }) : null,
2574
+ failureMessage ? /* @__PURE__ */ jsx10("div", { className: "a24-tool-detail a24-tool-detail--error", children: failureMessage }) : null,
2304
2575
  hostDetails
2305
2576
  ] })
2306
2577
  }
@@ -2308,24 +2579,24 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2308
2579
  }
2309
2580
 
2310
2581
  // src/ui/agent-response-timeline.tsx
2311
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
2582
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2312
2583
  function isInternalAskUserTool(part) {
2313
2584
  return [part.toolName, part.toolKey, part.action].some((value) => value?.trim().toLowerCase() === "runtime__ask_user");
2314
2585
  }
2315
2586
  function Shimmer({ children, className }) {
2316
- return /* @__PURE__ */ jsx10("span", { className: cn("inline-block animate-pulse", className), children });
2587
+ return /* @__PURE__ */ jsx11("span", { className: cn("inline-block animate-pulse", className), children });
2317
2588
  }
2318
2589
  function AgentChatToolPart({
2319
2590
  activeToolId,
2320
2591
  part
2321
2592
  }) {
2322
- return /* @__PURE__ */ jsx10(AgentChatToolRow, { activeToolId, part });
2593
+ return /* @__PURE__ */ jsx11(AgentChatToolRow, { activeToolId, part });
2323
2594
  }
2324
2595
  function AgentChatToolGroup({
2325
2596
  activeToolId,
2326
2597
  parts
2327
2598
  }) {
2328
- return /* @__PURE__ */ jsx10(AgentChatToolSession, { activeToolId, parts });
2599
+ return /* @__PURE__ */ jsx11(AgentChatToolSession, { activeToolId, parts });
2329
2600
  }
2330
2601
  function HitlPartRow({
2331
2602
  getHitlActionState,
@@ -2334,18 +2605,18 @@ function HitlPartRow({
2334
2605
  part
2335
2606
  }) {
2336
2607
  const state = getHitlActionState?.(part);
2337
- const [comment, setComment] = React9.useState("");
2608
+ const [comment, setComment] = React12.useState("");
2338
2609
  const presentation = part.presentation || {};
2339
2610
  const requireComment = presentation.require_comment === true;
2340
2611
  const isTerminal = part.status !== "pending";
2341
- const resolvedRef = React9.useRef(null);
2342
- const wasTerminal = React9.useRef(isTerminal);
2343
- React9.useEffect(() => {
2612
+ const resolvedRef = React12.useRef(null);
2613
+ const wasTerminal = React12.useRef(isTerminal);
2614
+ React12.useEffect(() => {
2344
2615
  if (isTerminal && !wasTerminal.current) resolvedRef.current?.focus();
2345
2616
  wasTerminal.current = isTerminal;
2346
2617
  }, [isTerminal]);
2347
2618
  if (part.hitlKind === "user_input") {
2348
- return /* @__PURE__ */ jsx10(
2619
+ return /* @__PURE__ */ jsx11(
2349
2620
  AskUserInteraction,
2350
2621
  {
2351
2622
  error: state?.error,
@@ -2363,11 +2634,11 @@ function HitlPartRow({
2363
2634
  );
2364
2635
  }
2365
2636
  if (isTerminal) {
2366
- return /* @__PURE__ */ jsx10("div", { className: "a24-hitl a24-hitl--resolved px-1 py-1 text-sm text-muted-foreground", ref: resolvedRef, role: "status", tabIndex: -1, children: resolvedHitlLabel(part) });
2637
+ return /* @__PURE__ */ jsx11("div", { className: "a24-hitl a24-hitl--resolved px-1 py-1 text-sm text-muted-foreground", ref: resolvedRef, role: "status", tabIndex: -1, children: resolvedHitlLabel(part) });
2367
2638
  }
2368
- return /* @__PURE__ */ jsxs6("div", { className: "a24-hitl space-y-2.5 px-1 py-2", children: [
2369
- /* @__PURE__ */ jsx10("div", { className: "a24-hitl__title text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
2370
- requireComment ? /* @__PURE__ */ jsx10(
2639
+ return /* @__PURE__ */ jsxs7("div", { className: "a24-hitl space-y-2.5 px-1 py-2", children: [
2640
+ /* @__PURE__ */ jsx11("div", { className: "a24-hitl__title text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
2641
+ requireComment ? /* @__PURE__ */ jsx11(
2371
2642
  "textarea",
2372
2643
  {
2373
2644
  "aria-label": "Approval comment",
@@ -2379,8 +2650,8 @@ function HitlPartRow({
2379
2650
  value: comment
2380
2651
  }
2381
2652
  ) : null,
2382
- state?.error ? /* @__PURE__ */ jsx10("div", { className: "a24-hitl__error text-sm text-destructive", children: state.error }) : null,
2383
- /* @__PURE__ */ jsx10("div", { className: "a24-hitl__actions flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ jsx10(
2653
+ state?.error ? /* @__PURE__ */ jsx11("div", { className: "a24-hitl__error text-sm text-destructive", children: state.error }) : null,
2654
+ /* @__PURE__ */ jsx11("div", { className: "a24-hitl__actions flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ jsx11(
2384
2655
  "button",
2385
2656
  {
2386
2657
  "aria-label": hitlActionLabel(part, action),
@@ -2413,7 +2684,7 @@ function AgentChatPart({
2413
2684
  toolSlots
2414
2685
  }) {
2415
2686
  if (part.kind === "text") {
2416
- return /* @__PURE__ */ jsx10(
2687
+ return /* @__PURE__ */ jsx11(
2417
2688
  MessageResponse,
2418
2689
  {
2419
2690
  ...responseProps,
@@ -2423,23 +2694,23 @@ function AgentChatPart({
2423
2694
  }
2424
2695
  );
2425
2696
  }
2426
- if (part.kind === "tool") return isAgentChatSubagent(part) ? /* @__PURE__ */ jsx10(AgentChatSubagentGroup, { part, slots: toolSlots }) : /* @__PURE__ */ jsx10(AgentChatToolRow, { activeToolId, part, slots: toolSlots });
2427
- if (part.kind === "model-turn") return /* @__PURE__ */ jsx10(AgentChatModelTurnRow, { part });
2697
+ if (part.kind === "tool") return isAgentChatSubagent(part) ? /* @__PURE__ */ jsx11(AgentChatSubagentGroup, { part, slots: toolSlots }) : /* @__PURE__ */ jsx11(AgentChatToolRow, { activeToolId, part, slots: toolSlots });
2698
+ if (part.kind === "model-turn") return /* @__PURE__ */ jsx11(AgentChatModelTurnRow, { part });
2428
2699
  if (part.kind === "reasoning") {
2429
2700
  const label = part.text || part.label || "Thinking";
2430
- return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ jsx10(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ jsx10("div", { className: "text-sm text-muted-foreground", children: label });
2701
+ return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ jsx11(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ jsx11("div", { className: "text-sm text-muted-foreground", children: label });
2431
2702
  }
2432
2703
  if (part.kind === "context-compression") {
2433
- return /* @__PURE__ */ jsx10(AgentChatContextCompressionRow, { part });
2704
+ return /* @__PURE__ */ jsx11(AgentChatContextCompressionRow, { part });
2434
2705
  }
2435
2706
  if (part.kind === "ui-blocks") {
2436
2707
  if (part.state === "output-error") {
2437
- return /* @__PURE__ */ jsx10("div", { className: "a24-timeline-error text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
2708
+ return /* @__PURE__ */ jsx11("div", { className: "a24-timeline-error text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
2438
2709
  }
2439
- return part.bundle ? /* @__PURE__ */ jsx10(SafeUiBlocks, { bundle: part.bundle }) : /* @__PURE__ */ jsx10("div", { className: "text-sm text-muted-foreground", children: part.state === "input-streaming" ? /* @__PURE__ */ jsx10(Shimmer, { children: "Rendering UI block" }) : "Rendered UI block" });
2710
+ return part.bundle ? /* @__PURE__ */ jsx11(SafeUiBlocks, { bundle: part.bundle }) : /* @__PURE__ */ jsx11("div", { className: "text-sm text-muted-foreground", children: part.state === "input-streaming" ? /* @__PURE__ */ jsx11(Shimmer, { children: "Rendering UI block" }) : "Rendered UI block" });
2440
2711
  }
2441
2712
  if (part.kind === "hitl") {
2442
- return /* @__PURE__ */ jsx10(
2713
+ return /* @__PURE__ */ jsx11(
2443
2714
  HitlPartRow,
2444
2715
  {
2445
2716
  getHitlActionState,
@@ -2449,18 +2720,18 @@ function AgentChatPart({
2449
2720
  }
2450
2721
  );
2451
2722
  }
2452
- if (part.kind === "error") return /* @__PURE__ */ jsx10("div", { className: "a24-timeline-error text-sm text-destructive", role: "alert", children: part.errorText });
2723
+ if (part.kind === "error") return /* @__PURE__ */ jsx11("div", { className: "a24-timeline-error text-sm text-destructive", role: "alert", children: part.errorText });
2453
2724
  if (part.kind === "source") {
2454
2725
  const href = safeExternalUrl(part.url);
2455
- return href ? /* @__PURE__ */ jsx10("a", { className: "a24-source-link", href, rel: "noopener noreferrer", target: "_blank", children: part.title }) : /* @__PURE__ */ jsx10("span", { className: "a24-source-link", children: part.title });
2726
+ return href ? /* @__PURE__ */ jsx11("a", { className: "a24-source-link", href, rel: "noopener noreferrer", target: "_blank", children: part.title }) : /* @__PURE__ */ jsx11("span", { className: "a24-source-link", children: part.title });
2456
2727
  }
2457
2728
  if (part.kind === "citation") {
2458
2729
  const href = safeExternalUrl(part.url);
2459
2730
  const label = part.label || "Citation";
2460
- return href ? /* @__PURE__ */ jsx10("a", { className: "a24-citation", href, rel: "noopener noreferrer", target: "_blank", children: label }) : /* @__PURE__ */ jsx10("span", { className: "a24-citation", children: label });
2731
+ return href ? /* @__PURE__ */ jsx11("a", { className: "a24-citation", href, rel: "noopener noreferrer", target: "_blank", children: label }) : /* @__PURE__ */ jsx11("span", { className: "a24-citation", children: label });
2461
2732
  }
2462
- if (part.kind === "attachment") return /* @__PURE__ */ jsx10("div", { className: "a24-output-attachment", children: part.attachment.filename || "Attachment" });
2463
- if (part.kind === "data") return /* @__PURE__ */ jsx10("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
2733
+ if (part.kind === "attachment") return /* @__PURE__ */ jsx11("div", { className: "a24-output-attachment", children: part.attachment.filename || "Attachment" });
2734
+ if (part.kind === "data") return /* @__PURE__ */ jsx11("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
2464
2735
  return null;
2465
2736
  }
2466
2737
  function safeExternalUrl(value) {
@@ -2474,28 +2745,28 @@ function safeExternalUrl(value) {
2474
2745
  }
2475
2746
  function SafeUiBlocks({ bundle }) {
2476
2747
  const rows = Array.isArray(bundle.rows) ? bundle.rows : [];
2477
- return /* @__PURE__ */ jsxs6("section", { "aria-label": typeof bundle.title === "string" ? bundle.title : "Agent result", className: "a24-ui-blocks", children: [
2478
- typeof bundle.title === "string" ? /* @__PURE__ */ jsx10("h3", { children: bundle.title }) : null,
2748
+ return /* @__PURE__ */ jsxs7("section", { "aria-label": typeof bundle.title === "string" ? bundle.title : "Agent result", className: "a24-ui-blocks", children: [
2749
+ typeof bundle.title === "string" ? /* @__PURE__ */ jsx11("h3", { children: bundle.title }) : null,
2479
2750
  rows.map((rawRow, rowIndex) => {
2480
2751
  const row = rawRow && typeof rawRow === "object" && !Array.isArray(rawRow) ? rawRow : {};
2481
2752
  const blocks = Array.isArray(row.blocks) ? row.blocks : [];
2482
- return /* @__PURE__ */ jsx10("div", { className: "a24-ui-blocks__row", children: blocks.map((rawBlock, blockIndex) => {
2753
+ return /* @__PURE__ */ jsx11("div", { className: "a24-ui-blocks__row", children: blocks.map((rawBlock, blockIndex) => {
2483
2754
  const block = rawBlock && typeof rawBlock === "object" && !Array.isArray(rawBlock) ? rawBlock : {};
2484
2755
  const title = typeof block.title === "string" ? block.title : "Result";
2485
2756
  const kind = String(block.kind || "note");
2486
2757
  if (kind === "table" && Array.isArray(block.columns) && Array.isArray(block.rows)) {
2487
- return /* @__PURE__ */ jsxs6("div", { className: "a24-ui-block", children: [
2488
- /* @__PURE__ */ jsx10("h4", { children: title }),
2489
- /* @__PURE__ */ jsx10("div", { className: "a24-ui-table-scroll", children: /* @__PURE__ */ jsxs6("table", { children: [
2490
- /* @__PURE__ */ jsx10("thead", { children: /* @__PURE__ */ jsx10("tr", { children: block.columns.map((column, index) => /* @__PURE__ */ jsx10("th", { children: String(column) }, index)) }) }),
2491
- /* @__PURE__ */ jsx10("tbody", { children: block.rows.map((rawCells, index) => /* @__PURE__ */ jsx10("tr", { children: (Array.isArray(rawCells) ? rawCells : []).map((cell, cellIndex) => /* @__PURE__ */ jsx10("td", { children: String(cell) }, cellIndex)) }, index)) })
2758
+ return /* @__PURE__ */ jsxs7("div", { className: "a24-ui-block", children: [
2759
+ /* @__PURE__ */ jsx11("h4", { children: title }),
2760
+ /* @__PURE__ */ jsx11("div", { className: "a24-ui-table-scroll", children: /* @__PURE__ */ jsxs7("table", { children: [
2761
+ /* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsx11("tr", { children: block.columns.map((column, index) => /* @__PURE__ */ jsx11("th", { children: String(column) }, index)) }) }),
2762
+ /* @__PURE__ */ jsx11("tbody", { children: block.rows.map((rawCells, index) => /* @__PURE__ */ jsx11("tr", { children: (Array.isArray(rawCells) ? rawCells : []).map((cell, cellIndex) => /* @__PURE__ */ jsx11("td", { children: String(cell) }, cellIndex)) }, index)) })
2492
2763
  ] }) })
2493
2764
  ] }, String(block.id || blockIndex));
2494
2765
  }
2495
2766
  const value = block.value ?? block.text ?? "";
2496
- return /* @__PURE__ */ jsxs6("div", { className: "a24-ui-block", children: [
2497
- /* @__PURE__ */ jsx10("h4", { children: title }),
2498
- /* @__PURE__ */ jsx10("p", { children: String(value) })
2767
+ return /* @__PURE__ */ jsxs7("div", { className: "a24-ui-block", children: [
2768
+ /* @__PURE__ */ jsx11("h4", { children: title }),
2769
+ /* @__PURE__ */ jsx11("p", { children: String(value) })
2499
2770
  ] }, String(block.id || blockIndex));
2500
2771
  }) }, `row-${rowIndex}`);
2501
2772
  })
@@ -2529,38 +2800,38 @@ function AgentResponseTimeline({
2529
2800
  if (segment.kind === "tool") {
2530
2801
  const isLatestActivity = segmentIndex === segments.length - 1;
2531
2802
  const showOrb = toolViewMode === "closed" ? isLoading && isLatestActivity : Boolean(activeToolId && (segment.part.id === activeToolId || segment.part.toolCallId === activeToolId));
2532
- rendered.push(/* @__PURE__ */ jsx10(AgentChatToolRow, { activeToolId, part: segment.part, showOrb, slots: toolSlots }, segment.part.id));
2803
+ rendered.push(/* @__PURE__ */ jsx11(AgentChatToolRow, { activeToolId, part: segment.part, showOrb, slots: toolSlots }, segment.part.id));
2533
2804
  continue;
2534
2805
  }
2535
2806
  if (segment.kind === "tool-session") {
2536
- rendered.push(/* @__PURE__ */ jsx10(AgentChatToolSession, { activeToolId, isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, leadingModelTurn: segment.leadingModelTurn, modelTurn: segment.modelTurn, parts: segment.parts, slots: toolSlots }, `tool-session-${segment.parts[0].id}`));
2807
+ rendered.push(/* @__PURE__ */ jsx11(AgentChatToolSession, { activeToolId, isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, leadingModelTurn: segment.leadingModelTurn, modelTurn: segment.modelTurn, parts: segment.parts, slots: toolSlots }, `tool-session-${segment.parts[0].id}`));
2537
2808
  continue;
2538
2809
  }
2539
2810
  if (segment.kind === "subagent") {
2540
- rendered.push(/* @__PURE__ */ jsx10(AgentChatSubagentGroup, { isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, part: segment.part, slots: toolSlots }, segment.part.id));
2811
+ rendered.push(/* @__PURE__ */ jsx11(AgentChatSubagentGroup, { isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, part: segment.part, slots: toolSlots }, segment.part.id));
2541
2812
  continue;
2542
2813
  }
2543
2814
  const part = segment.part;
2544
2815
  if (part.kind === "model-turn") {
2545
2816
  const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
2546
2817
  activeActivityClaimed = true;
2547
- rendered.push(/* @__PURE__ */ jsx10(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId }, key));
2818
+ rendered.push(/* @__PURE__ */ jsx11(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId }, key));
2548
2819
  continue;
2549
2820
  }
2550
2821
  if (part.kind === "node-activity") {
2551
2822
  const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
2552
2823
  if (part.status === "running") activeActivityClaimed = true;
2553
2824
  rendered.push(
2554
- part.status === "running" ? /* @__PURE__ */ jsx10(AgentChatActivityRow, { label: part.label, onSelect: onNodeSelect ? () => onNodeSelect(part) : void 0 }, key) : /* @__PURE__ */ jsx10(AgentChatNodeActivityRow, { onSelect: onNodeSelect, part }, part.id)
2825
+ part.status === "running" ? /* @__PURE__ */ jsx11(AgentChatActivityRow, { label: part.label, onSelect: onNodeSelect ? () => onNodeSelect(part) : void 0 }, key) : /* @__PURE__ */ jsx11(AgentChatNodeActivityRow, { onSelect: onNodeSelect, part }, part.id)
2555
2826
  );
2556
2827
  continue;
2557
2828
  }
2558
2829
  if (part.kind === "ui-blocks" && renderUiBlocks) {
2559
- rendered.push(/* @__PURE__ */ jsx10(React9.Fragment, { children: renderUiBlocks(part) }, part.id));
2830
+ rendered.push(/* @__PURE__ */ jsx11(React12.Fragment, { children: renderUiBlocks(part) }, part.id));
2560
2831
  continue;
2561
2832
  }
2562
2833
  rendered.push(
2563
- /* @__PURE__ */ jsx10(React9.Fragment, { children: /* @__PURE__ */ jsx10(
2834
+ /* @__PURE__ */ jsx11(React12.Fragment, { children: /* @__PURE__ */ jsx11(
2564
2835
  AgentChatPart,
2565
2836
  {
2566
2837
  activeToolId,
@@ -2577,16 +2848,16 @@ function AgentResponseTimeline({
2577
2848
  );
2578
2849
  }
2579
2850
  if (rendered.length === 0 && message.content) {
2580
- rendered.push(/* @__PURE__ */ jsx10(MessageResponse, { children: message.content }, `${message.id}-fallback`));
2851
+ rendered.push(/* @__PURE__ */ jsx11(MessageResponse, { children: message.content }, `${message.id}-fallback`));
2581
2852
  }
2582
2853
  if (rendered.length === 0 && isLoading) {
2583
- rendered.push(/* @__PURE__ */ jsx10(AgentChatActivityRow, { label: "Thinking" }, `${message.id}-active-activity`));
2854
+ rendered.push(/* @__PURE__ */ jsx11(AgentChatActivityRow, { label: "Thinking" }, `${message.id}-active-activity`));
2584
2855
  }
2585
- return /* @__PURE__ */ jsx10("div", { className: "space-y-3", children: rendered });
2856
+ return /* @__PURE__ */ jsx11("div", { className: "space-y-3", children: rendered });
2586
2857
  }
2587
2858
 
2588
2859
  // src/ui/agent-chat-message.tsx
2589
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2860
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2590
2861
  var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
2591
2862
  var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
2592
2863
  function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
@@ -2599,8 +2870,8 @@ function AgentChatUserMessageContent({
2599
2870
  showLessLabel = "Show less",
2600
2871
  showMoreLabel = "Show more"
2601
2872
  }) {
2602
- const [isExpanded, setIsExpanded] = React10.useState(false);
2603
- const contentId = React10.useId();
2873
+ const [isExpanded, setIsExpanded] = React13.useState(false);
2874
+ const contentId = React13.useId();
2604
2875
  const shouldCollapse = shouldCollapseUserMessage(content, collapseThreshold);
2605
2876
  const Icon = isExpanded ? ChevronUp : ChevronDown3;
2606
2877
  const clampedStyle = shouldCollapse && !isExpanded ? {
@@ -2609,9 +2880,9 @@ function AgentChatUserMessageContent({
2609
2880
  display: "-webkit-box",
2610
2881
  overflow: "hidden"
2611
2882
  } : void 0;
2612
- return /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-col gap-3", children: [
2613
- /* @__PURE__ */ jsx11("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
2614
- shouldCollapse ? /* @__PURE__ */ jsxs7(
2883
+ return /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-col gap-3", children: [
2884
+ /* @__PURE__ */ jsx12("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
2885
+ shouldCollapse ? /* @__PURE__ */ jsxs8(
2615
2886
  "button",
2616
2887
  {
2617
2888
  "aria-controls": contentId,
@@ -2624,7 +2895,7 @@ function AgentChatUserMessageContent({
2624
2895
  type: "button",
2625
2896
  children: [
2626
2897
  isExpanded ? showLessLabel : showMoreLabel,
2627
- /* @__PURE__ */ jsx11(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
2898
+ /* @__PURE__ */ jsx12(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
2628
2899
  ]
2629
2900
  }
2630
2901
  ) : null
@@ -2634,9 +2905,9 @@ function AgentChatUserMessageActionRow({
2634
2905
  children,
2635
2906
  className
2636
2907
  }) {
2637
- const rowRef = React10.useRef(null);
2638
- const [visible, setVisible] = React10.useState(false);
2639
- React10.useEffect(() => {
2908
+ const rowRef = React13.useRef(null);
2909
+ const [visible, setVisible] = React13.useState(false);
2910
+ React13.useEffect(() => {
2640
2911
  const message = rowRef.current?.closest('[data-slot="message"]');
2641
2912
  if (!message) return;
2642
2913
  const show = () => setVisible(true);
@@ -2655,7 +2926,7 @@ function AgentChatUserMessageActionRow({
2655
2926
  message.removeEventListener("focusout", hideWhenFocusLeaves);
2656
2927
  };
2657
2928
  }, []);
2658
- return /* @__PURE__ */ jsx11(
2929
+ return /* @__PURE__ */ jsx12(
2659
2930
  "div",
2660
2931
  {
2661
2932
  ref: rowRef,
@@ -2694,7 +2965,7 @@ function AgentChatMessage({
2694
2965
  const resolvedUserContent = userMessageContent ?? message.content;
2695
2966
  const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
2696
2967
  const showAttachments = Boolean(message.attachments?.length) && (message.role === "user" || showAssistantAttachments);
2697
- const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ jsx11(
2968
+ const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ jsx12(
2698
2969
  AgentChatDefaultActions,
2699
2970
  {
2700
2971
  additionalActions,
@@ -2704,14 +2975,14 @@ function AgentChatMessage({
2704
2975
  }
2705
2976
  ) : null);
2706
2977
  const defaultUserActions = !actions && Boolean(actionHandlers) && !isAssistant;
2707
- return /* @__PURE__ */ jsxs7(
2978
+ return /* @__PURE__ */ jsxs8(
2708
2979
  ChatMessage,
2709
2980
  {
2710
2981
  className,
2711
2982
  dir,
2712
2983
  from: message.role,
2713
2984
  children: [
2714
- showAttachments ? /* @__PURE__ */ jsx11(
2985
+ showAttachments ? /* @__PURE__ */ jsx12(
2715
2986
  ChatAttachmentRows,
2716
2987
  {
2717
2988
  attachments: message.attachments || [],
@@ -2720,14 +2991,14 @@ function AgentChatMessage({
2720
2991
  resolveContent: attachmentContentResolver
2721
2992
  }
2722
2993
  ) : null,
2723
- shouldRenderContent ? /* @__PURE__ */ jsxs7(
2994
+ shouldRenderContent ? /* @__PURE__ */ jsxs8(
2724
2995
  ChatMessageContent,
2725
2996
  {
2726
2997
  className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
2727
2998
  dir,
2728
2999
  from: message.role,
2729
3000
  children: [
2730
- isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx11(
3001
+ isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx12(
2731
3002
  Timeline,
2732
3003
  {
2733
3004
  getHitlActionState,
@@ -2738,7 +3009,7 @@ function AgentChatMessage({
2738
3009
  parts: message.parts
2739
3010
  }
2740
3011
  ) : null,
2741
- !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx11(
3012
+ !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx12(
2742
3013
  AgentChatUserMessageContent,
2743
3014
  {
2744
3015
  collapsedLines: userMessageCollapsedLines,
@@ -2751,108 +3022,7 @@ function AgentChatMessage({
2751
3022
  ]
2752
3023
  }
2753
3024
  ) : null,
2754
- renderedActions ? defaultUserActions ? /* @__PURE__ */ jsx11(AgentChatUserMessageActionRow, { className: actionsClassName, children: renderedActions }) : /* @__PURE__ */ jsx11("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
2755
- ]
2756
- }
2757
- );
2758
- }
2759
-
2760
- // src/ui/agent-chat-context-status.tsx
2761
- import * as React11 from "react";
2762
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2763
- var COMPACT_TOKENS = new Intl.NumberFormat("en-US", { notation: "compact" });
2764
- var PERCENT = new Intl.NumberFormat("en-US", {
2765
- style: "percent",
2766
- maximumFractionDigits: 1
2767
- });
2768
- var EXACT_SOURCES = /* @__PURE__ */ new Set(["exact", "provider_usage"]);
2769
- function contextStatusMetrics(contextWindow) {
2770
- const maximum = Number(contextWindow?.max_tokens || 0);
2771
- const input = Math.max(0, Number(contextWindow?.input_tokens || 0));
2772
- const admissionInput = Math.max(0, Number(contextWindow?.admission_input_tokens ?? input));
2773
- const usageRatio = Math.max(0, Math.min(1, Number(
2774
- contextWindow?.usage_ratio ?? input / maximum
2775
- )));
2776
- const admissionRatio = Math.max(0, Math.min(1, Number(
2777
- contextWindow?.admission_ratio ?? admissionInput / maximum
2778
- )));
2779
- return { maximum, input, admissionInput, usageRatio, admissionRatio };
2780
- }
2781
- function AgentChatContextStatus({
2782
- className,
2783
- contextWindow
2784
- }) {
2785
- const tooltipId = React11.useId();
2786
- const [open, setOpen] = React11.useState(false);
2787
- const { maximum, input, admissionInput, usageRatio, admissionRatio } = contextStatusMetrics(contextWindow);
2788
- const percentage = Math.round(usageRatio * 100);
2789
- const exact = EXACT_SOURCES.has(contextWindow?.source || "unknown");
2790
- if (!Number.isFinite(maximum) || maximum <= 0) return null;
2791
- return /* @__PURE__ */ jsxs8(
2792
- "div",
2793
- {
2794
- className: cn("a24-context-status", className),
2795
- onBlurCapture: (event) => {
2796
- if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
2797
- },
2798
- onFocusCapture: () => setOpen(true),
2799
- onMouseEnter: () => setOpen(true),
2800
- onMouseLeave: () => setOpen(false),
2801
- children: [
2802
- /* @__PURE__ */ jsxs8(
2803
- "button",
2804
- {
2805
- "aria-describedby": open ? tooltipId : void 0,
2806
- "aria-label": `Context window ${percentage}% used`,
2807
- className: "a24-context-status__trigger",
2808
- onKeyDown: (event) => {
2809
- if (event.key === "Escape") setOpen(false);
2810
- },
2811
- type: "button",
2812
- children: [
2813
- /* @__PURE__ */ jsxs8("svg", { "aria-hidden": "true", className: "a24-context-status__ring", viewBox: "0 0 24 24", children: [
2814
- /* @__PURE__ */ jsx12("circle", { className: "a24-context-status__track", cx: "12", cy: "12", r: "10" }),
2815
- /* @__PURE__ */ jsx12(
2816
- "circle",
2817
- {
2818
- className: "a24-context-status__value",
2819
- cx: "12",
2820
- cy: "12",
2821
- pathLength: "100",
2822
- r: "10",
2823
- strokeDasharray: `${percentage} 100`
2824
- }
2825
- )
2826
- ] }),
2827
- /* @__PURE__ */ jsxs8("span", { children: [
2828
- percentage,
2829
- "%"
2830
- ] })
2831
- ]
2832
- }
2833
- ),
2834
- open ? /* @__PURE__ */ jsxs8("div", { className: "a24-context-status__popover", id: tooltipId, role: "tooltip", children: [
2835
- /* @__PURE__ */ jsx12("span", { className: "a24-context-status__sr-only", children: "Context window" }),
2836
- /* @__PURE__ */ jsxs8("strong", { children: [
2837
- PERCENT.format(usageRatio),
2838
- " context used"
2839
- ] }),
2840
- /* @__PURE__ */ jsxs8("span", { children: [
2841
- exact ? "Input" : "Estimated input",
2842
- ": ",
2843
- COMPACT_TOKENS.format(input),
2844
- " / ",
2845
- COMPACT_TOKENS.format(maximum),
2846
- " tokens"
2847
- ] }),
2848
- admissionInput !== input ? /* @__PURE__ */ jsxs8("span", { children: [
2849
- "Safety bound: ",
2850
- COMPACT_TOKENS.format(admissionInput),
2851
- " tokens (",
2852
- PERCENT.format(admissionRatio),
2853
- ")"
2854
- ] }) : null
2855
- ] }) : null
3025
+ renderedActions ? defaultUserActions ? /* @__PURE__ */ jsx12(AgentChatUserMessageActionRow, { className: actionsClassName, children: renderedActions }) : /* @__PURE__ */ jsx12("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
2856
3026
  ]
2857
3027
  }
2858
3028
  );
@@ -3082,68 +3252,6 @@ function McpConnectRequiredCard({
3082
3252
  }
3083
3253
  );
3084
3254
  }
3085
-
3086
- // src/ui/use-audio-recorder.ts
3087
- import * as React12 from "react";
3088
- var RECORDING_CANDIDATES = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"];
3089
- function recordingExtension(mimeType) {
3090
- return mimeType.startsWith("audio/mp4") ? "m4a" : "webm";
3091
- }
3092
- function useAudioRecorder(onRecorded, options = {}) {
3093
- const recorderRef = React12.useRef(null);
3094
- const streamRef = React12.useRef(null);
3095
- const onRecordedRef = React12.useRef(onRecorded);
3096
- const onStreamChangeRef = React12.useRef(options.onStreamChange);
3097
- onRecordedRef.current = onRecorded;
3098
- onStreamChangeRef.current = options.onStreamChange;
3099
- const [isRecording, setIsRecording] = React12.useState(false);
3100
- const [error, setError] = React12.useState(null);
3101
- const stop = React12.useCallback(() => recorderRef.current?.stop(), []);
3102
- const start = React12.useCallback(async () => {
3103
- setError(null);
3104
- if (!navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
3105
- setError("Audio recording is not supported in this browser.");
3106
- return;
3107
- }
3108
- try {
3109
- const mimeType = RECORDING_CANDIDATES.find((candidate) => MediaRecorder.isTypeSupported(candidate));
3110
- if (!mimeType) {
3111
- setError("Audio recording is not supported in this browser.");
3112
- return;
3113
- }
3114
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
3115
- onStreamChangeRef.current?.(stream);
3116
- const recorder = new MediaRecorder(stream, { mimeType });
3117
- const chunks = [];
3118
- recorder.ondataavailable = (event) => {
3119
- if (event.data.size) chunks.push(event.data);
3120
- };
3121
- recorder.onstop = () => {
3122
- const actualType = recorder.mimeType || "audio/webm";
3123
- onRecordedRef.current(new File([new Blob(chunks, { type: actualType })], `recording-${Date.now()}.${recordingExtension(actualType)}`, { type: actualType }));
3124
- stream.getTracks().forEach((track) => track.stop());
3125
- onStreamChangeRef.current?.(null);
3126
- recorderRef.current = null;
3127
- streamRef.current = null;
3128
- setIsRecording(false);
3129
- };
3130
- recorderRef.current = recorder;
3131
- streamRef.current = stream;
3132
- recorder.start();
3133
- setIsRecording(true);
3134
- } catch {
3135
- streamRef.current?.getTracks().forEach((track) => track.stop());
3136
- onStreamChangeRef.current?.(null);
3137
- setError("Microphone access is unavailable.");
3138
- }
3139
- }, []);
3140
- React12.useEffect(() => () => {
3141
- recorderRef.current?.stop();
3142
- streamRef.current?.getTracks().forEach((track) => track.stop());
3143
- onStreamChangeRef.current?.(null);
3144
- }, []);
3145
- return { error, isRecording, start, stop };
3146
- }
3147
3255
  export {
3148
3256
  AgentChatActivityRow,
3149
3257
  AgentChatComposer,
@@ -3221,6 +3329,7 @@ export {
3221
3329
  resolvedHitlLabel,
3222
3330
  revokeAgentChatComposerFiles,
3223
3331
  shouldCollapseUserMessage,
3332
+ useAgentChatComposer,
3224
3333
  useAudioRecorder,
3225
3334
  useChatComposerFocus,
3226
3335
  useCompletionActionEntrance,