@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.cjs CHANGED
@@ -106,6 +106,7 @@ __export(ui_exports, {
106
106
  resolvedHitlLabel: () => resolvedHitlLabel,
107
107
  revokeAgentChatComposerFiles: () => revokeAgentChatComposerFiles,
108
108
  shouldCollapseUserMessage: () => shouldCollapseUserMessage,
109
+ useAgentChatComposer: () => useAgentChatComposer,
109
110
  useAudioRecorder: () => useAudioRecorder,
110
111
  useChatComposerFocus: () => useChatComposerFocus,
111
112
  useCompletionActionEntrance: () => useCompletionActionEntrance,
@@ -114,7 +115,7 @@ __export(ui_exports, {
114
115
  module.exports = __toCommonJS(ui_exports);
115
116
 
116
117
  // src/ui/agent-chat-composer.tsx
117
- var React3 = __toESM(require("react"), 1);
118
+ var React6 = __toESM(require("react"), 1);
118
119
  var import_lucide_react2 = require("lucide-react");
119
120
 
120
121
  // src/ui/adapters.ts
@@ -824,8 +825,55 @@ function ChatAttachmentRows({
824
825
  );
825
826
  }
826
827
 
827
- // src/ui/composer-attachments.ts
828
+ // src/ui/use-agent-chat-composer.ts
829
+ var React4 = __toESM(require("react"), 1);
830
+
831
+ // src/runtime/input-contract.ts
828
832
  var import_client = require("@agents24/client");
833
+ var import_client2 = require("@agents24/client");
834
+ function uploadByteSize(data) {
835
+ if (data instanceof Uint8Array || data instanceof ArrayBuffer) return data.byteLength;
836
+ return data.size;
837
+ }
838
+ function inputMimeTypes(contract) {
839
+ if (!contract) return [];
840
+ return [
841
+ ...contract.modalities.files.allowed_mime_types,
842
+ ...contract.modalities.images.allowed_mime_types,
843
+ ...contract.modalities.audio.allowed_mime_types
844
+ ];
845
+ }
846
+ function validateAgentChatSubmission(contract, text, files) {
847
+ const { modalities, limits } = contract;
848
+ const normalizedText = text.trim();
849
+ if (normalizedText && !modalities.text.enabled) return "This agent does not accept text input.";
850
+ if (modalities.text.required && !normalizedText) return "Text input is required.";
851
+ if (files.length > limits.max_attachments_per_turn) {
852
+ return `You can attach up to ${limits.max_attachments_per_turn} items per message.`;
853
+ }
854
+ let totalBytes = 0;
855
+ const present = { files: false, images: false, audio: false };
856
+ for (const file of files) {
857
+ const mediaType = (0, import_client.normalizeAttachmentMimeType)(file.mediaType, file.name);
858
+ const modality = mediaType.startsWith("image/") ? "images" : mediaType.startsWith("audio/") ? "audio" : "files";
859
+ const rule = modalities[modality];
860
+ if (!rule.enabled || !rule.allowed_mime_types.includes(mediaType)) {
861
+ return `The attachment type ${mediaType || "unknown"} is not accepted.`;
862
+ }
863
+ const byteSize = file.byteSize ?? uploadByteSize(file.data);
864
+ if (byteSize > limits.max_file_bytes) return "An attachment exceeds the per-file size limit.";
865
+ totalBytes += byteSize;
866
+ present[modality] = true;
867
+ }
868
+ if (totalBytes > limits.max_total_bytes) return "Attachments exceed the total size limit.";
869
+ for (const modality of ["files", "images", "audio"]) {
870
+ if (modalities[modality].required && !present[modality]) return `${modality[0].toUpperCase()}${modality.slice(1)} input is required.`;
871
+ }
872
+ return null;
873
+ }
874
+
875
+ // src/ui/composer-attachments.ts
876
+ var import_client3 = require("@agents24/client");
829
877
  var createId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `file-${Date.now()}-${Math.random().toString(36).slice(2)}`;
830
878
  function createAgentChatComposerFile(file) {
831
879
  return {
@@ -833,7 +881,7 @@ function createAgentChatComposerFile(file) {
833
881
  type: "file",
834
882
  url: URL.createObjectURL(file),
835
883
  filename: file.name || "attachment",
836
- mediaType: (0, import_client.normalizeAttachmentMimeType)(file.type, file.name),
884
+ mediaType: (0, import_client3.normalizeAttachmentMimeType)(file.type, file.name),
837
885
  source: file
838
886
  };
839
887
  }
@@ -885,8 +933,300 @@ function useChatComposerFocus({ textareaRef, disabled, focusKey, restoredDraft,
885
933
  return focus;
886
934
  }
887
935
 
888
- // src/ui/agent-chat-composer.tsx
936
+ // src/ui/use-audio-recorder.ts
937
+ var React3 = __toESM(require("react"), 1);
938
+ var RECORDING_CANDIDATES = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"];
939
+ function recordingExtension(mimeType) {
940
+ return mimeType.startsWith("audio/mp4") ? "m4a" : "webm";
941
+ }
942
+ function useAudioRecorder(onRecorded, options = {}) {
943
+ const mountedRef = React3.useRef(true);
944
+ const startingRef = React3.useRef(false);
945
+ const recorderRef = React3.useRef(null);
946
+ const streamRef = React3.useRef(null);
947
+ const onRecordedRef = React3.useRef(onRecorded);
948
+ const onStreamChangeRef = React3.useRef(options.onStreamChange);
949
+ onRecordedRef.current = onRecorded;
950
+ onStreamChangeRef.current = options.onStreamChange;
951
+ const [isRecording, setIsRecording] = React3.useState(false);
952
+ const [error, setError] = React3.useState(null);
953
+ const stop = React3.useCallback(() => {
954
+ if (recorderRef.current && recorderRef.current.state !== "inactive") recorderRef.current.stop();
955
+ }, []);
956
+ const start = React3.useCallback(async () => {
957
+ if (startingRef.current || recorderRef.current) return;
958
+ startingRef.current = true;
959
+ setError(null);
960
+ if (!navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
961
+ setError("Audio recording is not supported in this browser.");
962
+ startingRef.current = false;
963
+ return;
964
+ }
965
+ try {
966
+ const mimeType = RECORDING_CANDIDATES.find((candidate) => MediaRecorder.isTypeSupported(candidate));
967
+ if (!mimeType) {
968
+ setError("Audio recording is not supported in this browser.");
969
+ return;
970
+ }
971
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
972
+ if (!mountedRef.current) {
973
+ stream.getTracks().forEach((track) => track.stop());
974
+ return;
975
+ }
976
+ streamRef.current = stream;
977
+ onStreamChangeRef.current?.(stream);
978
+ const recorder = new MediaRecorder(stream, { mimeType });
979
+ const chunks = [];
980
+ recorder.ondataavailable = (event) => {
981
+ if (event.data.size) chunks.push(event.data);
982
+ };
983
+ recorder.onstop = () => {
984
+ const actualType = recorder.mimeType || "audio/webm";
985
+ if (mountedRef.current) onRecordedRef.current(new File([new Blob(chunks, { type: actualType })], `recording-${Date.now()}.${recordingExtension(actualType)}`, { type: actualType }));
986
+ stream.getTracks().forEach((track) => track.stop());
987
+ onStreamChangeRef.current?.(null);
988
+ recorderRef.current = null;
989
+ streamRef.current = null;
990
+ if (mountedRef.current) setIsRecording(false);
991
+ };
992
+ recorderRef.current = recorder;
993
+ streamRef.current = stream;
994
+ recorder.start();
995
+ setIsRecording(true);
996
+ } catch {
997
+ streamRef.current?.getTracks().forEach((track) => track.stop());
998
+ onStreamChangeRef.current?.(null);
999
+ streamRef.current = null;
1000
+ recorderRef.current = null;
1001
+ if (mountedRef.current) setError("Microphone access is unavailable.");
1002
+ } finally {
1003
+ startingRef.current = false;
1004
+ }
1005
+ }, []);
1006
+ React3.useEffect(() => {
1007
+ mountedRef.current = true;
1008
+ return () => {
1009
+ mountedRef.current = false;
1010
+ if (recorderRef.current && recorderRef.current.state !== "inactive") recorderRef.current.stop();
1011
+ streamRef.current?.getTracks().forEach((track) => track.stop());
1012
+ onStreamChangeRef.current?.(null);
1013
+ };
1014
+ }, []);
1015
+ return { error, isRecording, start, stop };
1016
+ }
1017
+
1018
+ // src/ui/use-agent-chat-composer.ts
1019
+ function useAgentChatComposer({
1020
+ disabled = false,
1021
+ isRunning = false,
1022
+ isCancelling = false,
1023
+ inputContract,
1024
+ recordingEnabled,
1025
+ focusKey,
1026
+ restoredDraft,
1027
+ textareaRef,
1028
+ onSubmit
1029
+ }) {
1030
+ const [text, setDraftText] = React4.useState("");
1031
+ const [files, setDraftFiles] = React4.useState([]);
1032
+ const [isSubmitting, setIsSubmitting] = React4.useState(false);
1033
+ const [attachmentError, setAttachmentError] = React4.useState(null);
1034
+ const draftRef = React4.useRef({ text, files, revision: 0 });
1035
+ const inFlightRef = React4.useRef([]);
1036
+ const submittingRef = React4.useRef(false);
1037
+ const mountedRef = React4.useRef(true);
1038
+ const updateDraft = (nextText, nextFiles) => {
1039
+ draftRef.current = { text: nextText, files: nextFiles, revision: draftRef.current.revision + 1 };
1040
+ setDraftText(nextText);
1041
+ setDraftFiles(nextFiles);
1042
+ };
1043
+ React4.useEffect(() => {
1044
+ mountedRef.current = true;
1045
+ return () => {
1046
+ mountedRef.current = false;
1047
+ revokeAgentChatComposerFiles(draftRef.current.files);
1048
+ revokeAgentChatComposerFiles(inFlightRef.current);
1049
+ };
1050
+ }, []);
1051
+ const focus = useChatComposerFocus({ textareaRef, disabled, focusKey, restoredDraft, onRestore: (draft) => {
1052
+ revokeAgentChatComposerFiles(draftRef.current.files.filter((file) => !draft.files.includes(file)));
1053
+ updateDraft(draft.text, draft.files);
1054
+ } });
1055
+ const accept = inputContract ? inputMimeTypes(inputContract) : null;
1056
+ const addFiles = (selected) => {
1057
+ const accepted = accept ? selected.filter((file) => accept.includes((0, import_client2.normalizeAttachmentMimeType)(file.type, file.name))) : selected;
1058
+ setAttachmentError(accepted.length === selected.length ? null : "One or more selected file types are not supported by this Agent.");
1059
+ updateDraft(draftRef.current.text, [...draftRef.current.files, ...accepted.map(createAgentChatComposerFile)]);
1060
+ };
1061
+ const recordedRef = React4.useRef(addFiles);
1062
+ recordedRef.current = addFiles;
1063
+ const recorder = useAudioRecorder((file) => {
1064
+ if (mountedRef.current) recordedRef.current([file]);
1065
+ });
1066
+ const recordingAllowed = inputContract ? inputContract.modalities.audio.enabled && inputContract.modalities.audio.recording_enabled && recordingEnabled !== false : recordingEnabled === true;
1067
+ const validationError = inputContract ? validateAgentChatSubmission(
1068
+ inputContract,
1069
+ text,
1070
+ files.map((file) => ({ data: file.source || new Uint8Array(), mediaType: file.mediaType, name: file.filename, byteSize: file.source ? void 0 : file.byteSize }))
1071
+ ) : null;
1072
+ const canSubmit = !disabled && !isCancelling && !isSubmitting && !recorder.isRecording && !validationError && Boolean(text.trim() || files.length);
1073
+ const submit = async () => {
1074
+ if (!canSubmit || submittingRef.current) return;
1075
+ const submitted = draftRef.current;
1076
+ submittingRef.current = true;
1077
+ inFlightRef.current = submitted.files;
1078
+ setIsSubmitting(true);
1079
+ updateDraft("", []);
1080
+ const clearedRevision = draftRef.current.revision;
1081
+ focus();
1082
+ try {
1083
+ await onSubmit({
1084
+ text: submitted.text,
1085
+ files: submitted.files,
1086
+ attachmentIds: submitted.files.flatMap((file) => file.persistedAttachmentId ? [file.persistedAttachmentId] : [])
1087
+ });
1088
+ revokeAgentChatComposerFiles(submitted.files);
1089
+ } catch {
1090
+ if (mountedRef.current && draftRef.current.revision === clearedRevision) updateDraft(submitted.text, submitted.files);
1091
+ else revokeAgentChatComposerFiles(submitted.files);
1092
+ } finally {
1093
+ inFlightRef.current = [];
1094
+ submittingRef.current = false;
1095
+ if (mountedRef.current) setIsSubmitting(false);
1096
+ }
1097
+ };
1098
+ return {
1099
+ text,
1100
+ files,
1101
+ isSubmitting,
1102
+ canSubmit,
1103
+ validationError,
1104
+ attachmentError,
1105
+ recordingAllowed,
1106
+ recorder,
1107
+ accept,
1108
+ fileAccept: accept ? (0, import_client2.attachmentFileAccept)(accept) : void 0,
1109
+ allowAttachments: accept ? accept.length > 0 : true,
1110
+ action: chatComposerAction({ hasDraft: Boolean(text.trim() || files.length), isRunning, isCancelling }),
1111
+ setText: (value) => updateDraft(value, draftRef.current.files),
1112
+ addFiles,
1113
+ removeFile: (id) => {
1114
+ revokeAgentChatComposerFiles(draftRef.current.files.filter((file) => file.id === id));
1115
+ updateDraft(draftRef.current.text, draftRef.current.files.filter((file) => file.id !== id));
1116
+ },
1117
+ submit,
1118
+ onKeyDown: (event) => {
1119
+ if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
1120
+ event.preventDefault();
1121
+ void submit();
1122
+ }
1123
+ }
1124
+ };
1125
+ }
1126
+
1127
+ // src/ui/agent-chat-context-status.tsx
1128
+ var React5 = __toESM(require("react"), 1);
889
1129
  var import_jsx_runtime3 = require("react/jsx-runtime");
1130
+ var COMPACT_TOKENS = new Intl.NumberFormat("en-US", { notation: "compact" });
1131
+ var PERCENT = new Intl.NumberFormat("en-US", {
1132
+ style: "percent",
1133
+ maximumFractionDigits: 1
1134
+ });
1135
+ var EXACT_SOURCES = /* @__PURE__ */ new Set(["exact", "provider_usage"]);
1136
+ function contextStatusMetrics(contextWindow) {
1137
+ const maximum = Number(contextWindow?.max_tokens || 0);
1138
+ const input = Math.max(0, Number(contextWindow?.input_tokens || 0));
1139
+ const admissionInput = Math.max(0, Number(contextWindow?.admission_input_tokens ?? input));
1140
+ const usageRatio = Math.max(0, Math.min(1, Number(
1141
+ contextWindow?.usage_ratio ?? input / maximum
1142
+ )));
1143
+ const admissionRatio = Math.max(0, Math.min(1, Number(
1144
+ contextWindow?.admission_ratio ?? admissionInput / maximum
1145
+ )));
1146
+ return { maximum, input, admissionInput, usageRatio, admissionRatio };
1147
+ }
1148
+ function AgentChatContextStatus({
1149
+ className,
1150
+ contextWindow
1151
+ }) {
1152
+ const tooltipId = React5.useId();
1153
+ const [open, setOpen] = React5.useState(false);
1154
+ const { maximum, input, admissionInput, usageRatio, admissionRatio } = contextStatusMetrics(contextWindow);
1155
+ const percentage = Math.round(usageRatio * 100);
1156
+ const exact = EXACT_SOURCES.has(contextWindow?.source || "unknown");
1157
+ if (!Number.isFinite(maximum) || maximum <= 0) return null;
1158
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1159
+ "div",
1160
+ {
1161
+ className: cn("a24-context-status", className),
1162
+ onBlurCapture: (event) => {
1163
+ if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
1164
+ },
1165
+ onFocusCapture: () => setOpen(true),
1166
+ onMouseEnter: () => setOpen(true),
1167
+ onMouseLeave: () => setOpen(false),
1168
+ children: [
1169
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1170
+ "button",
1171
+ {
1172
+ "aria-describedby": open ? tooltipId : void 0,
1173
+ "aria-label": `Context window ${percentage}% used`,
1174
+ className: "a24-context-status__trigger",
1175
+ onKeyDown: (event) => {
1176
+ if (event.key === "Escape") setOpen(false);
1177
+ },
1178
+ type: "button",
1179
+ children: [
1180
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { "aria-hidden": "true", className: "a24-context-status__ring", viewBox: "0 0 24 24", children: [
1181
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { className: "a24-context-status__track", cx: "12", cy: "12", r: "10" }),
1182
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1183
+ "circle",
1184
+ {
1185
+ className: "a24-context-status__value",
1186
+ cx: "12",
1187
+ cy: "12",
1188
+ pathLength: "100",
1189
+ r: "10",
1190
+ strokeDasharray: `${percentage} 100`
1191
+ }
1192
+ )
1193
+ ] }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
1195
+ percentage,
1196
+ "%"
1197
+ ] })
1198
+ ]
1199
+ }
1200
+ ),
1201
+ open ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "a24-context-status__popover", id: tooltipId, role: "tooltip", children: [
1202
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "a24-context-status__sr-only", children: "Context window" }),
1203
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("strong", { children: [
1204
+ PERCENT.format(usageRatio),
1205
+ " context used"
1206
+ ] }),
1207
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
1208
+ exact ? "Input" : "Estimated input",
1209
+ ": ",
1210
+ COMPACT_TOKENS.format(input),
1211
+ " / ",
1212
+ COMPACT_TOKENS.format(maximum),
1213
+ " tokens"
1214
+ ] }),
1215
+ admissionInput !== input ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
1216
+ "Safety bound: ",
1217
+ COMPACT_TOKENS.format(admissionInput),
1218
+ " tokens (",
1219
+ PERCENT.format(admissionRatio),
1220
+ ")"
1221
+ ] }) : null
1222
+ ] }) : null
1223
+ ]
1224
+ }
1225
+ );
1226
+ }
1227
+
1228
+ // src/ui/agent-chat-composer.tsx
1229
+ var import_jsx_runtime4 = require("react/jsx-runtime");
890
1230
  function formatFileCount(files) {
891
1231
  if (files.length === 1) return files[0].filename;
892
1232
  return `${files.length} files`;
@@ -894,6 +1234,9 @@ function formatFileCount(files) {
894
1234
  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";
895
1235
  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";
896
1236
  function AgentChatComposer({
1237
+ inputContract,
1238
+ recordingEnabled,
1239
+ contextWindow,
897
1240
  accept,
898
1241
  allowAttachments = true,
899
1242
  attachmentLayout = "flow",
@@ -911,16 +1254,22 @@ function AgentChatComposer({
911
1254
  restoredDraft,
912
1255
  textareaRef
913
1256
  }) {
914
- const fileInputRef = React3.useRef(null);
915
- const filesRef = React3.useRef([]);
916
- const inFlightFilesRef = React3.useRef([]);
917
- const localTextareaRef = React3.useRef(null);
918
- const draftRevisionRef = React3.useRef(0);
919
- const [text, setText] = React3.useState("");
920
- const [files, setFiles] = React3.useState([]);
921
- const [isSubmitting, setIsSubmitting] = React3.useState(false);
1257
+ const fileInputRef = React6.useRef(null);
1258
+ const localTextareaRef = React6.useRef(null);
1259
+ const composer = useAgentChatComposer({
1260
+ inputContract,
1261
+ recordingEnabled,
1262
+ disabled,
1263
+ isRunning,
1264
+ isCancelling,
1265
+ focusKey,
1266
+ restoredDraft,
1267
+ textareaRef: localTextareaRef,
1268
+ onSubmit: (input) => onSubmit({ ...input, text: input.text.trim() })
1269
+ });
1270
+ const { text, files, setText, isSubmitting, canSubmit, action, submit } = composer;
922
1271
  const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
923
- const setTextareaRef = React3.useCallback(
1272
+ const setTextareaRef = React6.useCallback(
924
1273
  (node) => {
925
1274
  localTextareaRef.current = node;
926
1275
  if (typeof textareaRef === "function") {
@@ -931,27 +1280,10 @@ function AgentChatComposer({
931
1280
  },
932
1281
  [textareaRef]
933
1282
  );
934
- React3.useEffect(() => {
935
- filesRef.current = files;
1283
+ React6.useEffect(() => {
936
1284
  onAttachmentCountChange?.(files.length);
937
1285
  }, [files, onAttachmentCountChange]);
938
- React3.useEffect(() => () => {
939
- revokeAgentChatComposerFiles(filesRef.current);
940
- revokeAgentChatComposerFiles(inFlightFilesRef.current);
941
- }, []);
942
- const focusComposer = useChatComposerFocus({
943
- textareaRef: localTextareaRef,
944
- disabled,
945
- focusKey,
946
- restoredDraft,
947
- onRestore: (draft) => {
948
- draftRevisionRef.current += 1;
949
- revokeAgentChatComposerFiles(filesRef.current);
950
- setText(draft.text);
951
- setFiles(draft.files);
952
- }
953
- });
954
- React3.useLayoutEffect(() => {
1286
+ React6.useLayoutEffect(() => {
955
1287
  const textarea = localTextareaRef.current;
956
1288
  if (!textarea) return;
957
1289
  if (isExpanded) {
@@ -964,65 +1296,12 @@ function AgentChatComposer({
964
1296
  textarea.style.height = "";
965
1297
  textarea.style.overflowY = "hidden";
966
1298
  }, [isExpanded, text]);
967
- const canSubmit = !disabled && !isCancelling && !isSubmitting && (text.trim().length > 0 || files.length > 0);
968
- const action = chatComposerAction({ hasDraft: text.trim().length > 0 || files.length > 0, isRunning, isCancelling });
969
1299
  const handleFilesChange = (event) => {
970
- const selected = Array.from(event.target.files || []).map(createAgentChatComposerFile);
971
- if (selected.length > 0) {
972
- draftRevisionRef.current += 1;
973
- setFiles((current) => [...current, ...selected]);
974
- }
1300
+ composer.addFiles(Array.from(event.target.files || []));
975
1301
  event.currentTarget.value = "";
976
1302
  };
977
- const removeFile = (fileId) => {
978
- draftRevisionRef.current += 1;
979
- setFiles((current) => {
980
- const target = current.find((file) => file.id === fileId);
981
- if (target) revokeAgentChatComposerFiles([target]);
982
- return current.filter((file) => file.id !== fileId);
983
- });
984
- };
985
- const submit = async () => {
986
- if (!canSubmit) return;
987
- const submittedText = text.trim();
988
- const submittedFiles = files;
989
- const clearedRevision = draftRevisionRef.current + 1;
990
- draftRevisionRef.current = clearedRevision;
991
- inFlightFilesRef.current = submittedFiles;
992
- setIsSubmitting(true);
993
- setText("");
994
- setFiles([]);
995
- focusComposer();
996
- try {
997
- await onSubmit({
998
- text: submittedText,
999
- files: submittedFiles,
1000
- attachmentIds: submittedFiles.flatMap((file) => file.persistedAttachmentId ? [file.persistedAttachmentId] : [])
1001
- });
1002
- revokeAgentChatComposerFiles(submittedFiles);
1003
- inFlightFilesRef.current = [];
1004
- } catch {
1005
- if (draftRevisionRef.current === clearedRevision) {
1006
- draftRevisionRef.current += 1;
1007
- setText(submittedText);
1008
- setFiles(submittedFiles);
1009
- inFlightFilesRef.current = [];
1010
- } else {
1011
- revokeAgentChatComposerFiles(submittedFiles);
1012
- inFlightFilesRef.current = [];
1013
- }
1014
- } finally {
1015
- setIsSubmitting(false);
1016
- }
1017
- };
1018
- const handleKeyDown = (event) => {
1019
- if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
1020
- event.preventDefault();
1021
- void submit();
1022
- }
1023
- };
1024
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), "data-agents24-chat-composer": "", children: [
1025
- files.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1303
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), "data-agents24-chat-composer": "", children: [
1304
+ files.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1026
1305
  "div",
1027
1306
  {
1028
1307
  "data-testid": "agent-chat-composer-attachments",
@@ -1031,16 +1310,17 @@ function AgentChatComposer({
1031
1310
  "a24-composer__attachments min-w-0 py-1",
1032
1311
  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"
1033
1312
  ),
1034
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1313
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1035
1314
  ChatAttachmentRows,
1036
1315
  {
1037
1316
  attachments: files,
1038
- onRemove: (attachment) => attachment.id && removeFile(attachment.id)
1317
+ onRemove: (attachment) => attachment.id && composer.removeFile(attachment.id)
1039
1318
  }
1040
1319
  )
1041
1320
  }
1042
1321
  ) : null,
1043
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1322
+ composer.attachmentError || composer.recorder.error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", children: composer.attachmentError || composer.recorder.error }) : null,
1323
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1044
1324
  "div",
1045
1325
  {
1046
1326
  "data-expanded": isExpanded ? "" : void 0,
@@ -1048,7 +1328,7 @@ function AgentChatComposer({
1048
1328
  "a24-composer__surface relative w-full border border-input bg-background shadow-sm",
1049
1329
  isExpanded ? "rounded-xl p-2 pb-1.5" : "rounded-xl px-2 py-[3px]"
1050
1330
  ),
1051
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1331
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1052
1332
  "div",
1053
1333
  {
1054
1334
  className: "a24-composer__grid w-full",
@@ -1060,12 +1340,12 @@ function AgentChatComposer({
1060
1340
  gap: isExpanded ? "3px 10px" : "8px"
1061
1341
  },
1062
1342
  children: [
1063
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { gridArea: "plus" }, className: "a24-composer__attach-slot flex shrink-0 items-center justify-center", children: [
1064
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1343
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { gridArea: "plus" }, className: "a24-composer__attach-slot flex shrink-0 items-center justify-center", children: [
1344
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1065
1345
  "input",
1066
1346
  {
1067
1347
  ref: fileInputRef,
1068
- accept,
1348
+ accept: composer.fileAccept ?? accept,
1069
1349
  "aria-label": "Attach files",
1070
1350
  className: "hidden",
1071
1351
  multiple: true,
@@ -1074,20 +1354,20 @@ function AgentChatComposer({
1074
1354
  type: "file"
1075
1355
  }
1076
1356
  ),
1077
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1357
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1078
1358
  "button",
1079
1359
  {
1080
1360
  "aria-label": "Attach files",
1081
1361
  className: cn("a24-composer__attach", pillButtonClass),
1082
- disabled: disabled || isSubmitting || !allowAttachments,
1362
+ disabled: disabled || isSubmitting || !allowAttachments || !composer.allowAttachments,
1083
1363
  onClick: () => fileInputRef.current?.click(),
1084
1364
  title: "Attach files",
1085
1365
  type: "button",
1086
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Plus, { className: "size-4" })
1366
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Plus, { className: "size-4" })
1087
1367
  }
1088
1368
  )
1089
1369
  ] }),
1090
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { gridArea: "textarea" }, className: "a24-composer__textarea-slot min-w-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1370
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { gridArea: "textarea" }, className: "a24-composer__textarea-slot min-w-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1091
1371
  "textarea",
1092
1372
  {
1093
1373
  ref: setTextareaRef,
@@ -1099,20 +1379,50 @@ function AgentChatComposer({
1099
1379
  ),
1100
1380
  disabled,
1101
1381
  name: "message",
1102
- onChange: (event) => {
1103
- draftRevisionRef.current += 1;
1104
- setText(event.target.value);
1105
- },
1106
- onKeyDown: handleKeyDown,
1382
+ onChange: (event) => setText(event.target.value),
1383
+ onKeyDown: composer.onKeyDown,
1107
1384
  placeholder,
1108
1385
  rows: isExpanded ? 2 : 1,
1109
1386
  value: text
1110
1387
  }
1111
1388
  ) }),
1112
- isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { gridArea: "toolbar" }, className: "a24-composer__toolbar flex min-w-0 items-center gap-1.5", children: inputToolbarContent }) : null,
1113
- !isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { gridArea: "composer" }, className: "flex min-w-0 items-center gap-1.5" }) : null,
1114
- !isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { gridArea: "mic" }, className: "flex shrink-0 items-center justify-end" }) : null,
1115
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { gridArea: "submit" }, className: "a24-composer__submit-slot flex shrink-0 items-center justify-end gap-1", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1389
+ isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { gridArea: "toolbar" }, className: "a24-composer__toolbar flex min-w-0 items-center gap-1.5", children: [
1390
+ inputToolbarContent,
1391
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AgentChatContextStatus, { contextWindow }),
1392
+ composer.recordingAllowed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1393
+ "button",
1394
+ {
1395
+ type: "button",
1396
+ className: pillButtonClass,
1397
+ "aria-label": composer.recorder.isRecording ? "Stop recording" : "Record audio",
1398
+ disabled: disabled || isRunning || isSubmitting,
1399
+ onClick: () => {
1400
+ if (composer.recorder.isRecording) composer.recorder.stop();
1401
+ else void composer.recorder.start();
1402
+ },
1403
+ children: composer.recorder.isRecording ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Square, {}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Mic, {})
1404
+ }
1405
+ ) : null
1406
+ ] }) : null,
1407
+ !isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { gridArea: "composer" }, className: "flex min-w-0 items-center gap-1.5" }) : null,
1408
+ !isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { gridArea: "mic" }, className: "flex shrink-0 items-center justify-end", children: [
1409
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AgentChatContextStatus, { contextWindow }),
1410
+ composer.recordingAllowed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1411
+ "button",
1412
+ {
1413
+ type: "button",
1414
+ className: pillButtonClass,
1415
+ "aria-label": composer.recorder.isRecording ? "Stop recording" : "Record audio",
1416
+ disabled: disabled || isRunning || isSubmitting,
1417
+ onClick: () => {
1418
+ if (composer.recorder.isRecording) composer.recorder.stop();
1419
+ else void composer.recorder.start();
1420
+ },
1421
+ children: composer.recorder.isRecording ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Square, {}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Mic, {})
1422
+ }
1423
+ ) : null
1424
+ ] }) : null,
1425
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { gridArea: "submit" }, className: "a24-composer__submit-slot flex shrink-0 items-center justify-end gap-1", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1116
1426
  "button",
