@agents24/chat-react 0.5.35 → 0.5.37

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 (46) hide show
  1. package/compatibility.json +5 -5
  2. package/dist/{chunk-INO5DSSJ.js → chunk-DWDHK4FZ.js} +3 -4
  3. package/dist/chunk-DWDHK4FZ.js.map +1 -0
  4. package/dist/generated/delegation-types.d.ts +3 -2
  5. package/dist/generated/run-usage.d.ts +11 -0
  6. package/dist/registry/agents24-chat.json +13 -13
  7. package/dist/runtime/index.cjs +25 -9
  8. package/dist/runtime/index.cjs.map +1 -1
  9. package/dist/runtime/index.js +24 -7
  10. package/dist/runtime/index.js.map +1 -1
  11. package/dist/runtime/input-contract.d.ts +1 -1
  12. package/dist/runtime/use-agent-chat-hitl.d.ts +2 -2
  13. package/dist/runtime/use-agent-chat-runtime.d.ts +4 -6
  14. package/dist/scaffold/app.d.ts +2 -2
  15. package/dist/scaffold/components/chat/chat-composer.d.ts +2 -1
  16. package/dist/scaffold/components/chat/chat-message.d.ts +2 -2
  17. package/dist/scaffold/components/chat/message-parts.d.ts +2 -2
  18. package/dist/scaffold/index.cjs +17 -13
  19. package/dist/scaffold/index.cjs.map +1 -1
  20. package/dist/scaffold/index.js +11 -7
  21. package/dist/scaffold/index.js.map +1 -1
  22. package/dist/styles.css +55 -0
  23. package/dist/ui/agent-chat-composer.d.ts +2 -1
  24. package/dist/ui/agent-chat-message.d.ts +6 -2
  25. package/dist/ui/agent-response-timeline.d.ts +11 -3
  26. package/dist/ui/ask-user-interaction.d.ts +5 -1
  27. package/dist/ui/bubble.d.ts +1 -1
  28. package/dist/ui/code-block.d.ts +33 -0
  29. package/dist/ui/code-highlighter.d.ts +8 -0
  30. package/dist/ui/hitl-submission-status.d.ts +22 -0
  31. package/dist/ui/index.cjs +985 -301
  32. package/dist/ui/index.cjs.map +1 -1
  33. package/dist/ui/index.d.ts +3 -0
  34. package/dist/ui/index.js +969 -296
  35. package/dist/ui/index.js.map +1 -1
  36. package/dist/ui/message-code.d.ts +21 -0
  37. package/dist/ui/use-agent-chat-composer.d.ts +17 -2
  38. package/dist/ui/use-audio-recorder.d.ts +15 -2
  39. package/dist/ui/use-highlighted-code.d.ts +2 -0
  40. package/package.json +4 -3
  41. package/scaffold/src/app.tsx +2 -1
  42. package/scaffold/src/components/chat/chat-composer.tsx +5 -3
  43. package/scaffold/src/components/chat/chat-message.tsx +3 -3
  44. package/scaffold/src/components/chat/chat-shell.tsx +2 -1
  45. package/scaffold/src/components/chat/message-parts.tsx +6 -6
  46. package/dist/chunk-INO5DSSJ.js.map +0 -1
package/dist/ui/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  canonicalInputMimeType,
8
8
  inputMimeTypes,
9
9
  validateAgentChatSubmission
10
- } from "../chunk-INO5DSSJ.js";
10
+ } from "../chunk-DWDHK4FZ.js";
11
11
 
12
12
  // src/ui/agent-chat-composer.tsx
13
13
  import * as React6 from "react";
