@invergent/agent-chat-react 1.5.2 → 1.5.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/artifact-chart-X53FKRDZ.js +153 -0
- package/dist/artifact-chart-X53FKRDZ.js.map +1 -0
- package/dist/chunk-QSC4UIVT.js +11 -0
- package/dist/chunk-QSC4UIVT.js.map +1 -0
- package/dist/index.cjs +795 -241
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +542 -185
- package/dist/index.js.map +1 -1
- package/package.json +5 -7
- package/dist/artifact-chart-7J6GOR4M.js +0 -88
- package/dist/artifact-chart-7J6GOR4M.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { cn } from './chunk-QSC4UIVT.js';
|
|
1
2
|
import { createContext, memo, useRef, useState, useEffect, useCallback, useMemo, lazy, useContext, Suspense, Children } from 'react';
|
|
2
3
|
import { cva } from 'class-variance-authority';
|
|
3
4
|
import { Collapsible as Collapsible$1, Slot, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Tooltip as Tooltip$1, Tabs as Tabs$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, HoverCard as HoverCard$1, Progress as Progress$1 } from 'radix-ui';
|
|
4
|
-
import { clsx } from 'clsx';
|
|
5
|
-
import { twMerge } from 'tailwind-merge';
|
|
6
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, ChevronRightIcon, GitBranchIcon, XIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, Loader2Icon, GlobeIcon, SearchIcon, ListTodoIcon, XCircleIcon, CheckCircle2Icon, Code, CheckIcon, CopyIcon, TerminalIcon, Trash2Icon, CircleDotIcon, CircleCheckIcon, CircleXIcon, SkullIcon, ClockIcon, CheckCircleIcon, CircleIcon, UsersIcon, MessageSquareIcon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, SquareIcon, ArrowDownIcon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, Maximize2Icon, FolderIcon, FileIcon, PlusIcon, CornerDownLeftIcon } from 'lucide-react';
|
|
6
|
+
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, ChevronRightIcon, GitBranchIcon, XIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, Loader2Icon, GlobeIcon, SearchIcon, ListTodoIcon, XCircleIcon, CheckCircle2Icon, Code, CheckIcon, CopyIcon, TerminalIcon, Trash2Icon, CircleDotIcon, CircleCheckIcon, CircleXIcon, SkullIcon, ClockIcon, CheckCircleIcon, CircleIcon, UsersIcon, MessageSquareIcon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, SquareIcon, ArrowDownIcon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, Maximize2Icon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, PlusIcon, CornerDownLeftIcon } from 'lucide-react';
|
|
8
7
|
import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom';
|
|
9
8
|
import { cjk } from '@streamdown/cjk';
|
|
10
9
|
import { code } from '@streamdown/code';
|
|
@@ -18,9 +17,9 @@ import Ansi from 'ansi-to-react';
|
|
|
18
17
|
import { getUsage } from 'tokenlens';
|
|
19
18
|
import { Command as Command$1 } from 'cmdk';
|
|
20
19
|
import { nanoid } from 'nanoid';
|
|
20
|
+
import 'pdfjs-dist/web/pdf_viewer.css';
|
|
21
21
|
import { formatDistanceToNow } from 'date-fns';
|
|
22
22
|
|
|
23
|
-
// src/agent-chat.tsx
|
|
24
23
|
var AgentChatAdapterContext = createContext(null);
|
|
25
24
|
var AgentChatAdapterProvider = AgentChatAdapterContext.Provider;
|
|
26
25
|
function useAgentChatAdapterContext() {
|
|
@@ -32,9 +31,6 @@ function useAgentChatAdapterContext() {
|
|
|
32
31
|
}
|
|
33
32
|
return value;
|
|
34
33
|
}
|
|
35
|
-
function cn(...inputs) {
|
|
36
|
-
return twMerge(clsx(inputs));
|
|
37
|
-
}
|
|
38
34
|
var buttonVariants = cva(
|
|
39
35
|
"group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-semibold tracking-widest whitespace-nowrap uppercase transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
40
36
|
{
|
|
@@ -86,7 +82,7 @@ function Button({
|
|
|
86
82
|
var Conversation = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
87
83
|
StickToBottom,
|
|
88
84
|
{
|
|
89
|
-
className: cn("relative flex-1
|
|
85
|
+
className: cn("relative flex-1", className),
|
|
90
86
|
initial: "smooth",
|
|
91
87
|
resize: "smooth",
|
|
92
88
|
role: "log",
|
|
@@ -569,6 +565,61 @@ function TimelineSeparator({
|
|
|
569
565
|
}
|
|
570
566
|
);
|
|
571
567
|
}
|
|
568
|
+
|
|
569
|
+
// src/components/chat/tools/shared.ts
|
|
570
|
+
function statusColorClass(status) {
|
|
571
|
+
if (status === "running") return "bg-primary animate-pulse";
|
|
572
|
+
if (status === "error") return "bg-red-500";
|
|
573
|
+
if (status === "cancelled") return "bg-muted-foreground/40";
|
|
574
|
+
return "bg-emerald-500";
|
|
575
|
+
}
|
|
576
|
+
function effectiveStatus(tc) {
|
|
577
|
+
if (tc.cancelled) return "cancelled";
|
|
578
|
+
if (tc.status !== "complete" || !tc.result) return tc.status;
|
|
579
|
+
try {
|
|
580
|
+
const parsed = JSON.parse(tc.result);
|
|
581
|
+
if (parsed?.exit_code !== void 0 && parsed.exit_code !== 0) return "error";
|
|
582
|
+
if (parsed?.error) return "error";
|
|
583
|
+
if (parsed?.status === "blocked" || parsed?.status === "error") return "error";
|
|
584
|
+
if (parsed?.success === false) return "error";
|
|
585
|
+
} catch {
|
|
586
|
+
}
|
|
587
|
+
return "complete";
|
|
588
|
+
}
|
|
589
|
+
function formatArgs(args) {
|
|
590
|
+
try {
|
|
591
|
+
return JSON.stringify(JSON.parse(args), null, 2);
|
|
592
|
+
} catch {
|
|
593
|
+
return args;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
function parseArgs(args) {
|
|
597
|
+
try {
|
|
598
|
+
return JSON.parse(args);
|
|
599
|
+
} catch {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function truncate(s, max) {
|
|
604
|
+
return s.length > max ? s.slice(0, max) + "\n... (truncated)" : s;
|
|
605
|
+
}
|
|
606
|
+
function toolErrorSummary(result, max = 180) {
|
|
607
|
+
if (!result) return "";
|
|
608
|
+
try {
|
|
609
|
+
const parsed = JSON.parse(result);
|
|
610
|
+
const error = typeof parsed?.error === "string" ? parsed.error : "";
|
|
611
|
+
if (error === "sandbox_unavailable") {
|
|
612
|
+
return "Sandbox is unavailable. Workspace commands cannot run right now.";
|
|
613
|
+
}
|
|
614
|
+
const reason = typeof parsed?.reason === "string" ? parsed.reason : "";
|
|
615
|
+
const message = typeof parsed?.message === "string" ? parsed.message : "";
|
|
616
|
+
const detail = reason || message;
|
|
617
|
+
const summary = error && detail && detail !== error ? `${error}: ${detail}` : error || detail;
|
|
618
|
+
return summary ? summary.replace(/\s+/g, " ").slice(0, max) : "";
|
|
619
|
+
} catch {
|
|
620
|
+
return "";
|
|
621
|
+
}
|
|
622
|
+
}
|
|
572
623
|
function CopyButton({ text }) {
|
|
573
624
|
const [copied, setCopied] = useState(false);
|
|
574
625
|
return /* @__PURE__ */ jsx(
|
|
@@ -604,7 +655,8 @@ function parseTerminalResult(result, args) {
|
|
|
604
655
|
const hasOutput = typeof parsed?.output === "string";
|
|
605
656
|
const hasStdout = typeof parsed?.stdout === "string";
|
|
606
657
|
const hasExitCode = typeof parsed?.exit_code === "number";
|
|
607
|
-
|
|
658
|
+
const errorSummary = toolErrorSummary(result, 400);
|
|
659
|
+
if (!hasOutput && !hasStdout && !hasExitCode && !errorSummary) {
|
|
608
660
|
return null;
|
|
609
661
|
}
|
|
610
662
|
let command = "";
|
|
@@ -614,20 +666,20 @@ function parseTerminalResult(result, args) {
|
|
|
614
666
|
} catch {
|
|
615
667
|
}
|
|
616
668
|
const output = parsed.output ?? parsed.stdout ?? "";
|
|
617
|
-
const stderr = parsed.stderr ??
|
|
669
|
+
const stderr = parsed.stderr ?? errorSummary;
|
|
618
670
|
const combined = stderr ? `${output}
|
|
619
671
|
${stderr}`.trim() : output;
|
|
620
672
|
return {
|
|
621
673
|
output: combined,
|
|
622
|
-
exit_code: parsed.exit_code ?? 0,
|
|
623
|
-
error:
|
|
674
|
+
exit_code: parsed.exit_code ?? (errorSummary ? 1 : 0),
|
|
675
|
+
error: errorSummary || null,
|
|
624
676
|
command
|
|
625
677
|
};
|
|
626
678
|
} catch {
|
|
627
679
|
return null;
|
|
628
680
|
}
|
|
629
681
|
}
|
|
630
|
-
function TerminalCollapsible({ command, output, isRunning }) {
|
|
682
|
+
function TerminalCollapsible({ command, output, isRunning, hasError }) {
|
|
631
683
|
const [isOpen, setIsOpen] = useState(false);
|
|
632
684
|
return /* @__PURE__ */ jsxs(
|
|
633
685
|
Collapsible,
|
|
@@ -637,7 +689,7 @@ function TerminalCollapsible({ command, output, isRunning }) {
|
|
|
637
689
|
className: "not-prose w-full",
|
|
638
690
|
children: [
|
|
639
691
|
/* @__PURE__ */ jsxs(CollapsibleTrigger, { className: "group/trigger flex w-fit items-center gap-2 text-sm transition-colors", children: [
|
|
640
|
-
/* @__PURE__ */ jsx("span", { className: "text-left", children: isRunning ? /* @__PURE__ */ jsx(Shimmer, { as: "span", duration: 1, children: "Running command..." }) : /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Command result" }) }),
|
|
692
|
+
/* @__PURE__ */ jsx("span", { className: "text-left", children: isRunning ? /* @__PURE__ */ jsx(Shimmer, { as: "span", duration: 1, children: "Running command..." }) : hasError ? /* @__PURE__ */ jsx("span", { className: "font-semibold text-destructive", children: "Command failed" }) : /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Command result" }) }),
|
|
641
693
|
/* @__PURE__ */ jsx(
|
|
642
694
|
ChevronDownIcon,
|
|
643
695
|
{
|
|
@@ -694,7 +746,8 @@ function TerminalToolBlock({ tc }) {
|
|
|
694
746
|
{
|
|
695
747
|
command: result.command,
|
|
696
748
|
output,
|
|
697
|
-
isRunning
|
|
749
|
+
isRunning,
|
|
750
|
+
hasError: result.exit_code !== 0 || Boolean(result.error)
|
|
698
751
|
}
|
|
699
752
|
);
|
|
700
753
|
}
|
|
@@ -2339,7 +2392,7 @@ var Terminal = ({
|
|
|
2339
2392
|
}
|
|
2340
2393
|
) });
|
|
2341
2394
|
};
|
|
2342
|
-
function
|
|
2395
|
+
function parseArgs2(args) {
|
|
2343
2396
|
try {
|
|
2344
2397
|
return JSON.parse(args);
|
|
2345
2398
|
} catch {
|
|
@@ -2563,7 +2616,7 @@ function OutputPreview({ output }) {
|
|
|
2563
2616
|
}
|
|
2564
2617
|
function ProcessToolBlock({ tc }) {
|
|
2565
2618
|
const isRunning = tc.status === "running";
|
|
2566
|
-
const args =
|
|
2619
|
+
const args = parseArgs2(tc.args);
|
|
2567
2620
|
const result = parseResult(tc.result);
|
|
2568
2621
|
const action = args.action || "unknown";
|
|
2569
2622
|
const actionLabel = {
|
|
@@ -2646,44 +2699,6 @@ function Textarea({ className, ...props }) {
|
|
|
2646
2699
|
}
|
|
2647
2700
|
);
|
|
2648
2701
|
}
|
|
2649
|
-
|
|
2650
|
-
// src/components/chat/tools/shared.ts
|
|
2651
|
-
function statusColorClass(status) {
|
|
2652
|
-
if (status === "running") return "bg-primary animate-pulse";
|
|
2653
|
-
if (status === "error") return "bg-red-500";
|
|
2654
|
-
if (status === "cancelled") return "bg-muted-foreground/40";
|
|
2655
|
-
return "bg-emerald-500";
|
|
2656
|
-
}
|
|
2657
|
-
function effectiveStatus(tc) {
|
|
2658
|
-
if (tc.cancelled) return "cancelled";
|
|
2659
|
-
if (tc.status !== "complete" || !tc.result) return tc.status;
|
|
2660
|
-
try {
|
|
2661
|
-
const parsed = JSON.parse(tc.result);
|
|
2662
|
-
if (parsed?.exit_code !== void 0 && parsed.exit_code !== 0) return "error";
|
|
2663
|
-
if (parsed?.error) return "error";
|
|
2664
|
-
if (parsed?.status === "blocked" || parsed?.status === "error") return "error";
|
|
2665
|
-
if (parsed?.success === false) return "error";
|
|
2666
|
-
} catch {
|
|
2667
|
-
}
|
|
2668
|
-
return "complete";
|
|
2669
|
-
}
|
|
2670
|
-
function formatArgs(args) {
|
|
2671
|
-
try {
|
|
2672
|
-
return JSON.stringify(JSON.parse(args), null, 2);
|
|
2673
|
-
} catch {
|
|
2674
|
-
return args;
|
|
2675
|
-
}
|
|
2676
|
-
}
|
|
2677
|
-
function parseArgs2(args) {
|
|
2678
|
-
try {
|
|
2679
|
-
return JSON.parse(args);
|
|
2680
|
-
} catch {
|
|
2681
|
-
return null;
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
function truncate(s, max) {
|
|
2685
|
-
return s.length > max ? s.slice(0, max) + "\n... (truncated)" : s;
|
|
2686
|
-
}
|
|
2687
2702
|
var MAX_REASON_LENGTH = 500;
|
|
2688
2703
|
function ExpertToolBlock({ tc }) {
|
|
2689
2704
|
const [expanded, setExpanded] = useState(false);
|
|
@@ -2719,7 +2734,7 @@ function ExpertToolBlock({ tc }) {
|
|
|
2719
2734
|
}
|
|
2720
2735
|
void submit("up");
|
|
2721
2736
|
};
|
|
2722
|
-
const args =
|
|
2737
|
+
const args = parseArgs(tc.args) ?? {};
|
|
2723
2738
|
const expertName = args.expert ?? null;
|
|
2724
2739
|
const question = args.question ?? args.prompt ?? "";
|
|
2725
2740
|
const result = parseExpertResult(tc.result);
|
|
@@ -2831,7 +2846,7 @@ function ExpertToolBlock({ tc }) {
|
|
|
2831
2846
|
}
|
|
2832
2847
|
function parseExpertResult(result) {
|
|
2833
2848
|
if (!result) return null;
|
|
2834
|
-
const parsed =
|
|
2849
|
+
const parsed = parseArgs(result);
|
|
2835
2850
|
if (parsed) {
|
|
2836
2851
|
return {
|
|
2837
2852
|
...parsed,
|
|
@@ -2938,11 +2953,11 @@ function ReasonForm({
|
|
|
2938
2953
|
] });
|
|
2939
2954
|
}
|
|
2940
2955
|
function SkillsListBlock({ tc }) {
|
|
2941
|
-
const args =
|
|
2956
|
+
const args = parseArgs(tc.args) ?? {};
|
|
2942
2957
|
const filter = args.category ? `category: ${args.category}` : "all";
|
|
2943
2958
|
let summary = "";
|
|
2944
2959
|
if (tc.result) {
|
|
2945
|
-
const parsed =
|
|
2960
|
+
const parsed = parseArgs(tc.result);
|
|
2946
2961
|
if (parsed?.count !== void 0) {
|
|
2947
2962
|
summary = `${parsed.count} skill${parsed.count === 1 ? "" : "s"}`;
|
|
2948
2963
|
}
|
|
@@ -2957,11 +2972,11 @@ function SkillsListBlock({ tc }) {
|
|
|
2957
2972
|
] });
|
|
2958
2973
|
}
|
|
2959
2974
|
function SkillViewBlock({ tc }) {
|
|
2960
|
-
const args =
|
|
2975
|
+
const args = parseArgs(tc.args) ?? {};
|
|
2961
2976
|
const target = args.file_path ? `${args.name ?? "?"}/${args.file_path}` : args.name ?? "?";
|
|
2962
2977
|
let summary = "";
|
|
2963
2978
|
if (tc.result) {
|
|
2964
|
-
const parsed =
|
|
2979
|
+
const parsed = parseArgs(tc.result);
|
|
2965
2980
|
if (parsed?.staged_at) {
|
|
2966
2981
|
summary = `staged at ${parsed.staged_at}`;
|
|
2967
2982
|
} else if (parsed?.token_estimate) {
|
|
@@ -3008,7 +3023,7 @@ function buildAnswer(q, sel) {
|
|
|
3008
3023
|
}
|
|
3009
3024
|
function ClarifyToolBlock({ tc }) {
|
|
3010
3025
|
const { adapter, sessionId } = useAgentChatAdapterContext();
|
|
3011
|
-
const args = useMemo(() =>
|
|
3026
|
+
const args = useMemo(() => parseArgs(tc.args), [tc.args]);
|
|
3012
3027
|
const questions = args?.questions ?? [];
|
|
3013
3028
|
const [active, setActive] = useState(0);
|
|
3014
3029
|
const [selections, setSelections] = useState(
|
|
@@ -3290,7 +3305,7 @@ function ClarifyLocked({
|
|
|
3290
3305
|
] });
|
|
3291
3306
|
}
|
|
3292
3307
|
function ArtifactToolBlock({ tc }) {
|
|
3293
|
-
const args =
|
|
3308
|
+
const args = parseArgs(tc.args) ?? {};
|
|
3294
3309
|
const status = effectiveStatus(tc);
|
|
3295
3310
|
const label = status === "running" ? "Creating artifact\u2026" : status === "error" ? "Tried to create" : "Created";
|
|
3296
3311
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-sm ", children: [
|
|
@@ -3304,7 +3319,7 @@ function firstLine(s) {
|
|
|
3304
3319
|
}
|
|
3305
3320
|
function DelegateToolBlock({ tc }) {
|
|
3306
3321
|
const [expanded, setExpanded] = useState(false);
|
|
3307
|
-
const args =
|
|
3322
|
+
const args = parseArgs(tc.args);
|
|
3308
3323
|
const goal = args?.goal ?? "";
|
|
3309
3324
|
const context = args?.context ?? "";
|
|
3310
3325
|
const agentType = args?.agent_type;
|
|
@@ -3414,8 +3429,8 @@ var TARGET_LABEL = {
|
|
|
3414
3429
|
};
|
|
3415
3430
|
function MemoryToolBlock({ tc }) {
|
|
3416
3431
|
const [isOpen, setIsOpen] = useState(false);
|
|
3417
|
-
const args =
|
|
3418
|
-
const result = tc.result ?
|
|
3432
|
+
const args = parseArgs(tc.args) ?? {};
|
|
3433
|
+
const result = tc.result ? parseArgs(tc.result) : null;
|
|
3419
3434
|
const action = args.action ?? "add";
|
|
3420
3435
|
const target = args.target ?? "memory";
|
|
3421
3436
|
const verb = ACTION_VERB[action] ?? action;
|
|
@@ -3493,8 +3508,8 @@ var ACTION_LABEL = {
|
|
|
3493
3508
|
remove_file: "Remove skill file"
|
|
3494
3509
|
};
|
|
3495
3510
|
function SkillManageToolBlock({ tc }) {
|
|
3496
|
-
const args =
|
|
3497
|
-
const result = tc.result ?
|
|
3511
|
+
const args = parseArgs(tc.args) ?? {};
|
|
3512
|
+
const result = tc.result ? parseArgs(tc.result) : null;
|
|
3498
3513
|
const action = args.action ?? "manage";
|
|
3499
3514
|
const label = ACTION_LABEL[action] ?? "Manage skill";
|
|
3500
3515
|
const target = args.file_path ? `${args.name ?? "?"}/${args.file_path}` : args.name ?? "?";
|
|
@@ -3515,8 +3530,8 @@ function firstLine2(value) {
|
|
|
3515
3530
|
return (index === -1 ? value : value.slice(0, index)).trim();
|
|
3516
3531
|
}
|
|
3517
3532
|
function CoordinatorToolBlock({ tc }) {
|
|
3518
|
-
const args =
|
|
3519
|
-
const result = tc.result ?
|
|
3533
|
+
const args = parseArgs(tc.args) ?? {};
|
|
3534
|
+
const result = tc.result ? parseArgs(tc.result) : null;
|
|
3520
3535
|
const failed = Boolean(result?.error);
|
|
3521
3536
|
let label = "Worker";
|
|
3522
3537
|
let target = "";
|
|
@@ -5467,7 +5482,7 @@ function exportArtifact(payload) {
|
|
|
5467
5482
|
};
|
|
5468
5483
|
case "chart":
|
|
5469
5484
|
return {
|
|
5470
|
-
text: JSON.stringify(payload.spec.
|
|
5485
|
+
text: JSON.stringify(payload.spec.chart_js, null, 2),
|
|
5471
5486
|
mime: "application/json",
|
|
5472
5487
|
extension: "json"
|
|
5473
5488
|
};
|
|
@@ -5528,7 +5543,7 @@ async function copyText(text) {
|
|
|
5528
5543
|
}
|
|
5529
5544
|
}
|
|
5530
5545
|
var ArtifactChart = lazy(
|
|
5531
|
-
() => import('./artifact-chart-
|
|
5546
|
+
() => import('./artifact-chart-X53FKRDZ.js').then((m) => ({ default: m.ArtifactChart }))
|
|
5532
5547
|
);
|
|
5533
5548
|
var KIND_LABEL = {
|
|
5534
5549
|
markdown: "Markdown document",
|
|
@@ -5653,7 +5668,7 @@ function ArtifactBody({
|
|
|
5653
5668
|
Suspense,
|
|
5654
5669
|
{
|
|
5655
5670
|
fallback: /* @__PURE__ */ jsx(Shimmer, { duration: 5, className: "text-sm text-muted-foreground", children: "Loading chart\u2026" }),
|
|
5656
|
-
children: /* @__PURE__ */ jsx(ArtifactChart, { spec: payload.spec })
|
|
5671
|
+
children: /* @__PURE__ */ jsx(ArtifactChart, { spec: payload.spec, fill })
|
|
5657
5672
|
}
|
|
5658
5673
|
);
|
|
5659
5674
|
case "html":
|
|
@@ -5873,7 +5888,7 @@ function OrphanSystemMarker({
|
|
|
5873
5888
|
);
|
|
5874
5889
|
}
|
|
5875
5890
|
if (message.systemKind === "error" && message.errorInfo) {
|
|
5876
|
-
return /* @__PURE__ */ jsx("div", { className: "mx-auto my-2 w-full max-w-4xl
|
|
5891
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto my-2 w-full max-w-4xl", children: /* @__PURE__ */ jsx(ErrorMessage, { errorInfo: message.errorInfo, onRetry }) });
|
|
5877
5892
|
}
|
|
5878
5893
|
return null;
|
|
5879
5894
|
}
|
|
@@ -5927,6 +5942,7 @@ function TimelineEntryItem({
|
|
|
5927
5942
|
] });
|
|
5928
5943
|
}
|
|
5929
5944
|
if (entry.kind === "tool") {
|
|
5945
|
+
const failureSummary = effectiveStatus(entry.tc) === "error" ? toolErrorSummary(entry.tc.result) : "";
|
|
5930
5946
|
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
5931
5947
|
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
5932
5948
|
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
@@ -5937,7 +5953,10 @@ function TimelineEntryItem({
|
|
|
5937
5953
|
}
|
|
5938
5954
|
)
|
|
5939
5955
|
] }),
|
|
5940
|
-
/* @__PURE__ */ jsx(TimelineContent, { children: entry.tc.cancelled ? /* @__PURE__ */ jsx(CancelledToolRow, { tc: entry.tc }) : /* @__PURE__ */
|
|
5956
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: entry.tc.cancelled ? /* @__PURE__ */ jsx(CancelledToolRow, { tc: entry.tc }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
5957
|
+
/* @__PURE__ */ jsx(ToolCallBlock, { tc: entry.tc, onFileSelect }),
|
|
5958
|
+
failureSummary ? /* @__PURE__ */ jsx("div", { className: "max-w-full truncate text-xs text-destructive", title: failureSummary, children: failureSummary }) : null
|
|
5959
|
+
] }) })
|
|
5941
5960
|
] });
|
|
5942
5961
|
}
|
|
5943
5962
|
if (entry.kind === "text") {
|
|
@@ -6055,6 +6074,7 @@ function ChatThread({
|
|
|
6055
6074
|
sessionId,
|
|
6056
6075
|
messages,
|
|
6057
6076
|
isRunning,
|
|
6077
|
+
isLoadingHistory = false,
|
|
6058
6078
|
onSend,
|
|
6059
6079
|
onStop,
|
|
6060
6080
|
onFileSelect,
|
|
@@ -6077,7 +6097,14 @@ function ChatThread({
|
|
|
6077
6097
|
}, [messages]);
|
|
6078
6098
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden bg-background text-sm", children: [
|
|
6079
6099
|
/* @__PURE__ */ jsxs(Conversation, { className: "relative flex-1 min-h-0", children: [
|
|
6080
|
-
/* @__PURE__ */ jsx(ConversationContent, { className: "mx-auto w-full max-w-
|
|
6100
|
+
/* @__PURE__ */ jsx(ConversationContent, { className: "mx-auto w-full max-w-4xl", children: messages.length === 0 && isLoadingHistory ? /* @__PURE__ */ jsx(
|
|
6101
|
+
ConversationEmptyState,
|
|
6102
|
+
{
|
|
6103
|
+
icon: /* @__PURE__ */ jsx(MessageSquareIcon, { className: "size-8 opacity-40" }),
|
|
6104
|
+
title: "Loading conversation",
|
|
6105
|
+
description: "Fetching the session history."
|
|
6106
|
+
}
|
|
6107
|
+
) : messages.length === 0 && !disabled ? /* @__PURE__ */ jsx(
|
|
6081
6108
|
ConversationEmptyState,
|
|
6082
6109
|
{
|
|
6083
6110
|
icon: /* @__PURE__ */ jsx(MessageSquareIcon, { className: "size-8 opacity-40" }),
|
|
@@ -6130,7 +6157,7 @@ function ChatThread({
|
|
|
6130
6157
|
] }) }),
|
|
6131
6158
|
/* @__PURE__ */ jsx(ConversationScrollButton, {})
|
|
6132
6159
|
] }),
|
|
6133
|
-
/* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-
|
|
6160
|
+
/* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-4xl px-6 pb-5 pt-3", children: [
|
|
6134
6161
|
retryIndicator && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(RetryBanner, { indicator: retryIndicator }) }),
|
|
6135
6162
|
/* @__PURE__ */ jsx(
|
|
6136
6163
|
ChatComposer,
|
|
@@ -6360,17 +6387,24 @@ function getLanguageHint(path) {
|
|
|
6360
6387
|
return map[ext] ?? "plaintext";
|
|
6361
6388
|
}
|
|
6362
6389
|
var SKELETON_WIDTHS = [70, 85, 55, 90, 60, 78, 45, 82, 65, 72];
|
|
6390
|
+
var PDF_WORKER_SRC = new URL(
|
|
6391
|
+
"pdfjs-dist/legacy/build/pdf.worker.mjs",
|
|
6392
|
+
import.meta.url
|
|
6393
|
+
).toString();
|
|
6363
6394
|
function FileViewer({
|
|
6364
6395
|
file,
|
|
6365
6396
|
loading,
|
|
6366
6397
|
error,
|
|
6398
|
+
downloadUrl,
|
|
6399
|
+
onDelete,
|
|
6367
6400
|
onClose
|
|
6368
6401
|
}) {
|
|
6369
6402
|
const visible = loading || file !== null || error !== null;
|
|
6370
6403
|
if (!visible) return null;
|
|
6371
6404
|
const fileName2 = file?.path.split("/").pop() ?? "File";
|
|
6372
6405
|
const lang = file ? getLanguageHint(file.path) : "";
|
|
6373
|
-
const
|
|
6406
|
+
const isPdf = file?.mime_type === "application/pdf" || file?.path.toLowerCase().endsWith(".pdf") || false;
|
|
6407
|
+
const isImage = file?.encoding === "base64" && !isPdf;
|
|
6374
6408
|
const HeaderIcon = isImage ? ImageIcon : FileTextIcon;
|
|
6375
6409
|
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col border-t border-line", children: [
|
|
6376
6410
|
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
|
|
@@ -6385,6 +6419,28 @@ function FileViewer({
|
|
|
6385
6419
|
] })
|
|
6386
6420
|
] })
|
|
6387
6421
|
] }),
|
|
6422
|
+
downloadUrl && /* @__PURE__ */ jsx(
|
|
6423
|
+
"a",
|
|
6424
|
+
{
|
|
6425
|
+
href: downloadUrl,
|
|
6426
|
+
download: fileName2,
|
|
6427
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
6428
|
+
"aria-label": `Download ${fileName2}`,
|
|
6429
|
+
title: "Download",
|
|
6430
|
+
children: /* @__PURE__ */ jsx(DownloadIcon, { className: "size-3.5" })
|
|
6431
|
+
}
|
|
6432
|
+
),
|
|
6433
|
+
onDelete && /* @__PURE__ */ jsx(
|
|
6434
|
+
"button",
|
|
6435
|
+
{
|
|
6436
|
+
type: "button",
|
|
6437
|
+
onClick: onDelete,
|
|
6438
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
|
|
6439
|
+
"aria-label": `Delete ${fileName2}`,
|
|
6440
|
+
title: "Delete",
|
|
6441
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { className: "size-3.5" })
|
|
6442
|
+
}
|
|
6443
|
+
),
|
|
6388
6444
|
/* @__PURE__ */ jsx(
|
|
6389
6445
|
"button",
|
|
6390
6446
|
{
|
|
@@ -6411,6 +6467,8 @@ function FileViewer({
|
|
|
6411
6467
|
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
6412
6468
|
/* @__PURE__ */ jsx("span", { children: error })
|
|
6413
6469
|
] }),
|
|
6470
|
+
file && isPdf && file.encoding !== "base64" && /* @__PURE__ */ jsx(FileViewerError, { message: "PDF preview requires base64 file content." }),
|
|
6471
|
+
file && isPdf && file.encoding === "base64" && /* @__PURE__ */ jsx(PdfPreview, { file, fileName: fileName2 }),
|
|
6414
6472
|
file && isImage && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsx(
|
|
6415
6473
|
"img",
|
|
6416
6474
|
{
|
|
@@ -6419,66 +6477,290 @@ function FileViewer({
|
|
|
6419
6477
|
className: "max-h-[60vh] max-w-full rounded object-contain"
|
|
6420
6478
|
}
|
|
6421
6479
|
) }),
|
|
6422
|
-
file && !isImage && /* @__PURE__ */ jsx("pre", { className: "wrap-break-word whitespace-pre-wrap p-3 text-[11px] leading-relaxed text-foreground", children: /* @__PURE__ */ jsx("code", { "data-language": lang, children: file.content }) })
|
|
6480
|
+
file && !isImage && !isPdf && /* @__PURE__ */ jsx("pre", { className: "wrap-break-word whitespace-pre-wrap p-3 text-[11px] leading-relaxed text-foreground", children: /* @__PURE__ */ jsx("code", { "data-language": lang, children: file.content }) })
|
|
6423
6481
|
] })
|
|
6424
6482
|
] });
|
|
6425
6483
|
}
|
|
6426
|
-
|
|
6427
|
-
"
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
"
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6484
|
+
function FileViewerError({ message }) {
|
|
6485
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
6486
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
6487
|
+
/* @__PURE__ */ jsx("span", { children: message })
|
|
6488
|
+
] });
|
|
6489
|
+
}
|
|
6490
|
+
function PdfPreview({
|
|
6491
|
+
file,
|
|
6492
|
+
fileName: fileName2
|
|
6493
|
+
}) {
|
|
6494
|
+
const containerRef = useRef(null);
|
|
6495
|
+
const viewerRef = useRef(null);
|
|
6496
|
+
const pdfViewerRef = useRef(null);
|
|
6497
|
+
const eventBusRef = useRef(null);
|
|
6498
|
+
const findControllerRef = useRef(null);
|
|
6499
|
+
const [error, setError] = useState(null);
|
|
6500
|
+
const [pageNumber, setPageNumber] = useState(1);
|
|
6501
|
+
const [pagesCount, setPagesCount] = useState(0);
|
|
6502
|
+
const [scale, setScale] = useState(1);
|
|
6503
|
+
const [query, setQuery] = useState("");
|
|
6504
|
+
useEffect(() => {
|
|
6505
|
+
let cancelled = false;
|
|
6506
|
+
let loadingTask = null;
|
|
6507
|
+
let pdfDocument = null;
|
|
6508
|
+
const renderPdf = async () => {
|
|
6509
|
+
setError(null);
|
|
6510
|
+
const container = containerRef.current;
|
|
6511
|
+
const viewerElement = viewerRef.current;
|
|
6512
|
+
if (!container || !viewerElement) return;
|
|
6513
|
+
const pdfBytes = decodeBase64(file.content);
|
|
6514
|
+
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
6515
|
+
pdfjs.GlobalWorkerOptions.workerSrc = PDF_WORKER_SRC;
|
|
6516
|
+
globalThis.pdfjsLib = pdfjs;
|
|
6517
|
+
const pdfViewerModule = await import('pdfjs-dist/web/pdf_viewer.mjs');
|
|
6518
|
+
loadingTask = pdfjs.getDocument({ data: pdfBytes });
|
|
6519
|
+
const pdf = await loadingTask.promise;
|
|
6520
|
+
pdfDocument = pdf;
|
|
6521
|
+
if (cancelled) return;
|
|
6522
|
+
const eventBus = new pdfViewerModule.EventBus();
|
|
6523
|
+
const linkService = new pdfViewerModule.PDFLinkService({ eventBus });
|
|
6524
|
+
const findController = new pdfViewerModule.PDFFindController({
|
|
6525
|
+
eventBus,
|
|
6526
|
+
linkService
|
|
6527
|
+
});
|
|
6528
|
+
const pdfViewer = new pdfViewerModule.PDFViewer({
|
|
6529
|
+
container,
|
|
6530
|
+
viewer: viewerElement,
|
|
6531
|
+
eventBus,
|
|
6532
|
+
linkService,
|
|
6533
|
+
findController,
|
|
6534
|
+
removePageBorders: true
|
|
6535
|
+
});
|
|
6536
|
+
linkService.setViewer(pdfViewer);
|
|
6537
|
+
linkService.setDocument(pdf);
|
|
6538
|
+
findController.setDocument(pdf);
|
|
6539
|
+
const onPagesInit = () => {
|
|
6540
|
+
pdfViewer.currentScaleValue = "page-width";
|
|
6541
|
+
setScale(pdfViewer.currentScale || 1);
|
|
6542
|
+
setPagesCount(pdfViewer.pagesCount);
|
|
6543
|
+
setPageNumber(pdfViewer.currentPageNumber);
|
|
6544
|
+
};
|
|
6545
|
+
const onPageChanging = (event) => {
|
|
6546
|
+
if (typeof event.pageNumber === "number") {
|
|
6547
|
+
setPageNumber(event.pageNumber);
|
|
6548
|
+
}
|
|
6549
|
+
};
|
|
6550
|
+
const onScaleChanging = (event) => {
|
|
6551
|
+
if (typeof event.scale === "number") {
|
|
6552
|
+
setScale(event.scale);
|
|
6553
|
+
}
|
|
6554
|
+
};
|
|
6555
|
+
eventBus.on("pagesinit", onPagesInit);
|
|
6556
|
+
eventBus.on("pagechanging", onPageChanging);
|
|
6557
|
+
eventBus.on("scalechanging", onScaleChanging);
|
|
6558
|
+
pdfViewerRef.current = pdfViewer;
|
|
6559
|
+
eventBusRef.current = eventBus;
|
|
6560
|
+
findControllerRef.current = findController;
|
|
6561
|
+
setPagesCount(pdf.numPages);
|
|
6562
|
+
pdfViewer.setDocument(pdf);
|
|
6563
|
+
};
|
|
6564
|
+
void renderPdf().catch((nextError) => {
|
|
6565
|
+
if (cancelled) return;
|
|
6566
|
+
if (nextError instanceof Error && nextError.name === "RenderingCancelledException") {
|
|
6567
|
+
return;
|
|
6568
|
+
}
|
|
6569
|
+
setError(formatPdfPreviewError(nextError));
|
|
6570
|
+
});
|
|
6571
|
+
return () => {
|
|
6572
|
+
cancelled = true;
|
|
6573
|
+
loadingTask?.destroy();
|
|
6574
|
+
pdfDocument?.destroy();
|
|
6575
|
+
pdfViewerRef.current?.cleanup();
|
|
6576
|
+
pdfViewerRef.current = null;
|
|
6577
|
+
eventBusRef.current = null;
|
|
6578
|
+
findControllerRef.current = null;
|
|
6579
|
+
};
|
|
6580
|
+
}, [file.content]);
|
|
6581
|
+
const setViewerPage = (nextPage) => {
|
|
6582
|
+
const viewer = pdfViewerRef.current;
|
|
6583
|
+
if (!viewer) return;
|
|
6584
|
+
const clampedPage = Math.min(
|
|
6585
|
+
Math.max(1, nextPage),
|
|
6586
|
+
Math.max(1, viewer.pagesCount)
|
|
6587
|
+
);
|
|
6588
|
+
viewer.currentPageNumber = clampedPage;
|
|
6589
|
+
setPageNumber(clampedPage);
|
|
6590
|
+
};
|
|
6591
|
+
const setViewerScale = (nextScale) => {
|
|
6592
|
+
const viewer = pdfViewerRef.current;
|
|
6593
|
+
if (!viewer) return;
|
|
6594
|
+
const clampedScale = Math.min(3, Math.max(0.5, nextScale));
|
|
6595
|
+
viewer.currentScale = clampedScale;
|
|
6596
|
+
setScale(clampedScale);
|
|
6597
|
+
};
|
|
6598
|
+
const runFind = (findPrevious = false) => {
|
|
6599
|
+
const eventBus = eventBusRef.current;
|
|
6600
|
+
if (!eventBus || !query.trim()) return;
|
|
6601
|
+
eventBus.dispatch("find", {
|
|
6602
|
+
source: eventBus,
|
|
6603
|
+
type: "again",
|
|
6604
|
+
query,
|
|
6605
|
+
phraseSearch: true,
|
|
6606
|
+
caseSensitive: false,
|
|
6607
|
+
entireWord: false,
|
|
6608
|
+
highlightAll: true,
|
|
6609
|
+
findPrevious,
|
|
6610
|
+
matchDiacritics: true
|
|
6611
|
+
});
|
|
6612
|
+
};
|
|
6613
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-full flex-col", children: [
|
|
6614
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-1.5 border-b border-line px-2 py-1.5", children: [
|
|
6615
|
+
/* @__PURE__ */ jsx(
|
|
6616
|
+
Button,
|
|
6617
|
+
{
|
|
6618
|
+
type: "button",
|
|
6619
|
+
variant: "ghost",
|
|
6620
|
+
size: "icon-xs",
|
|
6621
|
+
onClick: () => setViewerPage(pageNumber - 1),
|
|
6622
|
+
disabled: pageNumber <= 1,
|
|
6623
|
+
"aria-label": "Previous PDF page",
|
|
6624
|
+
title: "Previous page",
|
|
6625
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "size-3.5" })
|
|
6626
|
+
}
|
|
6627
|
+
),
|
|
6628
|
+
/* @__PURE__ */ jsx(
|
|
6629
|
+
Input,
|
|
6630
|
+
{
|
|
6631
|
+
type: "number",
|
|
6632
|
+
min: 1,
|
|
6633
|
+
max: pagesCount || 1,
|
|
6634
|
+
value: pageNumber,
|
|
6635
|
+
onChange: (event) => setViewerPage(Number(event.target.value)),
|
|
6636
|
+
"aria-label": "PDF page number",
|
|
6637
|
+
className: "h-7 w-12 border-input px-1 text-center text-xs"
|
|
6638
|
+
}
|
|
6639
|
+
),
|
|
6640
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
6641
|
+
"/ ",
|
|
6642
|
+
pagesCount || "-"
|
|
6643
|
+
] }),
|
|
6644
|
+
/* @__PURE__ */ jsx(
|
|
6645
|
+
Button,
|
|
6646
|
+
{
|
|
6647
|
+
type: "button",
|
|
6648
|
+
variant: "ghost",
|
|
6649
|
+
size: "icon-xs",
|
|
6650
|
+
onClick: () => setViewerPage(pageNumber + 1),
|
|
6651
|
+
disabled: pagesCount > 0 && pageNumber >= pagesCount,
|
|
6652
|
+
"aria-label": "Next PDF page",
|
|
6653
|
+
title: "Next page",
|
|
6654
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3.5" })
|
|
6655
|
+
}
|
|
6656
|
+
),
|
|
6657
|
+
/* @__PURE__ */ jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
6658
|
+
/* @__PURE__ */ jsx(
|
|
6659
|
+
Button,
|
|
6660
|
+
{
|
|
6661
|
+
type: "button",
|
|
6662
|
+
variant: "ghost",
|
|
6663
|
+
size: "icon-xs",
|
|
6664
|
+
onClick: () => setViewerScale(scale - 0.1),
|
|
6665
|
+
disabled: scale <= 0.5,
|
|
6666
|
+
"aria-label": "Zoom out PDF",
|
|
6667
|
+
title: "Zoom out",
|
|
6668
|
+
children: /* @__PURE__ */ jsx(MinusIcon, { className: "size-3.5" })
|
|
6669
|
+
}
|
|
6670
|
+
),
|
|
6671
|
+
/* @__PURE__ */ jsxs(
|
|
6672
|
+
"button",
|
|
6673
|
+
{
|
|
6674
|
+
type: "button",
|
|
6675
|
+
className: "h-7 min-w-12 px-1 text-xs text-muted-foreground hover:text-foreground",
|
|
6676
|
+
onClick: () => {
|
|
6677
|
+
const viewer = pdfViewerRef.current;
|
|
6678
|
+
if (!viewer) return;
|
|
6679
|
+
viewer.currentScaleValue = "page-width";
|
|
6680
|
+
setScale(viewer.currentScale || 1);
|
|
6681
|
+
},
|
|
6682
|
+
"aria-label": "Fit PDF to width",
|
|
6683
|
+
title: "Fit width",
|
|
6684
|
+
children: [
|
|
6685
|
+
Math.round(scale * 100),
|
|
6686
|
+
"%"
|
|
6687
|
+
]
|
|
6688
|
+
}
|
|
6689
|
+
),
|
|
6690
|
+
/* @__PURE__ */ jsx(
|
|
6691
|
+
Button,
|
|
6692
|
+
{
|
|
6693
|
+
type: "button",
|
|
6694
|
+
variant: "ghost",
|
|
6695
|
+
size: "icon-xs",
|
|
6696
|
+
onClick: () => setViewerScale(scale + 0.1),
|
|
6697
|
+
disabled: scale >= 3,
|
|
6698
|
+
"aria-label": "Zoom in PDF",
|
|
6699
|
+
title: "Zoom in",
|
|
6700
|
+
children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" })
|
|
6701
|
+
}
|
|
6702
|
+
),
|
|
6703
|
+
/* @__PURE__ */ jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
6704
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "size-3.5 text-muted-foreground" }),
|
|
6705
|
+
/* @__PURE__ */ jsx(
|
|
6706
|
+
Input,
|
|
6707
|
+
{
|
|
6708
|
+
type: "search",
|
|
6709
|
+
value: query,
|
|
6710
|
+
onChange: (event) => setQuery(event.target.value),
|
|
6711
|
+
onKeyDown: (event) => {
|
|
6712
|
+
if (event.key === "Enter") runFind(event.shiftKey);
|
|
6713
|
+
},
|
|
6714
|
+
placeholder: "Find",
|
|
6715
|
+
"aria-label": "Find in PDF",
|
|
6716
|
+
className: "h-7 w-28 border-input px-1 text-xs"
|
|
6717
|
+
}
|
|
6718
|
+
),
|
|
6719
|
+
/* @__PURE__ */ jsx(
|
|
6720
|
+
Button,
|
|
6721
|
+
{
|
|
6722
|
+
type: "button",
|
|
6723
|
+
variant: "ghost",
|
|
6724
|
+
size: "xs",
|
|
6725
|
+
onClick: () => runFind(false),
|
|
6726
|
+
disabled: !query.trim(),
|
|
6727
|
+
children: "Find"
|
|
6728
|
+
}
|
|
6729
|
+
)
|
|
6730
|
+
] }),
|
|
6731
|
+
error && /* @__PURE__ */ jsxs("div", { className: "flex w-full items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
6732
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
6733
|
+
/* @__PURE__ */ jsx("span", { children: error })
|
|
6734
|
+
] }),
|
|
6735
|
+
!error && /* @__PURE__ */ jsx("div", { className: "relative h-[70vh] min-h-[420px] flex-1 bg-muted/20", children: /* @__PURE__ */ jsx(
|
|
6736
|
+
"div",
|
|
6737
|
+
{
|
|
6738
|
+
ref: containerRef,
|
|
6739
|
+
"aria-label": `PDF viewer for ${fileName2}`,
|
|
6740
|
+
className: "absolute inset-0 overflow-auto",
|
|
6741
|
+
children: /* @__PURE__ */ jsx("div", { ref: viewerRef, className: "pdfViewer" })
|
|
6742
|
+
}
|
|
6743
|
+
) })
|
|
6744
|
+
] });
|
|
6745
|
+
}
|
|
6746
|
+
function decodeBase64(content) {
|
|
6747
|
+
const binary = globalThis.atob(content);
|
|
6748
|
+
const bytes = new Uint8Array(binary.length);
|
|
6749
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
6750
|
+
bytes[index] = binary.charCodeAt(index);
|
|
6751
|
+
}
|
|
6752
|
+
return bytes;
|
|
6753
|
+
}
|
|
6754
|
+
function formatPdfPreviewError(error) {
|
|
6755
|
+
if (error instanceof Error && (error.name === "InvalidCharacterError" || error.message === "Invalid character")) {
|
|
6756
|
+
return "PDF preview data is not valid base64.";
|
|
6757
|
+
}
|
|
6758
|
+
return error instanceof Error ? error.message : "Failed to render PDF preview.";
|
|
6759
|
+
}
|
|
6473
6760
|
var SKELETON_WIDTHS2 = [75, 60, 90, 65, 80, 70, 85, 55];
|
|
6474
|
-
var DEFAULT_WIDTH =
|
|
6761
|
+
var DEFAULT_WIDTH = 400;
|
|
6475
6762
|
var MIN_WIDTH = 300;
|
|
6476
6763
|
var MAX_WIDTH = 900;
|
|
6477
|
-
function isViewable(name) {
|
|
6478
|
-
const dot = name.lastIndexOf(".");
|
|
6479
|
-
const ext = dot >= 0 ? name.slice(dot).toLowerCase() : "";
|
|
6480
|
-
return TEXT_EXTENSIONS.has(ext) || IMAGE_EXTENSIONS.has(ext);
|
|
6481
|
-
}
|
|
6482
6764
|
function collectExpandedPaths(entries, depth = 0) {
|
|
6483
6765
|
const paths = [];
|
|
6484
6766
|
for (const entry of entries) {
|
|
@@ -6503,8 +6785,8 @@ function findEntry(entries, path) {
|
|
|
6503
6785
|
}
|
|
6504
6786
|
function RenderEntries({
|
|
6505
6787
|
entries,
|
|
6506
|
-
|
|
6507
|
-
|
|
6788
|
+
onDelete,
|
|
6789
|
+
downloadUrlFor
|
|
6508
6790
|
}) {
|
|
6509
6791
|
return /* @__PURE__ */ jsx(Fragment, { children: entries.map((entry) => {
|
|
6510
6792
|
if (entry.kind === "dir") {
|
|
@@ -6512,27 +6794,26 @@ function RenderEntries({
|
|
|
6512
6794
|
RenderEntries,
|
|
6513
6795
|
{
|
|
6514
6796
|
entries: entry.children,
|
|
6515
|
-
|
|
6516
|
-
|
|
6797
|
+
onDelete,
|
|
6798
|
+
downloadUrlFor
|
|
6517
6799
|
}
|
|
6518
6800
|
) }, entry.path);
|
|
6519
6801
|
}
|
|
6520
|
-
const
|
|
6802
|
+
const fileName2 = entry.name;
|
|
6521
6803
|
return /* @__PURE__ */ jsxs(FileTreeFile, { name: entry.name, path: entry.path, children: [
|
|
6522
6804
|
/* @__PURE__ */ jsx("span", { className: "size-4 shrink-0" }),
|
|
6523
6805
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: entry.name }),
|
|
6524
6806
|
entry.size != null && /* @__PURE__ */ jsx("span", { className: "ml-1 shrink-0 text-xs text-muted-foreground/60", children: formatFileSize(entry.size) }),
|
|
6525
6807
|
/* @__PURE__ */ jsxs("div", { className: "ml-1 flex shrink-0 items-center gap-0 opacity-0 transition-opacity group-hover:opacity-100", children: [
|
|
6526
|
-
|
|
6527
|
-
"
|
|
6808
|
+
/* @__PURE__ */ jsx(
|
|
6809
|
+
"a",
|
|
6528
6810
|
{
|
|
6529
|
-
|
|
6811
|
+
href: downloadUrlFor(entry.path),
|
|
6812
|
+
download: fileName2,
|
|
6530
6813
|
className: "rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
6531
|
-
onClick: (event) =>
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
},
|
|
6535
|
-
title: "View",
|
|
6814
|
+
onClick: (event) => event.stopPropagation(),
|
|
6815
|
+
title: "Download",
|
|
6816
|
+
"aria-label": `Download ${fileName2}`,
|
|
6536
6817
|
children: /* @__PURE__ */ jsx(DownloadIcon, { className: "size-3" })
|
|
6537
6818
|
}
|
|
6538
6819
|
),
|
|
@@ -6546,6 +6827,7 @@ function RenderEntries({
|
|
|
6546
6827
|
onDelete(entry.path);
|
|
6547
6828
|
},
|
|
6548
6829
|
title: "Delete",
|
|
6830
|
+
"aria-label": `Delete ${fileName2}`,
|
|
6549
6831
|
children: /* @__PURE__ */ jsx(TrashIcon, { className: "size-3" })
|
|
6550
6832
|
}
|
|
6551
6833
|
)
|
|
@@ -6558,6 +6840,8 @@ function WorkspacePanel({
|
|
|
6558
6840
|
sessionId,
|
|
6559
6841
|
selectedPath,
|
|
6560
6842
|
onSelectedPathChange,
|
|
6843
|
+
collapsed = false,
|
|
6844
|
+
onCollapsedChange,
|
|
6561
6845
|
disabled = false
|
|
6562
6846
|
}) {
|
|
6563
6847
|
const fileInputRef = useRef(null);
|
|
@@ -6752,6 +7036,25 @@ function WorkspacePanel({
|
|
|
6752
7036
|
window.removeEventListener("mouseup", onMouseUp);
|
|
6753
7037
|
};
|
|
6754
7038
|
}, []);
|
|
7039
|
+
if (collapsed) {
|
|
7040
|
+
return /* @__PURE__ */ jsx(
|
|
7041
|
+
"aside",
|
|
7042
|
+
{
|
|
7043
|
+
role: "button",
|
|
7044
|
+
tabIndex: 0,
|
|
7045
|
+
className: "relative z-10 flex min-h-0 w-10 shrink-0 cursor-pointer items-center justify-center border-l border-muted-foreground/20 bg-card text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30",
|
|
7046
|
+
"aria-label": "Expand workspace",
|
|
7047
|
+
onClick: () => onCollapsedChange?.(false),
|
|
7048
|
+
onKeyDown: (event) => {
|
|
7049
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
7050
|
+
event.preventDefault();
|
|
7051
|
+
onCollapsedChange?.(false);
|
|
7052
|
+
}
|
|
7053
|
+
},
|
|
7054
|
+
children: /* @__PURE__ */ jsx(FolderOpenIcon, { className: "size-4 text-amber-500" })
|
|
7055
|
+
}
|
|
7056
|
+
);
|
|
7057
|
+
}
|
|
6755
7058
|
return /* @__PURE__ */ jsxs(
|
|
6756
7059
|
"aside",
|
|
6757
7060
|
{
|
|
@@ -6784,6 +7087,19 @@ function WorkspacePanel({
|
|
|
6784
7087
|
/* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium text-foreground", children: rootName }),
|
|
6785
7088
|
/* @__PURE__ */ jsx("div", { className: "truncate text-xs text-faint", children: "Workspace" })
|
|
6786
7089
|
] }),
|
|
7090
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
7091
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
7092
|
+
Button,
|
|
7093
|
+
{
|
|
7094
|
+
variant: "ghost",
|
|
7095
|
+
size: "icon-sm",
|
|
7096
|
+
onClick: () => onCollapsedChange?.(true),
|
|
7097
|
+
"aria-label": "Collapse workspace",
|
|
7098
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-4" })
|
|
7099
|
+
}
|
|
7100
|
+
) }),
|
|
7101
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Collapse" })
|
|
7102
|
+
] }),
|
|
6787
7103
|
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
6788
7104
|
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
6789
7105
|
Button,
|
|
@@ -6863,8 +7179,8 @@ function WorkspacePanel({
|
|
|
6863
7179
|
RenderEntries,
|
|
6864
7180
|
{
|
|
6865
7181
|
entries,
|
|
6866
|
-
|
|
6867
|
-
|
|
7182
|
+
onDelete: setDeleteTarget,
|
|
7183
|
+
downloadUrlFor: (path) => sessionId ? adapter.getWorkspaceDownloadUrl({ sessionId, path }) : "#"
|
|
6868
7184
|
}
|
|
6869
7185
|
)
|
|
6870
7186
|
}
|
|
@@ -6876,7 +7192,13 @@ function WorkspacePanel({
|
|
|
6876
7192
|
file,
|
|
6877
7193
|
loading: fileLoading,
|
|
6878
7194
|
error: fileError,
|
|
7195
|
+
downloadUrl: file && sessionId ? adapter.getWorkspaceDownloadUrl({
|
|
7196
|
+
sessionId,
|
|
7197
|
+
path: file.path
|
|
7198
|
+
}) : null,
|
|
7199
|
+
onDelete: file ? () => setDeleteTarget(file.path) : null,
|
|
6879
7200
|
onClose: () => {
|
|
7201
|
+
onSelectedPathChange(null);
|
|
6880
7202
|
setFile(null);
|
|
6881
7203
|
setFileError(null);
|
|
6882
7204
|
}
|
|
@@ -6977,10 +7299,11 @@ var EMPTY_TOKEN_USAGE = {
|
|
|
6977
7299
|
contextWindow: 0,
|
|
6978
7300
|
model: ""
|
|
6979
7301
|
};
|
|
6980
|
-
function createInitialAgentChatState() {
|
|
7302
|
+
function createInitialAgentChatState(options = {}) {
|
|
6981
7303
|
return {
|
|
6982
7304
|
messages: [],
|
|
6983
7305
|
isRunning: false,
|
|
7306
|
+
isLoadingHistory: options.isLoadingHistory ?? false,
|
|
6984
7307
|
tokenUsage: EMPTY_TOKEN_USAGE,
|
|
6985
7308
|
retryIndicator: null,
|
|
6986
7309
|
lastEventId: 0,
|
|
@@ -6992,6 +7315,7 @@ function createInitialAgentChatState() {
|
|
|
6992
7315
|
function applyAgentChatEvent(state, event) {
|
|
6993
7316
|
let nextState = {
|
|
6994
7317
|
...state,
|
|
7318
|
+
isLoadingHistory: false,
|
|
6995
7319
|
lastEventId: Math.max(state.lastEventId, event.eventId),
|
|
6996
7320
|
sessionDone: state.sessionDone || event.type === "session.done"
|
|
6997
7321
|
};
|
|
@@ -7525,11 +7849,12 @@ function useAgentChatRuntime({
|
|
|
7525
7849
|
onSessionChange
|
|
7526
7850
|
}) {
|
|
7527
7851
|
const [state, setState] = useState(
|
|
7528
|
-
() => createInitialAgentChatState()
|
|
7852
|
+
() => createInitialAgentChatState({ isLoadingHistory: Boolean(sessionId) })
|
|
7529
7853
|
);
|
|
7530
7854
|
const stateRef = useRef(state);
|
|
7531
7855
|
const streamRef = useRef(null);
|
|
7532
7856
|
const reconnectTimerRef = useRef(null);
|
|
7857
|
+
const previousSessionIdRef = useRef(sessionId);
|
|
7533
7858
|
useEffect(() => {
|
|
7534
7859
|
stateRef.current = state;
|
|
7535
7860
|
}, [state]);
|
|
@@ -7545,6 +7870,8 @@ function useAgentChatRuntime({
|
|
|
7545
7870
|
stream?.close();
|
|
7546
7871
|
}, []);
|
|
7547
7872
|
useEffect(() => {
|
|
7873
|
+
const previousSessionId = previousSessionIdRef.current;
|
|
7874
|
+
previousSessionIdRef.current = sessionId;
|
|
7548
7875
|
clearReconnectTimer();
|
|
7549
7876
|
closeStream();
|
|
7550
7877
|
if (!sessionId) {
|
|
@@ -7552,11 +7879,11 @@ function useAgentChatRuntime({
|
|
|
7552
7879
|
return;
|
|
7553
7880
|
}
|
|
7554
7881
|
let cancelled = false;
|
|
7555
|
-
const connect = () => {
|
|
7882
|
+
const connect = (after) => {
|
|
7556
7883
|
if (cancelled) return;
|
|
7557
7884
|
const stream = adapter.openEventStream({
|
|
7558
7885
|
sessionId,
|
|
7559
|
-
after: stateRef.current.lastEventId
|
|
7886
|
+
after: after ?? stateRef.current.lastEventId
|
|
7560
7887
|
});
|
|
7561
7888
|
streamRef.current = stream;
|
|
7562
7889
|
for (const eventType of AGENT_CHAT_LISTENED_EVENTS) {
|
|
@@ -7579,14 +7906,32 @@ function useAgentChatRuntime({
|
|
|
7579
7906
|
streamRef.current = null;
|
|
7580
7907
|
}
|
|
7581
7908
|
if (!stateRef.current.sessionDone && !cancelled) {
|
|
7582
|
-
reconnectTimerRef.current = setTimeout(connect, 3e3);
|
|
7909
|
+
reconnectTimerRef.current = setTimeout(() => connect(), 3e3);
|
|
7583
7910
|
}
|
|
7584
7911
|
};
|
|
7585
7912
|
};
|
|
7586
|
-
|
|
7587
|
-
|
|
7913
|
+
const currentState = stateRef.current;
|
|
7914
|
+
const preservePendingFirstMessage = previousSessionId === null && currentState.isRunning && currentState.messages.some(
|
|
7915
|
+
(message) => message.role === "user" && message.id.startsWith("local-")
|
|
7916
|
+
);
|
|
7917
|
+
const initialState = preservePendingFirstMessage ? {
|
|
7918
|
+
...createInitialAgentChatState({ isLoadingHistory: false }),
|
|
7919
|
+
messages: currentState.messages,
|
|
7920
|
+
isRunning: true
|
|
7921
|
+
} : createInitialAgentChatState({
|
|
7922
|
+
isLoadingHistory: true
|
|
7923
|
+
});
|
|
7924
|
+
stateRef.current = initialState;
|
|
7925
|
+
setState(initialState);
|
|
7926
|
+
connect(0);
|
|
7588
7927
|
adapter.getSession({ sessionId }).then((session) => {
|
|
7589
7928
|
if (cancelled) return;
|
|
7929
|
+
if (session.messageCount === 0) {
|
|
7930
|
+
setState((prev) => ({
|
|
7931
|
+
...prev,
|
|
7932
|
+
isLoadingHistory: false
|
|
7933
|
+
}));
|
|
7934
|
+
}
|
|
7590
7935
|
if (isTerminalStatus(session.status)) {
|
|
7591
7936
|
setState((prev) => ({
|
|
7592
7937
|
...prev,
|
|
@@ -7669,13 +8014,18 @@ function useAgentChatRuntime({
|
|
|
7669
8014
|
}, []);
|
|
7670
8015
|
const send = useCallback(
|
|
7671
8016
|
async (content) => {
|
|
8017
|
+
markSending(content);
|
|
7672
8018
|
if (!sessionId) {
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
8019
|
+
try {
|
|
8020
|
+
const session = await adapter.createSession({ agentId });
|
|
8021
|
+
onSessionChange?.(session.id);
|
|
8022
|
+
await adapter.sendMessage({ sessionId: session.id, content });
|
|
8023
|
+
} catch (error) {
|
|
8024
|
+
markSendError(error instanceof Error ? error.message : "send failed");
|
|
8025
|
+
throw error;
|
|
8026
|
+
}
|
|
7676
8027
|
return;
|
|
7677
8028
|
}
|
|
7678
|
-
markSending(content);
|
|
7679
8029
|
try {
|
|
7680
8030
|
await adapter.sendMessage({ sessionId, content });
|
|
7681
8031
|
} catch (error) {
|
|
@@ -7712,6 +8062,7 @@ function useAgentChatRuntime({
|
|
|
7712
8062
|
return {
|
|
7713
8063
|
messages: state.messages,
|
|
7714
8064
|
isRunning: state.isRunning,
|
|
8065
|
+
isLoadingHistory: state.isLoadingHistory,
|
|
7715
8066
|
tokenUsage: state.tokenUsage,
|
|
7716
8067
|
retryIndicator: state.retryIndicator,
|
|
7717
8068
|
send,
|
|
@@ -7748,6 +8099,7 @@ function AgentChat({
|
|
|
7748
8099
|
disabled
|
|
7749
8100
|
}) {
|
|
7750
8101
|
const [workspacePath, setWorkspacePath] = useState(null);
|
|
8102
|
+
const [workspaceCollapsed, setWorkspaceCollapsed] = useState(false);
|
|
7751
8103
|
const runtime = useAgentChatRuntime({
|
|
7752
8104
|
adapter,
|
|
7753
8105
|
agentId,
|
|
@@ -7779,6 +8131,7 @@ function AgentChat({
|
|
|
7779
8131
|
sessionId,
|
|
7780
8132
|
messages: runtime.messages,
|
|
7781
8133
|
isRunning: runtime.isRunning,
|
|
8134
|
+
isLoadingHistory: runtime.isLoadingHistory,
|
|
7782
8135
|
onSend: (content) => void runtime.send(content),
|
|
7783
8136
|
onStop: () => void runtime.stop(),
|
|
7784
8137
|
onRetry: runtime.retry,
|
|
@@ -7795,6 +8148,8 @@ function AgentChat({
|
|
|
7795
8148
|
sessionId,
|
|
7796
8149
|
selectedPath: workspacePath,
|
|
7797
8150
|
onSelectedPathChange: setWorkspacePath,
|
|
8151
|
+
collapsed: workspaceCollapsed,
|
|
8152
|
+
onCollapsedChange: setWorkspaceCollapsed,
|
|
7798
8153
|
disabled
|
|
7799
8154
|
}
|
|
7800
8155
|
)
|
|
@@ -7865,6 +8220,20 @@ function mergeTreeNodes(groups) {
|
|
|
7865
8220
|
}
|
|
7866
8221
|
return Array.from(byId.values());
|
|
7867
8222
|
}
|
|
8223
|
+
function pruneDeletedSessionNodes(nodes, deletedSessionId) {
|
|
8224
|
+
const deletedIds = /* @__PURE__ */ new Set([deletedSessionId]);
|
|
8225
|
+
let changed = true;
|
|
8226
|
+
while (changed) {
|
|
8227
|
+
changed = false;
|
|
8228
|
+
for (const node of nodes) {
|
|
8229
|
+
if (node.parentId && deletedIds.has(node.parentId) && !deletedIds.has(node.id)) {
|
|
8230
|
+
deletedIds.add(node.id);
|
|
8231
|
+
changed = true;
|
|
8232
|
+
}
|
|
8233
|
+
}
|
|
8234
|
+
}
|
|
8235
|
+
return nodes.filter((node) => !deletedIds.has(node.id));
|
|
8236
|
+
}
|
|
7868
8237
|
function formatSessionTime(value) {
|
|
7869
8238
|
const date = new Date(value);
|
|
7870
8239
|
if (Number.isNaN(date.getTime())) return "";
|
|
@@ -7981,11 +8350,12 @@ function SessionTreePanel({
|
|
|
7981
8350
|
title = "Running",
|
|
7982
8351
|
sessionListLimit = DEFAULT_SESSION_LIST_LIMIT,
|
|
7983
8352
|
hideRoot = false,
|
|
8353
|
+
hideHeader = false,
|
|
8354
|
+
loadList = false,
|
|
7984
8355
|
onSessionSelect,
|
|
7985
8356
|
onSessionDelete
|
|
7986
8357
|
}) {
|
|
7987
8358
|
const [nodes, setNodes] = useState([]);
|
|
7988
|
-
const [loading, setLoading] = useState(false);
|
|
7989
8359
|
const [error, setError] = useState(null);
|
|
7990
8360
|
const [hasEverLoaded, setHasEverLoaded] = useState(false);
|
|
7991
8361
|
const [deletingSessionId, setDeletingSessionId] = useState(
|
|
@@ -7997,18 +8367,16 @@ function SessionTreePanel({
|
|
|
7997
8367
|
const resetContext = useRef(null);
|
|
7998
8368
|
const refetch = useCallback(
|
|
7999
8369
|
async (opts) => {
|
|
8000
|
-
const canLoadSessionList = Boolean(
|
|
8370
|
+
const canLoadSessionList = Boolean(loadList && adapter.listSessions);
|
|
8001
8371
|
const canLoadSessionTree = Boolean(sessionId && adapter.getSessionTree);
|
|
8002
8372
|
if (!canLoadSessionList && !canLoadSessionTree) {
|
|
8003
8373
|
setNodes([]);
|
|
8004
8374
|
setHasEverLoaded(true);
|
|
8005
|
-
setLoading(false);
|
|
8006
8375
|
return;
|
|
8007
8376
|
}
|
|
8008
8377
|
const currentRequestId = ++requestId.current;
|
|
8009
|
-
if (!opts?.silent) setLoading(true);
|
|
8010
8378
|
try {
|
|
8011
|
-
const sessionListPromise =
|
|
8379
|
+
const sessionListPromise = loadList && adapter.listSessions ? adapter.listSessions({
|
|
8012
8380
|
agentId,
|
|
8013
8381
|
limit: sessionListLimit
|
|
8014
8382
|
}) : Promise.resolve(null);
|
|
@@ -8034,13 +8402,9 @@ function SessionTreePanel({
|
|
|
8034
8402
|
if (!opts?.silent) {
|
|
8035
8403
|
setError(e instanceof Error ? e.message : "Failed to load tree");
|
|
8036
8404
|
}
|
|
8037
|
-
} finally {
|
|
8038
|
-
if (mounted.current && currentRequestId === requestId.current && !opts?.silent) {
|
|
8039
|
-
setLoading(false);
|
|
8040
|
-
}
|
|
8041
8405
|
}
|
|
8042
8406
|
},
|
|
8043
|
-
[adapter, agentId, sessionId, sessionListLimit]
|
|
8407
|
+
[adapter, agentId, loadList, sessionId, sessionListLimit]
|
|
8044
8408
|
);
|
|
8045
8409
|
useEffect(() => {
|
|
8046
8410
|
mounted.current = true;
|
|
@@ -8050,8 +8414,8 @@ function SessionTreePanel({
|
|
|
8050
8414
|
}, []);
|
|
8051
8415
|
useEffect(() => {
|
|
8052
8416
|
const previous = resetContext.current;
|
|
8053
|
-
const shouldReset = !previous || previous.
|
|
8054
|
-
resetContext.current = {
|
|
8417
|
+
const shouldReset = !previous || previous.loadList !== loadList || previous.agentId !== agentId || previous.sessionListLimit !== sessionListLimit;
|
|
8418
|
+
resetContext.current = { loadList, agentId, sessionListLimit };
|
|
8055
8419
|
if (shouldReset) {
|
|
8056
8420
|
setNodes([]);
|
|
8057
8421
|
setHasEverLoaded(false);
|
|
@@ -8059,7 +8423,7 @@ function SessionTreePanel({
|
|
|
8059
8423
|
}
|
|
8060
8424
|
setError(null);
|
|
8061
8425
|
void refetch();
|
|
8062
|
-
}, [adapter, agentId, refetch, sessionListLimit]);
|
|
8426
|
+
}, [adapter, agentId, loadList, refetch, sessionListLimit]);
|
|
8063
8427
|
const runningCount = useMemo(
|
|
8064
8428
|
() => nodes.filter((n) => n.status === "active").length,
|
|
8065
8429
|
[nodes]
|
|
@@ -8096,6 +8460,11 @@ function SessionTreePanel({
|
|
|
8096
8460
|
setDeletingSessionId(id);
|
|
8097
8461
|
try {
|
|
8098
8462
|
await adapter.deleteSession({ sessionId: id });
|
|
8463
|
+
setNodes((current) => {
|
|
8464
|
+
const next = pruneDeletedSessionNodes(current, id);
|
|
8465
|
+
lastFingerprint.current = treeFingerprint(next);
|
|
8466
|
+
return next;
|
|
8467
|
+
});
|
|
8099
8468
|
onSessionDelete?.(id);
|
|
8100
8469
|
await refetch({ silent: true });
|
|
8101
8470
|
} catch (e) {
|
|
@@ -8110,24 +8479,12 @@ function SessionTreePanel({
|
|
|
8110
8479
|
if (nodes.length === 0) return null;
|
|
8111
8480
|
const topLevel = hideRoot ? roots.flatMap((r) => r.children) : roots;
|
|
8112
8481
|
if (topLevel.length === 0) return null;
|
|
8113
|
-
return /* @__PURE__ */ jsxs(
|
|
8114
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-3 py-2 text-xs font-semibold uppercase tracking-wide", children: [
|
|
8482
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8483
|
+
!hideHeader && /* @__PURE__ */ jsxs("div", { className: "border-t border-line flex items-center gap-1.5 px-3 py-2 text-xs font-semibold uppercase tracking-wide", children: [
|
|
8115
8484
|
/* @__PURE__ */ jsx(UsersIcon, { className: "w-3.5 h-3.5" }),
|
|
8116
8485
|
/* @__PURE__ */ jsx("span", { children: title }),
|
|
8117
8486
|
runningCount > 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", className: "h-4 px-1.5 text-[10px] ml-auto", children: runningCount })
|
|
8118
8487
|
] }),
|
|
8119
|
-
loading && /* @__PURE__ */ jsx(
|
|
8120
|
-
"div",
|
|
8121
|
-
{
|
|
8122
|
-
className: "px-3 py-2",
|
|
8123
|
-
role: "status",
|
|
8124
|
-
"aria-label": "Loading sessions",
|
|
8125
|
-
children: /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
8126
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-28" }),
|
|
8127
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" })
|
|
8128
|
-
] })
|
|
8129
|
-
}
|
|
8130
|
-
),
|
|
8131
8488
|
error && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-destructive", children: error }),
|
|
8132
8489
|
!error && /* @__PURE__ */ jsx("div", { className: "px-1 pb-2", children: topLevel.map((entry) => /* @__PURE__ */ jsx(
|
|
8133
8490
|
TreeNodeRow,
|