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