@invergent/agent-chat-react 2.0.2 → 2.0.8

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 CHANGED
@@ -794,29 +794,6 @@ 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
-
820
797
  // src/components/ai-elements/message.tsx
821
798
  init_utils();
822
799
  var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -6493,6 +6470,194 @@ function ChatComposerInner({
6493
6470
  }
6494
6471
  );
6495
6472
  }
6473
+
6474
+ // src/components/chat/turn-feedback.tsx
6475
+ init_utils();
6476
+ var MAX_REASON_LENGTH2 = 500;
6477
+ function TurnFeedback({ msg }) {
6478
+ const { adapter, sessionId } = useAgentChatAdapterContext();
6479
+ const [pending, setPending] = react.useState(
6480
+ null
6481
+ );
6482
+ const [error, setError] = react.useState(null);
6483
+ const [reasonDraft, setReasonDraft] = react.useState(null);
6484
+ const llmResponseEventId = msg.llmResponseEventId;
6485
+ const canRate = llmResponseEventId !== void 0 && msg.status === "complete" && sessionId !== null && adapter.submitUserFeedback !== void 0;
6486
+ if (!canRate) return null;
6487
+ const rating = msg.userFeedback?.rating ?? pending;
6488
+ const alreadyRated = msg.userFeedback !== void 0;
6489
+ const submit = async (next, reason) => {
6490
+ if (sessionId === null || llmResponseEventId === void 0 || adapter.submitUserFeedback === void 0) return;
6491
+ setPending(next);
6492
+ setError(null);
6493
+ try {
6494
+ await adapter.submitUserFeedback({
6495
+ sessionId,
6496
+ llmResponseEventId,
6497
+ rating: next,
6498
+ ...reason ? { reason } : {}
6499
+ });
6500
+ setReasonDraft(null);
6501
+ } catch (e) {
6502
+ setPending(null);
6503
+ setError(e instanceof Error ? e.message : "Failed to submit feedback");
6504
+ }
6505
+ };
6506
+ const handleRate = (next) => {
6507
+ if (alreadyRated || pending !== null) return;
6508
+ if (next === "down") {
6509
+ setReasonDraft("");
6510
+ return;
6511
+ }
6512
+ void submit("up");
6513
+ };
6514
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 space-y-1.5", children: [
6515
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
6516
+ /* @__PURE__ */ jsxRuntime.jsx(
6517
+ Button,
6518
+ {
6519
+ type: "button",
6520
+ variant: "ghost",
6521
+ size: "icon-xs",
6522
+ "aria-label": "Good response",
6523
+ title: alreadyRated && rating === "up" ? "Good response (recorded)" : "Good response",
6524
+ disabled: pending !== null || alreadyRated,
6525
+ onClick: () => handleRate("up"),
6526
+ className: cn(
6527
+ rating === "up" ? "text-foreground" : "text-muted-foreground/60"
6528
+ ),
6529
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ThumbsUpIcon, { className: "size-3.5" })
6530
+ }
6531
+ ),
6532
+ /* @__PURE__ */ jsxRuntime.jsx(
6533
+ Button,
6534
+ {
6535
+ type: "button",
6536
+ variant: "ghost",
6537
+ size: "icon-xs",
6538
+ "aria-label": "Poor response",
6539
+ title: alreadyRated && rating === "down" ? "Poor response (recorded)" : "Poor response",
6540
+ disabled: pending !== null || reasonDraft !== null || alreadyRated,
6541
+ onClick: () => handleRate("down"),
6542
+ className: cn(
6543
+ rating === "down" ? "text-foreground" : "text-muted-foreground/60"
6544
+ ),
6545
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ThumbsDownIcon, { className: "size-3.5" })
6546
+ }
6547
+ ),
6548
+ alreadyRated && msg.userFeedback?.reason && /* @__PURE__ */ jsxRuntime.jsxs(
6549
+ "span",
6550
+ {
6551
+ className: "text-muted-foreground/70 truncate max-w-xs",
6552
+ title: msg.userFeedback.reason,
6553
+ children: [
6554
+ '\xB7 "',
6555
+ msg.userFeedback.reason,
6556
+ '"'
6557
+ ]
6558
+ }
6559
+ ),
6560
+ error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", children: error })
6561
+ ] }),
6562
+ reasonDraft !== null && !alreadyRated && /* @__PURE__ */ jsxRuntime.jsx(
6563
+ ReasonForm2,
6564
+ {
6565
+ initialValue: reasonDraft,
6566
+ busy: pending !== null,
6567
+ onSubmit: (reason) => void submit("down", reason),
6568
+ onCancel: () => {
6569
+ setReasonDraft(null);
6570
+ setError(null);
6571
+ }
6572
+ }
6573
+ )
6574
+ ] });
6575
+ }
6576
+ function ReasonForm2({
6577
+ initialValue,
6578
+ busy,
6579
+ onSubmit,
6580
+ onCancel
6581
+ }) {
6582
+ const [value, setValue] = react.useState(initialValue);
6583
+ const trimmed = value.trim();
6584
+ const charsLeft = MAX_REASON_LENGTH2 - value.length;
6585
+ const submit = () => {
6586
+ if (trimmed && !busy) onSubmit(trimmed);
6587
+ };
6588
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border border-border bg-muted/30 p-2 space-y-1.5", children: [
6589
+ /* @__PURE__ */ jsxRuntime.jsx(
6590
+ "label",
6591
+ {
6592
+ className: "text-xs text-muted-foreground",
6593
+ htmlFor: "turn-feedback-reason",
6594
+ children: "What was wrong with the response?"
6595
+ }
6596
+ ),
6597
+ /* @__PURE__ */ jsxRuntime.jsx(
6598
+ Textarea,
6599
+ {
6600
+ id: "turn-feedback-reason",
6601
+ autoFocus: true,
6602
+ rows: 3,
6603
+ value,
6604
+ maxLength: MAX_REASON_LENGTH2,
6605
+ placeholder: "e.g. wrong answer, missed a constraint, hallucinated a fact\u2026",
6606
+ onChange: (e) => setValue(e.target.value),
6607
+ onKeyDown: (e) => {
6608
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
6609
+ e.preventDefault();
6610
+ submit();
6611
+ } else if (e.key === "Escape") {
6612
+ e.preventDefault();
6613
+ onCancel();
6614
+ }
6615
+ },
6616
+ className: "text-xs min-h-12",
6617
+ disabled: busy
6618
+ }
6619
+ ),
6620
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
6621
+ /* @__PURE__ */ jsxRuntime.jsxs(
6622
+ "span",
6623
+ {
6624
+ className: cn(
6625
+ "text-[10px] tabular-nums",
6626
+ charsLeft < 50 ? "text-amber-500" : "text-muted-foreground/60"
6627
+ ),
6628
+ children: [
6629
+ charsLeft,
6630
+ " characters left"
6631
+ ]
6632
+ }
6633
+ ),
6634
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
6635
+ /* @__PURE__ */ jsxRuntime.jsx(
6636
+ Button,
6637
+ {
6638
+ type: "button",
6639
+ variant: "ghost",
6640
+ size: "xs",
6641
+ onClick: onCancel,
6642
+ disabled: busy,
6643
+ children: "Cancel"
6644
+ }
6645
+ ),
6646
+ /* @__PURE__ */ jsxRuntime.jsx(
6647
+ Button,
6648
+ {
6649
+ type: "button",
6650
+ variant: "default",
6651
+ size: "xs",
6652
+ onClick: submit,
6653
+ disabled: busy || !trimmed,
6654
+ children: busy ? "Sending\u2026" : "Send feedback"
6655
+ }
6656
+ )
6657
+ ] })
6658
+ ] })
6659
+ ] });
6660
+ }
6496
6661
  var MIN_CPS = 40;
