@tangle-network/agent-app 0.43.50 → 0.43.51
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/dist/assistant/index.d.ts +1 -1
- package/dist/assistant/index.js +2 -2
- package/dist/attachment-validation-DX2KIzMC.d.ts +219 -0
- package/dist/chat-routes/index.d.ts +90 -20
- package/dist/chat-routes/index.js +308 -169
- package/dist/chat-routes/index.js.map +1 -1
- package/dist/chunk-3EKOSBYL.js +239 -0
- package/dist/chunk-3EKOSBYL.js.map +1 -0
- package/dist/{chunk-O6H2WD3I.js → chunk-EIG7ZQW2.js} +854 -369
- package/dist/chunk-EIG7ZQW2.js.map +1 -0
- package/dist/web-react/index.d.ts +175 -5
- package/dist/web-react/index.js +15 -2
- package/package.json +1 -1
- package/dist/chunk-LCNY3DCM.js +0 -84
- package/dist/chunk-LCNY3DCM.js.map +0 -1
- package/dist/chunk-O6H2WD3I.js.map +0 -1
- package/dist/file-index-b26ee-_R.d.ts +0 -114
|
@@ -1,6 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ATTACHMENT_ACCEPT,
|
|
3
|
+
ATTACHMENT_MAX_COUNT,
|
|
4
|
+
MAX_ATTACHMENT_TOTAL_BYTES,
|
|
5
|
+
MAX_BINARY_ATTACHMENT_BYTES,
|
|
6
|
+
MAX_TEXT_ATTACHMENT_BYTES,
|
|
7
|
+
attachmentSizeErrorMessage,
|
|
8
|
+
attachmentTotalSizeErrorMessage,
|
|
9
|
+
checkAttachmentType,
|
|
10
|
+
sanitizeAttachmentFileName,
|
|
11
|
+
sniffBinary
|
|
12
|
+
} from "./chunk-3EKOSBYL.js";
|
|
1
13
|
import {
|
|
2
14
|
stepActivityFlowTrace
|
|
3
15
|
} from "./chunk-2QI7XV2T.js";
|
|
16
|
+
import {
|
|
17
|
+
attachmentPartsFromMessageParts,
|
|
18
|
+
formatBytes
|
|
19
|
+
} from "./chunk-JGYOYY5D.js";
|
|
4
20
|
import {
|
|
5
21
|
cancelStatusFor,
|
|
6
22
|
fieldAcceptsFreeText,
|
|
@@ -21,7 +37,7 @@ import {
|
|
|
21
37
|
} from "./chunk-MCJSS6SM.js";
|
|
22
38
|
|
|
23
39
|
// src/web-react/index.tsx
|
|
24
|
-
import { useEffect as
|
|
40
|
+
import { useEffect as useEffect10, useMemo as useMemo8, useRef as useRef9, useState as useState14, memo } from "react";
|
|
25
41
|
|
|
26
42
|
// src/web-react/smooth-text.ts
|
|
27
43
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -1145,6 +1161,176 @@ function DurableChatCards({
|
|
|
1145
1161
|
}) });
|
|
1146
1162
|
}
|
|
1147
1163
|
|
|
1164
|
+
// src/web-react/message-attachments.tsx
|
|
1165
|
+
import { useCallback, useEffect as useEffect5, useState as useState6 } from "react";
|
|
1166
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1167
|
+
function FileGlyph({ className }) {
|
|
1168
|
+
return /* @__PURE__ */ jsxs6("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
1169
|
+
/* @__PURE__ */ jsx8("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
1170
|
+
/* @__PURE__ */ jsx8("path", { d: "M14 2v6h6" })
|
|
1171
|
+
] });
|
|
1172
|
+
}
|
|
1173
|
+
function ImageGlyph({ className }) {
|
|
1174
|
+
return /* @__PURE__ */ jsxs6("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
1175
|
+
/* @__PURE__ */ jsx8("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
1176
|
+
/* @__PURE__ */ jsx8("circle", { cx: "9", cy: "9", r: "2" }),
|
|
1177
|
+
/* @__PURE__ */ jsx8("path", { d: "m21 15-5-5L5 21" })
|
|
1178
|
+
] });
|
|
1179
|
+
}
|
|
1180
|
+
function WarningGlyph({ className }) {
|
|
1181
|
+
return /* @__PURE__ */ jsx8("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx8("path", { d: "M12 9v4m0 4h.01M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z" }) });
|
|
1182
|
+
}
|
|
1183
|
+
function iconForMediaType(mediaType) {
|
|
1184
|
+
return mediaType?.startsWith("image/") ? ImageGlyph : FileGlyph;
|
|
1185
|
+
}
|
|
1186
|
+
var attachmentFileCache = /* @__PURE__ */ new Map();
|
|
1187
|
+
function __resetAttachmentFileCacheForTests() {
|
|
1188
|
+
attachmentFileCache.clear();
|
|
1189
|
+
}
|
|
1190
|
+
async function defaultFetchFile(url) {
|
|
1191
|
+
return fetch(url, { credentials: "same-origin" });
|
|
1192
|
+
}
|
|
1193
|
+
async function fetchAttachmentFile(url, fetchFile) {
|
|
1194
|
+
try {
|
|
1195
|
+
const res = await fetchFile(url);
|
|
1196
|
+
if (!res.ok) return { ok: false, message: `Failed to load attachment (${res.status})` };
|
|
1197
|
+
return { ok: true, blob: await res.blob() };
|
|
1198
|
+
} catch (err) {
|
|
1199
|
+
return { ok: false, message: err instanceof Error && err.message ? err.message : "Network error loading attachment" };
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
function loadAttachmentFile(url, fetchFile = defaultFetchFile) {
|
|
1203
|
+
const cached = attachmentFileCache.get(url);
|
|
1204
|
+
if (cached) return cached;
|
|
1205
|
+
const promise = fetchAttachmentFile(url, fetchFile);
|
|
1206
|
+
attachmentFileCache.set(url, promise);
|
|
1207
|
+
void promise.then((result) => {
|
|
1208
|
+
if (!result.ok && attachmentFileCache.get(url) === promise) attachmentFileCache.delete(url);
|
|
1209
|
+
});
|
|
1210
|
+
return promise;
|
|
1211
|
+
}
|
|
1212
|
+
function triggerAttachmentDownload(name, blob) {
|
|
1213
|
+
try {
|
|
1214
|
+
const url = URL.createObjectURL(blob);
|
|
1215
|
+
const link = document.createElement("a");
|
|
1216
|
+
link.href = url;
|
|
1217
|
+
link.download = name;
|
|
1218
|
+
document.body.appendChild(link);
|
|
1219
|
+
link.click();
|
|
1220
|
+
link.remove();
|
|
1221
|
+
URL.revokeObjectURL(url);
|
|
1222
|
+
return { ok: true };
|
|
1223
|
+
} catch (err) {
|
|
1224
|
+
return { ok: false, message: err instanceof Error && err.message ? err.message : "Failed to download attachment" };
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
function useAttachmentObjectUrl(blob) {
|
|
1228
|
+
const [url, setUrl] = useState6(null);
|
|
1229
|
+
useEffect5(() => {
|
|
1230
|
+
if (!blob) {
|
|
1231
|
+
setUrl(null);
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
1235
|
+
setUrl(objectUrl);
|
|
1236
|
+
return () => URL.revokeObjectURL(objectUrl);
|
|
1237
|
+
}, [blob]);
|
|
1238
|
+
return url;
|
|
1239
|
+
}
|
|
1240
|
+
function AttachmentThumbnailError({ name }) {
|
|
1241
|
+
return /* @__PURE__ */ jsxs6("span", { className: "inline-flex h-16 w-16 shrink-0 flex-col items-center justify-center gap-1 rounded-md border border-destructive/40 bg-destructive/10 px-1 text-center text-destructive", children: [
|
|
1242
|
+
/* @__PURE__ */ jsx8(WarningGlyph, { className: "h-4 w-4 shrink-0" }),
|
|
1243
|
+
/* @__PURE__ */ jsx8("span", { className: "line-clamp-2 text-[10px] leading-tight", children: name })
|
|
1244
|
+
] });
|
|
1245
|
+
}
|
|
1246
|
+
function AttachmentThumbnail({ part, resolveFileUrl, fetchFile }) {
|
|
1247
|
+
const url = resolveFileUrl(part);
|
|
1248
|
+
const [result, setResult] = useState6(null);
|
|
1249
|
+
useEffect5(() => {
|
|
1250
|
+
let cancelled = false;
|
|
1251
|
+
setResult(null);
|
|
1252
|
+
loadAttachmentFile(url, fetchFile).then((next) => {
|
|
1253
|
+
if (!cancelled) setResult(next);
|
|
1254
|
+
});
|
|
1255
|
+
return () => {
|
|
1256
|
+
cancelled = true;
|
|
1257
|
+
};
|
|
1258
|
+
}, [url, fetchFile]);
|
|
1259
|
+
const objectUrl = useAttachmentObjectUrl(result?.ok ? result.blob : void 0);
|
|
1260
|
+
const handleClick = useCallback(() => {
|
|
1261
|
+
if (!objectUrl) return;
|
|
1262
|
+
window.open(objectUrl, "_blank", "noopener");
|
|
1263
|
+
}, [objectUrl]);
|
|
1264
|
+
if (!result) {
|
|
1265
|
+
return /* @__PURE__ */ jsx8("span", { className: "inline-block h-16 w-16 shrink-0 animate-pulse rounded-md bg-muted", "aria-hidden": true });
|
|
1266
|
+
}
|
|
1267
|
+
if (!result.ok || !objectUrl) {
|
|
1268
|
+
return /* @__PURE__ */ jsx8(AttachmentThumbnailError, { name: part.name });
|
|
1269
|
+
}
|
|
1270
|
+
return /* @__PURE__ */ jsx8(
|
|
1271
|
+
"button",
|
|
1272
|
+
{
|
|
1273
|
+
type: "button",
|
|
1274
|
+
onClick: handleClick,
|
|
1275
|
+
"aria-label": `Open ${part.name}`,
|
|
1276
|
+
className: "h-16 w-16 shrink-0 overflow-hidden rounded-md border border-border focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1277
|
+
children: /* @__PURE__ */ jsx8("img", { src: objectUrl, alt: part.name, className: "h-16 w-16 object-cover" })
|
|
1278
|
+
}
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
function AttachmentChip({ part, resolveFileUrl, fetchFile }) {
|
|
1282
|
+
const [status, setStatus] = useState6("idle");
|
|
1283
|
+
const [errorMessage, setErrorMessage] = useState6(null);
|
|
1284
|
+
const handleClick = useCallback(() => {
|
|
1285
|
+
if (status === "loading") return;
|
|
1286
|
+
setStatus("loading");
|
|
1287
|
+
setErrorMessage(null);
|
|
1288
|
+
const url = resolveFileUrl(part);
|
|
1289
|
+
void loadAttachmentFile(url, fetchFile).then((result) => {
|
|
1290
|
+
if (!result.ok) {
|
|
1291
|
+
setStatus("error");
|
|
1292
|
+
setErrorMessage(result.message);
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
const download = triggerAttachmentDownload(part.name, result.blob);
|
|
1296
|
+
if (!download.ok) {
|
|
1297
|
+
setStatus("error");
|
|
1298
|
+
setErrorMessage(download.message);
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
setStatus("idle");
|
|
1302
|
+
});
|
|
1303
|
+
}, [status, resolveFileUrl, part, fetchFile]);
|
|
1304
|
+
const Icon = status === "error" ? WarningGlyph : iconForMediaType(part.mediaType);
|
|
1305
|
+
const className = [
|
|
1306
|
+
"inline-flex items-center gap-1 rounded-md border px-2 py-0.5 text-[11px]",
|
|
1307
|
+
status === "error" ? "border-destructive/40 bg-destructive/10 text-destructive" : "border-border bg-muted/60 text-muted-foreground"
|
|
1308
|
+
].join(" ");
|
|
1309
|
+
return /* @__PURE__ */ jsxs6(
|
|
1310
|
+
"button",
|
|
1311
|
+
{
|
|
1312
|
+
type: "button",
|
|
1313
|
+
onClick: handleClick,
|
|
1314
|
+
title: status === "error" ? errorMessage ?? void 0 : void 0,
|
|
1315
|
+
className,
|
|
1316
|
+
children: [
|
|
1317
|
+
/* @__PURE__ */ jsx8(Icon, { className: "h-3 w-3 shrink-0" }),
|
|
1318
|
+
part.name,
|
|
1319
|
+
typeof part.size === "number" && /* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground/70", children: [
|
|
1320
|
+
"\xB7 ",
|
|
1321
|
+
formatBytes(part.size)
|
|
1322
|
+
] })
|
|
1323
|
+
]
|
|
1324
|
+
}
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
function MessageAttachments({ parts, resolveFileUrl, justify = "end", fetchFile }) {
|
|
1328
|
+
if (parts.length === 0) return null;
|
|
1329
|
+
return /* @__PURE__ */ jsx8("div", { className: `flex flex-wrap gap-1.5 ${justify === "start" ? "justify-start" : "justify-end"}`, children: parts.map(
|
|
1330
|
+
(part) => part.type === "image" ? /* @__PURE__ */ jsx8(AttachmentThumbnail, { part, resolveFileUrl, fetchFile }, `${part.path}:${part.name}`) : /* @__PURE__ */ jsx8(AttachmentChip, { part, resolveFileUrl, fetchFile }, `${part.path}:${part.name}`)
|
|
1331
|
+
) });
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1148
1334
|
// src/web-react/chat-stream.ts
|
|
1149
1335
|
function dispatchChatStreamLine(line, cb) {
|
|
1150
1336
|
let receivedContent = false;
|
|
@@ -1315,32 +1501,32 @@ async function streamChatTurn(opts) {
|
|
|
1315
1501
|
|
|
1316
1502
|
// src/web-react/chat-composer.tsx
|
|
1317
1503
|
import {
|
|
1318
|
-
useCallback,
|
|
1319
|
-
useEffect as
|
|
1504
|
+
useCallback as useCallback2,
|
|
1505
|
+
useEffect as useEffect6,
|
|
1320
1506
|
useRef as useRef5,
|
|
1321
|
-
useState as
|
|
1507
|
+
useState as useState7
|
|
1322
1508
|
} from "react";
|
|
1323
|
-
import { Fragment as Fragment3, jsx as
|
|
1509
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1324
1510
|
function SendGlyph({ className }) {
|
|
1325
|
-
return /* @__PURE__ */
|
|
1511
|
+
return /* @__PURE__ */ jsx9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx9("path", { d: "M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z" }) });
|
|
1326
1512
|
}
|
|
1327
1513
|
function StopGlyph({ className }) {
|
|
1328
|
-
return /* @__PURE__ */
|
|
1514
|
+
return /* @__PURE__ */ jsx9("svg", { className, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx9("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) });
|
|
1329
1515
|
}
|
|
1330
1516
|
function PaperclipGlyph({ className }) {
|
|
1331
|
-
return /* @__PURE__ */
|
|
1517
|
+
return /* @__PURE__ */ jsx9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx9("path", { d: "m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) });
|
|
1332
1518
|
}
|
|
1333
1519
|
function FolderGlyph({ className }) {
|
|
1334
|
-
return /* @__PURE__ */
|
|
1335
|
-
/* @__PURE__ */
|
|
1336
|
-
/* @__PURE__ */
|
|
1520
|
+
return /* @__PURE__ */ jsxs7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
1521
|
+
/* @__PURE__ */ jsx9("path", { d: "M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z" }),
|
|
1522
|
+
/* @__PURE__ */ jsx9("path", { d: "M12 10v6m-3-3h6" })
|
|
1337
1523
|
] });
|
|
1338
1524
|
}
|
|
1339
1525
|
function CloseGlyph({ className }) {
|
|
1340
|
-
return /* @__PURE__ */
|
|
1526
|
+
return /* @__PURE__ */ jsx9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx9("path", { d: "M18 6 6 18M6 6l12 12" }) });
|
|
1341
1527
|
}
|
|
1342
1528
|
function UploadGlyph({ className }) {
|
|
1343
|
-
return /* @__PURE__ */
|
|
1529
|
+
return /* @__PURE__ */ jsx9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx9("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12" }) });
|
|
1344
1530
|
}
|
|
1345
1531
|
var MAX_HEIGHT = 168;
|
|
1346
1532
|
function ChatComposer({
|
|
@@ -1369,21 +1555,21 @@ function ChatComposer({
|
|
|
1369
1555
|
className
|
|
1370
1556
|
}) {
|
|
1371
1557
|
const isControlled = value !== void 0;
|
|
1372
|
-
const [internal, setInternal] =
|
|
1558
|
+
const [internal, setInternal] = useState7(initialValue ?? "");
|
|
1373
1559
|
const text = isControlled ? value : internal;
|
|
1374
1560
|
const textareaRef = useRef5(null);
|
|
1375
1561
|
const fileInputRef = useRef5(null);
|
|
1376
1562
|
const folderInputRef = useRef5(null);
|
|
1377
|
-
const [dragOver, setDragOver] =
|
|
1563
|
+
const [dragOver, setDragOver] = useState7(false);
|
|
1378
1564
|
const dragDepth = useRef5(0);
|
|
1379
|
-
const setText =
|
|
1565
|
+
const setText = useCallback2(
|
|
1380
1566
|
(next) => {
|
|
1381
1567
|
if (!isControlled) setInternal(next);
|
|
1382
1568
|
onValueChange?.(next);
|
|
1383
1569
|
},
|
|
1384
1570
|
[isControlled, onValueChange]
|
|
1385
1571
|
);
|
|
1386
|
-
|
|
1572
|
+
useEffect6(() => {
|
|
1387
1573
|
const el = textareaRef.current;
|
|
1388
1574
|
if (!el) return;
|
|
1389
1575
|
el.style.height = "auto";
|
|
@@ -1391,7 +1577,7 @@ function ChatComposer({
|
|
|
1391
1577
|
}, [text]);
|
|
1392
1578
|
const prevSeedRef = useRef5(null);
|
|
1393
1579
|
const pendingCaretRef = useRef5(null);
|
|
1394
|
-
|
|
1580
|
+
useEffect6(() => {
|
|
1395
1581
|
const prev = prevSeedRef.current;
|
|
1396
1582
|
prevSeedRef.current = seed ?? null;
|
|
1397
1583
|
if (seed == null || seed === prev || isControlled) return;
|
|
@@ -1405,7 +1591,7 @@ function ChatComposer({
|
|
|
1405
1591
|
pendingCaretRef.current = seed;
|
|
1406
1592
|
}
|
|
1407
1593
|
}, [seed, setText, onSeedApplied, isControlled]);
|
|
1408
|
-
|
|
1594
|
+
useEffect6(() => {
|
|
1409
1595
|
if (pendingCaretRef.current == null || pendingCaretRef.current !== text)
|
|
1410
1596
|
return;
|
|
1411
1597
|
pendingCaretRef.current = null;
|
|
@@ -1414,7 +1600,7 @@ function ChatComposer({
|
|
|
1414
1600
|
el.focus();
|
|
1415
1601
|
el.setSelectionRange(text.length, text.length);
|
|
1416
1602
|
}, [text]);
|
|
1417
|
-
|
|
1603
|
+
useEffect6(() => {
|
|
1418
1604
|
if (!focusShortcut || disabled) return;
|
|
1419
1605
|
function onKeyDown(e) {
|
|
1420
1606
|
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "l") {
|
|
@@ -1425,20 +1611,20 @@ function ChatComposer({
|
|
|
1425
1611
|
document.addEventListener("keydown", onKeyDown);
|
|
1426
1612
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
1427
1613
|
}, [focusShortcut, disabled]);
|
|
1428
|
-
const
|
|
1429
|
-
const hasSendable =
|
|
1614
|
+
const readyFileCount = pendingFiles.filter((f) => f.status === "ready").length;
|
|
1615
|
+
const hasSendable = text.trim().length > 0 || readyFileCount > 0;
|
|
1430
1616
|
const canSend = hasSendable && !isStreaming && !disabled;
|
|
1431
|
-
const send =
|
|
1617
|
+
const send = useCallback2(() => {
|
|
1432
1618
|
const trimmed = text.trim();
|
|
1433
1619
|
if (isStreaming || disabled) return;
|
|
1620
|
+
const readyFiles = pendingFiles.filter((f) => f.status === "ready");
|
|
1621
|
+
if (!trimmed && readyFiles.length === 0) return;
|
|
1434
1622
|
if (onSendParts) {
|
|
1435
|
-
const parts =
|
|
1436
|
-
if (!trimmed && parts.length === 0) return;
|
|
1623
|
+
const parts = readyFiles.filter((f) => f.part).map((f) => f.part);
|
|
1437
1624
|
onSendParts(trimmed, parts);
|
|
1438
1625
|
setText("");
|
|
1439
1626
|
return;
|
|
1440
1627
|
}
|
|
1441
|
-
if (!trimmed) return;
|
|
1442
1628
|
onSend?.(trimmed);
|
|
1443
1629
|
setText("");
|
|
1444
1630
|
}, [text, isStreaming, disabled, onSend, onSendParts, pendingFiles, setText]);
|
|
@@ -1457,13 +1643,13 @@ function ChatComposer({
|
|
|
1457
1643
|
if (e.target.files?.length) (onAttachFolder ?? onAttach)?.(e.target.files);
|
|
1458
1644
|
e.target.value = "";
|
|
1459
1645
|
};
|
|
1460
|
-
const handleDragEnter =
|
|
1646
|
+
const handleDragEnter = useCallback2((e) => {
|
|
1461
1647
|
e.preventDefault();
|
|
1462
1648
|
e.stopPropagation();
|
|
1463
1649
|
dragDepth.current++;
|
|
1464
1650
|
if (e.dataTransfer?.types.includes("Files")) setDragOver(true);
|
|
1465
1651
|
}, []);
|
|
1466
|
-
const handleDragLeave =
|
|
1652
|
+
const handleDragLeave = useCallback2((e) => {
|
|
1467
1653
|
e.preventDefault();
|
|
1468
1654
|
e.stopPropagation();
|
|
1469
1655
|
dragDepth.current--;
|
|
@@ -1472,12 +1658,12 @@ function ChatComposer({
|
|
|
1472
1658
|
setDragOver(false);
|
|
1473
1659
|
}
|
|
1474
1660
|
}, []);
|
|
1475
|
-
const handleDragOver =
|
|
1661
|
+
const handleDragOver = useCallback2((e) => {
|
|
1476
1662
|
e.preventDefault();
|
|
1477
1663
|
e.stopPropagation();
|
|
1478
1664
|
if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
|
|
1479
1665
|
}, []);
|
|
1480
|
-
const handleDrop =
|
|
1666
|
+
const handleDrop = useCallback2(
|
|
1481
1667
|
(e) => {
|
|
1482
1668
|
e.preventDefault();
|
|
1483
1669
|
e.stopPropagation();
|
|
@@ -1492,7 +1678,7 @@ function ChatComposer({
|
|
|
1492
1678
|
const fileChips = pendingFiles.filter((f) => f.kind !== "folder");
|
|
1493
1679
|
const showFooter = controls != null && controlsPlacement === "footer";
|
|
1494
1680
|
const showAbove = controls != null && controlsPlacement === "above";
|
|
1495
|
-
return /* @__PURE__ */
|
|
1681
|
+
return /* @__PURE__ */ jsxs7(
|
|
1496
1682
|
"div",
|
|
1497
1683
|
{
|
|
1498
1684
|
className: `relative ${className ?? ""}`,
|
|
@@ -1501,42 +1687,42 @@ function ChatComposer({
|
|
|
1501
1687
|
onDragOver: onAttach ? handleDragOver : void 0,
|
|
1502
1688
|
onDrop: onAttach ? handleDrop : void 0,
|
|
1503
1689
|
children: [
|
|
1504
|
-
dragOver && /* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1506
|
-
/* @__PURE__ */
|
|
1507
|
-
/* @__PURE__ */
|
|
1690
|
+
dragOver && /* @__PURE__ */ jsx9("div", { className: "pointer-events-none absolute inset-0 z-10 flex items-center justify-center rounded-2xl border-2 border-dashed border-primary/50 bg-card/95", children: /* @__PURE__ */ jsxs7("div", { className: "text-center", children: [
|
|
1691
|
+
/* @__PURE__ */ jsx9("span", { className: "mx-auto mb-2 flex h-11 w-11 items-center justify-center rounded-xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx9(UploadGlyph, { className: "h-5 w-5" }) }),
|
|
1692
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm font-semibold text-foreground", children: dropTitle }),
|
|
1693
|
+
/* @__PURE__ */ jsx9("p", { className: "mt-0.5 text-xs text-muted-foreground", children: dropDescription })
|
|
1508
1694
|
] }) }),
|
|
1509
|
-
showAbove && /* @__PURE__ */
|
|
1510
|
-
pendingFiles.length > 0 && /* @__PURE__ */
|
|
1695
|
+
showAbove && /* @__PURE__ */ jsx9("div", { className: "mb-1.5 flex flex-wrap items-center gap-1.5 px-1", children: controls }),
|
|
1696
|
+
pendingFiles.length > 0 && /* @__PURE__ */ jsx9("div", { className: "mb-2 flex flex-wrap gap-1.5", children: [...folderChips, ...fileChips].map((f) => /* @__PURE__ */ jsxs7(
|
|
1511
1697
|
"span",
|
|
1512
1698
|
{
|
|
1513
1699
|
className: `inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs ${f.status === "error" ? "border-destructive/40 text-destructive" : "border-border bg-muted/50 text-foreground"}`,
|
|
1514
1700
|
children: [
|
|
1515
|
-
f.kind === "folder" ? /* @__PURE__ */
|
|
1516
|
-
/* @__PURE__ */
|
|
1517
|
-
f.fileCount !== void 0 && /* @__PURE__ */
|
|
1701
|
+
f.kind === "folder" ? /* @__PURE__ */ jsx9(FolderGlyph, { className: "h-3 w-3 shrink-0" }) : /* @__PURE__ */ jsx9(PaperclipGlyph, { className: "h-3 w-3 shrink-0" }),
|
|
1702
|
+
/* @__PURE__ */ jsx9("span", { className: "max-w-[150px] truncate", children: f.name }),
|
|
1703
|
+
f.fileCount !== void 0 && /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground", children: [
|
|
1518
1704
|
"(",
|
|
1519
1705
|
f.fileCount,
|
|
1520
1706
|
")"
|
|
1521
1707
|
] }),
|
|
1522
|
-
f.status === "uploading" && /* @__PURE__ */
|
|
1523
|
-
onRemoveFile && /* @__PURE__ */
|
|
1708
|
+
f.status === "uploading" && /* @__PURE__ */ jsx9("span", { className: "h-3 w-3 animate-spin rounded-full border-2 border-primary border-t-transparent" }),
|
|
1709
|
+
onRemoveFile && /* @__PURE__ */ jsx9(
|
|
1524
1710
|
"button",
|
|
1525
1711
|
{
|
|
1526
1712
|
type: "button",
|
|
1527
1713
|
"aria-label": `Remove ${f.name}`,
|
|
1528
1714
|
onClick: () => onRemoveFile(f.id),
|
|
1529
1715
|
className: "rounded p-0.5 text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1530
|
-
children: /* @__PURE__ */
|
|
1716
|
+
children: /* @__PURE__ */ jsx9(CloseGlyph, { className: "h-3 w-3" })
|
|
1531
1717
|
}
|
|
1532
1718
|
)
|
|
1533
1719
|
]
|
|
1534
1720
|
},
|
|
1535
1721
|
f.id
|
|
1536
1722
|
)) }),
|
|
1537
|
-
/* @__PURE__ */
|
|
1538
|
-
onAttach && /* @__PURE__ */
|
|
1539
|
-
/* @__PURE__ */
|
|
1723
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-end gap-2 rounded-2xl border border-border bg-card px-2.5 py-2 transition focus-within:border-primary/40 focus-within:ring-2 focus-within:ring-primary/15", children: [
|
|
1724
|
+
onAttach && /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
1725
|
+
/* @__PURE__ */ jsx9(
|
|
1540
1726
|
"button",
|
|
1541
1727
|
{
|
|
1542
1728
|
type: "button",
|
|
@@ -1545,13 +1731,13 @@ function ChatComposer({
|
|
|
1545
1731
|
"aria-label": "Attach files",
|
|
1546
1732
|
title: "Attach files",
|
|
1547
1733
|
className: "mb-0.5 shrink-0 rounded-lg p-2 text-muted-foreground transition hover:bg-accent/40 hover:text-foreground disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1548
|
-
children: /* @__PURE__ */
|
|
1734
|
+
children: /* @__PURE__ */ jsx9(PaperclipGlyph, { className: "h-4 w-4" })
|
|
1549
1735
|
}
|
|
1550
1736
|
),
|
|
1551
|
-
/* @__PURE__ */
|
|
1737
|
+
/* @__PURE__ */ jsx9("input", { ref: fileInputRef, type: "file", multiple: true, className: "hidden", accept, onChange: handleFileChange })
|
|
1552
1738
|
] }),
|
|
1553
|
-
onAttachFolder && /* @__PURE__ */
|
|
1554
|
-
/* @__PURE__ */
|
|
1739
|
+
onAttachFolder && /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
1740
|
+
/* @__PURE__ */ jsx9(
|
|
1555
1741
|
"button",
|
|
1556
1742
|
{
|
|
1557
1743
|
type: "button",
|
|
@@ -1560,10 +1746,10 @@ function ChatComposer({
|
|
|
1560
1746
|
"aria-label": "Attach folder",
|
|
1561
1747
|
title: "Attach folder",
|
|
1562
1748
|
className: "mb-0.5 shrink-0 rounded-lg p-2 text-muted-foreground transition hover:bg-accent/40 hover:text-foreground disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1563
|
-
children: /* @__PURE__ */
|
|
1749
|
+
children: /* @__PURE__ */ jsx9(FolderGlyph, { className: "h-4 w-4" })
|
|
1564
1750
|
}
|
|
1565
1751
|
),
|
|
1566
|
-
/* @__PURE__ */
|
|
1752
|
+
/* @__PURE__ */ jsx9(
|
|
1567
1753
|
"input",
|
|
1568
1754
|
{
|
|
1569
1755
|
ref: folderInputRef,
|
|
@@ -1575,7 +1761,7 @@ function ChatComposer({
|
|
|
1575
1761
|
}
|
|
1576
1762
|
)
|
|
1577
1763
|
] }),
|
|
1578
|
-
/* @__PURE__ */
|
|
1764
|
+
/* @__PURE__ */ jsx9(
|
|
1579
1765
|
"textarea",
|
|
1580
1766
|
{
|
|
1581
1767
|
ref: textareaRef,
|
|
@@ -1589,8 +1775,8 @@ function ChatComposer({
|
|
|
1589
1775
|
className: "max-h-[168px] min-h-[40px] flex-1 resize-none bg-transparent px-1.5 py-2 text-[15px] leading-6 text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-50"
|
|
1590
1776
|
}
|
|
1591
1777
|
),
|
|
1592
|
-
showFooter && /* @__PURE__ */
|
|
1593
|
-
isStreaming ? /* @__PURE__ */
|
|
1778
|
+
showFooter && /* @__PURE__ */ jsx9("div", { className: "mb-0.5 flex shrink-0 items-center gap-1.5", children: controls }),
|
|
1779
|
+
isStreaming ? /* @__PURE__ */ jsxs7(
|
|
1594
1780
|
"button",
|
|
1595
1781
|
{
|
|
1596
1782
|
type: "button",
|
|
@@ -1598,11 +1784,11 @@ function ChatComposer({
|
|
|
1598
1784
|
"aria-label": "Stop response",
|
|
1599
1785
|
className: "mb-0.5 inline-flex shrink-0 items-center gap-1.5 rounded-full bg-destructive/15 px-3.5 py-2 text-sm font-medium text-destructive transition hover:bg-destructive/25 focus:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50",
|
|
1600
1786
|
children: [
|
|
1601
|
-
/* @__PURE__ */
|
|
1602
|
-
/* @__PURE__ */
|
|
1787
|
+
/* @__PURE__ */ jsx9(StopGlyph, { className: "h-3.5 w-3.5" }),
|
|
1788
|
+
/* @__PURE__ */ jsx9("span", { children: "Stop" })
|
|
1603
1789
|
]
|
|
1604
1790
|
}
|
|
1605
|
-
) : /* @__PURE__ */
|
|
1791
|
+
) : /* @__PURE__ */ jsxs7(
|
|
1606
1792
|
"button",
|
|
1607
1793
|
{
|
|
1608
1794
|
type: "button",
|
|
@@ -1611,16 +1797,16 @@ function ChatComposer({
|
|
|
1611
1797
|
"aria-label": sendLabel,
|
|
1612
1798
|
className: "mb-0.5 inline-flex shrink-0 items-center gap-1.5 rounded-full bg-primary px-3.5 py-2 text-sm font-medium text-primary-foreground shadow-sm transition hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-40 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-card",
|
|
1613
1799
|
children: [
|
|
1614
|
-
/* @__PURE__ */
|
|
1615
|
-
/* @__PURE__ */
|
|
1800
|
+
/* @__PURE__ */ jsx9(SendGlyph, { className: "h-3.5 w-3.5" }),
|
|
1801
|
+
/* @__PURE__ */ jsx9("span", { children: sendLabel })
|
|
1616
1802
|
]
|
|
1617
1803
|
}
|
|
1618
1804
|
)
|
|
1619
1805
|
] }),
|
|
1620
|
-
focusShortcut && /* @__PURE__ */
|
|
1621
|
-
/* @__PURE__ */
|
|
1622
|
-
/* @__PURE__ */
|
|
1623
|
-
/* @__PURE__ */
|
|
1806
|
+
focusShortcut && /* @__PURE__ */ jsx9("div", { className: "mt-1.5 flex justify-end px-1", children: /* @__PURE__ */ jsxs7("span", { className: "text-xs text-muted-foreground", children: [
|
|
1807
|
+
/* @__PURE__ */ jsx9("kbd", { className: "rounded border border-border bg-background px-1 py-0.5 text-[10px]", children: "Cmd" }),
|
|
1808
|
+
/* @__PURE__ */ jsx9("kbd", { className: "ml-0.5 rounded border border-border bg-background px-1 py-0.5 text-[10px]", children: "L" }),
|
|
1809
|
+
/* @__PURE__ */ jsx9("span", { className: "ml-1", children: "to focus" })
|
|
1624
1810
|
] }) })
|
|
1625
1811
|
]
|
|
1626
1812
|
}
|
|
@@ -1628,7 +1814,7 @@ function ChatComposer({
|
|
|
1628
1814
|
}
|
|
1629
1815
|
|
|
1630
1816
|
// src/web-react/durable-plan-flow.ts
|
|
1631
|
-
import { useCallback as
|
|
1817
|
+
import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef6, useState as useState8 } from "react";
|
|
1632
1818
|
var DurablePlanClientError = class extends Error {
|
|
1633
1819
|
constructor(message, status, code, currentPlan) {
|
|
1634
1820
|
super(message);
|
|
@@ -1715,14 +1901,14 @@ function createDurablePlanDecisionClient(options) {
|
|
|
1715
1901
|
};
|
|
1716
1902
|
}
|
|
1717
1903
|
function useDurablePlanFlow(options) {
|
|
1718
|
-
const [plan, setPlan] =
|
|
1719
|
-
const [deciding, setDeciding] =
|
|
1720
|
-
const [restoring, setRestoring] =
|
|
1721
|
-
const [error, setError] =
|
|
1904
|
+
const [plan, setPlan] = useState8(options.plan);
|
|
1905
|
+
const [deciding, setDeciding] = useState8(null);
|
|
1906
|
+
const [restoring, setRestoring] = useState8(false);
|
|
1907
|
+
const [error, setError] = useState8(null);
|
|
1722
1908
|
const attachments = useRef6(/* @__PURE__ */ new Map());
|
|
1723
1909
|
const decisionInFlight = useRef6(false);
|
|
1724
|
-
|
|
1725
|
-
const apply =
|
|
1910
|
+
useEffect7(() => setPlan(options.plan), [options.plan]);
|
|
1911
|
+
const apply = useCallback3(async (result) => {
|
|
1726
1912
|
setPlan(result.plan);
|
|
1727
1913
|
options.onUpdated?.(result.plan);
|
|
1728
1914
|
const receipt = result.followUp;
|
|
@@ -1735,7 +1921,7 @@ function useDurablePlanFlow(options) {
|
|
|
1735
1921
|
}
|
|
1736
1922
|
await pending;
|
|
1737
1923
|
}, [options.attachFollowUp, options.onUpdated]);
|
|
1738
|
-
const decide =
|
|
1924
|
+
const decide = useCallback3(async (decision, feedback) => {
|
|
1739
1925
|
if (decisionInFlight.current) return null;
|
|
1740
1926
|
decisionInFlight.current = true;
|
|
1741
1927
|
setDeciding(decision);
|
|
@@ -1761,7 +1947,7 @@ function useDurablePlanFlow(options) {
|
|
|
1761
1947
|
setDeciding(null);
|
|
1762
1948
|
}
|
|
1763
1949
|
}, [apply, options.client, options.onUpdated, plan.planId, plan.revision]);
|
|
1764
|
-
const restore =
|
|
1950
|
+
const restore = useCallback3(async () => {
|
|
1765
1951
|
setRestoring(true);
|
|
1766
1952
|
setError(null);
|
|
1767
1953
|
try {
|
|
@@ -1890,7 +2076,7 @@ function createDurableInteractionAnswerSubmitter(options) {
|
|
|
1890
2076
|
}
|
|
1891
2077
|
|
|
1892
2078
|
// src/web-react/use-chat-interactions.ts
|
|
1893
|
-
import { useCallback as
|
|
2079
|
+
import { useCallback as useCallback4, useMemo as useMemo4, useState as useState9 } from "react";
|
|
1894
2080
|
function hasPendingContentDuplicate(list, interaction) {
|
|
1895
2081
|
if (interaction.status !== "pending") return false;
|
|
1896
2082
|
const signature = questionInteractionContentSignature(interaction);
|
|
@@ -1969,34 +2155,34 @@ function hydrateChatInteractions(list, persisted) {
|
|
|
1969
2155
|
return persisted.reduce(upsertChatInteraction, list);
|
|
1970
2156
|
}
|
|
1971
2157
|
function useChatInteractions(options = {}) {
|
|
1972
|
-
const [interactions, setInteractions] =
|
|
1973
|
-
const upsert =
|
|
2158
|
+
const [interactions, setInteractions] = useState9([]);
|
|
2159
|
+
const upsert = useCallback4((interaction) => {
|
|
1974
2160
|
setInteractions((prev) => upsertChatInteraction(prev, interaction));
|
|
1975
2161
|
}, []);
|
|
1976
|
-
const applyCancel =
|
|
2162
|
+
const applyCancel = useCallback4((cancel) => {
|
|
1977
2163
|
setInteractions((prev) => cancelChatInteraction(prev, cancel));
|
|
1978
2164
|
}, []);
|
|
1979
|
-
const markResolved =
|
|
2165
|
+
const markResolved = useCallback4((id, status, answers) => {
|
|
1980
2166
|
setInteractions((prev) => resolveChatInteraction(prev, id, status, answers));
|
|
1981
2167
|
}, []);
|
|
1982
|
-
const restore =
|
|
2168
|
+
const restore = useCallback4((outstanding, restoreOptions) => {
|
|
1983
2169
|
setInteractions((prev) => restoreChatInteractions(prev, outstanding, {
|
|
1984
2170
|
mode: restoreOptions?.mode ?? options.mode
|
|
1985
2171
|
}));
|
|
1986
2172
|
}, [options.mode]);
|
|
1987
|
-
const hydrate =
|
|
2173
|
+
const hydrate = useCallback4((persisted) => {
|
|
1988
2174
|
setInteractions((prev) => hydrateChatInteractions(prev, persisted));
|
|
1989
2175
|
}, []);
|
|
1990
|
-
const terminalizePending =
|
|
2176
|
+
const terminalizePending = useCallback4((status) => {
|
|
1991
2177
|
setInteractions((prev) => terminalizePendingChatInteractions(prev, status));
|
|
1992
2178
|
}, []);
|
|
1993
|
-
const reset =
|
|
2179
|
+
const reset = useCallback4(() => setInteractions([]), []);
|
|
1994
2180
|
const pending = useMemo4(() => interactions.filter((item) => item.status === "pending"), [interactions]);
|
|
1995
2181
|
return { interactions, pending, upsert, applyCancel, markResolved, restore, hydrate, terminalizePending, reset };
|
|
1996
2182
|
}
|
|
1997
2183
|
|
|
1998
2184
|
// src/web-react/use-file-mentions.ts
|
|
1999
|
-
import { useCallback as
|
|
2185
|
+
import { useCallback as useCallback5, useMemo as useMemo5, useRef as useRef7, useState as useState10 } from "react";
|
|
2000
2186
|
var FILE_MENTION_KIND = "file";
|
|
2001
2187
|
function toMentionItem(file) {
|
|
2002
2188
|
return { id: file.path, label: file.name, detail: file.path, kind: FILE_MENTION_KIND };
|
|
@@ -2054,12 +2240,12 @@ function useFileMentions(options) {
|
|
|
2054
2240
|
emptyText = DEFAULT_MENTION_EMPTY_TEXT
|
|
2055
2241
|
} = options;
|
|
2056
2242
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
2057
|
-
const [state, setState] =
|
|
2243
|
+
const [state, setState] = useState10({ kind: "idle" });
|
|
2058
2244
|
const stateRef = useRef7(state);
|
|
2059
2245
|
stateRef.current = state;
|
|
2060
2246
|
const inFlightRef = useRef7(null);
|
|
2061
|
-
const [mentions, setMentions] =
|
|
2062
|
-
const load =
|
|
2247
|
+
const [mentions, setMentions] = useState10([]);
|
|
2248
|
+
const load = useCallback5(() => {
|
|
2063
2249
|
if (inFlightRef.current) return inFlightRef.current;
|
|
2064
2250
|
if (stateRef.current.kind === "idle") {
|
|
2065
2251
|
stateRef.current = { kind: "loading" };
|
|
@@ -2091,10 +2277,10 @@ function useFileMentions(options) {
|
|
|
2091
2277
|
inFlightRef.current = attempt;
|
|
2092
2278
|
return attempt;
|
|
2093
2279
|
}, [fetchImpl, indexUrl]);
|
|
2094
|
-
const refresh =
|
|
2280
|
+
const refresh = useCallback5(async () => {
|
|
2095
2281
|
await load();
|
|
2096
2282
|
}, [load]);
|
|
2097
|
-
const fetchItems =
|
|
2283
|
+
const fetchItems = useCallback5(
|
|
2098
2284
|
async (query) => {
|
|
2099
2285
|
let current = stateRef.current;
|
|
2100
2286
|
if (current.kind === "idle" || current.kind === "loading") {
|
|
@@ -2109,10 +2295,10 @@ function useFileMentions(options) {
|
|
|
2109
2295
|
},
|
|
2110
2296
|
[load, limit, refreshAfterMs]
|
|
2111
2297
|
);
|
|
2112
|
-
const onMentionsChange =
|
|
2298
|
+
const onMentionsChange = useCallback5((items) => {
|
|
2113
2299
|
setMentions(items.filter((item) => item.kind === void 0 || item.kind === FILE_MENTION_KIND).map(toFileMention));
|
|
2114
2300
|
}, []);
|
|
2115
|
-
const clearMentions =
|
|
2301
|
+
const clearMentions = useCallback5(() => setMentions([]), []);
|
|
2116
2302
|
const mention = useMemo5(
|
|
2117
2303
|
() => ({
|
|
2118
2304
|
fetchItems,
|
|
@@ -2166,9 +2352,284 @@ function segmentMentionContent(content, parts) {
|
|
|
2166
2352
|
return { segments, matched };
|
|
2167
2353
|
}
|
|
2168
2354
|
|
|
2355
|
+
// src/web-react/use-composer-attachments.ts
|
|
2356
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo6, useRef as useRef8, useState as useState11 } from "react";
|
|
2357
|
+
function newId() {
|
|
2358
|
+
const cryptoObject = globalThis.crypto;
|
|
2359
|
+
if (typeof cryptoObject?.randomUUID === "function") return cryptoObject.randomUUID();
|
|
2360
|
+
return `att-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
2361
|
+
}
|
|
2362
|
+
function dedupeName(name, taken) {
|
|
2363
|
+
if (!taken.has(name)) return name;
|
|
2364
|
+
const dot = name.lastIndexOf(".");
|
|
2365
|
+
const base = dot > 0 ? name.slice(0, dot) : name;
|
|
2366
|
+
const ext = dot > 0 ? name.slice(dot) : "";
|
|
2367
|
+
let n = 2;
|
|
2368
|
+
let candidate = `${base}-${n}${ext}`;
|
|
2369
|
+
while (taken.has(candidate)) {
|
|
2370
|
+
n += 1;
|
|
2371
|
+
candidate = `${base}-${n}${ext}`;
|
|
2372
|
+
}
|
|
2373
|
+
return candidate;
|
|
2374
|
+
}
|
|
2375
|
+
function kindForMime(mime) {
|
|
2376
|
+
return mime.startsWith("image/") ? "image" : "file";
|
|
2377
|
+
}
|
|
2378
|
+
function isAcceptedFileType(file, accept) {
|
|
2379
|
+
const patterns = accept.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2380
|
+
if (patterns.length === 0) return true;
|
|
2381
|
+
const name = file.name.toLowerCase();
|
|
2382
|
+
const type = (file.type || "").toLowerCase();
|
|
2383
|
+
return patterns.some((pattern) => {
|
|
2384
|
+
const lower = pattern.toLowerCase();
|
|
2385
|
+
if (lower.startsWith(".")) return name.endsWith(lower);
|
|
2386
|
+
if (lower.endsWith("/*")) return type.startsWith(lower.slice(0, -1));
|
|
2387
|
+
return type === lower;
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
async function parseUploadError(res) {
|
|
2391
|
+
const detail = await res.json().catch(() => null);
|
|
2392
|
+
if (detail && typeof detail === "object" && "error" in detail) {
|
|
2393
|
+
const error = detail.error;
|
|
2394
|
+
if (typeof error === "string" && error) return error;
|
|
2395
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
2396
|
+
const message = error.message;
|
|
2397
|
+
if (typeof message === "string" && message) return message;
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
return `Upload failed (${res.status})`;
|
|
2401
|
+
}
|
|
2402
|
+
var NO_UPLOAD_TARGET_MESSAGE = "No upload destination configured (pass uploadUrl or buildUploadRequest)";
|
|
2403
|
+
function useComposerAttachments(options) {
|
|
2404
|
+
const optionsRef = useRef8(options);
|
|
2405
|
+
optionsRef.current = options;
|
|
2406
|
+
const [staged, setStagedState] = useState11([]);
|
|
2407
|
+
const stagedRef = useRef8([]);
|
|
2408
|
+
const controllersRef = useRef8(/* @__PURE__ */ new Map());
|
|
2409
|
+
const setStaged = useCallback6(
|
|
2410
|
+
(updater) => {
|
|
2411
|
+
const next = typeof updater === "function" ? updater(stagedRef.current) : updater;
|
|
2412
|
+
stagedRef.current = next;
|
|
2413
|
+
setStagedState(next);
|
|
2414
|
+
},
|
|
2415
|
+
[]
|
|
2416
|
+
);
|
|
2417
|
+
const upload = useCallback6(
|
|
2418
|
+
async (id, file, name) => {
|
|
2419
|
+
const opts = optionsRef.current;
|
|
2420
|
+
setStaged(
|
|
2421
|
+
(prev) => prev.map((s) => s.id === id ? { ...s, status: "uploading", errorMessage: void 0 } : s)
|
|
2422
|
+
);
|
|
2423
|
+
const controller = new AbortController();
|
|
2424
|
+
controllersRef.current.set(id, controller);
|
|
2425
|
+
const form = new FormData();
|
|
2426
|
+
form.append("file", file, name);
|
|
2427
|
+
const request = opts.buildUploadRequest ? opts.buildUploadRequest({ file, name, form }) : opts.uploadUrl ? { url: opts.uploadUrl } : null;
|
|
2428
|
+
if (!request) {
|
|
2429
|
+
setStaged(
|
|
2430
|
+
(prev) => prev.map(
|
|
2431
|
+
(s) => s.id === id ? { ...s, status: "error", errorMessage: NO_UPLOAD_TARGET_MESSAGE } : s
|
|
2432
|
+
)
|
|
2433
|
+
);
|
|
2434
|
+
opts.onError?.(NO_UPLOAD_TARGET_MESSAGE);
|
|
2435
|
+
controllersRef.current.delete(id);
|
|
2436
|
+
return;
|
|
2437
|
+
}
|
|
2438
|
+
try {
|
|
2439
|
+
const res = await fetch(request.url, {
|
|
2440
|
+
method: "POST",
|
|
2441
|
+
credentials: "same-origin",
|
|
2442
|
+
...request.init,
|
|
2443
|
+
body: form,
|
|
2444
|
+
signal: controller.signal
|
|
2445
|
+
});
|
|
2446
|
+
if (!res.ok) {
|
|
2447
|
+
const message = await parseUploadError(res);
|
|
2448
|
+
setStaged(
|
|
2449
|
+
(prev) => prev.map((s) => s.id === id ? { ...s, status: "error", errorMessage: message } : s)
|
|
2450
|
+
);
|
|
2451
|
+
opts.onError?.(message);
|
|
2452
|
+
return;
|
|
2453
|
+
}
|
|
2454
|
+
const data = await res.json();
|
|
2455
|
+
const uploaded = data.files?.[0];
|
|
2456
|
+
if (!uploaded) {
|
|
2457
|
+
const message = "Upload returned no file";
|
|
2458
|
+
setStaged(
|
|
2459
|
+
(prev) => prev.map((s) => s.id === id ? { ...s, status: "error", errorMessage: message } : s)
|
|
2460
|
+
);
|
|
2461
|
+
opts.onError?.(message);
|
|
2462
|
+
return;
|
|
2463
|
+
}
|
|
2464
|
+
setStaged(
|
|
2465
|
+
(prev) => prev.map((s) => s.id === id ? { ...s, status: "ready", reference: uploaded } : s)
|
|
2466
|
+
);
|
|
2467
|
+
} catch (err) {
|
|
2468
|
+
if (err.name === "AbortError") return;
|
|
2469
|
+
const message = err instanceof Error && err.message ? err.message : "Upload failed \u2014 check your connection";
|
|
2470
|
+
setStaged(
|
|
2471
|
+
(prev) => prev.map((s) => s.id === id ? { ...s, status: "error", errorMessage: message } : s)
|
|
2472
|
+
);
|
|
2473
|
+
opts.onError?.(message);
|
|
2474
|
+
} finally {
|
|
2475
|
+
controllersRef.current.delete(id);
|
|
2476
|
+
}
|
|
2477
|
+
},
|
|
2478
|
+
[setStaged]
|
|
2479
|
+
);
|
|
2480
|
+
const addFiles = useCallback6(
|
|
2481
|
+
async (files) => {
|
|
2482
|
+
const opts = optionsRef.current;
|
|
2483
|
+
const enabled2 = opts.enabled ?? true;
|
|
2484
|
+
if (!enabled2) {
|
|
2485
|
+
opts.onReject?.("Attachments are disabled");
|
|
2486
|
+
return;
|
|
2487
|
+
}
|
|
2488
|
+
const accept = opts.accept ?? ATTACHMENT_ACCEPT;
|
|
2489
|
+
const maxCount = opts.limits?.maxCount ?? ATTACHMENT_MAX_COUNT;
|
|
2490
|
+
const maxBinaryBytes = opts.limits?.maxBinaryBytes ?? MAX_BINARY_ATTACHMENT_BYTES;
|
|
2491
|
+
const maxTextBytes = opts.limits?.maxTextBytes ?? MAX_TEXT_ATTACHMENT_BYTES;
|
|
2492
|
+
const maxTotalBytes = opts.limits?.maxTotalBytes ?? MAX_ATTACHMENT_TOTAL_BYTES;
|
|
2493
|
+
const allowedKinds = opts.allowedKinds ?? ["image", "file"];
|
|
2494
|
+
const list = Array.isArray(files) ? files : Array.from(files);
|
|
2495
|
+
const currentCount = stagedRef.current.length;
|
|
2496
|
+
const countAccepted = [];
|
|
2497
|
+
for (const file of list) {
|
|
2498
|
+
if (!isAcceptedFileType(file, accept)) {
|
|
2499
|
+
opts.onReject?.(`"${file.name}" is not an accepted file type (${accept}).`, file);
|
|
2500
|
+
continue;
|
|
2501
|
+
}
|
|
2502
|
+
if (currentCount + countAccepted.length >= maxCount) {
|
|
2503
|
+
opts.onReject?.(`"${file.name}" was not added \u2014 the ${maxCount}-file limit is already reached.`, file);
|
|
2504
|
+
continue;
|
|
2505
|
+
}
|
|
2506
|
+
countAccepted.push(file);
|
|
2507
|
+
}
|
|
2508
|
+
const sizeAccepted = [];
|
|
2509
|
+
for (const file of countAccepted) {
|
|
2510
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
2511
|
+
const sniff = sniffBinary(bytes);
|
|
2512
|
+
const typeCheck = checkAttachmentType(file.name, sniff);
|
|
2513
|
+
if (!typeCheck.succeeded) {
|
|
2514
|
+
opts.onReject?.(typeCheck.message, file);
|
|
2515
|
+
continue;
|
|
2516
|
+
}
|
|
2517
|
+
const limit = sniff.binary ? maxBinaryBytes : maxTextBytes;
|
|
2518
|
+
if (file.size > limit) {
|
|
2519
|
+
opts.onReject?.(attachmentSizeErrorMessage(file.name, file.size, limit), file);
|
|
2520
|
+
continue;
|
|
2521
|
+
}
|
|
2522
|
+
const mediaType = sniff.mime ?? file.type ?? "";
|
|
2523
|
+
const kind = kindForMime(mediaType);
|
|
2524
|
+
if (!allowedKinds.includes(kind)) {
|
|
2525
|
+
opts.onReject?.(`"${file.name}" is a ${kind} attachment, which isn't accepted here`, file);
|
|
2526
|
+
continue;
|
|
2527
|
+
}
|
|
2528
|
+
sizeAccepted.push(file);
|
|
2529
|
+
}
|
|
2530
|
+
const accepted = [];
|
|
2531
|
+
let totalBytes = stagedRef.current.reduce((total, s) => total + s.size, 0);
|
|
2532
|
+
for (const file of sizeAccepted) {
|
|
2533
|
+
const nextTotalBytes = totalBytes + file.size;
|
|
2534
|
+
if (nextTotalBytes > maxTotalBytes) {
|
|
2535
|
+
opts.onReject?.(attachmentTotalSizeErrorMessage(nextTotalBytes, maxTotalBytes), file);
|
|
2536
|
+
continue;
|
|
2537
|
+
}
|
|
2538
|
+
accepted.push(file);
|
|
2539
|
+
totalBytes = nextTotalBytes;
|
|
2540
|
+
}
|
|
2541
|
+
if (accepted.length === 0) return;
|
|
2542
|
+
const taken = new Set(stagedRef.current.map((s) => s.name));
|
|
2543
|
+
const entries = accepted.map((file) => {
|
|
2544
|
+
const name = dedupeName(sanitizeAttachmentFileName(file.name), taken);
|
|
2545
|
+
taken.add(name);
|
|
2546
|
+
return {
|
|
2547
|
+
id: newId(),
|
|
2548
|
+
file,
|
|
2549
|
+
name,
|
|
2550
|
+
size: file.size,
|
|
2551
|
+
status: "pending",
|
|
2552
|
+
previewUrl: file.type.startsWith("image/") ? URL.createObjectURL(file) : void 0
|
|
2553
|
+
};
|
|
2554
|
+
});
|
|
2555
|
+
setStaged((prev) => [...prev, ...entries]);
|
|
2556
|
+
for (const entry of entries) void upload(entry.id, entry.file, entry.name);
|
|
2557
|
+
},
|
|
2558
|
+
[setStaged, upload]
|
|
2559
|
+
);
|
|
2560
|
+
const retry = useCallback6(
|
|
2561
|
+
(id) => {
|
|
2562
|
+
const entry = stagedRef.current.find((s) => s.id === id);
|
|
2563
|
+
if (!entry) return;
|
|
2564
|
+
void upload(entry.id, entry.file, entry.name);
|
|
2565
|
+
},
|
|
2566
|
+
[upload]
|
|
2567
|
+
);
|
|
2568
|
+
const removeAttachment = useCallback6(
|
|
2569
|
+
(id) => {
|
|
2570
|
+
controllersRef.current.get(id)?.abort();
|
|
2571
|
+
controllersRef.current.delete(id);
|
|
2572
|
+
const entry = stagedRef.current.find((s) => s.id === id);
|
|
2573
|
+
if (entry?.previewUrl) URL.revokeObjectURL(entry.previewUrl);
|
|
2574
|
+
setStaged((prev) => prev.filter((s) => s.id !== id));
|
|
2575
|
+
},
|
|
2576
|
+
[setStaged]
|
|
2577
|
+
);
|
|
2578
|
+
const clear = useCallback6(() => {
|
|
2579
|
+
for (const controller of controllersRef.current.values()) controller.abort();
|
|
2580
|
+
controllersRef.current.clear();
|
|
2581
|
+
for (const entry of stagedRef.current) {
|
|
2582
|
+
if (entry.previewUrl) URL.revokeObjectURL(entry.previewUrl);
|
|
2583
|
+
}
|
|
2584
|
+
setStaged([]);
|
|
2585
|
+
}, [setStaged]);
|
|
2586
|
+
useEffect8(
|
|
2587
|
+
() => () => {
|
|
2588
|
+
for (const controller of controllersRef.current.values()) controller.abort();
|
|
2589
|
+
controllersRef.current.clear();
|
|
2590
|
+
for (const entry of stagedRef.current) {
|
|
2591
|
+
if (entry.previewUrl) URL.revokeObjectURL(entry.previewUrl);
|
|
2592
|
+
}
|
|
2593
|
+
},
|
|
2594
|
+
[]
|
|
2595
|
+
);
|
|
2596
|
+
const composerFiles = useMemo6(
|
|
2597
|
+
() => staged.map((s) => ({
|
|
2598
|
+
id: s.id,
|
|
2599
|
+
name: s.name,
|
|
2600
|
+
size: s.size,
|
|
2601
|
+
kind: "file",
|
|
2602
|
+
status: s.status
|
|
2603
|
+
})),
|
|
2604
|
+
[staged]
|
|
2605
|
+
);
|
|
2606
|
+
const references = useMemo6(
|
|
2607
|
+
() => staged.filter((s) => s.status === "ready" && !!s.reference).map((s) => s.reference),
|
|
2608
|
+
[staged]
|
|
2609
|
+
);
|
|
2610
|
+
const hasPending = useMemo6(
|
|
2611
|
+
() => staged.some((s) => s.status === "pending" || s.status === "uploading"),
|
|
2612
|
+
[staged]
|
|
2613
|
+
);
|
|
2614
|
+
const hasError = useMemo6(() => staged.some((s) => s.status === "error"), [staged]);
|
|
2615
|
+
const enabled = options.enabled ?? true;
|
|
2616
|
+
const blockReason = !enabled ? "Attachments are disabled" : hasPending ? "Attachments are still uploading" : hasError ? "Remove failed attachments to send" : null;
|
|
2617
|
+
return {
|
|
2618
|
+
composerFiles,
|
|
2619
|
+
references,
|
|
2620
|
+
addFiles,
|
|
2621
|
+
retry,
|
|
2622
|
+
removeAttachment,
|
|
2623
|
+
clear,
|
|
2624
|
+
hasPending,
|
|
2625
|
+
hasError,
|
|
2626
|
+
blockReason
|
|
2627
|
+
};
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2169
2630
|
// src/web-react/mission-activity.tsx
|
|
2170
|
-
import { useCallback as
|
|
2171
|
-
import { Fragment as Fragment4, jsx as
|
|
2631
|
+
import { useCallback as useCallback7, useEffect as useEffect9, useState as useState12 } from "react";
|
|
2632
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2172
2633
|
var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "running"]);
|
|
2173
2634
|
var OK_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "succeeded"]);
|
|
2174
2635
|
var ERROR_STATUSES = /* @__PURE__ */ new Set(["failed", "error", "cancelled", "aborted"]);
|
|
@@ -2215,20 +2676,20 @@ function waterfallLayout(trace) {
|
|
|
2215
2676
|
});
|
|
2216
2677
|
}
|
|
2217
2678
|
function ChevronGlyph({ className }) {
|
|
2218
|
-
return /* @__PURE__ */
|
|
2679
|
+
return /* @__PURE__ */ jsx10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx10("path", { d: "m6 9 6 6 6-6" }) });
|
|
2219
2680
|
}
|
|
2220
2681
|
function RefreshGlyph({ className }) {
|
|
2221
|
-
return /* @__PURE__ */
|
|
2682
|
+
return /* @__PURE__ */ jsx10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx10("path", { d: "M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6" }) });
|
|
2222
2683
|
}
|
|
2223
2684
|
function CopyGlyph({ className }) {
|
|
2224
|
-
return /* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2226
|
-
/* @__PURE__ */
|
|
2685
|
+
return /* @__PURE__ */ jsxs8("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
2686
|
+
/* @__PURE__ */ jsx10("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
|
|
2687
|
+
/* @__PURE__ */ jsx10("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
2227
2688
|
] });
|
|
2228
2689
|
}
|
|
2229
2690
|
function TraceIdCopy({ traceId }) {
|
|
2230
|
-
const [copied, setCopied] =
|
|
2231
|
-
const copy =
|
|
2691
|
+
const [copied, setCopied] = useState12(false);
|
|
2692
|
+
const copy = useCallback7(() => {
|
|
2232
2693
|
void navigator.clipboard?.writeText(traceId).then(
|
|
2233
2694
|
() => {
|
|
2234
2695
|
setCopied(true);
|
|
@@ -2238,7 +2699,7 @@ function TraceIdCopy({ traceId }) {
|
|
|
2238
2699
|
}
|
|
2239
2700
|
);
|
|
2240
2701
|
}, [traceId]);
|
|
2241
|
-
return /* @__PURE__ */
|
|
2702
|
+
return /* @__PURE__ */ jsxs8(
|
|
2242
2703
|
"button",
|
|
2243
2704
|
{
|
|
2244
2705
|
type: "button",
|
|
@@ -2247,23 +2708,23 @@ function TraceIdCopy({ traceId }) {
|
|
|
2247
2708
|
"aria-label": "Copy trace id",
|
|
2248
2709
|
className: "inline-flex min-w-0 items-center gap-1.5 rounded text-left font-mono text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-card",
|
|
2249
2710
|
children: [
|
|
2250
|
-
/* @__PURE__ */
|
|
2251
|
-
/* @__PURE__ */
|
|
2252
|
-
copied && /* @__PURE__ */
|
|
2711
|
+
/* @__PURE__ */ jsx10("span", { className: "truncate", children: traceId }),
|
|
2712
|
+
/* @__PURE__ */ jsx10(CopyGlyph, { className: "h-3 w-3 shrink-0" }),
|
|
2713
|
+
copied && /* @__PURE__ */ jsx10("span", { className: "shrink-0 not-italic text-success", children: "copied" })
|
|
2253
2714
|
]
|
|
2254
2715
|
}
|
|
2255
2716
|
);
|
|
2256
2717
|
}
|
|
2257
2718
|
function StatusDot({ tone }) {
|
|
2258
|
-
return /* @__PURE__ */
|
|
2259
|
-
/* @__PURE__ */
|
|
2719
|
+
return /* @__PURE__ */ jsxs8("span", { className: "inline-flex items-center", children: [
|
|
2720
|
+
/* @__PURE__ */ jsx10(
|
|
2260
2721
|
"span",
|
|
2261
2722
|
{
|
|
2262
2723
|
"aria-hidden": true,
|
|
2263
2724
|
className: `h-2 w-2 shrink-0 rounded-full ${tone === "live" ? "animate-pulse bg-warning" : tone === "ok" ? "bg-success" : tone === "error" ? "bg-destructive" : "bg-muted-foreground/40"}`
|
|
2264
2725
|
}
|
|
2265
2726
|
),
|
|
2266
|
-
/* @__PURE__ */
|
|
2727
|
+
/* @__PURE__ */ jsx10("span", { className: "sr-only", children: tone })
|
|
2267
2728
|
] });
|
|
2268
2729
|
}
|
|
2269
2730
|
var BAR_CLASS = {
|
|
@@ -2275,19 +2736,19 @@ function FlowWaterfall({ trace }) {
|
|
|
2275
2736
|
const rows = waterfallLayout(trace);
|
|
2276
2737
|
if (rows.length === 0) return null;
|
|
2277
2738
|
const cost = formatActivityCost(trace.costUsd);
|
|
2278
|
-
return /* @__PURE__ */
|
|
2279
|
-
rows.map((row, i) => /* @__PURE__ */
|
|
2280
|
-
/* @__PURE__ */
|
|
2281
|
-
/* @__PURE__ */
|
|
2739
|
+
return /* @__PURE__ */ jsxs8("div", { className: "space-y-1", children: [
|
|
2740
|
+
rows.map((row, i) => /* @__PURE__ */ jsxs8("div", { className: "grid grid-cols-[minmax(0,2fr)_minmax(0,3fr)_auto] items-center gap-2", children: [
|
|
2741
|
+
/* @__PURE__ */ jsx10("span", { className: "truncate font-mono text-[11px] text-muted-foreground", title: row.name, children: row.name }),
|
|
2742
|
+
/* @__PURE__ */ jsx10("div", { className: "relative h-2 rounded-sm bg-muted/40", children: /* @__PURE__ */ jsx10(
|
|
2282
2743
|
"div",
|
|
2283
2744
|
{
|
|
2284
2745
|
className: `absolute inset-y-0 rounded-sm ${row.ok ? BAR_CLASS[row.kind] : "bg-destructive/80"} ${row.approx ? "opacity-70" : ""}`,
|
|
2285
2746
|
style: { left: `${row.offsetPct}%`, width: `${row.widthPct}%` }
|
|
2286
2747
|
}
|
|
2287
2748
|
) }),
|
|
2288
|
-
/* @__PURE__ */
|
|
2749
|
+
/* @__PURE__ */ jsx10("span", { className: "shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: row.durationLabel })
|
|
2289
2750
|
] }, i)),
|
|
2290
|
-
/* @__PURE__ */
|
|
2751
|
+
/* @__PURE__ */ jsxs8("p", { className: "pt-0.5 text-right font-mono text-[10px] tabular-nums text-muted-foreground/60", children: [
|
|
2291
2752
|
(trace.totalMs / 1e3).toFixed(1),
|
|
2292
2753
|
"s",
|
|
2293
2754
|
cost ? ` \xB7 ${cost}` : ""
|
|
@@ -2295,43 +2756,43 @@ function FlowWaterfall({ trace }) {
|
|
|
2295
2756
|
] });
|
|
2296
2757
|
}
|
|
2297
2758
|
function MissionActivityLane({ activity, startedAt, nowMs }) {
|
|
2298
|
-
const [expanded, setExpanded] =
|
|
2759
|
+
const [expanded, setExpanded] = useState12(false);
|
|
2299
2760
|
if (activity.length === 0) return null;
|
|
2300
|
-
return /* @__PURE__ */
|
|
2761
|
+
return /* @__PURE__ */ jsxs8("div", { className: "mt-1 border-l border-border/50 pl-3", children: [
|
|
2301
2762
|
activity.map((run) => {
|
|
2302
2763
|
const tone = activityTone(run.status);
|
|
2303
2764
|
const cost = formatActivityCost(run.costUsd);
|
|
2304
2765
|
const duration = formatActivityDuration(run.durationMs);
|
|
2305
|
-
return /* @__PURE__ */
|
|
2306
|
-
/* @__PURE__ */
|
|
2307
|
-
/* @__PURE__ */
|
|
2308
|
-
/* @__PURE__ */
|
|
2309
|
-
/* @__PURE__ */
|
|
2766
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
|
|
2767
|
+
/* @__PURE__ */ jsx10(StatusDot, { tone }),
|
|
2768
|
+
/* @__PURE__ */ jsxs8("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
2769
|
+
/* @__PURE__ */ jsx10("span", { className: "font-medium", children: run.tool }),
|
|
2770
|
+
/* @__PURE__ */ jsxs8("span", { className: "text-muted-foreground", children: [
|
|
2310
2771
|
" \u2014 ",
|
|
2311
2772
|
run.detail
|
|
2312
2773
|
] })
|
|
2313
2774
|
] }),
|
|
2314
|
-
tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
tone !== "live" && tone !== "ok" && /* @__PURE__ */
|
|
2317
|
-
cost && /* @__PURE__ */
|
|
2318
|
-
duration && /* @__PURE__ */
|
|
2775
|
+
tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */ jsx10("span", { className: "shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 font-mono text-[10px] text-warning", children: [run.iteration !== void 0 ? `iter ${run.iteration}` : null, run.phase ?? null].filter(Boolean).join(" \xB7 ") }),
|
|
2776
|
+
/* @__PURE__ */ jsxs8("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: [
|
|
2777
|
+
tone !== "live" && tone !== "ok" && /* @__PURE__ */ jsx10("span", { children: run.status }),
|
|
2778
|
+
cost && /* @__PURE__ */ jsx10("span", { children: cost }),
|
|
2779
|
+
duration && /* @__PURE__ */ jsx10("span", { children: duration })
|
|
2319
2780
|
] })
|
|
2320
2781
|
] }, run.taskId);
|
|
2321
2782
|
}),
|
|
2322
|
-
/* @__PURE__ */
|
|
2783
|
+
/* @__PURE__ */ jsxs8(
|
|
2323
2784
|
"button",
|
|
2324
2785
|
{
|
|
2325
2786
|
type: "button",
|
|
2326
2787
|
onClick: () => setExpanded((v) => !v),
|
|
2327
2788
|
className: "flex items-center gap-1 py-0.5 text-[10px] font-medium text-muted-foreground/70 transition hover:text-foreground",
|
|
2328
2789
|
children: [
|
|
2329
|
-
/* @__PURE__ */
|
|
2790
|
+
/* @__PURE__ */ jsx10(ChevronGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
|
|
2330
2791
|
"timeline"
|
|
2331
2792
|
]
|
|
2332
2793
|
}
|
|
2333
2794
|
),
|
|
2334
|
-
expanded && /* @__PURE__ */
|
|
2795
|
+
expanded && /* @__PURE__ */ jsx10("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx10(
|
|
2335
2796
|
FlowWaterfall,
|
|
2336
2797
|
{
|
|
2337
2798
|
trace: stepActivityFlowTrace(activity, {
|
|
@@ -2346,45 +2807,45 @@ function ActivityRow({
|
|
|
2346
2807
|
record,
|
|
2347
2808
|
renderMissionRef
|
|
2348
2809
|
}) {
|
|
2349
|
-
const [open, setOpen] =
|
|
2810
|
+
const [open, setOpen] = useState12(false);
|
|
2350
2811
|
const tone = activityTone(record.status);
|
|
2351
2812
|
const cost = formatActivityCost(record.costUsd);
|
|
2352
2813
|
const duration = formatActivityDuration(record.durationMs);
|
|
2353
|
-
return /* @__PURE__ */
|
|
2354
|
-
/* @__PURE__ */
|
|
2355
|
-
/* @__PURE__ */
|
|
2356
|
-
/* @__PURE__ */
|
|
2357
|
-
/* @__PURE__ */
|
|
2358
|
-
/* @__PURE__ */
|
|
2814
|
+
return /* @__PURE__ */ jsxs8("div", { className: "rounded-lg border border-border/60 bg-card", children: [
|
|
2815
|
+
/* @__PURE__ */ jsxs8("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm", children: [
|
|
2816
|
+
/* @__PURE__ */ jsx10(StatusDot, { tone }),
|
|
2817
|
+
/* @__PURE__ */ jsxs8("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
2818
|
+
/* @__PURE__ */ jsx10("span", { className: "font-medium", children: record.tool }),
|
|
2819
|
+
/* @__PURE__ */ jsxs8("span", { className: "text-muted-foreground", children: [
|
|
2359
2820
|
" \u2014 ",
|
|
2360
2821
|
record.detail
|
|
2361
2822
|
] })
|
|
2362
2823
|
] }),
|
|
2363
|
-
tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */
|
|
2364
|
-
/* @__PURE__ */
|
|
2824
|
+
tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */ jsx10("span", { className: "shrink-0 rounded-full bg-warning/10 px-2 py-0.5 font-mono text-[10px] text-warning", children: [record.iteration !== void 0 ? `iter ${record.iteration}` : null, record.phase ?? null].filter(Boolean).join(" \xB7 ") }),
|
|
2825
|
+
/* @__PURE__ */ jsx10(
|
|
2365
2826
|
"span",
|
|
2366
2827
|
{
|
|
2367
2828
|
className: `shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium ${tone === "ok" ? "bg-success/10 text-success" : tone === "error" ? "bg-destructive/10 text-destructive" : tone === "live" ? "bg-warning/10 text-warning" : "bg-muted/60 text-muted-foreground"}`,
|
|
2368
2829
|
children: record.status
|
|
2369
2830
|
}
|
|
2370
2831
|
),
|
|
2371
|
-
cost && /* @__PURE__ */
|
|
2372
|
-
/* @__PURE__ */
|
|
2832
|
+
cost && /* @__PURE__ */ jsx10("span", { className: "shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground", children: cost }),
|
|
2833
|
+
/* @__PURE__ */ jsx10(ChevronGlyph, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })
|
|
2373
2834
|
] }),
|
|
2374
|
-
open && /* @__PURE__ */
|
|
2375
|
-
record.durationMs !== void 0 && /* @__PURE__ */
|
|
2376
|
-
/* @__PURE__ */
|
|
2377
|
-
/* @__PURE__ */
|
|
2378
|
-
/* @__PURE__ */
|
|
2379
|
-
/* @__PURE__ */
|
|
2380
|
-
/* @__PURE__ */
|
|
2381
|
-
duration && /* @__PURE__ */
|
|
2382
|
-
/* @__PURE__ */
|
|
2383
|
-
/* @__PURE__ */
|
|
2835
|
+
open && /* @__PURE__ */ jsxs8("div", { className: "space-y-2.5 border-t border-border/40 px-3 py-2.5", children: [
|
|
2836
|
+
record.durationMs !== void 0 && /* @__PURE__ */ jsx10("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx10(FlowWaterfall, { trace: stepActivityFlowTrace([record]) }) }),
|
|
2837
|
+
/* @__PURE__ */ jsxs8("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-[11px]", children: [
|
|
2838
|
+
/* @__PURE__ */ jsx10("dt", { className: "text-muted-foreground/60", children: "task" }),
|
|
2839
|
+
/* @__PURE__ */ jsx10("dd", { className: "truncate text-muted-foreground", children: record.taskId }),
|
|
2840
|
+
/* @__PURE__ */ jsx10("dt", { className: "text-muted-foreground/60", children: "started" }),
|
|
2841
|
+
/* @__PURE__ */ jsx10("dd", { className: "text-muted-foreground", children: new Date(record.startedAt).toLocaleString() }),
|
|
2842
|
+
duration && /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
2843
|
+
/* @__PURE__ */ jsx10("dt", { className: "text-muted-foreground/60", children: "duration" }),
|
|
2844
|
+
/* @__PURE__ */ jsx10("dd", { className: "text-muted-foreground", children: duration })
|
|
2384
2845
|
] }),
|
|
2385
|
-
record.traceId && /* @__PURE__ */
|
|
2386
|
-
/* @__PURE__ */
|
|
2387
|
-
/* @__PURE__ */
|
|
2846
|
+
record.traceId && /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
2847
|
+
/* @__PURE__ */ jsx10("dt", { className: "text-muted-foreground/60", children: "trace" }),
|
|
2848
|
+
/* @__PURE__ */ jsx10("dd", { className: "min-w-0", children: /* @__PURE__ */ jsx10(TraceIdCopy, { traceId: record.traceId }) })
|
|
2388
2849
|
] })
|
|
2389
2850
|
] }),
|
|
2390
2851
|
record.missionRef && renderMissionRef?.(record.missionRef, record)
|
|
@@ -2392,11 +2853,11 @@ function ActivityRow({
|
|
|
2392
2853
|
] });
|
|
2393
2854
|
}
|
|
2394
2855
|
function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent activity", emptyLabel = "No agent runs yet." }) {
|
|
2395
|
-
const [rows, setRows] =
|
|
2396
|
-
const [cursor, setCursor] =
|
|
2397
|
-
const [loading, setLoading] =
|
|
2398
|
-
const [error, setError] =
|
|
2399
|
-
const load =
|
|
2856
|
+
const [rows, setRows] = useState12([]);
|
|
2857
|
+
const [cursor, setCursor] = useState12(void 0);
|
|
2858
|
+
const [loading, setLoading] = useState12(false);
|
|
2859
|
+
const [error, setError] = useState12(null);
|
|
2860
|
+
const load = useCallback7(
|
|
2400
2861
|
async (from) => {
|
|
2401
2862
|
setLoading(true);
|
|
2402
2863
|
setError(null);
|
|
@@ -2412,13 +2873,13 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
2412
2873
|
},
|
|
2413
2874
|
[fetchActivity]
|
|
2414
2875
|
);
|
|
2415
|
-
|
|
2876
|
+
useEffect9(() => {
|
|
2416
2877
|
void load();
|
|
2417
2878
|
}, [load]);
|
|
2418
|
-
return /* @__PURE__ */
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
/* @__PURE__ */
|
|
2879
|
+
return /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
|
|
2880
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
2881
|
+
/* @__PURE__ */ jsx10("h2", { className: "flex-1 text-sm font-semibold", children: title }),
|
|
2882
|
+
/* @__PURE__ */ jsx10(
|
|
2422
2883
|
"button",
|
|
2423
2884
|
{
|
|
2424
2885
|
type: "button",
|
|
@@ -2426,14 +2887,14 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
2426
2887
|
disabled: loading,
|
|
2427
2888
|
"aria-label": "Refresh",
|
|
2428
2889
|
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground disabled:opacity-50",
|
|
2429
|
-
children: /* @__PURE__ */
|
|
2890
|
+
children: /* @__PURE__ */ jsx10(RefreshGlyph, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` })
|
|
2430
2891
|
}
|
|
2431
2892
|
)
|
|
2432
2893
|
] }),
|
|
2433
|
-
error && /* @__PURE__ */
|
|
2434
|
-
!error && rows.length === 0 && !loading && /* @__PURE__ */
|
|
2435
|
-
/* @__PURE__ */
|
|
2436
|
-
cursor && /* @__PURE__ */
|
|
2894
|
+
error && /* @__PURE__ */ jsx10("p", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: error }),
|
|
2895
|
+
!error && rows.length === 0 && !loading && /* @__PURE__ */ jsx10("p", { className: "px-1 text-sm text-muted-foreground", children: emptyLabel }),
|
|
2896
|
+
/* @__PURE__ */ jsx10("div", { className: "space-y-1.5", children: rows.map((record) => /* @__PURE__ */ jsx10(ActivityRow, { record, renderMissionRef }, record.taskId)) }),
|
|
2897
|
+
cursor && /* @__PURE__ */ jsx10(
|
|
2437
2898
|
"button",
|
|
2438
2899
|
{
|
|
2439
2900
|
type: "button",
|
|
@@ -2447,9 +2908,9 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
2447
2908
|
}
|
|
2448
2909
|
|
|
2449
2910
|
// src/web-react/seat-paywall.tsx
|
|
2450
|
-
import { jsx as
|
|
2911
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2451
2912
|
function CheckGlyph3() {
|
|
2452
|
-
return /* @__PURE__ */
|
|
2913
|
+
return /* @__PURE__ */ jsx11(
|
|
2453
2914
|
"svg",
|
|
2454
2915
|
{
|
|
2455
2916
|
className: "h-4 w-4 shrink-0 text-primary",
|
|
@@ -2460,14 +2921,14 @@ function CheckGlyph3() {
|
|
|
2460
2921
|
strokeLinecap: "round",
|
|
2461
2922
|
strokeLinejoin: "round",
|
|
2462
2923
|
"aria-hidden": true,
|
|
2463
|
-
children: /* @__PURE__ */
|
|
2924
|
+
children: /* @__PURE__ */ jsx11("path", { d: "M20 6 9 17l-5-5" })
|
|
2464
2925
|
}
|
|
2465
2926
|
);
|
|
2466
2927
|
}
|
|
2467
2928
|
function Benefit({ children }) {
|
|
2468
|
-
return /* @__PURE__ */
|
|
2469
|
-
/* @__PURE__ */
|
|
2470
|
-
/* @__PURE__ */
|
|
2929
|
+
return /* @__PURE__ */ jsxs9("li", { className: "flex items-start gap-2.5 text-sm text-foreground", children: [
|
|
2930
|
+
/* @__PURE__ */ jsx11("span", { className: "mt-0.5", children: /* @__PURE__ */ jsx11(CheckGlyph3, {}) }),
|
|
2931
|
+
/* @__PURE__ */ jsx11("span", { children })
|
|
2471
2932
|
] });
|
|
2472
2933
|
}
|
|
2473
2934
|
function SeatPaywall({
|
|
@@ -2481,30 +2942,30 @@ function SeatPaywall({
|
|
|
2481
2942
|
footnote
|
|
2482
2943
|
}) {
|
|
2483
2944
|
const { pending, run } = usePending();
|
|
2484
|
-
return /* @__PURE__ */
|
|
2485
|
-
/* @__PURE__ */
|
|
2486
|
-
/* @__PURE__ */
|
|
2945
|
+
return /* @__PURE__ */ jsx11("div", { className: "flex min-h-[60vh] w-full items-center justify-center p-6", children: /* @__PURE__ */ jsxs9("div", { className: "w-full max-w-md rounded-2xl border border-border bg-card p-8 shadow-sm", children: [
|
|
2946
|
+
/* @__PURE__ */ jsx11("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: product }),
|
|
2947
|
+
/* @__PURE__ */ jsxs9("h1", { className: "mt-2 text-2xl font-semibold tracking-tight text-foreground", children: [
|
|
2487
2948
|
"Unlock ",
|
|
2488
2949
|
product
|
|
2489
2950
|
] }),
|
|
2490
|
-
tagline && /* @__PURE__ */
|
|
2491
|
-
/* @__PURE__ */
|
|
2492
|
-
/* @__PURE__ */
|
|
2951
|
+
tagline && /* @__PURE__ */ jsx11("p", { className: "mt-2 text-sm text-muted-foreground", children: tagline }),
|
|
2952
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-6 flex items-baseline gap-1.5", children: [
|
|
2953
|
+
/* @__PURE__ */ jsxs9("span", { className: "text-3xl font-semibold text-foreground", children: [
|
|
2493
2954
|
"$",
|
|
2494
2955
|
priceUsd
|
|
2495
2956
|
] }),
|
|
2496
|
-
/* @__PURE__ */
|
|
2957
|
+
/* @__PURE__ */ jsx11("span", { className: "text-sm text-muted-foreground", children: "/mo" })
|
|
2497
2958
|
] }),
|
|
2498
|
-
/* @__PURE__ */
|
|
2959
|
+
/* @__PURE__ */ jsxs9("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
2499
2960
|
"Includes $",
|
|
2500
2961
|
includedUsageUsd,
|
|
2501
2962
|
"/mo of AI usage"
|
|
2502
2963
|
] }),
|
|
2503
|
-
/* @__PURE__ */
|
|
2964
|
+
/* @__PURE__ */ jsx11("ul", { className: "mt-6 space-y-2.5", children: (benefits ?? [
|
|
2504
2965
|
`Full access to ${product}`,
|
|
2505
2966
|
`$${includedUsageUsd}/mo of AI usage included, every month`
|
|
2506
|
-
]).map((benefit, i) => /* @__PURE__ */
|
|
2507
|
-
/* @__PURE__ */
|
|
2967
|
+
]).map((benefit, i) => /* @__PURE__ */ jsx11(Benefit, { children: benefit }, i)) }),
|
|
2968
|
+
/* @__PURE__ */ jsx11(
|
|
2508
2969
|
"button",
|
|
2509
2970
|
{
|
|
2510
2971
|
type: "button",
|
|
@@ -2514,13 +2975,13 @@ function SeatPaywall({
|
|
|
2514
2975
|
children: pending ? "Opening checkout\u2026" : ctaLabel ?? `Unlock ${product}`
|
|
2515
2976
|
}
|
|
2516
2977
|
),
|
|
2517
|
-
footnote && /* @__PURE__ */
|
|
2978
|
+
footnote && /* @__PURE__ */ jsx11("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: footnote })
|
|
2518
2979
|
] }) });
|
|
2519
2980
|
}
|
|
2520
2981
|
|
|
2521
2982
|
// src/web-react/agent-session-controls.tsx
|
|
2522
|
-
import { useMemo as
|
|
2523
|
-
import { jsx as
|
|
2983
|
+
import { useMemo as useMemo7, useState as useState13 } from "react";
|
|
2984
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2524
2985
|
var HARNESS_LABELS = {
|
|
2525
2986
|
opencode: "OpenCode (any model)",
|
|
2526
2987
|
"claude-code": "Claude Code (Anthropic)",
|
|
@@ -2540,12 +3001,12 @@ function harnessLabel(h) {
|
|
|
2540
3001
|
return HARNESS_LABELS[h] ?? h;
|
|
2541
3002
|
}
|
|
2542
3003
|
function ChevronDown2({ className }) {
|
|
2543
|
-
return /* @__PURE__ */
|
|
3004
|
+
return /* @__PURE__ */ jsx12("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" }) });
|
|
2544
3005
|
}
|
|
2545
3006
|
function GearGlyph({ className }) {
|
|
2546
|
-
return /* @__PURE__ */
|
|
2547
|
-
/* @__PURE__ */
|
|
2548
|
-
/* @__PURE__ */
|
|
3007
|
+
return /* @__PURE__ */ jsxs10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
3008
|
+
/* @__PURE__ */ jsx12("circle", { cx: "12", cy: "12", r: "3" }),
|
|
3009
|
+
/* @__PURE__ */ jsx12("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
|
|
2549
3010
|
] });
|
|
2550
3011
|
}
|
|
2551
3012
|
var FOCUS_RING = "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background";
|
|
@@ -2554,11 +3015,11 @@ function HarnessPicker({
|
|
|
2554
3015
|
onChange,
|
|
2555
3016
|
available
|
|
2556
3017
|
}) {
|
|
2557
|
-
const [open, setOpen] =
|
|
3018
|
+
const [open, setOpen] = useState13(false);
|
|
2558
3019
|
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
2559
3020
|
const options = available ?? Object.keys(HARNESS_LABELS);
|
|
2560
|
-
return /* @__PURE__ */
|
|
2561
|
-
/* @__PURE__ */
|
|
3021
|
+
return /* @__PURE__ */ jsxs10("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
3022
|
+
/* @__PURE__ */ jsxs10(
|
|
2562
3023
|
"button",
|
|
2563
3024
|
{
|
|
2564
3025
|
type: "button",
|
|
@@ -2567,12 +3028,12 @@ function HarnessPicker({
|
|
|
2567
3028
|
title: "Agent backend",
|
|
2568
3029
|
className: `inline-flex w-full items-center justify-between gap-1.5 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30 ${FOCUS_RING}`,
|
|
2569
3030
|
children: [
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
/* @__PURE__ */
|
|
3031
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate", children: harnessLabel(value) }),
|
|
3032
|
+
/* @__PURE__ */ jsx12(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
2572
3033
|
]
|
|
2573
3034
|
}
|
|
2574
3035
|
),
|
|
2575
|
-
open && /* @__PURE__ */
|
|
3036
|
+
open && /* @__PURE__ */ jsx12("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 max-h-64 w-full min-w-[220px] overflow-y-auto rounded-xl border border-border bg-card p-1 shadow-lg", children: options.map((h) => /* @__PURE__ */ jsx12(
|
|
2576
3037
|
"button",
|
|
2577
3038
|
{
|
|
2578
3039
|
type: "button",
|
|
@@ -2591,7 +3052,7 @@ function HarnessPicker({
|
|
|
2591
3052
|
}
|
|
2592
3053
|
function useCoherentHandlers(props) {
|
|
2593
3054
|
const { model, models, harness, onModelChange, onHarnessChange } = props;
|
|
2594
|
-
const canonicalIds =
|
|
3055
|
+
const canonicalIds = useMemo7(() => models.map((m) => m.id), [models]);
|
|
2595
3056
|
const onModel = (next) => {
|
|
2596
3057
|
onModelChange(next);
|
|
2597
3058
|
const nextHarness = snapHarnessToModel(harness, next);
|
|
@@ -2619,11 +3080,11 @@ function AgentSessionControls(props) {
|
|
|
2619
3080
|
className
|
|
2620
3081
|
} = props;
|
|
2621
3082
|
const { onModel, onHarness } = useCoherentHandlers(props);
|
|
2622
|
-
const [open, setOpen] =
|
|
3083
|
+
const [open, setOpen] = useState13(false);
|
|
2623
3084
|
const { containerRef: popoverRef, triggerProps } = usePopover(open, setOpen);
|
|
2624
3085
|
const selectedModel = models.find((m) => m.id === model);
|
|
2625
3086
|
const showEffort = selectedModel?.supportsReasoning ?? true;
|
|
2626
|
-
const modelPicker = /* @__PURE__ */
|
|
3087
|
+
const modelPicker = /* @__PURE__ */ jsx12(
|
|
2627
3088
|
ModelPicker,
|
|
2628
3089
|
{
|
|
2629
3090
|
value: model,
|
|
@@ -2634,17 +3095,17 @@ function AgentSessionControls(props) {
|
|
|
2634
3095
|
}
|
|
2635
3096
|
);
|
|
2636
3097
|
if (layout === "inline") {
|
|
2637
|
-
return /* @__PURE__ */
|
|
3098
|
+
return /* @__PURE__ */ jsxs10("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
2638
3099
|
modelPicker,
|
|
2639
|
-
showHarness && /* @__PURE__ */
|
|
2640
|
-
showEffort && /* @__PURE__ */
|
|
3100
|
+
showHarness && /* @__PURE__ */ jsx12(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
3101
|
+
showEffort && /* @__PURE__ */ jsx12(EffortPicker, { value: effort, onChange: onEffortChange })
|
|
2641
3102
|
] });
|
|
2642
3103
|
}
|
|
2643
3104
|
const hasAdvanced = showHarness || showEffort;
|
|
2644
|
-
return /* @__PURE__ */
|
|
3105
|
+
return /* @__PURE__ */ jsxs10("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
2645
3106
|
modelPicker,
|
|
2646
|
-
hasAdvanced && /* @__PURE__ */
|
|
2647
|
-
/* @__PURE__ */
|
|
3107
|
+
hasAdvanced && /* @__PURE__ */ jsxs10("div", { ref: popoverRef, className: "relative inline-flex", children: [
|
|
3108
|
+
/* @__PURE__ */ jsx12(
|
|
2648
3109
|
"button",
|
|
2649
3110
|
{
|
|
2650
3111
|
type: "button",
|
|
@@ -2653,19 +3114,19 @@ function AgentSessionControls(props) {
|
|
|
2653
3114
|
title: "Model settings \u2014 pick the agent backend and how hard it thinks",
|
|
2654
3115
|
className: `flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground data-[state=open]:bg-muted ${FOCUS_RING}`,
|
|
2655
3116
|
"data-state": open ? "open" : "closed",
|
|
2656
|
-
children: /* @__PURE__ */
|
|
3117
|
+
children: /* @__PURE__ */ jsx12(GearGlyph, { className: "h-4 w-4" })
|
|
2657
3118
|
}
|
|
2658
3119
|
),
|
|
2659
|
-
open && /* @__PURE__ */
|
|
2660
|
-
showHarness && /* @__PURE__ */
|
|
2661
|
-
/* @__PURE__ */
|
|
2662
|
-
/* @__PURE__ */
|
|
2663
|
-
/* @__PURE__ */
|
|
3120
|
+
open && /* @__PURE__ */ jsxs10("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-72 space-y-3 rounded-xl border border-border bg-card p-3 shadow-lg", children: [
|
|
3121
|
+
showHarness && /* @__PURE__ */ jsxs10("div", { className: "space-y-1.5", children: [
|
|
3122
|
+
/* @__PURE__ */ jsx12("p", { className: "text-xs font-medium text-foreground", children: "Agent backend" }),
|
|
3123
|
+
/* @__PURE__ */ jsx12(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
3124
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "The engine that runs the agent. Switching it keeps your model choice compatible." })
|
|
2664
3125
|
] }),
|
|
2665
|
-
showEffort && /* @__PURE__ */
|
|
2666
|
-
/* @__PURE__ */
|
|
2667
|
-
/* @__PURE__ */
|
|
2668
|
-
/* @__PURE__ */
|
|
3126
|
+
showEffort && /* @__PURE__ */ jsxs10("div", { className: "space-y-1.5", children: [
|
|
3127
|
+
/* @__PURE__ */ jsx12("p", { className: "text-xs font-medium text-foreground", children: "Thinking" }),
|
|
3128
|
+
/* @__PURE__ */ jsx12(EffortPicker, { value: effort, onChange: onEffortChange, label: "" }),
|
|
3129
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "How hard the agent thinks before answering. Higher is slower but more thorough." })
|
|
2669
3130
|
] })
|
|
2670
3131
|
] })
|
|
2671
3132
|
] })
|
|
@@ -2673,7 +3134,7 @@ function AgentSessionControls(props) {
|
|
|
2673
3134
|
}
|
|
2674
3135
|
|
|
2675
3136
|
// src/web-react/index.tsx
|
|
2676
|
-
import { Fragment as Fragment5, jsx as
|
|
3137
|
+
import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2677
3138
|
function formatModelCost(msg, models) {
|
|
2678
3139
|
if (msg.promptTokens == null && msg.completionTokens == null) return null;
|
|
2679
3140
|
const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing;
|
|
@@ -2687,41 +3148,41 @@ function formatTokensPerSecond(msg) {
|
|
|
2687
3148
|
return `${Math.round(msg.completionTokens / (msg.durationMs / 1e3))} tok/s`;
|
|
2688
3149
|
}
|
|
2689
3150
|
function RunDrillIn({ run, onClose }) {
|
|
2690
|
-
return /* @__PURE__ */
|
|
2691
|
-
/* @__PURE__ */
|
|
2692
|
-
/* @__PURE__ */
|
|
3151
|
+
return /* @__PURE__ */ jsxs11("div", { className: "fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-border bg-card shadow-xl", children: [
|
|
3152
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
|
|
3153
|
+
/* @__PURE__ */ jsx13(
|
|
2693
3154
|
"span",
|
|
2694
3155
|
{
|
|
2695
3156
|
className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-warning" : run.status === "error" ? "bg-destructive" : "bg-success"}`
|
|
2696
3157
|
}
|
|
2697
3158
|
),
|
|
2698
|
-
/* @__PURE__ */
|
|
2699
|
-
/* @__PURE__ */
|
|
2700
|
-
/* @__PURE__ */
|
|
3159
|
+
/* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
|
|
3160
|
+
/* @__PURE__ */ jsx13("p", { className: "truncate text-sm font-semibold", children: run.title }),
|
|
3161
|
+
/* @__PURE__ */ jsx13("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
|
|
2701
3162
|
] }),
|
|
2702
|
-
/* @__PURE__ */
|
|
3163
|
+
/* @__PURE__ */ jsx13(
|
|
2703
3164
|
"button",
|
|
2704
3165
|
{
|
|
2705
3166
|
type: "button",
|
|
2706
3167
|
onClick: onClose,
|
|
2707
3168
|
"aria-label": "Close",
|
|
2708
3169
|
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground",
|
|
2709
|
-
children: /* @__PURE__ */
|
|
3170
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx13("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
2710
3171
|
}
|
|
2711
3172
|
)
|
|
2712
3173
|
] }),
|
|
2713
|
-
/* @__PURE__ */
|
|
2714
|
-
run.steps.length === 0 && /* @__PURE__ */
|
|
2715
|
-
run.steps.map((step, i) => /* @__PURE__ */
|
|
2716
|
-
/* @__PURE__ */
|
|
2717
|
-
/* @__PURE__ */
|
|
2718
|
-
/* @__PURE__ */
|
|
2719
|
-
/* @__PURE__ */
|
|
3174
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
|
|
3175
|
+
run.steps.length === 0 && /* @__PURE__ */ jsx13("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
|
|
3176
|
+
run.steps.map((step, i) => /* @__PURE__ */ jsxs11("div", { className: "rounded-lg border border-border/60 bg-background", children: [
|
|
3177
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
|
|
3178
|
+
/* @__PURE__ */ jsx13("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-destructive" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
|
|
3179
|
+
/* @__PURE__ */ jsx13("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
|
|
3180
|
+
/* @__PURE__ */ jsx13("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: new Date(step.at).toLocaleTimeString() })
|
|
2720
3181
|
] }),
|
|
2721
|
-
step.detail && /* @__PURE__ */
|
|
3182
|
+
step.detail && /* @__PURE__ */ jsx13("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: step.detail })
|
|
2722
3183
|
] }, i))
|
|
2723
3184
|
] }),
|
|
2724
|
-
/* @__PURE__ */
|
|
3185
|
+
/* @__PURE__ */ jsx13("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground", children: "Readonly drill-in. Follow up in the main chat." })
|
|
2725
3186
|
] });
|
|
2726
3187
|
}
|
|
2727
3188
|
function pendingApprovalOf(call) {
|
|
@@ -2735,20 +3196,20 @@ function ChatEmptyState({
|
|
|
2735
3196
|
subline = "Describe the outcome you want. The agent works through it step by step, and pauses for your approval before anything irreversible.",
|
|
2736
3197
|
doors
|
|
2737
3198
|
}) {
|
|
2738
|
-
return /* @__PURE__ */
|
|
2739
|
-
/* @__PURE__ */
|
|
2740
|
-
/* @__PURE__ */
|
|
2741
|
-
/* @__PURE__ */
|
|
2742
|
-
subline && /* @__PURE__ */
|
|
2743
|
-
doors && doors.length > 0 && /* @__PURE__ */
|
|
3199
|
+
return /* @__PURE__ */ jsxs11("div", { className: "mx-auto flex w-full max-w-2xl flex-col items-center px-6 py-12 text-center sm:py-20", children: [
|
|
3200
|
+
/* @__PURE__ */ jsx13("span", { className: "mb-5 inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 ring-1 ring-primary/15", children: /* @__PURE__ */ jsx13(BrandMark, { size: 32, className: "shrink-0" }) }),
|
|
3201
|
+
/* @__PURE__ */ jsx13("p", { className: "text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground", children: productName }),
|
|
3202
|
+
/* @__PURE__ */ jsx13("h2", { className: "mt-1.5 text-balance text-2xl font-semibold leading-tight text-foreground sm:text-[28px]", children: headline }),
|
|
3203
|
+
subline && /* @__PURE__ */ jsx13("p", { className: "mt-3 max-w-md text-[15px] leading-relaxed text-muted-foreground", children: subline }),
|
|
3204
|
+
doors && doors.length > 0 && /* @__PURE__ */ jsx13("div", { className: "mt-7 grid w-full gap-2.5 sm:grid-cols-3", children: doors.slice(0, 3).map((door, i) => /* @__PURE__ */ jsxs11(
|
|
2744
3205
|
"button",
|
|
2745
3206
|
{
|
|
2746
3207
|
type: "button",
|
|
2747
3208
|
onClick: door.onSelect,
|
|
2748
3209
|
className: "group flex min-h-[44px] flex-col items-start rounded-xl border border-border bg-card px-4 py-3 text-left transition hover:border-primary/40 hover:bg-accent/30 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
2749
3210
|
children: [
|
|
2750
|
-
/* @__PURE__ */
|
|
2751
|
-
door.description && /* @__PURE__ */
|
|
3211
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sm font-semibold text-foreground", children: door.label }),
|
|
3212
|
+
door.description && /* @__PURE__ */ jsx13("span", { className: "mt-0.5 text-[12px] leading-snug text-muted-foreground", children: door.description })
|
|
2752
3213
|
]
|
|
2753
3214
|
},
|
|
2754
3215
|
i
|
|
@@ -2757,26 +3218,26 @@ function ChatEmptyState({
|
|
|
2757
3218
|
}
|
|
2758
3219
|
function ToolGlyph({ name, className }) {
|
|
2759
3220
|
if (name.startsWith("sandbox_")) {
|
|
2760
|
-
return /* @__PURE__ */
|
|
2761
|
-
/* @__PURE__ */
|
|
2762
|
-
/* @__PURE__ */
|
|
3221
|
+
return /* @__PURE__ */ jsxs11("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
3222
|
+
/* @__PURE__ */ jsx13("polyline", { points: "4 17 10 11 4 5" }),
|
|
3223
|
+
/* @__PURE__ */ jsx13("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
|
|
2763
3224
|
] });
|
|
2764
3225
|
}
|
|
2765
3226
|
if (name === "submit_proposal") {
|
|
2766
|
-
return /* @__PURE__ */
|
|
2767
|
-
/* @__PURE__ */
|
|
2768
|
-
/* @__PURE__ */
|
|
3227
|
+
return /* @__PURE__ */ jsxs11("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
3228
|
+
/* @__PURE__ */ jsx13("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
3229
|
+
/* @__PURE__ */ jsx13("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
|
|
2769
3230
|
] });
|
|
2770
3231
|
}
|
|
2771
3232
|
if (name === "schedule_followup") {
|
|
2772
|
-
return /* @__PURE__ */
|
|
2773
|
-
/* @__PURE__ */
|
|
2774
|
-
/* @__PURE__ */
|
|
3233
|
+
return /* @__PURE__ */ jsxs11("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
|
|
3234
|
+
/* @__PURE__ */ jsx13("circle", { cx: "12", cy: "12", r: "9" }),
|
|
3235
|
+
/* @__PURE__ */ jsx13("path", { d: "M12 7v5l3 3" })
|
|
2775
3236
|
] });
|
|
2776
3237
|
}
|
|
2777
|
-
return /* @__PURE__ */
|
|
2778
|
-
/* @__PURE__ */
|
|
2779
|
-
/* @__PURE__ */
|
|
3238
|
+
return /* @__PURE__ */ jsxs11("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
3239
|
+
/* @__PURE__ */ jsx13("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
|
|
3240
|
+
/* @__PURE__ */ jsx13("circle", { cx: "12", cy: "12", r: "4" })
|
|
2780
3241
|
] });
|
|
2781
3242
|
}
|
|
2782
3243
|
function toolOutcomeOf(call) {
|
|
@@ -2844,40 +3305,40 @@ function truncate(v, max = 240) {
|
|
|
2844
3305
|
function KvRows({ data }) {
|
|
2845
3306
|
const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
|
|
2846
3307
|
if (!entries.length) return null;
|
|
2847
|
-
return /* @__PURE__ */
|
|
2848
|
-
/* @__PURE__ */
|
|
2849
|
-
/* @__PURE__ */
|
|
3308
|
+
return /* @__PURE__ */ jsx13("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs11("div", { className: "contents", children: [
|
|
3309
|
+
/* @__PURE__ */ jsx13("dt", { className: "font-mono text-[11px] text-muted-foreground", children: k }),
|
|
3310
|
+
/* @__PURE__ */ jsx13("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
|
|
2850
3311
|
] }, k)) });
|
|
2851
3312
|
}
|
|
2852
3313
|
function ShellDetail({ call }) {
|
|
2853
3314
|
const outcome = toolOutcomeOf(call);
|
|
2854
3315
|
const r = outcome?.result ?? {};
|
|
2855
|
-
return /* @__PURE__ */
|
|
2856
|
-
/* @__PURE__ */
|
|
2857
|
-
/* @__PURE__ */
|
|
2858
|
-
/* @__PURE__ */
|
|
2859
|
-
r.exitCode != null && /* @__PURE__ */
|
|
3316
|
+
return /* @__PURE__ */ jsxs11("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
|
|
3317
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
|
|
3318
|
+
/* @__PURE__ */ jsx13("span", { className: "select-none text-zinc-500", children: "$" }),
|
|
3319
|
+
/* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
|
|
3320
|
+
r.exitCode != null && /* @__PURE__ */ jsxs11("span", { className: r.exitCode === 0 ? "text-success" : "text-destructive", children: [
|
|
2860
3321
|
"exit ",
|
|
2861
3322
|
r.exitCode
|
|
2862
3323
|
] })
|
|
2863
3324
|
] }),
|
|
2864
|
-
/* @__PURE__ */
|
|
3325
|
+
/* @__PURE__ */ jsx13("pre", { className: "max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300", children: outcome?.ok === false ? outcome.message ?? "failed" : [r.stdout, r.stderr].filter(Boolean).join("\n") || "(no output)" })
|
|
2865
3326
|
] });
|
|
2866
3327
|
}
|
|
2867
3328
|
function DefaultToolDetail({ call }) {
|
|
2868
3329
|
const result = call.result;
|
|
2869
3330
|
const envelope = typeof result === "object" && result !== null ? result : null;
|
|
2870
|
-
return /* @__PURE__ */
|
|
2871
|
-
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */
|
|
2872
|
-
/* @__PURE__ */
|
|
2873
|
-
/* @__PURE__ */
|
|
3331
|
+
return /* @__PURE__ */ jsxs11("div", { className: "space-y-2", children: [
|
|
3332
|
+
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs11("div", { children: [
|
|
3333
|
+
/* @__PURE__ */ jsx13("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: "Called with" }),
|
|
3334
|
+
/* @__PURE__ */ jsx13(KvRows, { data: call.args })
|
|
2874
3335
|
] }),
|
|
2875
|
-
envelope ? /* @__PURE__ */
|
|
2876
|
-
/* @__PURE__ */
|
|
2877
|
-
envelope.ok === false ? /* @__PURE__ */
|
|
2878
|
-
] }) : result != null ? /* @__PURE__ */
|
|
2879
|
-
/* @__PURE__ */
|
|
2880
|
-
/* @__PURE__ */
|
|
3336
|
+
envelope ? /* @__PURE__ */ jsxs11("div", { children: [
|
|
3337
|
+
/* @__PURE__ */ jsx13("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: envelope.ok === false ? "Failed" : "Result" }),
|
|
3338
|
+
envelope.ok === false ? /* @__PURE__ */ jsx13("p", { className: "text-xs text-destructive", children: envelope.message ?? "Tool failed" }) : envelope.result && typeof envelope.result === "object" ? /* @__PURE__ */ jsx13(KvRows, { data: envelope.result }) : envelope.result != null ? /* @__PURE__ */ jsx13("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(envelope.result) }) : null
|
|
3339
|
+
] }) : result != null ? /* @__PURE__ */ jsxs11("div", { children: [
|
|
3340
|
+
/* @__PURE__ */ jsx13("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: "Result" }),
|
|
3341
|
+
/* @__PURE__ */ jsx13("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(result) })
|
|
2881
3342
|
] }) : null
|
|
2882
3343
|
] });
|
|
2883
3344
|
}
|
|
@@ -2888,23 +3349,23 @@ function ProposalCard({
|
|
|
2888
3349
|
approval,
|
|
2889
3350
|
renderers
|
|
2890
3351
|
}) {
|
|
2891
|
-
const [expanded, setExpanded] =
|
|
3352
|
+
const [expanded, setExpanded] = useState14(false);
|
|
2892
3353
|
const { summary, meta } = proposalPreview(call);
|
|
2893
3354
|
const custom = renderers?.[call.name]?.(call, message);
|
|
2894
3355
|
const { pending: deciding, run: decide } = usePending();
|
|
2895
|
-
return /* @__PURE__ */
|
|
2896
|
-
/* @__PURE__ */
|
|
2897
|
-
/* @__PURE__ */
|
|
2898
|
-
/* @__PURE__ */
|
|
2899
|
-
/* @__PURE__ */
|
|
2900
|
-
/* @__PURE__ */
|
|
2901
|
-
summary && /* @__PURE__ */
|
|
2902
|
-
meta.length > 0 && /* @__PURE__ */
|
|
3356
|
+
return /* @__PURE__ */ jsxs11("div", { className: "w-full max-w-full rounded-xl border border-warning/50 bg-warning/[0.06] text-sm shadow-sm ring-1 ring-warning/10", children: [
|
|
3357
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-start gap-2.5 px-4 pt-3.5", children: [
|
|
3358
|
+
/* @__PURE__ */ jsx13("span", { className: "mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-warning/15 text-warning", children: /* @__PURE__ */ jsx13(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5" }) }),
|
|
3359
|
+
/* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
|
|
3360
|
+
/* @__PURE__ */ jsx13("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-warning-foreground", children: "Needs your approval" }),
|
|
3361
|
+
/* @__PURE__ */ jsx13("p", { className: "mt-0.5 text-[15px] font-semibold leading-snug text-foreground", children: friendlyToolTitle(call) }),
|
|
3362
|
+
summary && /* @__PURE__ */ jsx13("p", { className: "mt-1 text-[13px] leading-relaxed text-muted-foreground", children: summary }),
|
|
3363
|
+
meta.length > 0 && /* @__PURE__ */ jsx13("div", { className: "mt-1.5 flex flex-wrap items-center gap-1.5", children: meta.map((m, i) => /* @__PURE__ */ jsx13("span", { className: "rounded-full bg-muted/60 px-2 py-0.5 text-[11px] font-medium text-muted-foreground", children: m }, i)) })
|
|
2903
3364
|
] })
|
|
2904
3365
|
] }),
|
|
2905
|
-
/* @__PURE__ */
|
|
2906
|
-
approval ? /* @__PURE__ */
|
|
2907
|
-
/* @__PURE__ */
|
|
3366
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-2 px-4 pb-3.5 pt-3", children: [
|
|
3367
|
+
approval ? /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
3368
|
+
/* @__PURE__ */ jsx13(
|
|
2908
3369
|
"button",
|
|
2909
3370
|
{
|
|
2910
3371
|
type: "button",
|
|
@@ -2914,7 +3375,7 @@ function ProposalCard({
|
|
|
2914
3375
|
children: "Approve & run"
|
|
2915
3376
|
}
|
|
2916
3377
|
),
|
|
2917
|
-
/* @__PURE__ */
|
|
3378
|
+
/* @__PURE__ */ jsx13(
|
|
2918
3379
|
"button",
|
|
2919
3380
|
{
|
|
2920
3381
|
type: "button",
|
|
@@ -2924,8 +3385,8 @@ function ProposalCard({
|
|
|
2924
3385
|
children: "Reject"
|
|
2925
3386
|
}
|
|
2926
3387
|
)
|
|
2927
|
-
] }) : /* @__PURE__ */
|
|
2928
|
-
/* @__PURE__ */
|
|
3388
|
+
] }) : /* @__PURE__ */ jsx13("span", { className: "text-[12px] font-medium text-muted-foreground", children: "Awaiting approval\u2026" }),
|
|
3389
|
+
/* @__PURE__ */ jsxs11(
|
|
2929
3390
|
"button",
|
|
2930
3391
|
{
|
|
2931
3392
|
type: "button",
|
|
@@ -2934,23 +3395,23 @@ function ProposalCard({
|
|
|
2934
3395
|
className: "ml-auto inline-flex items-center gap-1 rounded text-[12px] font-medium text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2935
3396
|
children: [
|
|
2936
3397
|
expanded ? "Hide details" : "View details",
|
|
2937
|
-
/* @__PURE__ */
|
|
3398
|
+
/* @__PURE__ */ jsx13(ChevronDown, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
2938
3399
|
]
|
|
2939
3400
|
}
|
|
2940
3401
|
)
|
|
2941
3402
|
] }),
|
|
2942
|
-
expanded && /* @__PURE__ */
|
|
3403
|
+
expanded && /* @__PURE__ */ jsx13("div", { className: "border-t border-warning/20 px-4 py-3 text-xs", children: custom ?? /* @__PURE__ */ jsx13(DefaultToolDetail, { call }) })
|
|
2943
3404
|
] });
|
|
2944
3405
|
}
|
|
2945
3406
|
function FollowupCard({ call }) {
|
|
2946
3407
|
const a = call.args ?? {};
|
|
2947
3408
|
const when = typeof a.when === "string" ? a.when : typeof a.at === "string" ? a.at : typeof a.schedule === "string" ? a.schedule : null;
|
|
2948
|
-
return /* @__PURE__ */
|
|
2949
|
-
/* @__PURE__ */
|
|
2950
|
-
/* @__PURE__ */
|
|
2951
|
-
/* @__PURE__ */
|
|
3409
|
+
return /* @__PURE__ */ jsxs11("div", { className: "w-fit min-w-[260px] max-w-full rounded-lg border border-border/60 border-l-2 border-l-primary/60 bg-muted/20 px-3 py-2 text-sm", children: [
|
|
3410
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
|
|
3411
|
+
/* @__PURE__ */ jsx13(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-primary/80" }),
|
|
3412
|
+
/* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", children: friendlyToolTitle(call) })
|
|
2952
3413
|
] }),
|
|
2953
|
-
when && /* @__PURE__ */
|
|
3414
|
+
when && /* @__PURE__ */ jsx13("p", { className: "mt-0.5 pl-[22px] text-[12px] text-muted-foreground", children: when })
|
|
2954
3415
|
] });
|
|
2955
3416
|
}
|
|
2956
3417
|
function ToolCallCard({
|
|
@@ -2960,13 +3421,13 @@ function ToolCallCard({
|
|
|
2960
3421
|
onOpenRun,
|
|
2961
3422
|
renderers
|
|
2962
3423
|
}) {
|
|
2963
|
-
const [expanded, setExpanded] =
|
|
3424
|
+
const [expanded, setExpanded] = useState14(false);
|
|
2964
3425
|
const pending = call.status === "done" ? pendingApprovalOf(call) : null;
|
|
2965
3426
|
const kind = blockKindOf(call);
|
|
2966
3427
|
const failed = call.status === "error" || toolOutcomeOf(call)?.ok === false;
|
|
2967
3428
|
const custom = renderers?.[call.name]?.(call, message);
|
|
2968
3429
|
if (pending) {
|
|
2969
|
-
return /* @__PURE__ */
|
|
3430
|
+
return /* @__PURE__ */ jsx13(
|
|
2970
3431
|
ProposalCard,
|
|
2971
3432
|
{
|
|
2972
3433
|
call,
|
|
@@ -2978,16 +3439,16 @@ function ToolCallCard({
|
|
|
2978
3439
|
);
|
|
2979
3440
|
}
|
|
2980
3441
|
if (kind === "followup" && !failed) {
|
|
2981
|
-
return /* @__PURE__ */
|
|
3442
|
+
return /* @__PURE__ */ jsx13(FollowupCard, { call });
|
|
2982
3443
|
}
|
|
2983
3444
|
const isCommand = kind === "command";
|
|
2984
|
-
return /* @__PURE__ */
|
|
3445
|
+
return /* @__PURE__ */ jsxs11(
|
|
2985
3446
|
"div",
|
|
2986
3447
|
{
|
|
2987
3448
|
className: `w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${failed ? "border-destructive/40 bg-destructive/5" : "border-border/60 bg-muted/20"}`,
|
|
2988
3449
|
children: [
|
|
2989
|
-
/* @__PURE__ */
|
|
2990
|
-
/* @__PURE__ */
|
|
3450
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex w-full items-center gap-2 px-3 py-2", children: [
|
|
3451
|
+
/* @__PURE__ */ jsxs11(
|
|
2991
3452
|
"button",
|
|
2992
3453
|
{
|
|
2993
3454
|
type: "button",
|
|
@@ -2995,14 +3456,14 @@ function ToolCallCard({
|
|
|
2995
3456
|
"aria-expanded": expanded,
|
|
2996
3457
|
className: "flex min-w-0 flex-1 items-center gap-2 rounded text-left focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2997
3458
|
children: [
|
|
2998
|
-
/* @__PURE__ */
|
|
3459
|
+
/* @__PURE__ */ jsx13(
|
|
2999
3460
|
"span",
|
|
3000
3461
|
{
|
|
3001
3462
|
className: `h-2 w-2 shrink-0 rounded-full ${call.status === "running" ? "animate-pulse bg-warning" : failed ? "bg-destructive" : "bg-success"}`
|
|
3002
3463
|
}
|
|
3003
3464
|
),
|
|
3004
|
-
/* @__PURE__ */
|
|
3005
|
-
/* @__PURE__ */
|
|
3465
|
+
/* @__PURE__ */ jsx13(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
3466
|
+
/* @__PURE__ */ jsx13(
|
|
3006
3467
|
"span",
|
|
3007
3468
|
{
|
|
3008
3469
|
className: `min-w-0 flex-1 truncate ${isCommand ? "font-mono text-[12px] tracking-tight text-foreground/90" : "font-medium"}`,
|
|
@@ -3012,8 +3473,8 @@ function ToolCallCard({
|
|
|
3012
3473
|
]
|
|
3013
3474
|
}
|
|
3014
3475
|
),
|
|
3015
|
-
/* @__PURE__ */
|
|
3016
|
-
/* @__PURE__ */
|
|
3476
|
+
/* @__PURE__ */ jsx13("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: call.status === "running" ? "running\u2026" : failed ? "failed" : "done" }),
|
|
3477
|
+
/* @__PURE__ */ jsx13(
|
|
3017
3478
|
"button",
|
|
3018
3479
|
{
|
|
3019
3480
|
type: "button",
|
|
@@ -3021,13 +3482,13 @@ function ToolCallCard({
|
|
|
3021
3482
|
"aria-label": expanded ? "Collapse details" : "Expand details",
|
|
3022
3483
|
"aria-expanded": expanded,
|
|
3023
3484
|
className: "shrink-0 rounded p-0.5 focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
3024
|
-
children: /* @__PURE__ */
|
|
3485
|
+
children: /* @__PURE__ */ jsx13(ChevronDown, { className: `h-3 w-3 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
3025
3486
|
}
|
|
3026
3487
|
)
|
|
3027
3488
|
] }),
|
|
3028
|
-
expanded && /* @__PURE__ */
|
|
3029
|
-
custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */
|
|
3030
|
-
onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */
|
|
3489
|
+
expanded && /* @__PURE__ */ jsxs11("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
|
|
3490
|
+
custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx13(ShellDetail, { call }) : /* @__PURE__ */ jsx13(DefaultToolDetail, { call })),
|
|
3491
|
+
onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx13(
|
|
3031
3492
|
"button",
|
|
3032
3493
|
{
|
|
3033
3494
|
type: "button",
|
|
@@ -3042,7 +3503,7 @@ function ToolCallCard({
|
|
|
3042
3503
|
);
|
|
3043
3504
|
}
|
|
3044
3505
|
function StreamingCaret() {
|
|
3045
|
-
return /* @__PURE__ */
|
|
3506
|
+
return /* @__PURE__ */ jsx13(
|
|
3046
3507
|
"span",
|
|
3047
3508
|
{
|
|
3048
3509
|
className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70",
|
|
@@ -3057,11 +3518,11 @@ function SegmentText({
|
|
|
3057
3518
|
renderBody
|
|
3058
3519
|
}) {
|
|
3059
3520
|
const text = useSmoothText(content, streaming);
|
|
3060
|
-
const body =
|
|
3521
|
+
const body = useMemo8(() => renderBody(text), [renderBody, text]);
|
|
3061
3522
|
if (!content.trim() && !showCaret) return null;
|
|
3062
|
-
return /* @__PURE__ */
|
|
3523
|
+
return /* @__PURE__ */ jsxs11("div", { className: "text-base leading-[1.75]", children: [
|
|
3063
3524
|
body,
|
|
3064
|
-
showCaret && /* @__PURE__ */
|
|
3525
|
+
showCaret && /* @__PURE__ */ jsx13(StreamingCaret, {})
|
|
3065
3526
|
] });
|
|
3066
3527
|
}
|
|
3067
3528
|
var COLLAPSE_TOOL_RUN_AT = 3;
|
|
@@ -3084,7 +3545,7 @@ function SegmentedBody({
|
|
|
3084
3545
|
const leftoverToolCalls = (msg.toolCalls ?? []).filter(
|
|
3085
3546
|
(tc) => !segmentToolIds.has(tc.id)
|
|
3086
3547
|
);
|
|
3087
|
-
const renderToolCard = (call) => /* @__PURE__ */
|
|
3548
|
+
const renderToolCard = (call) => /* @__PURE__ */ jsx13(
|
|
3088
3549
|
ToolCallCard,
|
|
3089
3550
|
{
|
|
3090
3551
|
call,
|
|
@@ -3107,9 +3568,9 @@ function SegmentedBody({
|
|
|
3107
3568
|
else groups.push({ kind: "tools", index: i, calls: [seg.call] });
|
|
3108
3569
|
}
|
|
3109
3570
|
}
|
|
3110
|
-
return /* @__PURE__ */
|
|
3571
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-2", children: [
|
|
3111
3572
|
groups.map(
|
|
3112
|
-
(g) => g.kind === "text" ? /* @__PURE__ */
|
|
3573
|
+
(g) => g.kind === "text" ? /* @__PURE__ */ jsx13(
|
|
3113
3574
|
SegmentText,
|
|
3114
3575
|
{
|
|
3115
3576
|
content: g.content,
|
|
@@ -3118,24 +3579,24 @@ function SegmentedBody({
|
|
|
3118
3579
|
renderBody
|
|
3119
3580
|
},
|
|
3120
3581
|
`text-${g.index}`
|
|
3121
|
-
) : !streaming && g.calls.length >= COLLAPSE_TOOL_RUN_AT && !g.calls.some(isImportantTool) ? /* @__PURE__ */
|
|
3582
|
+
) : !streaming && g.calls.length >= COLLAPSE_TOOL_RUN_AT && !g.calls.some(isImportantTool) ? /* @__PURE__ */ jsxs11(
|
|
3122
3583
|
"details",
|
|
3123
3584
|
{
|
|
3124
3585
|
className: "rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2",
|
|
3125
3586
|
children: [
|
|
3126
|
-
/* @__PURE__ */
|
|
3587
|
+
/* @__PURE__ */ jsxs11("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: [
|
|
3127
3588
|
"Worked through ",
|
|
3128
3589
|
g.calls.length,
|
|
3129
3590
|
" steps"
|
|
3130
3591
|
] }),
|
|
3131
|
-
/* @__PURE__ */
|
|
3592
|
+
/* @__PURE__ */ jsx13("div", { className: "mt-2 flex flex-col gap-2", children: g.calls.map(renderToolCard) })
|
|
3132
3593
|
]
|
|
3133
3594
|
},
|
|
3134
3595
|
`tools-${g.index}`
|
|
3135
|
-
) : /* @__PURE__ */
|
|
3596
|
+
) : /* @__PURE__ */ jsx13("div", { className: "flex flex-col gap-2", children: g.calls.map(renderToolCard) }, `tools-${g.index}`)
|
|
3136
3597
|
),
|
|
3137
3598
|
leftoverToolCalls.map(renderToolCard),
|
|
3138
|
-
streaming && segments[lastIndex]?.kind === "tool" && /* @__PURE__ */
|
|
3599
|
+
streaming && segments[lastIndex]?.kind === "tool" && /* @__PURE__ */ jsx13(StreamingCaret, {})
|
|
3139
3600
|
] });
|
|
3140
3601
|
}
|
|
3141
3602
|
function AssistantMessageImpl({
|
|
@@ -3148,44 +3609,45 @@ function AssistantMessageImpl({
|
|
|
3148
3609
|
onToolCallClick,
|
|
3149
3610
|
toolRenderers,
|
|
3150
3611
|
renderExtras,
|
|
3151
|
-
durableCards
|
|
3612
|
+
durableCards,
|
|
3613
|
+
resolveAttachmentUrl
|
|
3152
3614
|
}) {
|
|
3153
3615
|
const content = useSmoothText(msg.content, streaming);
|
|
3154
3616
|
const reasoning = useSmoothText(msg.reasoning ?? "", streaming);
|
|
3155
|
-
const body =
|
|
3617
|
+
const body = useMemo8(() => renderBody(content), [renderBody, content]);
|
|
3156
3618
|
const segments = msg.segments;
|
|
3157
3619
|
const hasAnswerText = content !== "" || (segments?.some((s) => s.kind === "text" && s.content.trim() !== "") ?? false);
|
|
3158
|
-
const reasoningScrollRef =
|
|
3159
|
-
const thinkStartRef =
|
|
3160
|
-
const thinkMsRef =
|
|
3620
|
+
const reasoningScrollRef = useRef9(null);
|
|
3621
|
+
const thinkStartRef = useRef9(null);
|
|
3622
|
+
const thinkMsRef = useRef9(null);
|
|
3161
3623
|
if (streaming && reasoning && !hasAnswerText && thinkStartRef.current === null) {
|
|
3162
3624
|
thinkStartRef.current = performance.now();
|
|
3163
3625
|
}
|
|
3164
3626
|
if (hasAnswerText && thinkStartRef.current !== null && thinkMsRef.current === null) {
|
|
3165
3627
|
thinkMsRef.current = performance.now() - thinkStartRef.current;
|
|
3166
3628
|
}
|
|
3167
|
-
|
|
3629
|
+
useEffect10(() => {
|
|
3168
3630
|
const el = reasoningScrollRef.current;
|
|
3169
3631
|
if (el && streaming && !hasAnswerText) el.scrollTop = el.scrollHeight;
|
|
3170
3632
|
}, [reasoning, streaming, hasAnswerText]);
|
|
3171
3633
|
const thinkingSeconds = useThinkingSeconds(
|
|
3172
3634
|
streaming && !!reasoning && !hasAnswerText
|
|
3173
3635
|
);
|
|
3174
|
-
return /* @__PURE__ */
|
|
3175
|
-
/* @__PURE__ */
|
|
3176
|
-
/* @__PURE__ */
|
|
3177
|
-
msg.modelUsed && /* @__PURE__ */
|
|
3178
|
-
formatTokensPerSecond(msg) && /* @__PURE__ */
|
|
3179
|
-
formatModelCost(msg, models) && /* @__PURE__ */
|
|
3636
|
+
return /* @__PURE__ */ jsxs11("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
3637
|
+
/* @__PURE__ */ jsxs11("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground", children: [
|
|
3638
|
+
/* @__PURE__ */ jsx13("span", { className: "font-semibold uppercase", children: agentLabel }),
|
|
3639
|
+
msg.modelUsed && /* @__PURE__ */ jsx13("span", { className: "font-mono normal-case", children: msg.modelUsed }),
|
|
3640
|
+
formatTokensPerSecond(msg) && /* @__PURE__ */ jsx13("span", { children: formatTokensPerSecond(msg) }),
|
|
3641
|
+
formatModelCost(msg, models) && /* @__PURE__ */ jsx13("span", { children: formatModelCost(msg, models) })
|
|
3180
3642
|
] }),
|
|
3181
|
-
reasoning && /* @__PURE__ */
|
|
3182
|
-
/* @__PURE__ */
|
|
3643
|
+
reasoning && /* @__PURE__ */ jsxs11("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !hasAnswerText, children: [
|
|
3644
|
+
/* @__PURE__ */ jsx13("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !hasAnswerText ? /* @__PURE__ */ jsxs11("span", { className: "animate-pulse", children: [
|
|
3183
3645
|
"Thinking",
|
|
3184
3646
|
thinkingSeconds >= 3 ? ` \xB7 ${thinkingSeconds}s` : "\u2026"
|
|
3185
3647
|
] }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
|
|
3186
|
-
/* @__PURE__ */
|
|
3648
|
+
/* @__PURE__ */ jsx13("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground", children: reasoning })
|
|
3187
3649
|
] }),
|
|
3188
|
-
segments && segments.length > 0 ? /* @__PURE__ */
|
|
3650
|
+
segments && segments.length > 0 ? /* @__PURE__ */ jsx13(
|
|
3189
3651
|
SegmentedBody,
|
|
3190
3652
|
{
|
|
3191
3653
|
segments,
|
|
@@ -3196,12 +3658,12 @@ function AssistantMessageImpl({
|
|
|
3196
3658
|
onToolCallClick,
|
|
3197
3659
|
toolRenderers
|
|
3198
3660
|
}
|
|
3199
|
-
) : /* @__PURE__ */
|
|
3200
|
-
/* @__PURE__ */
|
|
3661
|
+
) : /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
3662
|
+
/* @__PURE__ */ jsxs11("div", { className: "text-base leading-[1.75]", children: [
|
|
3201
3663
|
body,
|
|
3202
|
-
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */
|
|
3664
|
+
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx13(StreamingCaret, {})
|
|
3203
3665
|
] }),
|
|
3204
|
-
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */
|
|
3666
|
+
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx13("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx13(
|
|
3205
3667
|
ToolCallCard,
|
|
3206
3668
|
{
|
|
3207
3669
|
call: tc,
|
|
@@ -3213,7 +3675,7 @@ function AssistantMessageImpl({
|
|
|
3213
3675
|
tc.id
|
|
3214
3676
|
)) })
|
|
3215
3677
|
] }),
|
|
3216
|
-
durableCards && msg.parts && /* @__PURE__ */
|
|
3678
|
+
durableCards && msg.parts && /* @__PURE__ */ jsx13(
|
|
3217
3679
|
DurableChatCards,
|
|
3218
3680
|
{
|
|
3219
3681
|
...durableCards,
|
|
@@ -3222,13 +3684,21 @@ function AssistantMessageImpl({
|
|
|
3222
3684
|
className: "mt-3"
|
|
3223
3685
|
}
|
|
3224
3686
|
),
|
|
3225
|
-
renderExtras?.(msg)
|
|
3687
|
+
renderExtras?.(msg),
|
|
3688
|
+
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */ jsx13("div", { className: "mt-2", children: /* @__PURE__ */ jsx13(
|
|
3689
|
+
MessageAttachments,
|
|
3690
|
+
{
|
|
3691
|
+
parts: attachmentPartsFromMessageParts(msg.parts),
|
|
3692
|
+
resolveFileUrl: resolveAttachmentUrl,
|
|
3693
|
+
justify: "start"
|
|
3694
|
+
}
|
|
3695
|
+
) })
|
|
3226
3696
|
] });
|
|
3227
3697
|
}
|
|
3228
3698
|
var AssistantMessage = memo(AssistantMessageImpl);
|
|
3229
3699
|
function useThinkingSeconds(active) {
|
|
3230
|
-
const [seconds, setSeconds] =
|
|
3231
|
-
|
|
3700
|
+
const [seconds, setSeconds] = useState14(0);
|
|
3701
|
+
useEffect10(() => {
|
|
3232
3702
|
if (!active) return;
|
|
3233
3703
|
setSeconds(0);
|
|
3234
3704
|
const id = setInterval(() => setSeconds((s) => s + 1), 1e3);
|
|
@@ -3238,23 +3708,23 @@ function useThinkingSeconds(active) {
|
|
|
3238
3708
|
}
|
|
3239
3709
|
function ThinkingRow({ agentLabel }) {
|
|
3240
3710
|
const seconds = useThinkingSeconds(true);
|
|
3241
|
-
return /* @__PURE__ */
|
|
3242
|
-
/* @__PURE__ */
|
|
3243
|
-
/* @__PURE__ */
|
|
3244
|
-
/* @__PURE__ */
|
|
3711
|
+
return /* @__PURE__ */ jsxs11("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
3712
|
+
/* @__PURE__ */ jsx13("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: agentLabel }),
|
|
3713
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
|
|
3714
|
+
/* @__PURE__ */ jsx13("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx13("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
|
|
3245
3715
|
"Thinking",
|
|
3246
3716
|
seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
|
|
3247
3717
|
] })
|
|
3248
3718
|
] });
|
|
3249
3719
|
}
|
|
3250
3720
|
function StreamErrorRow({ message, onRetry }) {
|
|
3251
|
-
return /* @__PURE__ */
|
|
3252
|
-
/* @__PURE__ */
|
|
3253
|
-
/* @__PURE__ */
|
|
3254
|
-
/* @__PURE__ */
|
|
3721
|
+
return /* @__PURE__ */ jsx13("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs11("div", { role: "alert", className: "flex items-start gap-2.5 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2.5 text-sm text-destructive", children: [
|
|
3722
|
+
/* @__PURE__ */ jsxs11("svg", { className: "mt-0.5 h-4 w-4 shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
3723
|
+
/* @__PURE__ */ jsx13("circle", { cx: "12", cy: "12", r: "9" }),
|
|
3724
|
+
/* @__PURE__ */ jsx13("path", { d: "M12 8v4m0 4h.01" })
|
|
3255
3725
|
] }),
|
|
3256
|
-
/* @__PURE__ */
|
|
3257
|
-
onRetry && /* @__PURE__ */
|
|
3726
|
+
/* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 break-words", children: message }),
|
|
3727
|
+
onRetry && /* @__PURE__ */ jsx13(
|
|
3258
3728
|
"button",
|
|
3259
3729
|
{
|
|
3260
3730
|
type: "button",
|
|
@@ -3281,27 +3751,36 @@ function ChatMessages({
|
|
|
3281
3751
|
onRetry,
|
|
3282
3752
|
renderEmpty,
|
|
3283
3753
|
emptyState,
|
|
3284
|
-
header
|
|
3754
|
+
header,
|
|
3755
|
+
resolveAttachmentUrl
|
|
3285
3756
|
}) {
|
|
3286
|
-
const renderBody =
|
|
3287
|
-
() => renderMarkdown ?? ((content) => /* @__PURE__ */
|
|
3757
|
+
const renderBody = useMemo8(
|
|
3758
|
+
() => renderMarkdown ?? ((content) => /* @__PURE__ */ jsx13("p", { className: "whitespace-pre-wrap", children: content })),
|
|
3288
3759
|
[renderMarkdown]
|
|
3289
3760
|
);
|
|
3290
3761
|
const lastIsUser = messages[messages.length - 1]?.role === "user";
|
|
3291
3762
|
if (messages.length === 0 && !loading && !error) {
|
|
3292
|
-
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
3293
|
-
return /* @__PURE__ */
|
|
3763
|
+
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */ jsx13(ChatEmptyState, { ...emptyState });
|
|
3764
|
+
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
3294
3765
|
header,
|
|
3295
3766
|
empty
|
|
3296
3767
|
] });
|
|
3297
3768
|
}
|
|
3298
|
-
return /* @__PURE__ */
|
|
3769
|
+
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
3299
3770
|
header,
|
|
3300
3771
|
messages.map(
|
|
3301
|
-
(msg) => msg.role === "user" ? /* @__PURE__ */
|
|
3302
|
-
/* @__PURE__ */
|
|
3303
|
-
/* @__PURE__ */
|
|
3304
|
-
|
|
3772
|
+
(msg) => msg.role === "user" ? /* @__PURE__ */ jsx13("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs11("div", { className: "ml-auto w-fit max-w-[85%]", children: [
|
|
3773
|
+
/* @__PURE__ */ jsx13("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: userLabel }),
|
|
3774
|
+
/* @__PURE__ */ jsx13("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx13("p", { className: "whitespace-pre-wrap", children: msg.content }) }),
|
|
3775
|
+
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */ jsx13("div", { className: "mt-1.5", children: /* @__PURE__ */ jsx13(
|
|
3776
|
+
MessageAttachments,
|
|
3777
|
+
{
|
|
3778
|
+
parts: attachmentPartsFromMessageParts(msg.parts),
|
|
3779
|
+
resolveFileUrl: resolveAttachmentUrl,
|
|
3780
|
+
justify: "end"
|
|
3781
|
+
}
|
|
3782
|
+
) })
|
|
3783
|
+
] }) }, msg.id) : /* @__PURE__ */ jsx13(
|
|
3305
3784
|
AssistantMessage,
|
|
3306
3785
|
{
|
|
3307
3786
|
msg,
|
|
@@ -3313,13 +3792,14 @@ function ChatMessages({
|
|
|
3313
3792
|
onToolCallClick,
|
|
3314
3793
|
toolRenderers,
|
|
3315
3794
|
renderExtras,
|
|
3316
|
-
durableCards
|
|
3795
|
+
durableCards,
|
|
3796
|
+
resolveAttachmentUrl
|
|
3317
3797
|
},
|
|
3318
3798
|
msg.id
|
|
3319
3799
|
)
|
|
3320
3800
|
),
|
|
3321
|
-
loading && lastIsUser && /* @__PURE__ */
|
|
3322
|
-
error && !loading && /* @__PURE__ */
|
|
3801
|
+
loading && lastIsUser && /* @__PURE__ */ jsx13(ThinkingRow, { agentLabel }),
|
|
3802
|
+
error && !loading && /* @__PURE__ */ jsx13(StreamErrorRow, { message: error, onRetry })
|
|
3323
3803
|
] });
|
|
3324
3804
|
}
|
|
3325
3805
|
|
|
@@ -3352,6 +3832,10 @@ export {
|
|
|
3352
3832
|
InteractionPlanCard,
|
|
3353
3833
|
durableChatCardsFromParts,
|
|
3354
3834
|
DurableChatCards,
|
|
3835
|
+
__resetAttachmentFileCacheForTests,
|
|
3836
|
+
loadAttachmentFile,
|
|
3837
|
+
triggerAttachmentDownload,
|
|
3838
|
+
MessageAttachments,
|
|
3355
3839
|
dispatchChatStreamLine,
|
|
3356
3840
|
consumeChatStream,
|
|
3357
3841
|
streamChatTurn,
|
|
@@ -3376,6 +3860,7 @@ export {
|
|
|
3376
3860
|
DEFAULT_MENTION_EMPTY_TEXT,
|
|
3377
3861
|
useFileMentions,
|
|
3378
3862
|
segmentMentionContent,
|
|
3863
|
+
useComposerAttachments,
|
|
3379
3864
|
activityTone,
|
|
3380
3865
|
formatActivityCost,
|
|
3381
3866
|
formatActivityDuration,
|
|
@@ -3394,4 +3879,4 @@ export {
|
|
|
3394
3879
|
useThinkingSeconds,
|
|
3395
3880
|
ChatMessages
|
|
3396
3881
|
};
|
|
3397
|
-
//# sourceMappingURL=chunk-
|
|
3882
|
+
//# sourceMappingURL=chunk-EIG7ZQW2.js.map
|