@@ -801,47 +801,69 @@ function useChatComposerFocus({ textareaRef, disabled, focusKey, restoredDraft,
801
801
 
802
802
  // src/ui/use-audio-recorder.ts
803
803
  import * as React3 from "react";
804
+ import { normalizeAttachmentMimeType as normalizeAttachmentMimeType2 } from "@agents24/client";
804
805
  var RECORDING_CANDIDATES = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"];
805
806
  function useAudioRecorder(onRecorded, options = {}) {
806
807
  const recorderRef = React3.useRef(null);
807
808
  const streamRef = React3.useRef(null);
809
+ const operationRef = React3.useRef(null);
808
810
  const pendingRef = React3.useRef(false);
809
- const generationRef = React3.useRef(0);
810
- const onRecordedRef = React3.useRef(onRecorded);
811
- const onStreamChangeRef = React3.useRef(options.onStreamChange);
812
- React3.useEffect(() => {
813
- onRecordedRef.current = onRecorded;
814
- onStreamChangeRef.current = options.onStreamChange;
811
+ const callbacksRef = React3.useRef({ onRecorded, onStreamChange: options.onStreamChange, acceptedMimeTypes: options.acceptedMimeTypes });
812
+ React3.useLayoutEffect(() => {
813
+ callbacksRef.current = { onRecorded, onStreamChange: options.onStreamChange, acceptedMimeTypes: options.acceptedMimeTypes };
815
814
  });
816
815
  const [isRecording, setIsRecording] = React3.useState(false);
816
+ const [isStarting, setIsStarting] = React3.useState(false);
817
+ const [isProcessing, setIsProcessing] = React3.useState(false);
817
818
  const [error, setError] = React3.useState(null);
818
819
  const release = React3.useCallback(() => {
819
820
  streamRef.current?.getTracks().forEach((track) => track.stop());
820
821
  streamRef.current = null;
821
822
  recorderRef.current = null;
822
- onStreamChangeRef.current?.(null);
823
+ callbacksRef.current.onStreamChange?.(null);
823
824
  }, []);
825
+ const discard = React3.useCallback(() => {
826
+ operationRef.current?.controller.abort();
827
+ operationRef.current = null;
828
+ pendingRef.current = false;
829
+ const recorder = recorderRef.current;
830
+ if (recorder) {
831
+ recorder.onstop = null;
832
+ recorder.onerror = null;
833
+ recorder.ondataavailable = null;
834
+ if (recorder.state !== "inactive") recorder.stop();
835
+ }
836
+ release();
837
+ }, [release]);
838
+ const cancel = React3.useCallback(() => {
839
+ discard();
840
+ setIsStarting(false);
841
+ setIsRecording(false);
842
+ setIsProcessing(false);
843
+ setError(null);
844
+ }, [discard]);
824
845
  const stop = React3.useCallback(() => {
825
846
  const recorder = recorderRef.current;
826
847
  if (recorder && recorder.state !== "inactive") recorder.stop();
827
848
  }, []);
828
- const start = React3.useCallback(async () => {
829
- if (pendingRef.current || recorderRef.current) return;
849
+ const isCapturing = React3.useCallback(() => pendingRef.current || recorderRef.current !== null, []);
850
+ const start = React3.useCallback(async (startOptions = {}) => {
851
+ if (operationRef.current) return;
830
852
  setError(null);
831
853
  if (!navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
832
854
  setError("Audio recording is not supported in this browser.");
833
855
  return;
834
856
  }
857
+ const controller = new AbortController();
858
+ const operation = { operationId: startOptions.operationId ?? crypto.randomUUID(), signal: controller.signal, controller };
859
+ operationRef.current = operation;
835
860
  pendingRef.current = true;
836
- const generation = generationRef.current;
861
+ setIsStarting(true);
837
862
  try {
838
- const mimeType = RECORDING_CANDIDATES.find((candidate) => MediaRecorder.isTypeSupported(candidate));
839
- if (!mimeType) {
840
- setError("Audio recording is not supported in this browser.");
841
- return;
842
- }
863
+ const mimeType = RECORDING_CANDIDATES.find((candidate) => MediaRecorder.isTypeSupported(candidate) && (callbacksRef.current.acceptedMimeTypes === void 0 || callbacksRef.current.acceptedMimeTypes.includes(normalizeAttachmentMimeType2(candidate))));
864
+ if (!mimeType) throw new Error("unsupported");
843
865
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
844
- if (generation !== generationRef.current) {
866
+ if (operation.signal.aborted) {
845
867
  stream.getTracks().forEach((track) => track.stop());
846
868
  return;
847
869
  }
@@ -853,48 +875,54 @@ function useAudioRecorder(onRecorded, options = {}) {
853
875
  if (event.data.size) chunks.push(event.data);
854
876
  };
855
877
  recorder.onstop = () => {
856
- if (generation !== generationRef.current) return;
878
+ if (operation.signal.aborted) return;
857
879
  const actualType = recorder.mimeType || mimeType;
858
- const extension = actualType.startsWith("audio/mp4") ? "m4a" : "webm";
859
- try {
860
- onRecordedRef.current(new File([new Blob(chunks, { type: actualType })], `recording-${Date.now()}.${extension}`, { type: actualType }));
861
- } finally {
862
- release();
863
- setIsRecording(false);
880
+ const accepted = callbacksRef.current.acceptedMimeTypes;
881
+ if (accepted !== void 0 && !accepted.includes(normalizeAttachmentMimeType2(actualType))) {
882
+ cancel();
883
+ setError("This Agent does not accept the recorded audio format.");
884
+ return;
864
885
  }
865
- };
866
- recorder.onerror = () => {
867
- recorder.onstop = null;
868
- if (recorder.state !== "inactive") recorder.stop();
886
+ const extension = actualType.startsWith("audio/mp4") ? "m4a" : "webm";
887
+ const file = new File(chunks, `recording-${Date.now()}.${extension}`, { type: actualType });
869
888
  release();
870
889
  setIsRecording(false);
890
+ setIsProcessing(true);
891
+ void Promise.resolve().then(() => {
892
+ if (!operation.signal.aborted) return callbacksRef.current.onRecorded(file, operation);
893
+ }).catch(() => {
894
+ if (!operation.signal.aborted) setError("Recording processing failed.");
895
+ }).finally(() => {
896
+ if (operationRef.current === operation) {
897
+ operationRef.current = null;
898
+ setIsProcessing(false);
899
+ }
900
+ });
901
+ };
902
+ recorder.onerror = () => {
903
+ cancel();
871
904
  setError("Audio recording failed. Try again.");
872
905
  };
873
906
  recorder.start();
874
907
  setIsRecording(true);
875
- onStreamChangeRef.current?.(stream);
908
+ callbacksRef.current.onStreamChange?.(stream);
876
909
  } catch {
877
- if (generation === generationRef.current) {
878
- release();
879
- setIsRecording(false);
880
- setError("Microphone access is unavailable.");
910
+ if (!operation.signal.aborted) {
911
+ cancel();
912
+ setError("Microphone access or audio recording is unavailable.");
881
913
  }
882
914
  } finally {
883
- if (generation === generationRef.current) pendingRef.current = false;
884
- }
885
- }, [release]);
886
- React3.useEffect(() => () => {
887
- generationRef.current += 1;
888
- pendingRef.current = false;
889
- const recorder = recorderRef.current;
890
- if (recorder) {
891
- recorder.onstop = null;
892
- recorder.onerror = null;
893
- if (recorder.state !== "inactive") recorder.stop();
915
+ if (!operation.signal.aborted) {
916
+ pendingRef.current = false;
917
+ setIsStarting(false);
918
+ }
894
919
  }
895
- release();
896
- }, [release]);
897
- return { error, isRecording, start, stop };
920
+ }, [cancel, discard, release]);
921
+ React3.useLayoutEffect(() => {
922
+ cancel();
923
+ return discard;
924
+ }, [options.scopeKey, cancel, discard]);
925
+ return { error, isRecording, isStarting, isProcessing, isCapturing, start, stop, cancel };
898
926
  }
899
927
 
900
928
  // src/ui/use-agent-chat-composer.ts
@@ -906,16 +934,29 @@ function useAgentChatComposer(options) {
906
934
  const localTextareaRef = React4.useRef(null);
907
935
  const textareaRef = options.textareaRef ?? localTextareaRef;
908
936
  const filesRef = React4.useRef(files);
909
- const inFlightFilesRef = React4.useRef([]);
937
+ const inFlightFilesRef = React4.useRef(/* @__PURE__ */ new Map());
910
938
  const revisionRef = React4.useRef(0);
911
939
  const submittingRef = React4.useRef(false);
912
- React4.useEffect(() => {
913
- filesRef.current = files;
914
- }, [files]);
940
+ const generationRef = React4.useRef(0);
941
+ const mountedRef = React4.useRef(true);
942
+ const textRef = React4.useRef(text);
943
+ React4.useLayoutEffect(() => {
944
+ mountedRef.current = true;
945
+ submittingRef.current = false;
946
+ setIsSubmitting(false);
947
+ return () => {
948
+ mountedRef.current = false;
949
+ generationRef.current += 1;
950
+ };
951
+ }, [options.scopeKey]);
915
952
  React4.useEffect(() => () => {
916
953
  revokeAgentChatComposerFiles(filesRef.current);
917
- revokeAgentChatComposerFiles(inFlightFilesRef.current);
954
+ revokeAgentChatComposerFiles([...inFlightFilesRef.current.values()].flat());
918
955
  }, []);
956
+ const revokeUnownedFiles = (candidates) => {
957
+ const retained = new Set([...filesRef.current, ...[...inFlightFilesRef.current.values()].flat()].map((file) => file.url));
958
+ revokeAgentChatComposerFiles(candidates.filter((file) => !retained.has(file.url)));
959
+ };
919
960
  const focusComposer = useChatComposerFocus({
920
961
  textareaRef,
921
962
  disabled: Boolean(options.disabled),
@@ -923,7 +964,10 @@ function useAgentChatComposer(options) {
923
964
  restoredDraft: options.restoredDraft,
924
965
  onRestore: (draft) => {
925
966
  revisionRef.current += 1;
926
- revokeAgentChatComposerFiles(filesRef.current);
967
+ const previousFiles = filesRef.current;
968
+ textRef.current = draft.text;
969
+ filesRef.current = draft.files;
970
+ revokeUnownedFiles(previousFiles);
927
971
  setTextState(draft.text);
928
972
  setFiles(draft.files);
929
973
  }
@@ -931,52 +975,80 @@ function useAgentChatComposer(options) {
931
975
  const attachmentMimeTypes = inputMimeTypes(options.inputContract);
932
976
  const setText = (value) => {
933
977
  revisionRef.current += 1;
978
+ textRef.current = value;
934
979
  setTextState(value);
935
980
  };
936
981
  const addFiles = (selected) => {
937
982
  const accepted = selected.filter((file) => attachmentMimeTypes.includes(canonicalInputMimeType(file.type, file.name)));
938
983
  revisionRef.current += 1;
939
- const additions = accepted.map(createAgentChatComposerFile);
940
- setFiles((current) => [...current, ...additions]);
984
+ const additions = selected.map(createAgentChatComposerFile);
985
+ filesRef.current = [...filesRef.current, ...additions];
986
+ setFiles(filesRef.current);
941
987
  setAttachmentError(accepted.length === selected.length ? null : "One or more selected file types are not supported by this Agent.");
942
988
  };
943
989
  const removeFile = (id) => {
944
990
  revisionRef.current += 1;
945
991
  const removed = filesRef.current.find((file) => file.id === id);
946
- if (removed) revokeAgentChatComposerFiles([removed]);
947
- setFiles((current) => current.filter((file) => file.id !== id));
992
+ filesRef.current = filesRef.current.filter((file) => file.id !== id);
993
+ if (removed) revokeUnownedFiles([removed]);
994
+ setFiles(filesRef.current);
948
995
  };
949
- const recorder = useAudioRecorder((file) => addFiles([file]), { onStreamChange: options.onRecordingStreamChange });
996
+ const recorder = useAudioRecorder(
997
+ (file, context) => options.onRecordingComplete ? options.onRecordingComplete(file, context) : addFiles([file]),
998
+ {
999
+ onStreamChange: options.onRecordingStreamChange,
1000
+ scopeKey: options.scopeKey,
1001
+ acceptedMimeTypes: options.onRecordingComplete ? void 0 : options.inputContract?.modalities.audio.allowed_mime_types ?? []
1002
+ }
1003
+ );
950
1004
  const validationError = options.inputContract ? validateAgentChatSubmission(
951
1005
  options.inputContract,
952
1006
  text,
953
1007
  files.map((file) => ({ data: file.source || new Uint8Array(), mediaType: file.mediaType, name: file.filename, byteSize: file.byteSize }))
954
1008
  ) : null;
955
- const canSubmit = Boolean(text.trim() || files.length) && !options.disabled && !options.isCancelling && !isSubmitting && !recorder.isRecording && !validationError;
956
- const submit = async () => {
957
- if (!canSubmit || submittingRef.current) return;
958
- const value = text;
959
- const selectedFiles = files;
1009
+ const canSubmit = Boolean(text.trim() || files.length) && !options.disabled && !options.isCancelling && !isSubmitting && !recorder.isRecording && !recorder.isStarting && !recorder.isProcessing && !validationError;
1010
+ const submit = async (submission) => {
1011
+ const value = submission?.text ?? textRef.current;
1012
+ const selectedFiles = submission?.files ?? filesRef.current;
1013
+ const suppliedError = options.inputContract ? validateAgentChatSubmission(
1014
+ options.inputContract,
1015
+ value,
1016
+ selectedFiles.map((file) => ({ data: file.source || new Uint8Array(), mediaType: file.mediaType, name: file.filename, byteSize: file.byteSize }))
1017
+ ) : null;
1018
+ if (!mountedRef.current || !value.trim() && !selectedFiles.length || options.disabled || options.isCancelling || submittingRef.current || recorder.isCapturing() || !submission && recorder.isProcessing || suppliedError) return false;
1019
+ const generation = generationRef.current;
960
1020
  const clearedRevision = ++revisionRef.current;
961
1021
  submittingRef.current = true;
962
1022
  setIsSubmitting(true);
963
- inFlightFilesRef.current = selectedFiles;
1023
+ const selectedUrls = new Set(selectedFiles.map((file) => file.url));
1024
+ const replacedFiles = filesRef.current.filter((file) => !selectedUrls.has(file.url));
1025
+ const submissionId = /* @__PURE__ */ Symbol();
1026
+ inFlightFilesRef.current.set(submissionId, selectedFiles);
1027
+ textRef.current = "";
1028
+ filesRef.current = [];
1029
+ revokeUnownedFiles(replacedFiles);
964
1030
  setTextState("");
965
1031
  setFiles([]);
966
1032
  focusComposer();
967
1033
  try {
968
1034
  await options.onSubmit(value, selectedFiles);
969
- revokeAgentChatComposerFiles(selectedFiles);
1035
+ return true;
970
1036
  } catch {
971
- if (revisionRef.current === clearedRevision) {
1037
+ if (mountedRef.current && generationRef.current === generation && revisionRef.current === clearedRevision) {
972
1038
  revisionRef.current += 1;
1039
+ textRef.current = value;
1040
+ filesRef.current = selectedFiles;
973
1041
  setTextState(value);
974
1042
  setFiles(selectedFiles);
975
- } else revokeAgentChatComposerFiles(selectedFiles);
1043
+ }
1044
+ return false;
976
1045
  } finally {
977
- inFlightFilesRef.current = [];
978
- submittingRef.current = false;
979
- setIsSubmitting(false);
1046
+ inFlightFilesRef.current.delete(submissionId);
1047
+ revokeUnownedFiles(selectedFiles);
1048
+ if (mountedRef.current && generationRef.current === generation) {
1049
+ submittingRef.current = false;
1050
+ setIsSubmitting(false);
1051
+ }
980
1052
  }
981
1053
  };
982
1054
  return {
@@ -993,6 +1065,7 @@ function useAgentChatComposer(options) {
993
1065
  attachmentMimeTypes,
994
1066
  validationError,
995
1067
  recorder,
1068
+ isProcessing: recorder.isProcessing,
996
1069
  recordingAllowed: options.recordingEnabled ?? options.inputContract?.modalities.audio.recording_enabled ?? false,
997
1070
  fileAccept: attachmentFileAccept(attachmentMimeTypes),
998
1071
  onKeyDown: (event) => {
@@ -1126,6 +1199,7 @@ function AgentChatComposer({
1126
1199
  disabled = false,
1127
1200
  forceExpanded = false,
1128
1201
  focusKey,
1202
+ scopeKey,
1129
1203
  inputToolbarContent,
1130
1204
  isRunning = false,
1131
1205
  isCancelling = false,
@@ -1144,6 +1218,7 @@ function AgentChatComposer({
1144
1218
  disabled,
1145
1219
  isRunning,
1146
1220
  isCancelling,
1221
+ scopeKey,
1147
1222
  focusKey,
1148
1223
  restoredDraft,
1149
1224
  textareaRef: localTextareaRef,
@@ -1378,7 +1453,7 @@ function QueueRow({ message, onRemove, onEdit }) {
1378
1453
  }
1379
1454
  function AgentChatQueue({ pending, queue, onRemove, onEdit, onResume, className }) {
1380
1455
  const [resumeError, setResumeError] = React7.useState(null);
1381
- if (!pending.length && !queue?.paused) return null;
1456
+ if (!pending.length) return null;
1382
1457
  return /* @__PURE__ */ jsxs3("section", { "aria-label": "Message queue", className: cn("a24-queue relative z-0 -mb-2 overflow-visible rounded-t-xl border border-b-0 border-border/50 bg-background pb-2", className), children: [
1383
1458
  queue?.paused ? /* @__PURE__ */ jsxs3("div", { className: "flex min-h-9 items-center justify-between gap-2 px-3 text-xs text-muted-foreground", children: [
1384
1459
  /* @__PURE__ */ jsx5("span", { children: "Queue paused" }),
@@ -1625,14 +1700,71 @@ function AgentChatDefaultActions({
1625
1700
  }
1626
1701
 
1627
1702
  // src/ui/agent-chat-message.tsx
1628
- import * as React13 from "react";
1703
+ import * as React17 from "react";
1629
1704
  import { ChevronDown as ChevronDown3, ChevronUp } from "lucide-react";
1630
1705
 
1706
+ // src/ui/hitl-submission-status.tsx
1707
+ import * as React9 from "react";
1708
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1709
+ var defaultHitlSubmissionLabels = {
1710
+ submitting: "Submitting\u2026",
1711
+ checking: "Checking submission\u2026",
1712
+ uncertain: "Submission could not be confirmed.",
1713
+ retry: "Retry submission",
1714
+ accepted: "Accepted; agent continuing",
1715
+ approved: "Approved; agent continuing",
1716
+ rejected: "Rejected"
1717
+ };
1718
+ function isHitlSubmissionCompact(state) {
1719
+ return ["submitting", "resuming", "checking", "uncertain", "accepted"].includes(state?.status || "");
1720
+ }
1721
+ function HitlSubmissionStatus({ state, labels: overrides, onPaint }) {
1722
+ const labels = { ...defaultHitlSubmissionLabels, ...overrides };
1723
+ const started = React9.useRef(performance.now());
1724
+ const ref = React9.useRef(null);
1725
+ const paintCallback = React9.useRef(onPaint);
1726
+ paintCallback.current = onPaint;
1727
+ React9.useEffect(() => {
1728
+ const frame = requestAnimationFrame(() => paintCallback.current?.(performance.now() - started.current));
1729
+ return () => cancelAnimationFrame(frame);
1730
+ }, []);
1731
+ React9.useEffect(() => {
1732
+ ref.current?.focus({ preventScroll: true });
1733
+ }, []);
1734
+ const text = state.status === "checking" ? labels.checking : state.status === "uncertain" ? labels.uncertain : state.status === "accepted" ? state.action === "approve" ? labels.approved : state.action === "reject" ? labels.rejected : labels.accepted : labels.submitting;
1735
+ return /* @__PURE__ */ jsxs5(
1736
+ "div",
1737
+ {
1738
+ ref,
1739
+ tabIndex: -1,
1740
+ role: "status",
1741
+ "aria-live": "polite",
1742
+ "aria-atomic": "true",
1743
+ "data-hitl-submission": state.status,
1744
+ className: "a24-hitl-submission flex items-center gap-2 py-1 text-start text-sm text-muted-foreground outline-none",
1745
+ children: [
1746
+ /* @__PURE__ */ jsx7("span", { children: text }),
1747
+ state.status === "uncertain" && state.retry && /* @__PURE__ */ jsx7(
1748
+ "button",
1749
+ {
1750
+ type: "button",
1751
+ className: "rounded px-2 py-1 text-foreground underline underline-offset-2",
1752
+ onClick: () => {
1753
+ void state.retry?.().catch(() => void 0);
1754
+ },
1755
+ children: labels.retry
1756
+ }
1757
+ )
1758
+ ]
1759
+ }
1760
+ );
1761
+ }
1762
+
1631
1763
  // src/ui/agent-response-timeline.tsx
1632
- import * as React12 from "react";
1764
+ import * as React16 from "react";
1633
1765
 
1634
1766
  // src/ui/ask-user-interaction.tsx
1635
- import * as React9 from "react";
1767
+ import * as React10 from "react";
1636
1768
  import {
1637
1769
  ChevronDown,
1638
1770
  ChevronLeft,
@@ -1694,7 +1826,7 @@ function askUserAnswersFromDrafts(questions, drafts) {
1694
1826
  }
1695
1827
 
1696
1828
  // src/ui/ask-user-interaction.tsx
1697
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1829
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1698
1830
  function resolvedAnswerText(question, answer) {
1699
1831
  if (!answer) return ["No response recorded"];
1700
1832
  const labels = answer.selectedOptionIds.flatMap((optionId) => {
@@ -1708,7 +1840,7 @@ function ResolvedQuestions({
1708
1840
  buttonRef,
1709
1841
  part
1710
1842
  }) {
1711
- const [open, setOpen] = React9.useState(false);
1843
+ const [open, setOpen] = React10.useState(false);
1712
1844
  const count = part.questions.length;
1713
1845
  const answers = new Map(
1714
1846
  (part.resolution?.answers || []).map((answer) => [
@@ -1716,8 +1848,8 @@ function ResolvedQuestions({
1716
1848
  answer
1717
1849
  ])
1718
1850
  );
1719
- return /* @__PURE__ */ jsxs5("div", { className: "a24-ask-user a24-ask-user--resolved w-full", children: [
1720
- /* @__PURE__ */ jsxs5(
1851
+ return /* @__PURE__ */ jsxs6("div", { className: "a24-ask-user a24-ask-user--resolved w-full", children: [
1852
+ /* @__PURE__ */ jsxs6(
1721
1853
  "button",
1722
1854
  {
1723
1855
  "aria-expanded": open,
@@ -1726,13 +1858,13 @@ function ResolvedQuestions({
1726
1858
  ref: buttonRef,
1727
1859
  type: "button",
1728
1860
  children: [
1729
- /* @__PURE__ */ jsxs5("span", { children: [
1861
+ /* @__PURE__ */ jsxs6("span", { children: [
1730
1862
  "Asked ",
1731
1863
  count,
1732
1864
  " question",
1733
1865
  count === 1 ? "" : "s"
1734
1866
  ] }),
1735
- open ? /* @__PURE__ */ jsx7(ChevronDown, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsx7(
1867
+ open ? /* @__PURE__ */ jsx8(ChevronDown, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsx8(
1736
1868
  ChevronRight,
1737
1869
  {
1738
1870
  "aria-hidden": "true",
@@ -1742,12 +1874,12 @@ function ResolvedQuestions({
1742
1874
  ]
1743
1875
  }
1744
1876
  ),
1745
- open ? /* @__PURE__ */ jsx7("div", { className: "mt-2 space-y-3 ps-4", children: part.questions.map((question) => /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1746
- /* @__PURE__ */ jsx7("div", { className: "text-sm font-medium text-foreground", children: question.question }),
1747
- /* @__PURE__ */ jsx7("div", { className: "mt-1 space-y-1 text-sm text-muted-foreground", children: resolvedAnswerText(
1877
+ open ? /* @__PURE__ */ jsx8("div", { className: "mt-2 space-y-3 ps-4", children: part.questions.map((question) => /* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
1878
+ /* @__PURE__ */ jsx8("div", { className: "text-sm font-medium text-foreground", children: question.question }),
1879
+ /* @__PURE__ */ jsx8("div", { className: "mt-1 space-y-1 text-sm text-muted-foreground", children: resolvedAnswerText(
1748
1880
  question,
1749
1881
  answers.get(question.id)
1750
- ).map((value, index) => /* @__PURE__ */ jsx7(
1882
+ ).map((value, index) => /* @__PURE__ */ jsx8(
1751
1883
  "div",
1752
1884
  {
1753
1885
  className: "whitespace-pre-wrap break-words",
@@ -1760,40 +1892,50 @@ function ResolvedQuestions({
1760
1892
  }
1761
1893
  function AskUserInteraction({
1762
1894
  error,
1895
+ submission,
1896
+ submissionLabels,
1897
+ onSubmissionPaint,
1763
1898
  isBusy = false,
1764
1899
  onSubmit,
1765
1900
  part
1766
1901
  }) {
1767
1902
  const questions = part.questions;
1768
- const [step, setStep] = React9.useState(0);
1769
- const [drafts, setDrafts] = React9.useState(
1903
+ const [step, setStep] = React10.useState(0);
1904
+ const [drafts, setDrafts] = React10.useState(
1770
1905
  () => emptyAskUserDrafts(questions)
1771
1906
  );
1772
- const headingRef = React9.useRef(null);
1773
- const questionsRef = React9.useRef(questions);
1774
- const resolvedButtonRef = React9.useRef(null);
1775
- const wasResolvedRef = React9.useRef(part.status !== "pending");
1907
+ const otherRef = React10.useRef(null);
1908
+ const headingRef = React10.useRef(null);
1909
+ const questionsRef = React10.useRef(questions);
1910
+ const resolvedButtonRef = React10.useRef(null);
1911
+ const wasResolvedRef = React10.useRef(part.status !== "pending");
1776
1912
  questionsRef.current = questions;
1777
- React9.useEffect(() => {
1913
+ React10.useEffect(() => {
1778
1914
  setStep(0);
1779
1915
  setDrafts(emptyAskUserDrafts(questionsRef.current));
1780
1916
  }, [part.interruptId]);
1781
- React9.useEffect(() => {
1917
+ React10.useEffect(() => {
1782
1918
  headingRef.current?.focus();
1783
1919
  }, [step]);
1784
- React9.useEffect(() => {
1920
+ React10.useEffect(() => {
1785
1921
  const isResolved = part.status !== "pending";
1786
1922
  if (isResolved && !wasResolvedRef.current) {
1787
1923
  resolvedButtonRef.current?.focus();
1788
1924
  }
1789
1925
  wasResolvedRef.current = isResolved;
1790
1926
  }, [part.status]);
1927
+ React10.useEffect(() => {
1928
+ if (submission?.status === "error") (otherRef.current?.value ? otherRef.current : headingRef.current)?.focus();
1929
+ }, [submission?.status]);
1930
+ if (part.status === "pending" && isHitlSubmissionCompact(submission)) {
1931
+ return /* @__PURE__ */ jsx8(HitlSubmissionStatus, { state: submission, labels: submissionLabels, onPaint: onSubmissionPaint });
1932
+ }
1791
1933
  if (part.status !== "pending") {
1792
- return /* @__PURE__ */ jsx7(ResolvedQuestions, { buttonRef: resolvedButtonRef, part });
1934
+ return /* @__PURE__ */ jsx8(ResolvedQuestions, { buttonRef: resolvedButtonRef, part });
1793
1935
  }
1794
1936
  const question = questions[step];
1795
1937
  if (!question) {
1796
- return /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", role: "alert", children: "This question request is unavailable." });
1938
+ return /* @__PURE__ */ jsx8("div", { className: "text-sm text-destructive", role: "alert", children: "This question request is unavailable." });
1797
1939
  }
1798
1940
  const draft = drafts[question.id] || {
1799
1941
  customText: "",
@@ -1827,9 +1969,9 @@ function AskUserInteraction({
1827
1969
  })
1828
1970
  );
1829
1971
  };
1830
- return /* @__PURE__ */ jsxs5("div", { className: "a24-ask-user space-y-3 rounded-xl border border-border/50 bg-background p-4 shadow-sm", children: [
1831
- /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-start justify-between gap-4", children: [
1832
- /* @__PURE__ */ jsx7(
1972
+ return /* @__PURE__ */ jsxs6("div", { className: "a24-ask-user space-y-3 rounded-xl border border-border/50 bg-background p-4 shadow-sm", children: [
1973
+ /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 items-start justify-between gap-4", children: [
1974
+ /* @__PURE__ */ jsx8(
1833
1975
  "h3",
1834
1976
  {
1835
1977
  className: "min-w-0 flex-1 text-base font-medium leading-6 text-foreground outline-none",
@@ -1838,8 +1980,8 @@ function AskUserInteraction({
1838
1980
  children: question.question
1839
1981
  }
1840
1982
  ),
1841
- /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: [
1842
- /* @__PURE__ */ jsx7(
1983
+ /* @__PURE__ */ jsxs6("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: [
1984
+ /* @__PURE__ */ jsx8(
1843
1985
  "button",
1844
1986
  {
1845
1987
  "aria-label": "Previous question",
@@ -1847,7 +1989,7 @@ function AskUserInteraction({
1847
1989
  disabled: isBusy || step === 0,
1848
1990
  onClick: () => setStep((current) => Math.max(0, current - 1)),
1849
1991
  type: "button",
1850
- children: /* @__PURE__ */ jsx7(
1992
+ children: /* @__PURE__ */ jsx8(
1851
1993
  ChevronLeft,
1852
1994
  {
1853
1995
  "aria-hidden": "true",
@@ -1856,7 +1998,7 @@ function AskUserInteraction({
1856
1998
  )
1857
1999
  }
1858
2000
  ),
1859
- /* @__PURE__ */ jsxs5(
2001
+ /* @__PURE__ */ jsxs6(
1860
2002
  "span",
1861
2003
  {
1862
2004
  "aria-label": `Question ${step + 1} of ${questions.length}`,
@@ -1868,7 +2010,7 @@ function AskUserInteraction({
1868
2010
  ]
1869
2011
  }
1870
2012
  ),
1871
- /* @__PURE__ */ jsx7(
2013
+ /* @__PURE__ */ jsx8(
1872
2014
  "button",
1873
2015
  {
1874
2016
  "aria-label": isLastQuestion ? "Submit answers" : "Next question",
@@ -1876,7 +2018,7 @@ function AskUserInteraction({
1876
2018
  disabled: isBusy || !onSubmit || !canMoveForward,
1877
2019
  onClick: () => completeStep(drafts),
1878
2020
  type: "button",
1879
- children: /* @__PURE__ */ jsx7(
2021
+ children: /* @__PURE__ */ jsx8(
1880
2022
  ChevronRight,
1881
2023
  {
1882
2024
  "aria-hidden": "true",
@@ -1887,10 +2029,10 @@ function AskUserInteraction({
1887
2029
  )
1888
2030
  ] })
1889
2031
  ] }),
1890
- /* @__PURE__ */ jsxs5("div", { className: "space-y-1", children: [
2032
+ /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
1891
2033
  question.options.map((option, index) => {
1892
2034
  const selected = draft.selectedOptionIds.includes(option.id);
1893
- return /* @__PURE__ */ jsxs5(
2035
+ return /* @__PURE__ */ jsxs6(
1894
2036
  "button",
1895
2037
  {
1896
2038
  "aria-pressed": selected,
@@ -1902,7 +2044,7 @@ function AskUserInteraction({
1902
2044
  onClick: () => selectOption(option.id),
1903
2045
  type: "button",
1904
2046
  children: [
1905
- /* @__PURE__ */ jsx7(
2047
+ /* @__PURE__ */ jsx8(
1906
2048
  "span",
1907
2049
  {
1908
2050
  className: cn(
@@ -1912,8 +2054,8 @@ function AskUserInteraction({
1912
2054
  children: index + 1
1913
2055
  }
1914
2056
  ),
1915
- /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 font-medium text-foreground", children: option.label }),
1916
- /* @__PURE__ */ jsx7(
2057
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 font-medium text-foreground", children: option.label }),
2058
+ /* @__PURE__ */ jsx8(
1917
2059
  ChevronRight,
1918
2060
  {
1919
2061
  "aria-hidden": "true",
@@ -1925,11 +2067,12 @@ function AskUserInteraction({
1925
2067
  option.id
1926
2068
  );
1927
2069
  }),
1928
- /* @__PURE__ */ jsxs5("div", { className: "flex min-h-11 items-center gap-2 rounded-xl bg-muted px-2.5 py-1.5 focus-within:ring-1 focus-within:ring-ring", children: [
1929
- /* @__PURE__ */ jsx7("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-full border border-border/70 bg-background/70 text-muted-foreground", children: /* @__PURE__ */ jsx7(Pencil, { "aria-hidden": "true", className: "size-4" }) }),
1930
- /* @__PURE__ */ jsx7(
2070
+ /* @__PURE__ */ jsxs6("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: [
2071
+ /* @__PURE__ */ jsx8("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__ */ jsx8(Pencil, { "aria-hidden": "true", className: "size-4" }) }),
2072
+ /* @__PURE__ */ jsx8(
1931
2073
  "input",
1932
2074
  {
2075
+ ref: otherRef,
1933
2076
  "aria-label": "Other response",
1934
2077
  autoComplete: "off",
1935
2078
  className: "h-8 min-w-0 flex-1 bg-transparent px-1 text-sm text-foreground outline-none placeholder:text-muted-foreground",
@@ -1946,7 +2089,7 @@ function AskUserInteraction({
1946
2089
  value: draft.customText
1947
2090
  }
1948
2091
  ),
1949
- draft.customText.trim() ? /* @__PURE__ */ jsx7(
2092
+ draft.customText.trim() ? /* @__PURE__ */ jsx8(
1950
2093
  "button",
1951
2094
  {
1952
2095
  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",
@@ -1958,12 +2101,12 @@ function AskUserInteraction({
1958
2101
  ) : null
1959
2102
  ] })
1960
2103
  ] }),
1961
- error ? /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", role: "alert", children: error }) : null
2104
+ error ? /* @__PURE__ */ jsx8("div", { className: "text-sm text-destructive", role: "alert", children: error }) : null
1962
2105
  ] });
1963
2106
  }
1964
2107
 
1965
2108
  // src/ui/agent-chat-context-compression-row.tsx
1966
- import { jsx as jsx8 } from "react/jsx-runtime";
2109
+ import { jsx as jsx9 } from "react/jsx-runtime";
1967
2110
  function compressionPresentation(part) {
1968
2111
  if (part.status === "failed") {
1969
2112
  return { label: "Could not compact message history", status: "failed" };
@@ -1978,7 +2121,7 @@ function AgentChatContextCompressionRow({
1978
2121
  part
1979
2122
  }) {
1980
2123
  const presentation = compressionPresentation(part);
1981
- return /* @__PURE__ */ jsx8(
2124
+ return /* @__PURE__ */ jsx9(
1982
2125
  "div",
1983
2126
  {
1984
2127
  "aria-live": "polite",
@@ -1986,11 +2129,11 @@ function AgentChatContextCompressionRow({
1986
2129
  "data-agents24-context-compression": "",
1987
2130
  "data-status": part.status,
1988
2131
  role: "status",
1989
- children: /* @__PURE__ */ jsx8("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsx8("div", { className: cn(
2132
+ children: /* @__PURE__ */ jsx9("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsx9("div", { className: cn(
1990
2133
  "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--without-orb",
1991
2134
  presentation.status === "failed" && "a24-tool-trigger--error",
1992
2135
  presentation.status === "running" && "a24-tool-trigger--active"
1993
- ), children: /* @__PURE__ */ jsx8("span", { className: cn(
2136
+ ), children: /* @__PURE__ */ jsx9("span", { className: cn(
1994
2137
  "a24-tool-trigger__label",
1995
2138
  presentation.status === "running" && "a24-tool-shimmer"
1996
2139
  ), children: presentation.label }) }) })
@@ -1999,7 +2142,7 @@ function AgentChatContextCompressionRow({
1999
2142
  }
2000
2143
 
2001
2144
  // src/ui/message-response.tsx
2002
- import * as React10 from "react";
2145
+ import * as React14 from "react";
2003
2146
  import { defaultRehypePlugins, Streamdown } from "streamdown";
2004
2147
 
2005
2148
  // src/active-content.ts
@@ -2023,18 +2166,494 @@ function safeChatMarkdownHref(value) {
2023
2166
  }
2024
2167
  }
2025
2168
 
2169
+ // src/ui/message-code.tsx
2170
+ import * as React13 from "react";
2171
+ import { FileCode2Icon } from "lucide-react";
2172
+
2173
+ // src/ui/code-block.tsx
2174
+ import * as React11 from "react";
2175
+ import { cva as cva2 } from "class-variance-authority";
2176
+ import { CheckIcon, CopyIcon, DownloadIcon, WrapTextIcon } from "lucide-react";
2177
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2178
+ var codeBlockVariants = cva2(
2179
+ "a24-code-block",
2180
+ {
2181
+ variants: {
2182
+ variant: {
2183
+ default: "a24-code-block--default",
2184
+ destructive: "a24-code-block--destructive"
2185
+ }
2186
+ },
2187
+ defaultVariants: {
2188
+ variant: "default"
2189
+ }
2190
+ }
2191
+ );
2192
+ function CodeBlock({
2193
+ className,
2194
+ variant = "default",
2195
+ size = "default",
2196
+ ...props
2197
+ }) {
2198
+ return /* @__PURE__ */ jsx10(
2199
+ "div",
2200
+ {
2201
+ "data-slot": "code-block",
2202
+ "data-variant": variant,
2203
+ "data-size": size,
2204
+ className: cn(codeBlockVariants({ variant }), className),
2205
+ ...props
2206
+ }
2207
+ );
2208
+ }
2209
+ function CodeBlockHeader({ className, ...props }) {
2210
+ return /* @__PURE__ */ jsx10(
2211
+ "div",
2212
+ {
2213
+ "data-slot": "code-block-header",
2214
+ className: cn(
2215
+ "a24-code-block__header",
2216
+ className
2217
+ ),
2218
+ ...props
2219
+ }
2220
+ );
2221
+ }
2222
+ function CodeBlockTitle({ className, ...props }) {
2223
+ return /* @__PURE__ */ jsx10(
2224
+ "div",
2225
+ {
2226
+ "data-slot": "code-block-title",
2227
+ className: cn(
2228
+ "a24-code-block__title",
2229
+ className
2230
+ ),
2231
+ ...props
2232
+ }
2233
+ );
2234
+ }
2235
+ function CodeBlockActions({
2236
+ className,
2237
+ ...props
2238
+ }) {
2239
+ return /* @__PURE__ */ jsx10(
2240
+ "div",
2241
+ {
2242
+ "data-slot": "code-block-actions",
2243
+ className: cn(
2244
+ "a24-code-block__actions",
2245
+ className
2246
+ ),
2247
+ ...props
2248
+ }
2249
+ );
2250
+ }
2251
+ function CodeBlockCopyButton({
2252
+ value,
2253
+ className,
2254
+ onClick,
2255
+ ...props
2256
+ }) {
2257
+ const [copied, setCopied] = React11.useState(false);
2258
+ React11.useEffect(() => {
2259
+ if (!copied) {
2260
+ return;
2261
+ }
2262
+ const timeout = setTimeout(() => setCopied(false), 2e3);
2263
+ return () => clearTimeout(timeout);
2264
+ }, [copied]);
2265
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
2266
+ /* @__PURE__ */ jsx10(
2267
+ "button",
2268
+ {
2269
+ type: "button",
2270
+ "data-slot": "code-block-copy-button",
2271
+ "data-copied": copied || void 0,
2272
+ "aria-label": copied ? "Copied" : "Copy",
2273
+ title: copied ? "Copied" : "Copy code",
2274
+ className: cn("a24-code-block__action", className),
2275
+ onClick: (event) => {
2276
+ onClick?.(event);
2277
+ if (event.defaultPrevented || !navigator.clipboard) return;
2278
+ navigator.clipboard.writeText(value).then(() => setCopied(true)).catch(() => {
2279
+ });
2280
+ },
2281
+ ...props,
2282
+ children: copied ? /* @__PURE__ */ jsx10(CheckIcon, { size: 12, strokeWidth: 1.5 }) : /* @__PURE__ */ jsx10(CopyIcon, { size: 12, strokeWidth: 1.5 })
2283
+ }
2284
+ ),
2285
+ /* @__PURE__ */ jsx10("span", { "aria-live": "polite", className: "a24-code-block__announcement", children: copied ? "Copied" : "" })
2286
+ ] });
2287
+ }
2288
+ function CodeBlockWrapButton({
2289
+ wrap,
2290
+ onWrapChange,
2291
+ className,
2292
+ onClick,
2293
+ ...props
2294
+ }) {
2295
+ return /* @__PURE__ */ jsx10(
2296
+ "button",
2297
+ {
2298
+ type: "button",
2299
+ "data-slot": "code-block-wrap-button",
2300
+ "aria-label": "Wrap lines",
2301
+ "aria-pressed": wrap,
2302
+ title: wrap ? "Unwrap lines" : "Wrap lines",
2303
+ className: cn("a24-code-block__action", className),
2304
+ onClick: (event) => {
2305
+ onClick?.(event);
2306
+ if (!event.defaultPrevented) onWrapChange(!wrap);
2307
+ },
2308
+ ...props,
2309
+ children: /* @__PURE__ */ jsx10(WrapTextIcon, { size: 12, strokeWidth: 1.5 })
2310
+ }
2311
+ );
2312
+ }
2313
+ function CodeBlockDownloadButton({
2314
+ value,
2315
+ filename = "code.txt",
2316
+ className,
2317
+ onClick,
2318
+ ...props
2319
+ }) {
2320
+ return /* @__PURE__ */ jsx10(
2321
+ "button",
2322
+ {
2323
+ type: "button",
2324
+ "data-slot": "code-block-download-button",
2325
+ "aria-label": "Download code",
2326
+ title: "Download code",
2327
+ className: cn("a24-code-block__action", className),
2328
+ onClick: (event) => {
2329
+ onClick?.(event);
2330
+ if (event.defaultPrevented) return;
2331
+ const url = URL.createObjectURL(new Blob([value], { type: "text/plain;charset=utf-8" }));
2332
+ const link = document.createElement("a");
2333
+ link.href = url;
2334
+ link.download = filename;
2335
+ document.body.append(link);
2336
+ link.click();
2337
+ link.remove();
2338
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
2339
+ },
2340
+ ...props,
2341
+ children: /* @__PURE__ */ jsx10(DownloadIcon, { size: 12, strokeWidth: 1.5 })
2342
+ }
2343
+ );
2344
+ }
2345
+ function CodeBlockContent({
2346
+ className,
2347
+ children,
2348
+ style,
2349
+ wrap = false,
2350
+ lineNumbers = false,
2351
+ startLine = 1,
2352
+ ...props
2353
+ }) {
2354
+ return /* @__PURE__ */ jsx10(
2355
+ "pre",
2356
+ {
2357
+ "data-slot": "code-block-content",
2358
+ "data-wrap": wrap || void 0,
2359
+ "data-numbered": lineNumbers || void 0,
2360
+ dir: "ltr",
2361
+ tabIndex: 0,
2362
+ style: { counterReset: `line ${startLine - 1}`, ...style },
2363
+ className: cn(
2364
+ "a24-code-block__content",
2365
+ className
2366
+ ),
2367
+ ...props,
2368
+ children: /* @__PURE__ */ jsx10(
2369
+ "code",
2370
+ {
2371
+ "data-slot": "code-block-code",
2372
+ className: "a24-code-block__code",
2373
+ children: lineNumbers && typeof children === "string" ? children.replace(/\n$/, "").split("\n").map((line, index) => /* @__PURE__ */ jsx10(CodeBlockLine, { children: line }, index)) : children
2374
+ }
2375
+ )
2376
+ }
2377
+ );
2378
+ }
2379
+ var codeBlockLineVariants = cva2(
2380
+ "a24-code-block__line",
2381
+ {
2382
+ variants: {
2383
+ variant: {
2384
+ default: "",
2385
+ added: "a24-code-block__line--added",
2386
+ removed: "a24-code-block__line--removed",
2387
+ highlighted: "a24-code-block__line--highlighted"
2388
+ }
2389
+ },
2390
+ defaultVariants: {
2391
+ variant: "default"
2392
+ }
2393
+ }
2394
+ );
2395
+ function CodeBlockLine({
2396
+ className,
2397
+ variant = "default",
2398
+ children,
2399
+ ...props
2400
+ }) {
2401
+ const empty = children === void 0 || children === null || children === "" || Array.isArray(children) && children.length === 0;
2402
+ return /* @__PURE__ */ jsx10(
2403
+ "span",
2404
+ {
2405
+ "data-slot": "code-block-line",
2406
+ "data-variant": variant,
2407
+ className: cn(codeBlockLineVariants({ variant }), className),
2408
+ ...props,
2409
+ children: /* @__PURE__ */ jsx10("span", { "data-slot": "code-block-line-content", className: "a24-code-block__line-content", children: empty ? "\n" : children })
2410
+ }
2411
+ );
2412
+ }
2413
+ function CodeBlockFooter({ className, ...props }) {
2414
+ return /* @__PURE__ */ jsx10(
2415
+ "div",
2416
+ {
2417
+ "data-slot": "code-block-footer",
2418
+ className: cn(
2419
+ "a24-code-block__footer",
2420
+ className
2421
+ ),
2422
+ ...props
2423
+ }
2424
+ );
2425
+ }
2426
+
2427
+ // src/ui/use-highlighted-code.ts
2428
+ import * as React12 from "react";
2429
+
2430
+ // src/ui/code-highlighter.tsx
2431
+ import {
2432
+ createHighlighterCore
2433
+ } from "shiki/core";
2434
+ import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
2435
+ import { bundledLanguages, bundledLanguagesAlias } from "shiki/langs";
2436
+ import { jsx as jsx11 } from "react/jsx-runtime";
2437
+ var languageLoaders = {
2438
+ ...bundledLanguages,
2439
+ ...bundledLanguagesAlias
2440
+ };
2441
+ var highlighter;
2442
+ function getHighlighter() {
2443
+ highlighter ?? (highlighter = createHighlighterCore({
2444
+ themes: [
2445
+ import("shiki/themes/github-light.mjs"),
2446
+ import("shiki/themes/github-dark.mjs")
2447
+ ],
2448
+ langs: [],
2449
+ engine: createJavaScriptRegexEngine({ forgiving: true })
2450
+ }));
2451
+ return highlighter;
2452
+ }
2453
+ function getLanguage(language) {
2454
+ const name = language.toLowerCase();
2455
+ if (name === "ansi") return name;
2456
+ if (Object.prototype.hasOwnProperty.call(languageLoaders, name)) return name;
2457
+ return null;
2458
+ }
2459
+ async function loadHighlighter(language) {
2460
+ const lang = getLanguage(language);
2461
+ if (!lang) {
2462
+ return null;
2463
+ }
2464
+ const shiki = await getHighlighter();
2465
+ if (lang !== "ansi" && !shiki.getLoadedLanguages().includes(lang)) {
2466
+ await shiki.loadLanguage(languageLoaders[lang]);
2467
+ }
2468
+ return {
2469
+ // Returns one React node per line, and the grammar state after the last
2470
+ // line. Pass that state back to continue where the code left off.
2471
+ highlight(code, state) {
2472
+ const tokenize = (text) => shiki.codeToTokens(text, {
2473
+ lang,
2474
+ themes: { light: "github-light", dark: "github-dark" },
2475
+ defaultColor: false,
2476
+ grammarState: state
2477
+ }).tokens;
2478
+ const tokens = lang === "ansi" ? code.split("\n").flatMap((line) => tokenize(line)) : tokenize(code);
2479
+ return {
2480
+ lines: tokens.map(
2481
+ (line) => line.map((token, index) => /* @__PURE__ */ jsx11(
2482
+ "span",
2483
+ {
2484
+ style: token.htmlStyle,
2485
+ className: "a24-code-token",
2486
+ children: token.content
2487
+ },
2488
+ index
2489
+ ))
2490
+ ),
2491
+ state: shiki.getLastGrammarState(tokens)
2492
+ };
2493
+ }
2494
+ };
2495
+ }
2496
+
2497
+ // src/ui/use-highlighted-code.ts
2498
+ function useHighlightedCode(value, language) {
2499
+ const code = value.endsWith("\n") ? value.slice(0, -1) : value;
2500
+ const [loaded, setLoaded] = React12.useState(null);
2501
+ const highlighter2 = loaded?.language === language ? loaded.highlighter : null;
2502
+ React12.useEffect(() => {
2503
+ let cancelled = false;
2504
+ loadHighlighter(language).then((next2) => {
2505
+ if (!cancelled) {
2506
+ setLoaded({ language, highlighter: next2 });
2507
+ }
2508
+ }).catch(() => {
2509
+ });
2510
+ return () => {
2511
+ cancelled = true;
2512
+ };
2513
+ }, [language]);
2514
+ const [done, setDone] = React12.useState({ highlighter: null, text: "", lines: [] });
2515
+ let next = done;
2516
+ if (next.highlighter !== highlighter2 || !code.startsWith(next.text)) {
2517
+ next = { highlighter: highlighter2, text: "", lines: [] };
2518
+ }
2519
+ const end = code.lastIndexOf("\n") + 1;
2520
+ if (highlighter2 && end > next.text.length) {
2521
+ const result = highlighter2.highlight(
2522
+ code.slice(next.text.length, end - 1),
2523
+ next.state
2524
+ );
2525
+ next = {
2526
+ highlighter: highlighter2,
2527
+ text: code.slice(0, end),
2528
+ lines: [...next.lines, ...result.lines],
2529
+ state: result.state
2530
+ };
2531
+ }
2532
+ if (next !== done) {
2533
+ setDone(next);
2534
+ }
2535
+ const tail = code.slice(end);
2536
+ return React12.useMemo(() => {
2537
+ if (!highlighter2) {
2538
+ return code.split("\n");
2539
+ }
2540
+ return [...next.lines, highlighter2.highlight(tail, next.state).lines[0]];
2541
+ }, [code, highlighter2, next, tail]);
2542
+ }
2543
+
2544
+ // src/ui/message-code.tsx
2545
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2546
+ var CODE_EXTENSIONS = {
2547
+ bash: "sh",
2548
+ shell: "sh",
2549
+ shellscript: "sh",
2550
+ sh: "sh",
2551
+ zsh: "sh",
2552
+ javascript: "js",
2553
+ js: "js",
2554
+ jsx: "jsx",
2555
+ typescript: "ts",
2556
+ ts: "ts",
2557
+ tsx: "tsx",
2558
+ python: "py",
2559
+ py: "py",
2560
+ ruby: "rb",
2561
+ rust: "rs",
2562
+ rs: "rs",
2563
+ go: "go",
2564
+ java: "java",
2565
+ kotlin: "kt",
2566
+ swift: "swift",
2567
+ c: "c",
2568
+ cpp: "cpp",
2569
+ csharp: "cs",
2570
+ json: "json",
2571
+ jsonc: "jsonc",
2572
+ yaml: "yaml",
2573
+ yml: "yml",
2574
+ toml: "toml",
2575
+ html: "html",
2576
+ xml: "xml",
2577
+ css: "css",
2578
+ scss: "scss",
2579
+ sql: "sql",
2580
+ markdown: "md",
2581
+ md: "md",
2582
+ diff: "diff",
2583
+ text: "txt",
2584
+ plaintext: "txt"
2585
+ };
2586
+ function MessageCodeBlock({ code, language = "text" }) {
2587
+ const [wrap, setWrap] = React13.useState(false);
2588
+ const lines = useHighlightedCode(code, language);
2589
+ const extension = Object.prototype.hasOwnProperty.call(CODE_EXTENSIONS, language.toLowerCase()) ? CODE_EXTENSIONS[language.toLowerCase()] : "txt";
2590
+ return /* @__PURE__ */ jsxs8(CodeBlock, { children: [
2591
+ /* @__PURE__ */ jsxs8(CodeBlockHeader, { children: [
2592
+ /* @__PURE__ */ jsxs8(CodeBlockTitle, { children: [
2593
+ /* @__PURE__ */ jsx12(FileCode2Icon, { size: 14, strokeWidth: 1.5, "aria-hidden": "true" }),
2594
+ /* @__PURE__ */ jsx12("span", { children: language })
2595
+ ] }),
2596
+ /* @__PURE__ */ jsxs8(CodeBlockActions, { children: [
2597
+ /* @__PURE__ */ jsx12(CodeBlockWrapButton, { wrap, onWrapChange: setWrap }),
2598
+ /* @__PURE__ */ jsx12(CodeBlockDownloadButton, { value: code, filename: `code.${extension}` }),
2599
+ /* @__PURE__ */ jsx12(CodeBlockCopyButton, { value: code })
2600
+ ] })
2601
+ ] }),
2602
+ /* @__PURE__ */ jsx12(CodeBlockContent, { "aria-label": `${language} code`, lineNumbers: true, wrap, children: lines.map((line, index) => /* @__PURE__ */ jsx12(CodeBlockLine, { children: line }, index)) })
2603
+ ] });
2604
+ }
2605
+ function MessageMarkdownCode({ children, className, node, ...props }) {
2606
+ const language = className?.match(/(?:^|\s)language-([^\s]+)/)?.[1];
2607
+ const multiline = node?.position?.start?.line !== node?.position?.end?.line;
2608
+ if (props["data-block"] === void 0 && !language && !multiline) {
2609
+ return /* @__PURE__ */ jsx12("code", { ...props, className: cn("a24-inline-code", className), "data-streamdown": "inline-code", children });
2610
+ }
2611
+ const code = typeof children === "string" ? children.replace(/\n$/, "") : "";
2612
+ return /* @__PURE__ */ jsx12(MessageCodeBlock, { code, language });
2613
+ }
2614
+ function formatMessageJson(text) {
2615
+ const trimmed = text.trim();
2616
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
2617
+ try {
2618
+ JSON.parse(trimmed);
2619
+ } catch {
2620
+ return null;
2621
+ }
2622
+ const tokens = trimmed.match(/"(?:\\.|[^"\\])*"|[{}\[\],:]|[^\s{}\[\],:]+/g) || [];
2623
+ let depth = 0;
2624
+ let result = "";
2625
+ const newline = () => `
2626
+ ${" ".repeat(depth)}`;
2627
+ tokens.forEach((token, index) => {
2628
+ const previous = tokens[index - 1];
2629
+ const next = tokens[index + 1];
2630
+ if (token === "{" || token === "[") {
2631
+ result += token;
2632
+ depth += 1;
2633
+ if (next !== "}" && next !== "]") result += newline();
2634
+ } else if (token === "}" || token === "]") {
2635
+ depth -= 1;
2636
+ if (previous !== "{" && previous !== "[") result += newline();
2637
+ result += token;
2638
+ } else if (token === ",") result += `,${newline()}`;
2639
+ else if (token === ":") result += ": ";
2640
+ else result += token;
2641
+ });
2642
+ return result;
2643
+ }
2644
+
2026
2645
  // src/ui/message-response.tsx
2027
- import { Fragment as Fragment2, jsx as jsx9 } from "react/jsx-runtime";
2646
+ import { Fragment as Fragment3, jsx as jsx13 } from "react/jsx-runtime";
2028
2647
  function SafeMarkdownLink({ children, href, ...props }) {
2029
2648
  const domProps = { ...props };
2030
2649
  delete domProps.node;
2031
2650
  const safeHref = safeChatMarkdownHref(href);
2032
- if (!safeHref) return /* @__PURE__ */ jsx9("span", { children });
2033
- if (safeHref.startsWith("#")) return /* @__PURE__ */ jsx9("a", { ...domProps, href: safeHref, children });
2034
- return /* @__PURE__ */ jsx9("a", { ...domProps, href: safeHref, rel: "noopener noreferrer", target: "_blank", children });
2651
+ if (!safeHref) return /* @__PURE__ */ jsx13("span", { children });
2652
+ if (safeHref.startsWith("#")) return /* @__PURE__ */ jsx13("a", { ...domProps, href: safeHref, children });
2653
+ return /* @__PURE__ */ jsx13("a", { ...domProps, href: safeHref, rel: "noopener noreferrer", target: "_blank", children });
2035
2654
  }
2036
2655
  function BlockedMarkdownImage({ alt }) {
2037
- return alt ? /* @__PURE__ */ jsx9("span", { "aria-label": `Image blocked: ${alt}`, role: "img", children: alt }) : null;
2656
+ return alt ? /* @__PURE__ */ jsx13("span", { "aria-label": `Image blocked: ${alt}`, role: "img", children: alt }) : null;
2038
2657
  }
2039
2658
  var BLOCK_MARKDOWN_TAGS = /* @__PURE__ */ new Set([
2040
2659
  "blockquote",
@@ -2055,7 +2674,7 @@ function isMultilineCodeNode(node) {
2055
2674
  return node?.tagName === "code" && node.position?.start?.line !== void 0 && node.position?.end?.line !== void 0 && node.position.start.line !== node.position.end.line;
2056
2675
  }
2057
2676
  function hasBlockMarkdownChild(child) {
2058
- if (!React10.isValidElement(child)) {
2677
+ if (!React14.isValidElement(child)) {
2059
2678
  return false;
2060
2679
  }
2061
2680
  if (typeof child.type === "string" && BLOCK_MARKDOWN_TAGS.has(child.type)) {
@@ -2065,7 +2684,7 @@ function hasBlockMarkdownChild(child) {
2065
2684
  if (BLOCK_MARKDOWN_TAGS.has(props.node?.tagName || "") || isMultilineCodeNode(props.node)) {
2066
2685
  return true;
2067
2686
  }
2068
- return React10.Children.toArray(props.children).some(hasBlockMarkdownChild);
2687
+ return React14.Children.toArray(props.children).some(hasBlockMarkdownChild);
2069
2688
  }
2070
2689
  function MessageMarkdownParagraph({
2071
2690
  children,
@@ -2073,22 +2692,23 @@ function MessageMarkdownParagraph({
2073
2692
  }) {
2074
2693
  const domProps = { ...props };
2075
2694
  delete domProps.node;
2076
- const childArray = React10.Children.toArray(children).filter(
2695
+ const childArray = React14.Children.toArray(children).filter(
2077
2696
  (child) => child !== null && child !== ""
2078
2697
  );
2079
- const isImageOnly = childArray.length === 1 && React10.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
2698
+ const isImageOnly = childArray.length === 1 && React14.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
2080
2699
  if (isImageOnly) {
2081
- return /* @__PURE__ */ jsx9(Fragment2, { children });
2700
+ return /* @__PURE__ */ jsx13(Fragment3, { children });
2082
2701
  }
2083
2702
  if (childArray.some(hasBlockMarkdownChild)) {
2084
- return /* @__PURE__ */ jsx9("div", { ...domProps, children });
2703
+ return /* @__PURE__ */ jsx13("div", { ...domProps, children });
2085
2704
  }
2086
- return /* @__PURE__ */ jsx9("p", { ...domProps, children });
2705
+ return /* @__PURE__ */ jsx13("p", { ...domProps, children });
2087
2706
  }
2088
2707
  var MESSAGE_RESPONSE_COMPONENTS = {
2089
2708
  a: SafeMarkdownLink,
2090
2709
  img: BlockedMarkdownImage,
2091
- p: MessageMarkdownParagraph
2710
+ p: MessageMarkdownParagraph,
2711
+ code: MessageMarkdownCode
2092
2712
  };
2093
2713
  var streamdownDefaultRehypePlugins = defaultRehypePlugins || {};
2094
2714
  var streamdownHardenPlugin = Array.isArray(
@@ -2103,7 +2723,7 @@ var MESSAGE_RESPONSE_REHYPE_PLUGINS = [
2103
2723
  ]
2104
2724
  ] : []
2105
2725
  ];
2106
- var MessageResponse = React10.memo(
2726
+ var MessageResponse = React14.memo(
2107
2727
  ({
2108
2728
  children,
2109
2729
  className,
@@ -2121,11 +2741,21 @@ var MessageResponse = React10.memo(
2121
2741
  maxCatchupChars: 32,
2122
2742
  text
2123
2743
  });
2124
- const streamdownComponents = React10.useMemo(
2744
+ const streamdownComponents = React14.useMemo(
2125
2745
  () => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
2126
2746
  [components]
2127
2747
  );
2128
- return /* @__PURE__ */ jsx9(
2748
+ const json = React14.useMemo(() => formatMessageJson(text), [text]);
2749
+ if (json !== null && !components?.code) {
2750
+ return /* @__PURE__ */ jsx13("div", { className: cn("a24-message-response", className), children: /* @__PURE__ */ jsx13(
2751
+ MessageCodeBlock,
2752
+ {
2753
+ code: streaming || streamingText.isAnimating ? streamingText.displayedText : json,
2754
+ language: "json"
2755
+ }
2756
+ ) });
2757
+ }
2758
+ return /* @__PURE__ */ jsx13(
2129
2759
  Streamdown,
2130
2760
  {
2131
2761
  className: cn("a24-message-response", className),
@@ -2177,10 +2807,10 @@ function resolvedHitlLabel(part) {
2177
2807
  }
2178
2808
 
2179
2809
  // src/ui/tool-sessions.tsx
2180
- import * as React11 from "react";
2810
+ import * as React15 from "react";
2181
2811
  import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2 } from "lucide-react";
2182
2812
  import { ThinkingOrb } from "thinking-orbs";
2183
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
2813
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
2184
2814
  function toolSlotContext(isActive2, label, part, slots) {
2185
2815
  return {
2186
2816
  isActive: isActive2,
@@ -2198,7 +2828,7 @@ function ToolResourceAction({ context }) {
2198
2828
  const target = context.resourceTargets[0];
2199
2829
  if (!target) return null;
2200
2830
  const name = resourceTargetName(target);
2201
- return /* @__PURE__ */ jsx10(
2831
+ return /* @__PURE__ */ jsx14(
2202
2832
  "button",
2203
2833
  {
2204
2834
  "aria-label": `Open ${target.kind} ${target.path}`,
@@ -2212,8 +2842,8 @@ function ToolResourceAction({ context }) {
2212
2842
  );
2213
2843
  }
2214
2844
  function toolAccessory(context, slots) {
2215
- return /* @__PURE__ */ jsxs6(Fragment3, { children: [
2216
- slots?.onResourceAction ? /* @__PURE__ */ jsx10(ToolResourceAction, { context }) : null,
2845
+ return /* @__PURE__ */ jsxs9(Fragment4, { children: [
2846
+ slots?.onResourceAction ? /* @__PURE__ */ jsx14(ToolResourceAction, { context }) : null,
2217
2847
  slots?.renderToolAccessory?.(context)
2218
2848
  ] });
2219
2849
  }
@@ -2290,12 +2920,12 @@ function ToolActivityReel({
2290
2920
  }) {
2291
2921
  const initial = initialLabel && initialLabel !== label ? initialLabel : label;
2292
2922
  const parsedInitialShownAt = initialShownAt ? Date.parse(initialShownAt) : Number.NaN;
2293
- const [displayed, setDisplayed] = React11.useState(initial);
2294
- const [previous, setPrevious] = React11.useState(null);
2295
- const displayedRef = React11.useRef(initial);
2296
- const latestRef = React11.useRef(label);
2297
- const shownAtRef = React11.useRef(Number.isFinite(parsedInitialShownAt) ? parsedInitialShownAt : Date.now());
2298
- React11.useEffect(() => {
2923
+ const [displayed, setDisplayed] = React15.useState(initial);
2924
+ const [previous, setPrevious] = React15.useState(null);
2925
+ const displayedRef = React15.useRef(initial);
2926
+ const latestRef = React15.useRef(label);
2927
+ const shownAtRef = React15.useRef(Number.isFinite(parsedInitialShownAt) ? parsedInitialShownAt : Date.now());
2928
+ React15.useEffect(() => {
2299
2929
  latestRef.current = label;
2300
2930
  if (displayedRef.current === label) return;
2301
2931
  const showLatest = () => {
@@ -2315,18 +2945,18 @@ function ToolActivityReel({
2315
2945
  const timer = window.setTimeout(showLatest, remaining);
2316
2946
  return () => window.clearTimeout(timer);
2317
2947
  }, [label]);
2318
- React11.useEffect(() => {
2948
+ React15.useEffect(() => {
2319
2949
  if (!previous) return;
2320
2950
  const timer = window.setTimeout(() => setPrevious(null), 200);
2321
2951
  return () => window.clearTimeout(timer);
2322
2952
  }, [previous]);
2323
- return /* @__PURE__ */ jsxs6("span", { className: "a24-tool-reel", "aria-live": announce ? "polite" : "off", children: [
2324
- previous ? /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", className: "a24-tool-reel__previous", children: previous }) : null,
2325
- /* @__PURE__ */ jsx10("span", { className: previous ? "a24-tool-reel__current" : void 0, children: displayed })
2953
+ return /* @__PURE__ */ jsxs9("span", { className: "a24-tool-reel", "aria-live": announce ? "polite" : "off", children: [
2954
+ previous ? /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", className: "a24-tool-reel__previous", children: previous }) : null,
2955
+ /* @__PURE__ */ jsx14("span", { className: previous ? "a24-tool-reel__current" : void 0, children: displayed })
2326
2956
  ] });
2327
2957
  }
2328
2958
  function ToolActivityOrb({ label = "Working", kind = "tool", part, renderActivityIcon }) {
2329
- return /* @__PURE__ */ jsx10("span", { className: "a24-tool-orb", children: renderActivityIcon ? renderActivityIcon({ label, kind, part }) : /* @__PURE__ */ jsx10(ThinkingOrb, { "aria-label": label, size: 20, speed: 0.8, state: "searching" }) });
2959
+ return /* @__PURE__ */ jsx14("span", { className: "a24-tool-orb", children: renderActivityIcon ? renderActivityIcon({ label, kind, part }) : /* @__PURE__ */ jsx14(ThinkingOrb, { "aria-label": label, size: 20, speed: 0.8, state: "searching" }) });
2330
2960
  }
2331
2961
  function AgentChatActivityRow({
2332
2962
  label,
@@ -2334,22 +2964,22 @@ function AgentChatActivityRow({
2334
2964
  renderActivityIcon,
2335
2965
  onSelect
2336
2966
  }) {
2337
- const content = /* @__PURE__ */ jsxs6(Fragment3, { children: [
2338
- /* @__PURE__ */ jsx10(ToolActivityOrb, { label, kind: "planning", renderActivityIcon }),
2339
- /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label a24-tool-shimmer", children: /* @__PURE__ */ jsx10(ToolActivityReel, { label }) })
2967
+ const content = /* @__PURE__ */ jsxs9(Fragment4, { children: [
2968
+ /* @__PURE__ */ jsx14(ToolActivityOrb, { label, kind: "planning", renderActivityIcon }),
2969
+ /* @__PURE__ */ jsx14("span", { className: "a24-tool-trigger__label a24-tool-shimmer", children: /* @__PURE__ */ jsx14(ToolActivityReel, { label }) })
2340
2970
  ] });
2341
- return /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger-row a24-tool-trigger-row--root", "data-agents24-model-turn": modelTurnId, role: "status", children: onSelect ? /* @__PURE__ */ jsx10("button", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", onClick: onSelect, type: "button", children: content }) : /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", children: content }) });
2971
+ return /* @__PURE__ */ jsx14("div", { className: "a24-tool-trigger-row a24-tool-trigger-row--root", "data-agents24-model-turn": modelTurnId, role: "status", children: onSelect ? /* @__PURE__ */ jsx14("button", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", onClick: onSelect, type: "button", children: content }) : /* @__PURE__ */ jsx14("div", { className: "a24-tool-trigger a24-tool-trigger--root a24-tool-trigger--active", children: content }) });
2342
2972
  }
2343
2973
  function AgentChatModelTurnRow({ part }) {
2344
- return /* @__PURE__ */ jsx10(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId });
2974
+ return /* @__PURE__ */ jsx14(AgentChatActivityRow, { label: "Planning next moves", modelTurnId: part.modelTurnId });
2345
2975
  }
2346
2976
  function AgentChatNodeActivityRow({
2347
2977
  renderActivityIcon,
2348
2978
  onSelect,
2349
2979
  part
2350
2980
  }) {
2351
- const [open, setOpen] = React11.useState(false);
2352
- const contentId = React11.useId();
2981
+ const [open, setOpen] = React15.useState(false);
2982
+ const contentId = React15.useId();
2353
2983
  const running = part.status === "running";
2354
2984
  const failed = part.status === "failed";
2355
2985
  const failureMessage = part.failure?.message || "The node could not complete the request.";
@@ -2360,18 +2990,18 @@ function AgentChatNodeActivityRow({
2360
2990
  running && "a24-tool-trigger--active",
2361
2991
  failed && "a24-tool-trigger--error"
2362
2992
  );
2363
- const label = running ? /* @__PURE__ */ jsx10("span", { className: "a24-tool-shimmer", children: /* @__PURE__ */ jsx10(ToolActivityReel, { label: part.label }) }) : part.label;
2993
+ const label = running ? /* @__PURE__ */ jsx14("span", { className: "a24-tool-shimmer", children: /* @__PURE__ */ jsx14(ToolActivityReel, { label: part.label }) }) : part.label;
2364
2994
  if (!failed) {
2365
- return /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger-row", role: "status", children: onSelect ? /* @__PURE__ */ jsxs6("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2366
- running ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: part.label, kind: "node", part, renderActivityIcon }) : null,
2367
- /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
2368
- ] }) : /* @__PURE__ */ jsxs6("div", { className: triggerClassName, children: [
2369
- running ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: part.label, kind: "node", part, renderActivityIcon }) : null,
2370
- /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
2995
+ return /* @__PURE__ */ jsx14("div", { className: "a24-tool-trigger-row", role: "status", children: onSelect ? /* @__PURE__ */ jsxs9("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2996
+ running ? /* @__PURE__ */ jsx14(ToolActivityOrb, { label: part.label, kind: "node", part, renderActivityIcon }) : null,
2997
+ /* @__PURE__ */ jsx14("span", { className: "a24-tool-trigger__label", children: label })
2998
+ ] }) : /* @__PURE__ */ jsxs9("div", { className: triggerClassName, children: [
2999
+ running ? /* @__PURE__ */ jsx14(ToolActivityOrb, { label: part.label, kind: "node", part, renderActivityIcon }) : null,
3000
+ /* @__PURE__ */ jsx14("span", { className: "a24-tool-trigger__label", children: label })
2371
3001
  ] }) });
2372
3002
  }
2373
- return /* @__PURE__ */ jsxs6("div", { className: "a24-tool-disclosure", children: [
2374
- /* @__PURE__ */ jsx10("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsxs6(
3003
+ return /* @__PURE__ */ jsxs9("div", { className: "a24-tool-disclosure", children: [
3004
+ /* @__PURE__ */ jsx14("div", { className: "a24-tool-trigger-row", children: /* @__PURE__ */ jsxs9(
2375
3005
  "button",
2376
3006
  {
2377
3007
  "aria-controls": contentId,
@@ -2383,12 +3013,12 @@ function AgentChatNodeActivityRow({
2383
3013
  },
2384
3014
  type: "button",
2385
3015
  children: [
2386
- /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label }),
2387
- open ? /* @__PURE__ */ jsx10(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx10(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
3016
+ /* @__PURE__ */ jsx14("span", { className: "a24-tool-trigger__label", children: label }),
3017
+ open ? /* @__PURE__ */ jsx14(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx14(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2388
3018
  ]
2389
3019
  }
2390
3020
  ) }),
2391
- open ? /* @__PURE__ */ jsx10("div", { className: "a24-tool-detail a24-tool-detail--error", id: contentId, children: failureMessage }) : null
3021
+ open ? /* @__PURE__ */ jsx14("div", { className: "a24-tool-detail a24-tool-detail--error", id: contentId, children: failureMessage }) : null
2392
3022
  ] });
2393
3023
  }
2394
3024
  function toolRowLabel(part, separateResource = false) {
@@ -2415,25 +3045,25 @@ function ToolDisclosure({
2415
3045
  renderActivityIcon,
2416
3046
  accessory
2417
3047
  }) {
2418
- const [open, setOpen] = React11.useState(false);
2419
- const contentId = React11.useId();
2420
- const expandable = React11.Children.toArray(children).length > 0;
3048
+ const [open, setOpen] = React15.useState(false);
3049
+ const contentId = React15.useId();
3050
+ const expandable = React15.Children.toArray(children).length > 0;
2421
3051
  if (!expandable) {
2422
3052
  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");
2423
- return /* @__PURE__ */ jsxs6("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2424
- onSelect && part ? /* @__PURE__ */ jsxs6("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
2425
- showOrb ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: statusLabel || "Working", kind: grouped ? "group" : "tool", part, renderActivityIcon }) : null,
2426
- /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
2427
- ] }) : /* @__PURE__ */ jsxs6("div", { className: triggerClassName, children: [
2428
- showOrb ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: statusLabel || "Working", kind: grouped ? "group" : "tool", part, renderActivityIcon }) : null,
2429
- /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label })
3053
+ return /* @__PURE__ */ jsxs9("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
3054
+ onSelect && part ? /* @__PURE__ */ jsxs9("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
3055
+ showOrb ? /* @__PURE__ */ jsx14(ToolActivityOrb, { label: statusLabel || "Working", kind: grouped ? "group" : "tool", part, renderActivityIcon }) : null,
3056
+ /* @__PURE__ */ jsx14("span", { className: "a24-tool-trigger__label", children: label })
3057
+ ] }) : /* @__PURE__ */ jsxs9("div", { className: triggerClassName, children: [
3058
+ showOrb ? /* @__PURE__ */ jsx14(ToolActivityOrb, { label: statusLabel || "Working", kind: grouped ? "group" : "tool", part, renderActivityIcon }) : null,
3059
+ /* @__PURE__ */ jsx14("span", { className: "a24-tool-trigger__label", children: label })
2430
3060
  ] }),
2431
3061
  accessory
2432
3062
  ] });
2433
3063
  }
2434
- return /* @__PURE__ */ jsxs6("div", { className: "a24-tool-disclosure", children: [
2435
- /* @__PURE__ */ jsxs6("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
2436
- /* @__PURE__ */ jsxs6(
3064
+ return /* @__PURE__ */ jsxs9("div", { className: "a24-tool-disclosure", children: [
3065
+ /* @__PURE__ */ jsxs9("div", { className: cn("a24-tool-trigger-row", root && "a24-tool-trigger-row--root"), children: [
3066
+ /* @__PURE__ */ jsxs9(
2437
3067
  "button",
2438
3068
  {
2439
3069
  "aria-controls": contentId,
@@ -2447,25 +3077,25 @@ function ToolDisclosure({
2447
3077
  },
2448
3078
  type: "button",
2449
3079
  children: [
2450
- showOrb ? /* @__PURE__ */ jsx10(ToolActivityOrb, { label: statusLabel || "Working", kind: grouped ? "group" : "tool", part, renderActivityIcon }) : null,
2451
- /* @__PURE__ */ jsx10("span", { className: "a24-tool-trigger__label", children: label }),
2452
- open ? /* @__PURE__ */ jsx10(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx10(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
3080
+ showOrb ? /* @__PURE__ */ jsx14(ToolActivityOrb, { label: statusLabel || "Working", kind: grouped ? "group" : "tool", part, renderActivityIcon }) : null,
3081
+ /* @__PURE__ */ jsx14("span", { className: "a24-tool-trigger__label", children: label }),
3082
+ open ? /* @__PURE__ */ jsx14(ChevronDown2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" }) : /* @__PURE__ */ jsx14(ChevronRight2, { "aria-hidden": "true", className: "a24-tool-trigger__chevron" })
2453
3083
  ]
2454
3084
  }
2455
3085
  ),
2456
3086
  accessory
2457
3087
  ] }),
2458
- open ? /* @__PURE__ */ jsx10("div", { className: "a24-tool-disclosure__content", id: contentId, children }) : null
3088
+ open ? /* @__PURE__ */ jsx14("div", { className: "a24-tool-disclosure__content", id: contentId, children }) : null
2459
3089
  ] });
2460
3090
  }
2461
3091
  function ToolLabel({ active, label, part, slots }) {
2462
3092
  const rendered = slots?.renderToolLabel?.(toolSlotContext(active, label, part, slots)) ?? label;
2463
- return active ? /* @__PURE__ */ jsx10("span", { className: "a24-tool-shimmer", children: rendered }) : /* @__PURE__ */ jsx10(Fragment3, { children: rendered });
3093
+ return active ? /* @__PURE__ */ jsx14("span", { className: "a24-tool-shimmer", children: rendered }) : /* @__PURE__ */ jsx14(Fragment4, { children: rendered });
2464
3094
  }
2465
3095
  function ToolList({ children }) {
2466
- const listRef = React11.useRef(null);
2467
- const [fades, setFades] = React11.useState({ bottom: false, top: false });
2468
- const updateFades = React11.useCallback(() => {
3096
+ const listRef = React15.useRef(null);
3097
+ const [fades, setFades] = React15.useState({ bottom: false, top: false });
3098
+ const updateFades = React15.useCallback(() => {
2469
3099
  const list = listRef.current;
2470
3100
  if (!list) return;
2471
3101
  const next = {
@@ -2474,7 +3104,7 @@ function ToolList({ children }) {
2474
3104
  };
2475
3105
  setFades((current) => current.bottom === next.bottom && current.top === next.top ? current : next);
2476
3106
  }, []);
2477
- React11.useEffect(() => {
3107
+ React15.useEffect(() => {
2478
3108
  updateFades();
2479
3109
  const list = listRef.current;
2480
3110
  if (!list || typeof ResizeObserver === "undefined") return;
@@ -2482,13 +3112,13 @@ function ToolList({ children }) {
2482
3112
  observer.observe(list);
2483
3113
  return () => observer.disconnect();
2484
3114
  }, [children, updateFades]);
2485
- return /* @__PURE__ */ jsx10(
3115
+ return /* @__PURE__ */ jsx14(
2486
3116
  "div",
2487
3117
  {
2488
3118
  className: "a24-tool-list-frame",
2489
3119
  "data-scroll-fade-bottom": fades.bottom ? "" : void 0,
2490
3120
  "data-scroll-fade-top": fades.top ? "" : void 0,
2491
- children: /* @__PURE__ */ jsx10("div", { className: "a24-tool-list", onScroll: updateFades, ref: listRef, role: "list", children })
3121
+ children: /* @__PURE__ */ jsx14("div", { className: "a24-tool-list", onScroll: updateFades, ref: listRef, role: "list", children })
2492
3122
  }
2493
3123
  );
2494
3124
  }
@@ -2505,13 +3135,13 @@ function AgentChatToolRow({
2505
3135
  const detail = failed ? failureMessage : optionalText(part.presentation.detail);
2506
3136
  const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
2507
3137
  const context = toolSlotContext(active, toolRowLabel(part, Boolean(slots?.onResourceAction)), part, slots);
2508
- return /* @__PURE__ */ jsx10("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsxs6(
3138
+ return /* @__PURE__ */ jsx14("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsxs9(
2509
3139
  ToolDisclosure,
2510
3140
  {
2511
3141
  renderActivityIcon: slots?.renderActivityIcon,
2512
3142
  error: failed,
2513
3143
  accessory: toolAccessory(context, slots),
2514
- label: /* @__PURE__ */ jsx10(ToolLabel, { active, label: context.label, part, slots }),
3144
+ label: /* @__PURE__ */ jsx14(ToolLabel, { active, label: context.label, part, slots }),
2515
3145
  loading: active,
2516
3146
  onExpandedChange: slots?.onExpandedChange,
2517
3147
  onSelect: slots?.onToolSelect,
@@ -2520,7 +3150,7 @@ function AgentChatToolRow({
2520
3150
  showOrb: showOrb ?? active,
2521
3151
  statusLabel: active ? context.label : void 0,
2522
3152
  children: [
2523
- detail ? /* @__PURE__ */ jsx10("div", { className: cn("a24-tool-detail", failed && "a24-tool-detail--error"), children: detail }) : null,
3153
+ detail ? /* @__PURE__ */ jsx14("div", { className: cn("a24-tool-detail", failed && "a24-tool-detail--error"), children: detail }) : null,
2524
3154
  hostDetails
2525
3155
  ]
2526
3156
  }
@@ -2540,19 +3170,19 @@ function AgentChatToolSession({
2540
3170
  parts,
2541
3171
  slots
2542
3172
  }) {
2543
- const presentedLiveRef = React11.useRef(false);
3173
+ const presentedLiveRef = React15.useRef(false);
2544
3174
  if (isLive && isLatestActivity) presentedLiveRef.current = true;
2545
3175
  const activeIndex = parts.findLastIndex((part) => isActive(part, activeToolId));
2546
3176
  const running = activeIndex >= 0;
2547
- if (parts.length === 1 && !modelTurn && !leadingModelTurn) return /* @__PURE__ */ jsx10(AgentChatToolRow, { activeToolId, part: parts[0], slots });
3177
+ if (parts.length === 1 && !modelTurn && !leadingModelTurn) return /* @__PURE__ */ jsx14(AgentChatToolRow, { activeToolId, part: parts[0], slots });
2548
3178
  const visibleIndex = running ? activeIndex : parts.length - 1;
2549
3179
  const visiblePart = parts[visibleIndex];
2550
3180
  const planning = Boolean(modelTurn);
2551
3181
  const presentingActivity = isLatestActivity && (planning || running || isLive);
2552
3182
  const failed = isLatestActivity && (visiblePart.state === "output-error" || visiblePart.state === "cancelled");
2553
3183
  const label = planning ? "Planning next moves" : isLive && isLatestActivity ? toolRowLabel(visiblePart, true) : sessionLabel(parts, visiblePart, running);
2554
- const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx10("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx10(ToolActivityReel, { initialLabel: leadingModelTurn ? "Planning next moves" : void 0, initialShownAt: leadingModelTurn?.timestamp, label }) }) : label;
2555
- return /* @__PURE__ */ jsx10(
3184
+ const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx14("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx14(ToolActivityReel, { initialLabel: leadingModelTurn ? "Planning next moves" : void 0, initialShownAt: leadingModelTurn?.timestamp, label }) }) : label;
3185
+ return /* @__PURE__ */ jsx14(
2556
3186
  ToolDisclosure,
2557
3187
  {
2558
3188
  renderActivityIcon: slots?.renderActivityIcon,
@@ -2565,7 +3195,7 @@ function AgentChatToolSession({
2565
3195
  root: true,
2566
3196
  showOrb: isLive && isLatestActivity,
2567
3197
  statusLabel: planning ? "Planning next moves" : label,
2568
- children: /* @__PURE__ */ jsx10(ToolList, { children: parts.map((part) => /* @__PURE__ */ jsx10("div", { role: "listitem", children: /* @__PURE__ */ jsx10(AgentChatToolRow, { activeToolId, part, root: false, showOrb: false, slots }) }, part.id)) })
3198
+ children: /* @__PURE__ */ jsx14(ToolList, { children: parts.map((part) => /* @__PURE__ */ jsx14("div", { role: "listitem", children: /* @__PURE__ */ jsx14(AgentChatToolRow, { activeToolId, part, root: false, showOrb: false, slots }) }, part.id)) })
2569
3199
  }
2570
3200
  );
2571
3201
  }
@@ -2586,7 +3216,7 @@ function subagentLabel(part) {
2586
3216
  return { label: `Agent ${name}, ran ${children.length} ${children.length === 1 ? "tool" : "tools"}`, running: false };
2587
3217
  }
2588
3218
  function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part, slots }) {
2589
- const presentedLiveRef = React11.useRef(false);
3219
+ const presentedLiveRef = React15.useRef(false);
2590
3220
  if (isLive && isLatestActivity) presentedLiveRef.current = true;
2591
3221
  const children = part.presentation.childTools || [];
2592
3222
  const state = subagentLabel(part);
@@ -2595,9 +3225,9 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2595
3225
  const hostDetails = failed ? null : slots?.renderToolDetails?.(part);
2596
3226
  const failureMessage = part.failure?.message || null;
2597
3227
  const presentingActivity = isLatestActivity && state.running;
2598
- const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx10("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx10(ToolActivityReel, { label: state.label }) }) : state.label;
3228
+ const labelContent = presentedLiveRef.current ? /* @__PURE__ */ jsx14("span", { className: presentingActivity ? "a24-tool-shimmer" : void 0, children: /* @__PURE__ */ jsx14(ToolActivityReel, { label: state.label }) }) : state.label;
2599
3229
  const context = toolSlotContext(presentingActivity, state.label, part, slots);
2600
- return /* @__PURE__ */ jsx10(
3230
+ return /* @__PURE__ */ jsx14(
2601
3231
  ToolDisclosure,
2602
3232
  {
2603
3233
  renderActivityIcon: slots?.renderActivityIcon,
@@ -2611,12 +3241,12 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2611
3241
  root: true,
2612
3242
  showOrb: isLive && isLatestActivity,
2613
3243
  statusLabel: state.label,
2614
- children: /* @__PURE__ */ jsxs6(ToolList, { children: [
2615
- children.map((child) => /* @__PURE__ */ jsx10("div", { className: cn("a24-child-tool", child.status === "failed" && "a24-child-tool--error"), role: "listitem", children: slots?.renderChildTool?.(child, part) ?? /* @__PURE__ */ jsxs6(Fragment3, { children: [
2616
- /* @__PURE__ */ jsx10("span", { className: cn(isLive && isLatestActivity && child.status === "running" && "a24-tool-shimmer"), children: childLabel(child) }),
2617
- child.detail ? /* @__PURE__ */ jsx10("span", { className: "a24-child-tool__detail", children: child.detail }) : null
3244
+ children: /* @__PURE__ */ jsxs9(ToolList, { children: [
3245
+ children.map((child) => /* @__PURE__ */ jsx14("div", { className: cn("a24-child-tool", child.status === "failed" && "a24-child-tool--error"), role: "listitem", children: slots?.renderChildTool?.(child, part) ?? /* @__PURE__ */ jsxs9(Fragment4, { children: [
3246
+ /* @__PURE__ */ jsx14("span", { className: cn(isLive && isLatestActivity && child.status === "running" && "a24-tool-shimmer"), children: childLabel(child) }),
3247
+ child.detail ? /* @__PURE__ */ jsx14("span", { className: "a24-child-tool__detail", children: child.detail }) : null
2618
3248
  ] }) }, child.id)),
2619
- failureMessage ? /* @__PURE__ */ jsx10("div", { className: "a24-tool-detail a24-tool-detail--error", children: failureMessage }) : null,
3249
+ failureMessage ? /* @__PURE__ */ jsx14("div", { className: "a24-tool-detail a24-tool-detail--error", children: failureMessage }) : null,
2620
3250
  hostDetails
2621
3251
  ] })
2622
3252
  }
@@ -2624,41 +3254,51 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
2624
3254
  }
2625
3255
 
2626
3256
  // src/ui/agent-response-timeline.tsx
2627
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
3257
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2628
3258
  function isInternalAskUserTool(part) {
2629
3259
  return [part.toolName, part.toolKey, part.action].some((value) => value?.trim().toLowerCase() === "runtime__ask_user");
2630
3260
  }
2631
3261
  function Shimmer({ children, className }) {
2632
- return /* @__PURE__ */ jsx11("span", { className: cn("inline-block animate-pulse", className), children });
3262
+ return /* @__PURE__ */ jsx15("span", { className: cn("inline-block animate-pulse", className), children });
2633
3263
  }
2634
3264
  function AgentChatToolPart({
2635
3265
  activeToolId,
2636
3266
  part
2637
3267
  }) {
2638
- return /* @__PURE__ */ jsx11(AgentChatToolRow, { activeToolId, part });
3268
+ return /* @__PURE__ */ jsx15(AgentChatToolRow, { activeToolId, part });
2639
3269
  }
2640
3270
  function AgentChatToolGroup({
2641
3271
  activeToolId,
2642
3272
  parts
2643
3273
  }) {
2644
- return /* @__PURE__ */ jsx11(AgentChatToolSession, { activeToolId, parts });
3274
+ return /* @__PURE__ */ jsx15(AgentChatToolSession, { activeToolId, parts });
2645
3275
  }
2646
3276
  function HitlPartRow({
2647
3277
  getHitlActionState,
3278
+ hitlLabels,
3279
+ onHitlPaint,
2648
3280
  isLoading,
2649
3281
  onHitlAction,
2650
3282
  part
2651
3283
  }) {
2652
3284
  const state = getHitlActionState?.(part);
2653
- const [comment, setComment] = React12.useState("");
3285
+ const [comment, setComment] = React16.useState("");
3286
+ const commentRef = React16.useRef(null);
3287
+ const retryActionRef = React16.useRef(null);
3288
+ React16.useEffect(() => {
3289
+ if (state?.status === "error") (commentRef.current || retryActionRef.current)?.focus();
3290
+ }, [state?.status]);
2654
3291
  const presentation = part.presentation || {};
2655
3292
  const requireComment = presentation.require_comment === true;
2656
3293
  const isTerminal = part.status !== "pending";
2657
3294
  if (part.hitlKind === "user_input") {
2658
- return /* @__PURE__ */ jsx11(
3295
+ return /* @__PURE__ */ jsx15(
2659
3296
  AskUserInteraction,
2660
3297
  {
2661
3298
  error: state?.error,
3299
+ submission: state,
3300
+ submissionLabels: hitlLabels,
3301
+ onSubmissionPaint: onHitlPaint,
2662
3302
  isBusy: isLoading || state?.status === "resuming",
2663
3303
  onSubmit: onHitlAction ? (answers) => onHitlAction(part, {
2664
3304
  action: "respond",
@@ -2672,12 +3312,14 @@ function HitlPartRow({
2672
3312
  }
2673
3313
  );
2674
3314
  }
3315
+ if (isHitlSubmissionCompact(state)) return /* @__PURE__ */ jsx15(HitlSubmissionStatus, { state, labels: hitlLabels, onPaint: onHitlPaint });
2675
3316
  if (isTerminal) return null;
2676
- return /* @__PURE__ */ jsxs7("div", { className: "a24-hitl space-y-2.5 px-1 py-2", children: [
2677
- /* @__PURE__ */ jsx11("div", { className: "a24-hitl__title text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
2678
- requireComment ? /* @__PURE__ */ jsx11(
3317
+ return /* @__PURE__ */ jsxs10("div", { className: "a24-hitl space-y-2.5 px-1 py-2", children: [
3318
+ /* @__PURE__ */ jsx15("div", { className: "a24-hitl__title text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
3319
+ requireComment ? /* @__PURE__ */ jsx15(
2679
3320
  "textarea",
2680
3321
  {
3322
+ ref: commentRef,
2681
3323
  "aria-label": "Approval comment",
2682
3324
  autoComplete: "off",
2683
3325
  className: "a24-hitl__comment min-h-20 w-full resize-y rounded-md border border-border/60 bg-background px-3 py-2 text-sm outline-none focus-visible:border-neutral-300 focus-visible:ring-0 dark:focus-visible:border-neutral-600",
@@ -2687,10 +3329,11 @@ function HitlPartRow({
2687
3329
  value: comment
2688
3330
  }
2689
3331
  ) : null,
2690
- state?.error ? /* @__PURE__ */ jsx11("div", { className: "a24-hitl__error text-sm text-destructive", children: state.error }) : null,
2691
- /* @__PURE__ */ jsx11("div", { className: "a24-hitl__actions flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ jsx11(
3332
+ state?.error ? /* @__PURE__ */ jsx15("div", { className: "a24-hitl__error text-sm text-destructive", children: state.error }) : null,
3333
+ /* @__PURE__ */ jsx15("div", { className: "a24-hitl__actions flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ jsx15(
2692
3334
  "button",
2693
3335
  {
3336
+ ref: state?.action === action || !state?.action && action === part.allowedActions[0] ? retryActionRef : void 0,
2694
3337
  "aria-label": hitlActionLabel(part, action),
2695
3338
  className: cn(
2696
3339
  "a24-hitl__action min-h-10 rounded-md px-3 text-sm font-medium transition-[background-color,color,opacity,transform] duration-150 ease-out active:scale-[0.96] disabled:pointer-events-none disabled:opacity-60",
@@ -2712,6 +3355,8 @@ function HitlPartRow({
2712
3355
  function AgentChatPart({
2713
3356
  activeToolId,
2714
3357
  getHitlActionState,
3358
+ hitlLabels,
3359
+ onHitlPaint,
2715
3360
  isLoading,
2716
3361
  isTextStreaming,
2717
3362
  message,
@@ -2721,7 +3366,7 @@ function AgentChatPart({
2721
3366
  toolSlots
2722
3367
  }) {
2723
3368
  if (part.kind === "text") {
2724
- return /* @__PURE__ */ jsx11(
3369
+ return /* @__PURE__ */ jsx15(
2725
3370
  MessageResponse,
2726
3371
  {
2727
3372
  ...responseProps,
@@ -2731,44 +3376,46 @@ function AgentChatPart({
2731
3376
  }
2732
3377
  );
2733
3378
  }
2734
- if (part.kind === "tool") return isAgentChatSubagent(part) ? /* @__PURE__ */ jsx11(AgentChatSubagentGroup, { part, slots: toolSlots }) : /* @__PURE__ */ jsx11(AgentChatToolRow, { activeToolId, part, slots: toolSlots });
2735
- if (part.kind === "model-turn") return /* @__PURE__ */ jsx11(AgentChatModelTurnRow, { part });
3379
+ if (part.kind === "tool") return isAgentChatSubagent(part) ? /* @__PURE__ */ jsx15(AgentChatSubagentGroup, { part, slots: toolSlots }) : /* @__PURE__ */ jsx15(AgentChatToolRow, { activeToolId, part, slots: toolSlots });
3380
+ if (part.kind === "model-turn") return /* @__PURE__ */ jsx15(AgentChatModelTurnRow, { part });
2736
3381
  if (part.kind === "reasoning") {
2737
3382
  const label = part.text || part.label || "Thinking";
2738
- return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ jsx11(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ jsx11("div", { className: "text-sm text-muted-foreground", children: label });
3383
+ return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ jsx15(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ jsx15("div", { className: "text-sm text-muted-foreground", children: label });
2739
3384
  }
2740
3385
  if (part.kind === "context-compression") {
2741
- return /* @__PURE__ */ jsx11(AgentChatContextCompressionRow, { part });
3386
+ return /* @__PURE__ */ jsx15(AgentChatContextCompressionRow, { part });
2742
3387
  }
2743
3388
  if (part.kind === "ui-blocks") {
2744
3389
  if (part.state === "output-error") {
2745
- return /* @__PURE__ */ jsx11("div", { className: "a24-timeline-error text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
3390
+ return /* @__PURE__ */ jsx15("div", { className: "a24-timeline-error text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
2746
3391
  }
2747
- return part.bundle ? /* @__PURE__ */ jsx11(SafeUiBlocks, { bundle: part.bundle }) : /* @__PURE__ */ jsx11("div", { className: "text-sm text-muted-foreground", children: part.state === "input-streaming" ? /* @__PURE__ */ jsx11(Shimmer, { children: "Rendering UI block" }) : "Rendered UI block" });
3392
+ return part.bundle ? /* @__PURE__ */ jsx15(SafeUiBlocks, { bundle: part.bundle }) : /* @__PURE__ */ jsx15("div", { className: "text-sm text-muted-foreground", children: part.state === "input-streaming" ? /* @__PURE__ */ jsx15(Shimmer, { children: "Rendering UI block" }) : "Rendered UI block" });
2748
3393
  }
2749
3394
  if (part.kind === "hitl") {
2750
- return /* @__PURE__ */ jsx11(
3395
+ return /* @__PURE__ */ jsx15(
2751
3396
  HitlPartRow,
2752
3397
  {
2753
3398
  getHitlActionState,
3399
+ hitlLabels,
3400
+ onHitlPaint,
2754
3401
  isLoading,
2755
3402
  onHitlAction,
2756
3403
  part
2757
3404
  }
2758
3405
  );
2759
3406
  }
2760
- if (part.kind === "error") return /* @__PURE__ */ jsx11("div", { className: "a24-timeline-error text-sm text-destructive", role: "alert", children: part.errorText });
3407
+ if (part.kind === "error") return /* @__PURE__ */ jsx15("div", { className: "a24-timeline-error text-sm text-destructive", role: "alert", children: part.errorText });
2761
3408
  if (part.kind === "source") {
2762
3409
  const href = safeExternalUrl(part.url);
2763
- return href ? /* @__PURE__ */ jsx11("a", { className: "a24-source-link", href, rel: "noopener noreferrer", target: "_blank", children: part.title }) : /* @__PURE__ */ jsx11("span", { className: "a24-source-link", children: part.title });
3410
+ return href ? /* @__PURE__ */ jsx15("a", { className: "a24-source-link", href, rel: "noopener noreferrer", target: "_blank", children: part.title }) : /* @__PURE__ */ jsx15("span", { className: "a24-source-link", children: part.title });
2764
3411
  }
2765
3412
  if (part.kind === "citation") {
2766
3413
  const href = safeExternalUrl(part.url);
2767
3414
  const label = part.label || "Citation";
2768
- return href ? /* @__PURE__ */ jsx11("a", { className: "a24-citation", href, rel: "noopener noreferrer", target: "_blank", children: label }) : /* @__PURE__ */ jsx11("span", { className: "a24-citation", children: label });
3415
+ return href ? /* @__PURE__ */ jsx15("a", { className: "a24-citation", href, rel: "noopener noreferrer", target: "_blank", children: label }) : /* @__PURE__ */ jsx15("span", { className: "a24-citation", children: label });
2769
3416
  }
2770
- if (part.kind === "attachment") return /* @__PURE__ */ jsx11("div", { className: "a24-output-attachment", children: part.attachment.filename || "Attachment" });
2771
- if (part.kind === "data") return /* @__PURE__ */ jsx11("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
3417
+ if (part.kind === "attachment") return /* @__PURE__ */ jsx15("div", { className: "a24-output-attachment", children: part.attachment.filename || "Attachment" });
3418
+ if (part.kind === "data") return /* @__PURE__ */ jsx15("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
2772
3419
  return null;
2773
3420
  }
2774
3421
  function safeExternalUrl(value) {
@@ -2782,28 +3429,28 @@ function safeExternalUrl(value) {
2782
3429
  }
2783
3430
  function SafeUiBlocks({ bundle }) {
2784
3431
  const rows = Array.isArray(bundle.rows) ? bundle.rows : [];
2785
- return /* @__PURE__ */ jsxs7("section", { "aria-label": typeof bundle.title === "string" ? bundle.title : "Agent result", className: "a24-ui-blocks", children: [
2786
- typeof bundle.title === "string" ? /* @__PURE__ */ jsx11("h3", { children: bundle.title }) : null,
3432
+ return /* @__PURE__ */ jsxs10("section", { "aria-label": typeof bundle.title === "string" ? bundle.title : "Agent result", className: "a24-ui-blocks", children: [
3433
+ typeof bundle.title === "string" ? /* @__PURE__ */ jsx15("h3", { children: bundle.title }) : null,
2787
3434
  rows.map((rawRow, rowIndex) => {
2788
3435
  const row = rawRow && typeof rawRow === "object" && !Array.isArray(rawRow) ? rawRow : {};
2789
3436
  const blocks = Array.isArray(row.blocks) ? row.blocks : [];
2790
- return /* @__PURE__ */ jsx11("div", { className: "a24-ui-blocks__row", children: blocks.map((rawBlock, blockIndex) => {
3437
+ return /* @__PURE__ */ jsx15("div", { className: "a24-ui-blocks__row", children: blocks.map((rawBlock, blockIndex) => {
2791
3438
  const block = rawBlock && typeof rawBlock === "object" && !Array.isArray(rawBlock) ? rawBlock : {};
2792
3439
  const title = typeof block.title === "string" ? block.title : "Result";
2793
3440
  const kind = String(block.kind || "note");
2794
3441
  if (kind === "table" && Array.isArray(block.columns) && Array.isArray(block.rows)) {
2795
- return /* @__PURE__ */ jsxs7("div", { className: "a24-ui-block", children: [
2796
- /* @__PURE__ */ jsx11("h4", { children: title }),
2797
- /* @__PURE__ */ jsx11("div", { className: "a24-ui-table-scroll", children: /* @__PURE__ */ jsxs7("table", { children: [
2798
- /* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsx11("tr", { children: block.columns.map((column, index) => /* @__PURE__ */ jsx11("th", { children: String(column) }, index)) }) }),
2799
- /* @__PURE__ */ jsx11("tbody", { children: block.rows.map((rawCells, index) => /* @__PURE__ */ jsx11("tr", { children: (Array.isArray(rawCells) ? rawCells : []).map((cell, cellIndex) => /* @__PURE__ */ jsx11("td", { children: String(cell) }, cellIndex)) }, index)) })
3442
+ return /* @__PURE__ */ jsxs10("div", { className: "a24-ui-block", children: [
3443
+ /* @__PURE__ */ jsx15("h4", { children: title }),
3444
+ /* @__PURE__ */ jsx15("div", { className: "a24-ui-table-scroll", children: /* @__PURE__ */ jsxs10("table", { children: [
3445
+ /* @__PURE__ */ jsx15("thead", { children: /* @__PURE__ */ jsx15("tr", { children: block.columns.map((column, index) => /* @__PURE__ */ jsx15("th", { children: String(column) }, index)) }) }),
3446
+ /* @__PURE__ */ jsx15("tbody", { children: block.rows.map((rawCells, index) => /* @__PURE__ */ jsx15("tr", { children: (Array.isArray(rawCells) ? rawCells : []).map((cell, cellIndex) => /* @__PURE__ */ jsx15("td", { children: String(cell) }, cellIndex)) }, index)) })
2800
3447
  ] }) })
2801
3448
  ] }, String(block.id || blockIndex));
2802
3449
  }
2803
3450
  const value = block.value ?? block.text ?? "";
2804
- return /* @__PURE__ */ jsxs7("div", { className: "a24-ui-block", children: [
2805
- /* @__PURE__ */ jsx11("h4", { children: title }),
2806
- /* @__PURE__ */ jsx11("p", { children: String(value) })
3451
+ return /* @__PURE__ */ jsxs10("div", { className: "a24-ui-block", children: [
3452
+ /* @__PURE__ */ jsx15("h4", { children: title }),
3453
+ /* @__PURE__ */ jsx15("p", { children: String(value) })
2807
3454
  ] }, String(block.id || blockIndex));
2808
3455
  }) }, `row-${rowIndex}`);
2809
3456
  })
@@ -2811,6 +3458,8 @@ function SafeUiBlocks({ bundle }) {
2811
3458
  }
2812
3459
  function AgentResponseTimeline({
2813
3460
  getHitlActionState,
3461
+ hitlLabels,
3462
+ onHitlPaint,
2814
3463
  isLoading = false,
2815
3464
  message,
2816
3465
  nodeActivityMode = "default",
@@ -2823,7 +3472,7 @@ function AgentResponseTimeline({
2823
3472
  toolViewMode = "closed"
2824
3473
  }) {
2825
3474
  isLoading = isLoading && !message.responseCompletion;
2826
- const parts = (displayParts || message.parts || []).filter((part) => (part.kind !== "tool" || !isInternalAskUserTool(part)) && (part.kind !== "hitl" || part.hitlKind === "user_input" || part.status === "pending") && (part.kind !== "model-turn" || part.turnKind === "agent") && (part.kind !== "node-activity" || nodeActivityMode === "all" || nodeActivityMode === "default" && part.defaultChatVisible));
3475
+ const parts = (displayParts || message.parts || []).filter((part) => (part.kind !== "tool" || !isInternalAskUserTool(part)) && (part.kind !== "hitl" || part.hitlKind === "user_input" || part.status === "pending" || getHitlActionState?.(part)?.status === "accepted") && (part.kind !== "model-turn" || part.turnKind === "agent") && (part.kind !== "node-activity" || nodeActivityMode === "all" || nodeActivityMode === "default" && part.defaultChatVisible));
2827
3476
  const toolParts = parts.filter((part) => part.kind === "tool");
2828
3477
  const activeToolId = latestRunningAgentChatToolId(toolParts);
2829
3478
  const activeTextPartId = getActiveStreamingTextPartId(
@@ -2837,42 +3486,44 @@ function AgentResponseTimeline({
2837
3486
  if (segment.kind === "tool") {
2838
3487
  const isLatestActivity = segmentIndex === segments.length - 1;
2839
3488
  const showOrb = toolViewMode === "closed" ? isLoading && isLatestActivity : Boolean(activeToolId && (segment.part.id === activeToolId || segment.part.toolCallId === activeToolId));
2840
- rendered.push(/* @__PURE__ */ jsx11(AgentChatToolRow, { activeToolId, part: segment.part, showOrb, slots: toolSlots }, segment.part.id));
3489
+ rendered.push(/* @__PURE__ */ jsx15(AgentChatToolRow, { activeToolId, part: segment.part, showOrb, slots: toolSlots }, segment.part.id));
2841
3490
  continue;
2842
3491
  }
2843
3492
  if (segment.kind === "tool-session") {
2844
- rendered.push(/* @__PURE__ */ jsx11(AgentChatToolSession, { activeToolId, isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, leadingModelTurn: segment.leadingModelTurn, modelTurn: segment.modelTurn, parts: segment.parts, slots: toolSlots }, `tool-session-${segment.parts[0].id}`));
3493
+ rendered.push(/* @__PURE__ */ jsx15(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}`));
2845
3494
  continue;
2846
3495
  }
2847
3496
  if (segment.kind === "subagent") {
2848
- rendered.push(/* @__PURE__ */ jsx11(AgentChatSubagentGroup, { isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, part: segment.part, slots: toolSlots }, segment.part.id));
3497
+ rendered.push(/* @__PURE__ */ jsx15(AgentChatSubagentGroup, { isLatestActivity: segmentIndex === segments.length - 1, isLive: isLoading, part: segment.part, slots: toolSlots }, segment.part.id));
2849
3498
  continue;
2850
3499
  }
2851
3500
  const part = segment.part;
2852
3501
  if (part.kind === "model-turn") {
2853
3502
  const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
2854
3503
  activeActivityClaimed = true;
2855
- rendered.push(/* @__PURE__ */ jsx11(AgentChatActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, label: "Planning next moves", modelTurnId: part.modelTurnId }, key));
3504
+ rendered.push(/* @__PURE__ */ jsx15(AgentChatActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, label: "Planning next moves", modelTurnId: part.modelTurnId }, key));
2856
3505
  continue;
2857
3506
  }
2858
3507
  if (part.kind === "node-activity") {
2859
3508
  const key = activeActivityClaimed ? part.id : `${message.id}-active-activity`;
2860
3509
  if (part.status === "running") activeActivityClaimed = true;
2861
3510
  rendered.push(
2862
- part.status === "running" ? /* @__PURE__ */ jsx11(AgentChatActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, label: part.label, onSelect: onNodeSelect ? () => onNodeSelect(part) : void 0 }, key) : /* @__PURE__ */ jsx11(AgentChatNodeActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, onSelect: onNodeSelect, part }, part.id)
3511
+ part.status === "running" ? /* @__PURE__ */ jsx15(AgentChatActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, label: part.label, onSelect: onNodeSelect ? () => onNodeSelect(part) : void 0 }, key) : /* @__PURE__ */ jsx15(AgentChatNodeActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, onSelect: onNodeSelect, part }, part.id)
2863
3512
  );
2864
3513
  continue;
2865
3514
  }
2866
3515
  if (part.kind === "ui-blocks" && renderUiBlocks) {
2867
- rendered.push(/* @__PURE__ */ jsx11(React12.Fragment, { children: renderUiBlocks(part) }, part.id));
3516
+ rendered.push(/* @__PURE__ */ jsx15(React16.Fragment, { children: renderUiBlocks(part) }, part.id));
2868
3517
  continue;
2869
3518
  }
2870
3519
  rendered.push(
2871
- /* @__PURE__ */ jsx11(React12.Fragment, { children: /* @__PURE__ */ jsx11(
3520
+ /* @__PURE__ */ jsx15(React16.Fragment, { children: /* @__PURE__ */ jsx15(
2872
3521
  AgentChatPart,
2873
3522
  {
2874
3523
  activeToolId,
2875
3524
  getHitlActionState,
3525
+ hitlLabels,
3526
+ onHitlPaint,
2876
3527
  isLoading,
2877
3528
  isTextStreaming: part.kind === "text" && part.id === activeTextPartId,
2878
3529
  message,
@@ -2885,16 +3536,16 @@ function AgentResponseTimeline({
2885
3536
  );
2886
3537
  }
2887
3538
  if (rendered.length === 0 && message.content) {
2888
- rendered.push(/* @__PURE__ */ jsx11(MessageResponse, { children: message.content }, `${message.id}-fallback`));
3539
+ rendered.push(/* @__PURE__ */ jsx15(MessageResponse, { children: message.content }, `${message.id}-fallback`));
2889
3540
  }
2890
3541
  if (rendered.length === 0 && isLoading) {
2891
- rendered.push(/* @__PURE__ */ jsx11(AgentChatActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, label: "Thinking" }, `${message.id}-active-activity`));
3542
+ rendered.push(/* @__PURE__ */ jsx15(AgentChatActivityRow, { renderActivityIcon: toolSlots?.renderActivityIcon, label: "Thinking" }, `${message.id}-active-activity`));
2892
3543
  }
2893
- return /* @__PURE__ */ jsx11("div", { className: "space-y-3", children: rendered });
3544
+ return /* @__PURE__ */ jsx15("div", { className: "space-y-3", children: rendered });
2894
3545
  }
2895
3546
 
2896
3547
  // src/ui/agent-chat-message.tsx
2897
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
3548
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
2898
3549
  var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
2899
3550
  var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
2900
3551
  function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
@@ -2907,8 +3558,8 @@ function AgentChatUserMessageContent({
2907
3558
  showLessLabel = "Show less",
2908
3559
  showMoreLabel = "Show more"
2909
3560
  }) {
2910
- const [isExpanded, setIsExpanded] = React13.useState(false);
2911
- const contentId = React13.useId();
3561
+ const [isExpanded, setIsExpanded] = React17.useState(false);
3562
+ const contentId = React17.useId();
2912
3563
  const shouldCollapse = shouldCollapseUserMessage(content, collapseThreshold);
2913
3564
  const Icon = isExpanded ? ChevronUp : ChevronDown3;
2914
3565
  const clampedStyle = shouldCollapse && !isExpanded ? {
@@ -2917,9 +3568,9 @@ function AgentChatUserMessageContent({
2917
3568
  display: "-webkit-box",
2918
3569
  overflow: "hidden"
2919
3570
  } : void 0;
2920
- return /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-col gap-3", children: [
2921
- /* @__PURE__ */ jsx12("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
2922
- shouldCollapse ? /* @__PURE__ */ jsxs8(
3571
+ return /* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 flex-col gap-3", children: [
3572
+ /* @__PURE__ */ jsx16("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
3573
+ shouldCollapse ? /* @__PURE__ */ jsxs11(
2923
3574
  "button",
2924
3575
  {
2925
3576
  "aria-controls": contentId,
@@ -2932,7 +3583,7 @@ function AgentChatUserMessageContent({
2932
3583
  type: "button",
2933
3584
  children: [
2934
3585
  isExpanded ? showLessLabel : showMoreLabel,
2935
- /* @__PURE__ */ jsx12(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
3586
+ /* @__PURE__ */ jsx16(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
2936
3587
  ]
2937
3588
  }
2938
3589
  ) : null
@@ -2942,9 +3593,9 @@ function AgentChatUserMessageActionRow({
2942
3593
  children,
2943
3594
  className
2944
3595
  }) {
2945
- const rowRef = React13.useRef(null);
2946
- const [visible, setVisible] = React13.useState(false);
2947
- React13.useEffect(() => {
3596
+ const rowRef = React17.useRef(null);
3597
+ const [visible, setVisible] = React17.useState(false);
3598
+ React17.useEffect(() => {
2948
3599
  const message = rowRef.current?.closest('[data-slot="message"]');
2949
3600
  if (!message) return;
2950
3601
  const show = () => setVisible(true);
@@ -2963,7 +3614,7 @@ function AgentChatUserMessageActionRow({
2963
3614
  message.removeEventListener("focusout", hideWhenFocusLeaves);
2964
3615
  };
2965
3616
  }, []);
2966
- return /* @__PURE__ */ jsx12(
3617
+ return /* @__PURE__ */ jsx16(
2967
3618
  "div",
2968
3619
  {
2969
3620
  ref: rowRef,
@@ -2983,6 +3634,8 @@ function AgentChatMessage({
2983
3634
  contentClassName,
2984
3635
  dir,
2985
3636
  getHitlActionState,
3637
+ hitlLabels,
3638
+ onHitlPaint,
2986
3639
  message,
2987
3640
  nodeActivityMode,
2988
3641
  onHitlAction,
@@ -3002,7 +3655,7 @@ function AgentChatMessage({
3002
3655
  const resolvedUserContent = userMessageContent ?? message.content;
3003
3656
  const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
3004
3657
  const showAttachments = Boolean(message.attachments?.length) && (message.role === "user" || showAssistantAttachments);
3005
- const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ jsx12(
3658
+ const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ jsx16(
3006
3659
  AgentChatDefaultActions,
3007
3660
  {
3008
3661
  additionalActions,
@@ -3012,14 +3665,14 @@ function AgentChatMessage({
3012
3665
  }
3013
3666
  ) : null);
3014
3667
  const defaultUserActions = !actions && Boolean(actionHandlers) && !isAssistant;
3015
- return /* @__PURE__ */ jsxs8(
3668
+ return /* @__PURE__ */ jsxs11(
3016
3669
  ChatMessage,
3017
3670
  {
3018
3671
  className,
3019
3672
  dir,
3020
3673
  from: message.role,
3021
3674
  children: [
3022
- showAttachments ? /* @__PURE__ */ jsx12(
3675
+ showAttachments ? /* @__PURE__ */ jsx16(
3023
3676
  ChatAttachmentRows,
3024
3677
  {
3025
3678
  attachments: message.attachments || [],
@@ -3028,17 +3681,19 @@ function AgentChatMessage({
3028
3681
  resolveContent: attachmentContentResolver
3029
3682
  }
3030
3683
  ) : null,
3031
- shouldRenderContent ? /* @__PURE__ */ jsxs8(
3684
+ shouldRenderContent ? /* @__PURE__ */ jsxs11(
3032
3685
  ChatMessageContent,
3033
3686
  {
3034
3687
  className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
3035
3688
  dir,
3036
3689
  from: message.role,
3037
3690
  children: [
3038
- isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx12(
3691
+ isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx16(
3039
3692
  Timeline,
3040
3693
  {
3041
3694
  getHitlActionState,
3695
+ hitlLabels,
3696
+ onHitlPaint,
3042
3697
  isLoading: isStreaming,
3043
3698
  message,
3044
3699
  nodeActivityMode,
@@ -3046,7 +3701,7 @@ function AgentChatMessage({
3046
3701
  parts: message.parts
3047
3702
  }
3048
3703
  ) : null,
3049
- !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx12(
3704
+ !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx16(
3050
3705
  AgentChatUserMessageContent,
3051
3706
  {
3052
3707
  collapsedLines: userMessageCollapsedLines,
@@ -3059,18 +3714,22 @@ function AgentChatMessage({
3059
3714
  ]
3060
3715
  }
3061
3716
  ) : null,
3062
- renderedActions ? defaultUserActions ? /* @__PURE__ */ jsx12(AgentChatUserMessageActionRow, { className: actionsClassName, children: renderedActions }) : /* @__PURE__ */ jsx12("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
3717
+ renderedActions ? defaultUserActions ? /* @__PURE__ */ jsx16(AgentChatUserMessageActionRow, { className: actionsClassName, children: renderedActions }) : /* @__PURE__ */ jsx16("div", { className: cn(
3718
+ dir === "rtl" ? "mt-1 h-9 w-full" : "mt-1 h-9 w-full -translate-x-2",
3719
+ isAssistant && "a24-chat-message-action-row--assistant",
3720
+ actionsClassName
3721
+ ), children: renderedActions }) : null
3063
3722
  ]
3064
3723
  }
3065
3724
  );
3066
3725
  }
3067
3726
 
3068
3727
  // src/ui/bubble.tsx
3069
- import { cva as cva2 } from "class-variance-authority";
3728
+ import { cva as cva3 } from "class-variance-authority";
3070
3729
  import { Slot as Slot2 } from "@radix-ui/react-slot";
3071
- import { jsx as jsx13 } from "react/jsx-runtime";
3730
+ import { jsx as jsx17 } from "react/jsx-runtime";
3072
3731
  function BubbleGroup({ className, ...props }) {
3073
- return /* @__PURE__ */ jsx13(
3732
+ return /* @__PURE__ */ jsx17(
3074
3733
  "div",
3075
3734
  {
3076
3735
  "data-slot": "bubble-group",
@@ -3079,7 +3738,7 @@ function BubbleGroup({ className, ...props }) {
3079
3738
  }
3080
3739
  );
3081
3740
  }
3082
- var bubbleVariants = cva2(
3741
+ var bubbleVariants = cva3(
3083
3742
  "group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
3084
3743
  {
3085
3744
  variants: {
@@ -3104,7 +3763,7 @@ function Bubble({
3104
3763
  className,
3105
3764
  ...props
3106
3765
  }) {
3107
- return /* @__PURE__ */ jsx13(
3766
+ return /* @__PURE__ */ jsx17(
3108
3767
  "div",
3109
3768
  {
3110
3769
  "data-slot": "bubble",
@@ -3121,7 +3780,7 @@ function BubbleContent({
3121
3780
  ...props
3122
3781
  }) {
3123
3782
  const Comp = asChild ? Slot2 : "div";
3124
- return /* @__PURE__ */ jsx13(
3783
+ return /* @__PURE__ */ jsx17(
3125
3784
  Comp,
3126
3785
  {
3127
3786
  "data-slot": "bubble-content",
@@ -3133,7 +3792,7 @@ function BubbleContent({
3133
3792
  }
3134
3793
  );
3135
3794
  }
3136
- var bubbleReactionsVariants = cva2(
3795
+ var bubbleReactionsVariants = cva3(
3137
3796
  "absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0",
3138
3797
  {
3139
3798
  variants: {
@@ -3158,7 +3817,7 @@ function BubbleReactions({
3158
3817
  className,
3159
3818
  ...props
3160
3819
  }) {
3161
- return /* @__PURE__ */ jsx13(
3820
+ return /* @__PURE__ */ jsx17(
3162
3821
  "div",
3163
3822
  {
3164
3823
  "data-slot": "bubble-reactions",
@@ -3171,10 +3830,10 @@ function BubbleReactions({
3171
3830
  }
3172
3831
 
3173
3832
  // src/ui/marker.tsx
3174
- import { cva as cva3 } from "class-variance-authority";
3833
+ import { cva as cva4 } from "class-variance-authority";
3175
3834
  import { Slot as Slot3 } from "@radix-ui/react-slot";
3176
- import { jsx as jsx14 } from "react/jsx-runtime";
3177
- var markerVariants = cva3(
3835
+ import { jsx as jsx18 } from "react/jsx-runtime";
3836
+ var markerVariants = cva4(
3178
3837
  "group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground",
3179
3838
  {
3180
3839
  variants: {
@@ -3193,7 +3852,7 @@ function Marker({
3193
3852
  ...props
3194
3853
  }) {
3195
3854
  const Comp = asChild ? Slot3 : "div";
3196
- return /* @__PURE__ */ jsx14(
3855
+ return /* @__PURE__ */ jsx18(
3197
3856
  Comp,
3198
3857
  {
3199
3858
  "data-slot": "marker",
@@ -3204,7 +3863,7 @@ function Marker({
3204
3863
  );
3205
3864
  }
3206
3865
  function MarkerIcon({ className, ...props }) {
3207
- return /* @__PURE__ */ jsx14(
3866
+ return /* @__PURE__ */ jsx18(
3208
3867
  "span",
3209
3868
  {
3210
3869
  "data-slot": "marker-icon",
@@ -3218,7 +3877,7 @@ function MarkerIcon({ className, ...props }) {
3218
3877
  );
3219
3878
  }
3220
3879
  function MarkerContent({ className, ...props }) {
3221
- return /* @__PURE__ */ jsx14(
3880
+ return /* @__PURE__ */ jsx18(
3222
3881
  "span",
3223
3882
  {
3224
3883
  "data-slot": "marker-content",
@@ -3232,7 +3891,7 @@ function MarkerContent({ className, ...props }) {
3232
3891
  }
3233
3892
 
3234
3893
  // src/ui/mcp-connect-required-card.tsx
3235
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
3894
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
3236
3895
  var STATUS_LABELS = {
3237
3896
  pending: "Connect",
3238
3897
  connecting: "Connecting",
@@ -3256,7 +3915,7 @@ function McpConnectRequiredCard({
3256
3915
  const isBusy = loading || status === "connecting" || status === "resuming";
3257
3916
  const isConnected = status === "connected";
3258
3917
  const buttonDisabled = disabled || isBusy || isConnected || !onConnect;
3259
- return /* @__PURE__ */ jsx15(
3918
+ return /* @__PURE__ */ jsx19(
3260
3919
  "div",
3261
3920
  {
3262
3921
  "data-agents24-mcp-connect-card": true,
@@ -3266,13 +3925,13 @@ function McpConnectRequiredCard({
3266
3925
  className
3267
3926
  ),
3268
3927
  ...props,
3269
- children: /* @__PURE__ */ jsxs9("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
3270
- /* @__PURE__ */ jsxs9("div", { className: "min-w-0", children: [
3271
- /* @__PURE__ */ jsx15("div", { className: "truncate text-sm font-medium", children: label }),
3272
- /* @__PURE__ */ jsx15("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
3273
- status === "error" && error ? /* @__PURE__ */ jsx15("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
3928
+ children: /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
3929
+ /* @__PURE__ */ jsxs12("div", { className: "min-w-0", children: [
3930
+ /* @__PURE__ */ jsx19("div", { className: "truncate text-sm font-medium", children: label }),
3931
+ /* @__PURE__ */ jsx19("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
3932
+ status === "error" && error ? /* @__PURE__ */ jsx19("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
3274
3933
  ] }),
3275
- /* @__PURE__ */ jsx15(
3934
+ /* @__PURE__ */ jsx19(
3276
3935
  "button",
3277
3936
  {
3278
3937
  type: "button",
@@ -3329,6 +3988,17 @@ export {
3329
3988
  ChatMessageAction,
3330
3989
  ChatMessageActions,
3331
3990
  ChatMessageContent,
3991
+ CodeBlock,
3992
+ CodeBlockActions,
3993
+ CodeBlockContent,
3994
+ CodeBlockCopyButton,
3995
+ CodeBlockDownloadButton,
3996
+ CodeBlockFooter,
3997
+ CodeBlockHeader,
3998
+ CodeBlockLine,
3999
+ CodeBlockTitle,
4000
+ CodeBlockWrapButton,
4001
+ HitlSubmissionStatus,
3332
4002
  Marker,
3333
4003
  MarkerContent,
3334
4004
  MarkerIcon,
@@ -3355,10 +4025,12 @@ export {
3355
4025
  cn,
3356
4026
  contextStatusMetrics,
3357
4027
  createAgentChatComposerFile,
4028
+ defaultHitlSubmissionLabels,
3358
4029
  hitlActionLabel,
3359
4030
  hitlTitle,
3360
4031
  isAgentChatSubagent,
3361
4032
  isAgentChatToolRunning,
4033
+ isHitlSubmissionCompact,
3362
4034
  latestRunningAgentChatToolId,
3363
4035
  markerVariants,
3364
4036
  partitionAgentChatToolTimeline,
@@ -3370,6 +4042,7 @@ export {
3370
4042
  useAudioRecorder,
3371
4043
  useChatComposerFocus,
3372
4044
  useCompletionActionEntrance,
4045
+ useHighlightedCode,
3373
4046
  useLiveCompletionRuns
3374
4047
  };
3375
4048
  //# sourceMappingURL=index.js.map