1117
1427
  {
1118
1428
  "aria-label": isCancelling ? "Cancelling response" : action === "stop" ? "Stop generating" : files.length > 0 ? `Send ${formatFileCount(files)}` : isRunning ? "Queue message" : "Send message",
@@ -1122,9 +1432,9 @@ function AgentChatComposer({
1122
1432
  if (action === "stop") onStop?.();
1123
1433
  else void submit();
1124
1434
  },
1125
- title: action === "stop" ? "Stop" : isRunning ? "Queue message" : "Send",
1435
+ title: composer.validationError || (action === "stop" ? "Stop" : isRunning ? "Queue message" : "Send"),
1126
1436
  type: "button",
1127
- children: isCancelling ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Loader2, { className: "size-3.5 animate-spin" }) : action === "stop" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Square, { className: "size-3.5 fill-current" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ArrowUp, { className: "size-4", strokeWidth: 2.5 })
1437
+ children: isCancelling ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Loader2, { className: "size-3.5 animate-spin" }) : action === "stop" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Square, { className: "size-3.5 fill-current" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ArrowUp, { className: "size-4", strokeWidth: 2.5 })
1128
1438
  }
1129
1439
  ) })
1130
1440
  ]
@@ -1132,17 +1442,17 @@ function AgentChatComposer({
1132
1442
  )
1133
1443
  }
