@invergent/agent-chat-react 2.0.9 → 2.1.4
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/index.cjs +2458 -1265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -15
- package/dist/index.d.ts +70 -15
- package/dist/index.js +2447 -1255
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -263,90 +263,6 @@ function Button({
|
|
|
263
263
|
}
|
|
264
264
|
);
|
|
265
265
|
}
|
|
266
|
-
function BrowserControlBar({
|
|
267
|
-
sessionId,
|
|
268
|
-
hasControl,
|
|
269
|
-
adapter,
|
|
270
|
-
onControlAcquired,
|
|
271
|
-
onControlReleased
|
|
272
|
-
}) {
|
|
273
|
-
const [pending, setPending] = react.useState(false);
|
|
274
|
-
const [error, setError] = react.useState(null);
|
|
275
|
-
async function toggleControl() {
|
|
276
|
-
if (!sessionId || pending) return;
|
|
277
|
-
setPending(true);
|
|
278
|
-
setError(null);
|
|
279
|
-
try {
|
|
280
|
-
if (hasControl) {
|
|
281
|
-
await adapter.releaseBrowserControl(sessionId);
|
|
282
|
-
onControlReleased?.();
|
|
283
|
-
} else {
|
|
284
|
-
await adapter.acquireBrowserControl(sessionId);
|
|
285
|
-
onControlAcquired?.();
|
|
286
|
-
}
|
|
287
|
-
} catch (nextError) {
|
|
288
|
-
setError(nextError.message);
|
|
289
|
-
} finally {
|
|
290
|
-
setPending(false);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-11 items-center gap-2 border-t border-line bg-card px-3 py-2", children: [
|
|
294
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
295
|
-
Button,
|
|
296
|
-
{
|
|
297
|
-
type: "button",
|
|
298
|
-
size: "xs",
|
|
299
|
-
variant: hasControl ? "secondary" : "default",
|
|
300
|
-
disabled: !sessionId || pending,
|
|
301
|
-
onClick: () => void toggleControl(),
|
|
302
|
-
children: [
|
|
303
|
-
hasControl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcwIcon, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MousePointer2Icon, { className: "size-3", "aria-hidden": "true" }),
|
|
304
|
-
hasControl ? "Return control" : "Take control"
|
|
305
|
-
]
|
|
306
|
-
}
|
|
307
|
-
),
|
|
308
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
309
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-1.5 rounded-full bg-red-500", "aria-hidden": "true" }),
|
|
310
|
-
"Live"
|
|
311
|
-
] }),
|
|
312
|
-
error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-40 truncate text-[11px] text-destructive", children: error })
|
|
313
|
-
] });
|
|
314
|
-
}
|
|
315
|
-
function BrowserLiveView({
|
|
316
|
-
src,
|
|
317
|
-
testId = "browser-iframe"
|
|
318
|
-
}) {
|
|
319
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
320
|
-
"iframe",
|
|
321
|
-
{
|
|
322
|
-
"data-testid": testId,
|
|
323
|
-
title: "Browser live view",
|
|
324
|
-
src,
|
|
325
|
-
className: "h-full w-full border-0 bg-black",
|
|
326
|
-
allow: "clipboard-read; clipboard-write"
|
|
327
|
-
}
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// src/components/browser/browser-status-dot.tsx
|
|
332
|
-
init_utils();
|
|
333
|
-
function BrowserStatusDot({
|
|
334
|
-
status
|
|
335
|
-
}) {
|
|
336
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
337
|
-
"span",
|
|
338
|
-
{
|
|
339
|
-
"aria-hidden": "true",
|
|
340
|
-
className: cn(
|
|
341
|
-
"inline-block size-2 shrink-0 rounded-full",
|
|
342
|
-
status === "live" && "bg-emerald-500",
|
|
343
|
-
status === "user-control" && "bg-amber-500",
|
|
344
|
-
status === "provisioning" && "animate-pulse bg-sky-500",
|
|
345
|
-
status === "closed" && "bg-muted-foreground"
|
|
346
|
-
)
|
|
347
|
-
}
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
266
|
|
|
351
267
|
// src/components/ui/dialog.tsx
|
|
352
268
|
init_utils();
|
|
@@ -479,6 +395,197 @@ function DialogDescription({
|
|
|
479
395
|
}
|
|
480
396
|
);
|
|
481
397
|
}
|
|
398
|
+
function ConfirmDialog({
|
|
399
|
+
open,
|
|
400
|
+
title,
|
|
401
|
+
description,
|
|
402
|
+
confirmLabel = "Confirm",
|
|
403
|
+
confirmIcon,
|
|
404
|
+
variant = "destructive",
|
|
405
|
+
confirmDisabled = false,
|
|
406
|
+
onConfirm,
|
|
407
|
+
onCancel
|
|
408
|
+
}) {
|
|
409
|
+
const [loading, setLoading] = react.useState(false);
|
|
410
|
+
const handleConfirm = async () => {
|
|
411
|
+
setLoading(true);
|
|
412
|
+
try {
|
|
413
|
+
await onConfirm();
|
|
414
|
+
} finally {
|
|
415
|
+
setLoading(false);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
419
|
+
Dialog,
|
|
420
|
+
{
|
|
421
|
+
open,
|
|
422
|
+
onOpenChange: (next) => {
|
|
423
|
+
if (!next && !loading) onCancel();
|
|
424
|
+
},
|
|
425
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
426
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
427
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: title }),
|
|
428
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: description })
|
|
429
|
+
] }),
|
|
430
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { children: [
|
|
431
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", disabled: loading, onClick: onCancel, children: "Cancel" }),
|
|
432
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
433
|
+
Button,
|
|
434
|
+
{
|
|
435
|
+
variant,
|
|
436
|
+
disabled: loading || confirmDisabled,
|
|
437
|
+
onClick: () => void handleConfirm(),
|
|
438
|
+
children: [
|
|
439
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-1.5 size-3.5 animate-spin", "aria-hidden": "true" }) : confirmIcon,
|
|
440
|
+
confirmLabel
|
|
441
|
+
]
|
|
442
|
+
}
|
|
443
|
+
)
|
|
444
|
+
] })
|
|
445
|
+
] })
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
function BrowserControlBar({
|
|
450
|
+
sessionId,
|
|
451
|
+
hasControl,
|
|
452
|
+
adapter,
|
|
453
|
+
onControlAcquired,
|
|
454
|
+
onControlReleased,
|
|
455
|
+
onClose
|
|
456
|
+
}) {
|
|
457
|
+
const [pending, setPending] = react.useState(false);
|
|
458
|
+
const [confirmOpen, setConfirmOpen] = react.useState(false);
|
|
459
|
+
const [error, setError] = react.useState(null);
|
|
460
|
+
async function toggleControl() {
|
|
461
|
+
if (!sessionId || pending) return;
|
|
462
|
+
setPending(true);
|
|
463
|
+
setError(null);
|
|
464
|
+
try {
|
|
465
|
+
if (hasControl) {
|
|
466
|
+
await adapter.releaseBrowserControl(sessionId);
|
|
467
|
+
onControlReleased?.();
|
|
468
|
+
} else {
|
|
469
|
+
await adapter.acquireBrowserControl(sessionId);
|
|
470
|
+
onControlAcquired?.();
|
|
471
|
+
}
|
|
472
|
+
} catch (nextError) {
|
|
473
|
+
setError(nextError.message);
|
|
474
|
+
} finally {
|
|
475
|
+
setPending(false);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
async function handleConfirmClose() {
|
|
479
|
+
setError(null);
|
|
480
|
+
try {
|
|
481
|
+
if (hasControl) {
|
|
482
|
+
try {
|
|
483
|
+
await adapter.releaseBrowserControl(sessionId);
|
|
484
|
+
onControlReleased?.();
|
|
485
|
+
} catch (releaseError) {
|
|
486
|
+
console.error(
|
|
487
|
+
"Failed to release browser control before close",
|
|
488
|
+
releaseError
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
if (adapter.closeBrowserSession) {
|
|
493
|
+
await adapter.closeBrowserSession(sessionId);
|
|
494
|
+
}
|
|
495
|
+
setConfirmOpen(false);
|
|
496
|
+
onClose?.();
|
|
497
|
+
} catch (nextError) {
|
|
498
|
+
setError(nextError.message);
|
|
499
|
+
throw nextError;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-11 items-center gap-2 border-t border-line bg-card px-3 py-2", children: [
|
|
503
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
504
|
+
Button,
|
|
505
|
+
{
|
|
506
|
+
type: "button",
|
|
507
|
+
size: "xs",
|
|
508
|
+
variant: hasControl ? "secondary" : "default",
|
|
509
|
+
disabled: !sessionId || pending,
|
|
510
|
+
onClick: () => void toggleControl(),
|
|
511
|
+
children: [
|
|
512
|
+
hasControl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcwIcon, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MousePointer2Icon, { className: "size-3", "aria-hidden": "true" }),
|
|
513
|
+
hasControl ? "Return control" : "Take control"
|
|
514
|
+
]
|
|
515
|
+
}
|
|
516
|
+
),
|
|
517
|
+
onClose && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
518
|
+
Button,
|
|
519
|
+
{
|
|
520
|
+
type: "button",
|
|
521
|
+
size: "xs",
|
|
522
|
+
variant: "secondary",
|
|
523
|
+
disabled: !sessionId,
|
|
524
|
+
onClick: () => {
|
|
525
|
+
setError(null);
|
|
526
|
+
setConfirmOpen(true);
|
|
527
|
+
},
|
|
528
|
+
children: [
|
|
529
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-3", "aria-hidden": "true" }),
|
|
530
|
+
"Close"
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
),
|
|
534
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
535
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-1.5 rounded-full bg-red-500", "aria-hidden": "true" }),
|
|
536
|
+
"Live"
|
|
537
|
+
] }),
|
|
538
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-40 truncate text-[11px] text-destructive", children: error }),
|
|
539
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
540
|
+
ConfirmDialog,
|
|
541
|
+
{
|
|
542
|
+
open: confirmOpen,
|
|
543
|
+
title: "Close browser session?",
|
|
544
|
+
description: adapter.closeBrowserSession ? "This permanently shuts down the browser sandbox for this session. The agent will lose access to the page until it re-opens a browser. This cannot be undone." : "This hides the browser panel. The sandbox stays running so the agent can keep using it.",
|
|
545
|
+
confirmLabel: "Close browser",
|
|
546
|
+
variant: "destructive",
|
|
547
|
+
confirmIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
548
|
+
onConfirm: handleConfirmClose,
|
|
549
|
+
onCancel: () => setConfirmOpen(false)
|
|
550
|
+
}
|
|
551
|
+
)
|
|
552
|
+
] });
|
|
553
|
+
}
|
|
554
|
+
function BrowserLiveView({
|
|
555
|
+
src,
|
|
556
|
+
testId = "browser-iframe"
|
|
557
|
+
}) {
|
|
558
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
559
|
+
"iframe",
|
|
560
|
+
{
|
|
561
|
+
"data-testid": testId,
|
|
562
|
+
title: "Browser live view",
|
|
563
|
+
src,
|
|
564
|
+
className: "h-full w-full border-0 bg-black",
|
|
565
|
+
allow: "clipboard-read; clipboard-write"
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// src/components/browser/browser-status-dot.tsx
|
|
571
|
+
init_utils();
|
|
572
|
+
function BrowserStatusDot({
|
|
573
|
+
status
|
|
574
|
+
}) {
|
|
575
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
576
|
+
"span",
|
|
577
|
+
{
|
|
578
|
+
"aria-hidden": "true",
|
|
579
|
+
className: cn(
|
|
580
|
+
"inline-block size-2 shrink-0 rounded-full",
|
|
581
|
+
status === "live" && "bg-emerald-500",
|
|
582
|
+
status === "user-control" && "bg-amber-500",
|
|
583
|
+
status === "provisioning" && "animate-pulse bg-sky-500",
|
|
584
|
+
status === "closed" && "bg-muted-foreground"
|
|
585
|
+
)
|
|
586
|
+
}
|
|
587
|
+
);
|
|
588
|
+
}
|
|
482
589
|
|
|
483
590
|
// src/components/ui/tooltip.tsx
|
|
484
591
|
init_utils();
|
|
@@ -528,7 +635,12 @@ function TooltipContent({
|
|
|
528
635
|
}
|
|
529
636
|
) });
|
|
530
637
|
}
|
|
531
|
-
function BrowserPane({
|
|
638
|
+
function BrowserPane({
|
|
639
|
+
sessionId,
|
|
640
|
+
state,
|
|
641
|
+
adapter,
|
|
642
|
+
onClose
|
|
643
|
+
}) {
|
|
532
644
|
const [fullscreenOpen, setFullscreenOpen] = react.useState(false);
|
|
533
645
|
const [openFullscreenOnControl, setOpenFullscreenOnControl] = react.useState(false);
|
|
534
646
|
const [localControlActive, setLocalControlActive] = react.useState(false);
|
|
@@ -588,14 +700,19 @@ function BrowserPane({ sessionId, state, adapter }) {
|
|
|
588
700
|
const handleFullscreenOpenChange = react.useCallback(
|
|
589
701
|
(open) => {
|
|
590
702
|
setFullscreenOpen(open);
|
|
591
|
-
if (open || !hasUserControl || !hasControlAdapter) return;
|
|
592
|
-
setLocalControlActive(false);
|
|
593
|
-
void adapter.releaseBrowserControl(sessionId).catch((error) => {
|
|
594
|
-
console.error("Failed to release browser control", error);
|
|
595
|
-
});
|
|
596
703
|
},
|
|
597
|
-
[
|
|
704
|
+
[]
|
|
598
705
|
);
|
|
706
|
+
react.useEffect(() => {
|
|
707
|
+
if (!canUseLiveView || !hasControlAdapter) return;
|
|
708
|
+
const handle = window.setInterval(() => {
|
|
709
|
+
void adapter.acquireBrowserControl(sessionId).catch((error) => {
|
|
710
|
+
console.error("Failed to refresh browser control", error);
|
|
711
|
+
setLocalControlActive(false);
|
|
712
|
+
});
|
|
713
|
+
}, 25e3);
|
|
714
|
+
return () => window.clearInterval(handle);
|
|
715
|
+
}, [adapter, canUseLiveView, hasControlAdapter, sessionId]);
|
|
599
716
|
react.useEffect(() => {
|
|
600
717
|
if (!hasLiveView || canUseLiveView) {
|
|
601
718
|
setPreviewLoading(false);
|
|
@@ -666,7 +783,8 @@ function BrowserPane({ sessionId, state, adapter }) {
|
|
|
666
783
|
setLocalControlActive(true);
|
|
667
784
|
setOpenFullscreenOnControl(true);
|
|
668
785
|
},
|
|
669
|
-
onControlReleased: () => setLocalControlActive(false)
|
|
786
|
+
onControlReleased: () => setLocalControlActive(false),
|
|
787
|
+
onClose
|
|
670
788
|
}
|
|
671
789
|
)
|
|
672
790
|
]
|
|
@@ -890,7 +1008,7 @@ var ShimmerComponent = ({
|
|
|
890
1008
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
891
1009
|
Component,
|
|
892
1010
|
{
|
|
893
|
-
className: cn("shimmer text-
|
|
1011
|
+
className: cn("shimmer text-foreground/70", className),
|
|
894
1012
|
style: {
|
|
895
1013
|
"--shimmer-duration": duration * 1e3,
|
|
896
1014
|
"--shimmer-spread": `${dynamicSpread}px`
|
|
@@ -992,12 +1110,12 @@ var ReasoningTrigger = react.memo(
|
|
|
992
1110
|
CollapsibleTrigger,
|
|
993
1111
|
{
|
|
994
1112
|
className: cn(
|
|
995
|
-
"flex w-full items-center gap-2 text-
|
|
1113
|
+
"flex w-full items-center gap-2 text-foreground/70 text-sm transition-colors hover:text-foreground",
|
|
996
1114
|
className
|
|
997
1115
|
),
|
|
998
1116
|
...props,
|
|
999
1117
|
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1000
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-
|
|
1118
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foregound/70 text-sm", children: getThinkingMessage(isStreaming, duration) }),
|
|
1001
1119
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1002
1120
|
lucideReact.ChevronDownIcon,
|
|
1003
1121
|
{
|
|
@@ -1019,7 +1137,7 @@ var ReasoningContent = react.memo(
|
|
|
1019
1137
|
{
|
|
1020
1138
|
className: cn(
|
|
1021
1139
|
"mt-4 text-sm",
|
|
1022
|
-
"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-foreground/
|
|
1140
|
+
"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-foreground/70 italic outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
1023
1141
|
className
|
|
1024
1142
|
),
|
|
1025
1143
|
...props,
|
|
@@ -3696,7 +3814,7 @@ function SkillViewBlock({ tc }) {
|
|
|
3696
3814
|
] });
|
|
3697
3815
|
}
|
|
3698
3816
|
|
|
3699
|
-
// src/components/chat/tools/
|
|
3817
|
+
// src/components/chat/tools/ask-user-question-tool.tsx
|
|
3700
3818
|
init_utils();
|
|
3701
3819
|
|
|
3702
3820
|
// src/components/ui/input.tsx
|
|
@@ -3730,7 +3848,7 @@ function buildAnswer(q, sel) {
|
|
|
3730
3848
|
if (!choice) return null;
|
|
3731
3849
|
return { question: q.prompt, answer: choice.label, is_other: false };
|
|
3732
3850
|
}
|
|
3733
|
-
function
|
|
3851
|
+
function AskUserQuestionToolBlock({ tc }) {
|
|
3734
3852
|
const { adapter, sessionId } = useAgentChatAdapterContext();
|
|
3735
3853
|
const args = react.useMemo(() => parseArgs(tc.args), [tc.args]);
|
|
3736
3854
|
const questions = args?.questions ?? [];
|
|
@@ -3740,7 +3858,7 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3740
3858
|
);
|
|
3741
3859
|
const [submitting, setSubmitting] = react.useState(false);
|
|
3742
3860
|
const [error, setError] = react.useState(null);
|
|
3743
|
-
const locked = tc.
|
|
3861
|
+
const locked = tc.askUserQuestionAnswers !== void 0 || tc.status !== "running";
|
|
3744
3862
|
react.useEffect(() => {
|
|
3745
3863
|
if (active >= questions.length && questions.length > 0) setActive(0);
|
|
3746
3864
|
}, [active, questions.length]);
|
|
@@ -3768,7 +3886,7 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3768
3886
|
setError(null);
|
|
3769
3887
|
setSubmitting(true);
|
|
3770
3888
|
try {
|
|
3771
|
-
await adapter.
|
|
3889
|
+
await adapter.submitAskUserQuestionResponse({
|
|
3772
3890
|
sessionId,
|
|
3773
3891
|
toolCallId: tc.id,
|
|
3774
3892
|
responses: answers
|
|
@@ -3801,10 +3919,10 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3801
3919
|
return () => window.removeEventListener("keydown", handler);
|
|
3802
3920
|
}, [handleCancel, handleSubmit, locked]);
|
|
3803
3921
|
if (questions.length === 0) {
|
|
3804
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: "
|
|
3922
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: "ask_user_question: no questions provided" });
|
|
3805
3923
|
}
|
|
3806
3924
|
if (locked) {
|
|
3807
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3925
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AskUserQuestionLocked, { tc, questions });
|
|
3808
3926
|
}
|
|
3809
3927
|
const current = questions[active];
|
|
3810
3928
|
const currentSel = selections[active] ?? emptySelection();
|
|
@@ -3816,7 +3934,7 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3816
3934
|
"max-w-2xl"
|
|
3817
3935
|
),
|
|
3818
3936
|
role: "group",
|
|
3819
|
-
"aria-label": "
|
|
3937
|
+
"aria-label": "Questions for the user",
|
|
3820
3938
|
children: [
|
|
3821
3939
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 pt-2", children: [
|
|
3822
3940
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 overflow-x-auto text-sm", children: questions.map((_, i) => {
|
|
@@ -3980,11 +4098,11 @@ function Radio({ selected }) {
|
|
|
3980
4098
|
}
|
|
3981
4099
|
);
|
|
3982
4100
|
}
|
|
3983
|
-
function
|
|
4101
|
+
function AskUserQuestionLocked({
|
|
3984
4102
|
tc,
|
|
3985
4103
|
questions
|
|
3986
4104
|
}) {
|
|
3987
|
-
const answers = tc.
|
|
4105
|
+
const answers = tc.askUserQuestionAnswers;
|
|
3988
4106
|
const byPrompt = new Map(
|
|
3989
4107
|
answers?.map((a) => [a.question, a]) ?? []
|
|
3990
4108
|
);
|
|
@@ -4399,8 +4517,8 @@ function ToolCallBlock({
|
|
|
4399
4517
|
return /* @__PURE__ */ jsxRuntime.jsx(SkillViewBlock, { tc });
|
|
4400
4518
|
case "skill_manage":
|
|
4401
4519
|
return /* @__PURE__ */ jsxRuntime.jsx(SkillManageToolBlock, { tc });
|
|
4402
|
-
case "
|
|
4403
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4520
|
+
case "ask_user_question":
|
|
4521
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AskUserQuestionToolBlock, { tc });
|
|
4404
4522
|
case "create_artifact":
|
|
4405
4523
|
return /* @__PURE__ */ jsxRuntime.jsx(ArtifactToolBlock, { tc, resolvedName: resolvedArtifactName });
|
|
4406
4524
|
case "delegate_task":
|
|
@@ -5965,7 +6083,9 @@ function ChatComposerInner({
|
|
|
5965
6083
|
showWorkspace = false,
|
|
5966
6084
|
onToggleWorkspace,
|
|
5967
6085
|
canShowBrowser = false,
|
|
5968
|
-
canShowWorkspace = false
|
|
6086
|
+
canShowWorkspace = false,
|
|
6087
|
+
viewMode = "simple",
|
|
6088
|
+
onViewModeChange
|
|
5969
6089
|
}) {
|
|
5970
6090
|
const { adapter } = useAgentChatAdapterContext();
|
|
5971
6091
|
const { textInput, attachments } = usePromptInputController();
|
|
@@ -6272,6 +6392,36 @@ function ChatComposerInner({
|
|
|
6272
6392
|
}
|
|
6273
6393
|
)
|
|
6274
6394
|
] }),
|
|
6395
|
+
onViewModeChange && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6396
|
+
"div",
|
|
6397
|
+
{
|
|
6398
|
+
role: "group",
|
|
6399
|
+
"aria-label": "Chat view mode",
|
|
6400
|
+
className: "inline-flex overflow-hidden rounded-md border border-border",
|
|
6401
|
+
children: [
|
|
6402
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6403
|
+
"button",
|
|
6404
|
+
{
|
|
6405
|
+
type: "button",
|
|
6406
|
+
"aria-pressed": viewMode === "simple",
|
|
6407
|
+
onClick: () => onViewModeChange("simple"),
|
|
6408
|
+
className: viewMode === "simple" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
|
|
6409
|
+
children: "Simple"
|
|
6410
|
+
}
|
|
6411
|
+
),
|
|
6412
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6413
|
+
"button",
|
|
6414
|
+
{
|
|
6415
|
+
type: "button",
|
|
6416
|
+
"aria-pressed": viewMode === "expert",
|
|
6417
|
+
onClick: () => onViewModeChange("expert"),
|
|
6418
|
+
className: viewMode === "expert" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
|
|
6419
|
+
children: "Expert"
|
|
6420
|
+
}
|
|
6421
|
+
)
|
|
6422
|
+
]
|
|
6423
|
+
}
|
|
6424
|
+
),
|
|
6275
6425
|
canShowBrowser && onToggleBrowser && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6276
6426
|
PromptInputButton,
|
|
6277
6427
|
{
|
|
@@ -6438,16 +6588,26 @@ function ChatComposerInner({
|
|
|
6438
6588
|
CommandItem,
|
|
6439
6589
|
{
|
|
6440
6590
|
value: cmd.value,
|
|
6441
|
-
keywords: [cmd.description],
|
|
6591
|
+
keywords: cmd.isExpert ? [cmd.description, "expert"] : [cmd.description],
|
|
6442
6592
|
onSelect: () => handleCommandSelect(cmd.value),
|
|
6443
6593
|
className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
|
|
6444
6594
|
children: [
|
|
6445
|
-
/* @__PURE__ */ jsxRuntime.
|
|
6595
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6446
6596
|
"span",
|
|
6447
6597
|
{
|
|
6448
|
-
className: "
|
|
6598
|
+
className: "inline-flex items-center gap-1.5 min-w-0 max-w-full",
|
|
6449
6599
|
title: cmd.label,
|
|
6450
|
-
children:
|
|
6600
|
+
children: [
|
|
6601
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-foreground truncate", children: cmd.label }),
|
|
6602
|
+
cmd.isExpert && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6603
|
+
"span",
|
|
6604
|
+
{
|
|
6605
|
+
className: "shrink-0 rounded-sm bg-primary/10 px-1 text-[9px] font-semibold uppercase tracking-wider text-primary",
|
|
6606
|
+
"aria-label": "Expert specialist",
|
|
6607
|
+
children: "expert"
|
|
6608
|
+
}
|
|
6609
|
+
)
|
|
6610
|
+
]
|
|
6451
6611
|
}
|
|
6452
6612
|
),
|
|
6453
6613
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -7249,1207 +7409,1990 @@ var ErrorMessage = react.memo(function ErrorMessage2({
|
|
|
7249
7409
|
}
|
|
7250
7410
|
);
|
|
7251
7411
|
});
|
|
7252
|
-
|
|
7253
|
-
// src/components/chat/chat-thread.tsx
|
|
7254
7412
|
init_utils();
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
skill: msg.systemMeta?.skill ?? msg.content,
|
|
7262
|
-
stagedAt: msg.systemMeta?.staged_at ?? null
|
|
7263
|
-
}];
|
|
7264
|
-
}
|
|
7265
|
-
if (msg.systemKind === "artifact") {
|
|
7266
|
-
const { artifactId, name, kind, version } = unpackArtifactMeta(
|
|
7267
|
-
msg.systemMeta,
|
|
7268
|
-
msg.content
|
|
7269
|
-
);
|
|
7270
|
-
return [{
|
|
7271
|
-
kind: "artifact",
|
|
7272
|
-
key: msg.id,
|
|
7273
|
-
artifactId,
|
|
7274
|
-
name,
|
|
7275
|
-
artifactKind: kind,
|
|
7276
|
-
version
|
|
7277
|
-
}];
|
|
7278
|
-
}
|
|
7279
|
-
return [];
|
|
7280
|
-
}
|
|
7281
|
-
const entries = [];
|
|
7282
|
-
const hasToolCalls = !!(msg.toolCalls && msg.toolCalls.length > 0);
|
|
7283
|
-
const hasContent = !!(msg.content && msg.content !== msg.reasoning);
|
|
7284
|
-
const isStreaming = msg.status === "streaming" && isLast;
|
|
7285
|
-
const effectiveReasoning = hasToolCalls && hasContent ? msg.reasoning ? msg.reasoning + "\n" + msg.content : msg.content : msg.reasoning;
|
|
7286
|
-
const effectiveHasContent = hasContent && !hasToolCalls;
|
|
7287
|
-
if (effectiveReasoning) {
|
|
7288
|
-
entries.push({
|
|
7289
|
-
kind: "reasoning",
|
|
7290
|
-
key: `${msg.id}-reasoning`,
|
|
7291
|
-
reasoning: effectiveReasoning,
|
|
7292
|
-
isStreaming: isStreaming && !effectiveHasContent && !hasToolCalls
|
|
7293
|
-
});
|
|
7294
|
-
}
|
|
7295
|
-
if (hasToolCalls) {
|
|
7296
|
-
for (const tc of msg.toolCalls) {
|
|
7297
|
-
if (tc.toolName === "create_artifact") {
|
|
7298
|
-
const resolvedName = parseArgs(tc.args)?.name ?? artifactFallbacks[tc.id];
|
|
7299
|
-
const status = effectiveStatus(tc);
|
|
7300
|
-
if (!resolvedName && status !== "error") continue;
|
|
7301
|
-
entries.push({
|
|
7302
|
-
kind: "tool",
|
|
7303
|
-
key: tc.id,
|
|
7304
|
-
tc,
|
|
7305
|
-
resolvedArtifactName: resolvedName
|
|
7306
|
-
});
|
|
7307
|
-
continue;
|
|
7308
|
-
}
|
|
7309
|
-
if (tc.toolName === "terminal" && tc.status !== "running") {
|
|
7310
|
-
const parsed = parseTerminalResult(tc.result, tc.args);
|
|
7311
|
-
if (parsed && (parsed.exit_code !== 0 || parsed.error)) continue;
|
|
7312
|
-
}
|
|
7313
|
-
entries.push({ kind: "tool", key: tc.id, tc });
|
|
7314
|
-
}
|
|
7315
|
-
}
|
|
7316
|
-
if (effectiveHasContent) {
|
|
7317
|
-
entries.push({
|
|
7318
|
-
kind: "text",
|
|
7319
|
-
key: `${msg.id}-text`,
|
|
7320
|
-
content: msg.content,
|
|
7321
|
-
isStreaming,
|
|
7322
|
-
msg
|
|
7323
|
-
});
|
|
7324
|
-
}
|
|
7325
|
-
const hasRunningTool = hasToolCalls && msg.toolCalls.some(
|
|
7326
|
-
(tc) => tc.status === "running"
|
|
7327
|
-
);
|
|
7328
|
-
if (isStreaming && !effectiveHasContent && !hasRunningTool) {
|
|
7329
|
-
entries.push({ kind: "thinking", key: `${msg.id}-thinking` });
|
|
7330
|
-
}
|
|
7331
|
-
return entries;
|
|
7332
|
-
}
|
|
7333
|
-
function groupBrowserActivityEntries(entries) {
|
|
7334
|
-
const grouped = [];
|
|
7335
|
-
let buffer = [];
|
|
7336
|
-
const flush = () => {
|
|
7337
|
-
if (buffer.length === 0) return;
|
|
7338
|
-
grouped.push({
|
|
7339
|
-
kind: "browser_activity",
|
|
7340
|
-
key: `browser-activity-${buffer[0]?.id}-${buffer[buffer.length - 1]?.id}`,
|
|
7341
|
-
calls: buffer
|
|
7342
|
-
});
|
|
7343
|
-
buffer = [];
|
|
7344
|
-
};
|
|
7345
|
-
for (const entry of entries) {
|
|
7346
|
-
if (entry.kind === "tool" && isBrowserToolCall(entry.tc)) {
|
|
7347
|
-
buffer.push(entry.tc);
|
|
7348
|
-
continue;
|
|
7349
|
-
}
|
|
7350
|
-
flush();
|
|
7351
|
-
grouped.push(entry);
|
|
7352
|
-
}
|
|
7353
|
-
flush();
|
|
7354
|
-
return grouped;
|
|
7355
|
-
}
|
|
7356
|
-
function isBrowserToolCall(call) {
|
|
7357
|
-
return call.toolName.startsWith("browser_");
|
|
7413
|
+
|
|
7414
|
+
// src/lib/format.ts
|
|
7415
|
+
function formatFileSize(bytes) {
|
|
7416
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
7417
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
7418
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
7358
7419
|
}
|
|
7359
|
-
function
|
|
7360
|
-
const
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7420
|
+
function getLanguageHint(path) {
|
|
7421
|
+
const name = path.split("/").pop() ?? path;
|
|
7422
|
+
const dot = name.lastIndexOf(".");
|
|
7423
|
+
if (dot < 0) return "plaintext";
|
|
7424
|
+
const ext = name.slice(dot).toLowerCase();
|
|
7425
|
+
const map = {
|
|
7426
|
+
".py": "python",
|
|
7427
|
+
".js": "javascript",
|
|
7428
|
+
".ts": "typescript",
|
|
7429
|
+
".tsx": "tsx",
|
|
7430
|
+
".jsx": "jsx",
|
|
7431
|
+
".json": "json",
|
|
7432
|
+
".yaml": "yaml",
|
|
7433
|
+
".yml": "yaml",
|
|
7434
|
+
".toml": "toml",
|
|
7435
|
+
".sql": "sql",
|
|
7436
|
+
".sh": "bash",
|
|
7437
|
+
".css": "css",
|
|
7438
|
+
".html": "html",
|
|
7439
|
+
".md": "markdown",
|
|
7440
|
+
".rs": "rust",
|
|
7441
|
+
".go": "go",
|
|
7442
|
+
".java": "java",
|
|
7443
|
+
".rb": "ruby",
|
|
7444
|
+
".php": "php",
|
|
7445
|
+
".c": "c",
|
|
7446
|
+
".cpp": "cpp",
|
|
7447
|
+
".h": "c",
|
|
7448
|
+
".hpp": "cpp"
|
|
7374
7449
|
};
|
|
7375
|
-
|
|
7376
|
-
if (entry.kind === "tool" && entry.tc.toolName === "web_search") {
|
|
7377
|
-
buffer.push(entry.tc);
|
|
7378
|
-
continue;
|
|
7379
|
-
}
|
|
7380
|
-
flush();
|
|
7381
|
-
grouped.push(entry);
|
|
7382
|
-
}
|
|
7383
|
-
flush();
|
|
7384
|
-
return grouped;
|
|
7450
|
+
return map[ext] ?? "plaintext";
|
|
7385
7451
|
}
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
for (let i = 0; i < messages.length; i++) {
|
|
7396
|
-
const msg = messages[i];
|
|
7397
|
-
if (msg.role === "system") {
|
|
7398
|
-
pendingSystem.push({ msg, index: i });
|
|
7399
|
-
continue;
|
|
7400
|
-
}
|
|
7401
|
-
if (msg.role === "assistant") {
|
|
7402
|
-
const prev = groups[groups.length - 1];
|
|
7403
|
-
if (prev && prev.role === "assistant" && pendingSystem.length === 0) {
|
|
7404
|
-
prev.messages.push(msg);
|
|
7405
|
-
prev.lastGlobalIndex = i;
|
|
7406
|
-
} else {
|
|
7407
|
-
const folded = pendingSystem.map((p) => p.msg);
|
|
7408
|
-
pendingSystem = [];
|
|
7409
|
-
groups.push({
|
|
7410
|
-
role: "assistant",
|
|
7411
|
-
messages: [...folded, msg],
|
|
7412
|
-
lastGlobalIndex: i
|
|
7413
|
-
});
|
|
7414
|
-
}
|
|
7415
|
-
continue;
|
|
7452
|
+
|
|
7453
|
+
// src/components/ui/skeleton.tsx
|
|
7454
|
+
init_utils();
|
|
7455
|
+
function Skeleton({ className, ...props }) {
|
|
7456
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7457
|
+
"div",
|
|
7458
|
+
{
|
|
7459
|
+
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
7460
|
+
...props
|
|
7416
7461
|
}
|
|
7417
|
-
|
|
7418
|
-
groups.push({ role: "user", messages: [msg], lastGlobalIndex: i });
|
|
7419
|
-
}
|
|
7420
|
-
drainPendingAsOrphans();
|
|
7421
|
-
return groups;
|
|
7422
|
-
}
|
|
7423
|
-
function unpackArtifactMeta(systemMeta, fallbackName) {
|
|
7424
|
-
const meta = systemMeta ?? {};
|
|
7425
|
-
return {
|
|
7426
|
-
artifactId: meta.artifact_id ?? "",
|
|
7427
|
-
name: meta.name ?? fallbackName,
|
|
7428
|
-
kind: meta.kind ?? "markdown",
|
|
7429
|
-
version: meta.version ?? 1
|
|
7430
|
-
};
|
|
7462
|
+
);
|
|
7431
7463
|
}
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7464
|
+
var SKELETON_WIDTHS = [70, 85, 55, 90, 60, 78, 45, 82, 65, 72];
|
|
7465
|
+
var PDF_WORKER_SRC = new URL(
|
|
7466
|
+
"pdfjs-dist/legacy/build/pdf.worker.mjs",
|
|
7467
|
+
(typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))
|
|
7468
|
+
).toString();
|
|
7469
|
+
function FileViewer({
|
|
7470
|
+
file,
|
|
7471
|
+
loading,
|
|
7472
|
+
error,
|
|
7473
|
+
downloadUrl,
|
|
7474
|
+
onDelete,
|
|
7475
|
+
onClose
|
|
7436
7476
|
}) {
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
kind: unpacked.kind,
|
|
7456
|
-
version: unpacked.version
|
|
7457
|
-
}
|
|
7458
|
-
);
|
|
7459
|
-
}
|
|
7460
|
-
if (message.systemKind === "error" && message.errorInfo) {
|
|
7461
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto my-2 w-full max-w-4xl", children: /* @__PURE__ */ jsxRuntime.jsx(ErrorMessage, { errorInfo: message.errorInfo, onRetry }) });
|
|
7462
|
-
}
|
|
7463
|
-
return null;
|
|
7464
|
-
}
|
|
7465
|
-
function cancelledToolLabel(toolName) {
|
|
7466
|
-
const map = {
|
|
7467
|
-
terminal: "Command",
|
|
7468
|
-
execute_code: "Execute Code",
|
|
7469
|
-
read_file: "Read",
|
|
7470
|
-
write_file: "Write",
|
|
7471
|
-
patch: "Patch",
|
|
7472
|
-
search_files: "Search Files",
|
|
7473
|
-
list_files: "List Files",
|
|
7474
|
-
web_search: "Web Search",
|
|
7475
|
-
web_extract: "Web Fetch",
|
|
7476
|
-
web_crawl: "Web Crawl",
|
|
7477
|
-
session_search: "Session Search",
|
|
7478
|
-
memory: "Memory",
|
|
7479
|
-
todo: "Todo",
|
|
7480
|
-
skills_list: "Skills",
|
|
7481
|
-
skill_view: "Skill",
|
|
7482
|
-
consult_expert: "Expert",
|
|
7483
|
-
delegate_task: "Delegate",
|
|
7484
|
-
clarify: "Clarify",
|
|
7485
|
-
process: "Process",
|
|
7486
|
-
create_artifact: "Artifact"
|
|
7487
|
-
};
|
|
7488
|
-
return map[toolName] ?? toolName;
|
|
7489
|
-
}
|
|
7490
|
-
function CancelledToolRow({ tc }) {
|
|
7491
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
|
|
7492
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-muted-foreground", children: cancelledToolLabel(tc.toolName) }),
|
|
7493
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/70", children: "Cancelled" })
|
|
7494
|
-
] });
|
|
7495
|
-
}
|
|
7496
|
-
function TimelineEntryItem({
|
|
7497
|
-
entry,
|
|
7498
|
-
step,
|
|
7499
|
-
sessionId,
|
|
7500
|
-
onFileSelect
|
|
7501
|
-
}) {
|
|
7502
|
-
if (entry.kind === "reasoning") {
|
|
7503
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ReasoningEntry, { entry, step });
|
|
7504
|
-
}
|
|
7505
|
-
if (entry.kind === "tool") {
|
|
7506
|
-
const rawStatus = effectiveStatus(entry.tc);
|
|
7507
|
-
const hideArtifactFailure = rawStatus === "error" && entry.tc.toolName === "create_artifact";
|
|
7508
|
-
const indicatorStatus = hideArtifactFailure ? "running" : rawStatus;
|
|
7509
|
-
const failureSummary = rawStatus === "error" && !hideArtifactFailure ? toolErrorSummary(entry.tc.result) : "";
|
|
7510
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7511
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7512
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7513
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7514
|
-
TimelineIndicator,
|
|
7515
|
-
{
|
|
7516
|
-
className: cn("size-2 border-none", statusColorClass(indicatorStatus))
|
|
7517
|
-
}
|
|
7518
|
-
)
|
|
7519
|
-
] }),
|
|
7520
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: entry.tc.cancelled ? /* @__PURE__ */ jsxRuntime.jsx(CancelledToolRow, { tc: entry.tc }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
7521
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7522
|
-
ToolCallBlock,
|
|
7523
|
-
{
|
|
7524
|
-
tc: entry.tc,
|
|
7525
|
-
resolvedArtifactName: entry.resolvedArtifactName,
|
|
7526
|
-
onFileSelect
|
|
7527
|
-
}
|
|
7528
|
-
),
|
|
7529
|
-
failureSummary ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-full truncate text-xs text-destructive", title: failureSummary, children: failureSummary }) : null
|
|
7530
|
-
] }) })
|
|
7531
|
-
] });
|
|
7532
|
-
}
|
|
7533
|
-
if (entry.kind === "browser_activity") {
|
|
7534
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7535
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7536
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7537
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-amber-500" })
|
|
7538
|
-
] }),
|
|
7539
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(BrowserActivityGroup, { calls: entry.calls }) })
|
|
7540
|
-
] });
|
|
7541
|
-
}
|
|
7542
|
-
if (entry.kind === "web_search_group") {
|
|
7543
|
-
const allComplete = entry.calls.every((tc) => tc.status === "complete");
|
|
7544
|
-
const anyRunning = entry.calls.some((tc) => tc.status === "running");
|
|
7545
|
-
const indicatorClass = anyRunning ? "bg-emerald-500 animate-pulse" : allComplete ? "bg-emerald-500" : "bg-red-500";
|
|
7546
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7547
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7548
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7549
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: cn("size-2 border-none", indicatorClass) })
|
|
7550
|
-
] }),
|
|
7551
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(WebSearchGroupBlock, { tcs: entry.calls }) })
|
|
7552
|
-
] });
|
|
7553
|
-
}
|
|
7554
|
-
if (entry.kind === "text") {
|
|
7555
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextEntry, { entry, step });
|
|
7556
|
-
}
|
|
7557
|
-
if (entry.kind === "skill_invoked") {
|
|
7558
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7559
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7560
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7561
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-emerald-500" })
|
|
7562
|
-
] }),
|
|
7563
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 py-1 text-sm ", children: [
|
|
7564
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "Skill" }),
|
|
7565
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground truncate", children: entry.skill }),
|
|
7566
|
-
entry.stagedAt && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground/70 ", children: [
|
|
7567
|
-
"staged at ",
|
|
7568
|
-
entry.stagedAt
|
|
7477
|
+
const visible = loading || file !== null || error !== null;
|
|
7478
|
+
if (!visible) return null;
|
|
7479
|
+
const fileName2 = file?.path.split("/").pop() ?? "File";
|
|
7480
|
+
const lang = file ? getLanguageHint(file.path) : "";
|
|
7481
|
+
const isPdf = file?.mime_type === "application/pdf" || file?.path.toLowerCase().endsWith(".pdf") || false;
|
|
7482
|
+
const isImage = file?.encoding === "base64" && !isPdf;
|
|
7483
|
+
const HeaderIcon = isImage ? lucideReact.ImageIcon : lucideReact.FileTextIcon;
|
|
7484
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col border-t border-line", children: [
|
|
7485
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
|
|
7486
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeaderIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
7487
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7488
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs font-medium", children: fileName2 }),
|
|
7489
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "truncate text-[10px] text-muted-foreground", children: [
|
|
7490
|
+
file?.path ?? "Loading...",
|
|
7491
|
+
file && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-1.5", children: [
|
|
7492
|
+
formatFileSize(file.size),
|
|
7493
|
+
file.truncated && " (truncated)"
|
|
7494
|
+
] })
|
|
7569
7495
|
] })
|
|
7570
|
-
] }) })
|
|
7571
|
-
] });
|
|
7572
|
-
}
|
|
7573
|
-
if (entry.kind === "artifact") {
|
|
7574
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7575
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7576
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7577
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-sky-500" })
|
|
7578
7496
|
] }),
|
|
7579
|
-
|
|
7580
|
-
|
|
7497
|
+
downloadUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7498
|
+
"a",
|
|
7581
7499
|
{
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7500
|
+
href: downloadUrl,
|
|
7501
|
+
download: fileName2,
|
|
7502
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
7503
|
+
"aria-label": `Download ${fileName2}`,
|
|
7504
|
+
title: "Download",
|
|
7505
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { className: "size-3.5" })
|
|
7587
7506
|
}
|
|
7588
|
-
)
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
}
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7507
|
+
),
|
|
7508
|
+
onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7509
|
+
"button",
|
|
7510
|
+
{
|
|
7511
|
+
type: "button",
|
|
7512
|
+
onClick: onDelete,
|
|
7513
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
|
|
7514
|
+
"aria-label": `Delete ${fileName2}`,
|
|
7515
|
+
title: "Delete",
|
|
7516
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrashIcon, { className: "size-3.5" })
|
|
7517
|
+
}
|
|
7518
|
+
),
|
|
7519
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7520
|
+
"button",
|
|
7521
|
+
{
|
|
7522
|
+
type: "button",
|
|
7523
|
+
onClick: onClose,
|
|
7524
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
7525
|
+
"aria-label": "Close file",
|
|
7526
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-3.5" })
|
|
7527
|
+
}
|
|
7528
|
+
)
|
|
7608
7529
|
] }),
|
|
7609
|
-
/* @__PURE__ */ jsxRuntime.
|
|
7610
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7611
|
-
|
|
7612
|
-
|
|
7530
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "min-h-0 flex-1", children: [
|
|
7531
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5 p-3", children: Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7532
|
+
Skeleton,
|
|
7533
|
+
{
|
|
7534
|
+
className: "h-3.5 rounded",
|
|
7535
|
+
style: {
|
|
7536
|
+
width: `${SKELETON_WIDTHS[index % SKELETON_WIDTHS.length]}%`
|
|
7537
|
+
}
|
|
7538
|
+
},
|
|
7539
|
+
index
|
|
7540
|
+
)) }),
|
|
7541
|
+
error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
7542
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7543
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
|
|
7544
|
+
] }),
|
|
7545
|
+
file && isPdf && file.encoding !== "base64" && /* @__PURE__ */ jsxRuntime.jsx(FileViewerError, { message: "PDF preview requires base64 file content." }),
|
|
7546
|
+
file && isPdf && file.encoding === "base64" && /* @__PURE__ */ jsxRuntime.jsx(PdfPreview, { file, fileName: fileName2 }),
|
|
7547
|
+
file && isImage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7548
|
+
"img",
|
|
7549
|
+
{
|
|
7550
|
+
src: `data:${file.mime_type ?? "image/png"};base64,${file.content}`,
|
|
7551
|
+
alt: fileName2,
|
|
7552
|
+
className: "max-h-[60vh] max-w-full rounded object-contain"
|
|
7553
|
+
}
|
|
7554
|
+
) }),
|
|
7555
|
+
file && !isImage && !isPdf && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "wrap-break-word whitespace-pre-wrap p-3 text-[11px] leading-relaxed text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("code", { "data-language": lang, children: file.content }) })
|
|
7556
|
+
] })
|
|
7613
7557
|
] });
|
|
7614
7558
|
}
|
|
7615
|
-
function
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
})
|
|
7619
|
-
const content = useSmoothStream(entry.content, entry.isStreaming);
|
|
7620
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7621
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7622
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7623
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
|
|
7624
|
-
] }),
|
|
7625
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineContent, { children: [
|
|
7626
|
-
/* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: content }),
|
|
7627
|
-
entry.isFinalTurnText && entry.msg.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnFeedback, { msg: entry.msg })
|
|
7628
|
-
] })
|
|
7559
|
+
function FileViewerError({ message }) {
|
|
7560
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
7561
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7562
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: message })
|
|
7629
7563
|
] });
|
|
7630
7564
|
}
|
|
7631
|
-
function
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
totalMessages,
|
|
7635
|
-
isRunning,
|
|
7636
|
-
sessionId,
|
|
7637
|
-
artifactFallbacks,
|
|
7638
|
-
onFileSelect,
|
|
7639
|
-
onRetry
|
|
7565
|
+
function PdfPreview({
|
|
7566
|
+
file,
|
|
7567
|
+
fileName: fileName2
|
|
7640
7568
|
}) {
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
}
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
children: [
|
|
7696
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3 shrink-0" }),
|
|
7697
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate font-medium", children: indicator.title }),
|
|
7698
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
|
|
7699
|
-
"attempt ",
|
|
7700
|
-
indicator.attempt
|
|
7701
|
-
] }),
|
|
7702
|
-
indicator.detail && (open ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-3" }))
|
|
7703
|
-
]
|
|
7704
|
-
}
|
|
7705
|
-
),
|
|
7706
|
-
open && indicator.detail && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "mt-1 overflow-x-auto rounded-none bg-background p-2 font-mono text-[11px] whitespace-pre-wrap wrap-break-word text-muted-foreground", children: indicator.detail })
|
|
7707
|
-
]
|
|
7708
|
-
}
|
|
7709
|
-
);
|
|
7710
|
-
}
|
|
7711
|
-
function ChatThread({
|
|
7712
|
-
sessionId,
|
|
7713
|
-
messages,
|
|
7714
|
-
isRunning,
|
|
7715
|
-
isLoadingHistory = false,
|
|
7716
|
-
onSend,
|
|
7717
|
-
onStop,
|
|
7718
|
-
onFileSelect,
|
|
7719
|
-
disabled = false,
|
|
7720
|
-
disabledReason,
|
|
7721
|
-
tokenUsage,
|
|
7722
|
-
retryIndicator,
|
|
7723
|
-
onRetry,
|
|
7724
|
-
onComposerError,
|
|
7725
|
-
showBrowser = false,
|
|
7726
|
-
onToggleBrowser,
|
|
7727
|
-
showWorkspace = false,
|
|
7728
|
-
onToggleWorkspace,
|
|
7729
|
-
canShowBrowser = false,
|
|
7730
|
-
canShowWorkspace = false
|
|
7731
|
-
}) {
|
|
7732
|
-
const groups = react.useMemo(() => groupMessages(messages), [messages]);
|
|
7733
|
-
const artifactFallbacks = react.useMemo(() => {
|
|
7734
|
-
const fallbacks = {};
|
|
7735
|
-
const createArtifactToolCallIds = [];
|
|
7736
|
-
let artifactIdx = 0;
|
|
7737
|
-
for (const msg of messages) {
|
|
7738
|
-
if (msg.role === "assistant" && msg.toolCalls) {
|
|
7739
|
-
for (const tc of msg.toolCalls) {
|
|
7740
|
-
if (tc.toolName === "create_artifact" && !tc.cancelled && tc.status !== "error") {
|
|
7741
|
-
createArtifactToolCallIds.push(tc.id);
|
|
7742
|
-
}
|
|
7569
|
+
const containerRef = react.useRef(null);
|
|
7570
|
+
const viewerRef = react.useRef(null);
|
|
7571
|
+
const pdfViewerRef = react.useRef(null);
|
|
7572
|
+
const eventBusRef = react.useRef(null);
|
|
7573
|
+
const findControllerRef = react.useRef(null);
|
|
7574
|
+
const [error, setError] = react.useState(null);
|
|
7575
|
+
const [pageNumber, setPageNumber] = react.useState(1);
|
|
7576
|
+
const [pagesCount, setPagesCount] = react.useState(0);
|
|
7577
|
+
const [scale, setScale] = react.useState(1);
|
|
7578
|
+
const [query, setQuery] = react.useState("");
|
|
7579
|
+
react.useEffect(() => {
|
|
7580
|
+
let cancelled = false;
|
|
7581
|
+
let loadingTask = null;
|
|
7582
|
+
let pdfDocument = null;
|
|
7583
|
+
const renderPdf = async () => {
|
|
7584
|
+
setError(null);
|
|
7585
|
+
const container = containerRef.current;
|
|
7586
|
+
const viewerElement = viewerRef.current;
|
|
7587
|
+
if (!container || !viewerElement) return;
|
|
7588
|
+
const pdfBytes = decodeBase64(file.content);
|
|
7589
|
+
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
7590
|
+
pdfjs.GlobalWorkerOptions.workerSrc = PDF_WORKER_SRC;
|
|
7591
|
+
globalThis.pdfjsLib = pdfjs;
|
|
7592
|
+
const pdfViewerModule = await import('pdfjs-dist/web/pdf_viewer.mjs');
|
|
7593
|
+
loadingTask = pdfjs.getDocument({ data: pdfBytes });
|
|
7594
|
+
const pdf = await loadingTask.promise;
|
|
7595
|
+
pdfDocument = pdf;
|
|
7596
|
+
if (cancelled) return;
|
|
7597
|
+
const eventBus = new pdfViewerModule.EventBus();
|
|
7598
|
+
const linkService = new pdfViewerModule.PDFLinkService({ eventBus });
|
|
7599
|
+
const findController = new pdfViewerModule.PDFFindController({
|
|
7600
|
+
eventBus,
|
|
7601
|
+
linkService
|
|
7602
|
+
});
|
|
7603
|
+
const pdfViewer = new pdfViewerModule.PDFViewer({
|
|
7604
|
+
container,
|
|
7605
|
+
viewer: viewerElement,
|
|
7606
|
+
eventBus,
|
|
7607
|
+
linkService,
|
|
7608
|
+
findController,
|
|
7609
|
+
removePageBorders: true
|
|
7610
|
+
});
|
|
7611
|
+
linkService.setViewer(pdfViewer);
|
|
7612
|
+
linkService.setDocument(pdf);
|
|
7613
|
+
findController.setDocument(pdf);
|
|
7614
|
+
const onPagesInit = () => {
|
|
7615
|
+
pdfViewer.currentScaleValue = "page-width";
|
|
7616
|
+
setScale(pdfViewer.currentScale || 1);
|
|
7617
|
+
setPagesCount(pdfViewer.pagesCount);
|
|
7618
|
+
setPageNumber(pdfViewer.currentPageNumber);
|
|
7619
|
+
};
|
|
7620
|
+
const onPageChanging = (event) => {
|
|
7621
|
+
if (typeof event.pageNumber === "number") {
|
|
7622
|
+
setPageNumber(event.pageNumber);
|
|
7743
7623
|
}
|
|
7744
|
-
}
|
|
7745
|
-
|
|
7746
|
-
if (
|
|
7747
|
-
|
|
7748
|
-
if (name) fallbacks[tcId] = name;
|
|
7624
|
+
};
|
|
7625
|
+
const onScaleChanging = (event) => {
|
|
7626
|
+
if (typeof event.scale === "number") {
|
|
7627
|
+
setScale(event.scale);
|
|
7749
7628
|
}
|
|
7750
|
-
|
|
7629
|
+
};
|
|
7630
|
+
eventBus.on("pagesinit", onPagesInit);
|
|
7631
|
+
eventBus.on("pagechanging", onPageChanging);
|
|
7632
|
+
eventBus.on("scalechanging", onScaleChanging);
|
|
7633
|
+
pdfViewerRef.current = pdfViewer;
|
|
7634
|
+
eventBusRef.current = eventBus;
|
|
7635
|
+
findControllerRef.current = findController;
|
|
7636
|
+
setPagesCount(pdf.numPages);
|
|
7637
|
+
pdfViewer.setDocument(pdf);
|
|
7638
|
+
};
|
|
7639
|
+
void renderPdf().catch((nextError) => {
|
|
7640
|
+
if (cancelled) return;
|
|
7641
|
+
if (nextError instanceof Error && nextError.name === "RenderingCancelledException") {
|
|
7642
|
+
return;
|
|
7751
7643
|
}
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7644
|
+
setError(formatPdfPreviewError(nextError));
|
|
7645
|
+
});
|
|
7646
|
+
return () => {
|
|
7647
|
+
cancelled = true;
|
|
7648
|
+
loadingTask?.destroy();
|
|
7649
|
+
pdfDocument?.destroy();
|
|
7650
|
+
pdfViewerRef.current?.cleanup();
|
|
7651
|
+
pdfViewerRef.current = null;
|
|
7652
|
+
eventBusRef.current = null;
|
|
7653
|
+
findControllerRef.current = null;
|
|
7654
|
+
};
|
|
7655
|
+
}, [file.content]);
|
|
7656
|
+
const setViewerPage = (nextPage) => {
|
|
7657
|
+
const viewer = pdfViewerRef.current;
|
|
7658
|
+
if (!viewer) return;
|
|
7659
|
+
const clampedPage = Math.min(
|
|
7660
|
+
Math.max(1, nextPage),
|
|
7661
|
+
Math.max(1, viewer.pagesCount)
|
|
7662
|
+
);
|
|
7663
|
+
viewer.currentPageNumber = clampedPage;
|
|
7664
|
+
setPageNumber(clampedPage);
|
|
7665
|
+
};
|
|
7666
|
+
const setViewerScale = (nextScale) => {
|
|
7667
|
+
const viewer = pdfViewerRef.current;
|
|
7668
|
+
if (!viewer) return;
|
|
7669
|
+
const clampedScale = Math.min(3, Math.max(0.5, nextScale));
|
|
7670
|
+
viewer.currentScale = clampedScale;
|
|
7671
|
+
setScale(clampedScale);
|
|
7672
|
+
};
|
|
7673
|
+
const runFind = (findPrevious = false) => {
|
|
7674
|
+
const eventBus = eventBusRef.current;
|
|
7675
|
+
if (!eventBus || !query.trim()) return;
|
|
7676
|
+
eventBus.dispatch("find", {
|
|
7677
|
+
source: eventBus,
|
|
7678
|
+
type: "again",
|
|
7679
|
+
query,
|
|
7680
|
+
phraseSearch: true,
|
|
7681
|
+
caseSensitive: false,
|
|
7682
|
+
entireWord: false,
|
|
7683
|
+
highlightAll: true,
|
|
7684
|
+
findPrevious,
|
|
7685
|
+
matchDiacritics: true
|
|
7686
|
+
});
|
|
7687
|
+
};
|
|
7688
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-full flex-col", children: [
|
|
7689
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-1.5 border-b border-line px-2 py-1.5", children: [
|
|
7690
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7691
|
+
Button,
|
|
7770
7692
|
{
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7693
|
+
type: "button",
|
|
7694
|
+
variant: "ghost",
|
|
7695
|
+
size: "icon-xs",
|
|
7696
|
+
onClick: () => setViewerPage(pageNumber - 1),
|
|
7697
|
+
disabled: pageNumber <= 1,
|
|
7698
|
+
"aria-label": "Previous PDF page",
|
|
7699
|
+
title: "Previous page",
|
|
7700
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeftIcon, { className: "size-3.5" })
|
|
7774
7701
|
}
|
|
7775
|
-
)
|
|
7776
|
-
|
|
7702
|
+
),
|
|
7703
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7704
|
+
Input,
|
|
7777
7705
|
{
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7706
|
+
type: "number",
|
|
7707
|
+
min: 1,
|
|
7708
|
+
max: pagesCount || 1,
|
|
7709
|
+
value: pageNumber,
|
|
7710
|
+
onChange: (event) => setViewerPage(Number(event.target.value)),
|
|
7711
|
+
"aria-label": "PDF page number",
|
|
7712
|
+
className: "h-7 w-12 border-input px-1 text-center text-xs"
|
|
7781
7713
|
}
|
|
7782
|
-
)
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
message: msg,
|
|
7790
|
-
onFileSelect
|
|
7791
|
-
},
|
|
7792
|
-
msg.id
|
|
7793
|
-
);
|
|
7794
|
-
}
|
|
7795
|
-
if (group.role === "system") {
|
|
7796
|
-
const msg = group.messages[0];
|
|
7797
|
-
const groupRetry2 = msg.id === activeFailureId ? onRetry : void 0;
|
|
7798
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7799
|
-
OrphanSystemMarker,
|
|
7800
|
-
{
|
|
7801
|
-
message: msg,
|
|
7802
|
-
sessionId,
|
|
7803
|
-
onRetry: groupRetry2
|
|
7804
|
-
},
|
|
7805
|
-
msg.id
|
|
7806
|
-
);
|
|
7807
|
-
}
|
|
7808
|
-
const groupTail = group.messages[group.messages.length - 1];
|
|
7809
|
-
const groupRetry = groupTail.id === activeFailureId ? onRetry : void 0;
|
|
7810
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7811
|
-
AssistantGroup,
|
|
7812
|
-
{
|
|
7813
|
-
messages: group.messages,
|
|
7814
|
-
lastGlobalIndex: group.lastGlobalIndex,
|
|
7815
|
-
totalMessages: messages.length,
|
|
7816
|
-
isRunning,
|
|
7817
|
-
sessionId,
|
|
7818
|
-
artifactFallbacks,
|
|
7819
|
-
onFileSelect,
|
|
7820
|
-
onRetry: groupRetry
|
|
7821
|
-
},
|
|
7822
|
-
group.messages[0].id
|
|
7823
|
-
);
|
|
7824
|
-
}),
|
|
7825
|
-
isRunning && messages.length > 0 && messages[messages.length - 1].role === "user" && /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) }) })
|
|
7826
|
-
] }) }),
|
|
7827
|
-
/* @__PURE__ */ jsxRuntime.jsx(ConversationScrollButton, {})
|
|
7828
|
-
] }),
|
|
7829
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-4xl px-3 sm:px-6 pb-3 sm:pb-5 pt-3", children: [
|
|
7830
|
-
retryIndicator && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(RetryBanner, { indicator: retryIndicator }) }),
|
|
7831
|
-
disabled && disabledReason ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7832
|
-
"div",
|
|
7714
|
+
),
|
|
7715
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
7716
|
+
"/ ",
|
|
7717
|
+
pagesCount || "-"
|
|
7718
|
+
] }),
|
|
7719
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7720
|
+
Button,
|
|
7833
7721
|
{
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7722
|
+
type: "button",
|
|
7723
|
+
variant: "ghost",
|
|
7724
|
+
size: "icon-xs",
|
|
7725
|
+
onClick: () => setViewerPage(pageNumber + 1),
|
|
7726
|
+
disabled: pagesCount > 0 && pageNumber >= pagesCount,
|
|
7727
|
+
"aria-label": "Next PDF page",
|
|
7728
|
+
title: "Next page",
|
|
7729
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: "size-3.5" })
|
|
7837
7730
|
}
|
|
7838
|
-
)
|
|
7839
|
-
|
|
7731
|
+
),
|
|
7732
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
7733
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7734
|
+
Button,
|
|
7840
7735
|
{
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7736
|
+
type: "button",
|
|
7737
|
+
variant: "ghost",
|
|
7738
|
+
size: "icon-xs",
|
|
7739
|
+
onClick: () => setViewerScale(scale - 0.1),
|
|
7740
|
+
disabled: scale <= 0.5,
|
|
7741
|
+
"aria-label": "Zoom out PDF",
|
|
7742
|
+
title: "Zoom out",
|
|
7743
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusIcon, { className: "size-3.5" })
|
|
7744
|
+
}
|
|
7745
|
+
),
|
|
7746
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7747
|
+
"button",
|
|
7748
|
+
{
|
|
7749
|
+
type: "button",
|
|
7750
|
+
className: "h-7 min-w-12 px-1 text-xs text-muted-foreground hover:text-foreground",
|
|
7751
|
+
onClick: () => {
|
|
7752
|
+
const viewer = pdfViewerRef.current;
|
|
7753
|
+
if (!viewer) return;
|
|
7754
|
+
viewer.currentScaleValue = "page-width";
|
|
7755
|
+
setScale(viewer.currentScale || 1);
|
|
7756
|
+
},
|
|
7757
|
+
"aria-label": "Fit PDF to width",
|
|
7758
|
+
title: "Fit width",
|
|
7759
|
+
children: [
|
|
7760
|
+
Math.round(scale * 100),
|
|
7761
|
+
"%"
|
|
7762
|
+
]
|
|
7763
|
+
}
|
|
7764
|
+
),
|
|
7765
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7766
|
+
Button,
|
|
7767
|
+
{
|
|
7768
|
+
type: "button",
|
|
7769
|
+
variant: "ghost",
|
|
7770
|
+
size: "icon-xs",
|
|
7771
|
+
onClick: () => setViewerScale(scale + 0.1),
|
|
7772
|
+
disabled: scale >= 3,
|
|
7773
|
+
"aria-label": "Zoom in PDF",
|
|
7774
|
+
title: "Zoom in",
|
|
7775
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { className: "size-3.5" })
|
|
7776
|
+
}
|
|
7777
|
+
),
|
|
7778
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
7779
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { className: "size-3.5 text-muted-foreground" }),
|
|
7780
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7781
|
+
Input,
|
|
7782
|
+
{
|
|
7783
|
+
type: "search",
|
|
7784
|
+
value: query,
|
|
7785
|
+
onChange: (event) => setQuery(event.target.value),
|
|
7786
|
+
onKeyDown: (event) => {
|
|
7787
|
+
if (event.key === "Enter") runFind(event.shiftKey);
|
|
7788
|
+
},
|
|
7789
|
+
placeholder: "Find",
|
|
7790
|
+
"aria-label": "Find in PDF",
|
|
7791
|
+
className: "h-7 w-28 border-input px-1 text-xs"
|
|
7792
|
+
}
|
|
7793
|
+
),
|
|
7794
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7795
|
+
Button,
|
|
7796
|
+
{
|
|
7797
|
+
type: "button",
|
|
7798
|
+
variant: "ghost",
|
|
7799
|
+
size: "xs",
|
|
7800
|
+
onClick: () => runFind(false),
|
|
7801
|
+
disabled: !query.trim(),
|
|
7802
|
+
children: "Find"
|
|
7854
7803
|
}
|
|
7855
7804
|
)
|
|
7856
|
-
] })
|
|
7805
|
+
] }),
|
|
7806
|
+
error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
7807
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7808
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
|
|
7809
|
+
] }),
|
|
7810
|
+
!error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-[70vh] min-h-[420px] flex-1 bg-muted/20", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7811
|
+
"div",
|
|
7812
|
+
{
|
|
7813
|
+
ref: containerRef,
|
|
7814
|
+
"aria-label": `PDF viewer for ${fileName2}`,
|
|
7815
|
+
className: "absolute inset-0 overflow-auto",
|
|
7816
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: viewerRef, className: "pdfViewer" })
|
|
7817
|
+
}
|
|
7818
|
+
) })
|
|
7857
7819
|
] });
|
|
7858
7820
|
}
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7821
|
+
function decodeBase64(content) {
|
|
7822
|
+
const binary = globalThis.atob(content);
|
|
7823
|
+
const bytes = new Uint8Array(binary.length);
|
|
7824
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
7825
|
+
bytes[index] = binary.charCodeAt(index);
|
|
7826
|
+
}
|
|
7827
|
+
return bytes;
|
|
7828
|
+
}
|
|
7829
|
+
function formatPdfPreviewError(error) {
|
|
7830
|
+
if (error instanceof Error && (error.name === "InvalidCharacterError" || error.message === "Invalid character")) {
|
|
7831
|
+
return "PDF preview data is not valid base64.";
|
|
7832
|
+
}
|
|
7833
|
+
return error instanceof Error ? error.message : "Failed to render PDF preview.";
|
|
7834
|
+
}
|
|
7835
|
+
var _EXTENSION_KIND = {
|
|
7836
|
+
// Documents
|
|
7837
|
+
pdf: { icon: lucideReact.FileTextIcon, typeLabel: "PDF" },
|
|
7838
|
+
doc: { icon: lucideReact.FileTextIcon, typeLabel: "Word document" },
|
|
7839
|
+
docx: { icon: lucideReact.FileTextIcon, typeLabel: "Word document" },
|
|
7840
|
+
odt: { icon: lucideReact.FileTextIcon, typeLabel: "OpenDocument text" },
|
|
7841
|
+
rtf: { icon: lucideReact.FileTextIcon, typeLabel: "Rich text" },
|
|
7842
|
+
txt: { icon: lucideReact.FileTextIcon, typeLabel: "Text" },
|
|
7843
|
+
md: { icon: lucideReact.FileTextIcon, typeLabel: "Markdown" },
|
|
7844
|
+
// Spreadsheets
|
|
7845
|
+
xls: { icon: lucideReact.FileSpreadsheetIcon, typeLabel: "Spreadsheet" },
|
|
7846
|
+
xlsx: { icon: lucideReact.FileSpreadsheetIcon, typeLabel: "Spreadsheet" },
|
|
7847
|
+
ods: { icon: lucideReact.FileSpreadsheetIcon, typeLabel: "OpenDocument spreadsheet" },
|
|
7848
|
+
csv: { icon: lucideReact.FileSpreadsheetIcon, typeLabel: "CSV" },
|
|
7849
|
+
tsv: { icon: lucideReact.FileSpreadsheetIcon, typeLabel: "TSV" },
|
|
7850
|
+
// Presentations / charts
|
|
7851
|
+
ppt: { icon: lucideReact.FileChartLineIcon, typeLabel: "Presentation" },
|
|
7852
|
+
pptx: { icon: lucideReact.FileChartLineIcon, typeLabel: "Presentation" },
|
|
7853
|
+
// Images
|
|
7854
|
+
png: { icon: lucideReact.FileImageIcon, typeLabel: "Image" },
|
|
7855
|
+
jpg: { icon: lucideReact.FileImageIcon, typeLabel: "Image" },
|
|
7856
|
+
jpeg: { icon: lucideReact.FileImageIcon, typeLabel: "Image" },
|
|
7857
|
+
gif: { icon: lucideReact.FileImageIcon, typeLabel: "Image" },
|
|
7858
|
+
svg: { icon: lucideReact.FileImageIcon, typeLabel: "SVG image" },
|
|
7859
|
+
webp: { icon: lucideReact.FileImageIcon, typeLabel: "Image" },
|
|
7860
|
+
bmp: { icon: lucideReact.FileImageIcon, typeLabel: "Image" },
|
|
7861
|
+
// Audio / video
|
|
7862
|
+
mp3: { icon: lucideReact.FileAudioIcon, typeLabel: "Audio" },
|
|
7863
|
+
wav: { icon: lucideReact.FileAudioIcon, typeLabel: "Audio" },
|
|
7864
|
+
ogg: { icon: lucideReact.FileAudioIcon, typeLabel: "Audio" },
|
|
7865
|
+
mp4: { icon: lucideReact.FileVideoIcon, typeLabel: "Video" },
|
|
7866
|
+
mov: { icon: lucideReact.FileVideoIcon, typeLabel: "Video" },
|
|
7867
|
+
webm: { icon: lucideReact.FileVideoIcon, typeLabel: "Video" },
|
|
7868
|
+
// Archives
|
|
7869
|
+
zip: { icon: lucideReact.FileArchiveIcon, typeLabel: "Archive" },
|
|
7870
|
+
tar: { icon: lucideReact.FileArchiveIcon, typeLabel: "Archive" },
|
|
7871
|
+
gz: { icon: lucideReact.FileArchiveIcon, typeLabel: "Archive" },
|
|
7872
|
+
bz2: { icon: lucideReact.FileArchiveIcon, typeLabel: "Archive" },
|
|
7873
|
+
"7z": { icon: lucideReact.FileArchiveIcon, typeLabel: "Archive" },
|
|
7874
|
+
// Code
|
|
7875
|
+
py: { icon: lucideReact.FileCodeIcon, typeLabel: "Python" },
|
|
7876
|
+
js: { icon: lucideReact.FileCodeIcon, typeLabel: "JavaScript" },
|
|
7877
|
+
ts: { icon: lucideReact.FileCodeIcon, typeLabel: "TypeScript" },
|
|
7878
|
+
tsx: { icon: lucideReact.FileCodeIcon, typeLabel: "TypeScript" },
|
|
7879
|
+
jsx: { icon: lucideReact.FileCodeIcon, typeLabel: "JavaScript" },
|
|
7880
|
+
json: { icon: lucideReact.FileCodeIcon, typeLabel: "JSON" },
|
|
7881
|
+
yaml: { icon: lucideReact.FileCodeIcon, typeLabel: "YAML" },
|
|
7882
|
+
yml: { icon: lucideReact.FileCodeIcon, typeLabel: "YAML" },
|
|
7883
|
+
toml: { icon: lucideReact.FileCodeIcon, typeLabel: "TOML" },
|
|
7884
|
+
sh: { icon: lucideReact.CodeIcon, typeLabel: "Shell" },
|
|
7885
|
+
rs: { icon: lucideReact.FileCodeIcon, typeLabel: "Rust" },
|
|
7886
|
+
go: { icon: lucideReact.FileCodeIcon, typeLabel: "Go" },
|
|
7887
|
+
rb: { icon: lucideReact.FileCodeIcon, typeLabel: "Ruby" },
|
|
7888
|
+
java: { icon: lucideReact.FileCodeIcon, typeLabel: "Java" },
|
|
7889
|
+
cpp: { icon: lucideReact.FileCodeIcon, typeLabel: "C++" },
|
|
7890
|
+
c: { icon: lucideReact.FileCodeIcon, typeLabel: "C" },
|
|
7891
|
+
html: { icon: lucideReact.FileCodeIcon, typeLabel: "HTML" },
|
|
7892
|
+
css: { icon: lucideReact.FileCodeIcon, typeLabel: "CSS" },
|
|
7893
|
+
scss: { icon: lucideReact.FileCodeIcon, typeLabel: "Sass" },
|
|
7894
|
+
sql: { icon: lucideReact.FileCodeIcon, typeLabel: "SQL" }
|
|
7863
7895
|
};
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
function FileTree({
|
|
7869
|
-
expanded: controlledExpanded,
|
|
7870
|
-
defaultExpanded = /* @__PURE__ */ new Set(),
|
|
7871
|
-
selectedPath,
|
|
7872
|
-
onSelect,
|
|
7873
|
-
onExpandedChange,
|
|
7874
|
-
className,
|
|
7875
|
-
children,
|
|
7876
|
-
...props
|
|
7877
|
-
}) {
|
|
7878
|
-
const [internalExpanded, setInternalExpanded] = react.useState(defaultExpanded);
|
|
7879
|
-
const expandedPaths = controlledExpanded ?? internalExpanded;
|
|
7880
|
-
const togglePath = react.useCallback(
|
|
7881
|
-
(path) => {
|
|
7882
|
-
const next = new Set(expandedPaths);
|
|
7883
|
-
if (next.has(path)) {
|
|
7884
|
-
next.delete(path);
|
|
7885
|
-
} else {
|
|
7886
|
-
next.add(path);
|
|
7887
|
-
}
|
|
7888
|
-
setInternalExpanded(next);
|
|
7889
|
-
onExpandedChange?.(next);
|
|
7890
|
-
},
|
|
7891
|
-
[expandedPaths, onExpandedChange]
|
|
7892
|
-
);
|
|
7893
|
-
const contextValue = react.useMemo(
|
|
7894
|
-
() => ({
|
|
7895
|
-
expandedPaths,
|
|
7896
|
-
onSelect,
|
|
7897
|
-
selectedPath: selectedPath ?? void 0,
|
|
7898
|
-
togglePath
|
|
7899
|
-
}),
|
|
7900
|
-
[expandedPaths, onSelect, selectedPath, togglePath]
|
|
7901
|
-
);
|
|
7902
|
-
return /* @__PURE__ */ jsxRuntime.jsx(FileTreeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7903
|
-
"div",
|
|
7904
|
-
{
|
|
7905
|
-
className: cn("rounded-lg border bg-background text-sm", className),
|
|
7906
|
-
role: "tree",
|
|
7907
|
-
...props,
|
|
7908
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children })
|
|
7909
|
-
}
|
|
7910
|
-
) });
|
|
7896
|
+
function _extension(path) {
|
|
7897
|
+
const idx = path.lastIndexOf(".");
|
|
7898
|
+
if (idx < 0 || idx === path.length - 1) return "";
|
|
7899
|
+
return path.slice(idx + 1).toLowerCase();
|
|
7911
7900
|
}
|
|
7912
|
-
function
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
...props
|
|
7916
|
-
}) {
|
|
7917
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0", className), ...props, children });
|
|
7901
|
+
function _fileKindFor(path) {
|
|
7902
|
+
const ext = _extension(path);
|
|
7903
|
+
return _EXTENSION_KIND[ext] ?? { icon: lucideReact.FileIcon, typeLabel: "File" };
|
|
7918
7904
|
}
|
|
7919
|
-
function
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
...props
|
|
7923
|
-
}) {
|
|
7924
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("truncate", className), ...props, children });
|
|
7905
|
+
function _basename(path) {
|
|
7906
|
+
const idx = path.lastIndexOf("/");
|
|
7907
|
+
return idx >= 0 ? path.slice(idx + 1) : path;
|
|
7925
7908
|
}
|
|
7926
|
-
function
|
|
7909
|
+
function WorkspaceFileCard({
|
|
7910
|
+
sessionId,
|
|
7927
7911
|
path,
|
|
7928
|
-
|
|
7929
|
-
className,
|
|
7930
|
-
children,
|
|
7931
|
-
...props
|
|
7912
|
+
label
|
|
7932
7913
|
}) {
|
|
7933
|
-
const {
|
|
7934
|
-
const
|
|
7935
|
-
const
|
|
7936
|
-
const
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
const
|
|
7940
|
-
|
|
7941
|
-
}, [
|
|
7942
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
7914
|
+
const { adapter } = useAgentChatAdapterContext();
|
|
7915
|
+
const kind = _fileKindFor(path);
|
|
7916
|
+
const Icon = kind.icon;
|
|
7917
|
+
const downloadUrl = adapter.getWorkspaceDownloadUrl({ sessionId, path });
|
|
7918
|
+
const downloadName = _basename(path) || label;
|
|
7919
|
+
const [previewOpen, setPreviewOpen] = react.useState(false);
|
|
7920
|
+
const handleCardClick = react.useCallback(() => {
|
|
7921
|
+
setPreviewOpen(true);
|
|
7922
|
+
}, []);
|
|
7923
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7943
7924
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7944
7925
|
"div",
|
|
7945
7926
|
{
|
|
7927
|
+
role: "button",
|
|
7928
|
+
tabIndex: 0,
|
|
7929
|
+
onClick: handleCardClick,
|
|
7930
|
+
onKeyDown: (e) => {
|
|
7931
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7932
|
+
e.preventDefault();
|
|
7933
|
+
handleCardClick();
|
|
7934
|
+
}
|
|
7935
|
+
},
|
|
7946
7936
|
className: cn(
|
|
7947
|
-
"flex
|
|
7948
|
-
|
|
7937
|
+
"group/file flex items-center gap-3 rounded-lg border border-border",
|
|
7938
|
+
"bg-muted/20 px-3 py-2 text-left transition-colors",
|
|
7939
|
+
"cursor-pointer hover:bg-muted/40"
|
|
7949
7940
|
),
|
|
7950
7941
|
children: [
|
|
7951
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7952
|
-
|
|
7953
|
-
{
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
"aria-label": isExpanded ? `Collapse ${name}` : `Expand ${name}`,
|
|
7957
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7958
|
-
lucideReact.ChevronRightIcon,
|
|
7959
|
-
{
|
|
7960
|
-
className: cn(
|
|
7961
|
-
"size-4 shrink-0 text-muted-foreground transition-transform",
|
|
7962
|
-
isExpanded && "rotate-90"
|
|
7963
|
-
)
|
|
7964
|
-
}
|
|
7965
|
-
)
|
|
7966
|
-
}
|
|
7967
|
-
) }),
|
|
7942
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-md border border-border bg-background", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-5 text-muted-foreground", "aria-hidden": true }) }),
|
|
7943
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7944
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-medium text-foreground", children: label }),
|
|
7945
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs text-muted-foreground", children: kind.typeLabel })
|
|
7946
|
+
] }),
|
|
7968
7947
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7969
|
-
"
|
|
7948
|
+
"a",
|
|
7970
7949
|
{
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7950
|
+
href: downloadUrl,
|
|
7951
|
+
download: downloadName,
|
|
7952
|
+
onClick: (e) => e.stopPropagation(),
|
|
7953
|
+
className: cn(
|
|
7954
|
+
"shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border",
|
|
7955
|
+
"bg-background px-2.5 py-1.5 text-xs font-medium text-foreground",
|
|
7956
|
+
"transition-colors hover:bg-muted"
|
|
7957
|
+
),
|
|
7958
|
+
"aria-label": `Download ${downloadName}`,
|
|
7974
7959
|
children: [
|
|
7975
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7976
|
-
|
|
7960
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { className: "size-3.5", "aria-hidden": true }),
|
|
7961
|
+
"Download"
|
|
7977
7962
|
]
|
|
7978
7963
|
}
|
|
7979
7964
|
)
|
|
7980
7965
|
]
|
|
7981
7966
|
}
|
|
7982
7967
|
),
|
|
7983
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7984
|
-
|
|
7968
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7969
|
+
WorkspaceFilePreviewDialog,
|
|
7970
|
+
{
|
|
7971
|
+
open: previewOpen,
|
|
7972
|
+
onOpenChange: setPreviewOpen,
|
|
7973
|
+
sessionId,
|
|
7974
|
+
path,
|
|
7975
|
+
downloadUrl
|
|
7976
|
+
}
|
|
7977
|
+
)
|
|
7978
|
+
] });
|
|
7985
7979
|
}
|
|
7986
|
-
function
|
|
7980
|
+
function WorkspaceFilePreviewDialog({
|
|
7981
|
+
open,
|
|
7982
|
+
onOpenChange,
|
|
7983
|
+
sessionId,
|
|
7987
7984
|
path,
|
|
7988
|
-
|
|
7989
|
-
icon,
|
|
7990
|
-
className,
|
|
7991
|
-
children,
|
|
7992
|
-
...props
|
|
7985
|
+
downloadUrl
|
|
7993
7986
|
}) {
|
|
7994
|
-
const {
|
|
7995
|
-
const
|
|
7996
|
-
const
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
7987
|
+
const { adapter } = useAgentChatAdapterContext();
|
|
7988
|
+
const [file, setFile] = react.useState(null);
|
|
7989
|
+
const [loading, setLoading] = react.useState(false);
|
|
7990
|
+
const [error, setError] = react.useState(null);
|
|
7991
|
+
react.useEffect(() => {
|
|
7992
|
+
if (!open) return;
|
|
7993
|
+
let cancelled = false;
|
|
7994
|
+
setLoading(true);
|
|
7995
|
+
setError(null);
|
|
7996
|
+
setFile(null);
|
|
7997
|
+
adapter.getWorkspaceFile({ sessionId, path }).then((result) => {
|
|
7998
|
+
if (cancelled) return;
|
|
7999
|
+
setFile(result);
|
|
8000
|
+
setLoading(false);
|
|
8001
|
+
}).catch((err) => {
|
|
8002
|
+
if (cancelled) return;
|
|
8003
|
+
const message = err instanceof Error ? err.message : "Failed to load file";
|
|
8004
|
+
setError(message);
|
|
8005
|
+
setLoading(false);
|
|
8006
|
+
});
|
|
8007
|
+
return () => {
|
|
8008
|
+
cancelled = true;
|
|
8009
|
+
};
|
|
8010
|
+
}, [adapter, sessionId, path, open]);
|
|
8011
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "flex h-[80vh] w-full max-w-5xl flex-col gap-0 overflow-hidden p-0", children: [
|
|
8012
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { className: "border-b border-line px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "truncate text-sm", children: _basename(path) }) }),
|
|
8013
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8014
|
+
FileViewer,
|
|
8015
|
+
{
|
|
8016
|
+
file,
|
|
8017
|
+
loading,
|
|
8018
|
+
error,
|
|
8019
|
+
downloadUrl,
|
|
8020
|
+
onDelete: null,
|
|
8021
|
+
onClose: () => onOpenChange(false)
|
|
8003
8022
|
}
|
|
8004
|
-
}
|
|
8005
|
-
|
|
8006
|
-
);
|
|
8007
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8008
|
-
"div",
|
|
8009
|
-
{
|
|
8010
|
-
className: cn(
|
|
8011
|
-
"group flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50",
|
|
8012
|
-
isSelected && "bg-muted",
|
|
8013
|
-
className
|
|
8014
|
-
),
|
|
8015
|
-
onClick: handleClick,
|
|
8016
|
-
onKeyDown: handleKeyDown,
|
|
8017
|
-
role: "treeitem",
|
|
8018
|
-
tabIndex: 0,
|
|
8019
|
-
...props,
|
|
8020
|
-
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8021
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-4 shrink-0" }),
|
|
8022
|
-
/* @__PURE__ */ jsxRuntime.jsx(FileTreeIcon, { children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileIcon, { className: "size-4 text-muted-foreground" }) }),
|
|
8023
|
-
/* @__PURE__ */ jsxRuntime.jsx(FileTreeName, { children: name })
|
|
8024
|
-
] })
|
|
8025
|
-
}
|
|
8026
|
-
);
|
|
8023
|
+
) })
|
|
8024
|
+
] }) });
|
|
8027
8025
|
}
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
"
|
|
8026
|
+
function resolveArtifactRef(ref, messages) {
|
|
8027
|
+
for (const msg of messages) {
|
|
8028
|
+
if (msg.role !== "system" || msg.systemKind !== "artifact") continue;
|
|
8029
|
+
const meta = msg.systemMeta ?? {};
|
|
8030
|
+
if (meta.artifact_id !== ref) continue;
|
|
8031
|
+
const kind = meta.kind ?? "markdown";
|
|
8032
|
+
const version = typeof meta.version === "number" ? meta.version : 1;
|
|
8033
|
+
const name = typeof meta.name === "string" ? meta.name : "";
|
|
8034
|
+
return { artifactId: ref, name, kind, version };
|
|
8035
|
+
}
|
|
8036
|
+
return null;
|
|
8037
|
+
}
|
|
8038
|
+
function TurnSummaryCard({
|
|
8039
|
+
summary,
|
|
8040
|
+
sessionId,
|
|
8041
|
+
messages,
|
|
8042
|
+
onFileSelect,
|
|
8043
|
+
onCommandSelect
|
|
8044
|
+
}) {
|
|
8045
|
+
const hasRecap = summary.recap.trim().length > 0;
|
|
8046
|
+
const hasArtifacts = summary.artifacts.length > 0;
|
|
8047
|
+
if (!hasRecap && !hasArtifacts) return null;
|
|
8048
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded border border-border bg-muted/20 px-3 py-2 text-sm", children: [
|
|
8049
|
+
hasRecap && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 whitespace-pre-wrap text-foreground", children: summary.recap }),
|
|
8050
|
+
hasArtifacts && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: summary.artifacts.map((artifact, i) => {
|
|
8051
|
+
const key = `${artifact.kind}:${artifact.ref}:${i}`;
|
|
8052
|
+
if (artifact.kind === "file" && sessionId) {
|
|
8053
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8054
|
+
WorkspaceFileCard,
|
|
8055
|
+
{
|
|
8056
|
+
sessionId,
|
|
8057
|
+
path: artifact.ref,
|
|
8058
|
+
label: artifact.label
|
|
8059
|
+
},
|
|
8060
|
+
key
|
|
8061
|
+
);
|
|
8062
|
+
}
|
|
8063
|
+
if (artifact.kind === "artifact") {
|
|
8064
|
+
const resolved = sessionId ? resolveArtifactRef(artifact.ref, messages) : null;
|
|
8065
|
+
if (resolved && sessionId) {
|
|
8066
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8067
|
+
ArtifactBlock,
|
|
8068
|
+
{
|
|
8069
|
+
sessionId,
|
|
8070
|
+
artifactId: resolved.artifactId,
|
|
8071
|
+
name: resolved.name || artifact.label,
|
|
8072
|
+
kind: resolved.kind,
|
|
8073
|
+
version: resolved.version
|
|
8074
|
+
},
|
|
8075
|
+
key
|
|
8076
|
+
);
|
|
8077
|
+
}
|
|
8078
|
+
}
|
|
8079
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8080
|
+
"div",
|
|
8081
|
+
{
|
|
8082
|
+
className: "flex items-baseline gap-2 text-sm",
|
|
8083
|
+
children: [
|
|
8084
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2022" }),
|
|
8085
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8086
|
+
ArtifactRow,
|
|
8087
|
+
{
|
|
8088
|
+
artifact,
|
|
8089
|
+
sessionId,
|
|
8090
|
+
messages,
|
|
8091
|
+
onFileSelect,
|
|
8092
|
+
onCommandSelect
|
|
8093
|
+
}
|
|
8094
|
+
)
|
|
8095
|
+
]
|
|
8096
|
+
},
|
|
8097
|
+
key
|
|
8098
|
+
);
|
|
8099
|
+
}) })
|
|
8100
|
+
] });
|
|
8101
|
+
}
|
|
8102
|
+
function ArtifactRow({
|
|
8103
|
+
artifact,
|
|
8104
|
+
sessionId,
|
|
8105
|
+
messages,
|
|
8106
|
+
onFileSelect,
|
|
8107
|
+
onCommandSelect
|
|
8108
|
+
}) {
|
|
8109
|
+
if (artifact.kind === "file") {
|
|
8110
|
+
if (!onFileSelect) {
|
|
8111
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: artifact.label });
|
|
8112
|
+
}
|
|
8113
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8114
|
+
"button",
|
|
8115
|
+
{
|
|
8116
|
+
type: "button",
|
|
8117
|
+
onClick: () => onFileSelect(artifact.ref),
|
|
8118
|
+
className: "truncate cursor-pointer text-primary hover:underline",
|
|
8119
|
+
children: artifact.label
|
|
8120
|
+
}
|
|
8121
|
+
);
|
|
8122
|
+
}
|
|
8123
|
+
if (artifact.kind === "url") {
|
|
8124
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8125
|
+
"a",
|
|
8126
|
+
{
|
|
8127
|
+
href: artifact.ref,
|
|
8128
|
+
target: "_blank",
|
|
8129
|
+
rel: "noopener noreferrer",
|
|
8130
|
+
className: "truncate text-primary hover:underline",
|
|
8131
|
+
children: artifact.label
|
|
8132
|
+
}
|
|
8133
|
+
);
|
|
8134
|
+
}
|
|
8135
|
+
if (artifact.kind === "command") {
|
|
8136
|
+
if (!onCommandSelect) {
|
|
8137
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: artifact.label });
|
|
8138
|
+
}
|
|
8139
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8140
|
+
"button",
|
|
8141
|
+
{
|
|
8142
|
+
type: "button",
|
|
8143
|
+
onClick: () => onCommandSelect(artifact.ref),
|
|
8144
|
+
className: "truncate text-left cursor-pointer text-primary hover:underline",
|
|
8145
|
+
children: artifact.label
|
|
8146
|
+
}
|
|
8147
|
+
);
|
|
8148
|
+
}
|
|
8149
|
+
const resolved = sessionId ? resolveArtifactRef(artifact.ref, messages) : null;
|
|
8150
|
+
if (!resolved) {
|
|
8151
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: artifact.label });
|
|
8152
|
+
}
|
|
8153
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8154
|
+
ArtifactBlock,
|
|
8034
8155
|
{
|
|
8035
|
-
|
|
8036
|
-
|
|
8156
|
+
sessionId,
|
|
8157
|
+
artifactId: resolved.artifactId,
|
|
8158
|
+
name: resolved.name || artifact.label,
|
|
8159
|
+
kind: resolved.kind,
|
|
8160
|
+
version: resolved.version
|
|
8037
8161
|
}
|
|
8038
|
-
);
|
|
8162
|
+
) });
|
|
8039
8163
|
}
|
|
8040
8164
|
|
|
8041
|
-
// src/components/
|
|
8165
|
+
// src/components/chat/chat-thread.tsx
|
|
8042
8166
|
init_utils();
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
}
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
).
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
})
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8167
|
+
function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
8168
|
+
if (msg.role === "system") {
|
|
8169
|
+
if (msg.systemKind === "skill_invoked") {
|
|
8170
|
+
return [{
|
|
8171
|
+
kind: "skill_invoked",
|
|
8172
|
+
key: msg.id,
|
|
8173
|
+
skill: msg.systemMeta?.skill ?? msg.content,
|
|
8174
|
+
stagedAt: msg.systemMeta?.staged_at ?? null
|
|
8175
|
+
}];
|
|
8176
|
+
}
|
|
8177
|
+
if (msg.systemKind === "artifact") {
|
|
8178
|
+
const { artifactId, name, kind, version } = unpackArtifactMeta(
|
|
8179
|
+
msg.systemMeta,
|
|
8180
|
+
msg.content
|
|
8181
|
+
);
|
|
8182
|
+
return [{
|
|
8183
|
+
kind: "artifact",
|
|
8184
|
+
key: msg.id,
|
|
8185
|
+
artifactId,
|
|
8186
|
+
name,
|
|
8187
|
+
artifactKind: kind,
|
|
8188
|
+
version
|
|
8189
|
+
}];
|
|
8190
|
+
}
|
|
8191
|
+
return [];
|
|
8192
|
+
}
|
|
8193
|
+
const entries = [];
|
|
8194
|
+
const hasToolCalls = !!(msg.toolCalls && msg.toolCalls.length > 0);
|
|
8195
|
+
const hasContent = !!(msg.content && msg.content !== msg.reasoning);
|
|
8196
|
+
const isStreaming = msg.status === "streaming" && isLast;
|
|
8197
|
+
const effectiveReasoning = hasToolCalls && hasContent ? msg.reasoning ? msg.reasoning + "\n" + msg.content : msg.content : msg.reasoning;
|
|
8198
|
+
const effectiveHasContent = hasContent && !hasToolCalls;
|
|
8199
|
+
if (effectiveReasoning) {
|
|
8200
|
+
entries.push({
|
|
8201
|
+
kind: "reasoning",
|
|
8202
|
+
key: `${msg.id}-reasoning`,
|
|
8203
|
+
reasoning: effectiveReasoning,
|
|
8204
|
+
isStreaming: isStreaming && !effectiveHasContent && !hasToolCalls
|
|
8205
|
+
});
|
|
8206
|
+
}
|
|
8207
|
+
if (hasToolCalls) {
|
|
8208
|
+
for (const tc of msg.toolCalls) {
|
|
8209
|
+
if (tc.toolName === "create_artifact") {
|
|
8210
|
+
const resolvedName = parseArgs(tc.args)?.name ?? artifactFallbacks[tc.id];
|
|
8211
|
+
const status = effectiveStatus(tc);
|
|
8212
|
+
if (!resolvedName && status !== "error") continue;
|
|
8213
|
+
entries.push({
|
|
8214
|
+
kind: "tool",
|
|
8215
|
+
key: tc.id,
|
|
8216
|
+
tc,
|
|
8217
|
+
resolvedArtifactName: resolvedName
|
|
8218
|
+
});
|
|
8219
|
+
continue;
|
|
8220
|
+
}
|
|
8221
|
+
if (tc.toolName === "terminal" && tc.status !== "running") {
|
|
8222
|
+
const parsed = parseTerminalResult(tc.result, tc.args);
|
|
8223
|
+
if (parsed && (parsed.exit_code !== 0 || parsed.error)) continue;
|
|
8224
|
+
}
|
|
8225
|
+
entries.push({ kind: "tool", key: tc.id, tc });
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
8228
|
+
if (effectiveHasContent) {
|
|
8229
|
+
entries.push({
|
|
8230
|
+
kind: "text",
|
|
8231
|
+
key: `${msg.id}-text`,
|
|
8232
|
+
content: msg.content,
|
|
8233
|
+
isStreaming,
|
|
8234
|
+
msg
|
|
8235
|
+
});
|
|
8236
|
+
}
|
|
8237
|
+
const hasRunningTool = hasToolCalls && msg.toolCalls.some(
|
|
8238
|
+
(tc) => tc.status === "running"
|
|
8239
|
+
);
|
|
8240
|
+
if (isStreaming && !effectiveHasContent && !hasRunningTool) {
|
|
8241
|
+
entries.push({ kind: "thinking", key: `${msg.id}-thinking` });
|
|
8242
|
+
}
|
|
8243
|
+
return entries;
|
|
8244
|
+
}
|
|
8245
|
+
function groupBrowserActivityEntries(entries) {
|
|
8246
|
+
const grouped = [];
|
|
8247
|
+
let buffer = [];
|
|
8248
|
+
const flush = () => {
|
|
8249
|
+
if (buffer.length === 0) return;
|
|
8250
|
+
grouped.push({
|
|
8251
|
+
kind: "browser_activity",
|
|
8252
|
+
key: `browser-activity-${buffer[0]?.id}-${buffer[buffer.length - 1]?.id}`,
|
|
8253
|
+
calls: buffer
|
|
8254
|
+
});
|
|
8255
|
+
buffer = [];
|
|
8256
|
+
};
|
|
8257
|
+
for (const entry of entries) {
|
|
8258
|
+
if (entry.kind === "tool" && isBrowserToolCall(entry.tc)) {
|
|
8259
|
+
buffer.push(entry.tc);
|
|
8260
|
+
continue;
|
|
8261
|
+
}
|
|
8262
|
+
flush();
|
|
8263
|
+
grouped.push(entry);
|
|
8264
|
+
}
|
|
8265
|
+
flush();
|
|
8266
|
+
return grouped;
|
|
8267
|
+
}
|
|
8268
|
+
function isBrowserToolCall(call) {
|
|
8269
|
+
return call.toolName.startsWith("browser_");
|
|
8270
|
+
}
|
|
8271
|
+
function groupWebSearchEntries(entries) {
|
|
8272
|
+
const grouped = [];
|
|
8273
|
+
let buffer = [];
|
|
8274
|
+
const flush = () => {
|
|
8275
|
+
if (buffer.length === 0) return;
|
|
8276
|
+
if (buffer.length === 1) {
|
|
8277
|
+
grouped.push({ kind: "tool", key: buffer[0].id, tc: buffer[0] });
|
|
8278
|
+
} else {
|
|
8279
|
+
grouped.push({
|
|
8280
|
+
kind: "web_search_group",
|
|
8281
|
+
key: `web-search-${buffer[0].id}-${buffer[buffer.length - 1].id}`,
|
|
8282
|
+
calls: buffer
|
|
8283
|
+
});
|
|
8284
|
+
}
|
|
8285
|
+
buffer = [];
|
|
8286
|
+
};
|
|
8287
|
+
for (const entry of entries) {
|
|
8288
|
+
if (entry.kind === "tool" && entry.tc.toolName === "web_search") {
|
|
8289
|
+
buffer.push(entry.tc);
|
|
8290
|
+
continue;
|
|
8291
|
+
}
|
|
8292
|
+
flush();
|
|
8293
|
+
grouped.push(entry);
|
|
8294
|
+
}
|
|
8295
|
+
flush();
|
|
8296
|
+
return grouped;
|
|
8297
|
+
}
|
|
8298
|
+
function groupMessages(messages) {
|
|
8299
|
+
const groups = [];
|
|
8300
|
+
let pendingSystem = [];
|
|
8301
|
+
const drainPendingAsOrphans = () => {
|
|
8302
|
+
for (const { msg, index } of pendingSystem) {
|
|
8303
|
+
groups.push({ role: "system", messages: [msg], lastGlobalIndex: index });
|
|
8304
|
+
}
|
|
8305
|
+
pendingSystem = [];
|
|
8306
|
+
};
|
|
8307
|
+
for (let i = 0; i < messages.length; i++) {
|
|
8308
|
+
const msg = messages[i];
|
|
8309
|
+
if (msg.role === "system") {
|
|
8310
|
+
pendingSystem.push({ msg, index: i });
|
|
8311
|
+
continue;
|
|
8312
|
+
}
|
|
8313
|
+
if (msg.role === "assistant") {
|
|
8314
|
+
const prev = groups[groups.length - 1];
|
|
8315
|
+
if (prev && prev.role === "assistant" && pendingSystem.length === 0) {
|
|
8316
|
+
prev.messages.push(msg);
|
|
8317
|
+
prev.lastGlobalIndex = i;
|
|
8318
|
+
} else {
|
|
8319
|
+
const folded = pendingSystem.map((p) => p.msg);
|
|
8320
|
+
pendingSystem = [];
|
|
8321
|
+
groups.push({
|
|
8322
|
+
role: "assistant",
|
|
8323
|
+
messages: [...folded, msg],
|
|
8324
|
+
lastGlobalIndex: i
|
|
8325
|
+
});
|
|
8326
|
+
}
|
|
8327
|
+
continue;
|
|
8328
|
+
}
|
|
8329
|
+
drainPendingAsOrphans();
|
|
8330
|
+
groups.push({ role: "user", messages: [msg], lastGlobalIndex: i });
|
|
8331
|
+
}
|
|
8332
|
+
drainPendingAsOrphans();
|
|
8333
|
+
return groups;
|
|
8334
|
+
}
|
|
8335
|
+
function unpackArtifactMeta(systemMeta, fallbackName) {
|
|
8336
|
+
const meta = systemMeta ?? {};
|
|
8337
|
+
return {
|
|
8338
|
+
artifactId: meta.artifact_id ?? "",
|
|
8339
|
+
name: meta.name ?? fallbackName,
|
|
8340
|
+
kind: meta.kind ?? "markdown",
|
|
8341
|
+
version: meta.version ?? 1
|
|
8342
|
+
};
|
|
8343
|
+
}
|
|
8344
|
+
function OrphanSystemMarker({
|
|
8345
|
+
message,
|
|
8346
|
+
sessionId,
|
|
8347
|
+
onRetry
|
|
8348
|
+
}) {
|
|
8349
|
+
if (message.systemKind === "skill_invoked") {
|
|
8350
|
+
const skill = message.systemMeta?.skill ?? message.content;
|
|
8351
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 flex items-center gap-2 px-4 text-xs text-foreground/60 ", children: [
|
|
8352
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-2 rounded-full bg-emerald-500" }),
|
|
8353
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
8354
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "Skill" }),
|
|
8355
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground/60 truncate", children: skill })
|
|
8356
|
+
] })
|
|
8357
|
+
] });
|
|
8358
|
+
}
|
|
8359
|
+
if (message.systemKind === "artifact" && sessionId) {
|
|
8360
|
+
const unpacked = unpackArtifactMeta(message.systemMeta, message.content);
|
|
8361
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8362
|
+
ArtifactBlock,
|
|
8363
|
+
{
|
|
8364
|
+
sessionId,
|
|
8365
|
+
artifactId: unpacked.artifactId,
|
|
8366
|
+
name: unpacked.name,
|
|
8367
|
+
kind: unpacked.kind,
|
|
8368
|
+
version: unpacked.version
|
|
8369
|
+
}
|
|
8370
|
+
);
|
|
8371
|
+
}
|
|
8372
|
+
if (message.systemKind === "error" && message.errorInfo) {
|
|
8373
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto my-2 w-full max-w-4xl", children: /* @__PURE__ */ jsxRuntime.jsx(ErrorMessage, { errorInfo: message.errorInfo, onRetry }) });
|
|
8374
|
+
}
|
|
8375
|
+
return null;
|
|
8376
|
+
}
|
|
8377
|
+
function cancelledToolLabel(toolName) {
|
|
8378
|
+
const map = {
|
|
8379
|
+
terminal: "Command",
|
|
8380
|
+
execute_code: "Execute Code",
|
|
8381
|
+
read_file: "Read",
|
|
8382
|
+
write_file: "Write",
|
|
8383
|
+
patch: "Patch",
|
|
8384
|
+
search_files: "Search Files",
|
|
8385
|
+
list_files: "List Files",
|
|
8386
|
+
web_search: "Web Search",
|
|
8387
|
+
web_extract: "Web Fetch",
|
|
8388
|
+
web_crawl: "Web Crawl",
|
|
8389
|
+
session_search: "Session Search",
|
|
8390
|
+
memory: "Memory",
|
|
8391
|
+
todo: "Todo",
|
|
8392
|
+
skills_list: "Skills",
|
|
8393
|
+
skill_view: "Skill",
|
|
8394
|
+
consult_expert: "Expert",
|
|
8395
|
+
delegate_task: "Delegate",
|
|
8396
|
+
ask_user_question: "Ask User Question",
|
|
8397
|
+
process: "Process",
|
|
8398
|
+
create_artifact: "Artifact"
|
|
8399
|
+
};
|
|
8400
|
+
return map[toolName] ?? toolName;
|
|
8401
|
+
}
|
|
8402
|
+
function CancelledToolRow({ tc }) {
|
|
8403
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
|
|
8404
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground/60", children: cancelledToolLabel(tc.toolName) }),
|
|
8405
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground/60/70", children: "Cancelled" })
|
|
8406
|
+
] });
|
|
8407
|
+
}
|
|
8408
|
+
function TimelineEntryItem({
|
|
8409
|
+
entry,
|
|
8410
|
+
step,
|
|
8411
|
+
sessionId,
|
|
8412
|
+
onFileSelect
|
|
8413
|
+
}) {
|
|
8414
|
+
if (entry.kind === "reasoning") {
|
|
8415
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ReasoningEntry, { entry, step });
|
|
8416
|
+
}
|
|
8417
|
+
if (entry.kind === "tool") {
|
|
8418
|
+
const rawStatus = effectiveStatus(entry.tc);
|
|
8419
|
+
const hideArtifactFailure = rawStatus === "error" && entry.tc.toolName === "create_artifact";
|
|
8420
|
+
const indicatorStatus = hideArtifactFailure ? "running" : rawStatus;
|
|
8421
|
+
const failureSummary = rawStatus === "error" && !hideArtifactFailure ? toolErrorSummary(entry.tc.result) : "";
|
|
8422
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8423
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8424
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8425
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8426
|
+
TimelineIndicator,
|
|
8427
|
+
{
|
|
8428
|
+
className: cn("size-2 border-none", statusColorClass(indicatorStatus))
|
|
8429
|
+
}
|
|
8430
|
+
)
|
|
8431
|
+
] }),
|
|
8432
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: entry.tc.cancelled ? /* @__PURE__ */ jsxRuntime.jsx(CancelledToolRow, { tc: entry.tc }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
8433
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8434
|
+
ToolCallBlock,
|
|
8435
|
+
{
|
|
8436
|
+
tc: entry.tc,
|
|
8437
|
+
resolvedArtifactName: entry.resolvedArtifactName,
|
|
8438
|
+
onFileSelect
|
|
8439
|
+
}
|
|
8440
|
+
),
|
|
8441
|
+
failureSummary ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-full truncate text-xs text-destructive", title: failureSummary, children: failureSummary }) : null
|
|
8442
|
+
] }) })
|
|
8443
|
+
] });
|
|
8444
|
+
}
|
|
8445
|
+
if (entry.kind === "browser_activity") {
|
|
8446
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8447
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8448
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8449
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-amber-500" })
|
|
8450
|
+
] }),
|
|
8451
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(BrowserActivityGroup, { calls: entry.calls }) })
|
|
8452
|
+
] });
|
|
8453
|
+
}
|
|
8454
|
+
if (entry.kind === "web_search_group") {
|
|
8455
|
+
const allComplete = entry.calls.every((tc) => tc.status === "complete");
|
|
8456
|
+
const anyRunning = entry.calls.some((tc) => tc.status === "running");
|
|
8457
|
+
const indicatorClass = anyRunning ? "bg-emerald-500 animate-pulse" : allComplete ? "bg-emerald-500" : "bg-red-500";
|
|
8458
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8459
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8460
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8461
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: cn("size-2 border-none", indicatorClass) })
|
|
8462
|
+
] }),
|
|
8463
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(WebSearchGroupBlock, { tcs: entry.calls }) })
|
|
8464
|
+
] });
|
|
8465
|
+
}
|
|
8466
|
+
if (entry.kind === "text") {
|
|
8467
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextEntry, { entry, step });
|
|
8468
|
+
}
|
|
8469
|
+
if (entry.kind === "skill_invoked") {
|
|
8470
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8471
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8472
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8473
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-emerald-500" })
|
|
8474
|
+
] }),
|
|
8475
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 py-1 text-sm ", children: [
|
|
8476
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "Skill" }),
|
|
8477
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground/60 truncate", children: entry.skill }),
|
|
8478
|
+
entry.stagedAt && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-foreground/60/70 ", children: [
|
|
8479
|
+
"staged at ",
|
|
8480
|
+
entry.stagedAt
|
|
8113
8481
|
] })
|
|
8482
|
+
] }) })
|
|
8483
|
+
] });
|
|
8484
|
+
}
|
|
8485
|
+
if (entry.kind === "artifact") {
|
|
8486
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8487
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8488
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8489
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-sky-500" })
|
|
8114
8490
|
] }),
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
{
|
|
8118
|
-
href: downloadUrl,
|
|
8119
|
-
download: fileName2,
|
|
8120
|
-
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
8121
|
-
"aria-label": `Download ${fileName2}`,
|
|
8122
|
-
title: "Download",
|
|
8123
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { className: "size-3.5" })
|
|
8124
|
-
}
|
|
8125
|
-
),
|
|
8126
|
-
onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8127
|
-
"button",
|
|
8128
|
-
{
|
|
8129
|
-
type: "button",
|
|
8130
|
-
onClick: onDelete,
|
|
8131
|
-
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
|
|
8132
|
-
"aria-label": `Delete ${fileName2}`,
|
|
8133
|
-
title: "Delete",
|
|
8134
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrashIcon, { className: "size-3.5" })
|
|
8135
|
-
}
|
|
8136
|
-
),
|
|
8137
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8138
|
-
"button",
|
|
8491
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: sessionId ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8492
|
+
ArtifactBlock,
|
|
8139
8493
|
{
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8494
|
+
sessionId,
|
|
8495
|
+
artifactId: entry.artifactId,
|
|
8496
|
+
name: entry.name,
|
|
8497
|
+
kind: entry.artifactKind,
|
|
8498
|
+
version: entry.version
|
|
8145
8499
|
}
|
|
8146
|
-
)
|
|
8500
|
+
) : null })
|
|
8501
|
+
] });
|
|
8502
|
+
}
|
|
8503
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8504
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8505
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8506
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-primary animate-pulse" })
|
|
8147
8507
|
] }),
|
|
8148
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
)
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8508
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) })
|
|
8509
|
+
] });
|
|
8510
|
+
}
|
|
8511
|
+
function ReasoningEntry({
|
|
8512
|
+
entry,
|
|
8513
|
+
step
|
|
8514
|
+
}) {
|
|
8515
|
+
const reasoning = useSmoothStream(entry.reasoning, entry.isStreaming);
|
|
8516
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8517
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8518
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8519
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2" })
|
|
8520
|
+
] }),
|
|
8521
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(Reasoning, { isStreaming: entry.isStreaming, children: [
|
|
8522
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReasoningTrigger, {}),
|
|
8523
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReasoningContent, { children: reasoning })
|
|
8524
|
+
] }) })
|
|
8525
|
+
] });
|
|
8526
|
+
}
|
|
8527
|
+
function TextEntry({
|
|
8528
|
+
entry,
|
|
8529
|
+
step
|
|
8530
|
+
}) {
|
|
8531
|
+
const content = useSmoothStream(entry.content, entry.isStreaming);
|
|
8532
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
8533
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
8534
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8535
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
|
|
8536
|
+
] }),
|
|
8537
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineContent, { children: [
|
|
8538
|
+
/* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: content }),
|
|
8539
|
+
entry.isFinalTurnText && entry.msg.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnFeedback, { msg: entry.msg })
|
|
8174
8540
|
] })
|
|
8175
8541
|
] });
|
|
8176
8542
|
}
|
|
8177
|
-
function
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8543
|
+
function deriveIterationLabel(message) {
|
|
8544
|
+
const calls = visibleToolCalls(message);
|
|
8545
|
+
if (calls.length === 0) {
|
|
8546
|
+
return message.reasoning ? "Thought through the problem" : null;
|
|
8547
|
+
}
|
|
8548
|
+
if (calls.length === 1) {
|
|
8549
|
+
const tc = calls[0];
|
|
8550
|
+
return deriveSingleToolLabel(tc);
|
|
8551
|
+
}
|
|
8552
|
+
const firstName = calls[0].toolName;
|
|
8553
|
+
const allSame = calls.every((tc) => tc.toolName === firstName);
|
|
8554
|
+
if (allSame) {
|
|
8555
|
+
const human = cancelledToolLabel(firstName);
|
|
8556
|
+
return `${human} \xD7 ${calls.length}`;
|
|
8557
|
+
}
|
|
8558
|
+
return `Used ${calls.length} tools`;
|
|
8559
|
+
}
|
|
8560
|
+
function deriveSingleToolLabel(tc) {
|
|
8561
|
+
const name = cancelledToolLabel(tc.toolName);
|
|
8562
|
+
if (_HEADER_HIDES_DETAIL.has(tc.toolName)) {
|
|
8563
|
+
return _HEADER_GENERIC_VERB[tc.toolName] ?? name;
|
|
8564
|
+
}
|
|
8565
|
+
const detail = extractToolDetail(tc);
|
|
8566
|
+
return detail ? `${name} \xB7 ${detail}` : name;
|
|
8567
|
+
}
|
|
8568
|
+
var _HEADER_HIDES_DETAIL = /* @__PURE__ */ new Set([
|
|
8569
|
+
"terminal",
|
|
8570
|
+
"execute_code",
|
|
8571
|
+
"memory"
|
|
8572
|
+
]);
|
|
8573
|
+
var _HEADER_GENERIC_VERB = {
|
|
8574
|
+
terminal: "Ran a command",
|
|
8575
|
+
execute_code: "Executed code",
|
|
8576
|
+
memory: "Updated memory"
|
|
8577
|
+
};
|
|
8578
|
+
function extractToolDetail(tc) {
|
|
8579
|
+
const args = parseArgs(tc.args);
|
|
8580
|
+
if (!args) return null;
|
|
8581
|
+
const stringArg = (key) => {
|
|
8582
|
+
const v = args[key];
|
|
8583
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
8584
|
+
};
|
|
8585
|
+
switch (tc.toolName) {
|
|
8586
|
+
case "read_file":
|
|
8587
|
+
case "write_file":
|
|
8588
|
+
case "patch":
|
|
8589
|
+
case "list_files":
|
|
8590
|
+
case "search_files": {
|
|
8591
|
+
const path = stringArg("path") ?? stringArg("file_path");
|
|
8592
|
+
return path ? lastPathSegment(path) : null;
|
|
8593
|
+
}
|
|
8594
|
+
case "terminal": {
|
|
8595
|
+
const cmd = stringArg("command");
|
|
8596
|
+
return cmd ? truncate2(cmd, 40) : null;
|
|
8597
|
+
}
|
|
8598
|
+
case "execute_code": {
|
|
8599
|
+
const code3 = stringArg("code");
|
|
8600
|
+
return code3 ? truncate2(code3.split("\n")[0] ?? "", 40) : null;
|
|
8601
|
+
}
|
|
8602
|
+
case "web_search":
|
|
8603
|
+
case "web_crawl":
|
|
8604
|
+
return stringArg("query");
|
|
8605
|
+
case "web_extract":
|
|
8606
|
+
return stringArg("url");
|
|
8607
|
+
case "skill_view":
|
|
8608
|
+
case "skill_manage":
|
|
8609
|
+
return stringArg("name") ?? stringArg("skill");
|
|
8610
|
+
case "create_artifact":
|
|
8611
|
+
case "consult_expert":
|
|
8612
|
+
case "delegate_task":
|
|
8613
|
+
return stringArg("name") ?? stringArg("task") ?? stringArg("title");
|
|
8614
|
+
case "memory":
|
|
8615
|
+
return stringArg("action") ?? stringArg("key");
|
|
8616
|
+
default:
|
|
8617
|
+
return null;
|
|
8618
|
+
}
|
|
8619
|
+
}
|
|
8620
|
+
function lastPathSegment(path) {
|
|
8621
|
+
const cleaned = path.replace(/\/+$/, "");
|
|
8622
|
+
const idx = cleaned.lastIndexOf("/");
|
|
8623
|
+
return idx >= 0 ? cleaned.slice(idx + 1) : cleaned;
|
|
8624
|
+
}
|
|
8625
|
+
function truncate2(s, max) {
|
|
8626
|
+
return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
8627
|
+
}
|
|
8628
|
+
var _SIMPLE_MODE_HIDDEN_TOOLS = /* @__PURE__ */ new Set([
|
|
8629
|
+
"list_files",
|
|
8630
|
+
"search_files",
|
|
8631
|
+
"session_search",
|
|
8632
|
+
"skills_list",
|
|
8633
|
+
"process",
|
|
8634
|
+
"memory",
|
|
8635
|
+
// Shell commands and code execution are infrastructure plumbing the
|
|
8636
|
+
// user doesn't need to see when the goal is to know *what* the
|
|
8637
|
+
// agent accomplished, not *how*. Expert mode still has the full
|
|
8638
|
+
// command + output block.
|
|
8639
|
+
"terminal",
|
|
8640
|
+
"execute_code"
|
|
8641
|
+
]);
|
|
8642
|
+
function _isHiddenSimpleTool(tc) {
|
|
8643
|
+
if (_SIMPLE_MODE_HIDDEN_TOOLS.has(tc.toolName)) return true;
|
|
8644
|
+
if (tc.toolName.startsWith("browser_")) return true;
|
|
8645
|
+
return false;
|
|
8646
|
+
}
|
|
8647
|
+
function visibleToolCalls(message) {
|
|
8648
|
+
return (message.toolCalls ?? []).filter((tc) => {
|
|
8649
|
+
if (_isHiddenSimpleTool(tc)) return false;
|
|
8650
|
+
const status = effectiveStatus(tc);
|
|
8651
|
+
if (status === "error" || status === "cancelled") return false;
|
|
8652
|
+
return true;
|
|
8653
|
+
});
|
|
8654
|
+
}
|
|
8655
|
+
function isIterationLive(message) {
|
|
8656
|
+
const calls = message.toolCalls ?? [];
|
|
8657
|
+
if (calls.length > 0) {
|
|
8658
|
+
return calls.some((tc) => tc.status === "running");
|
|
8659
|
+
}
|
|
8660
|
+
return message.status === "streaming";
|
|
8661
|
+
}
|
|
8662
|
+
function liveIterationLabel(message) {
|
|
8663
|
+
const running = (message.toolCalls ?? []).filter(
|
|
8664
|
+
(tc) => tc.status === "running" && !_isHiddenSimpleTool(tc)
|
|
8665
|
+
);
|
|
8666
|
+
if (running.length === 0) return "Thinking\u2026";
|
|
8667
|
+
if (running.length === 1) {
|
|
8668
|
+
const tc = running[0];
|
|
8669
|
+
const name = cancelledToolLabel(tc.toolName);
|
|
8670
|
+
const detail = extractToolDetail(tc);
|
|
8671
|
+
return detail ? `Running ${name} \xB7 ${detail}\u2026` : `Running ${name}\u2026`;
|
|
8672
|
+
}
|
|
8673
|
+
const firstName = running[0].toolName;
|
|
8674
|
+
const allSame = running.every((tc) => tc.toolName === firstName);
|
|
8675
|
+
if (allSame) {
|
|
8676
|
+
return `Running ${cancelledToolLabel(firstName)} \xD7 ${running.length}\u2026`;
|
|
8677
|
+
}
|
|
8678
|
+
return `Running ${running.length} tools\u2026`;
|
|
8679
|
+
}
|
|
8680
|
+
var _TOOL_ROW_ICON = {
|
|
8681
|
+
read_file: lucideReact.FileTextIcon,
|
|
8682
|
+
write_file: lucideReact.FileTextIcon,
|
|
8683
|
+
patch: lucideReact.FileEditIcon,
|
|
8684
|
+
list_files: lucideReact.ListIcon,
|
|
8685
|
+
search_files: lucideReact.SearchIcon,
|
|
8686
|
+
terminal: lucideReact.TerminalIcon,
|
|
8687
|
+
execute_code: lucideReact.TerminalIcon,
|
|
8688
|
+
web_search: lucideReact.GlobeIcon,
|
|
8689
|
+
web_extract: lucideReact.GlobeIcon,
|
|
8690
|
+
web_crawl: lucideReact.GlobeIcon,
|
|
8691
|
+
session_search: lucideReact.SearchIcon,
|
|
8692
|
+
skill_view: lucideReact.BookOpenIcon,
|
|
8693
|
+
skills_list: lucideReact.BookOpenIcon,
|
|
8694
|
+
skill_manage: lucideReact.PenLineIcon,
|
|
8695
|
+
consult_expert: lucideReact.SparklesIcon,
|
|
8696
|
+
delegate_task: lucideReact.ArrowRight,
|
|
8697
|
+
create_artifact: lucideReact.FileTextIcon,
|
|
8698
|
+
memory: lucideReact.PenLineIcon,
|
|
8699
|
+
todo: lucideReact.ListIcon
|
|
8700
|
+
};
|
|
8701
|
+
function _toolRowIcon(toolName) {
|
|
8702
|
+
return _TOOL_ROW_ICON[toolName] ?? lucideReact.WrenchIcon;
|
|
8703
|
+
}
|
|
8704
|
+
function _toolRowLabel(tc) {
|
|
8705
|
+
const detail = extractToolDetail(tc);
|
|
8706
|
+
switch (tc.toolName) {
|
|
8707
|
+
case "read_file":
|
|
8708
|
+
return detail ? `Read ${detail}` : "Read a file";
|
|
8709
|
+
case "write_file":
|
|
8710
|
+
return detail ? `Wrote ${detail}` : "Wrote a file";
|
|
8711
|
+
case "patch":
|
|
8712
|
+
return detail ? `Edited ${detail}` : "Edited a file";
|
|
8713
|
+
case "list_files":
|
|
8714
|
+
return detail ? `Listed ${detail}` : "Listed files";
|
|
8715
|
+
case "search_files":
|
|
8716
|
+
return detail ? `Searched files for "${detail}"` : "Searched files";
|
|
8717
|
+
case "terminal":
|
|
8718
|
+
return "Ran a command";
|
|
8719
|
+
case "execute_code":
|
|
8720
|
+
return "Executed code";
|
|
8721
|
+
case "web_search":
|
|
8722
|
+
return detail ? `Searched the web for "${detail}"` : "Searched the web";
|
|
8723
|
+
case "web_crawl":
|
|
8724
|
+
return detail ? `Crawled "${detail}"` : "Crawled the web";
|
|
8725
|
+
case "web_extract":
|
|
8726
|
+
return detail ? `Fetched ${detail}` : "Fetched a page";
|
|
8727
|
+
case "session_search":
|
|
8728
|
+
return detail ? `Searched session for "${detail}"` : "Searched session";
|
|
8729
|
+
case "skill_view":
|
|
8730
|
+
return detail ? `Read the ${detail} skill` : "Read a skill";
|
|
8731
|
+
case "skills_list":
|
|
8732
|
+
return "Listed available skills";
|
|
8733
|
+
case "skill_manage":
|
|
8734
|
+
return detail ? `Updated skill ${detail}` : "Managed skills";
|
|
8735
|
+
case "consult_expert":
|
|
8736
|
+
return detail ? `Consulted ${detail} expert` : "Consulted an expert";
|
|
8737
|
+
case "delegate_task":
|
|
8738
|
+
return detail ? `Delegated: ${detail}` : "Delegated a task";
|
|
8739
|
+
case "create_artifact":
|
|
8740
|
+
return detail ? `Created artifact "${detail}"` : "Created an artifact";
|
|
8741
|
+
case "memory":
|
|
8742
|
+
return detail ? `Memory ${detail}` : "Updated memory";
|
|
8743
|
+
case "todo":
|
|
8744
|
+
return detail ? `Todo ${detail}` : "Updated todo list";
|
|
8745
|
+
default:
|
|
8746
|
+
return cancelledToolLabel(tc.toolName);
|
|
8747
|
+
}
|
|
8748
|
+
}
|
|
8749
|
+
function SimpleDetailRow({ icon: Icon, children }) {
|
|
8750
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 text-sm", children: [
|
|
8751
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8752
|
+
Icon,
|
|
8753
|
+
{
|
|
8754
|
+
className: "mt-0.5 size-4 shrink-0 text-foreground/60",
|
|
8755
|
+
"aria-hidden": true
|
|
8756
|
+
}
|
|
8757
|
+
),
|
|
8758
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1 leading-relaxed text-foreground/60", children })
|
|
8759
|
+
] });
|
|
8760
|
+
}
|
|
8761
|
+
function ClampedReasoning({
|
|
8762
|
+
text,
|
|
8763
|
+
previewParagraphs = 2
|
|
8764
|
+
}) {
|
|
8765
|
+
const paragraphs = splitReasoningParagraphs(text);
|
|
8766
|
+
const [expanded, setExpanded] = react.useState(false);
|
|
8767
|
+
const hasMore = paragraphs.length > previewParagraphs;
|
|
8768
|
+
const visible = expanded || !hasMore ? paragraphs : paragraphs.slice(0, previewParagraphs);
|
|
8769
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
8770
|
+
visible.map((paragraph, i) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap", children: paragraph }, i)),
|
|
8771
|
+
hasMore && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8772
|
+
"button",
|
|
8773
|
+
{
|
|
8774
|
+
type: "button",
|
|
8775
|
+
onClick: () => setExpanded((prev) => !prev),
|
|
8776
|
+
className: "text-xs font-medium text-foreground hover:text-foreground/70 cursor-pointer",
|
|
8777
|
+
children: expanded ? "Show less" : "Show more..."
|
|
8778
|
+
}
|
|
8779
|
+
)
|
|
8780
|
+
] });
|
|
8781
|
+
}
|
|
8782
|
+
function splitReasoningParagraphs(text) {
|
|
8783
|
+
const trimmed = text.trim();
|
|
8784
|
+
if (!trimmed) return [];
|
|
8785
|
+
const blankSplit = trimmed.split(/\n\s*\n+/).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
8786
|
+
if (blankSplit.length > 1) return blankSplit;
|
|
8787
|
+
return trimmed.split(/\n+/).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
8788
|
+
}
|
|
8789
|
+
function IterationExpanded({
|
|
8790
|
+
message
|
|
8791
|
+
}) {
|
|
8792
|
+
const calls = visibleToolCalls(message);
|
|
8793
|
+
const reasoning = (message.reasoning ?? "").trim();
|
|
8794
|
+
const anyVisibleRunning = calls.some((tc) => tc.status === "running");
|
|
8795
|
+
const showDone = !anyVisibleRunning && (calls.length > 0 || !!reasoning);
|
|
8796
|
+
if (!reasoning && calls.length === 0) return null;
|
|
8797
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-2 space-y-3 border-l border-border/40 pl-4 py-1", children: [
|
|
8798
|
+
reasoning && /* @__PURE__ */ jsxRuntime.jsx(SimpleDetailRow, { icon: lucideReact.ClockIcon, children: /* @__PURE__ */ jsxRuntime.jsx(ClampedReasoning, { text: reasoning }) }),
|
|
8799
|
+
calls.map((tc) => {
|
|
8800
|
+
if (tc.toolName === "todo") {
|
|
8801
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-1", children: /* @__PURE__ */ jsxRuntime.jsx(TodoToolBlock, { tc }) }, tc.id);
|
|
8802
|
+
}
|
|
8803
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SimpleDetailRow, { icon: _toolRowIcon(tc.toolName), children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: _toolRowLabel(tc) }) }, tc.id);
|
|
8804
|
+
}),
|
|
8805
|
+
showDone && /* @__PURE__ */ jsxRuntime.jsx(SimpleDetailRow, { icon: lucideReact.CircleCheckIcon, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: "Done" }) })
|
|
8806
|
+
] });
|
|
8807
|
+
}
|
|
8808
|
+
function IterationGroup({
|
|
8809
|
+
message,
|
|
8810
|
+
sessionId,
|
|
8811
|
+
artifactFallbacks,
|
|
8812
|
+
onFileSelect
|
|
8813
|
+
}) {
|
|
8814
|
+
const summary = message.iterationSummary?.summary;
|
|
8815
|
+
const [open, setOpen] = react.useState(false);
|
|
8816
|
+
if (isIterationLive(message)) {
|
|
8817
|
+
const askCall = (message.toolCalls ?? []).find(
|
|
8818
|
+
(tc) => tc.toolName === "ask_user_question" && tc.status === "running"
|
|
8819
|
+
);
|
|
8820
|
+
if (askCall) {
|
|
8821
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1 py-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(AskUserQuestionToolBlock, { tc: askCall }) });
|
|
8822
|
+
}
|
|
8823
|
+
const label2 = liveIterationLabel(message);
|
|
8824
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1 py-0.5 text-sm", children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: label2 }) });
|
|
8825
|
+
}
|
|
8826
|
+
const label = summary ?? deriveIterationLabel(message);
|
|
8827
|
+
if (!label) {
|
|
8828
|
+
return null;
|
|
8829
|
+
}
|
|
8830
|
+
const labelTone = summary ? "text-foreground/80" : "text-foreground/50";
|
|
8831
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
8832
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8833
|
+
"button",
|
|
8834
|
+
{
|
|
8835
|
+
type: "button",
|
|
8836
|
+
onClick: () => setOpen((prev) => !prev),
|
|
8837
|
+
"aria-expanded": open,
|
|
8838
|
+
className: "flex w-full items-center gap-2 rounded px-1 py-0.5 text-left text-sm hover:bg-muted/40",
|
|
8839
|
+
children: [
|
|
8840
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-1 truncate", labelTone), children: label }),
|
|
8841
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8842
|
+
lucideReact.ChevronDown,
|
|
8843
|
+
{
|
|
8844
|
+
className: cn(
|
|
8845
|
+
"size-3 shrink-0 text-foreground/60 transition-transform",
|
|
8846
|
+
open && "rotate-180"
|
|
8847
|
+
),
|
|
8848
|
+
"aria-hidden": true
|
|
8849
|
+
}
|
|
8850
|
+
)
|
|
8851
|
+
]
|
|
8852
|
+
}
|
|
8853
|
+
),
|
|
8854
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8855
|
+
IterationExpanded,
|
|
8856
|
+
{
|
|
8857
|
+
message,
|
|
8858
|
+
sessionId,
|
|
8859
|
+
artifactFallbacks,
|
|
8860
|
+
onFileSelect
|
|
8861
|
+
}
|
|
8862
|
+
)
|
|
8181
8863
|
] });
|
|
8182
8864
|
}
|
|
8183
|
-
function
|
|
8184
|
-
|
|
8185
|
-
|
|
8865
|
+
function deriveFileArtifactsFromMessages(messages) {
|
|
8866
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8867
|
+
const out = [];
|
|
8868
|
+
for (const msg of messages) {
|
|
8869
|
+
if (msg.role !== "assistant" || !msg.toolCalls) continue;
|
|
8870
|
+
for (const tc of msg.toolCalls) {
|
|
8871
|
+
const status = effectiveStatus(tc);
|
|
8872
|
+
if (status === "error" || status === "cancelled") continue;
|
|
8873
|
+
const args = parseArgs(tc.args);
|
|
8874
|
+
if (!args) continue;
|
|
8875
|
+
if (tc.toolName === "write_file" || tc.toolName === "patch") {
|
|
8876
|
+
const path = typeof args.path === "string" ? args.path : typeof args.file_path === "string" ? args.file_path : "";
|
|
8877
|
+
if (!path || seen.has(`file:${path}`)) continue;
|
|
8878
|
+
seen.add(`file:${path}`);
|
|
8879
|
+
out.push({
|
|
8880
|
+
kind: "file",
|
|
8881
|
+
label: path.split("/").pop() || path,
|
|
8882
|
+
ref: path
|
|
8883
|
+
});
|
|
8884
|
+
continue;
|
|
8885
|
+
}
|
|
8886
|
+
if (tc.toolName === "create_artifact") {
|
|
8887
|
+
const name = typeof args.name === "string" ? args.name : "";
|
|
8888
|
+
if (!name || seen.has(`artifact:${name}`)) continue;
|
|
8889
|
+
seen.add(`artifact:${name}`);
|
|
8890
|
+
out.push({
|
|
8891
|
+
kind: "artifact",
|
|
8892
|
+
label: name,
|
|
8893
|
+
ref: name
|
|
8894
|
+
});
|
|
8895
|
+
}
|
|
8896
|
+
}
|
|
8897
|
+
}
|
|
8898
|
+
return out;
|
|
8899
|
+
}
|
|
8900
|
+
function SimpleAssistantGroup({
|
|
8901
|
+
messages,
|
|
8902
|
+
lastGlobalIndex,
|
|
8903
|
+
totalMessages,
|
|
8904
|
+
isRunning,
|
|
8905
|
+
sessionId,
|
|
8906
|
+
artifactFallbacks,
|
|
8907
|
+
onFileSelect,
|
|
8908
|
+
onRetry
|
|
8909
|
+
}) {
|
|
8910
|
+
const assistantMessages = messages.filter((m) => m.role === "assistant");
|
|
8911
|
+
const tail = assistantMessages[assistantMessages.length - 1];
|
|
8912
|
+
const tailHasTools = !!(tail?.toolCalls && tail.toolCalls.length > 0);
|
|
8913
|
+
const tailIsTextOnly = !!tail && !tailHasTools;
|
|
8914
|
+
const finalText = tailIsTextOnly && tail.content ? tail.content : "";
|
|
8915
|
+
const isTailGroup = lastGlobalIndex === totalMessages - 1;
|
|
8916
|
+
const showThinkingShim = isTailGroup && isRunning && (!tail && messages.some((m) => m.role !== "assistant") || tailIsTextOnly && tail.status === "streaming" && !tail.content);
|
|
8917
|
+
const showErrorInfo = !!tail && tail.status === "error" && !!tail.errorInfo;
|
|
8918
|
+
const effectiveTurnSummary = (() => {
|
|
8919
|
+
const fromHarness = tail?.turnSummary;
|
|
8920
|
+
if (fromHarness && fromHarness.artifacts.length > 0) {
|
|
8921
|
+
return fromHarness;
|
|
8922
|
+
}
|
|
8923
|
+
const derived = deriveFileArtifactsFromMessages(messages);
|
|
8924
|
+
if (derived.length === 0) return fromHarness;
|
|
8925
|
+
return {
|
|
8926
|
+
turnId: fromHarness?.turnId ?? "",
|
|
8927
|
+
recap: fromHarness?.recap ?? "",
|
|
8928
|
+
artifacts: derived
|
|
8929
|
+
};
|
|
8930
|
+
})();
|
|
8931
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsxs(MessageContent, { children: [
|
|
8932
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
8933
|
+
messages.map((message) => {
|
|
8934
|
+
if (message.role === "system") {
|
|
8935
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8936
|
+
OrphanSystemMarker,
|
|
8937
|
+
{
|
|
8938
|
+
message,
|
|
8939
|
+
sessionId,
|
|
8940
|
+
onRetry: void 0
|
|
8941
|
+
},
|
|
8942
|
+
message.id
|
|
8943
|
+
);
|
|
8944
|
+
}
|
|
8945
|
+
if (message === tail && tailIsTextOnly) return null;
|
|
8946
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8947
|
+
IterationGroup,
|
|
8948
|
+
{
|
|
8949
|
+
message,
|
|
8950
|
+
sessionId,
|
|
8951
|
+
artifactFallbacks,
|
|
8952
|
+
onFileSelect
|
|
8953
|
+
},
|
|
8954
|
+
message.id
|
|
8955
|
+
);
|
|
8956
|
+
}),
|
|
8957
|
+
showThinkingShim && /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." })
|
|
8958
|
+
] }),
|
|
8959
|
+
finalText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3", children: [
|
|
8960
|
+
/* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: finalText }),
|
|
8961
|
+
tail?.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnFeedback, { msg: tail })
|
|
8962
|
+
] }),
|
|
8963
|
+
effectiveTurnSummary && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8964
|
+
TurnSummaryCard,
|
|
8965
|
+
{
|
|
8966
|
+
summary: effectiveTurnSummary,
|
|
8967
|
+
sessionId,
|
|
8968
|
+
messages,
|
|
8969
|
+
onFileSelect
|
|
8970
|
+
}
|
|
8971
|
+
),
|
|
8972
|
+
showErrorInfo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsx(ErrorMessage, { errorInfo: tail.errorInfo, onRetry }) })
|
|
8973
|
+
] }) });
|
|
8974
|
+
}
|
|
8975
|
+
function AssistantGroup({
|
|
8976
|
+
messages,
|
|
8977
|
+
lastGlobalIndex,
|
|
8978
|
+
totalMessages,
|
|
8979
|
+
isRunning,
|
|
8980
|
+
sessionId,
|
|
8981
|
+
artifactFallbacks,
|
|
8982
|
+
onFileSelect,
|
|
8983
|
+
onRetry,
|
|
8984
|
+
viewMode = "simple"
|
|
8186
8985
|
}) {
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
let loadingTask = null;
|
|
8200
|
-
let pdfDocument = null;
|
|
8201
|
-
const renderPdf = async () => {
|
|
8202
|
-
setError(null);
|
|
8203
|
-
const container = containerRef.current;
|
|
8204
|
-
const viewerElement = viewerRef.current;
|
|
8205
|
-
if (!container || !viewerElement) return;
|
|
8206
|
-
const pdfBytes = decodeBase64(file.content);
|
|
8207
|
-
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
8208
|
-
pdfjs.GlobalWorkerOptions.workerSrc = PDF_WORKER_SRC;
|
|
8209
|
-
globalThis.pdfjsLib = pdfjs;
|
|
8210
|
-
const pdfViewerModule = await import('pdfjs-dist/web/pdf_viewer.mjs');
|
|
8211
|
-
loadingTask = pdfjs.getDocument({ data: pdfBytes });
|
|
8212
|
-
const pdf = await loadingTask.promise;
|
|
8213
|
-
pdfDocument = pdf;
|
|
8214
|
-
if (cancelled) return;
|
|
8215
|
-
const eventBus = new pdfViewerModule.EventBus();
|
|
8216
|
-
const linkService = new pdfViewerModule.PDFLinkService({ eventBus });
|
|
8217
|
-
const findController = new pdfViewerModule.PDFFindController({
|
|
8218
|
-
eventBus,
|
|
8219
|
-
linkService
|
|
8220
|
-
});
|
|
8221
|
-
const pdfViewer = new pdfViewerModule.PDFViewer({
|
|
8222
|
-
container,
|
|
8223
|
-
viewer: viewerElement,
|
|
8224
|
-
eventBus,
|
|
8225
|
-
linkService,
|
|
8226
|
-
findController,
|
|
8227
|
-
removePageBorders: true
|
|
8228
|
-
});
|
|
8229
|
-
linkService.setViewer(pdfViewer);
|
|
8230
|
-
linkService.setDocument(pdf);
|
|
8231
|
-
findController.setDocument(pdf);
|
|
8232
|
-
const onPagesInit = () => {
|
|
8233
|
-
pdfViewer.currentScaleValue = "page-width";
|
|
8234
|
-
setScale(pdfViewer.currentScale || 1);
|
|
8235
|
-
setPagesCount(pdfViewer.pagesCount);
|
|
8236
|
-
setPageNumber(pdfViewer.currentPageNumber);
|
|
8237
|
-
};
|
|
8238
|
-
const onPageChanging = (event) => {
|
|
8239
|
-
if (typeof event.pageNumber === "number") {
|
|
8240
|
-
setPageNumber(event.pageNumber);
|
|
8241
|
-
}
|
|
8242
|
-
};
|
|
8243
|
-
const onScaleChanging = (event) => {
|
|
8244
|
-
if (typeof event.scale === "number") {
|
|
8245
|
-
setScale(event.scale);
|
|
8246
|
-
}
|
|
8247
|
-
};
|
|
8248
|
-
eventBus.on("pagesinit", onPagesInit);
|
|
8249
|
-
eventBus.on("pagechanging", onPageChanging);
|
|
8250
|
-
eventBus.on("scalechanging", onScaleChanging);
|
|
8251
|
-
pdfViewerRef.current = pdfViewer;
|
|
8252
|
-
eventBusRef.current = eventBus;
|
|
8253
|
-
findControllerRef.current = findController;
|
|
8254
|
-
setPagesCount(pdf.numPages);
|
|
8255
|
-
pdfViewer.setDocument(pdf);
|
|
8256
|
-
};
|
|
8257
|
-
void renderPdf().catch((nextError) => {
|
|
8258
|
-
if (cancelled) return;
|
|
8259
|
-
if (nextError instanceof Error && nextError.name === "RenderingCancelledException") {
|
|
8260
|
-
return;
|
|
8986
|
+
if (viewMode === "simple") {
|
|
8987
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8988
|
+
SimpleAssistantGroup,
|
|
8989
|
+
{
|
|
8990
|
+
messages,
|
|
8991
|
+
lastGlobalIndex,
|
|
8992
|
+
totalMessages,
|
|
8993
|
+
isRunning,
|
|
8994
|
+
sessionId,
|
|
8995
|
+
artifactFallbacks,
|
|
8996
|
+
onFileSelect,
|
|
8997
|
+
onRetry
|
|
8261
8998
|
}
|
|
8262
|
-
setError(formatPdfPreviewError(nextError));
|
|
8263
|
-
});
|
|
8264
|
-
return () => {
|
|
8265
|
-
cancelled = true;
|
|
8266
|
-
loadingTask?.destroy();
|
|
8267
|
-
pdfDocument?.destroy();
|
|
8268
|
-
pdfViewerRef.current?.cleanup();
|
|
8269
|
-
pdfViewerRef.current = null;
|
|
8270
|
-
eventBusRef.current = null;
|
|
8271
|
-
findControllerRef.current = null;
|
|
8272
|
-
};
|
|
8273
|
-
}, [file.content]);
|
|
8274
|
-
const setViewerPage = (nextPage) => {
|
|
8275
|
-
const viewer = pdfViewerRef.current;
|
|
8276
|
-
if (!viewer) return;
|
|
8277
|
-
const clampedPage = Math.min(
|
|
8278
|
-
Math.max(1, nextPage),
|
|
8279
|
-
Math.max(1, viewer.pagesCount)
|
|
8280
8999
|
);
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
9000
|
+
}
|
|
9001
|
+
let entries = [];
|
|
9002
|
+
for (let i = 0; i < messages.length; i++) {
|
|
9003
|
+
const isLast = i === messages.length - 1 && lastGlobalIndex === totalMessages - 1;
|
|
9004
|
+
entries.push(...messageToEntries(messages[i], isLast, artifactFallbacks));
|
|
9005
|
+
}
|
|
9006
|
+
entries = groupBrowserActivityEntries(entries);
|
|
9007
|
+
entries = groupWebSearchEntries(entries);
|
|
9008
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
9009
|
+
const entry = entries[i];
|
|
9010
|
+
if (entry?.kind === "text") {
|
|
9011
|
+
entries[i] = { ...entry, isFinalTurnText: true };
|
|
9012
|
+
break;
|
|
9013
|
+
}
|
|
9014
|
+
}
|
|
9015
|
+
const isTailGroup = lastGlobalIndex === totalMessages - 1;
|
|
9016
|
+
const lastEntry = entries[entries.length - 1];
|
|
9017
|
+
const hasRunningTool = entries.some(
|
|
9018
|
+
(e) => e.kind === "tool" && e.tc.status === "running"
|
|
9019
|
+
);
|
|
9020
|
+
const tailMsg = messages[messages.length - 1];
|
|
9021
|
+
if (isTailGroup && isRunning && !hasRunningTool && lastEntry?.kind !== "thinking") {
|
|
9022
|
+
entries.push({ kind: "thinking", key: `${tailMsg.id}-tail-thinking` });
|
|
9023
|
+
}
|
|
9024
|
+
const tail = messages[messages.length - 1];
|
|
9025
|
+
const showErrorInfo = tail && tail.role === "assistant" && tail.status === "error" && !!tail.errorInfo;
|
|
9026
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsxs(MessageContent, { children: [
|
|
9027
|
+
/* @__PURE__ */ jsxRuntime.jsx(Timeline, { defaultValue: 999, className: "gap-0", children: entries.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
9028
|
+
TimelineEntryItem,
|
|
9029
|
+
{
|
|
9030
|
+
entry,
|
|
9031
|
+
step: i + 1,
|
|
9032
|
+
sessionId,
|
|
9033
|
+
onFileSelect
|
|
9034
|
+
},
|
|
9035
|
+
entry.key
|
|
9036
|
+
)) }),
|
|
9037
|
+
showErrorInfo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsx(ErrorMessage, { errorInfo: tail.errorInfo, onRetry }) })
|
|
9038
|
+
] }) });
|
|
9039
|
+
}
|
|
9040
|
+
function RetryBanner({ indicator }) {
|
|
9041
|
+
const [open, setOpen] = react.useState(false);
|
|
9042
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9043
|
+
"div",
|
|
9044
|
+
{
|
|
9045
|
+
role: "status",
|
|
9046
|
+
className: "flex flex-col gap-1 border-l-2 border-amber-500 bg-amber-500/5 px-3 py-2 text-xs",
|
|
9047
|
+
children: [
|
|
9048
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9049
|
+
"button",
|
|
9050
|
+
{
|
|
9051
|
+
type: "button",
|
|
9052
|
+
onClick: () => setOpen((prev) => !prev),
|
|
9053
|
+
className: "flex items-center gap-2 text-left text-amber-600 hover:text-amber-700",
|
|
9054
|
+
"aria-expanded": open,
|
|
9055
|
+
children: [
|
|
9056
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3 shrink-0" }),
|
|
9057
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate font-medium", children: indicator.title }),
|
|
9058
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-foreground/60", children: [
|
|
9059
|
+
"attempt ",
|
|
9060
|
+
indicator.attempt
|
|
9061
|
+
] }),
|
|
9062
|
+
indicator.detail && (open ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-3" }))
|
|
9063
|
+
]
|
|
9064
|
+
}
|
|
9065
|
+
),
|
|
9066
|
+
open && indicator.detail && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "mt-1 overflow-x-auto rounded-none bg-background p-2 font-mono text-[11px] whitespace-pre-wrap wrap-break-word text-foreground/60", children: indicator.detail })
|
|
9067
|
+
]
|
|
9068
|
+
}
|
|
9069
|
+
);
|
|
9070
|
+
}
|
|
9071
|
+
function ChatThread({
|
|
9072
|
+
sessionId,
|
|
9073
|
+
messages,
|
|
9074
|
+
isRunning,
|
|
9075
|
+
isLoadingHistory = false,
|
|
9076
|
+
onSend,
|
|
9077
|
+
onStop,
|
|
9078
|
+
onFileSelect,
|
|
9079
|
+
disabled = false,
|
|
9080
|
+
disabledReason,
|
|
9081
|
+
tokenUsage,
|
|
9082
|
+
retryIndicator,
|
|
9083
|
+
onRetry,
|
|
9084
|
+
onComposerError,
|
|
9085
|
+
showBrowser = false,
|
|
9086
|
+
onToggleBrowser,
|
|
9087
|
+
showWorkspace = false,
|
|
9088
|
+
onToggleWorkspace,
|
|
9089
|
+
canShowBrowser = false,
|
|
9090
|
+
canShowWorkspace = false,
|
|
9091
|
+
viewMode = "simple",
|
|
9092
|
+
onViewModeChange
|
|
9093
|
+
}) {
|
|
9094
|
+
const groups = react.useMemo(() => groupMessages(messages), [messages]);
|
|
9095
|
+
const artifactFallbacks = react.useMemo(() => {
|
|
9096
|
+
const fallbacks = {};
|
|
9097
|
+
const createArtifactToolCallIds = [];
|
|
9098
|
+
let artifactIdx = 0;
|
|
9099
|
+
for (const msg of messages) {
|
|
9100
|
+
if (msg.role === "assistant" && msg.toolCalls) {
|
|
9101
|
+
for (const tc of msg.toolCalls) {
|
|
9102
|
+
if (tc.toolName === "create_artifact" && !tc.cancelled && tc.status !== "error") {
|
|
9103
|
+
createArtifactToolCallIds.push(tc.id);
|
|
9104
|
+
}
|
|
8348
9105
|
}
|
|
8349
|
-
)
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
type: "button",
|
|
8355
|
-
variant: "ghost",
|
|
8356
|
-
size: "icon-xs",
|
|
8357
|
-
onClick: () => setViewerScale(scale - 0.1),
|
|
8358
|
-
disabled: scale <= 0.5,
|
|
8359
|
-
"aria-label": "Zoom out PDF",
|
|
8360
|
-
title: "Zoom out",
|
|
8361
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusIcon, { className: "size-3.5" })
|
|
9106
|
+
} else if (msg.role === "system" && msg.systemKind === "artifact") {
|
|
9107
|
+
const tcId = createArtifactToolCallIds[artifactIdx];
|
|
9108
|
+
if (tcId) {
|
|
9109
|
+
const { name } = unpackArtifactMeta(msg.systemMeta, msg.content);
|
|
9110
|
+
if (name) fallbacks[tcId] = name;
|
|
8362
9111
|
}
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
9112
|
+
artifactIdx += 1;
|
|
9113
|
+
}
|
|
9114
|
+
}
|
|
9115
|
+
return fallbacks;
|
|
9116
|
+
}, [messages]);
|
|
9117
|
+
const activeFailureId = react.useMemo(() => {
|
|
9118
|
+
if (messages.length === 0) return null;
|
|
9119
|
+
const tail = messages[messages.length - 1];
|
|
9120
|
+
if (tail.role === "system" && tail.systemKind === "error" && tail.errorInfo) {
|
|
9121
|
+
return tail.id;
|
|
9122
|
+
}
|
|
9123
|
+
if (tail.role === "assistant" && tail.status === "error" && tail.errorInfo) {
|
|
9124
|
+
return tail.id;
|
|
9125
|
+
}
|
|
9126
|
+
return null;
|
|
9127
|
+
}, [messages]);
|
|
9128
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden bg-background text-sm", children: [
|
|
9129
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Conversation, { className: "relative flex-1 min-h-0", children: [
|
|
9130
|
+
/* @__PURE__ */ jsxRuntime.jsx(ConversationContent, { className: "mx-auto w-full max-w-4xl", children: messages.length === 0 && isLoadingHistory ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9131
|
+
ConversationEmptyState,
|
|
8366
9132
|
{
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
const viewer = pdfViewerRef.current;
|
|
8371
|
-
if (!viewer) return;
|
|
8372
|
-
viewer.currentScaleValue = "page-width";
|
|
8373
|
-
setScale(viewer.currentScale || 1);
|
|
8374
|
-
},
|
|
8375
|
-
"aria-label": "Fit PDF to width",
|
|
8376
|
-
title: "Fit width",
|
|
8377
|
-
children: [
|
|
8378
|
-
Math.round(scale * 100),
|
|
8379
|
-
"%"
|
|
8380
|
-
]
|
|
9133
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquareIcon, { className: "size-8 opacity-40" }),
|
|
9134
|
+
title: "Loading conversation",
|
|
9135
|
+
description: "Fetching the session history."
|
|
8381
9136
|
}
|
|
8382
|
-
)
|
|
8383
|
-
|
|
8384
|
-
Button,
|
|
9137
|
+
) : messages.length === 0 && !disabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9138
|
+
ConversationEmptyState,
|
|
8385
9139
|
{
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
onClick: () => setViewerScale(scale + 0.1),
|
|
8390
|
-
disabled: scale >= 3,
|
|
8391
|
-
"aria-label": "Zoom in PDF",
|
|
8392
|
-
title: "Zoom in",
|
|
8393
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { className: "size-3.5" })
|
|
9140
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquareIcon, { className: "size-8 opacity-40" }),
|
|
9141
|
+
title: "Start a conversation",
|
|
9142
|
+
description: "Ask me anything \u2014 I can search, analyze, write code, and more."
|
|
8394
9143
|
}
|
|
8395
|
-
),
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
9144
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9145
|
+
groups.map((group) => {
|
|
9146
|
+
if (group.role === "user") {
|
|
9147
|
+
const msg = group.messages[0];
|
|
9148
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9149
|
+
ChatMessage,
|
|
9150
|
+
{
|
|
9151
|
+
message: msg,
|
|
9152
|
+
onFileSelect
|
|
9153
|
+
},
|
|
9154
|
+
msg.id
|
|
9155
|
+
);
|
|
9156
|
+
}
|
|
9157
|
+
if (group.role === "system") {
|
|
9158
|
+
const msg = group.messages[0];
|
|
9159
|
+
const groupRetry2 = msg.id === activeFailureId ? onRetry : void 0;
|
|
9160
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9161
|
+
OrphanSystemMarker,
|
|
9162
|
+
{
|
|
9163
|
+
message: msg,
|
|
9164
|
+
sessionId,
|
|
9165
|
+
onRetry: groupRetry2
|
|
9166
|
+
},
|
|
9167
|
+
msg.id
|
|
9168
|
+
);
|
|
9169
|
+
}
|
|
9170
|
+
const groupTail = group.messages[group.messages.length - 1];
|
|
9171
|
+
const groupRetry = groupTail.id === activeFailureId ? onRetry : void 0;
|
|
9172
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9173
|
+
AssistantGroup,
|
|
9174
|
+
{
|
|
9175
|
+
messages: group.messages,
|
|
9176
|
+
lastGlobalIndex: group.lastGlobalIndex,
|
|
9177
|
+
totalMessages: messages.length,
|
|
9178
|
+
isRunning,
|
|
9179
|
+
sessionId,
|
|
9180
|
+
artifactFallbacks,
|
|
9181
|
+
onFileSelect,
|
|
9182
|
+
onRetry: groupRetry,
|
|
9183
|
+
viewMode
|
|
9184
|
+
},
|
|
9185
|
+
group.messages[0].id
|
|
9186
|
+
);
|
|
9187
|
+
}),
|
|
9188
|
+
isRunning && messages.length > 0 && messages[messages.length - 1].role === "user" && /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) }) })
|
|
9189
|
+
] }) }),
|
|
9190
|
+
/* @__PURE__ */ jsxRuntime.jsx(ConversationScrollButton, {})
|
|
9191
|
+
] }),
|
|
9192
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-4xl px-3 sm:px-6 pb-3 sm:pb-5 pt-3", children: [
|
|
9193
|
+
retryIndicator && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(RetryBanner, { indicator: retryIndicator }) }),
|
|
9194
|
+
disabled && disabledReason ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9195
|
+
"div",
|
|
8400
9196
|
{
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
onKeyDown: (event) => {
|
|
8405
|
-
if (event.key === "Enter") runFind(event.shiftKey);
|
|
8406
|
-
},
|
|
8407
|
-
placeholder: "Find",
|
|
8408
|
-
"aria-label": "Find in PDF",
|
|
8409
|
-
className: "h-7 w-28 border-input px-1 text-xs"
|
|
9197
|
+
className: "rounded border border-line bg-muted/40 px-3 py-2 text-sm text-foreground/60",
|
|
9198
|
+
role: "status",
|
|
9199
|
+
children: disabledReason
|
|
8410
9200
|
}
|
|
8411
|
-
)
|
|
8412
|
-
|
|
8413
|
-
Button,
|
|
9201
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9202
|
+
ChatComposer,
|
|
8414
9203
|
{
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
9204
|
+
onSend,
|
|
9205
|
+
onStop,
|
|
9206
|
+
isRunning,
|
|
9207
|
+
disabled,
|
|
9208
|
+
disabledReason,
|
|
9209
|
+
tokenUsage,
|
|
9210
|
+
onComposerError,
|
|
9211
|
+
showBrowser,
|
|
9212
|
+
onToggleBrowser,
|
|
9213
|
+
showWorkspace,
|
|
9214
|
+
onToggleWorkspace,
|
|
9215
|
+
canShowBrowser,
|
|
9216
|
+
canShowWorkspace,
|
|
9217
|
+
viewMode,
|
|
9218
|
+
onViewModeChange
|
|
8421
9219
|
}
|
|
8422
9220
|
)
|
|
8423
|
-
] })
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
9221
|
+
] })
|
|
9222
|
+
] });
|
|
9223
|
+
}
|
|
9224
|
+
|
|
9225
|
+
// src/components/ai-elements/file-tree.tsx
|
|
9226
|
+
init_utils();
|
|
9227
|
+
var noop = () => {
|
|
9228
|
+
};
|
|
9229
|
+
var FileTreeContext = react.createContext({
|
|
9230
|
+
expandedPaths: /* @__PURE__ */ new Set(),
|
|
9231
|
+
togglePath: noop
|
|
9232
|
+
});
|
|
9233
|
+
function FileTree({
|
|
9234
|
+
expanded: controlledExpanded,
|
|
9235
|
+
defaultExpanded = /* @__PURE__ */ new Set(),
|
|
9236
|
+
selectedPath,
|
|
9237
|
+
onSelect,
|
|
9238
|
+
onExpandedChange,
|
|
9239
|
+
className,
|
|
9240
|
+
children,
|
|
9241
|
+
...props
|
|
9242
|
+
}) {
|
|
9243
|
+
const [internalExpanded, setInternalExpanded] = react.useState(defaultExpanded);
|
|
9244
|
+
const expandedPaths = controlledExpanded ?? internalExpanded;
|
|
9245
|
+
const togglePath = react.useCallback(
|
|
9246
|
+
(path) => {
|
|
9247
|
+
const next = new Set(expandedPaths);
|
|
9248
|
+
if (next.has(path)) {
|
|
9249
|
+
next.delete(path);
|
|
9250
|
+
} else {
|
|
9251
|
+
next.add(path);
|
|
9252
|
+
}
|
|
9253
|
+
setInternalExpanded(next);
|
|
9254
|
+
onExpandedChange?.(next);
|
|
9255
|
+
},
|
|
9256
|
+
[expandedPaths, onExpandedChange]
|
|
9257
|
+
);
|
|
9258
|
+
const contextValue = react.useMemo(
|
|
9259
|
+
() => ({
|
|
9260
|
+
expandedPaths,
|
|
9261
|
+
onSelect,
|
|
9262
|
+
selectedPath: selectedPath ?? void 0,
|
|
9263
|
+
togglePath
|
|
9264
|
+
}),
|
|
9265
|
+
[expandedPaths, onSelect, selectedPath, togglePath]
|
|
9266
|
+
);
|
|
9267
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FileTreeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9268
|
+
"div",
|
|
9269
|
+
{
|
|
9270
|
+
className: cn("rounded-lg border bg-background text-sm", className),
|
|
9271
|
+
role: "tree",
|
|
9272
|
+
...props,
|
|
9273
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children })
|
|
9274
|
+
}
|
|
9275
|
+
) });
|
|
9276
|
+
}
|
|
9277
|
+
function FileTreeIcon({
|
|
9278
|
+
className,
|
|
9279
|
+
children,
|
|
9280
|
+
...props
|
|
9281
|
+
}) {
|
|
9282
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0", className), ...props, children });
|
|
9283
|
+
}
|
|
9284
|
+
function FileTreeName({
|
|
9285
|
+
className,
|
|
9286
|
+
children,
|
|
9287
|
+
...props
|
|
9288
|
+
}) {
|
|
9289
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("truncate", className), ...props, children });
|
|
9290
|
+
}
|
|
9291
|
+
function FileTreeFolder({
|
|
9292
|
+
path,
|
|
9293
|
+
name,
|
|
9294
|
+
className,
|
|
9295
|
+
children,
|
|
9296
|
+
...props
|
|
9297
|
+
}) {
|
|
9298
|
+
const { expandedPaths, togglePath, selectedPath, onSelect } = react.useContext(FileTreeContext);
|
|
9299
|
+
const isExpanded = expandedPaths.has(path);
|
|
9300
|
+
const isSelected = selectedPath === path;
|
|
9301
|
+
const handleOpenChange = react.useCallback(() => {
|
|
9302
|
+
togglePath(path);
|
|
9303
|
+
}, [togglePath, path]);
|
|
9304
|
+
const handleSelect = react.useCallback(() => {
|
|
9305
|
+
onSelect?.(path);
|
|
9306
|
+
}, [onSelect, path]);
|
|
9307
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Collapsible, { onOpenChange: handleOpenChange, open: isExpanded, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("", className), role: "treeitem", tabIndex: 0, ...props, children: [
|
|
9308
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8429
9309
|
"div",
|
|
8430
9310
|
{
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
9311
|
+
className: cn(
|
|
9312
|
+
"flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50",
|
|
9313
|
+
isSelected && "bg-muted"
|
|
9314
|
+
),
|
|
9315
|
+
children: [
|
|
9316
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9317
|
+
"button",
|
|
9318
|
+
{
|
|
9319
|
+
className: "flex shrink-0 cursor-pointer items-center border-none bg-transparent p-0",
|
|
9320
|
+
type: "button",
|
|
9321
|
+
"aria-label": isExpanded ? `Collapse ${name}` : `Expand ${name}`,
|
|
9322
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9323
|
+
lucideReact.ChevronRightIcon,
|
|
9324
|
+
{
|
|
9325
|
+
className: cn(
|
|
9326
|
+
"size-4 shrink-0 text-muted-foreground transition-transform",
|
|
9327
|
+
isExpanded && "rotate-90"
|
|
9328
|
+
)
|
|
9329
|
+
}
|
|
9330
|
+
)
|
|
9331
|
+
}
|
|
9332
|
+
) }),
|
|
9333
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9334
|
+
"button",
|
|
9335
|
+
{
|
|
9336
|
+
className: "flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left",
|
|
9337
|
+
onClick: handleSelect,
|
|
9338
|
+
type: "button",
|
|
9339
|
+
children: [
|
|
9340
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeIcon, { children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpenIcon, { className: "size-4 text-blue-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderIcon, { className: "size-4 text-blue-500" }) }),
|
|
9341
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeName, { children: name })
|
|
9342
|
+
]
|
|
9343
|
+
}
|
|
9344
|
+
)
|
|
9345
|
+
]
|
|
8435
9346
|
}
|
|
8436
|
-
)
|
|
8437
|
-
|
|
8438
|
-
}
|
|
8439
|
-
function decodeBase64(content) {
|
|
8440
|
-
const binary = globalThis.atob(content);
|
|
8441
|
-
const bytes = new Uint8Array(binary.length);
|
|
8442
|
-
for (let index = 0; index < binary.length; index += 1) {
|
|
8443
|
-
bytes[index] = binary.charCodeAt(index);
|
|
8444
|
-
}
|
|
8445
|
-
return bytes;
|
|
9347
|
+
),
|
|
9348
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-4 border-l border-muted-foreground/50 pl-2", children }) })
|
|
9349
|
+
] }) });
|
|
8446
9350
|
}
|
|
8447
|
-
function
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
9351
|
+
function FileTreeFile({
|
|
9352
|
+
path,
|
|
9353
|
+
name,
|
|
9354
|
+
icon,
|
|
9355
|
+
className,
|
|
9356
|
+
children,
|
|
9357
|
+
...props
|
|
9358
|
+
}) {
|
|
9359
|
+
const { selectedPath, onSelect } = react.useContext(FileTreeContext);
|
|
9360
|
+
const isSelected = selectedPath === path;
|
|
9361
|
+
const handleClick = react.useCallback(() => {
|
|
9362
|
+
onSelect?.(path);
|
|
9363
|
+
}, [onSelect, path]);
|
|
9364
|
+
const handleKeyDown = react.useCallback(
|
|
9365
|
+
(event) => {
|
|
9366
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
9367
|
+
onSelect?.(path);
|
|
9368
|
+
}
|
|
9369
|
+
},
|
|
9370
|
+
[onSelect, path]
|
|
9371
|
+
);
|
|
9372
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9373
|
+
"div",
|
|
9374
|
+
{
|
|
9375
|
+
className: cn(
|
|
9376
|
+
"group flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50",
|
|
9377
|
+
isSelected && "bg-muted",
|
|
9378
|
+
className
|
|
9379
|
+
),
|
|
9380
|
+
onClick: handleClick,
|
|
9381
|
+
onKeyDown: handleKeyDown,
|
|
9382
|
+
role: "treeitem",
|
|
9383
|
+
tabIndex: 0,
|
|
9384
|
+
...props,
|
|
9385
|
+
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9386
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-4 shrink-0" }),
|
|
9387
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeIcon, { children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileIcon, { className: "size-4 text-muted-foreground" }) }),
|
|
9388
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileTreeName, { children: name })
|
|
9389
|
+
] })
|
|
9390
|
+
}
|
|
9391
|
+
);
|
|
8452
9392
|
}
|
|
9393
|
+
|
|
9394
|
+
// src/components/workspace/workspace-panel.tsx
|
|
9395
|
+
init_utils();
|
|
8453
9396
|
var SKELETON_WIDTHS2 = [75, 60, 90, 65, 80, 70, 85, 55];
|
|
8454
9397
|
var DEFAULT_WIDTH = 400;
|
|
8455
9398
|
var MIN_WIDTH = 300;
|
|
@@ -8877,7 +9820,7 @@ function WorkspacePanel({
|
|
|
8877
9820
|
}
|
|
8878
9821
|
),
|
|
8879
9822
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8880
|
-
|
|
9823
|
+
ConfirmDialog2,
|
|
8881
9824
|
{
|
|
8882
9825
|
open: deleteTarget !== null,
|
|
8883
9826
|
title: "Delete file?",
|
|
@@ -8891,7 +9834,7 @@ function WorkspacePanel({
|
|
|
8891
9834
|
}
|
|
8892
9835
|
);
|
|
8893
9836
|
}
|
|
8894
|
-
function
|
|
9837
|
+
function ConfirmDialog2({
|
|
8895
9838
|
open,
|
|
8896
9839
|
title,
|
|
8897
9840
|
description,
|
|
@@ -8970,7 +9913,9 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
8970
9913
|
"skill.invoked",
|
|
8971
9914
|
"policy.denied",
|
|
8972
9915
|
"stream.timeout",
|
|
9916
|
+
"expert.delegation",
|
|
8973
9917
|
"expert.result",
|
|
9918
|
+
"expert.failure",
|
|
8974
9919
|
"expert.endorse",
|
|
8975
9920
|
"expert.override",
|
|
8976
9921
|
"user.feedback",
|
|
@@ -8980,7 +9925,9 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
8980
9925
|
"browser.destroyed",
|
|
8981
9926
|
"browser.control_granted",
|
|
8982
9927
|
"browser.control_returned",
|
|
8983
|
-
"
|
|
9928
|
+
"ask_user_question.response",
|
|
9929
|
+
"iteration.summary",
|
|
9930
|
+
"turn.summary"
|
|
8984
9931
|
];
|
|
8985
9932
|
|
|
8986
9933
|
// src/runtime/reducer.ts
|
|
@@ -9005,7 +9952,8 @@ function createInitialAgentChatState(options = {}) {
|
|
|
9005
9952
|
hadDeltas: false,
|
|
9006
9953
|
terminal: false,
|
|
9007
9954
|
workspaceRefreshKey: 0,
|
|
9008
|
-
browser: null
|
|
9955
|
+
browser: null,
|
|
9956
|
+
viewMode: options.viewMode ?? "simple"
|
|
9009
9957
|
};
|
|
9010
9958
|
}
|
|
9011
9959
|
function applyAgentChatEvent(state, event) {
|
|
@@ -9018,11 +9966,10 @@ function applyAgentChatEvent(state, event) {
|
|
|
9018
9966
|
nextState = applyRetryIndicator(nextState, event);
|
|
9019
9967
|
switch (event.type) {
|
|
9020
9968
|
case "user.message":
|
|
9021
|
-
return withMessages(
|
|
9022
|
-
nextState
|
|
9023
|
-
event.eventId,
|
|
9024
|
-
|
|
9025
|
-
));
|
|
9969
|
+
return withMessages(
|
|
9970
|
+
{ ...nextState, terminal: false, isRunning: true },
|
|
9971
|
+
applyUserMessage(nextState.messages, event.eventId, event.data)
|
|
9972
|
+
);
|
|
9026
9973
|
case "skill.invoked":
|
|
9027
9974
|
return withMessages(nextState, [
|
|
9028
9975
|
...nextState.messages,
|
|
@@ -9097,7 +10044,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
9097
10044
|
}
|
|
9098
10045
|
case "harness.wake":
|
|
9099
10046
|
case "llm.request":
|
|
9100
|
-
return
|
|
10047
|
+
return { ...nextState, terminal: false, isRunning: true };
|
|
9101
10048
|
case "harness.crash":
|
|
9102
10049
|
case "stream.timeout":
|
|
9103
10050
|
return nextState;
|
|
@@ -9121,10 +10068,17 @@ function applyAgentChatEvent(state, event) {
|
|
|
9121
10068
|
};
|
|
9122
10069
|
}
|
|
9123
10070
|
return nextState;
|
|
10071
|
+
case "expert.delegation":
|
|
10072
|
+
return applyExpertDelegation(nextState, event);
|
|
9124
10073
|
case "expert.result":
|
|
9125
10074
|
return withMessages(
|
|
9126
10075
|
nextState,
|
|
9127
|
-
applyExpertResult(nextState.messages, event.eventId)
|
|
10076
|
+
applyExpertResult(nextState.messages, event.eventId, event.data)
|
|
10077
|
+
);
|
|
10078
|
+
case "expert.failure":
|
|
10079
|
+
return withMessages(
|
|
10080
|
+
nextState,
|
|
10081
|
+
applyExpertFailure(nextState.messages, event.eventId, event.data)
|
|
9128
10082
|
);
|
|
9129
10083
|
case "expert.endorse":
|
|
9130
10084
|
case "expert.override":
|
|
@@ -9137,15 +10091,19 @@ function applyAgentChatEvent(state, event) {
|
|
|
9137
10091
|
nextState,
|
|
9138
10092
|
applyUserFeedback(nextState.messages, event.data)
|
|
9139
10093
|
);
|
|
9140
|
-
case "
|
|
10094
|
+
case "ask_user_question.response":
|
|
9141
10095
|
return withMessages(
|
|
9142
10096
|
nextState,
|
|
9143
|
-
|
|
10097
|
+
applyAskUserQuestionResponse(nextState.messages, event.data)
|
|
9144
10098
|
);
|
|
9145
10099
|
case "policy.denied":
|
|
9146
10100
|
return applyPolicyDenied(nextState, event.data);
|
|
9147
10101
|
case "session.start":
|
|
9148
10102
|
return nextState;
|
|
10103
|
+
case "iteration.summary":
|
|
10104
|
+
return applyIterationSummary(nextState, event);
|
|
10105
|
+
case "turn.summary":
|
|
10106
|
+
return applyTurnSummary(nextState, event);
|
|
9149
10107
|
}
|
|
9150
10108
|
}
|
|
9151
10109
|
function applyRetryIndicator(state, event) {
|
|
@@ -9278,6 +10236,7 @@ function browserMarker(event) {
|
|
|
9278
10236
|
function applyLlmDelta(state, event) {
|
|
9279
10237
|
const deltaContent = stringValue2(event.data.content);
|
|
9280
10238
|
const deltaReasoning = stringValue2(event.data.reasoning);
|
|
10239
|
+
const { turnId, iterationIndex } = readTurnMeta(event.data);
|
|
9281
10240
|
const messages = [...state.messages];
|
|
9282
10241
|
const lastIdx = findLastAssistantIndex(messages);
|
|
9283
10242
|
const lastMsg = lastIdx >= 0 ? messages[lastIdx] : null;
|
|
@@ -9292,7 +10251,9 @@ function applyLlmDelta(state, event) {
|
|
|
9292
10251
|
messages[lastIdx] = {
|
|
9293
10252
|
...lastMsg,
|
|
9294
10253
|
content: deltaContent ? lastMsg.content + deltaContent : lastMsg.content,
|
|
9295
|
-
reasoning: deltaReasoning ? (lastMsg.reasoning ?? "") + deltaReasoning : lastMsg.reasoning
|
|
10254
|
+
reasoning: deltaReasoning ? (lastMsg.reasoning ?? "") + deltaReasoning : lastMsg.reasoning,
|
|
10255
|
+
turnId: turnId ?? lastMsg.turnId,
|
|
10256
|
+
iterationIndex: iterationIndex ?? lastMsg.iterationIndex
|
|
9296
10257
|
};
|
|
9297
10258
|
} else {
|
|
9298
10259
|
messages.push({
|
|
@@ -9301,14 +10262,17 @@ function applyLlmDelta(state, event) {
|
|
|
9301
10262
|
content: deltaContent,
|
|
9302
10263
|
reasoning: deltaReasoning || void 0,
|
|
9303
10264
|
createdAt: /* @__PURE__ */ new Date(),
|
|
9304
|
-
status: "streaming"
|
|
10265
|
+
status: "streaming",
|
|
10266
|
+
turnId,
|
|
10267
|
+
iterationIndex
|
|
9305
10268
|
});
|
|
9306
10269
|
}
|
|
9307
10270
|
return {
|
|
9308
10271
|
...state,
|
|
9309
10272
|
messages,
|
|
9310
10273
|
hadDeltas: state.hadDeltas || Boolean(deltaContent),
|
|
9311
|
-
|
|
10274
|
+
terminal: false,
|
|
10275
|
+
isRunning: true
|
|
9312
10276
|
};
|
|
9313
10277
|
}
|
|
9314
10278
|
function applyLlmResponse(state, event) {
|
|
@@ -9318,6 +10282,7 @@ function applyLlmResponse(state, event) {
|
|
|
9318
10282
|
const toolCalls = Array.isArray(message?.tool_calls) ? message?.tool_calls : [];
|
|
9319
10283
|
const hasToolCalls = toolCalls.length > 0;
|
|
9320
10284
|
const responseToolCallIds = toolCallIdsFromResponse(toolCalls);
|
|
10285
|
+
const { turnId, iterationIndex } = readTurnMeta(event.data);
|
|
9321
10286
|
const idx = findLastAssistantIndex(messages);
|
|
9322
10287
|
const prevAssistant = idx >= 0 ? messages[idx] : void 0;
|
|
9323
10288
|
const prevHasTools = Boolean(prevAssistant?.toolCalls?.length);
|
|
@@ -9335,13 +10300,17 @@ function applyLlmResponse(state, event) {
|
|
|
9335
10300
|
reasoning: (current.reasoning ?? "") + current.content,
|
|
9336
10301
|
content: "",
|
|
9337
10302
|
status: "streaming",
|
|
9338
|
-
llmResponseEventId: event.eventId
|
|
10303
|
+
llmResponseEventId: event.eventId,
|
|
10304
|
+
turnId: turnId ?? current.turnId,
|
|
10305
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9339
10306
|
};
|
|
9340
10307
|
} else {
|
|
9341
10308
|
messages[idx] = {
|
|
9342
10309
|
...current,
|
|
9343
10310
|
status: "complete",
|
|
9344
|
-
llmResponseEventId: event.eventId
|
|
10311
|
+
llmResponseEventId: event.eventId,
|
|
10312
|
+
turnId: turnId ?? current.turnId,
|
|
10313
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9345
10314
|
};
|
|
9346
10315
|
}
|
|
9347
10316
|
} else if (matchesExistingToolTurn && idx >= 0) {
|
|
@@ -9350,7 +10319,9 @@ function applyLlmResponse(state, event) {
|
|
|
9350
10319
|
...current,
|
|
9351
10320
|
reasoning: responseContent ? appendText(current.reasoning, responseContent) : current.reasoning,
|
|
9352
10321
|
status: "streaming",
|
|
9353
|
-
llmResponseEventId: event.eventId
|
|
10322
|
+
llmResponseEventId: event.eventId,
|
|
10323
|
+
turnId: turnId ?? current.turnId,
|
|
10324
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9354
10325
|
};
|
|
9355
10326
|
} else if (prevHasTools || !prevAssistant || hasUserAfter) {
|
|
9356
10327
|
messages.push({
|
|
@@ -9360,7 +10331,9 @@ function applyLlmResponse(state, event) {
|
|
|
9360
10331
|
reasoning: hasToolCalls && responseContent ? responseContent : void 0,
|
|
9361
10332
|
createdAt: /* @__PURE__ */ new Date(),
|
|
9362
10333
|
status: hasToolCalls ? "streaming" : "complete",
|
|
9363
|
-
llmResponseEventId: event.eventId
|
|
10334
|
+
llmResponseEventId: event.eventId,
|
|
10335
|
+
turnId,
|
|
10336
|
+
iterationIndex
|
|
9364
10337
|
});
|
|
9365
10338
|
} else {
|
|
9366
10339
|
const current = messages[idx];
|
|
@@ -9369,14 +10342,18 @@ function applyLlmResponse(state, event) {
|
|
|
9369
10342
|
...current,
|
|
9370
10343
|
reasoning: (current.reasoning ?? "") + responseContent,
|
|
9371
10344
|
status: "streaming",
|
|
9372
|
-
llmResponseEventId: event.eventId
|
|
10345
|
+
llmResponseEventId: event.eventId,
|
|
10346
|
+
turnId: turnId ?? current.turnId,
|
|
10347
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9373
10348
|
};
|
|
9374
10349
|
} else {
|
|
9375
10350
|
messages[idx] = {
|
|
9376
10351
|
...current,
|
|
9377
10352
|
content: responseContent || current.content,
|
|
9378
10353
|
status: hasToolCalls ? "streaming" : "complete",
|
|
9379
|
-
llmResponseEventId: event.eventId
|
|
10354
|
+
llmResponseEventId: event.eventId,
|
|
10355
|
+
turnId: turnId ?? current.turnId,
|
|
10356
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9380
10357
|
};
|
|
9381
10358
|
}
|
|
9382
10359
|
}
|
|
@@ -9409,6 +10386,7 @@ ${addition}`;
|
|
|
9409
10386
|
}
|
|
9410
10387
|
function applyLlmThinking(state, event) {
|
|
9411
10388
|
const reasoningText = stringValue2(event.data.reasoning) || stringValue2(event.data.content);
|
|
10389
|
+
const { turnId, iterationIndex } = readTurnMeta(event.data);
|
|
9412
10390
|
const messages = [...state.messages];
|
|
9413
10391
|
const idx = findLastAssistantIndex(messages);
|
|
9414
10392
|
const prev = idx >= 0 ? messages[idx] : null;
|
|
@@ -9423,19 +10401,85 @@ function applyLlmThinking(state, event) {
|
|
|
9423
10401
|
content: "",
|
|
9424
10402
|
reasoning: reasoningText,
|
|
9425
10403
|
createdAt: /* @__PURE__ */ new Date(),
|
|
9426
|
-
status: "streaming"
|
|
10404
|
+
status: "streaming",
|
|
10405
|
+
turnId,
|
|
10406
|
+
iterationIndex
|
|
9427
10407
|
});
|
|
9428
10408
|
} else {
|
|
9429
10409
|
messages[idx] = {
|
|
9430
10410
|
...prev,
|
|
9431
|
-
reasoning: (prev.reasoning ?? "") + reasoningText
|
|
10411
|
+
reasoning: (prev.reasoning ?? "") + reasoningText,
|
|
10412
|
+
turnId: turnId ?? prev.turnId,
|
|
10413
|
+
iterationIndex: iterationIndex ?? prev.iterationIndex
|
|
9432
10414
|
};
|
|
9433
10415
|
}
|
|
9434
10416
|
return {
|
|
9435
10417
|
...state,
|
|
9436
10418
|
messages,
|
|
9437
|
-
|
|
10419
|
+
terminal: false,
|
|
10420
|
+
isRunning: true
|
|
10421
|
+
};
|
|
10422
|
+
}
|
|
10423
|
+
function applyIterationSummary(state, event) {
|
|
10424
|
+
const turnId = optionalStringValue(event.data.turn_id);
|
|
10425
|
+
const iterationIndex = optionalNumberValue(event.data.iteration_index);
|
|
10426
|
+
const summary = optionalStringValue(event.data.summary);
|
|
10427
|
+
if (!turnId || iterationIndex === null || !summary) return state;
|
|
10428
|
+
const idx = state.messages.findIndex(
|
|
10429
|
+
(m) => m.role === "assistant" && m.turnId === turnId && m.iterationIndex === iterationIndex
|
|
10430
|
+
);
|
|
10431
|
+
if (idx < 0) return state;
|
|
10432
|
+
const toolCallIds = Array.isArray(event.data.tool_call_ids) ? event.data.tool_call_ids.map((x) => String(x)) : [];
|
|
10433
|
+
const messages = [...state.messages];
|
|
10434
|
+
messages[idx] = {
|
|
10435
|
+
...messages[idx],
|
|
10436
|
+
iterationSummary: {
|
|
10437
|
+
iterationIndex,
|
|
10438
|
+
summary,
|
|
10439
|
+
toolCallIds,
|
|
10440
|
+
startedAt: stringValue2(event.data.started_at),
|
|
10441
|
+
endedAt: stringValue2(event.data.ended_at)
|
|
10442
|
+
}
|
|
10443
|
+
};
|
|
10444
|
+
return { ...state, messages };
|
|
10445
|
+
}
|
|
10446
|
+
function applyTurnSummary(state, event) {
|
|
10447
|
+
const turnId = optionalStringValue(event.data.turn_id);
|
|
10448
|
+
if (!turnId) return state;
|
|
10449
|
+
const recap = stringValue2(event.data.recap);
|
|
10450
|
+
const artifacts = parseTurnArtifacts(event.data.artifacts);
|
|
10451
|
+
let idx = -1;
|
|
10452
|
+
for (let i = state.messages.length - 1; i >= 0; i--) {
|
|
10453
|
+
const message = state.messages[i];
|
|
10454
|
+
if (message.role === "assistant" && message.turnId === turnId) {
|
|
10455
|
+
idx = i;
|
|
10456
|
+
break;
|
|
10457
|
+
}
|
|
10458
|
+
}
|
|
10459
|
+
if (idx < 0) return state;
|
|
10460
|
+
const messages = [...state.messages];
|
|
10461
|
+
messages[idx] = {
|
|
10462
|
+
...messages[idx],
|
|
10463
|
+
turnSummary: { turnId, recap, artifacts }
|
|
9438
10464
|
};
|
|
10465
|
+
return { ...state, messages };
|
|
10466
|
+
}
|
|
10467
|
+
function parseTurnArtifacts(raw) {
|
|
10468
|
+
if (!Array.isArray(raw)) return [];
|
|
10469
|
+
const out = [];
|
|
10470
|
+
for (const item of raw) {
|
|
10471
|
+
if (!item || typeof item !== "object") continue;
|
|
10472
|
+
const obj = item;
|
|
10473
|
+
const kind = obj.kind;
|
|
10474
|
+
if (kind !== "file" && kind !== "artifact" && kind !== "url" && kind !== "command") {
|
|
10475
|
+
continue;
|
|
10476
|
+
}
|
|
10477
|
+
const label = typeof obj.label === "string" ? obj.label : "";
|
|
10478
|
+
const ref = typeof obj.ref === "string" ? obj.ref : "";
|
|
10479
|
+
if (!label || !ref) continue;
|
|
10480
|
+
out.push({ kind, label, ref });
|
|
10481
|
+
}
|
|
10482
|
+
return out;
|
|
9439
10483
|
}
|
|
9440
10484
|
function applyToolCall(state, event) {
|
|
9441
10485
|
const messages = [...state.messages];
|
|
@@ -9472,7 +10516,8 @@ function applyToolCall(state, event) {
|
|
|
9472
10516
|
return {
|
|
9473
10517
|
...state,
|
|
9474
10518
|
messages,
|
|
9475
|
-
|
|
10519
|
+
terminal: false,
|
|
10520
|
+
isRunning: true
|
|
9476
10521
|
};
|
|
9477
10522
|
}
|
|
9478
10523
|
function applyToolResult(messages, data) {
|
|
@@ -9550,16 +10595,84 @@ function buildErrorInfo(event) {
|
|
|
9550
10595
|
retryable: Boolean(event.data.retryable)
|
|
9551
10596
|
};
|
|
9552
10597
|
}
|
|
9553
|
-
function applyExpertResult(messages, eventId) {
|
|
10598
|
+
function applyExpertResult(messages, eventId, data) {
|
|
9554
10599
|
const match = findLatestConsultExpertCall(messages);
|
|
9555
10600
|
if (!match) return messages;
|
|
10601
|
+
const content = stringValue2(data.content);
|
|
9556
10602
|
const next = [...messages];
|
|
9557
10603
|
const msg = next[match.msgIdx];
|
|
9558
10604
|
next[match.msgIdx] = {
|
|
9559
10605
|
...msg,
|
|
9560
|
-
toolCalls: msg.toolCalls?.map(
|
|
9561
|
-
(tc
|
|
9562
|
-
|
|
10606
|
+
toolCalls: msg.toolCalls?.map((tc) => {
|
|
10607
|
+
if (tc.id !== match.toolId) return tc;
|
|
10608
|
+
const updated = {
|
|
10609
|
+
...tc,
|
|
10610
|
+
expertResultEventId: eventId,
|
|
10611
|
+
status: "complete"
|
|
10612
|
+
};
|
|
10613
|
+
if (tc.result === void 0 && content) {
|
|
10614
|
+
updated.result = JSON.stringify({ content });
|
|
10615
|
+
}
|
|
10616
|
+
return updated;
|
|
10617
|
+
})
|
|
10618
|
+
};
|
|
10619
|
+
return next;
|
|
10620
|
+
}
|
|
10621
|
+
function applyExpertDelegation(state, event) {
|
|
10622
|
+
if (findLatestConsultExpertCall(state.messages) !== null) {
|
|
10623
|
+
return state;
|
|
10624
|
+
}
|
|
10625
|
+
const expertName = stringValue2(event.data.expert);
|
|
10626
|
+
const task = stringValue2(event.data.task);
|
|
10627
|
+
if (!expertName) return state;
|
|
10628
|
+
const messages = [...state.messages];
|
|
10629
|
+
const assistantIdx = findLastAssistantIndex(messages);
|
|
10630
|
+
let assistant = assistantIdx >= 0 ? messages[assistantIdx] : null;
|
|
10631
|
+
const userAfterAssistant = assistantIdx >= 0 && hasUserAfterIndex(messages, assistantIdx);
|
|
10632
|
+
if (!assistant || assistant.status === "complete" || userAfterAssistant) {
|
|
10633
|
+
assistant = {
|
|
10634
|
+
id: `evt-${event.eventId}-expert-delegation`,
|
|
10635
|
+
role: "assistant",
|
|
10636
|
+
content: "",
|
|
10637
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
10638
|
+
status: "streaming"
|
|
10639
|
+
};
|
|
10640
|
+
messages.push(assistant);
|
|
10641
|
+
} else {
|
|
10642
|
+
assistant = { ...assistant };
|
|
10643
|
+
messages[assistantIdx] = assistant;
|
|
10644
|
+
}
|
|
10645
|
+
const toolCall = {
|
|
10646
|
+
id: `expert-delegation-${event.eventId}`,
|
|
10647
|
+
toolName: "consult_expert",
|
|
10648
|
+
args: JSON.stringify({ expert: expertName, question: task }),
|
|
10649
|
+
status: "running"
|
|
10650
|
+
};
|
|
10651
|
+
assistant.toolCalls = [...assistant.toolCalls ?? [], toolCall];
|
|
10652
|
+
return {
|
|
10653
|
+
...state,
|
|
10654
|
+
messages,
|
|
10655
|
+
terminal: false,
|
|
10656
|
+
isRunning: true
|
|
10657
|
+
};
|
|
10658
|
+
}
|
|
10659
|
+
function applyExpertFailure(messages, eventId, data) {
|
|
10660
|
+
const match = findLatestConsultExpertCall(messages);
|
|
10661
|
+
if (!match) return messages;
|
|
10662
|
+
const errorMsg = stringValue2(data.error) || "Expert consultation failed.";
|
|
10663
|
+
const next = [...messages];
|
|
10664
|
+
const msg = next[match.msgIdx];
|
|
10665
|
+
next[match.msgIdx] = {
|
|
10666
|
+
...msg,
|
|
10667
|
+
toolCalls: msg.toolCalls?.map((tc) => {
|
|
10668
|
+
if (tc.id !== match.toolId) return tc;
|
|
10669
|
+
return {
|
|
10670
|
+
...tc,
|
|
10671
|
+
expertResultEventId: eventId,
|
|
10672
|
+
status: "error",
|
|
10673
|
+
result: tc.result ?? JSON.stringify({ error: errorMsg })
|
|
10674
|
+
};
|
|
10675
|
+
})
|
|
9563
10676
|
};
|
|
9564
10677
|
return next;
|
|
9565
10678
|
}
|
|
@@ -9609,7 +10722,7 @@ function applyUserFeedback(messages, data) {
|
|
|
9609
10722
|
}
|
|
9610
10723
|
return messages;
|
|
9611
10724
|
}
|
|
9612
|
-
function
|
|
10725
|
+
function applyAskUserQuestionResponse(messages, data) {
|
|
9613
10726
|
const targetToolId = stringValue2(data.tool_call_id);
|
|
9614
10727
|
const responses = Array.isArray(data.responses) ? data.responses : void 0;
|
|
9615
10728
|
if (!targetToolId || !responses) return messages;
|
|
@@ -9622,7 +10735,7 @@ function applyClarifyResponse(messages, data) {
|
|
|
9622
10735
|
toolCalls: msg.toolCalls.map(
|
|
9623
10736
|
(tc) => tc.id === targetToolId ? {
|
|
9624
10737
|
...tc,
|
|
9625
|
-
|
|
10738
|
+
askUserQuestionAnswers: responses.map((response) => {
|
|
9626
10739
|
const row = objectValue(response) ?? {};
|
|
9627
10740
|
return {
|
|
9628
10741
|
question: stringValue2(row.question),
|
|
@@ -9704,8 +10817,39 @@ function stringValue2(value) {
|
|
|
9704
10817
|
function numberValue(value) {
|
|
9705
10818
|
return typeof value === "number" ? value : 0;
|
|
9706
10819
|
}
|
|
10820
|
+
function optionalNumberValue(value) {
|
|
10821
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
10822
|
+
}
|
|
10823
|
+
function optionalStringValue(value) {
|
|
10824
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
10825
|
+
}
|
|
10826
|
+
function readTurnMeta(data) {
|
|
10827
|
+
const turnId = optionalStringValue(data.turn_id);
|
|
10828
|
+
const iterationIndex = optionalNumberValue(data.iteration_index);
|
|
10829
|
+
return {
|
|
10830
|
+
turnId,
|
|
10831
|
+
iterationIndex: iterationIndex === null ? void 0 : iterationIndex
|
|
10832
|
+
};
|
|
10833
|
+
}
|
|
9707
10834
|
|
|
9708
10835
|
// src/runtime/use-agent-chat-runtime.ts
|
|
10836
|
+
var VIEW_MODE_KEY = "@invergent/agent-chat-react:viewMode";
|
|
10837
|
+
function readPersistedViewMode() {
|
|
10838
|
+
if (typeof window === "undefined") return null;
|
|
10839
|
+
try {
|
|
10840
|
+
const raw = window.localStorage.getItem(VIEW_MODE_KEY);
|
|
10841
|
+
if (raw === "simple" || raw === "expert") return raw;
|
|
10842
|
+
} catch {
|
|
10843
|
+
}
|
|
10844
|
+
return null;
|
|
10845
|
+
}
|
|
10846
|
+
function writePersistedViewMode(mode) {
|
|
10847
|
+
if (typeof window === "undefined") return;
|
|
10848
|
+
try {
|
|
10849
|
+
window.localStorage.setItem(VIEW_MODE_KEY, mode);
|
|
10850
|
+
} catch {
|
|
10851
|
+
}
|
|
10852
|
+
}
|
|
9709
10853
|
function useAgentChatRuntime({
|
|
9710
10854
|
adapter,
|
|
9711
10855
|
agentId,
|
|
@@ -9713,7 +10857,13 @@ function useAgentChatRuntime({
|
|
|
9713
10857
|
onSessionChange
|
|
9714
10858
|
}) {
|
|
9715
10859
|
const [state, setState] = react.useState(
|
|
9716
|
-
() => createInitialAgentChatState({
|
|
10860
|
+
() => createInitialAgentChatState({
|
|
10861
|
+
isLoadingHistory: Boolean(sessionId),
|
|
10862
|
+
// Seed from localStorage so the first paint matches the user's
|
|
10863
|
+
// last choice without flashing the default. The async adapter
|
|
10864
|
+
// load can still upgrade this later.
|
|
10865
|
+
viewMode: readPersistedViewMode() ?? "simple"
|
|
10866
|
+
})
|
|
9717
10867
|
);
|
|
9718
10868
|
const [session, setSession] = react.useState(null);
|
|
9719
10869
|
const stateRef = react.useRef(state);
|
|
@@ -10009,6 +11159,41 @@ function useAgentChatRuntime({
|
|
|
10009
11159
|
throw error;
|
|
10010
11160
|
}
|
|
10011
11161
|
}, [adapter, sessionId]);
|
|
11162
|
+
react.useEffect(() => {
|
|
11163
|
+
if (!adapter.getChatViewMode) {
|
|
11164
|
+
const cached = readPersistedViewMode();
|
|
11165
|
+
if (cached !== null) {
|
|
11166
|
+
setState(
|
|
11167
|
+
(prev) => prev.viewMode === cached ? prev : { ...prev, viewMode: cached }
|
|
11168
|
+
);
|
|
11169
|
+
}
|
|
11170
|
+
return;
|
|
11171
|
+
}
|
|
11172
|
+
let cancelled = false;
|
|
11173
|
+
void adapter.getChatViewMode().then((persisted) => {
|
|
11174
|
+
if (cancelled) return;
|
|
11175
|
+
if (persisted === "simple" || persisted === "expert") {
|
|
11176
|
+
setState(
|
|
11177
|
+
(prev) => prev.viewMode === persisted ? prev : { ...prev, viewMode: persisted }
|
|
11178
|
+
);
|
|
11179
|
+
}
|
|
11180
|
+
}).catch(() => void 0);
|
|
11181
|
+
return () => {
|
|
11182
|
+
cancelled = true;
|
|
11183
|
+
};
|
|
11184
|
+
}, [adapter]);
|
|
11185
|
+
const setViewMode = react.useCallback(
|
|
11186
|
+
(mode) => {
|
|
11187
|
+
setState(
|
|
11188
|
+
(prev) => prev.viewMode === mode ? prev : { ...prev, viewMode: mode }
|
|
11189
|
+
);
|
|
11190
|
+
writePersistedViewMode(mode);
|
|
11191
|
+
if (adapter.setChatViewMode) {
|
|
11192
|
+
void adapter.setChatViewMode(mode).catch(() => void 0);
|
|
11193
|
+
}
|
|
11194
|
+
},
|
|
11195
|
+
[adapter]
|
|
11196
|
+
);
|
|
10012
11197
|
return {
|
|
10013
11198
|
state,
|
|
10014
11199
|
session,
|
|
@@ -10022,7 +11207,9 @@ function useAgentChatRuntime({
|
|
|
10022
11207
|
stop,
|
|
10023
11208
|
retry,
|
|
10024
11209
|
markSending,
|
|
10025
|
-
markSendError
|
|
11210
|
+
markSendError,
|
|
11211
|
+
viewMode: state.viewMode,
|
|
11212
|
+
setViewMode
|
|
10026
11213
|
};
|
|
10027
11214
|
}
|
|
10028
11215
|
function parseEventData(data) {
|
|
@@ -10093,6 +11280,9 @@ function AgentChat({
|
|
|
10093
11280
|
sessionId,
|
|
10094
11281
|
onSessionChange
|
|
10095
11282
|
});
|
|
11283
|
+
react.useEffect(() => {
|
|
11284
|
+
setShowWorkspace(runtime.viewMode === "expert");
|
|
11285
|
+
}, [runtime.viewMode]);
|
|
10096
11286
|
const isReadOnlySession = isScheduledRunSession(runtime.session);
|
|
10097
11287
|
const effectiveDisabled = disabled || isReadOnlySession;
|
|
10098
11288
|
const disabledReason = isReadOnlySession ? "Scheduled run is read-only" : void 0;
|
|
@@ -10213,7 +11403,9 @@ function AgentChat({
|
|
|
10213
11403
|
showWorkspace,
|
|
10214
11404
|
onToggleWorkspace: handleToggleWorkspace,
|
|
10215
11405
|
canShowBrowser: browserAvailable,
|
|
10216
|
-
canShowWorkspace: workspaceAvailable
|
|
11406
|
+
canShowWorkspace: workspaceAvailable,
|
|
11407
|
+
viewMode: runtime.viewMode,
|
|
11408
|
+
onViewModeChange: runtime.setViewMode
|
|
10217
11409
|
}
|
|
10218
11410
|
)
|
|
10219
11411
|
}
|
|
@@ -10249,7 +11441,8 @@ function AgentChat({
|
|
|
10249
11441
|
{
|
|
10250
11442
|
sessionId,
|
|
10251
11443
|
state: browserState,
|
|
10252
|
-
adapter
|
|
11444
|
+
adapter,
|
|
11445
|
+
onClose: () => setShowBrowser(false)
|
|
10253
11446
|
}
|
|
10254
11447
|
)
|
|
10255
11448
|
}
|
|
@@ -10434,7 +11627,7 @@ function InputRequiredDetail({
|
|
|
10434
11627
|
answer: answers[question.prompt]?.trim() ?? "",
|
|
10435
11628
|
is_other: false
|
|
10436
11629
|
}));
|
|
10437
|
-
await adapter.
|
|
11630
|
+
await adapter.submitAskUserQuestionResponse({
|
|
10438
11631
|
sessionId: item.sessionId,
|
|
10439
11632
|
toolCallId,
|
|
10440
11633
|
responses
|
|
@@ -11021,7 +12214,7 @@ function groupMissionTasksByBucket(tasks) {
|
|
|
11021
12214
|
function deriveMissionWorkerActivityLabel(worker) {
|
|
11022
12215
|
const kind = worker.latestEventKind;
|
|
11023
12216
|
if (kind === "tool.call" && worker.latestEventSummary) {
|
|
11024
|
-
return `tool: ${
|
|
12217
|
+
return `tool: ${truncate3(worker.latestEventSummary, 80)}`;
|
|
11025
12218
|
}
|
|
11026
12219
|
if (kind === "llm.response") {
|
|
11027
12220
|
return "thinking";
|
|
@@ -11030,11 +12223,11 @@ function deriveMissionWorkerActivityLabel(worker) {
|
|
|
11030
12223
|
return "received tool result";
|
|
11031
12224
|
}
|
|
11032
12225
|
if (kind && worker.latestEventSummary) {
|
|
11033
|
-
return `${kind}: ${
|
|
12226
|
+
return `${kind}: ${truncate3(worker.latestEventSummary, 60)}`;
|
|
11034
12227
|
}
|
|
11035
12228
|
return worker.sessionStatus || "active";
|
|
11036
12229
|
}
|
|
11037
|
-
function
|
|
12230
|
+
function truncate3(s, max) {
|
|
11038
12231
|
if (s.length <= max) return s;
|
|
11039
12232
|
return `${s.slice(0, max - 1)}\u2026`;
|
|
11040
12233
|
}
|
|
@@ -12405,7 +13598,8 @@ function pruneDeletedSessionNodes(nodes, deletedSessionId) {
|
|
|
12405
13598
|
return nodes.filter((node) => !deletedIds.has(node.id));
|
|
12406
13599
|
}
|
|
12407
13600
|
function formatSessionTime(value) {
|
|
12408
|
-
const
|
|
13601
|
+
const normalized = /[zZ]|[+-]\d{2}:?\d{2}$/.test(value) ? value : `${value}Z`;
|
|
13602
|
+
const date = new Date(normalized);
|
|
12409
13603
|
if (Number.isNaN(date.getTime())) return "";
|
|
12410
13604
|
return dateFns.formatDistanceToNow(date, { addSuffix: true });
|
|
12411
13605
|
}
|
|
@@ -12445,7 +13639,6 @@ function TreeNodeRow({
|
|
|
12445
13639
|
const title = entry.title ?? fallbackSessionTitle(entry);
|
|
12446
13640
|
const subtitle = [
|
|
12447
13641
|
formatRunKind(entry.runKind),
|
|
12448
|
-
entry.model ?? entry.agentType,
|
|
12449
13642
|
formatSessionTime(entry.updatedAt)
|
|
12450
13643
|
].filter(Boolean).join(" \xB7 ");
|
|
12451
13644
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -12461,7 +13654,7 @@ function TreeNodeRow({
|
|
|
12461
13654
|
className: cn(
|
|
12462
13655
|
"group flex items-center gap-2 w-full py-2 pr-2 text-left cursor-pointer transition-colors border-l-2",
|
|
12463
13656
|
"min-h-11 md:min-h-0",
|
|
12464
|
-
isActive ? "bg-line text-foreground border-l-primary" : "bg-transparent text-
|
|
13657
|
+
isActive ? "bg-line text-foreground border-l-primary" : "bg-transparent text-foreground/80 hover:bg-input hover:text-foreground border-l-transparent"
|
|
12465
13658
|
),
|
|
12466
13659
|
style: { paddingLeft: `${depth * 12 + 12}px` },
|
|
12467
13660
|
children: [
|