@invergent/agent-chat-react 1.8.1 → 1.9.0
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 +957 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +127 -1
- package/dist/index.d.ts +127 -1
- package/dist/index.js +946 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -794,6 +794,29 @@ var ConversationScrollButton = ({
|
|
|
794
794
|
);
|
|
795
795
|
};
|
|
796
796
|
|
|
797
|
+
// src/components/ui/separator.tsx
|
|
798
|
+
init_utils();
|
|
799
|
+
function Separator({
|
|
800
|
+
className,
|
|
801
|
+
orientation = "horizontal",
|
|
802
|
+
decorative = true,
|
|
803
|
+
...props
|
|
804
|
+
}) {
|
|
805
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
806
|
+
radixUi.Separator.Root,
|
|
807
|
+
{
|
|
808
|
+
"data-slot": "separator",
|
|
809
|
+
decorative,
|
|
810
|
+
orientation,
|
|
811
|
+
className: cn(
|
|
812
|
+
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
|
|
813
|
+
className
|
|
814
|
+
),
|
|
815
|
+
...props
|
|
816
|
+
}
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
|
|
797
820
|
// src/components/ai-elements/message.tsx
|
|
798
821
|
init_utils();
|
|
799
822
|
var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4462,32 +4485,28 @@ function WebSearchGroupBlock({ tcs }) {
|
|
|
4462
4485
|
}
|
|
4463
4486
|
var ChatMessage = react.memo(function ChatMessage2({
|
|
4464
4487
|
message,
|
|
4465
|
-
isLast,
|
|
4466
4488
|
onFileSelect
|
|
4467
4489
|
}) {
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
] }) });
|
|
4489
|
-
}
|
|
4490
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AssistantMessage, { message, isLast, onFileSelect });
|
|
4490
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "user", children: /* @__PURE__ */ jsxRuntime.jsxs(MessageContent, { children: [
|
|
4491
|
+
message.content,
|
|
4492
|
+
message.images && message.images.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 mt-2", children: message.images.map((img, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4493
|
+
"img",
|
|
4494
|
+
{
|
|
4495
|
+
src: img.data,
|
|
4496
|
+
alt: "Attached",
|
|
4497
|
+
className: "max-w-64 max-h-48 rounded-lg border border-border object-contain"
|
|
4498
|
+
},
|
|
4499
|
+
i
|
|
4500
|
+
)) }),
|
|
4501
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 mt-2", children: message.attachments.map((a, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4502
|
+
AttachmentChip,
|
|
4503
|
+
{
|
|
4504
|
+
attachment: a,
|
|
4505
|
+
onSelect: onFileSelect
|
|
4506
|
+
},
|
|
4507
|
+
a.path ?? `pending-${i}`
|
|
4508
|
+
)) })
|
|
4509
|
+
] }) });
|
|
4491
4510
|
});
|
|
4492
4511
|
function iconForMime(mime) {
|
|
4493
4512
|
if (!mime) return lucideReact.File;
|
|
@@ -4542,28 +4561,6 @@ function AttachmentChip({
|
|
|
4542
4561
|
}
|
|
4543
4562
|
);
|
|
4544
4563
|
}
|
|
4545
|
-
function AssistantMessage({
|
|
4546
|
-
message,
|
|
4547
|
-
isLast,
|
|
4548
|
-
onFileSelect
|
|
4549
|
-
}) {
|
|
4550
|
-
const hasReasoning = !!message.reasoning;
|
|
4551
|
-
const hasToolCalls = !!(message.toolCalls && message.toolCalls.length > 0);
|
|
4552
|
-
const isStreaming = message.status === "streaming" && isLast;
|
|
4553
|
-
const hasContent = !!(message.content && message.content !== message.reasoning);
|
|
4554
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsxs(MessageContent, { children: [
|
|
4555
|
-
hasReasoning && /* @__PURE__ */ jsxRuntime.jsxs(Reasoning, { isStreaming: isStreaming && !hasContent && !hasToolCalls, children: [
|
|
4556
|
-
/* @__PURE__ */ jsxRuntime.jsx(ReasoningTrigger, {}),
|
|
4557
|
-
/* @__PURE__ */ jsxRuntime.jsx(ReasoningContent, { children: message.reasoning })
|
|
4558
|
-
] }),
|
|
4559
|
-
hasToolCalls && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex flex-col gap-8", children: message.toolCalls.map((tc) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallBlock, { tc, onFileSelect }, tc.id)) }),
|
|
4560
|
-
hasContent && /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: message.content }),
|
|
4561
|
-
isStreaming && !hasContent && !hasToolCalls && !hasReasoning && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 py-1 text-muted-foreground", children: [
|
|
4562
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block size-1.5 animate-pulse rounded-full bg-primary" }),
|
|
4563
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: "Thinking..." })
|
|
4564
|
-
] })
|
|
4565
|
-
] }) });
|
|
4566
|
-
}
|
|
4567
4564
|
|
|
4568
4565
|
// src/components/ui/command.tsx
|
|
4569
4566
|
init_utils();
|
|
@@ -6156,6 +6153,11 @@ function ChatComposerInner({
|
|
|
6156
6153
|
{ value: "/goal pause", label: "/goal pause", description: "Pause automatic goal continuation" },
|
|
6157
6154
|
{ value: "/goal resume", label: "/goal resume", description: "Resume a paused goal" },
|
|
6158
6155
|
{ value: "/goal clear", label: "/goal clear", description: "Clear the current goal" },
|
|
6156
|
+
{ value: "/mission ", label: "/mission", description: "Start an orchestrated rubric-judged mission" },
|
|
6157
|
+
{ value: "/mission status", label: "/mission status", description: "Show current mission status" },
|
|
6158
|
+
{ value: "/mission pause", label: "/mission pause", description: "Pause the mission evaluator" },
|
|
6159
|
+
{ value: "/mission resume", label: "/mission resume", description: "Resume a paused mission" },
|
|
6160
|
+
{ value: "/mission cancel", label: "/mission cancel", description: "Cancel the mission" },
|
|
6159
6161
|
{ value: "/loop", label: "/loop", description: "Schedule recurring prompt" },
|
|
6160
6162
|
{ value: "/loop list", label: "/loop list", description: "List active loops" },
|
|
6161
6163
|
{ value: "/loop cancel", label: "/loop cancel", description: "Cancel a loop by ID" }
|
|
@@ -6461,6 +6463,54 @@ function ChatComposerInner({
|
|
|
6461
6463
|
}
|
|
6462
6464
|
);
|
|
6463
6465
|
}
|
|
6466
|
+
var MIN_CPS = 40;
|
|
6467
|
+
var MAX_CPS = 240;
|
|
6468
|
+
var DRAIN_SECONDS = 0.25;
|
|
6469
|
+
var SNAP_LAG = 800;
|
|
6470
|
+
var MAX_FRAME_DT = 0.1;
|
|
6471
|
+
function useSmoothStream(target, isStreaming) {
|
|
6472
|
+
const [displayedLen, setDisplayedLen] = react.useState(
|
|
6473
|
+
() => isStreaming ? 0 : target.length
|
|
6474
|
+
);
|
|
6475
|
+
const targetRef = react.useRef(target);
|
|
6476
|
+
targetRef.current = target;
|
|
6477
|
+
react.useEffect(() => {
|
|
6478
|
+
setDisplayedLen((cur) => cur > target.length ? target.length : cur);
|
|
6479
|
+
}, [target]);
|
|
6480
|
+
const isActive = isStreaming || displayedLen < target.length;
|
|
6481
|
+
react.useEffect(() => {
|
|
6482
|
+
if (!isActive) return;
|
|
6483
|
+
let raf = 0;
|
|
6484
|
+
let carry = 0;
|
|
6485
|
+
let lastTime = 0;
|
|
6486
|
+
const tick = (now) => {
|
|
6487
|
+
const dt = lastTime ? Math.min(MAX_FRAME_DT, (now - lastTime) / 1e3) : 0;
|
|
6488
|
+
lastTime = now;
|
|
6489
|
+
setDisplayedLen((current) => {
|
|
6490
|
+
const targetLen = targetRef.current.length;
|
|
6491
|
+
const lag = targetLen - current;
|
|
6492
|
+
if (lag <= 0) return current;
|
|
6493
|
+
if (lag >= SNAP_LAG) {
|
|
6494
|
+
carry = 0;
|
|
6495
|
+
return targetLen;
|
|
6496
|
+
}
|
|
6497
|
+
const cps = Math.min(
|
|
6498
|
+
MAX_CPS,
|
|
6499
|
+
Math.max(MIN_CPS, lag / DRAIN_SECONDS)
|
|
6500
|
+
);
|
|
6501
|
+
carry += cps * dt;
|
|
6502
|
+
const step = Math.floor(carry);
|
|
6503
|
+
if (step <= 0) return current;
|
|
6504
|
+
carry -= step;
|
|
6505
|
+
return Math.min(targetLen, current + step);
|
|
6506
|
+
});
|
|
6507
|
+
raf = requestAnimationFrame(tick);
|
|
6508
|
+
};
|
|
6509
|
+
raf = requestAnimationFrame(tick);
|
|
6510
|
+
return () => cancelAnimationFrame(raf);
|
|
6511
|
+
}, [isActive]);
|
|
6512
|
+
return displayedLen >= target.length ? target : target.slice(0, displayedLen);
|
|
6513
|
+
}
|
|
6464
6514
|
|
|
6465
6515
|
// src/components/ai-elements/artifact.tsx
|
|
6466
6516
|
init_utils();
|
|
@@ -7069,7 +7119,12 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
|
7069
7119
|
}
|
|
7070
7120
|
}
|
|
7071
7121
|
if (effectiveHasContent) {
|
|
7072
|
-
entries.push({
|
|
7122
|
+
entries.push({
|
|
7123
|
+
kind: "text",
|
|
7124
|
+
key: `${msg.id}-text`,
|
|
7125
|
+
content: msg.content,
|
|
7126
|
+
isStreaming
|
|
7127
|
+
});
|
|
7073
7128
|
}
|
|
7074
7129
|
const hasRunningTool = hasToolCalls && msg.toolCalls.some(
|
|
7075
7130
|
(tc) => tc.status === "running"
|
|
@@ -7249,16 +7304,7 @@ function TimelineEntryItem({
|
|
|
7249
7304
|
onFileSelect
|
|
7250
7305
|
}) {
|
|
7251
7306
|
if (entry.kind === "reasoning") {
|
|
7252
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
7253
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7254
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7255
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2" })
|
|
7256
|
-
] }),
|
|
7257
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(Reasoning, { isStreaming: entry.isStreaming, children: [
|
|
7258
|
-
/* @__PURE__ */ jsxRuntime.jsx(ReasoningTrigger, {}),
|
|
7259
|
-
/* @__PURE__ */ jsxRuntime.jsx(ReasoningContent, { children: entry.reasoning })
|
|
7260
|
-
] }) })
|
|
7261
|
-
] });
|
|
7307
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ReasoningEntry, { entry, step });
|
|
7262
7308
|
}
|
|
7263
7309
|
if (entry.kind === "tool") {
|
|
7264
7310
|
const rawStatus = effectiveStatus(entry.tc);
|
|
@@ -7310,13 +7356,7 @@ function TimelineEntryItem({
|
|
|
7310
7356
|
] });
|
|
7311
7357
|
}
|
|
7312
7358
|
if (entry.kind === "text") {
|
|
7313
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
7314
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7315
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7316
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
|
|
7317
|
-
] }),
|
|
7318
|
-
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: entry.content }) })
|
|
7319
|
-
] });
|
|
7359
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextEntry, { entry, step });
|
|
7320
7360
|
}
|
|
7321
7361
|
if (entry.kind === "skill_invoked") {
|
|
7322
7362
|
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
@@ -7360,6 +7400,35 @@ function TimelineEntryItem({
|
|
|
7360
7400
|
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) })
|
|
7361
7401
|
] });
|
|
7362
7402
|
}
|
|
7403
|
+
function ReasoningEntry({
|
|
7404
|
+
entry,
|
|
7405
|
+
step
|
|
7406
|
+
}) {
|
|
7407
|
+
const reasoning = useSmoothStream(entry.reasoning, entry.isStreaming);
|
|
7408
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7409
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7410
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7411
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2" })
|
|
7412
|
+
] }),
|
|
7413
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(Reasoning, { isStreaming: entry.isStreaming, children: [
|
|
7414
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReasoningTrigger, {}),
|
|
7415
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReasoningContent, { children: reasoning })
|
|
7416
|
+
] }) })
|
|
7417
|
+
] });
|
|
7418
|
+
}
|
|
7419
|
+
function TextEntry({
|
|
7420
|
+
entry,
|
|
7421
|
+
step
|
|
7422
|
+
}) {
|
|
7423
|
+
const content = useSmoothStream(entry.content, entry.isStreaming);
|
|
7424
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
7425
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
7426
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7427
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
|
|
7428
|
+
] }),
|
|
7429
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: content }) })
|
|
7430
|
+
] });
|
|
7431
|
+
}
|
|
7363
7432
|
function AssistantGroup({
|
|
7364
7433
|
messages,
|
|
7365
7434
|
lastGlobalIndex,
|
|
@@ -7506,7 +7575,6 @@ function ChatThread({
|
|
|
7506
7575
|
ChatMessage,
|
|
7507
7576
|
{
|
|
7508
7577
|
message: msg,
|
|
7509
|
-
isLast: group.lastGlobalIndex === messages.length - 1,
|
|
7510
7578
|
onFileSelect
|
|
7511
7579
|
},
|
|
7512
7580
|
msg.id
|
|
@@ -10538,10 +10606,822 @@ function useInboxUnreadCount(adapter) {
|
|
|
10538
10606
|
}, [adapter]);
|
|
10539
10607
|
return { unreadCount, hasLoaded, error };
|
|
10540
10608
|
}
|
|
10609
|
+
|
|
10610
|
+
// src/components/ui/card.tsx
|
|
10541
10611
|
init_utils();
|
|
10542
|
-
|
|
10543
|
-
|
|
10612
|
+
function Card({
|
|
10613
|
+
className,
|
|
10614
|
+
size = "default",
|
|
10615
|
+
...props
|
|
10616
|
+
}) {
|
|
10617
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10618
|
+
"div",
|
|
10619
|
+
{
|
|
10620
|
+
"data-slot": "card",
|
|
10621
|
+
"data-size": size,
|
|
10622
|
+
className: cn(
|
|
10623
|
+
"group/card flex flex-col gap-8 overflow-hidden bg-card py-8 text-sm text-card-foreground shadow-sm ring-1 ring-foreground/5 has-[>img:first-child]:pt-0 data-[size=sm]:gap-5 data-[size=sm]:py-5 *:[img:first-child]:rounded-none *:[img:last-child]:rounded-none",
|
|
10624
|
+
className
|
|
10625
|
+
),
|
|
10626
|
+
...props
|
|
10627
|
+
}
|
|
10628
|
+
);
|
|
10629
|
+
}
|
|
10630
|
+
function CardHeader({ className, ...props }) {
|
|
10631
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10632
|
+
"div",
|
|
10633
|
+
{
|
|
10634
|
+
"data-slot": "card-header",
|
|
10635
|
+
className: cn(
|
|
10636
|
+
"group/card-header @container/card-header grid auto-rows-min items-start gap-1.5 rounded-none px-8 group-data-[size=sm]/card:px-5 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-8 group-data-[size=sm]/card:[.border-b]:pb-5",
|
|
10637
|
+
className
|
|
10638
|
+
),
|
|
10639
|
+
...props
|
|
10640
|
+
}
|
|
10641
|
+
);
|
|
10642
|
+
}
|
|
10643
|
+
function CardTitle({ className, ...props }) {
|
|
10644
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10645
|
+
"div",
|
|
10646
|
+
{
|
|
10647
|
+
"data-slot": "card-title",
|
|
10648
|
+
className: cn(
|
|
10649
|
+
"font-heading text-lg font-semibold tracking-wider uppercase",
|
|
10650
|
+
className
|
|
10651
|
+
),
|
|
10652
|
+
...props
|
|
10653
|
+
}
|
|
10654
|
+
);
|
|
10655
|
+
}
|
|
10656
|
+
function CardDescription({ className, ...props }) {
|
|
10657
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10658
|
+
"div",
|
|
10659
|
+
{
|
|
10660
|
+
"data-slot": "card-description",
|
|
10661
|
+
className: cn("text-sm leading-relaxed text-muted-foreground", className),
|
|
10662
|
+
...props
|
|
10663
|
+
}
|
|
10664
|
+
);
|
|
10665
|
+
}
|
|
10666
|
+
function CardContent({ className, ...props }) {
|
|
10667
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10668
|
+
"div",
|
|
10669
|
+
{
|
|
10670
|
+
"data-slot": "card-content",
|
|
10671
|
+
className: cn("px-8 group-data-[size=sm]/card:px-5", className),
|
|
10672
|
+
...props
|
|
10673
|
+
}
|
|
10674
|
+
);
|
|
10675
|
+
}
|
|
10676
|
+
|
|
10677
|
+
// src/components/missions/mission-derive.ts
|
|
10678
|
+
var ACTIVE_MISSION_STATUSES = /* @__PURE__ */ new Set(["active", "paused"]);
|
|
10679
|
+
function isTerminalMissionStatus(status) {
|
|
10680
|
+
return !ACTIVE_MISSION_STATUSES.has(status);
|
|
10681
|
+
}
|
|
10682
|
+
function missionTaskBucket(status) {
|
|
10683
|
+
if (status === "done") return "done";
|
|
10684
|
+
if (status === "blocked") return "blocked";
|
|
10685
|
+
if (status === "failed" || status === "cancelled") {
|
|
10686
|
+
return "failed_or_cancelled";
|
|
10687
|
+
}
|
|
10688
|
+
return "in_flight";
|
|
10689
|
+
}
|
|
10690
|
+
function groupMissionTasksByBucket(tasks) {
|
|
10691
|
+
const buckets = {
|
|
10692
|
+
in_flight: [],
|
|
10693
|
+
done: [],
|
|
10694
|
+
blocked: [],
|
|
10695
|
+
failed_or_cancelled: []
|
|
10696
|
+
};
|
|
10697
|
+
for (const t of tasks) {
|
|
10698
|
+
buckets[missionTaskBucket(t.status)].push(t);
|
|
10699
|
+
}
|
|
10700
|
+
return buckets;
|
|
10701
|
+
}
|
|
10702
|
+
function deriveMissionWorkerActivityLabel(worker) {
|
|
10703
|
+
const kind = worker.latestEventKind;
|
|
10704
|
+
if (kind === "tool.call" && worker.latestEventSummary) {
|
|
10705
|
+
return `tool: ${truncate2(worker.latestEventSummary, 80)}`;
|
|
10706
|
+
}
|
|
10707
|
+
if (kind === "llm.response") {
|
|
10708
|
+
return "thinking";
|
|
10709
|
+
}
|
|
10710
|
+
if (kind === "tool.result") {
|
|
10711
|
+
return "received tool result";
|
|
10712
|
+
}
|
|
10713
|
+
if (kind && worker.latestEventSummary) {
|
|
10714
|
+
return `${kind}: ${truncate2(worker.latestEventSummary, 60)}`;
|
|
10715
|
+
}
|
|
10716
|
+
return worker.sessionStatus || "active";
|
|
10717
|
+
}
|
|
10718
|
+
function truncate2(s, max) {
|
|
10719
|
+
if (s.length <= max) return s;
|
|
10720
|
+
return `${s.slice(0, max - 1)}\u2026`;
|
|
10721
|
+
}
|
|
10722
|
+
var DEFAULT_POLL_INTERVAL_MS = 5e3;
|
|
10723
|
+
var INITIAL_STATE = {
|
|
10724
|
+
mission: null,
|
|
10725
|
+
tasks: [],
|
|
10726
|
+
workers: [],
|
|
10727
|
+
loading: true,
|
|
10728
|
+
error: null
|
|
10729
|
+
};
|
|
10730
|
+
function requireMissionApi(adapter) {
|
|
10731
|
+
const required = {
|
|
10732
|
+
getMission: adapter.getMission,
|
|
10733
|
+
getMissionTasks: adapter.getMissionTasks,
|
|
10734
|
+
getMissionWorkers: adapter.getMissionWorkers,
|
|
10735
|
+
pauseMission: adapter.pauseMission,
|
|
10736
|
+
resumeMission: adapter.resumeMission,
|
|
10737
|
+
cancelMission: adapter.cancelMission
|
|
10738
|
+
};
|
|
10739
|
+
for (const [name, fn] of Object.entries(required)) {
|
|
10740
|
+
if (typeof fn !== "function") {
|
|
10741
|
+
throw new Error(
|
|
10742
|
+
`MissionDashboard requires adapter.${name} to be implemented; this adapter is missing the mission surface.`
|
|
10743
|
+
);
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
10746
|
+
return required;
|
|
10747
|
+
}
|
|
10748
|
+
function MissionDashboard({
|
|
10749
|
+
adapter,
|
|
10750
|
+
missionId,
|
|
10751
|
+
pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,
|
|
10752
|
+
onNavigateBack,
|
|
10753
|
+
onOpenTranscript
|
|
10754
|
+
}) {
|
|
10755
|
+
const api = react.useMemo(() => requireMissionApi(adapter), [adapter]);
|
|
10756
|
+
const [state, setState] = react.useState(INITIAL_STATE);
|
|
10757
|
+
const [cancelOpen, setCancelOpen] = react.useState(false);
|
|
10758
|
+
const [cancelCascade, setCancelCascade] = react.useState(false);
|
|
10759
|
+
const [busy, setBusy] = react.useState(false);
|
|
10760
|
+
const isMounted = react.useRef(true);
|
|
10761
|
+
react.useEffect(() => {
|
|
10762
|
+
isMounted.current = true;
|
|
10763
|
+
return () => {
|
|
10764
|
+
isMounted.current = false;
|
|
10765
|
+
};
|
|
10766
|
+
}, []);
|
|
10767
|
+
const refresh = react.useCallback(async () => {
|
|
10768
|
+
try {
|
|
10769
|
+
const [mission2, tasksResp, workersResp] = await Promise.all([
|
|
10770
|
+
api.getMission({ missionId }),
|
|
10771
|
+
api.getMissionTasks({ missionId }),
|
|
10772
|
+
api.getMissionWorkers({ missionId })
|
|
10773
|
+
]);
|
|
10774
|
+
if (!isMounted.current) return;
|
|
10775
|
+
setState({
|
|
10776
|
+
mission: mission2,
|
|
10777
|
+
tasks: tasksResp.tasks,
|
|
10778
|
+
workers: workersResp.workers,
|
|
10779
|
+
loading: false,
|
|
10780
|
+
error: null
|
|
10781
|
+
});
|
|
10782
|
+
} catch (err) {
|
|
10783
|
+
if (!isMounted.current) return;
|
|
10784
|
+
setState((prev) => ({
|
|
10785
|
+
...prev,
|
|
10786
|
+
loading: false,
|
|
10787
|
+
error: err instanceof Error ? err.message : String(err)
|
|
10788
|
+
}));
|
|
10789
|
+
}
|
|
10790
|
+
}, [api, missionId]);
|
|
10791
|
+
react.useEffect(() => {
|
|
10792
|
+
void refresh();
|
|
10793
|
+
}, [refresh]);
|
|
10794
|
+
react.useEffect(() => {
|
|
10795
|
+
if (!state.mission) return;
|
|
10796
|
+
if (isTerminalMissionStatus(state.mission.status)) return;
|
|
10797
|
+
const id = window.setInterval(() => {
|
|
10798
|
+
void refresh();
|
|
10799
|
+
}, pollIntervalMs);
|
|
10800
|
+
return () => {
|
|
10801
|
+
window.clearInterval(id);
|
|
10802
|
+
};
|
|
10803
|
+
}, [refresh, state.mission, pollIntervalMs]);
|
|
10804
|
+
const taskBuckets = react.useMemo(
|
|
10805
|
+
() => groupMissionTasksByBucket(state.tasks),
|
|
10806
|
+
[state.tasks]
|
|
10807
|
+
);
|
|
10808
|
+
const runningWorkerCount = react.useMemo(
|
|
10809
|
+
() => state.workers.filter((w) => w.taskStatus === "running").length,
|
|
10810
|
+
[state.workers]
|
|
10811
|
+
);
|
|
10812
|
+
if (state.loading && !state.mission) {
|
|
10813
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center p-6", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-5 animate-spin text-foreground/70" }) });
|
|
10814
|
+
}
|
|
10815
|
+
if (state.error && !state.mission) {
|
|
10816
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-3", children: [
|
|
10817
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-destructive", children: [
|
|
10818
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "size-4" }),
|
|
10819
|
+
"Failed to load mission: ",
|
|
10820
|
+
state.error
|
|
10821
|
+
] }),
|
|
10822
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10823
|
+
Button,
|
|
10824
|
+
{
|
|
10825
|
+
variant: "outline",
|
|
10826
|
+
size: "sm",
|
|
10827
|
+
onClick: () => {
|
|
10828
|
+
setState(INITIAL_STATE);
|
|
10829
|
+
void refresh();
|
|
10830
|
+
},
|
|
10831
|
+
children: [
|
|
10832
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "size-4" }),
|
|
10833
|
+
" Retry"
|
|
10834
|
+
]
|
|
10835
|
+
}
|
|
10836
|
+
)
|
|
10837
|
+
] });
|
|
10838
|
+
}
|
|
10839
|
+
const mission = state.mission;
|
|
10840
|
+
const doPause = async () => {
|
|
10841
|
+
setBusy(true);
|
|
10842
|
+
try {
|
|
10843
|
+
await api.pauseMission({ missionId });
|
|
10844
|
+
await refresh();
|
|
10845
|
+
} finally {
|
|
10846
|
+
setBusy(false);
|
|
10847
|
+
}
|
|
10848
|
+
};
|
|
10849
|
+
const doResume = async () => {
|
|
10850
|
+
setBusy(true);
|
|
10851
|
+
try {
|
|
10852
|
+
await api.resumeMission({ missionId });
|
|
10853
|
+
await refresh();
|
|
10854
|
+
} finally {
|
|
10855
|
+
setBusy(false);
|
|
10856
|
+
}
|
|
10857
|
+
};
|
|
10858
|
+
const doCancel = async () => {
|
|
10859
|
+
setBusy(true);
|
|
10860
|
+
try {
|
|
10861
|
+
await api.cancelMission({
|
|
10862
|
+
missionId,
|
|
10863
|
+
cascadeToWorkers: cancelCascade
|
|
10864
|
+
});
|
|
10865
|
+
await refresh();
|
|
10866
|
+
setCancelOpen(false);
|
|
10867
|
+
} finally {
|
|
10868
|
+
setBusy(false);
|
|
10869
|
+
}
|
|
10870
|
+
};
|
|
10871
|
+
const statusVariant = mission.status === "satisfied" ? "default" : mission.status === "failed" || mission.status === "cancelled" ? "destructive" : "secondary";
|
|
10872
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6 p-6 max-w-6xl mx-auto", children: [
|
|
10873
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
|
|
10874
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
10875
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
10876
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "wrap-break-word -uppercase text-sm", children: mission.description }),
|
|
10877
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardDescription, { className: "wrap-break-word text-foreground/70", children: [
|
|
10878
|
+
"Rubric: ",
|
|
10879
|
+
mission.rubric
|
|
10880
|
+
] }),
|
|
10881
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 pt-2 text-xs text-foreground/70", children: [
|
|
10882
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant, className: "font-mono text-foreground", children: mission.status }),
|
|
10883
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-primary", children: [
|
|
10884
|
+
"Iteration ",
|
|
10885
|
+
mission.iteration,
|
|
10886
|
+
"/",
|
|
10887
|
+
mission.maxIterations
|
|
10888
|
+
] }),
|
|
10889
|
+
mission.lastEvaluationResult ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
10890
|
+
"Last verdict:",
|
|
10891
|
+
" ",
|
|
10892
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-primary", children: mission.lastEvaluationResult })
|
|
10893
|
+
] }) : null
|
|
10894
|
+
] })
|
|
10895
|
+
] }),
|
|
10896
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: ACTIVE_MISSION_STATUSES.has(mission.status) ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10897
|
+
mission.status === "active" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10898
|
+
Button,
|
|
10899
|
+
{
|
|
10900
|
+
size: "sm",
|
|
10901
|
+
variant: "outline",
|
|
10902
|
+
onClick: doPause,
|
|
10903
|
+
disabled: busy,
|
|
10904
|
+
children: [
|
|
10905
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "size-4" }),
|
|
10906
|
+
" Pause"
|
|
10907
|
+
]
|
|
10908
|
+
}
|
|
10909
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10910
|
+
Button,
|
|
10911
|
+
{
|
|
10912
|
+
size: "sm",
|
|
10913
|
+
variant: "outline",
|
|
10914
|
+
onClick: doResume,
|
|
10915
|
+
disabled: busy,
|
|
10916
|
+
children: [
|
|
10917
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-4" }),
|
|
10918
|
+
" Resume"
|
|
10919
|
+
]
|
|
10920
|
+
}
|
|
10921
|
+
),
|
|
10922
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10923
|
+
Button,
|
|
10924
|
+
{
|
|
10925
|
+
size: "sm",
|
|
10926
|
+
variant: "destructive",
|
|
10927
|
+
onClick: () => {
|
|
10928
|
+
setCancelCascade(false);
|
|
10929
|
+
setCancelOpen(true);
|
|
10930
|
+
},
|
|
10931
|
+
disabled: busy,
|
|
10932
|
+
children: [
|
|
10933
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "size-4" }),
|
|
10934
|
+
" Cancel"
|
|
10935
|
+
]
|
|
10936
|
+
}
|
|
10937
|
+
)
|
|
10938
|
+
] }) : onNavigateBack ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "outline", onClick: onNavigateBack, children: "Back" }) : null })
|
|
10939
|
+
] }) }),
|
|
10940
|
+
mission.lastEvaluationFeedback ? /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-2", children: [
|
|
10941
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: "Evaluator feedback" }),
|
|
10942
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationFeedback }),
|
|
10943
|
+
mission.lastEvaluationExplanation ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-foreground/70 whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationExplanation }) : null
|
|
10944
|
+
] }) : null
|
|
10945
|
+
] }),
|
|
10946
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
|
|
10947
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { children: [
|
|
10948
|
+
"Tasks (",
|
|
10949
|
+
state.tasks.length,
|
|
10950
|
+
")"
|
|
10951
|
+
] }) }),
|
|
10952
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-4", children: [
|
|
10953
|
+
["in_flight", "blocked", "done", "failed_or_cancelled"].map((bucket) => {
|
|
10954
|
+
const rows = taskBuckets[bucket];
|
|
10955
|
+
if (rows.length === 0) return null;
|
|
10956
|
+
const heading = {
|
|
10957
|
+
in_flight: "In flight",
|
|
10958
|
+
blocked: "Blocked",
|
|
10959
|
+
done: "Done",
|
|
10960
|
+
failed_or_cancelled: "Failed / cancelled"
|
|
10961
|
+
}[bucket];
|
|
10962
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
10963
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: [
|
|
10964
|
+
heading,
|
|
10965
|
+
" (",
|
|
10966
|
+
rows.length,
|
|
10967
|
+
")"
|
|
10968
|
+
] }),
|
|
10969
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1.5", children: rows.map((task) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
10970
|
+
"li",
|
|
10971
|
+
{
|
|
10972
|
+
className: "flex items-start justify-between gap-3 rounded border border-border/40 px-3 py-2 text-sm",
|
|
10973
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
|
|
10974
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10975
|
+
task.agentDefName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-foreground/70", children: task.agentDefName }) : null,
|
|
10976
|
+
task.attemptCount > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-foreground/70", children: [
|
|
10977
|
+
"attempt ",
|
|
10978
|
+
task.attemptCount,
|
|
10979
|
+
"/",
|
|
10980
|
+
task.maxAttempts
|
|
10981
|
+
] }) : null
|
|
10982
|
+
] }),
|
|
10983
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm wrap-break-word", children: task.goal }),
|
|
10984
|
+
task.parentIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-foreground/70", children: [
|
|
10985
|
+
"after:",
|
|
10986
|
+
" ",
|
|
10987
|
+
task.parentIds.map((p) => p.slice(0, 8)).join(", ")
|
|
10988
|
+
] }) : null,
|
|
10989
|
+
task.result ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs whitespace-pre-wrap bg-muted/30 rounded px-2 py-1 max-h-32 overflow-auto", children: task.result }) : null,
|
|
10990
|
+
task.resultMetadata ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs whitespace-pre-wrap bg-muted/30 rounded px-2 py-1 max-h-32 overflow-auto", children: JSON.stringify(task.resultMetadata, null, 2) }) : null
|
|
10991
|
+
] })
|
|
10992
|
+
},
|
|
10993
|
+
task.id
|
|
10994
|
+
)) })
|
|
10995
|
+
] }, bucket);
|
|
10996
|
+
}),
|
|
10997
|
+
state.tasks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground/70", children: "No tasks spawned yet." }) : null
|
|
10998
|
+
] })
|
|
10999
|
+
] }),
|
|
11000
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
|
|
11001
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { children: [
|
|
11002
|
+
"Live workers (",
|
|
11003
|
+
state.workers.length,
|
|
11004
|
+
")"
|
|
11005
|
+
] }) }),
|
|
11006
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: state.workers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground/70", children: "No workers attached to this mission right now." }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1.5", children: state.workers.map((w) => {
|
|
11007
|
+
const onTranscriptClick = (e) => {
|
|
11008
|
+
if (onOpenTranscript) {
|
|
11009
|
+
e.preventDefault();
|
|
11010
|
+
onOpenTranscript(w.workerSessionId);
|
|
11011
|
+
}
|
|
11012
|
+
};
|
|
11013
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11014
|
+
"li",
|
|
11015
|
+
{
|
|
11016
|
+
className: "flex items-start justify-between gap-3 rounded border border-border/40 px-3 py-2 text-sm",
|
|
11017
|
+
children: [
|
|
11018
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
|
|
11019
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
11020
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { className: "text-foreground/70", children: w.taskStatus }),
|
|
11021
|
+
w.agentDefName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-foreground/70", children: w.agentDefName }) : null
|
|
11022
|
+
] }),
|
|
11023
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm wrap-break-word", children: deriveMissionWorkerActivityLabel(w) }),
|
|
11024
|
+
w.latestEventAt ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-foreground/70", children: new Date(w.latestEventAt).toLocaleTimeString() }) : null
|
|
11025
|
+
] }),
|
|
11026
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11027
|
+
"a",
|
|
11028
|
+
{
|
|
11029
|
+
href: w.transcriptUrl,
|
|
11030
|
+
target: "_blank",
|
|
11031
|
+
rel: "noreferrer",
|
|
11032
|
+
onClick: onTranscriptClick,
|
|
11033
|
+
className: "text-xs text-primary hover:underline self-start",
|
|
11034
|
+
children: "View session"
|
|
11035
|
+
}
|
|
11036
|
+
)
|
|
11037
|
+
]
|
|
11038
|
+
},
|
|
11039
|
+
w.workerSessionId
|
|
11040
|
+
);
|
|
11041
|
+
}) }) })
|
|
11042
|
+
] }),
|
|
11043
|
+
/* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
|
|
11044
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center text-xs text-foreground/70", children: [
|
|
11045
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
11046
|
+
"Auto-refresh every ",
|
|
11047
|
+
pollIntervalMs / 1e3,
|
|
11048
|
+
"s while mission is active."
|
|
11049
|
+
] }),
|
|
11050
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11051
|
+
Button,
|
|
11052
|
+
{
|
|
11053
|
+
variant: "ghost",
|
|
11054
|
+
size: "sm",
|
|
11055
|
+
onClick: () => {
|
|
11056
|
+
void refresh();
|
|
11057
|
+
},
|
|
11058
|
+
disabled: busy,
|
|
11059
|
+
children: [
|
|
11060
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "size-4" }),
|
|
11061
|
+
" Refresh"
|
|
11062
|
+
]
|
|
11063
|
+
}
|
|
11064
|
+
)
|
|
11065
|
+
] }),
|
|
11066
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11067
|
+
Dialog,
|
|
11068
|
+
{
|
|
11069
|
+
open: cancelOpen,
|
|
11070
|
+
onOpenChange: (open) => {
|
|
11071
|
+
if (!open && !busy) setCancelOpen(false);
|
|
11072
|
+
},
|
|
11073
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
11074
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
11075
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Cancel mission?" }),
|
|
11076
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "This terminates the mission and clears its evaluator loop." })
|
|
11077
|
+
] }),
|
|
11078
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
11079
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11080
|
+
"input",
|
|
11081
|
+
{
|
|
11082
|
+
type: "checkbox",
|
|
11083
|
+
checked: cancelCascade,
|
|
11084
|
+
onChange: (e) => setCancelCascade(e.target.checked)
|
|
11085
|
+
}
|
|
11086
|
+
),
|
|
11087
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
11088
|
+
"Also cancel ",
|
|
11089
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: runningWorkerCount }),
|
|
11090
|
+
" running worker",
|
|
11091
|
+
runningWorkerCount === 1 ? "" : "s",
|
|
11092
|
+
" (sends an interrupt to each worker session)."
|
|
11093
|
+
] })
|
|
11094
|
+
] }),
|
|
11095
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { children: [
|
|
11096
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11097
|
+
Button,
|
|
11098
|
+
{
|
|
11099
|
+
variant: "outline",
|
|
11100
|
+
size: "sm",
|
|
11101
|
+
onClick: () => setCancelOpen(false),
|
|
11102
|
+
disabled: busy,
|
|
11103
|
+
children: "Keep mission"
|
|
11104
|
+
}
|
|
11105
|
+
),
|
|
11106
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11107
|
+
Button,
|
|
11108
|
+
{
|
|
11109
|
+
variant: "destructive",
|
|
11110
|
+
size: "sm",
|
|
11111
|
+
onClick: doCancel,
|
|
11112
|
+
disabled: busy,
|
|
11113
|
+
children: [
|
|
11114
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "size-4" }),
|
|
11115
|
+
"Cancel mission"
|
|
11116
|
+
]
|
|
11117
|
+
}
|
|
11118
|
+
)
|
|
11119
|
+
] })
|
|
11120
|
+
] })
|
|
11121
|
+
}
|
|
11122
|
+
)
|
|
11123
|
+
] });
|
|
11124
|
+
}
|
|
11125
|
+
init_utils();
|
|
11126
|
+
var DEFAULT_POLL_INTERVAL_MS2 = 3e4;
|
|
11127
|
+
var DEFAULT_STATUS = "active,paused";
|
|
10544
11128
|
function fingerprint(items) {
|
|
11129
|
+
return items.map(
|
|
11130
|
+
(m) => `${m.id}:${m.status}:${m.iteration}:${m.lastEvaluationResult ?? ""}:${m.lastEvaluationAt ?? ""}:${m.pausedReason ?? ""}:${m.updatedAt}`
|
|
11131
|
+
).join("|");
|
|
11132
|
+
}
|
|
11133
|
+
function sortMissions(items) {
|
|
11134
|
+
return [...items].sort((a, b) => {
|
|
11135
|
+
const rank = (s) => s === "active" ? 0 : s === "paused" ? 1 : 2;
|
|
11136
|
+
const diff = rank(a.status) - rank(b.status);
|
|
11137
|
+
if (diff !== 0) return diff;
|
|
11138
|
+
return (a.updatedAt ?? "") > (b.updatedAt ?? "") ? -1 : 1;
|
|
11139
|
+
});
|
|
11140
|
+
}
|
|
11141
|
+
function MissionRow({
|
|
11142
|
+
mission,
|
|
11143
|
+
onOpen,
|
|
11144
|
+
onPause,
|
|
11145
|
+
onResume,
|
|
11146
|
+
onCancel,
|
|
11147
|
+
busy,
|
|
11148
|
+
canMutate
|
|
11149
|
+
}) {
|
|
11150
|
+
const isActive = mission.status === "active";
|
|
11151
|
+
const isPaused = mission.status === "paused";
|
|
11152
|
+
const description = mission.description.trim() || "(no description)";
|
|
11153
|
+
const verdict = mission.lastEvaluationResult;
|
|
11154
|
+
const verdictAt = mission.lastEvaluationAt ? dateFns.formatDistanceToNow(new Date(mission.lastEvaluationAt), {
|
|
11155
|
+
addSuffix: true
|
|
11156
|
+
}) : null;
|
|
11157
|
+
const meta = [
|
|
11158
|
+
`Iter ${mission.iteration}/${mission.maxIterations}`,
|
|
11159
|
+
verdict ? `Verdict: ${verdict}${verdictAt ? ` (${verdictAt})` : ""}` : null,
|
|
11160
|
+
isPaused && mission.pausedReason ? `Paused: ${mission.pausedReason}` : null
|
|
11161
|
+
].filter(Boolean);
|
|
11162
|
+
const stopActionClick = (e) => {
|
|
11163
|
+
e.stopPropagation();
|
|
11164
|
+
};
|
|
11165
|
+
const openMission = () => onOpen(mission.id);
|
|
11166
|
+
const handleRowKeyDown = (e) => {
|
|
11167
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
11168
|
+
e.preventDefault();
|
|
11169
|
+
openMission();
|
|
11170
|
+
};
|
|
11171
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11172
|
+
"div",
|
|
11173
|
+
{
|
|
11174
|
+
className: cn(
|
|
11175
|
+
"group flex min-w-0 items-start gap-2 border-l-2 border-l-transparent px-3 py-2 text-sm transition-colors cursor-pointer hover:border-l-primary hover:bg-input"
|
|
11176
|
+
),
|
|
11177
|
+
onClick: openMission,
|
|
11178
|
+
onKeyDown: handleRowKeyDown,
|
|
11179
|
+
role: "button",
|
|
11180
|
+
tabIndex: 0,
|
|
11181
|
+
"aria-label": `Open mission ${description}`,
|
|
11182
|
+
title: "Open mission dashboard",
|
|
11183
|
+
children: [
|
|
11184
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 flex size-5 shrink-0 items-center justify-center text-faint", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TargetIcon, { className: "size-3.5" }) }),
|
|
11185
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 items-start gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
11186
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-foreground", children: description }),
|
|
11187
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 flex min-w-0 items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11188
|
+
Badge,
|
|
11189
|
+
{
|
|
11190
|
+
variant: isActive ? "default" : "secondary",
|
|
11191
|
+
className: "shrink-0",
|
|
11192
|
+
children: mission.status
|
|
11193
|
+
}
|
|
11194
|
+
) }),
|
|
11195
|
+
meta.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 space-y-0.5 text-xs text-faint", children: meta.map((line) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate", children: line }, line)) })
|
|
11196
|
+
] }) }) }),
|
|
11197
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
11198
|
+
isActive && canMutate.pause && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11199
|
+
"button",
|
|
11200
|
+
{
|
|
11201
|
+
type: "button",
|
|
11202
|
+
className: "rounded p-1 text-faint opacity-70 transition-all hover:bg-line hover:text-foreground disabled:pointer-events-none disabled:opacity-40 group-hover:opacity-100",
|
|
11203
|
+
onClick: (e) => {
|
|
11204
|
+
stopActionClick(e);
|
|
11205
|
+
onPause(mission.id);
|
|
11206
|
+
},
|
|
11207
|
+
"aria-label": "Pause mission",
|
|
11208
|
+
title: "Pause mission",
|
|
11209
|
+
disabled: busy,
|
|
11210
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "size-3.5" })
|
|
11211
|
+
}
|
|
11212
|
+
),
|
|
11213
|
+
isPaused && canMutate.resume && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11214
|
+
"button",
|
|
11215
|
+
{
|
|
11216
|
+
type: "button",
|
|
11217
|
+
className: "rounded p-1 text-faint opacity-70 transition-all hover:bg-line hover:text-foreground disabled:pointer-events-none disabled:opacity-40 group-hover:opacity-100",
|
|
11218
|
+
onClick: (e) => {
|
|
11219
|
+
stopActionClick(e);
|
|
11220
|
+
onResume(mission.id);
|
|
11221
|
+
},
|
|
11222
|
+
"aria-label": "Resume mission",
|
|
11223
|
+
title: "Resume mission",
|
|
11224
|
+
disabled: busy,
|
|
11225
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-3.5" })
|
|
11226
|
+
}
|
|
11227
|
+
),
|
|
11228
|
+
(isActive || isPaused) && canMutate.cancel && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11229
|
+
"button",
|
|
11230
|
+
{
|
|
11231
|
+
type: "button",
|
|
11232
|
+
className: "rounded p-1 text-faint opacity-70 transition-all hover:bg-destructive/10 hover:text-destructive disabled:pointer-events-none disabled:opacity-40 group-hover:opacity-100",
|
|
11233
|
+
onClick: (e) => {
|
|
11234
|
+
stopActionClick(e);
|
|
11235
|
+
onCancel(mission.id);
|
|
11236
|
+
},
|
|
11237
|
+
"aria-label": "Cancel mission",
|
|
11238
|
+
title: "Cancel mission",
|
|
11239
|
+
disabled: busy,
|
|
11240
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "size-3.5" })
|
|
11241
|
+
}
|
|
11242
|
+
)
|
|
11243
|
+
] })
|
|
11244
|
+
]
|
|
11245
|
+
}
|
|
11246
|
+
);
|
|
11247
|
+
}
|
|
11248
|
+
function MissionsPanel({
|
|
11249
|
+
adapter,
|
|
11250
|
+
agentId,
|
|
11251
|
+
title = "Missions",
|
|
11252
|
+
status = DEFAULT_STATUS,
|
|
11253
|
+
hideHeader = false,
|
|
11254
|
+
pollIntervalMs = DEFAULT_POLL_INTERVAL_MS2,
|
|
11255
|
+
onMissionSelect,
|
|
11256
|
+
onMissionPause,
|
|
11257
|
+
onMissionResume,
|
|
11258
|
+
onMissionCancel
|
|
11259
|
+
}) {
|
|
11260
|
+
const [items, setItems] = react.useState([]);
|
|
11261
|
+
const [error, setError] = react.useState(null);
|
|
11262
|
+
const [hasEverLoaded, setHasEverLoaded] = react.useState(false);
|
|
11263
|
+
const [busyMissionId, setBusyMissionId] = react.useState(null);
|
|
11264
|
+
const [collapsed, setCollapsed] = react.useState(false);
|
|
11265
|
+
const mounted = react.useRef(true);
|
|
11266
|
+
const requestId = react.useRef(0);
|
|
11267
|
+
const lastFingerprint = react.useRef("");
|
|
11268
|
+
const refetch = react.useCallback(
|
|
11269
|
+
async (opts) => {
|
|
11270
|
+
if (!adapter.listMissions) {
|
|
11271
|
+
setItems([]);
|
|
11272
|
+
setHasEverLoaded(true);
|
|
11273
|
+
return;
|
|
11274
|
+
}
|
|
11275
|
+
const currentRequestId = ++requestId.current;
|
|
11276
|
+
try {
|
|
11277
|
+
const list = await adapter.listMissions({ agentId, status });
|
|
11278
|
+
if (!mounted.current || currentRequestId !== requestId.current) return;
|
|
11279
|
+
const next = sortMissions(list.missions);
|
|
11280
|
+
const fp = fingerprint(next);
|
|
11281
|
+
if (fp !== lastFingerprint.current) {
|
|
11282
|
+
lastFingerprint.current = fp;
|
|
11283
|
+
setItems(next);
|
|
11284
|
+
}
|
|
11285
|
+
setError(null);
|
|
11286
|
+
setHasEverLoaded(true);
|
|
11287
|
+
} catch (e) {
|
|
11288
|
+
if (!mounted.current || currentRequestId !== requestId.current) return;
|
|
11289
|
+
if (!opts?.silent) {
|
|
11290
|
+
setError(
|
|
11291
|
+
e instanceof Error ? e.message : "Failed to load missions"
|
|
11292
|
+
);
|
|
11293
|
+
setHasEverLoaded(true);
|
|
11294
|
+
}
|
|
11295
|
+
}
|
|
11296
|
+
},
|
|
11297
|
+
[adapter, agentId, status]
|
|
11298
|
+
);
|
|
11299
|
+
react.useEffect(() => {
|
|
11300
|
+
mounted.current = true;
|
|
11301
|
+
return () => {
|
|
11302
|
+
mounted.current = false;
|
|
11303
|
+
};
|
|
11304
|
+
}, []);
|
|
11305
|
+
react.useEffect(() => {
|
|
11306
|
+
setError(null);
|
|
11307
|
+
lastFingerprint.current = "";
|
|
11308
|
+
void refetch();
|
|
11309
|
+
}, [refetch]);
|
|
11310
|
+
react.useEffect(() => {
|
|
11311
|
+
if (!adapter.listMissions || pollIntervalMs <= 0) return;
|
|
11312
|
+
const id = setInterval(() => {
|
|
11313
|
+
void refetch({ silent: true });
|
|
11314
|
+
}, pollIntervalMs);
|
|
11315
|
+
return () => clearInterval(id);
|
|
11316
|
+
}, [adapter.listMissions, pollIntervalMs, refetch]);
|
|
11317
|
+
const activeCount = react.useMemo(
|
|
11318
|
+
() => items.filter((m) => m.status === "active").length,
|
|
11319
|
+
[items]
|
|
11320
|
+
);
|
|
11321
|
+
const handleOpen = react.useCallback(
|
|
11322
|
+
(missionId) => {
|
|
11323
|
+
onMissionSelect?.(missionId);
|
|
11324
|
+
},
|
|
11325
|
+
[onMissionSelect]
|
|
11326
|
+
);
|
|
11327
|
+
const handlePause = react.useCallback(
|
|
11328
|
+
async (missionId) => {
|
|
11329
|
+
if (!adapter.pauseMission || busyMissionId) return;
|
|
11330
|
+
setBusyMissionId(missionId);
|
|
11331
|
+
try {
|
|
11332
|
+
await adapter.pauseMission({ missionId });
|
|
11333
|
+
onMissionPause?.(missionId);
|
|
11334
|
+
await refetch({ silent: true });
|
|
11335
|
+
} catch (e) {
|
|
11336
|
+
setError(e instanceof Error ? e.message : "Failed to pause mission");
|
|
11337
|
+
} finally {
|
|
11338
|
+
if (mounted.current) setBusyMissionId(null);
|
|
11339
|
+
}
|
|
11340
|
+
},
|
|
11341
|
+
[adapter, busyMissionId, onMissionPause, refetch]
|
|
11342
|
+
);
|
|
11343
|
+
const handleResume = react.useCallback(
|
|
11344
|
+
async (missionId) => {
|
|
11345
|
+
if (!adapter.resumeMission || busyMissionId) return;
|
|
11346
|
+
setBusyMissionId(missionId);
|
|
11347
|
+
try {
|
|
11348
|
+
await adapter.resumeMission({ missionId });
|
|
11349
|
+
onMissionResume?.(missionId);
|
|
11350
|
+
await refetch({ silent: true });
|
|
11351
|
+
} catch (e) {
|
|
11352
|
+
setError(e instanceof Error ? e.message : "Failed to resume mission");
|
|
11353
|
+
} finally {
|
|
11354
|
+
if (mounted.current) setBusyMissionId(null);
|
|
11355
|
+
}
|
|
11356
|
+
},
|
|
11357
|
+
[adapter, busyMissionId, onMissionResume, refetch]
|
|
11358
|
+
);
|
|
11359
|
+
const handleCancel = react.useCallback(
|
|
11360
|
+
async (missionId) => {
|
|
11361
|
+
if (!adapter.cancelMission || busyMissionId) return;
|
|
11362
|
+
setBusyMissionId(missionId);
|
|
11363
|
+
try {
|
|
11364
|
+
await adapter.cancelMission({ missionId });
|
|
11365
|
+
setItems((current) => {
|
|
11366
|
+
const next = current.filter((m) => m.id !== missionId);
|
|
11367
|
+
lastFingerprint.current = fingerprint(next);
|
|
11368
|
+
return next;
|
|
11369
|
+
});
|
|
11370
|
+
onMissionCancel?.(missionId);
|
|
11371
|
+
await refetch({ silent: true });
|
|
11372
|
+
} catch (e) {
|
|
11373
|
+
setError(e instanceof Error ? e.message : "Failed to cancel mission");
|
|
11374
|
+
} finally {
|
|
11375
|
+
if (mounted.current) setBusyMissionId(null);
|
|
11376
|
+
}
|
|
11377
|
+
},
|
|
11378
|
+
[adapter, busyMissionId, onMissionCancel, refetch]
|
|
11379
|
+
);
|
|
11380
|
+
if (!hasEverLoaded) return null;
|
|
11381
|
+
if (!adapter.listMissions) return null;
|
|
11382
|
+
const showBody = hideHeader || !collapsed;
|
|
11383
|
+
const canMutate = {
|
|
11384
|
+
pause: Boolean(adapter.pauseMission),
|
|
11385
|
+
resume: Boolean(adapter.resumeMission),
|
|
11386
|
+
cancel: Boolean(adapter.cancelMission)
|
|
11387
|
+
};
|
|
11388
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "min-w-0 border-t border-line", children: [
|
|
11389
|
+
!hideHeader && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11390
|
+
"button",
|
|
11391
|
+
{
|
|
11392
|
+
type: "button",
|
|
11393
|
+
className: "flex w-full items-center gap-1.5 px-3 py-2 text-left text-xs font-semibold uppercase tracking-wide text-foreground transition-colors hover:bg-input",
|
|
11394
|
+
onClick: () => setCollapsed((c) => !c),
|
|
11395
|
+
"aria-expanded": !collapsed,
|
|
11396
|
+
children: [
|
|
11397
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.TargetIcon, { className: "size-3.5" }),
|
|
11398
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: title }),
|
|
11399
|
+
activeCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", className: "ml-auto", children: activeCount }),
|
|
11400
|
+
collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: "size-3.5 shrink-0 text-faint" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-3.5 shrink-0 text-faint" })
|
|
11401
|
+
]
|
|
11402
|
+
}
|
|
11403
|
+
),
|
|
11404
|
+
showBody && error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-xs text-destructive", children: error }),
|
|
11405
|
+
showBody && !error && items.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-xs text-faint", children: "No missions" }),
|
|
11406
|
+
showBody && !error && items.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("pb-2", hideHeader && "pt-1"), children: items.map((mission) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
11407
|
+
MissionRow,
|
|
11408
|
+
{
|
|
11409
|
+
mission,
|
|
11410
|
+
busy: busyMissionId === mission.id,
|
|
11411
|
+
canMutate,
|
|
11412
|
+
onOpen: handleOpen,
|
|
11413
|
+
onPause: handlePause,
|
|
11414
|
+
onResume: handleResume,
|
|
11415
|
+
onCancel: handleCancel
|
|
11416
|
+
},
|
|
11417
|
+
mission.id
|
|
11418
|
+
)) })
|
|
11419
|
+
] });
|
|
11420
|
+
}
|
|
11421
|
+
init_utils();
|
|
11422
|
+
var DEFAULT_LIMIT2 = 50;
|
|
11423
|
+
var DEFAULT_POLL_INTERVAL_MS3 = 3e4;
|
|
11424
|
+
function fingerprint2(items) {
|
|
10545
11425
|
return items.map(
|
|
10546
11426
|
(item) => `${item.id}:${item.status}:${item.kind ?? ""}:${item.name ?? ""}:${item.prompt}:${item.scheduleDisplay}:${item.runCount}:${item.nextRunAt ?? ""}:${item.lastRunAt ?? ""}:${item.lastSessionId ?? ""}:${item.lastError ?? ""}:${item.updatedAt}`
|
|
10547
11427
|
).join("|");
|
|
@@ -10691,7 +11571,7 @@ function ScheduledWorkPanel({
|
|
|
10691
11571
|
limit = DEFAULT_LIMIT2,
|
|
10692
11572
|
status = "active",
|
|
10693
11573
|
hideHeader = false,
|
|
10694
|
-
pollIntervalMs =
|
|
11574
|
+
pollIntervalMs = DEFAULT_POLL_INTERVAL_MS3,
|
|
10695
11575
|
onSessionSelect,
|
|
10696
11576
|
onScheduleCancel,
|
|
10697
11577
|
onScheduleRunNow
|
|
@@ -10720,7 +11600,7 @@ function ScheduledWorkPanel({
|
|
|
10720
11600
|
});
|
|
10721
11601
|
if (!mounted.current || currentRequestId !== requestId.current) return;
|
|
10722
11602
|
const nextItems = sortScheduledWork(list.items);
|
|
10723
|
-
const fp =
|
|
11603
|
+
const fp = fingerprint2(nextItems);
|
|
10724
11604
|
if (fp !== lastFingerprint.current) {
|
|
10725
11605
|
lastFingerprint.current = fp;
|
|
10726
11606
|
setItems(nextItems);
|
|
@@ -10791,7 +11671,7 @@ function ScheduledWorkPanel({
|
|
|
10791
11671
|
await adapter.cancelScheduledWork({ scheduleId });
|
|
10792
11672
|
setItems((current) => {
|
|
10793
11673
|
const next = current.filter((item) => item.id !== scheduleId);
|
|
10794
|
-
lastFingerprint.current =
|
|
11674
|
+
lastFingerprint.current = fingerprint2(next);
|
|
10795
11675
|
return next;
|
|
10796
11676
|
});
|
|
10797
11677
|
onScheduleCancel?.(scheduleId);
|
|
@@ -11211,12 +12091,19 @@ function SessionTreePanel({
|
|
|
11211
12091
|
] });
|
|
11212
12092
|
}
|
|
11213
12093
|
|
|
12094
|
+
exports.ACTIVE_MISSION_STATUSES = ACTIVE_MISSION_STATUSES;
|
|
11214
12095
|
exports.AgentChat = AgentChat;
|
|
11215
12096
|
exports.AgentChatAdapterProvider = AgentChatAdapterProvider;
|
|
11216
12097
|
exports.InboxPanel = InboxPanel;
|
|
11217
12098
|
exports.MessageResponse = MessageResponse;
|
|
12099
|
+
exports.MissionDashboard = MissionDashboard;
|
|
12100
|
+
exports.MissionsPanel = MissionsPanel;
|
|
11218
12101
|
exports.ScheduledWorkPanel = ScheduledWorkPanel;
|
|
11219
12102
|
exports.SessionTreePanel = SessionTreePanel;
|
|
12103
|
+
exports.deriveMissionWorkerActivityLabel = deriveMissionWorkerActivityLabel;
|
|
12104
|
+
exports.groupMissionTasksByBucket = groupMissionTasksByBucket;
|
|
12105
|
+
exports.isTerminalMissionStatus = isTerminalMissionStatus;
|
|
12106
|
+
exports.missionTaskBucket = missionTaskBucket;
|
|
11220
12107
|
exports.useAgentChatAdapterContext = useAgentChatAdapterContext;
|
|
11221
12108
|
exports.useAgentChatRuntime = useAgentChatRuntime;
|
|
11222
12109
|
exports.useInboxUnreadCount = useInboxUnreadCount;
|