6497
6662
  var MAX_CPS = 240;
6498
6663
  var DRAIN_SECONDS = 0.25;
@@ -7153,7 +7318,8 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
7153
7318
  kind: "text",
7154
7319
  key: `${msg.id}-text`,
7155
7320
  content: msg.content,
7156
- isStreaming
7321
+ isStreaming,
7322
+ msg
7157
7323
  });
7158
7324
  }
7159
7325
  const hasRunningTool = hasToolCalls && msg.toolCalls.some(
@@ -7456,7 +7622,10 @@ function TextEntry({
7456
7622
  /* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
7457
7623
  /* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
7458
7624
  ] }),
7459
- /* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: content }) })
7625
+ /* @__PURE__ */ jsxRuntime.jsxs(TimelineContent, { children: [
7626
+ /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: content }),
7627
+ entry.isFinalTurnText && entry.msg.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnFeedback, { msg: entry.msg })
7628
+ ] })
7460
7629
  ] });
7461
7630
  }
7462
7631
  function AssistantGroup({
@@ -7476,6 +7645,13 @@ function AssistantGroup({
7476
7645
  }
7477
7646
  entries = groupBrowserActivityEntries(entries);
7478
7647
  entries = groupWebSearchEntries(entries);
7648
+ for (let i = entries.length - 1; i >= 0; i--) {
7649
+ const entry = entries[i];
7650
+ if (entry?.kind === "text") {
7651
+ entries[i] = { ...entry, isFinalTurnText: true };
7652
+ break;
7653
+ }
7654
+ }
7479
7655
  const isTailGroup = lastGlobalIndex === totalMessages - 1;
7480
7656
  const lastEntry = entries[entries.length - 1];
7481
7657
  const hasRunningTool = entries.some(
@@ -8797,6 +8973,7 @@ var AGENT_CHAT_LISTENED_EVENTS = [
8797
8973
  "expert.result",
8798
8974
  "expert.endorse",
8799
8975
  "expert.override",
8976
+ "user.feedback",
8800
8977
  "artifact.created",
8801
8978
  "artifact.updated",
8802
8979
  "browser.provisioned",
@@ -8955,6 +9132,11 @@ function applyAgentChatEvent(state, event) {
8955
9132
  nextState,
8956
9133
  applyExpertFeedback(nextState.messages, event.type, event.data)
8957
9134
  );
9135
+ case "user.feedback":
9136
+ return withMessages(
9137
+ nextState,
9138
+ applyUserFeedback(nextState.messages, event.data)
9139
+ );
8958
9140
  case "clarify.response":
8959
9141
  return withMessages(
8960
9142
  nextState,
@@ -9152,17 +9334,23 @@ function applyLlmResponse(state, event) {
9152
9334
  ...current,
9153
9335
  reasoning: (current.reasoning ?? "") + current.content,
9154
9336
  content: "",
9155
- status: "streaming"
9337
+ status: "streaming",
9338
+ llmResponseEventId: event.eventId
9156
9339
  };
9157
9340
  } else {
9158
- messages[idx] = { ...current, status: "complete" };
9341
+ messages[idx] = {
9342
+ ...current,
9343
+ status: "complete",
9344
+ llmResponseEventId: event.eventId
9345
+ };
9159
9346
  }
9160
9347
  } else if (matchesExistingToolTurn && idx >= 0) {
9161
9348
  const current = messages[idx];
9162
9349
  messages[idx] = {
9163
9350
  ...current,
9164
9351
  reasoning: responseContent ? appendText(current.reasoning, responseContent) : current.reasoning,
9165
- status: "streaming"
9352
+ status: "streaming",
9353
+ llmResponseEventId: event.eventId
9166
9354
  };
9167
9355
  } else if (prevHasTools || !prevAssistant || hasUserAfter) {
9168
9356
  messages.push({
@@ -9171,7 +9359,8 @@ function applyLlmResponse(state, event) {
9171
9359
  content: hasToolCalls ? "" : responseContent,
9172
9360
  reasoning: hasToolCalls && responseContent ? responseContent : void 0,
9173
9361
  createdAt: /* @__PURE__ */ new Date(),
9174
- status: hasToolCalls ? "streaming" : "complete"
9362
+ status: hasToolCalls ? "streaming" : "complete",
9363
+ llmResponseEventId: event.eventId
9175
9364
  });
9176
9365
  } else {
9177
9366
  const current = messages[idx];
@@ -9179,13 +9368,15 @@ function applyLlmResponse(state, event) {
9179
9368
  messages[idx] = {
9180
9369
  ...current,
9181
9370
  reasoning: (current.reasoning ?? "") + responseContent,
9182
- status: "streaming"
9371
+ status: "streaming",
9372
+ llmResponseEventId: event.eventId
9183
9373
  };
9184
9374
  } else {
9185
9375
  messages[idx] = {
9186
9376
  ...current,
9187
9377
  content: responseContent || current.content,
9188
- status: hasToolCalls ? "streaming" : "complete"
9378
+ status: hasToolCalls ? "streaming" : "complete",
9379
+ llmResponseEventId: event.eventId
9189
9380
  };
9190
9381
  }
9191
9382
  }
@@ -9398,6 +9589,26 @@ function applyExpertFeedback(messages, type, data) {
9398
9589
  }
9399
9590
  return messages;
9400
9591
  }
9592
+ function applyUserFeedback(messages, data) {
9593
+ const source = typeof data.source === "string" ? data.source : "user";
9594
+ if (source !== "user") return messages;
9595
+ const targetEventId = typeof data.target_event_id === "number" ? data.target_event_id : void 0;
9596
+ if (targetEventId == null) return messages;
9597
+ const rating = data.rating === "down" ? "down" : "up";
9598
+ const reason = typeof data.reason === "string" ? data.reason : void 0;
9599
+ for (let i = messages.length - 1; i >= 0; i--) {
9600
+ const msg = messages[i];
9601
+ if (msg?.role !== "assistant") continue;
9602
+ if (msg.llmResponseEventId !== targetEventId) continue;
9603
+ if (msg.userFeedback?.rating === rating && msg.userFeedback?.reason === reason) {
9604
+ return messages;
9605
+ }
9606
+ const next = [...messages];
9607
+ next[i] = { ...msg, userFeedback: { rating, reason } };
9608
+ return next;
9609
+ }
9610
+ return messages;
9611
+ }
9401
9612
  function applyClarifyResponse(messages, data) {
9402
9613
  const targetToolId = stringValue2(data.tool_call_id);
9403
9614
  const responses = Array.isArray(data.responses) ? data.responses : void 0;
@@ -10771,42 +10982,6 @@ function Card({
10771
10982
  }
10772
10983
  );
10773
10984
  }
10774
- function CardHeader({ className, ...props }) {
10775
- return /* @__PURE__ */ jsxRuntime.jsx(
10776
- "div",
10777
- {
10778
- "data-slot": "card-header",
10779
- className: cn(
10780
- "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",
10781
- className
10782
- ),
10783
- ...props
10784
- }
10785
- );
10786
- }
10787
- function CardTitle({ className, ...props }) {
10788
- return /* @__PURE__ */ jsxRuntime.jsx(
10789
- "div",
10790
- {
10791
- "data-slot": "card-title",
10792
- className: cn(
10793
- "font-heading text-lg font-semibold tracking-wider uppercase",
10794
- className
10795
- ),
10796
- ...props
10797
- }
10798
- );
10799
- }
10800
- function CardDescription({ className, ...props }) {
10801
- return /* @__PURE__ */ jsxRuntime.jsx(
10802
- "div",
10803
- {
10804
- "data-slot": "card-description",
10805
- className: cn("text-sm leading-relaxed text-muted-foreground", className),
10806
- ...props
10807
- }
10808
- );
10809
- }
10810
10985
  function CardContent({ className, ...props }) {
10811
10986
  return /* @__PURE__ */ jsxRuntime.jsx(
10812
10987
  "div",
@@ -10874,6 +11049,97 @@ var MISSION_WORKER_KIND_TOOLTIP = {
10874
11049
  worker: "Async one-shot session spawned by spawn_worker. Durable session, no retry/DAG.",
10875
11050
  delegation: "Sync fork-join child spawned by delegate_task. Coordinator's wake blocked until it finished."
10876
11051
  };
11052
+ function CountBadge({ n }) {
11053
+ if (n === 0) return null;
11054
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 rounded bg-muted px-1 py-px text-[9px] text-muted-foreground/70", children: n });
11055
+ }
11056
+ function firstLine3(text, max = 140) {
11057
+ const trimmed = text.replace(/\s+/g, " ").trim();
11058
+ if (trimmed.length <= max) return trimmed;
11059
+ return `${trimmed.slice(0, max).trimEnd()}\u2026`;
11060
+ }
11061
+ var ACTIVITY_KIND_TONE = {
11062
+ "mission.defined": "bg-primary/10 text-primary border-primary/30",
11063
+ "mission.paused": "bg-amber-500/10 text-amber-600 border-amber-500/30",
11064
+ "mission.cancelled": "bg-destructive/10 text-destructive border-destructive/30",
11065
+ "task.spawned": "bg-foreground/5 text-foreground/80 border-foreground/20",
11066
+ "task.completed": "bg-emerald-500/10 text-emerald-600 border-emerald-500/30",
11067
+ "task.failed": "bg-destructive/10 text-destructive border-destructive/30",
11068
+ "task.cancelled": "bg-muted text-muted-foreground border-border",
11069
+ "worker.latest": "bg-foreground/5 text-foreground/70 border-foreground/15",
11070
+ "evaluator.verdict": "bg-primary/10 text-primary border-primary/30"
11071
+ };
11072
+ function buildMissionActivity(mission, tasks, workers) {
11073
+ const entries = [];
11074
+ entries.push({
11075
+ at: mission.createdAt,
11076
+ kind: "mission.defined",
11077
+ label: "Mission defined",
11078
+ detail: mission.description
11079
+ });
11080
+ if (mission.status === "paused" && mission.pausedReason) {
11081
+ entries.push({
11082
+ at: mission.updatedAt,
11083
+ kind: "mission.paused",
11084
+ label: "Paused",
11085
+ detail: mission.pausedReason
11086
+ });
11087
+ }
11088
+ if (mission.status === "cancelled" && mission.cancelledReason) {
11089
+ entries.push({
11090
+ at: mission.updatedAt,
11091
+ kind: "mission.cancelled",
11092
+ label: "Cancelled",
11093
+ detail: mission.cancelledReason
11094
+ });
11095
+ }
11096
+ for (const task of tasks) {
11097
+ if (task.createdAt) {
11098
+ entries.push({
11099
+ at: task.createdAt,
11100
+ kind: "task.spawned",
11101
+ label: `Spawn \xB7 ${task.agentDefName ?? "task"}`,
11102
+ detail: firstLine3(task.goal, 200)
11103
+ });
11104
+ }
11105
+ if (task.completedAt) {
11106
+ const kind = task.status === "done" ? "task.completed" : task.status === "failed" ? "task.failed" : task.status === "cancelled" ? "task.cancelled" : "task.completed";
11107
+ entries.push({
11108
+ at: task.completedAt,
11109
+ kind,
11110
+ label: `${task.status} \xB7 ${task.agentDefName ?? "task"}`,
11111
+ detail: task.result ? firstLine3(task.result, 200) : void 0
11112
+ });
11113
+ }
11114
+ }
11115
+ for (const worker of workers) {
11116
+ if (worker.latestEventAt && worker.latestEventKind) {
11117
+ entries.push({
11118
+ at: worker.latestEventAt,
11119
+ kind: "worker.latest",
11120
+ label: `${worker.kind} \xB7 ${worker.latestEventKind}`,
11121
+ detail: deriveMissionWorkerActivityLabel(worker)
11122
+ });
11123
+ }
11124
+ }
11125
+ if (mission.lastEvaluationAt && mission.lastEvaluationResult) {
11126
+ entries.push({
11127
+ at: mission.lastEvaluationAt,
11128
+ kind: "evaluator.verdict",
11129
+ label: `Verdict \xB7 ${mission.lastEvaluationResult}`,
11130
+ detail: mission.lastEvaluationFeedback ?? void 0
11131
+ });
11132
+ }
11133
+ entries.sort((a, b) => b.at.localeCompare(a.at));
11134
+ return entries;
11135
+ }
11136
+ function formatTimestamp(iso) {
11137
+ try {
11138
+ return new Date(iso).toLocaleTimeString();
11139
+ } catch {
11140
+ return iso;
11141
+ }
11142
+ }
10877
11143
  var INITIAL_STATE = {
10878
11144
  mission: null,
10879
11145
  tasks: [],
@@ -11026,210 +11292,153 @@ function MissionDashboard({
11026
11292
  setBusy(false);
11027
11293
  }
11028
11294
  };
11029
- const statusVariant = mission.status === "satisfied" ? "default" : mission.status === "failed" || mission.status === "cancelled" ? "destructive" : "secondary";
11030
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 p-4 sm:gap-6 sm:p-6", children: [
11031
- /* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
11032
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-stretch gap-4 sm:flex-row sm:items-start sm:justify-between", children: [
11033
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 min-w-0 flex-1", children: [
11034
- /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "wrap-break-word -uppercase text-sm", children: mission.description }),
11035
- /* @__PURE__ */ jsxRuntime.jsxs(CardDescription, { className: "wrap-break-word text-foreground/70", children: [
11036
- "Rubric: ",
11037
- mission.rubric
11038
- ] }),
11039
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 pt-2 text-xs text-foreground/70", children: [
11040
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant, className: "font-mono text-foreground", children: mission.status }),
11041
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-primary", children: [
11042
- "Iteration ",
11043
- mission.iteration,
11044
- "/",
11045
- mission.maxIterations
11046
- ] }),
11047
- mission.lastEvaluationResult ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
11048
- "Last verdict:",
11049
- " ",
11050
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-primary", children: mission.lastEvaluationResult })
11051
- ] }) : null
11052
- ] })
11053
- ] }),
11054
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2 shrink-0", children: ACTIVE_MISSION_STATUSES.has(mission.status) ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11055
- mission.status === "active" ? /* @__PURE__ */ jsxRuntime.jsxs(
11056
- Button,
11057
- {
11058
- size: "sm",
11059
- variant: "outline",
11060
- onClick: doPause,
11061
- disabled: busy,
11062
- children: [
11063
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "size-4" }),
11064
- " Pause"
11065
- ]
11066
- }
11067
- ) : /* @__PURE__ */ jsxRuntime.jsxs(
11068
- Button,
11295
+ const statusTone = mission.status === "satisfied" ? "border-emerald-500/40 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400" : mission.status === "failed" || mission.status === "cancelled" ? "border-destructive/40 bg-destructive/10 text-destructive" : mission.status === "paused" ? "border-amber-500/40 bg-amber-500/10 text-amber-700 dark:text-amber-400" : "border-primary/40 bg-primary/10 text-primary";
11296
+ const activity = buildMissionActivity(mission, state.tasks, state.workers);
11297
+ const isActive = ACTIVE_MISSION_STATUSES.has(mission.status);
11298
+ const iterationPct = mission.maxIterations > 0 ? Math.min(100, mission.iteration / mission.maxIterations * 100) : 0;
11299
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-1 flex-col overflow-hidden bg-muted/30", children: [
11300
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 px-5 pt-5 sm:px-6 sm:pt-6", children: /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-border/60 bg-card shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-4 p-5 sm:p-6", children: [
11301
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
11302
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
11303
+ /* @__PURE__ */ jsxRuntime.jsx(
11304
+ "span",
11069
11305
  {
11070
- size: "sm",
11071
- variant: "outline",
11072
- onClick: doResume,
11073
- disabled: busy,
11074
- children: [
11075
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-4" }),
11076
- " Resume"
11077
- ]
11306
+ className: `rounded-md border px-2 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-wider ${statusTone}`,
11307
+ children: mission.status
11078
11308
  }
11079
11309
  ),
11080
- /* @__PURE__ */ jsxRuntime.jsxs(
11310
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5", children: [
11311
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-display text-2xl font-bold tracking-tight tabular-nums text-foreground", children: mission.iteration }),
11312
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-muted-foreground/70", children: [
11313
+ "/ ",
11314
+ mission.maxIterations
11315
+ ] }),
11316
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-[10px] uppercase tracking-wider text-muted-foreground/60", children: "iterations" })
11317
+ ] }),
11318
+ mission.lastEvaluationResult ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-muted-foreground/70", children: [
11319
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-70", children: "last verdict" }),
11320
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded border border-primary/30 bg-primary/10 px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-wider text-primary", children: mission.lastEvaluationResult })
11321
+ ] }) : null
11322
+ ] }),
11323
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: [
11324
+ isActive ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11325
+ mission.status === "active" ? /* @__PURE__ */ jsxRuntime.jsxs(
11326
+ Button,
11327
+ {
11328
+ size: "sm",
11329
+ variant: "outline",
11330
+ onClick: doPause,
11331
+ disabled: busy,
11332
+ children: [
11333
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "size-4" }),
11334
+ " Pause"
11335
+ ]
11336
+ }
11337
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
11338
+ Button,
11339
+ {
11340
+ size: "sm",
11341
+ variant: "outline",
11342
+ onClick: doResume,
11343
+ disabled: busy,
11344
+ children: [
11345
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-4" }),
11346
+ " Resume"
11347
+ ]
11348
+ }
11349
+ ),
11350
+ /* @__PURE__ */ jsxRuntime.jsxs(
11351
+ Button,
11352
+ {
11353
+ size: "sm",
11354
+ variant: "destructive",
11355
+ onClick: () => {
11356
+ setCancelCascade(false);
11357
+ setCancelOpen(true);
11358
+ },
11359
+ disabled: busy,
11360
+ children: [
11361
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "size-4" }),
11362
+ " Cancel"
11363
+ ]
11364
+ }
11365
+ )
11366
+ ] }) : onNavigateBack ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "outline", onClick: onNavigateBack, children: "Back" }) : null,
11367
+ /* @__PURE__ */ jsxRuntime.jsx(
11081
11368
  Button,
11082
11369
  {
11370
+ variant: "ghost",
11083
11371
  size: "sm",
11084
- variant: "destructive",
11085
- onClick: () => {
11086
- setCancelCascade(false);
11087
- setCancelOpen(true);
11088
- },
11372
+ onClick: () => void refresh(),
11089
11373
  disabled: busy,
11090
- children: [
11091
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "size-4" }),
11092
- " Cancel"
11093
- ]
11374
+ "aria-label": "Refresh",
11375
+ title: "Refresh",
11376
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "size-4" })
11094
11377
  }
