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