1134
1444
  ),
1135
- !isExpanded && inputToolbarContent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "a24-composer__toolbar a24-composer__toolbar--external mt-2 flex items-center gap-2 px-1", children: inputToolbarContent }) : null
1445
+ !isExpanded && inputToolbarContent ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "a24-composer__toolbar a24-composer__toolbar--external mt-2 flex items-center gap-2 px-1", children: inputToolbarContent }) : null
1136
1446
  ] });
1137
1447
  }
1138
1448
 
1139
1449
  // src/ui/agent-chat-queue.tsx
1140
- var React4 = __toESM(require("react"), 1);
1450
+ var React7 = __toESM(require("react"), 1);
1141
1451
  var import_lucide_react3 = require("lucide-react");
1142
- var import_jsx_runtime4 = require("react/jsx-runtime");
1452
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1143
1453
  function QueueRow({ message, onRemove, onEdit }) {
1144
- const [busy, setBusy] = React4.useState(false);
1145
- const [error, setError] = React4.useState(null);
1454
+ const [busy, setBusy] = React7.useState(false);
1455
+ const [error, setError] = React7.useState(null);
1146
1456
  const editable = message.revision > 0 && (message.status === "queued" || message.status === "blocked");
1147
1457
  const act = async (operation) => {
1148
1458
  setBusy(true);
@@ -1155,14 +1465,14 @@ function QueueRow({ message, onRemove, onEdit }) {
1155
1465
  setBusy(false);
1156
1466
  }
1157
1467
  };
1158
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { "data-message-id": message.id, className: "a24-queue__row min-w-0 border-b border-border/40 last:border-b-0", children: [
1159
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "a24-queue__row-content flex min-h-9 items-center gap-2 px-3 text-sm", children: [
1160
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.CornerDownLeft, { "aria-hidden": true, className: "size-4 shrink-0 text-muted-foreground" }),
1161
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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"}` }),
1162
- message.status === "blocked" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "shrink-0 text-xs text-amber-700", children: "Needs attention" }) : null,
1163
- ["steer_pending", "delivering"].includes(message.status) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: "Steering\u2026" }) : null,
1164
- editable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1165
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1468
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { "data-message-id": message.id, className: "a24-queue__row min-w-0 border-b border-border/40 last:border-b-0", children: [
1469
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "a24-queue__row-content flex min-h-9 items-center gap-2 px-3 text-sm", children: [
1470
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.CornerDownLeft, { "aria-hidden": true, className: "size-4 shrink-0 text-muted-foreground" }),
1471
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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"}` }),
1472
+ message.status === "blocked" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "shrink-0 text-xs text-amber-700", children: "Needs attention" }) : null,
1473
+ ["steer_pending", "delivering"].includes(message.status) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: "Steering\u2026" }) : null,
1474
+ editable ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1475
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1166
1476
  "button",
1167
1477
  {
1168
1478
  type: "button",
@@ -1170,12 +1480,12 @@ function QueueRow({ message, onRemove, onEdit }) {
1170
1480
  disabled: busy,
1171
1481
  onClick: () => void act(() => onRemove(message)),
1172
1482
  className: "a24-queue__icon flex size-8 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground disabled:opacity-50",
1173
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.Trash2, { "aria-hidden": true, className: "size-4" })
1483
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.Trash2, { "aria-hidden": true, className: "size-4" })
1174
1484
  }
1175
1485
  ),
1176
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("details", { className: "a24-queue__menu relative group/queue-menu", children: [
1177
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.Ellipsis, { "aria-hidden": true, className: "size-4" }) }),
1178
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "a24-queue__menu-content mt-1 min-w-28 rounded-md border bg-background p-1", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1486
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "a24-queue__menu relative group/queue-menu", children: [
1487
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.Ellipsis, { "aria-hidden": true, className: "size-4" }) }),
1488
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "a24-queue__menu-content mt-1 min-w-28 rounded-md border bg-background p-1", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1179
1489
  "button",
1180
1490
  {
1181
1491
  type: "button",
@@ -1188,29 +1498,29 @@ function QueueRow({ message, onRemove, onEdit }) {
1188
1498
  ] })
1189
1499
  ] }) : null
1190
1500
  ] }),
1191
- error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", className: "px-9 pb-2 text-xs text-destructive", children: error }) : null
1501
+ error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "alert", className: "px-9 pb-2 text-xs text-destructive", children: error }) : null
1192
1502
  ] });
1193
1503
  }
1194
1504
  function AgentChatQueue({ pending, queue, onRemove, onEdit, onResume, className }) {
1195
- const [resumeError, setResumeError] = React4.useState(null);
1505
+ const [resumeError, setResumeError] = React7.useState(null);
1196
1506
  if (!pending.length && !queue?.paused) return null;
1197
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("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: [
1198
- queue?.paused ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-h-9 items-center justify-between gap-2 px-3 text-xs text-muted-foreground", children: [
1199
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Queue paused" }),
1200
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", onClick: () => {
1507
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("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: [
1508
+ queue?.paused ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex min-h-9 items-center justify-between gap-2 px-3 text-xs text-muted-foreground", children: [
1509
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Queue paused" }),
1510
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: () => {
1201
1511
  void onResume().then(() => setResumeError(null)).catch((cause) => setResumeError(cause instanceof Error ? cause.message : "Could not resume queue"));
1202
1512
  }, className: "font-medium text-foreground hover:underline", children: "Resume queue" })
1203
1513
  ] }) : null,
1204
- resumeError ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", className: "px-3 pb-2 text-xs text-destructive", children: resumeError }) : null,
1205
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "max-h-40 overflow-y-auto", children: pending.map((message) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueRow, { message, onRemove, onEdit }, message.client_submission_id || message.id)) })
1514
+ resumeError ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "alert", className: "px-3 pb-2 text-xs text-destructive", children: resumeError }) : null,
1515
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-h-40 overflow-y-auto", children: pending.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QueueRow, { message, onRemove, onEdit }, message.client_submission_id || message.id)) })
1206
1516
  ] });
1207
1517
  }
1208
1518
 
1209
1519
  // src/ui/agent-chat-actions.tsx
1210
- var React5 = __toESM(require("react"), 1);
1520
+ var React8 = __toESM(require("react"), 1);
1211
1521
  var import_lucide_react4 = require("lucide-react");
1212
1522
  var import_radix_ui = require("radix-ui");
