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