11095
11378
  )
11096
- ] }) : onNavigateBack ? /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "outline", onClick: onNavigateBack, children: "Back" }) : null })
11097
- ] }) }),
11098
- mission.lastEvaluationFeedback ? /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-2", children: [
11099
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: "Evaluator feedback" }),
11100
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationFeedback }),
11101
- mission.lastEvaluationExplanation ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-foreground/70 whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationExplanation }) : null
11102
- ] }) : null
11103
- ] }),
11104
- /* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
11105
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { children: [
11106
- "Tasks (",
11107
- state.tasks.length,
11108
- ")"
11109
- ] }) }),
11110
- /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-4", children: [
11111
- ["in_flight", "blocked", "done", "failed_or_cancelled"].map((bucket) => {
11112
- const rows = taskBuckets[bucket];
11113
- if (rows.length === 0) return null;
11114
- const heading = {
11115
- in_flight: "In flight",
11116
- blocked: "Blocked",
11117
- done: "Done",
11118
- failed_or_cancelled: "Failed / cancelled"
11119
- }[bucket];
11120
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11121
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: [
11122
- heading,
11123
- " (",
11124
- rows.length,
11125
- ")"
11126
- ] }),
11127
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1.5", children: rows.map((task) => /* @__PURE__ */ jsxRuntime.jsx(
11128
- "li",
11129
- {
11130
- className: "flex items-start justify-between gap-3 rounded border border-border/40 px-3 py-2 text-sm",
11131
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
11132
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
11133
- task.agentDefName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-foreground/70", children: task.agentDefName }) : null,
11134
- task.attemptCount > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-foreground/70", children: [
11135
- "attempt ",
11136
- task.attemptCount,
11137
- "/",
11138
- task.maxAttempts
11139
- ] }) : null
11140
- ] }),
11141
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm wrap-break-word", children: task.goal }),
11142
- task.parentIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-foreground/70", children: [
11143
- "after:",
11144
- " ",
11145
- task.parentIds.map((p) => p.slice(0, 8)).join(", ")
11146
- ] }) : null,
11147
- 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,
11148
- 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
11149
- ] })
11150
- },
11151
- task.id
11152
- )) })
11153
- ] }, bucket);
11154
- }),
11155
- state.tasks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground/70", children: "No tasks spawned yet." }) : null
11156
- ] })
11157
- ] }),
11158
- /* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
11159
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { children: [
11160
- "Live workers (",
11161
- state.workers.length,
11162
- ")"
11163
- ] }) }),
11164
- /* @__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) => {
11165
- const onTranscriptClick = (e) => {
11166
- if (onOpenTranscript) {
11167
- e.preventDefault();
11168
- onOpenTranscript(w.workerSessionId);
11169
- }
11170
- };
11171
- return /* @__PURE__ */ jsxRuntime.jsxs(
11172
- "li",
11173
- {
11174
- className: "flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between rounded border border-border/40 px-3 py-2 text-sm",
11175
- children: [
11176
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
11177
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
11178
- /* @__PURE__ */ jsxRuntime.jsx(
11179
- Badge,
11180
- {
11181
- variant: "outline",
11182
- className: MISSION_WORKER_KIND_BADGE_CLASS[w.kind],
11183
- title: MISSION_WORKER_KIND_TOOLTIP[w.kind],
11184
- children: w.kind
11185
- }
11186
- ),
11187
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { className: "text-foreground/70", children: w.kind === "task" ? w.taskStatus ?? "\u2014" : w.sessionStatus }),
11188
- w.agentDefName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-foreground/70", children: w.agentDefName }) : null
11189
- ] }),
11190
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm wrap-break-word", children: deriveMissionWorkerActivityLabel(w) }),
11191
- w.latestEventAt ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-foreground/70", children: new Date(w.latestEventAt).toLocaleTimeString() }) : null
11192
- ] }),
11193
- /* @__PURE__ */ jsxRuntime.jsx(
11194
- "a",
11195
- {
11196
- href: w.transcriptUrl,
11197
- target: "_blank",
11198
- rel: "noreferrer",
11199
- onClick: onTranscriptClick,
11200
- className: "text-xs text-primary hover:underline self-start",
11201
- children: "View session"
11202
- }
11203
- )
11204
- ]
11205
- },
11206
- w.workerSessionId
11207
- );
11208
- }) }) })
11209
- ] }),
11210
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
11211
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center text-xs text-foreground/70", children: [
11212
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
11213
- "Auto-refresh every ",
11214
- pollIntervalMs / 1e3,
11215
- "s while mission is active."
11379
+ ] })
11216
11380
  ] }),