1213
- var import_jsx_runtime5 = require("react/jsx-runtime");
1523
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1214
1524
  var FEEDBACK_REASONS = [
1215
1525
  ["incorrect", "Incorrect"],
1216
1526
  ["irrelevant", "Irrelevant"],
@@ -1221,8 +1531,8 @@ var FEEDBACK_REASONS = [
1221
1531
  ];
1222
1532
  var enteredCompletionRuns = /* @__PURE__ */ new Set();
1223
1533
  function useLiveCompletionRuns(runId, isRunning) {
1224
- const liveRuns = React5.useRef(/* @__PURE__ */ new Set());
1225
- React5.useEffect(() => {
1534
+ const liveRuns = React8.useRef(/* @__PURE__ */ new Set());
1535
+ React8.useEffect(() => {
1226
1536
  if (!runId || !isRunning) return;
1227
1537
  liveRuns.current.add(runId);
1228
1538
  if (liveRuns.current.size > 256) liveRuns.current.delete(liveRuns.current.values().next().value);
@@ -1230,10 +1540,10 @@ function useLiveCompletionRuns(runId, isRunning) {
1230
1540
  return (candidate) => Boolean(candidate && liveRuns.current.has(candidate));
1231
1541
  }
1232
1542
  function useCompletionActionEntrance(isComplete, runId, wasLive = false) {
1233
- const sawIncomplete = React5.useRef(!isComplete);
1234
- const entered = React5.useRef(false);
1543
+ const sawIncomplete = React8.useRef(!isComplete);
1544
+ const entered = React8.useRef(false);
1235
1545
  const shouldEnter = isComplete && !entered.current && (runId ? wasLive && !enteredCompletionRuns.has(runId) : sawIncomplete.current);
1236
- React5.useEffect(() => {
1546
+ React8.useEffect(() => {
1237
1547
  if (!isComplete) sawIncomplete.current = true;
1238
1548
  else if (shouldEnter) {
1239
1549
  entered.current = true;
@@ -1261,17 +1571,17 @@ function AgentChatDefaultActions({
1261
1571
  handlers,
1262
1572
  message
1263
1573
  }) {
1264
- const [feedbackOpen, setFeedbackOpen] = React5.useState(false);
1265
- const [feedbackTrigger, setFeedbackTrigger] = React5.useState(null);
1266
- const [reason, setReason] = React5.useState(handlers?.feedback?.reason ?? null);
1267
- const [comment, setComment] = React5.useState(handlers?.feedback?.comment ?? "");
1268
- const [optimisticCopied, setOptimisticCopied] = React5.useState(false);
1269
- const copyResetTimer = React5.useRef(null);
1270
- React5.useEffect(() => {
1574
+ const [feedbackOpen, setFeedbackOpen] = React8.useState(false);
1575
+ const [feedbackTrigger, setFeedbackTrigger] = React8.useState(null);
1576
+ const [reason, setReason] = React8.useState(handlers?.feedback?.reason ?? null);
1577
+ const [comment, setComment] = React8.useState(handlers?.feedback?.comment ?? "");
1578
+ const [optimisticCopied, setOptimisticCopied] = React8.useState(false);
1579
+ const copyResetTimer = React8.useRef(null);
1580
+ React8.useEffect(() => {
1271
1581
  setReason(handlers?.feedback?.reason ?? null);
1272
1582
  setComment(handlers?.feedback?.comment ?? "");
1273
1583
  }, [handlers?.feedback?.comment, handlers?.feedback?.reason]);
1274
- React5.useEffect(() => () => {
1584
+ React8.useEffect(() => () => {
1275
1585
  if (copyResetTimer.current !== null) window.clearTimeout(copyResetTimer.current);
1276
1586
  }, []);
1277
1587
  const copied = handlers?.copied ?? optimisticCopied;
@@ -1288,32 +1598,32 @@ function AgentChatDefaultActions({
1288
1598
  if (!handlers || message.isFinal === false) return null;
1289
1599
  if (message.role === "user") {
1290
1600
  const sentAt = formatSentAt(message.createdAt);
1291
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ChatMessageActions, { className: "a24-user-message-actions", children: [
1292
- sentAt ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("time", { dateTime: sentAt.dateTime, children: sentAt.label }) : null,
1293
- handlers.onCopy ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1601
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(ChatMessageActions, { className: "a24-user-message-actions", children: [
1602
+ sentAt ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("time", { dateTime: sentAt.dateTime, children: sentAt.label }) : null,
1603
+ handlers.onCopy ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1294
1604
  ChatMessageAction,
1295
1605
  {
1296
1606
  label: "Copy",
1297
1607
  onClick: copyMessage,
1298
1608
  tooltip: copied ? "Copied!" : "Copy to clipboard",
1299
1609
  className: "a24-user-message-copy",
1300
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.Check, { className: "a24-user-message-copy__check text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.Copy, { className: "a24-user-message-copy__icon" })
1610
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.Check, { className: "a24-user-message-copy__check text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.Copy, { className: "a24-user-message-copy__icon" })
1301
1611
  }
1302
1612
  ) : null
1303
1613
  ] });
1304
1614
  }
1305
1615
  const canWriteFeedback = Boolean(message.runId && handlers.onSetFeedback);
1306
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ChatMessageActions, { className: animateCompletion ? "a24-chat-completion-actions" : void 0, children: [
1307
- handlers.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1616
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(ChatMessageActions, { className: animateCompletion ? "a24-chat-completion-actions" : void 0, children: [
1617
+ handlers.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1308
1618
  ChatMessageAction,
1309
1619
  {
1310
1620
  label: "Retry",
1311
1621
  onClick: () => void handlers.onRetry?.(message),
1312
1622
  tooltip: "Regenerate response",
1313
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.RefreshCcw, { className: "size-4" })
1623
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.RefreshCcw, { className: "size-4" })
1314
1624
  }
1315
1625
  ) : null,
1316
- canWriteFeedback ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1626
+ canWriteFeedback ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1317
1627
  ChatMessageAction,
1318
1628
  {
1319
1629
  label: "Like",
@@ -1321,11 +1631,11 @@ function AgentChatDefaultActions({
1321
1631
  rating: handlers.feedback?.rating === "like" ? null : "like"
1322
1632
  }),
1323
1633
  tooltip: "Like this response",
1324
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.ThumbsUp, { className: "size-4", fill: handlers.feedback?.rating === "like" ? "currentColor" : "none" })
1634
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.ThumbsUp, { className: "size-4", fill: handlers.feedback?.rating === "like" ? "currentColor" : "none" })
1325
1635
  }
1326
1636
  ) : null,
1327
- canWriteFeedback ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_radix_ui.Popover.Root, { onOpenChange: setFeedbackOpen, open: feedbackOpen, children: [
1328
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_radix_ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1637
+ canWriteFeedback ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_radix_ui.Popover.Root, { onOpenChange: setFeedbackOpen, open: feedbackOpen, children: [
1638
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1329
1639
  ChatMessageAction,
1330
1640
  {
1331
1641
  label: "Dislike",
@@ -1337,14 +1647,14 @@ function AgentChatDefaultActions({
1337
1647
  },
1338
1648
  ref: setFeedbackTrigger,
1339
1649
  tooltip: "Dislike this response",
1340
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.ThumbsDown, { className: "size-4", fill: handlers.feedback?.rating === "dislike" ? "currentColor" : "none" })
1650
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.ThumbsDown, { className: "size-4", fill: handlers.feedback?.rating === "dislike" ? "currentColor" : "none" })
1341
1651
  }
1342
1652
  ) }),
1343
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1653
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1344
1654
  import_radix_ui.Popover.Portal,
1345
1655
  {
1346
1656
  container: feedbackTrigger?.closest("[data-agents24-theme-root]") ?? void 0,
1347
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1657
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1348
1658
  import_radix_ui.Popover.Content,
1349
1659
  {
1350
1660
  align: "end",
@@ -1354,8 +1664,8 @@ function AgentChatDefaultActions({
1354
1664
  side: "top",
1355
1665
  sideOffset: 8,
1356
1666
  children: [
1357
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-sm font-medium", children: "What could be better?" }),
1358
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "mt-3 flex flex-wrap gap-1.5", children: FEEDBACK_REASONS.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1667
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm font-medium", children: "What could be better?" }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mt-3 flex flex-wrap gap-1.5", children: FEEDBACK_REASONS.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1359
1669
  "button",
1360
1670
  {
1361
1671
  "aria-pressed": reason === value,
@@ -1366,7 +1676,7 @@ function AgentChatDefaultActions({
1366
1676
  },
1367
1677
  value
1368
1678
  )) }),
1369
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1679
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1370
1680
  "textarea",
1371
1681
  {
1372
1682
  "aria-label": "Optional feedback comment",
@@ -1377,8 +1687,8 @@ function AgentChatDefaultActions({
1377
1687
  value: comment
1378
1688
  }
1379
1689
  ),
1380
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "mt-3 flex items-center justify-between gap-2", children: [
1381
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1690
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mt-3 flex items-center justify-between gap-2", children: [
1691
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1382
1692
  "button",
1383
1693
  {
1384
1694
  className: "rounded-md px-3 py-2 text-sm font-medium hover:bg-muted",
@@ -1389,7 +1699,7 @@ function AgentChatDefaultActions({
1389
1699
  children: "Remove feedback"
1390
1700
  }
1391
1701
  ),
1392
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1702
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1393
1703
  "button",
1394
1704
  {
1395
1705
  className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90",
@@ -1408,24 +1718,24 @@ function AgentChatDefaultActions({
1408
1718
  )
1409
1719
  ] }) : null,
1410
1720
  additionalActions,
1411
- handlers.onCopy ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1721
+ handlers.onCopy ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1412
1722
  ChatMessageAction,
1413
1723
  {
1414
1724
  label: "Copy",
1415
1725
  onClick: copyMessage,
1416
1726
  tooltip: copied ? "Copied!" : "Copy to clipboard",
1417
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.Check, { className: "size-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.Copy, { className: "size-4" })
1727
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.Check, { className: "size-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react4.Copy, { className: "size-4" })
1418
1728
  }
1419
1729
  ) : null
1420
1730
  ] });
1421
1731
  }
1422
1732
 
1423
1733
  // src/ui/agent-chat-message.tsx
1424
- var React10 = __toESM(require("react"), 1);
1734
+ var React13 = __toESM(require("react"), 1);
1425
1735
  var import_lucide_react7 = require("lucide-react");
1426
1736
 
1427
1737
  // src/ui/agent-response-timeline.tsx
1428
- var React9 = __toESM(require("react"), 1);
1738
+ var React12 = __toESM(require("react"), 1);
1429
1739
 
1430
1740
  // src/streaming-text.ts
1431
1741
  var import_react = require("react");
@@ -1610,7 +1920,7 @@ function useStreamingText({
1610
1920
  }
1611
1921
 
1612
1922
  // src/ui/ask-user-interaction.tsx
1613
- var React6 = __toESM(require("react"), 1);
1923
+ var React9 = __toESM(require("react"), 1);
1614
1924
  var import_lucide_react5 = require("lucide-react");
1615
1925
 
1616
1926
  // src/ui/ask-user-interaction-state.ts
@@ -1667,7 +1977,7 @@ function askUserAnswersFromDrafts(questions, drafts) {
1667
1977
  }
1668
1978
 
1669
1979
  // src/ui/ask-user-interaction.tsx
1670
- var import_jsx_runtime6 = require("react/jsx-runtime");
1980
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1671
1981
  function resolvedAnswerText(question, answer) {
1672
1982
  if (!answer) return ["No response recorded"];
1673
1983
  const labels = answer.selectedOptionIds.flatMap((optionId) => {
@@ -1681,7 +1991,7 @@ function ResolvedQuestions({
1681
1991
  buttonRef,
1682
1992
  part
1683
1993
  }) {
1684
- const [open, setOpen] = React6.useState(false);
1994
+ const [open, setOpen] = React9.useState(false);
1685
1995
  const count = part.questions.length;
1686
1996
  const answers = new Map(
1687
1997
  (part.resolution?.answers || []).map((answer) => [
@@ -1689,8 +1999,8 @@ function ResolvedQuestions({
1689
1999
  answer
1690
2000
  ])
1691
2001
  );
1692
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "a24-ask-user a24-ask-user--resolved w-full", children: [
1693
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2002
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "a24-ask-user a24-ask-user--resolved w-full", children: [
2003
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1694
2004
  "button",
1695
2005
  {
1696
2006
  "aria-expanded": open,
@@ -1699,13 +2009,13 @@ function ResolvedQuestions({
1699
2009
  ref: buttonRef,
1700
2010
  type: "button",
1701
2011
  children: [
1702
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
2012
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1703
2013
  "Asked ",
1704
2014
  count,
1705
2015
  " question",
1706
2016
  count === 1 ? "" : "s"
1707
2017
  ] }),
1708
- open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.ChevronDown, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2018
+ open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react5.ChevronDown, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1709
2019
  import_lucide_react5.ChevronRight,
1710
2020
  {
1711
2021
  "aria-hidden": "true",
@@ -1715,12 +2025,12 @@ function ResolvedQuestions({
1715
2025
  ]
1716
2026
  }
1717
2027
  ),
1718
- open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mt-2 space-y-3 ps-4", children: part.questions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "min-w-0", children: [
1719
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm font-medium text-foreground", children: question.question }),
1720
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mt-1 space-y-1 text-sm text-muted-foreground", children: resolvedAnswerText(
2028
+ open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-2 space-y-3 ps-4", children: part.questions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "min-w-0", children: [
2029
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm font-medium text-foreground", children: question.question }),
2030
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-1 space-y-1 text-sm text-muted-foreground", children: resolvedAnswerText(
1721
2031
  question,
1722
2032
  answers.get(question.id)
1723
- ).map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2033
+ ).map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1724
2034
  "div",
1725
2035
  {
1726
2036
  className: "whitespace-pre-wrap break-words",
@@ -1738,23 +2048,23 @@ function AskUserInteraction({
1738
2048
  part
1739
2049
  }) {
1740
2050
  const questions = part.questions;
1741
- const [step, setStep] = React6.useState(0);
1742
- const [drafts, setDrafts] = React6.useState(
2051
+ const [step, setStep] = React9.useState(0);
2052
+ const [drafts, setDrafts] = React9.useState(
1743
2053
  () => emptyAskUserDrafts(questions)
1744
2054
  );
1745
- const headingRef = React6.useRef(null);
1746
- const questionsRef = React6.useRef(questions);
1747
- const resolvedButtonRef = React6.useRef(null);
1748
- const wasResolvedRef = React6.useRef(part.status !== "pending");
2055
+ const headingRef = React9.useRef(null);
2056
+ const questionsRef = React9.useRef(questions);
2057
+ const resolvedButtonRef = React9.useRef(null);
2058
+ const wasResolvedRef = React9.useRef(part.status !== "pending");
1749
2059
  questionsRef.current = questions;
1750
- React6.useEffect(() => {
2060
+ React9.useEffect(() => {
1751
2061
  setStep(0);
1752
2062
  setDrafts(emptyAskUserDrafts(questionsRef.current));
1753
2063
  }, [part.interruptId]);
1754
- React6.useEffect(() => {
2064
+ React9.useEffect(() => {
1755
2065
  headingRef.current?.focus();
1756
2066
  }, [step]);
1757
- React6.useEffect(() => {
2067
+ React9.useEffect(() => {
1758
2068
  const isResolved = part.status !== "pending";
1759
2069
  if (isResolved && !wasResolvedRef.current) {
1760
2070
  resolvedButtonRef.current?.focus();
@@ -1762,11 +2072,11 @@ function AskUserInteraction({
1762
2072
  wasResolvedRef.current = isResolved;
1763
2073
  }, [part.status]);
1764
2074
  if (part.status !== "pending") {
1765
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ResolvedQuestions, { buttonRef: resolvedButtonRef, part });
2075
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ResolvedQuestions, { buttonRef: resolvedButtonRef, part });
1766
2076
  }
1767
2077
  const question = questions[step];
1768
2078
  if (!question) {
1769
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm text-destructive", role: "alert", children: "This question request is unavailable." });
2079
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-destructive", role: "alert", children: "This question request is unavailable." });
1770
2080
  }
1771
2081
  const draft = drafts[question.id] || {
1772
2082
  customText: "",
@@ -1800,9 +2110,9 @@ function AskUserInteraction({
1800
2110
  })
1801
2111
  );
1802
2112
  };
1803
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "a24-ask-user space-y-3 rounded-xl border border-border/50 bg-background p-4 shadow-sm", children: [
1804
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex min-w-0 items-start justify-between gap-4", children: [
1805
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2113
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "a24-ask-user space-y-3 rounded-xl border border-border/50 bg-background p-4 shadow-sm", children: [
2114
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 items-start justify-between gap-4", children: [
2115
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1806
2116
  "h3",
1807
2117
  {
1808
2118
  className: "min-w-0 flex-1 text-base font-medium leading-6 text-foreground outline-none",
@@ -1811,8 +2121,8 @@ function AskUserInteraction({
1811
2121
  children: question.question
1812
2122
  }
1813
2123
  ),
1814
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: [
1815
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2124
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: [
2125
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1816
2126
  "button",
1817
2127
  {
1818
2128
  "aria-label": "Previous question",
@@ -1820,7 +2130,7 @@ function AskUserInteraction({
1820
2130
  disabled: isBusy || step === 0,
1821
2131
  onClick: () => setStep((current) => Math.max(0, current - 1)),
1822
2132
  type: "button",
1823
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2133
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1824
2134
  import_lucide_react5.ChevronLeft,
1825
2135
  {
1826
2136
  "aria-hidden": "true",
@@ -1829,7 +2139,7 @@ function AskUserInteraction({
1829
2139
  )
1830
2140
  }
1831
2141
  ),
1832
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2142
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1833
2143
  "span",
1834
2144
  {
1835
2145
  "aria-label": `Question ${step + 1} of ${questions.length}`,
@@ -1841,7 +2151,7 @@ function AskUserInteraction({
1841
2151
  ]
1842
2152
  }
1843
2153
  ),
1844
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2154
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1845
2155
  "button",
1846
2156
  {
1847
2157
  "aria-label": isLastQuestion ? "Submit answers" : "Next question",
@@ -1849,7 +2159,7 @@ function AskUserInteraction({
1849
2159
  disabled: isBusy || !onSubmit || !canMoveForward,
1850
2160
  onClick: () => completeStep(drafts),
1851
2161
  type: "button",
1852
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2162
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1853
2163
  import_lucide_react5.ChevronRight,
1854
2164
  {
1855
2165
  "aria-hidden": "true",
@@ -1860,10 +2170,10 @@ function AskUserInteraction({
1860
2170
  )
1861
2171
  ] })
1862
2172
  ] }),
1863
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-1", children: [
2173
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-1", children: [
1864
2174
  question.options.map((option, index) => {
1865
2175
  const selected = draft.selectedOptionIds.includes(option.id);
1866
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2176
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1867
2177
  "button",
1868
2178
  {
1869
2179
  "aria-pressed": selected,
@@ -1875,7 +2185,7 @@ function AskUserInteraction({
1875
2185
  onClick: () => selectOption(option.id),
1876
2186
  type: "button",
1877
2187
  children: [
1878
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2188
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1879
2189
  "span",
1880
2190
  {
1881
2191
  className: cn(
@@ -1885,8 +2195,8 @@ function AskUserInteraction({
1885
2195
  children: index + 1
1886
2196
  }
1887
2197
  ),
1888
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "min-w-0 flex-1 font-medium text-foreground", children: option.label }),
1889
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2198
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "min-w-0 flex-1 font-medium text-foreground", children: option.label }),
2199
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1890
2200
  import_lucide_react5.ChevronRight,
1891
2201
  {
1892
2202
  "aria-hidden": "true",
@@ -1898,9 +2208,9 @@ function AskUserInteraction({
1898
2208
  option.id
1899
2209
  );
1900
2210
  }),
1901
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("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: [
1902
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react5.Pencil, { "aria-hidden": "true", className: "size-4" }) }),
1903
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2211
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("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: [
2212
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("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__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react5.Pencil, { "aria-hidden": "true", className: "size-4" }) }),
2213
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1904
2214
  "input",
1905
2215
  {
1906
2216
  "aria-label": "Other response",
@@ -1919,7 +2229,7 @@ function AskUserInteraction({
1919
2229
  value: draft.customText
1920
2230
  }
1921
2231
  ),
1922
- draft.customText.trim() ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2232
+ draft.customText.trim() ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1923
2233
  "button",
1924
2234
  {
1925
2235
  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",
@@ -1931,12 +2241,12 @@ function AskUserInteraction({
1931
2241
  ) : null
1932
2242
  ] })
1933
2243
  ] }),
1934
- error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm text-destructive", role: "alert", children: error }) : null
2244
+ error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-destructive", role: "alert", children: error }) : null
1935
2245
  ] });
1936
2246
  }
1937
2247
 
1938
2248
  // src/ui/agent-chat-context-compression-row.tsx
1939
- var import_jsx_runtime7 = require("react/jsx-runtime");
2249
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1940
2250
  function compressionPresentation(part) {
1941
2251
  if (part.status === "failed") {
1942
2252
  return { label: "Could not compact message history", status: "failed" };
@@ -1951,7 +2261,7 @@ function AgentChatContextCompressionRow({
1951
2261
  part
1952
2262
  }) {
1953
2263
  const presentation = compressionPresentation(part);
1954
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2264
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1955
2265
  "div",
1956
2266
  {
1957
2267
  "aria-live": "polite",
@@ -1959,11 +2269,11 @@ function AgentChatContextCompressionRow({
1959
2269
  "data-agents24-context-compression": "",
1960
2270
  "data-status": part.status,
1961
2271
  role: "status",
1962
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cn(
2272
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn(
1963
2273
  "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--without-orb",
1964
2274
  presentation.status === "failed" && "a24-tool-trigger--error",
1965
2275
  presentation.status === "running" && "a24-tool-trigger--active"
1966
- ), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn(
2276
+ ), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: cn(
1967
2277
  "a24-tool-trigger__label",
1968
2278
  presentation.status === "running" && "a24-tool-shimmer"
1969
2279
  ), children: presentation.label }) }) })
@@ -1972,7 +2282,7 @@ function AgentChatContextCompressionRow({
1972
2282
  }
1973
2283
 
1974
2284
  // src/ui/message-response.tsx
1975
- var React7 = __toESM(require("react"), 1);
2285
+ var React10 = __toESM(require("react"), 1);
1976
2286
  var import_streamdown = require("streamdown");
1977
2287
 
1978
2288
  // src/active-content.ts
@@ -1997,17 +2307,17 @@ function safeChatMarkdownHref(value) {
1997
2307
  }
1998
2308
 
1999
2309
  // src/ui/message-response.tsx
2000
- var import_jsx_runtime8 = require("react/jsx-runtime");
2310
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2001
2311
  function SafeMarkdownLink({ children, href, ...props }) {
2002
2312
  const domProps = { ...props };
2003
2313
  delete domProps.node;
2004
2314
  const safeHref = safeChatMarkdownHref(href);
2005
- if (!safeHref) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children });
2006
- if (safeHref.startsWith("#")) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("a", { ...domProps, href: safeHref, children });
2007
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("a", { ...domProps, href: safeHref, rel: "noopener noreferrer", target: "_blank", children });
2315
+ if (!safeHref) return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children });
2316
+ if (safeHref.startsWith("#")) return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { ...domProps, href: safeHref, children });
2317
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { ...domProps, href: safeHref, rel: "noopener noreferrer", target: "_blank", children });
2008
2318
  }
2009
2319
  function BlockedMarkdownImage({ alt }) {
2010
- return alt ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-label": `Image blocked: ${alt}`, role: "img", children: alt }) : null;
2320
+ return alt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "aria-label": `Image blocked: ${alt}`, role: "img", children: alt }) : null;
2011
2321
  }
2012
2322
  var BLOCK_MARKDOWN_TAGS = /* @__PURE__ */ new Set([
2013
2323
  "blockquote",
@@ -2028,7 +2338,7 @@ function isMultilineCodeNode(node) {
2028
2338
  return node?.tagName === "code" && node.position?.start?.line !== void 0 && node.position?.end?.line !== void 0 && node.position.start.line !== node.position.end.line;
2029
2339
  }
2030
2340
  function hasBlockMarkdownChild(child) {
2031
- if (!React7.isValidElement(child)) {
2341
+ if (!React10.isValidElement(child)) {
2032
2342
  return false;
2033
2343
  }
2034
2344
  if (typeof child.type === "string" && BLOCK_MARKDOWN_TAGS.has(child.type)) {
@@ -2038,7 +2348,7 @@ function hasBlockMarkdownChild(child) {
2038
2348
  if (BLOCK_MARKDOWN_TAGS.has(props.node?.tagName || "") || isMultilineCodeNode(props.node)) {
2039
2349
  return true;
2040
2350
  }
2041
- return React7.Children.toArray(props.children).some(hasBlockMarkdownChild);
2351
+ return React10.Children.toArray(props.children).some(hasBlockMarkdownChild);
2042
2352
  }
2043
2353
  function MessageMarkdownParagraph({
2044
2354
  children,
@@ -2046,17 +2356,17 @@ function MessageMarkdownParagraph({
2046
2356
  }) {
2047
2357
  const domProps = { ...props };
2048
2358
  delete domProps.node;
2049
- const childArray = React7.Children.toArray(children).filter(
2359
+ const childArray = React10.Children.toArray(children).filter(
2050
2360
  (child) => child !== null && child !== ""
2051
2361
  );
2052
- const isImageOnly = childArray.length === 1 && React7.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
2362
+ const isImageOnly = childArray.length === 1 && React10.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
2053
2363
  if (isImageOnly) {
2054
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children });
2364
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
2055
2365
  }
2056
2366
  if (childArray.some(hasBlockMarkdownChild)) {
2057
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ...domProps, children });
2367
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ...domProps, children });
2058
2368
  }
2059
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { ...domProps, children });
2369
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { ...domProps, children });
2060
2370
  }
2061
2371
  var MESSAGE_RESPONSE_COMPONENTS = {
2062
2372
  a: SafeMarkdownLink,
@@ -2076,7 +2386,7 @@ var MESSAGE_RESPONSE_REHYPE_PLUGINS = [
2076
2386
  ]
2077
2387
  ] : []
2078
2388
  ];
2079
- var MessageResponse = React7.memo(
2389
+ var MessageResponse = React10.memo(
2080
2390
  ({
2081
2391
  children,
2082
2392
  className,
@@ -2094,11 +2404,11 @@ var MessageResponse = React7.memo(
2094
2404
  maxCatchupChars: 32,
2095
2405
  text
2096
2406
  });
2097
- const streamdownComponents = React7.useMemo(
2407
+ const streamdownComponents = React10.useMemo(
2098
2408
  () => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
2099
2409
  [components]
2100
2410
  );
2101
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2411
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2102
2412
  import_streamdown.Streamdown,
2103
2413
  {
2104
2414
  className: cn("a24-message-response", className),
@@ -2150,10 +2460,10 @@ function resolvedHitlLabel(part) {
2150
2460
  }
2151
2461
 
2152
2462
  // src/ui/tool-sessions.tsx
2153
- var React8 = __toESM(require("react"), 1);
2463
+ var React11 = __toESM(require("react"), 1);
2154
2464
  var import_lucide_react6 = require("lucide-react");
2155
2465
  var import_thinking_orbs = require("thinking-orbs");
2156
- var import_jsx_runtime9 = require("react/jsx-runtime");
2466
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2157
2467
  function toolSlotContext(isActive2, label, part, slots) {
2158
2468
  return {
2159
2469
  isActive: isActive2,
@@ -2171,7 +2481,7 @@ function ToolResourceAction({ context }) {
2171
2481
  const target = context.resourceTargets[0];
2172
2482
  if (!target) return null;
2173
2483
  const name = resourceTargetName(target);
2174
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2484
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2175
2485
  "button",
2176
2486
  {
2177
2487
  "aria-label": `Open ${target.kind} ${target.path}`,
@@ -2185,8 +2495,8 @@ function ToolResourceAction({ context }) {
2185
2495
  );
2186
2496
  }
2187
2497
  function toolAccessory(context, slots) {
2188
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2189
- slots?.onResourceAction ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolResourceAction, { context }) : null,
2498
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2499
+ slots?.onResourceAction ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolResourceAction, { context }) : null,
2190
2500
  slots?.renderToolAccessory?.(context)
2191
2501
  ] });
2192
2502
  }
@@ -2263,12 +2573,12 @@ function ToolActivityReel({
2263
2573
  }) {
2264
2574
  const initial = initialLabel && initialLabel !== label ? initialLabel : label;
2265
2575
  const parsedInitialShownAt = initialShownAt ? Date.parse(initialShownAt) : Number.NaN;
2266
- const [displayed, setDisplayed] = React8.useState(initial);
2267
- const [previous, setPrevious] = React8.useState(null);
2268
- const displayedRef = React8.useRef(initial);
2269
- const latestRef = React8.useRef(label);
2270
- const shownAtRef = React8.useRef(Number.isFinite(parsedInitialShownAt) ? parsedInitialShownAt : Date.now());
2271
- React8.useEffect(() => {
2576
+ const [displayed, setDisplayed] = React11.useState(initial);
2577
+ const [previous, setPrevious] = React11.useState(null);
2578
+ const displayedRef = React11.useRef(initial);
2579
+ const latestRef = React11.useRef(label);
2580
+ const shownAtRef = React11.useRef(Number.isFinite(parsedInitialShownAt) ? parsedInitialShownAt : Date.now());
2581
+ React11.useEffect(() => {
2272
2582
  latestRef.current = label;
2273
2583
  if (displayedRef.current === label) return;
2274
2584
  const showLatest = () => {
@@ -2288,39 +2598,39 @@ function ToolActivityReel({
2288
2598
  const timer = window.setTimeout(showLatest, remaining);
2289
2599
  return () => window.clearTimeout(timer);
2290
2600
  }, [label]);
2291
- React8.useEffect(() => {
2601
+ React11.useEffect(() => {
2292
2602
  if (!previous) return;
2293
2603
  const timer = window.setTimeout(() => setPrevious(null), 200);
2294
2604
  return () => window.clearTimeout(timer);
2295
2605
  }, [previous]);
2296
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "a24-tool-reel", "aria-live": announce ? "polite" : "off", children: [
2297
- previous ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "aria-hidden": "true", className: "a24-tool-reel__previous", children: previous }) : null,
2298
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: previous ? "a24-tool-reel__current" : void 0, children: displayed })
2606
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "a24-tool-reel", "aria-live": announce ? "polite" : "off", children: [
2607
+ previous ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { "aria-hidden": "true", className: "a24-tool-reel__previous", children: previous }) : null,
2608
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: previous ? "a24-tool-reel__current" : void 0, children: displayed })
2299
2609
  ] });
2300
2610
  }
2301
2611
  function ToolActivityOrb({ label }) {
2302
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-orb", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_thinking_orbs.ThinkingOrb, { "aria-label": label || "Working", size: 20, speed: 0.8, state: "searching" }) });
2612
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-orb", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_thinking_orbs.ThinkingOrb, { "aria-label": label || "Working", size: 20, speed: 0.8, state: "searching" }) });
2303
2613
  }
2304
2614
  function AgentChatActivityRow({
2305
2615
  label,
2306
2616
  modelTurnId,
2307
2617
  onSelect
2308
2618
  }) {
2309
- const content = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2310
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityOrb, { label }),
2311
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-trigger__label a24-tool-shimmer", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityReel, { label }) })
2619
+ const content = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2620
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityOrb, { label }),
2621
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-trigger__label a24-tool-shimmer", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityReel, { label }) })
2312
2622
  ] });
2313
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-trigger-row a24-tool-trigger-row--root", "data-agents24-model-turn": modelTurnId, role: "status", children: onSelect ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", onClick: onSelect, type: "button", children: content }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", children: content }) });
2623
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-trigger-row a24-tool-trigger-row--root", "data-agents24-model-turn": modelTurnId, role: "status", children: onSelect ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", onClick: onSelect, type: "button", children: content }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", children: content }) });
2314
2624
  }
2315
2625
  function AgentChatModelTurnRow({ part }) {
2316
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId });
2626
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId });
2317
2627
  }
2318
2628
  function AgentChatNodeActivityRow({
2319
2629
  onSelect,
2320
2630
  part
2321
2631
  }) {
2322
- const [open, setOpen] = React8.useState(false);
2323
- const contentId = React8.useId();
2632
+ const [open, setOpen] = React11.useState(false);
2633
+ const contentId = React11.useId();
2324
2634
  const running = part.status === "running";
2325
2635
  const failed = part.status === "failed";
2326
2636
  const failureMessage = part.failure?.message || "The node could not complete the request.";
@@ -2331,18 +2641,18 @@ function AgentChatNodeActivityRow({
2331
2641
  running && "a24-tool-trigger--active",
2332
2642
  failed && "a24-tool-trigger--error"
2333
2643
  );
2334
- const label = running ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-shimmer", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityReel, { label: part.label }) }) : part.label;
2644
+ const label = running ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-shimmer", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityReel, { label: part.label }) }) : part.label;
2335
2645
  if (!failed) {
2336
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-trigger-row", role: "status", children: onSelect ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2337
- running ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityOrb, { label: part.label }) : null,
2338
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2339
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: triggerClassName, children: [
2340
- running ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityOrb, { label: part.label }) : null,
2341
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2646
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-trigger-row", role: "status", children: onSelect ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2647
+ running ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityOrb, { label: part.label }) : null,
2648
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2649
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: triggerClassName, children: [
2650
+ running ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityOrb, { label: part.label }) : null,
2651
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2342
2652
  ] }) });
2343
2653
  }
2344
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "a24-tool-disclosure", children: [
2345
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2654
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "a24-tool-disclosure", children: [
2655
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2346
2656
  "button",
2347
2657
  {
2348
2658
  "aria-controls": contentId,
@@ -2354,12 +2664,12 @@ function AgentChatNodeActivityRow({
2354
2664
  },
2355
2665
  type: "button",
2356
2666
  children: [
2357
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-trigger__label", children: label }),
2358
- open ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react6.ChevronDown, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react6.ChevronRight, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2667
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-trigger__label", children: label }),
2668
+ open ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.ChevronDown, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.ChevronRight, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2359
2669
  ]
2360
2670
  }
2361
2671
  ) }),
2362
- open ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-detail a24-tool-detail--error", id: contentId, children: failureMessage }) : null
2672
+ open ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-detail a24-tool-detail--error", id: contentId, children: failureMessage }) : null
2363
2673
  ] });
2364
2674
  }
2365
2675
  function toolRowLabel(part, separateResource = false) {
@@ -2385,25 +2695,25 @@ function ToolDisclosure({
2385
2695
  statusLabel,
2386
2696
  accessory
2387
2697
  }) {
2388
- const [open, setOpen] = React8.useState(false);
2389
- const contentId = React8.useId();
2390
- const expandable = React8.Children.toArray(children).length > 0;
2698
+ const [open, setOpen] = React11.useState(false);
2699
+ const contentId = React11.useId();
2700
+ const expandable = React11.Children.toArray(children).length > 0;
2391
2701
  if (!expandable) {
2392
2702
  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");
2393
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2394
- onSelect && part ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2395
- showOrb ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
2396
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2397
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: triggerClassName, children: [
2398
- showOrb ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
2399
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2703
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2704
+ onSelect && part ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2705
+ showOrb ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
2706
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2707
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: triggerClassName, children: [
2708
+ showOrb ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
2709
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-trigger__label", children: label })
2400
2710
  ] }),
2401
2711
  accessory
2402
2712
  ] });
2403
2713
  }
2404
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "a24-tool-disclosure", children: [
2405
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2406
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2714
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "a24-tool-disclosure", children: [
2715
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2716
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2407
2717
  "button",
2408
2718
  {
2409
2719
  "aria-controls": contentId,
@@ -2417,25 +2727,25 @@ function ToolDisclosure({
2417
2727
  },
2418
2728
  type: "button",
2419
2729
  children: [
2420
- showOrb ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
2421
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-trigger__label", children: label }),
2422
- open ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react6.ChevronDown, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react6.ChevronRight, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2730
+ showOrb ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityOrb, { label: statusLabel }) : null,
2731
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-trigger__label", children: label }),
2732
+ open ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.ChevronDown, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react6.ChevronRight, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2423
2733
  ]
2424
2734
  }
2425
2735
  ),
2426
2736
  accessory
2427
2737
  ] }),
2428
- open ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-disclosure__content", id: contentId, children }) : null
2738
+ open ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-disclosure__content", id: contentId, children }) : null
2429
2739
  ] });
2430
2740
  }
2431
2741
  function ToolLabel({ active, label, part, slots }) {
2432
2742
  const rendered = slots?.renderToolLabel?.(toolSlotContext(active, label, part, slots)) ?? label;
2433
- return active ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-tool-shimmer", children: rendered }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: rendered });
2743
+ return active ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-tool-shimmer", children: rendered }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: rendered });
2434
2744
  }
2435
2745
  function ToolList({ children }) {
2436
- const listRef = React8.useRef(null);
2437
- const [fades, setFades] = React8.useState({ bottom: false, top: false });
2438
- const updateFades = React8.useCallback(() => {
2746
+ const listRef = React11.useRef(null);
2747
+ const [fades, setFades] = React11.useState({ bottom: false, top: false });
2748
+ const updateFades = React11.useCallback(() => {
2439
2749
  const list = listRef.current;
2440
2750
  if (!list) return;
2441
2751
  const next = {
@@ -2444,7 +2754,7 @@ function ToolList({ children }) {
2444
2754
  };
2445
2755
  setFades((current) => current.bottom === next.bottom && current.top === next.top ? current : next);
2446
2756
  }, []);
2447
- React8.useEffect(() => {
2757
+ React11.useEffect(() => {
2448
2758
  updateFades();
2449
2759
  const list = listRef.current;
2450
2760
  if (!list || typeof ResizeObserver === "undefined") return;
@@ -2452,13 +2762,13 @@ function ToolList({ children }) {
2452
2762
  observer.observe(list);
2453
2763
  return () => observer.disconnect();
2454
2764
  }, [children, updateFades]);
2455
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2765
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2456
2766
  "div",
2457
2767
  {
2458
2768
  className: "a24-tool-list-frame",
2459
2769
  "data-scroll-fade-bottom": fades.bottom ? "" : void 0,
2460
2770
  "data-scroll-fade-top": fades.top ? "" : void 0,
2461
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-list", onScroll: updateFades, ref: listRef, role: "list", children })
2771
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-list", onScroll: updateFades, ref: listRef, role: "list", children })
2462
2772
  }
2463
2773
  );
2464
2774
  }
@@ -2475,12 +2785,12 @@ function AgentChatToolRow({
2475
2785
  const detail = failed ? failureMessage : optionalText(part.presentation.detail);
2476
2786
  const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
2477
2787
  const context = toolSlotContext(active, toolRowLabel(part, Boolean(slots?.onResourceAction)), part, slots);
2478
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2788
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2479
2789
  ToolDisclosure,
2480
2790
  {
2481
2791
  error: failed,
2482
2792
  accessory: toolAccessory(context, slots),
2483
- label: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolLabel, { active, label: context.label, part, slots }),
2793
+ label: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolLabel, { active, label: context.label, part, slots }),
2484
2794
  loading: active,
2485
2795
  onExpandedChange: slots?.onExpandedChange,
2486
2796
  onSelect: slots?.onToolSelect,
@@ -2489,7 +2799,7 @@ function AgentChatToolRow({
2489
2799
  showOrb: showOrb ?? active,
2490
2800
  statusLabel: active ? context.label : void 0,
2491
2801
  children: [
2492
- detail ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: cn("a24-tool-detail", failed && "a24-tool-detail--error"), children: detail }) : null,
2802
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: cn("a24-tool-detail", failed && "a24-tool-detail--error"), children: detail }) : null,
2493
2803
  hostDetails
2494
2804
  ]
2495
2805
  }
@@ -2509,19 +2819,19 @@ function AgentChatToolSession({
2509
2819
  parts,
2510
2820
  slots
2511
2821
  }) {
2512
- const presentedLiveRef = React8.useRef(false);
2822
+ const presentedLiveRef = React11.useRef(false);
2513
2823
  if (isLive && isLatestActivity) presentedLiveRef.current = true;
2514
2824
  const activeIndex = parts.findLastIndex((part) => isActive(part, activeToolId));
2515
2825
  const running = activeIndex >= 0;
2516
- if (parts.length === 1 && !modelTurn && !leadingModelTurn) return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatToolRow, { activeToolId, part: parts[0], slots });
2826
+ if (parts.length === 1 && !modelTurn && !leadingModelTurn) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatToolRow, { activeToolId, part: parts[0], slots });
2517
2827
  const visibleIndex = running ? activeIndex : parts.length - 1;
2518
2828
  const visiblePart = parts[visibleIndex];
2519
2829
  const planning = Boolean(modelTurn);
2520
2830
  const presentingActivity = isLatestActivity && (planning || running || isLive);
2521
2831
  const failed = isLatestActivity && (visiblePart.state === "output-error" || visiblePart.state === "cancelled");
2522
2832
  const label = planning ? "Planning next moves" : isLive && isLatestActivity ? toolRowLabel(visiblePart, true) : sessionLabel(parts, visiblePart, running);
2523
- const labelContent = presentedLiveRef.current ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityReel, { initialLabel: leadingModelTurn ? "Planning next moves" : void 0, initialShownAt: leadingModelTurn?.timestamp, label }) }) : label;
2524
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2833
+ const labelContent = presentedLiveRef.current ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityReel, { initialLabel: leadingModelTurn ? "Planning next moves" : void 0, initialShownAt: leadingModelTurn?.timestamp, label }) }) : label;
2834
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2525
2835
  ToolDisclosure,
2526
2836
  {
2527
2837
  error: failed,
@@ -2533,7 +2843,7 @@ function AgentChatToolSession({
2533
2843
  root: true,
2534
2844
  showOrb: isLive && isLatestActivity,
2535
2845
  statusLabel: planning ? "Planning next moves" : label,
2536
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolList, { children: parts.map((part) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { role: "listitem", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentChatToolRow, { activeToolId, part, root: false, showOrb: false, slots }) }, part.id)) })
2846
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolList, { children: parts.map((part) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "listitem", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatToolRow, { activeToolId, part, root: false, showOrb: false, slots }) }, part.id)) })
2537
2847
  }
2538
2848
  );
2539
2849
  }
