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