11217
- /* @__PURE__ */ jsxRuntime.jsxs(
11218
- Button,
11381
+ /* @__PURE__ */ jsxRuntime.jsx(
11382
+ Progress,
11219
11383
  {
11220
- variant: "ghost",
11221
- size: "sm",
11222
- onClick: () => {
11223
- void refresh();
11224
- },
11225
- disabled: busy,
11226
- children: [
11227
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "size-4" }),
11228
- " Refresh"
11229
- ]
11384
+ value: iterationPct,
11385
+ className: `h-1 ${isActive ? "" : "opacity-40"}`
11230
11386
  }
11231
- )
11232
- ] }),
11387
+ ),
11388
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
11389
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "line-clamp-4 cursor-default font-display text-lg font-semibold leading-snug text-foreground wrap-break-word", children: mission.description }) }),
11390
+ mission.description.length > 240 ? /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { className: "max-w-lg", side: "bottom", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap text-xs", children: mission.description }) }) : null
11391
+ ] }) }),
11392
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border border-border/60 bg-muted/40 px-3 py-2", children: [
11393
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-0.5 font-mono text-[9px] uppercase tracking-widest text-muted-foreground/70", children: "Rubric" }),
11394
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
11395
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-3 cursor-default text-sm leading-relaxed text-foreground/90 wrap-break-word", children: mission.rubric }) }),
11396
+ mission.rubric.length > 200 ? /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { className: "max-w-lg", side: "bottom", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap text-xs", children: mission.rubric }) }) : null
11397
+ ] })
11398
+ ] })
11399
+ ] }) }) }),
11400
+ /* @__PURE__ */ jsxRuntime.jsxs(
11401
+ Tabs,
11402
+ {
11403
+ defaultValue: "activity",
11404
+ className: "mt-5 flex flex-1 flex-col overflow-hidden sm:mt-6",
11405
+ children: [
11406
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-b border-border bg-background px-5 sm:px-6", children: /* @__PURE__ */ jsxRuntime.jsxs(TabsList, { variant: "line", children: [
11407
+ /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "activity", children: [
11408
+ "Activity",
11409
+ /* @__PURE__ */ jsxRuntime.jsx(CountBadge, { n: activity.length })
11410
+ ] }),
11411
+ /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "tasks", children: [
11412
+ "Tasks",
11413
+ /* @__PURE__ */ jsxRuntime.jsx(CountBadge, { n: state.tasks.length })
11414
+ ] }),
11415
+ /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "workers", children: [
11416
+ "Workers",
11417
+ /* @__PURE__ */ jsxRuntime.jsx(CountBadge, { n: state.workers.length })
11418
+ ] }),
11419
+ /* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { value: "metadata", children: "Metadata" })
11420
+ ] }) }),
11421
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto bg-background px-5 py-4 sm:px-6", children: [
11422
+ /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "activity", className: "mt-0", children: /* @__PURE__ */ jsxRuntime.jsx(ActivityTimeline, { entries: activity }) }),
11423
+ /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "tasks", className: "mt-0", children: /* @__PURE__ */ jsxRuntime.jsx(
11424
+ TasksList,
11425
+ {
11426
+ taskBuckets,
11427
+ totalTasks: state.tasks.length
11428
+ }
11429
+ ) }),
11430
+ /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "workers", className: "mt-0", children: /* @__PURE__ */ jsxRuntime.jsx(
11431
+ WorkersList,
11432
+ {
11433
+ workers: state.workers,
11434
+ onOpenTranscript
11435
+ }
11436
+ ) }),
11437
+ /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "metadata", className: "mt-0", children: /* @__PURE__ */ jsxRuntime.jsx(MetadataPane, { mission }) })
11438
+ ] })
11439
+ ]
11440
+ }
11441
+ ),
11233
11442
  /* @__PURE__ */ jsxRuntime.jsx(
11234
11443
  Dialog,
11235
11444
  {
@@ -11287,11 +11496,238 @@ function MissionDashboard({
11287
11496
  ] })
11288
11497
  }