@@ -2554,7 +2864,7 @@ function subagentLabel(part) {
2554
2864
  return { label: `Agent ${name}, ran ${children.length} ${children.length === 1 ? "tool" : "tools"}`, running: false };
2555
2865
  }
2556
2866
  function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part, slots }) {
2557
- const presentedLiveRef = React8.useRef(false);
2867
+ const presentedLiveRef = React11.useRef(false);
2558
2868
  if (isLive && isLatestActivity) presentedLiveRef.current = true;
2559
2869
  const children = part.presentation.childTools || [];
2560
2870
  const state = subagentLabel(part);
@@ -2563,9 +2873,9 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2563
2873
  const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
2564
2874
  const failureMessage = part.failure?.message || null;
2565
2875
  const presentingActivity = isLatestActivity && state.running;
2566
- const labelContent = presentedLiveRef.current ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolActivityReel, { label: state.label }) }) : state.label;
2876
+ const labelContent = presentedLiveRef.current ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolActivityReel, { label: state.label }) }) : state.label;
2567
2877
  const context = toolSlotContext(presentingActivity, state.label, part, slots);
2568
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2878
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2569
2879
  ToolDisclosure,
2570
2880
  {
2571
2881
  accessory: slots?.renderToolAccessory?.(context),
@@ -2578,12 +2888,12 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2578
2888
  root: true,
2579
2889
  showOrb: isLive && isLatestActivity,
2580
2890
  statusLabel: state.label,
2581
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(ToolList, { children: [
2582
- children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: cn("a24-child-tool", child.status === "failed" && "a24-child-tool--error"), role: "listitem", children: slots?.renderChildTool?.(child, part) ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2583
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: cn(isLive && isLatestActivity && child.status === "running" && "a24-tool-shimmer"), children: childLabel(child) }),
2584
- child.detail ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "a24-child-tool__detail", children: child.detail }) : null
2891
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ToolList, { children: [
2892
+ children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: cn("a24-child-tool", child.status === "failed" && "a24-child-tool--error"), role: "listitem", children: slots?.renderChildTool?.(child, part) ?? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2893
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn(isLive && isLatestActivity && child.status === "running" && "a24-tool-shimmer"), children: childLabel(child) }),
2894
+ child.detail ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-child-tool__detail", children: child.detail }) : null
2585
2895
  ] }) }, child.id)),
