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