11289
11498
  )
11499
+ ] }) });
11500
+ }
11501
+ function ActivityTimeline({ entries }) {
11502
+ if (entries.length === 0) {
11503
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No mission activity yet." });
11504
+ }
11505
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "space-y-1", children: entries.map((e, i) => /* @__PURE__ */ jsxRuntime.jsxs(
11506
+ "li",
11507
+ {
11508
+ className: "flex items-start gap-3 rounded px-2 py-1.5 text-sm hover:bg-muted/30",
11509
+ children: [
11510
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-20 shrink-0 font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(e.at) }),
11511
+ /* @__PURE__ */ jsxRuntime.jsx(
11512
+ "span",
11513
+ {
11514
+ className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${ACTIVITY_KIND_TONE[e.kind]}`,
11515
+ children: e.label
11516
+ }
11517
+ ),
11518
+ e.detail ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: e.detail }) : null
11519
+ ]
11520
+ },
11521
+ `${e.kind}-${e.at}-${i}`
11522
+ )) });
11523
+ }
11524
+ function TaskRow({ task }) {
11525
+ const [open, setOpen] = react.useState(false);
11526
+ const goalPreview = firstLine3(task.goal, 160);
11527
+ const hasMore = task.goal.length > 160 || Boolean(task.result) || Boolean(task.resultMetadata);
11528
+ const statusTone = task.status === "done" ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-600" : task.status === "failed" ? "border-destructive/30 bg-destructive/10 text-destructive" : task.status === "cancelled" ? "border-border bg-muted text-muted-foreground" : task.status === "running" ? "border-primary/30 bg-primary/10 text-primary" : "border-foreground/20 bg-foreground/5 text-foreground/70";
11529
+ return /* @__PURE__ */ jsxRuntime.jsx(Collapsible, { open, onOpenChange: setOpen, asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "rounded border border-border/40 text-sm", children: [
11530
+ /* @__PURE__ */ jsxRuntime.jsx(
11531
+ CollapsibleTrigger,
11532
+ {
11533
+ asChild: true,
11534
+ disabled: !hasMore,
11535
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
11536
+ "button",
11537
+ {
11538
+ type: "button",
11539
+ className: "flex w-full items-start gap-3 px-3 py-2 text-left hover:bg-muted/30 disabled:hover:bg-transparent",
11540
+ children: [
11541
+ /* @__PURE__ */ jsxRuntime.jsx(
11542
+ lucideReact.ChevronRight,
11543
+ {
11544
+ className: `mt-0.5 size-3.5 shrink-0 text-muted-foreground/60 transition-transform ${open ? "rotate-90" : ""} ${hasMore ? "" : "opacity-0"}`
11545
+ }
11546
+ ),
11547
+ /* @__PURE__ */ jsxRuntime.jsx(
11548
+ "span",
11549
+ {
11550
+ className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${statusTone}`,
11551
+ children: task.status
11552
+ }
11553
+ ),
11554
+ task.agentDefName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground/70", children: task.agentDefName }) : null,
11555
+ task.attemptCount > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: [
11556
+ "(",
11557
+ task.attemptCount,
11558
+ "/",
11559
+ task.maxAttempts,
11560
+ ")"
11561
+ ] }) : null,
11562
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: goalPreview })
11563
+ ]
11564
+ }
11565
+ )
11566
+ }
11567
+ ),
11568
+ /* @__PURE__ */ jsxRuntime.jsxs(CollapsibleContent, { className: "border-t border-border/40 px-3 py-2 text-xs", children: [
11569
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2", children: [
11570
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Goal" }),
11571
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap rounded bg-muted/30 px-2 py-1.5 text-[11px] text-foreground/90", children: task.goal })
11572
+ ] }),
11573
+ task.parentIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 text-[10px] text-muted-foreground/70", children: [
11574
+ "after: ",
11575
+ task.parentIds.map((p) => p.slice(0, 8)).join(", ")
11576
+ ] }) : null,
11577
+ task.result ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2", children: [
11578
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result" }),
11579
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap rounded bg-muted/30 px-2 py-1.5 text-[11px] text-foreground/90", children: task.result })
11580
+ ] }) : null,
11581
+ task.resultMetadata ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11582
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result metadata" }),
11583
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap rounded bg-muted/30 px-2 py-1.5 text-[11px] text-foreground/90", children: JSON.stringify(task.resultMetadata, null, 2) })
11584
+ ] }) : null
11585
+ ] })
11586
+ ] }) });
11587
+ }
11588
+ function TasksList({
11589
+ taskBuckets,
11590
+ totalTasks
11591
+ }) {
11592
+ if (totalTasks === 0) {
11593
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No tasks spawned yet." });
11594
+ }
11595
+ const headings = {
11596
+ in_flight: "In flight",
11597
+ blocked: "Blocked",
11598
+ done: "Done",
11599
+ failed_or_cancelled: "Failed / cancelled"
11600
+ };
11601
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: Object.keys(headings).map((bucket) => {
11602
+ const rows = taskBuckets[bucket];
11603
+ if (rows.length === 0) return null;
11604
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
11605
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
11606
+ headings[bucket],
11607
+ " (",
11608
+ rows.length,
11609
+ ")"
11610
+ ] }),
11611
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", children: rows.map((task) => /* @__PURE__ */ jsxRuntime.jsx(TaskRow, { task }, task.id)) })
11612
+ ] }, bucket);
11613
+ }) });
11614
+ }
11615
+ function WorkersList({
11616
+ workers,
11617
+ onOpenTranscript
11618
+ }) {
11619
+ if (workers.length === 0) {
11620
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No workers attached to this mission right now." });
11621
+ }
11622
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", children: workers.map((w) => {
11623
+ const onTranscriptClick = (e) => {
11624
+ if (onOpenTranscript) {
11625
+ e.preventDefault();
11626
+ onOpenTranscript(w.workerSessionId);
11627
+ }
11628
+ };
11629
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11630
+ "li",
11631
+ {
11632
+ className: "flex flex-col gap-2 rounded border border-border/40 px-3 py-2 text-sm sm:flex-row sm:items-start sm:justify-between",
11633
+ children: [
11634
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
11635
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
11636
+ /* @__PURE__ */ jsxRuntime.jsx(
11637
+ Badge,
11638
+ {
11639
+ variant: "outline",
11640
+ className: MISSION_WORKER_KIND_BADGE_CLASS[w.kind],
11641
+ title: MISSION_WORKER_KIND_TOOLTIP[w.kind],
11642
+ children: w.kind
11643
+ }
11644
+ ),
11645
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { className: "text-foreground/70", children: w.kind === "task" ? w.taskStatus ?? "\u2014" : w.sessionStatus }),
11646
+ w.agentDefName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground/70", children: w.agentDefName }) : null,
11647
+ w.latestEventAt ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(w.latestEventAt) }) : null
11648
+ ] }),
11649
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm text-foreground/80", children: deriveMissionWorkerActivityLabel(w) })
11650
+ ] }),
11651
+ /* @__PURE__ */ jsxRuntime.jsx(
11652
+ "a",
11653
+ {
11654
+ href: w.transcriptUrl,
11655
+ target: "_blank",
11656
+ rel: "noreferrer",
11657
+ onClick: onTranscriptClick,
11658
+ className: "self-start text-xs text-primary hover:underline",
11659
+ children: "View session"
11660
+ }
11661
+ )
11662
+ ]
11663
+ },
11664
+ w.workerSessionId
11665
+ );
11666
+ }) });
11667
+ }
11668
+ function MetadataPane({ mission }) {
11669
+ const rows = [];
11670
+ rows.push({
11671
+ label: "Mission ID",
11672
+ value: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-[11px]", children: mission.id })
11673
+ });
11674
+ rows.push({
11675
+ label: "Session ID",
11676
+ value: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-[11px]", children: mission.sessionId })
11677
+ });
11678
+ rows.push({
11679
+ label: "Agent ID",
11680
+ value: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-[11px]", children: mission.agentId })
11681
+ });
11682
+ rows.push({ label: "Status", value: mission.status });
11683
+ rows.push({
11684
+ label: "Iteration",
11685
+ value: `${mission.iteration} / ${mission.maxIterations}`
11686
+ });
11687
+ rows.push({
11688
+ label: "Owner",
11689
+ value: mission.userId ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11690
+ "user ",
11691
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-[11px]", children: mission.userId })
11692
+ ] }) : mission.serviceAccountId ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11693
+ "service account ",
11694
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-[11px]", children: mission.serviceAccountId })
11695
+ ] }) : "\u2014"
11696
+ });
11697
+ rows.push({
11698
+ label: "Created",
11699
+ value: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.createdAt).toLocaleString() })
11700
+ });
11701
+ rows.push({
11702
+ label: "Updated",
11703
+ value: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.updatedAt).toLocaleString() })
11704
+ });
11705
+ if (mission.pausedReason) {
11706
+ rows.push({ label: "Paused reason", value: mission.pausedReason });
11707
+ }
11708
+ if (mission.cancelledReason) {
11709
+ rows.push({ label: "Cancelled reason", value: mission.cancelledReason });
11710
+ }
11711
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
11712
+ mission.lastEvaluationResult ? /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-2", children: [
11713
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
11714
+ "Last verdict \u2014 ",
11715
+ mission.lastEvaluationResult
11716
+ ] }),
11717
+ mission.lastEvaluationFeedback ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap text-sm text-foreground/90", children: mission.lastEvaluationFeedback }) : null,
11718
+ mission.lastEvaluationExplanation ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap text-xs text-muted-foreground/70", children: mission.lastEvaluationExplanation }) : null
11719
+ ] }) : null,
11720
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
11721
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Identifiers" }),
11722
+ /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1 text-xs", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
11723
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-muted-foreground/70", children: r.label }),
11724
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "break-all text-foreground/90", children: r.value })
11725
+ ] }, r.label)) })
11726
+ ] })
11290
11727
  ] });
11291
11728
  }
11292
11729
  init_utils();
11293
11730
  var DEFAULT_POLL_INTERVAL_MS2 = 3e4;
11294
- var DEFAULT_STATUS = "active,paused";
11295
11731
  function fingerprint(items) {
11296
11732
  return items.map(
11297
11733
  (m) => `${m.id}:${m.status}:${m.iteration}:${m.lastEvaluationResult ?? ""}:${m.lastEvaluationAt ?? ""}:${m.pausedReason ?? ""}:${m.updatedAt}`
@@ -11417,7 +11853,7 @@ function MissionsPanel({
11417
11853
  adapter,
11418
11854
  agentId,
11419
11855
  title = "Missions",
11420
- status = DEFAULT_STATUS,
11856
+ status,
11421
11857
  hideHeader = false,
11422
11858
  pollIntervalMs = DEFAULT_POLL_INTERVAL_MS2,
11423
11859
  onMissionSelect,