2586
- failureMessage ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "a24-tool-detail a24-tool-detail--error", children: failureMessage }) : null,
2896
+ failureMessage ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-tool-detail a24-tool-detail--error", children: failureMessage }) : null,
2587
2897
  hostDetails
2588
2898
  ] })
2589
2899
  }
@@ -2591,24 +2901,24 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2591
2901
  }
2592
2902
 
2593
2903
  // src/ui/agent-response-timeline.tsx
2594
- var import_jsx_runtime10 = require("react/jsx-runtime");
2904
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2595
2905
  function isInternalAskUserTool(part) {
2596
2906
  return [part.toolName, part.toolKey, part.action].some((value) => value?.trim().toLowerCase() === "runtime__ask_user");
2597
2907
  }
2598
2908
  function Shimmer({ children, className }) {
2599
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn("inline-block animate-pulse", className), children });
2909
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: cn("inline-block animate-pulse", className), children });
2600
2910
  }
2601
2911
  function AgentChatToolPart({
2602
2912
  activeToolId,
2603
2913
  part
2604
2914
  }) {
2605
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatToolRow, { activeToolId, part });
2915
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatToolRow, { activeToolId, part });
2606
2916
  }
2607
2917
  function AgentChatToolGroup({
2608
2918
  activeToolId,
2609
2919
  parts
2610
2920
  }) {
2611
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatToolSession, { activeToolId, parts });
2921
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatToolSession, { activeToolId, parts });
2612
2922
  }
2613
2923
  function HitlPartRow({
2614
2924
  getHitlActionState,
@@ -2617,18 +2927,18 @@ function HitlPartRow({
2617
2927
  part
2618
2928
  }) {
2619
2929
  const state = getHitlActionState?.(part);
2620
- const [comment, setComment] = React9.useState("");
2930
+ const [comment, setComment] = React12.useState("");
2621
2931
  const presentation = part.presentation || {};
2622
2932
  const requireComment = presentation.require_comment === true;
2623
2933
  const isTerminal = part.status !== "pending";
2624
- const resolvedRef = React9.useRef(null);
2625
- const wasTerminal = React9.useRef(isTerminal);
2626
- React9.useEffect(() => {
2934
+ const resolvedRef = React12.useRef(null);
2935
+ const wasTerminal = React12.useRef(isTerminal);
2936
+ React12.useEffect(() => {
2627
2937
  if (isTerminal && !wasTerminal.current) resolvedRef.current?.focus();
2628
2938
  wasTerminal.current = isTerminal;
2629
2939
  }, [isTerminal]);
2630
2940
  if (part.hitlKind === "user_input") {
2631
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2941
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2632
2942
  AskUserInteraction,
2633
2943
  {
2634
2944
  error: state?.error,
@@ -2646,11 +2956,11 @@ function HitlPartRow({
2646
2956
  );
2647
2957
  }
2648
2958
  if (isTerminal) {
2649
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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) });
2959
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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) });
2650
2960
  }
2651
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "a24-hitl space-y-2.5 px-1 py-2", children: [
2652
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-hitl__title text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
2653
- requireComment ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2961
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "a24-hitl space-y-2.5 px-1 py-2", children: [
2962
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-hitl__title text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
2963
+ requireComment ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2654
2964
  "textarea",
2655
2965
  {
2656
2966
  "aria-label": "Approval comment",
@@ -2662,8 +2972,8 @@ function HitlPartRow({
2662
2972
  value: comment
2663
2973
  }
2664
2974
  ) : null,
2665
- state?.error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-hitl__error text-sm text-destructive", children: state.error }) : null,
2666
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-hitl__actions flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2975
+ state?.error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-hitl__error text-sm text-destructive", children: state.error }) : null,
2976
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-hitl__actions flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2667
2977
  "button",
2668
2978
  {
2669
2979
  "aria-label": hitlActionLabel(part, action),
@@ -2696,7 +3006,7 @@ function AgentChatPart({
2696
3006
  toolSlots
2697
3007
  }) {
2698
3008
  if (part.kind === "text") {
2699
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3009
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2700
3010
  MessageResponse,
2701
3011
  {
2702
3012
  ...responseProps,
@@ -2706,23 +3016,23 @@ function AgentChatPart({
2706
3016
  }
2707
3017
  );
2708
3018
  }
2709
- if (part.kind === "tool") return isAgentChatSubagent(part) ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatSubagentGroup, { part, slots: toolSlots }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatToolRow, { activeToolId, part, slots: toolSlots });
2710
- if (part.kind === "model-turn") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatModelTurnRow, { part });
3019
+ if (part.kind === "tool") return isAgentChatSubagent(part) ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatSubagentGroup, { part, slots: toolSlots }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatToolRow, { activeToolId, part, slots: toolSlots });
3020
+ if (part.kind === "model-turn") return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatModelTurnRow, { part });
2711
3021
  if (part.kind === "reasoning") {
2712
3022
  const label = part.text || part.label || "Thinking";
2713
- return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-sm text-muted-foreground", children: label });
3023
+ return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "text-sm text-muted-foreground", children: label });
2714
3024
  }
2715
3025
  if (part.kind === "context-compression") {
2716
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatContextCompressionRow, { part });
3026
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatContextCompressionRow, { part });
2717
3027
  }
2718
3028
  if (part.kind === "ui-blocks") {
2719
3029
  if (part.state === "output-error") {
2720
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-timeline-error text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
3030
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-timeline-error text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
2721
3031
  }
2722
- return part.bundle ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SafeUiBlocks, { bundle: part.bundle }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-sm text-muted-foreground", children: part.state === "input-streaming" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Shimmer, { children: "Rendering UI block" }) : "Rendered UI block" });
3032
+ return part.bundle ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SafeUiBlocks, { bundle: part.bundle }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "text-sm text-muted-foreground", children: part.state === "input-streaming" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Shimmer, { children: "Rendering UI block" }) : "Rendered UI block" });
2723
3033
  }
2724
3034
  if (part.kind === "hitl") {
2725
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3035
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2726
3036
  HitlPartRow,
2727
3037
  {
2728
3038
  getHitlActionState,
@@ -2732,18 +3042,18 @@ function AgentChatPart({
2732
3042
  }
2733
3043
  );
2734
3044
  }
2735
- if (part.kind === "error") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-timeline-error text-sm text-destructive", role: "alert", children: part.errorText });
3045
+ if (part.kind === "error") return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-timeline-error text-sm text-destructive", role: "alert", children: part.errorText });
2736
3046
  if (part.kind === "source") {
2737
3047
  const href = safeExternalUrl(part.url);
2738
- return href ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { className: "a24-source-link", href, rel: "noopener noreferrer", target: "_blank", children: part.title }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-source-link", children: part.title });
3048
+ return href ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { className: "a24-source-link", href, rel: "noopener noreferrer", target: "_blank", children: part.title }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "a24-source-link", children: part.title });
2739
3049
  }
2740
3050
  if (part.kind === "citation") {
2741
3051
  const href = safeExternalUrl(part.url);
2742
3052
  const label = part.label || "Citation";
2743
- return href ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { className: "a24-citation", href, rel: "noopener noreferrer", target: "_blank", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "a24-citation", children: label });
3053
+ return href ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { className: "a24-citation", href, rel: "noopener noreferrer", target: "_blank", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "a24-citation", children: label });
2744
3054
  }
2745
- if (part.kind === "attachment") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-output-attachment", children: part.attachment.filename || "Attachment" });
2746
- if (part.kind === "data") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
3055
+ if (part.kind === "attachment") return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-output-attachment", children: part.attachment.filename || "Attachment" });
3056
+ if (part.kind === "data") return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
2747
3057
  return null;
2748
3058
  }
2749
3059
  function safeExternalUrl(value) {
@@ -2757,28 +3067,28 @@ function safeExternalUrl(value) {
2757
3067
  }
2758
3068
  function SafeUiBlocks({ bundle }) {
2759
3069
  const rows = Array.isArray(bundle.rows) ? bundle.rows : [];
2760
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { "aria-label": typeof bundle.title === "string" ? bundle.title : "Agent result", className: "a24-ui-blocks", children: [
2761
- typeof bundle.title === "string" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { children: bundle.title }) : null,
3070
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { "aria-label": typeof bundle.title === "string" ? bundle.title : "Agent result", className: "a24-ui-blocks", children: [
3071
+ typeof bundle.title === "string" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { children: bundle.title }) : null,
2762
3072
  rows.map((rawRow, rowIndex) => {
2763
3073
  const row = rawRow && typeof rawRow === "object" && !Array.isArray(rawRow) ? rawRow : {};
2764
3074
  const blocks = Array.isArray(row.blocks) ? row.blocks : [];
2765
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-ui-blocks__row", children: blocks.map((rawBlock, blockIndex) => {
3075
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-ui-blocks__row", children: blocks.map((rawBlock, blockIndex) => {
2766
3076
  const block = rawBlock && typeof rawBlock === "object" && !Array.isArray(rawBlock) ? rawBlock : {};
2767
3077
  const title = typeof block.title === "string" ? block.title : "Result";
2768
3078
  const kind = String(block.kind || "note");
2769
3079
  if (kind === "table" && Array.isArray(block.columns) && Array.isArray(block.rows)) {
2770
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "a24-ui-block", children: [
2771
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h4", { children: title }),
2772
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "a24-ui-table-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { children: [
2773
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: block.columns.map((column, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { children: String(column) }, index)) }) }),
2774
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: block.rows.map((rawCells, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: (Array.isArray(rawCells) ? rawCells : []).map((cell, cellIndex) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { children: String(cell) }, cellIndex)) }, index)) })
3080
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "a24-ui-block", children: [
3081
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h4", { children: title }),
3082
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "a24-ui-table-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { children: [
3083
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tr", { children: block.columns.map((column, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { children: String(column) }, index)) }) }),
3084
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: block.rows.map((rawCells, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tr", { children: (Array.isArray(rawCells) ? rawCells : []).map((cell, cellIndex) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { children: String(cell) }, cellIndex)) }, index)) })
2775
3085
  ] }) })
2776
3086
  ] }, String(block.id || blockIndex));
2777
3087
  }
2778
3088
  const value = block.value ?? block.text ?? "";
2779
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "a24-ui-block", children: [
2780
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h4", { children: title }),
2781
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { children: String(value) })
3089
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "a24-ui-block", children: [
3090
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h4", { children: title }),
3091
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { children: String(value) })
2782
3092
  ] }, String(block.id || blockIndex));
2783
3093
  }) }, `row-${rowIndex}`);
2784
3094
  })
@@ -2812,38 +3122,38 @@ function AgentResponseTimeline({
2812
3122
  if (segment.kind === "tool") {
2813
3123
  const isLatestActivity = segmentIndex === segments.length - 1;
2814
3124
  const showOrb = toolViewMode === "closed" ? isLoading && isLatestActivity : Boolean(activeToolId && (segment.part.id === activeToolId || segment.part.toolCallId === activeToolId));
2815
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatToolRow, { activeToolId, part: segment.part, showOrb, slots: toolSlots }, segment.part.id));
3125
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatToolRow, { activeToolId, part: segment.part, showOrb, slots: toolSlots }, segment.part.id));
2816
3126
  continue;
2817
3127
  }
2818
3128
  if (segment.kind === "tool-session") {
2819
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(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}`));
3129
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(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}`));
2820
3130
  continue;
2821
3131
  }
2822
3132
  if (segment.kind === "subagent") {
2823
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatSubagentGroup, { isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, part: segment.part, slots: toolSlots }, segment.part.id));
3133
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatSubagentGroup, { isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, part: segment.part, slots: toolSlots }, segment.part.id));
2824
3134
  continue;
2825
3135
  }
2826
3136
  const part = segment.part;
2827
3137
  if (part.kind === "model-turn") {
2828
3138
  const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
2829
3139
  activeActivityClaimed = true;
2830
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId }, key));
3140
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId }, key));
2831
3141
  continue;
2832
3142
  }
2833
3143
  if (part.kind === "node-activity") {
2834
3144
  const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
2835
3145
  if (part.status === "running") activeActivityClaimed = true;
2836
3146
  rendered.push(
2837
- part.status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatActivityRow, { label: part.label, onSelect: onNodeSelect ? () => onNodeSelect(part) : void 0 }, key) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatNodeActivityRow, { onSelect: onNodeSelect, part }, part.id)
3147
+ part.status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatActivityRow, { label: part.label, onSelect: onNodeSelect ? () => onNodeSelect(part) : void 0 }, key) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatNodeActivityRow, { onSelect: onNodeSelect, part }, part.id)
2838
3148
  );
2839
3149
  continue;
2840
3150
  }
2841
3151
  if (part.kind === "ui-blocks" && renderUiBlocks) {
2842
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(React9.Fragment, { children: renderUiBlocks(part) }, part.id));
3152
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(React12.Fragment, { children: renderUiBlocks(part) }, part.id));
2843
3153
  continue;
2844
3154
  }
2845
3155
  rendered.push(
2846
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(React9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3156
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(React12.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2847
3157
  AgentChatPart,
2848
3158
  {
2849
3159
  activeToolId,
@@ -2860,16 +3170,16 @@ function AgentResponseTimeline({
2860
3170
  );
2861
3171
  }
2862
3172
  if (rendered.length === 0 && message.content) {
2863
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageResponse, { children: message.content }, `${message.id}-fallback`));
3173
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MessageResponse, { children: message.content }, `${message.id}-fallback`));
2864
3174
  }
2865
3175
  if (rendered.length === 0 && isLoading) {
2866
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentChatActivityRow, { label: "Thinking" }, `${message.id}-active-activity`));
3176
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatActivityRow, { label: "Thinking" }, `${message.id}-active-activity`));
2867
3177
  }
2868
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "space-y-3", children: rendered });
3178
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-3", children: rendered });
2869
3179
  }
2870
3180
 
2871
3181
  // src/ui/agent-chat-message.tsx
2872
- var import_jsx_runtime11 = require("react/jsx-runtime");
3182
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2873
3183
  var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
2874
3184
  var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
2875
3185
  function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
@@ -2882,8 +3192,8 @@ function AgentChatUserMessageContent({
2882
3192
  showLessLabel = "Show less",
2883
3193
  showMoreLabel = "Show more"
2884
3194
  }) {
2885
- const [isExpanded, setIsExpanded] = React10.useState(false);
2886
- const contentId = React10.useId();
3195
+ const [isExpanded, setIsExpanded] = React13.useState(false);
3196
+ const contentId = React13.useId();
2887
3197
  const shouldCollapse = shouldCollapseUserMessage(content, collapseThreshold);
2888
3198
  const Icon = isExpanded ? import_lucide_react7.ChevronUp : import_lucide_react7.ChevronDown;
2889
3199
  const clampedStyle = shouldCollapse && !isExpanded ? {
@@ -2892,9 +3202,9 @@ function AgentChatUserMessageContent({
2892
3202
  display: "-webkit-box",
2893
3203
  overflow: "hidden"
2894
3204
  } : void 0;
2895
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [
2896
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
2897
- shouldCollapse ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3205
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [
3206
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
3207
+ shouldCollapse ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2898
3208
  "button",
2899
3209
  {
2900
3210
  "aria-controls": contentId,
@@ -2907,7 +3217,7 @@ function AgentChatUserMessageContent({
2907
3217
  type: "button",
2908
3218
  children: [
2909
3219
  isExpanded ? showLessLabel : showMoreLabel,
2910
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
3220
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
2911
3221
  ]
2912
3222
  }
2913
3223
  ) : null
@@ -2917,9 +3227,9 @@ function AgentChatUserMessageActionRow({
2917
3227
  children,
2918
3228
  className
2919
3229
  }) {
2920
- const rowRef = React10.useRef(null);
2921
- const [visible, setVisible] = React10.useState(false);
2922
- React10.useEffect(() => {
3230
+ const rowRef = React13.useRef(null);
3231
+ const [visible, setVisible] = React13.useState(false);
3232
+ React13.useEffect(() => {
2923
3233
  const message = rowRef.current?.closest('[data-slot="message"]');
2924
3234
  if (!message) return;
2925
3235
  const show = () => setVisible(true);
@@ -2938,7 +3248,7 @@ function AgentChatUserMessageActionRow({
2938
3248
  message.removeEventListener("focusout", hideWhenFocusLeaves);
2939
3249
  };
2940
3250
  }, []);
2941
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3251
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2942
3252
  "div",
2943
3253
  {
2944
3254
  ref: rowRef,
@@ -2977,7 +3287,7 @@ function AgentChatMessage({
2977
3287
  const resolvedUserContent = userMessageContent ?? message.content;
2978
3288
  const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
2979
3289
  const showAttachments = Boolean(message.attachments?.length) && (message.role === "user" || showAssistantAttachments);
2980
- const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3290
+ const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2981
3291
  AgentChatDefaultActions,
2982
3292
  {
2983
3293
  additionalActions,
@@ -2987,14 +3297,14 @@ function AgentChatMessage({
2987
3297
  }
2988
3298
  ) : null);
2989
3299
  const defaultUserActions = !actions && Boolean(actionHandlers) && !isAssistant;
2990
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3300
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2991
3301
  ChatMessage,
2992
3302
  {
2993
3303
  className,
2994
3304
  dir,
2995
3305
  from: message.role,
2996
3306
  children: [
2997
- showAttachments ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3307
+ showAttachments ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2998
3308
  ChatAttachmentRows,
2999
3309
  {
3000
3310
  attachments: message.attachments || [],
@@ -3003,14 +3313,14 @@ function AgentChatMessage({
3003
3313
  resolveContent: attachmentContentResolver
3004
3314
  }
3005
3315
  ) : null,
3006
- shouldRenderContent ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3316
+ shouldRenderContent ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3007
3317
  ChatMessageContent,
3008
3318
  {
3009
3319
  className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
3010
3320
  dir,
3011
3321
  from: message.role,
3012
3322
  children: [
3013
- isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3323
+ isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3014
3324
  Timeline,
3015
3325
  {
3016
3326
  getHitlActionState,
@@ -3021,7 +3331,7 @@ function AgentChatMessage({
3021
3331
  parts: message.parts
3022
3332
  }
3023
3333
  ) : null,
3024
- !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3334
+ !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3025
3335
  AgentChatUserMessageContent,
3026
3336
  {
3027
3337
  collapsedLines: userMessageCollapsedLines,
@@ -3034,108 +3344,7 @@ function AgentChatMessage({
3034
3344
  ]
3035
3345
  }
3036
3346
  ) : null,
3037
- renderedActions ? defaultUserActions ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentChatUserMessageActionRow, { className: actionsClassName, children: renderedActions }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
3038
- ]
3039
- }
3040
- );
3041
- }
3042
-
3043
- // src/ui/agent-chat-context-status.tsx
3044
- var React11 = __toESM(require("react"), 1);
3045
- var import_jsx_runtime12 = require("react/jsx-runtime");
3046
- var COMPACT_TOKENS = new Intl.NumberFormat("en-US", { notation: "compact" });
3047
- var PERCENT = new Intl.NumberFormat("en-US", {
3048
- style: "percent",
3049
- maximumFractionDigits: 1
3050
- });
3051
- var EXACT_SOURCES = /* @__PURE__ */ new Set(["exact", "provider_usage"]);
3052
- function contextStatusMetrics(contextWindow) {
3053
- const maximum = Number(contextWindow?.max_tokens || 0);
3054
- const input = Math.max(0, Number(contextWindow?.input_tokens || 0));
3055
- const admissionInput = Math.max(0, Number(contextWindow?.admission_input_tokens ?? input));
3056
- const usageRatio = Math.max(0, Math.min(1, Number(
3057
- contextWindow?.usage_ratio ?? input / maximum
3058
- )));
3059
- const admissionRatio = Math.max(0, Math.min(1, Number(
3060
- contextWindow?.admission_ratio ?? admissionInput / maximum
3061
- )));
3062
- return { maximum, input, admissionInput, usageRatio, admissionRatio };
3063
- }
3064
- function AgentChatContextStatus({
3065
- className,
3066
- contextWindow
3067
- }) {
3068
- const tooltipId = React11.useId();
3069
- const [open, setOpen] = React11.useState(false);
3070
- const { maximum, input, admissionInput, usageRatio, admissionRatio } = contextStatusMetrics(contextWindow);
3071
- const percentage = Math.round(usageRatio * 100);
3072
- const exact = EXACT_SOURCES.has(contextWindow?.source || "unknown");
3073
- if (!Number.isFinite(maximum) || maximum <= 0) return null;
3074
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3075
- "div",
3076
- {
3077
- className: cn("a24-context-status", className),
3078
- onBlurCapture: (event) => {
3079
- if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
3080
- },
3081
- onFocusCapture: () => setOpen(true),
3082
- onMouseEnter: () => setOpen(true),
3083
- onMouseLeave: () => setOpen(false),
3084
- children: [
3085
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3086
- "button",
3087
- {
3088
- "aria-describedby": open ? tooltipId : void 0,
3089
- "aria-label": `Context window ${percentage}% used`,
3090
- className: "a24-context-status__trigger",
3091
- onKeyDown: (event) => {
3092
- if (event.key === "Escape") setOpen(false);
3093
- },
3094
- type: "button",
3095
- children: [
3096
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { "aria-hidden": "true", className: "a24-context-status__ring", viewBox: "0 0 24 24", children: [
3097
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { className: "a24-context-status__track", cx: "12", cy: "12", r: "10" }),
3098
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3099
- "circle",
3100
- {
3101
- className: "a24-context-status__value",
3102
- cx: "12",
3103
- cy: "12",
3104
- pathLength: "100",
3105
- r: "10",
3106
- strokeDasharray: `${percentage} 100`
3107
- }
3108
- )
3109
- ] }),
3110
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
3111
- percentage,
3112
- "%"
3113
- ] })
3114
- ]
3115
- }
3116
- ),
3117
- open ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "a24-context-status__popover", id: tooltipId, role: "tooltip", children: [
3118
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "a24-context-status__sr-only", children: "Context window" }),
3119
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("strong", { children: [
3120
- PERCENT.format(usageRatio),
3121
- " context used"
3122
- ] }),
3123
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
3124
- exact ? "Input" : "Estimated input",
3125
- ": ",
3126
- COMPACT_TOKENS.format(input),
3127
- " / ",
3128
- COMPACT_TOKENS.format(maximum),
3129
- " tokens"
3130
- ] }),
3131
- admissionInput !== input ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
3132
- "Safety bound: ",
3133
- COMPACT_TOKENS.format(admissionInput),
3134
- " tokens (",
3135
- PERCENT.format(admissionRatio),
3136
- ")"
3137
- ] }) : null
3138
- ] }) : null
3347
+ renderedActions ? defaultUserActions ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AgentChatUserMessageActionRow, { className: actionsClassName, children: renderedActions }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
3139
3348
  ]
3140
3349
  }
3141
3350
  );
@@ -3365,68 +3574,6 @@ function McpConnectRequiredCard({
3365
3574
  }
3366
3575
  );
3367
3576
  }
3368
-
3369
- // src/ui/use-audio-recorder.ts
3370
- var React12 = __toESM(require("react"), 1);
3371
- var RECORDING_CANDIDATES = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"];
3372
- function recordingExtension(mimeType) {
3373
- return mimeType.startsWith("audio/mp4") ? "m4a" : "webm";
3374
- }
3375
- function useAudioRecorder(onRecorded, options = {}) {
3376
- const recorderRef = React12.useRef(null);
3377
- const streamRef = React12.useRef(null);
3378
- const onRecordedRef = React12.useRef(onRecorded);
3379
- const onStreamChangeRef = React12.useRef(options.onStreamChange);
3380
- onRecordedRef.current = onRecorded;
3381
- onStreamChangeRef.current = options.onStreamChange;
3382
- const [isRecording, setIsRecording] = React12.useState(false);
3383
- const [error, setError] = React12.useState(null);
3384
- const stop = React12.useCallback(() => recorderRef.current?.stop(), []);
3385
- const start = React12.useCallback(async () => {
3386
- setError(null);
3387
- if (!navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
3388
- setError("Audio recording is not supported in this browser.");
3389
- return;
3390
- }
3391
- try {
3392
- const mimeType = RECORDING_CANDIDATES.find((candidate) => MediaRecorder.isTypeSupported(candidate));
3393
- if (!mimeType) {
3394
- setError("Audio recording is not supported in this browser.");
3395
- return;
3396
- }
3397
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
3398
- onStreamChangeRef.current?.(stream);
3399
- const recorder = new MediaRecorder(stream, { mimeType });
3400
- const chunks = [];
3401
- recorder.ondataavailable = (event) => {
3402
- if (event.data.size) chunks.push(event.data);
3403
- };
3404
- recorder.onstop = () => {
3405
- const actualType = recorder.mimeType || "audio/webm";
3406
- onRecordedRef.current(new File([new Blob(chunks, { type: actualType })], `recording-${Date.now()}.${recordingExtension(actualType)}`, { type: actualType }));
3407
- stream.getTracks().forEach((track) => track.stop());
3408
- onStreamChangeRef.current?.(null);
3409
- recorderRef.current = null;
3410
- streamRef.current = null;
3411
- setIsRecording(false);
3412
- };
3413
- recorderRef.current = recorder;
3414
- streamRef.current = stream;
3415
- recorder.start();
3416
- setIsRecording(true);
3417
- } catch {
3418
- streamRef.current?.getTracks().forEach((track) => track.stop());
3419
- onStreamChangeRef.current?.(null);
3420
- setError("Microphone access is unavailable.");
3421
- }
3422
- }, []);
3423
- React12.useEffect(() => () => {
3424
- recorderRef.current?.stop();
3425
- streamRef.current?.getTracks().forEach((track) => track.stop());
3426
- onStreamChangeRef.current?.(null);
3427
- }, []);
3428
- return { error, isRecording, start, stop };
3429
- }
3430
3577
  // Annotate the CommonJS export names for ESM import in node:
3431
3578
  0 && (module.exports = {
3432
3579
  AgentChatActivityRow,
@@ -3505,6 +3652,7 @@ function useAudioRecorder(onRecorded, options = {}) {
3505
3652
  resolvedHitlLabel,
3506
3653
  revokeAgentChatComposerFiles,
3507
3654
  shouldCollapseUserMessage,
3655
+ useAgentChatComposer,
3508
3656
  useAudioRecorder,
3509
3657
  useChatComposerFocus,
3510
3658
  useCompletionActionEntrance,