@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.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { cn } from './chunk-QSC4UIVT.js';
2
- import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, lazy, useContext, Suspense, Children } from 'react';
2
+ import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, lazy, useContext, Fragment as Fragment$1, Suspense, Children } from 'react';
3
3
  import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, ChevronRightIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, Loader2Icon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, CopyIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, GitBranchIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, EyeIcon, ListTodoIcon, ArrowUpIcon, XCircleIcon, CheckCircle2Icon, Code, CircleCheckIcon, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
4
4
  import { cva } from 'class-variance-authority';
5
- import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Separator as Separator$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1, Progress as Progress$1, Tabs as Tabs$1 } from 'radix-ui';
5
+ import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Progress as Progress$1, Tabs as Tabs$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1 } from 'radix-ui';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom';
8
8
  import { cjk } from '@streamdown/cjk';
@@ -597,26 +597,6 @@ var ConversationScrollButton = ({
597
597
  }
598
598
  );
599
599
  };
600
- function Separator({
601
- className,
602
- orientation = "horizontal",
603
- decorative = true,
604
- ...props
605
- }) {
606
- return /* @__PURE__ */ jsx(
607
- Separator$1.Root,
608
- {
609
- "data-slot": "separator",
610
- decorative,
611
- orientation,
612
- className: cn(
613
- "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
614
- className
615
- ),
616
- ...props
617
- }
618
- );
619
- }
620
600
  var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx(
621
601
  "div",
622
602
  {
@@ -6209,6 +6189,191 @@ function ChatComposerInner({
6209
6189
  }
6210
6190
  );
6211
6191
  }
6192
+ var MAX_REASON_LENGTH2 = 500;
6193
+ function TurnFeedback({ msg }) {
6194
+ const { adapter, sessionId } = useAgentChatAdapterContext();
6195
+ const [pending, setPending] = useState(
6196
+ null
6197
+ );
6198
+ const [error, setError] = useState(null);
6199
+ const [reasonDraft, setReasonDraft] = useState(null);
6200
+ const llmResponseEventId = msg.llmResponseEventId;
6201
+ const canRate = llmResponseEventId !== void 0 && msg.status === "complete" && sessionId !== null && adapter.submitUserFeedback !== void 0;
6202
+ if (!canRate) return null;
6203
+ const rating = msg.userFeedback?.rating ?? pending;
6204
+ const alreadyRated = msg.userFeedback !== void 0;
6205
+ const submit = async (next, reason) => {
6206
+ if (sessionId === null || llmResponseEventId === void 0 || adapter.submitUserFeedback === void 0) return;
6207
+ setPending(next);
6208
+ setError(null);
6209
+ try {
6210
+ await adapter.submitUserFeedback({
6211
+ sessionId,
6212
+ llmResponseEventId,
6213
+ rating: next,
6214
+ ...reason ? { reason } : {}
6215
+ });
6216
+ setReasonDraft(null);
6217
+ } catch (e) {
6218
+ setPending(null);
6219
+ setError(e instanceof Error ? e.message : "Failed to submit feedback");
6220
+ }
6221
+ };
6222
+ const handleRate = (next) => {
6223
+ if (alreadyRated || pending !== null) return;
6224
+ if (next === "down") {
6225
+ setReasonDraft("");
6226
+ return;
6227
+ }
6228
+ void submit("up");
6229
+ };
6230
+ return /* @__PURE__ */ jsxs("div", { className: "mt-1 space-y-1.5", children: [
6231
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
6232
+ /* @__PURE__ */ jsx(
6233
+ Button,
6234
+ {
6235
+ type: "button",
6236
+ variant: "ghost",
6237
+ size: "icon-xs",
6238
+ "aria-label": "Good response",
6239
+ title: alreadyRated && rating === "up" ? "Good response (recorded)" : "Good response",
6240
+ disabled: pending !== null || alreadyRated,
6241
+ onClick: () => handleRate("up"),
6242
+ className: cn(
6243
+ rating === "up" ? "text-foreground" : "text-muted-foreground/60"
6244
+ ),
6245
+ children: /* @__PURE__ */ jsx(ThumbsUpIcon, { className: "size-3.5" })
6246
+ }
6247
+ ),
6248
+ /* @__PURE__ */ jsx(
6249
+ Button,
6250
+ {
6251
+ type: "button",
6252
+ variant: "ghost",
6253
+ size: "icon-xs",
6254
+ "aria-label": "Poor response",
6255
+ title: alreadyRated && rating === "down" ? "Poor response (recorded)" : "Poor response",
6256
+ disabled: pending !== null || reasonDraft !== null || alreadyRated,
6257
+ onClick: () => handleRate("down"),
6258
+ className: cn(
6259
+ rating === "down" ? "text-foreground" : "text-muted-foreground/60"
6260
+ ),
6261
+ children: /* @__PURE__ */ jsx(ThumbsDownIcon, { className: "size-3.5" })
6262
+ }
6263
+ ),
6264
+ alreadyRated && msg.userFeedback?.reason && /* @__PURE__ */ jsxs(
6265
+ "span",
6266
+ {
6267
+ className: "text-muted-foreground/70 truncate max-w-xs",
6268
+ title: msg.userFeedback.reason,
6269
+ children: [
6270
+ '\xB7 "',
6271
+ msg.userFeedback.reason,
6272
+ '"'
6273
+ ]
6274
+ }
6275
+ ),
6276
+ error && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-1", children: error })
6277
+ ] }),
6278
+ reasonDraft !== null && !alreadyRated && /* @__PURE__ */ jsx(
6279
+ ReasonForm2,
6280
+ {
6281
+ initialValue: reasonDraft,
6282
+ busy: pending !== null,
6283
+ onSubmit: (reason) => void submit("down", reason),
6284
+ onCancel: () => {
6285
+ setReasonDraft(null);
6286
+ setError(null);
6287
+ }
6288
+ }
6289
+ )
6290
+ ] });
6291
+ }
6292
+ function ReasonForm2({
6293
+ initialValue,
6294
+ busy,
6295
+ onSubmit,
6296
+ onCancel
6297
+ }) {
6298
+ const [value, setValue] = useState(initialValue);
6299
+ const trimmed = value.trim();
6300
+ const charsLeft = MAX_REASON_LENGTH2 - value.length;
6301
+ const submit = () => {
6302
+ if (trimmed && !busy) onSubmit(trimmed);
6303
+ };
6304
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-muted/30 p-2 space-y-1.5", children: [
6305
+ /* @__PURE__ */ jsx(
6306
+ "label",
6307
+ {
6308
+ className: "text-xs text-muted-foreground",
6309
+ htmlFor: "turn-feedback-reason",
6310
+ children: "What was wrong with the response?"
6311
+ }
6312
+ ),
6313
+ /* @__PURE__ */ jsx(
6314
+ Textarea,
6315
+ {
6316
+ id: "turn-feedback-reason",
6317
+ autoFocus: true,
6318
+ rows: 3,
6319
+ value,
6320
+ maxLength: MAX_REASON_LENGTH2,
6321
+ placeholder: "e.g. wrong answer, missed a constraint, hallucinated a fact\u2026",
6322
+ onChange: (e) => setValue(e.target.value),
6323
+ onKeyDown: (e) => {
6324
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
6325
+ e.preventDefault();
6326
+ submit();
6327
+ } else if (e.key === "Escape") {
6328
+ e.preventDefault();
6329
+ onCancel();
6330
+ }
6331
+ },
6332
+ className: "text-xs min-h-12",
6333
+ disabled: busy
6334
+ }
6335
+ ),
6336
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
6337
+ /* @__PURE__ */ jsxs(
6338
+ "span",
6339
+ {
6340
+ className: cn(
6341
+ "text-[10px] tabular-nums",
6342
+ charsLeft < 50 ? "text-amber-500" : "text-muted-foreground/60"
6343
+ ),
6344
+ children: [
6345
+ charsLeft,
6346
+ " characters left"
6347
+ ]
6348
+ }
6349
+ ),
6350
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
6351
+ /* @__PURE__ */ jsx(
6352
+ Button,
6353
+ {
6354
+ type: "button",
6355
+ variant: "ghost",
6356
+ size: "xs",
6357
+ onClick: onCancel,
6358
+ disabled: busy,
6359
+ children: "Cancel"
6360
+ }
6361
+ ),
6362
+ /* @__PURE__ */ jsx(
6363
+ Button,
6364
+ {
6365
+ type: "button",
6366
+ variant: "default",
6367
+ size: "xs",
6368
+ onClick: submit,
6369
+ disabled: busy || !trimmed,
6370
+ children: busy ? "Sending\u2026" : "Send feedback"
6371
+ }
6372
+ )
6373
+ ] })
6374
+ ] })
6375
+ ] });
6376
+ }
6212
6377
  var MIN_CPS = 40;
6213
6378
  var MAX_CPS = 240;
6214
6379
  var DRAIN_SECONDS = 0.25;
@@ -6859,7 +7024,8 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
6859
7024
  kind: "text",
6860
7025
  key: `${msg.id}-text`,
6861
7026
  content: msg.content,
6862
- isStreaming
7027
+ isStreaming,
7028
+ msg
6863
7029
  });
6864
7030
  }
6865
7031
  const hasRunningTool = hasToolCalls && msg.toolCalls.some(
@@ -7162,7 +7328,10 @@ function TextEntry({
7162
7328
  /* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
7163
7329
  /* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
7164
7330
  ] }),
7165
- /* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(MessageResponse, { children: content }) })
7331
+ /* @__PURE__ */ jsxs(TimelineContent, { children: [
7332
+ /* @__PURE__ */ jsx(MessageResponse, { children: content }),
7333
+ entry.isFinalTurnText && entry.msg.status === "complete" && /* @__PURE__ */ jsx(TurnFeedback, { msg: entry.msg })
7334
+ ] })
7166
7335
  ] });
7167
7336
  }
7168
7337
  function AssistantGroup({
@@ -7182,6 +7351,13 @@ function AssistantGroup({
7182
7351
  }
7183
7352
  entries = groupBrowserActivityEntries(entries);
7184
7353
  entries = groupWebSearchEntries(entries);
7354
+ for (let i = entries.length - 1; i >= 0; i--) {
7355
+ const entry = entries[i];
7356
+ if (entry?.kind === "text") {
7357
+ entries[i] = { ...entry, isFinalTurnText: true };
7358
+ break;
7359
+ }
7360
+ }
7185
7361
  const isTailGroup = lastGlobalIndex === totalMessages - 1;
7186
7362
  const lastEntry = entries[entries.length - 1];
7187
7363
  const hasRunningTool = entries.some(
@@ -8491,6 +8667,7 @@ var AGENT_CHAT_LISTENED_EVENTS = [
8491
8667
  "expert.result",
8492
8668
  "expert.endorse",
8493
8669
  "expert.override",
8670
+ "user.feedback",
8494
8671
  "artifact.created",
8495
8672
  "artifact.updated",
8496
8673
  "browser.provisioned",
@@ -8649,6 +8826,11 @@ function applyAgentChatEvent(state, event) {
8649
8826
  nextState,
8650
8827
  applyExpertFeedback(nextState.messages, event.type, event.data)
8651
8828
  );
8829
+ case "user.feedback":
8830
+ return withMessages(
8831
+ nextState,
8832
+ applyUserFeedback(nextState.messages, event.data)
8833
+ );
8652
8834
  case "clarify.response":
8653
8835
  return withMessages(
8654
8836
  nextState,
@@ -8846,17 +9028,23 @@ function applyLlmResponse(state, event) {
8846
9028
  ...current,
8847
9029
  reasoning: (current.reasoning ?? "") + current.content,
8848
9030
  content: "",
8849
- status: "streaming"
9031
+ status: "streaming",
9032
+ llmResponseEventId: event.eventId
8850
9033
  };
8851
9034
  } else {
8852
- messages[idx] = { ...current, status: "complete" };
9035
+ messages[idx] = {
9036
+ ...current,
9037
+ status: "complete",
9038
+ llmResponseEventId: event.eventId
9039
+ };
8853
9040
  }
8854
9041
  } else if (matchesExistingToolTurn && idx >= 0) {
8855
9042
  const current = messages[idx];
8856
9043
  messages[idx] = {
8857
9044
  ...current,
8858
9045
  reasoning: responseContent ? appendText(current.reasoning, responseContent) : current.reasoning,
8859
- status: "streaming"
9046
+ status: "streaming",
9047
+ llmResponseEventId: event.eventId
8860
9048
  };
8861
9049
  } else if (prevHasTools || !prevAssistant || hasUserAfter) {
8862
9050
  messages.push({
@@ -8865,7 +9053,8 @@ function applyLlmResponse(state, event) {
8865
9053
  content: hasToolCalls ? "" : responseContent,
8866
9054
  reasoning: hasToolCalls && responseContent ? responseContent : void 0,
8867
9055
  createdAt: /* @__PURE__ */ new Date(),
8868
- status: hasToolCalls ? "streaming" : "complete"
9056
+ status: hasToolCalls ? "streaming" : "complete",
9057
+ llmResponseEventId: event.eventId
8869
9058
  });
8870
9059
  } else {
8871
9060
  const current = messages[idx];
@@ -8873,13 +9062,15 @@ function applyLlmResponse(state, event) {
8873
9062
  messages[idx] = {
8874
9063
  ...current,
8875
9064
  reasoning: (current.reasoning ?? "") + responseContent,
8876
- status: "streaming"
9065
+ status: "streaming",
9066
+ llmResponseEventId: event.eventId
8877
9067
  };
8878
9068
  } else {
8879
9069
  messages[idx] = {
8880
9070
  ...current,
8881
9071
  content: responseContent || current.content,
8882
- status: hasToolCalls ? "streaming" : "complete"
9072
+ status: hasToolCalls ? "streaming" : "complete",
9073
+ llmResponseEventId: event.eventId
8883
9074
  };
8884
9075
  }
8885
9076
  }
@@ -9092,6 +9283,26 @@ function applyExpertFeedback(messages, type, data) {
9092
9283
  }
9093
9284
  return messages;
9094
9285
  }
9286
+ function applyUserFeedback(messages, data) {
9287
+ const source = typeof data.source === "string" ? data.source : "user";
9288
+ if (source !== "user") return messages;
9289
+ const targetEventId = typeof data.target_event_id === "number" ? data.target_event_id : void 0;
9290
+ if (targetEventId == null) return messages;
9291
+ const rating = data.rating === "down" ? "down" : "up";
9292
+ const reason = typeof data.reason === "string" ? data.reason : void 0;
9293
+ for (let i = messages.length - 1; i >= 0; i--) {
9294
+ const msg = messages[i];
9295
+ if (msg?.role !== "assistant") continue;
9296
+ if (msg.llmResponseEventId !== targetEventId) continue;
9297
+ if (msg.userFeedback?.rating === rating && msg.userFeedback?.reason === reason) {
9298
+ return messages;
9299
+ }
9300
+ const next = [...messages];
9301
+ next[i] = { ...msg, userFeedback: { rating, reason } };
9302
+ return next;
9303
+ }
9304
+ return messages;
9305
+ }
9095
9306
  function applyClarifyResponse(messages, data) {
9096
9307
  const targetToolId = stringValue2(data.tool_call_id);
9097
9308
  const responses = Array.isArray(data.responses) ? data.responses : void 0;
@@ -10461,42 +10672,6 @@ function Card({
10461
10672
  }
10462
10673
  );
10463
10674
  }
10464
- function CardHeader({ className, ...props }) {
10465
- return /* @__PURE__ */ jsx(
10466
- "div",
10467
- {
10468
- "data-slot": "card-header",
10469
- className: cn(
10470
- "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",
10471
- className
10472
- ),
10473
- ...props
10474
- }
10475
- );
10476
- }
10477
- function CardTitle({ className, ...props }) {
10478
- return /* @__PURE__ */ jsx(
10479
- "div",
10480
- {
10481
- "data-slot": "card-title",
10482
- className: cn(
10483
- "font-heading text-lg font-semibold tracking-wider uppercase",
10484
- className
10485
- ),
10486
- ...props
10487
- }
10488
- );
10489
- }
10490
- function CardDescription({ className, ...props }) {
10491
- return /* @__PURE__ */ jsx(
10492
- "div",
10493
- {
10494
- "data-slot": "card-description",
10495
- className: cn("text-sm leading-relaxed text-muted-foreground", className),
10496
- ...props
10497
- }
10498
- );
10499
- }
10500
10675
  function CardContent({ className, ...props }) {
10501
10676
  return /* @__PURE__ */ jsx(
10502
10677
  "div",
@@ -10564,6 +10739,97 @@ var MISSION_WORKER_KIND_TOOLTIP = {
10564
10739
  worker: "Async one-shot session spawned by spawn_worker. Durable session, no retry/DAG.",
10565
10740
  delegation: "Sync fork-join child spawned by delegate_task. Coordinator's wake blocked until it finished."
10566
10741
  };
10742
+ function CountBadge({ n }) {
10743
+ if (n === 0) return null;
10744
+ return /* @__PURE__ */ jsx("span", { className: "ml-1 rounded bg-muted px-1 py-px text-[9px] text-muted-foreground/70", children: n });
10745
+ }
10746
+ function firstLine3(text, max = 140) {
10747
+ const trimmed = text.replace(/\s+/g, " ").trim();
10748
+ if (trimmed.length <= max) return trimmed;
10749
+ return `${trimmed.slice(0, max).trimEnd()}\u2026`;
10750
+ }
10751
+ var ACTIVITY_KIND_TONE = {
10752
+ "mission.defined": "bg-primary/10 text-primary border-primary/30",
10753
+ "mission.paused": "bg-amber-500/10 text-amber-600 border-amber-500/30",
10754
+ "mission.cancelled": "bg-destructive/10 text-destructive border-destructive/30",
10755
+ "task.spawned": "bg-foreground/5 text-foreground/80 border-foreground/20",
10756
+ "task.completed": "bg-emerald-500/10 text-emerald-600 border-emerald-500/30",
10757
+ "task.failed": "bg-destructive/10 text-destructive border-destructive/30",
10758
+ "task.cancelled": "bg-muted text-muted-foreground border-border",
10759
+ "worker.latest": "bg-foreground/5 text-foreground/70 border-foreground/15",
10760
+ "evaluator.verdict": "bg-primary/10 text-primary border-primary/30"
10761
+ };
10762
+ function buildMissionActivity(mission, tasks, workers) {
10763
+ const entries = [];
10764
+ entries.push({
10765
+ at: mission.createdAt,
10766
+ kind: "mission.defined",
10767
+ label: "Mission defined",
10768
+ detail: mission.description
10769
+ });
10770
+ if (mission.status === "paused" && mission.pausedReason) {
10771
+ entries.push({
10772
+ at: mission.updatedAt,
10773
+ kind: "mission.paused",
10774
+ label: "Paused",
10775
+ detail: mission.pausedReason
10776
+ });
10777
+ }
10778
+ if (mission.status === "cancelled" && mission.cancelledReason) {
10779
+ entries.push({
10780
+ at: mission.updatedAt,
10781
+ kind: "mission.cancelled",
10782
+ label: "Cancelled",
10783
+ detail: mission.cancelledReason
10784
+ });
10785
+ }
10786
+ for (const task of tasks) {
10787
+ if (task.createdAt) {
10788
+ entries.push({
10789
+ at: task.createdAt,
10790
+ kind: "task.spawned",
10791
+ label: `Spawn \xB7 ${task.agentDefName ?? "task"}`,
10792
+ detail: firstLine3(task.goal, 200)
10793
+ });
10794
+ }
10795
+ if (task.completedAt) {
10796
+ const kind = task.status === "done" ? "task.completed" : task.status === "failed" ? "task.failed" : task.status === "cancelled" ? "task.cancelled" : "task.completed";
10797
+ entries.push({
10798
+ at: task.completedAt,
10799
+ kind,
10800
+ label: `${task.status} \xB7 ${task.agentDefName ?? "task"}`,
10801
+ detail: task.result ? firstLine3(task.result, 200) : void 0
10802
+ });
10803
+ }
10804
+ }
10805
+ for (const worker of workers) {
10806
+ if (worker.latestEventAt && worker.latestEventKind) {
10807
+ entries.push({
10808
+ at: worker.latestEventAt,
10809
+ kind: "worker.latest",
10810
+ label: `${worker.kind} \xB7 ${worker.latestEventKind}`,
10811
+ detail: deriveMissionWorkerActivityLabel(worker)
10812
+ });
10813
+ }
10814
+ }
10815
+ if (mission.lastEvaluationAt && mission.lastEvaluationResult) {
10816
+ entries.push({
10817
+ at: mission.lastEvaluationAt,
10818
+ kind: "evaluator.verdict",
10819
+ label: `Verdict \xB7 ${mission.lastEvaluationResult}`,
10820
+ detail: mission.lastEvaluationFeedback ?? void 0
10821
+ });
10822
+ }
10823
+ entries.sort((a, b) => b.at.localeCompare(a.at));
10824
+ return entries;
10825
+ }
10826
+ function formatTimestamp(iso) {
10827
+ try {
10828
+ return new Date(iso).toLocaleTimeString();
10829
+ } catch {
10830
+ return iso;
10831
+ }
10832
+ }
10567
10833
  var INITIAL_STATE = {
10568
10834
  mission: null,
10569
10835
  tasks: [],
@@ -10716,210 +10982,153 @@ function MissionDashboard({
10716
10982
  setBusy(false);
10717
10983
  }
10718
10984
  };
10719
- const statusVariant = mission.status === "satisfied" ? "default" : mission.status === "failed" || mission.status === "cancelled" ? "destructive" : "secondary";
10720
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4 sm:gap-6 sm:p-6", children: [
10721
- /* @__PURE__ */ jsxs(Card, { children: [
10722
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-stretch gap-4 sm:flex-row sm:items-start sm:justify-between", children: [
10723
- /* @__PURE__ */ jsxs("div", { className: "space-y-1 min-w-0 flex-1", children: [
10724
- /* @__PURE__ */ jsx(CardTitle, { className: "wrap-break-word -uppercase text-sm", children: mission.description }),
10725
- /* @__PURE__ */ jsxs(CardDescription, { className: "wrap-break-word text-foreground/70", children: [
10726
- "Rubric: ",
10727
- mission.rubric
10728
- ] }),
10729
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 pt-2 text-xs text-foreground/70", children: [
10730
- /* @__PURE__ */ jsx(Badge, { variant: statusVariant, className: "font-mono text-foreground", children: mission.status }),
10731
- /* @__PURE__ */ jsxs("span", { className: "font-mono text-primary", children: [
10732
- "Iteration ",
10733
- mission.iteration,
10734
- "/",
10735
- mission.maxIterations
10736
- ] }),
10737
- mission.lastEvaluationResult ? /* @__PURE__ */ jsxs("span", { children: [
10738
- "Last verdict:",
10739
- " ",
10740
- /* @__PURE__ */ jsx("span", { className: "font-mono text-primary", children: mission.lastEvaluationResult })
10741
- ] }) : null
10742
- ] })
10743
- ] }),
10744
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 shrink-0", children: ACTIVE_MISSION_STATUSES.has(mission.status) ? /* @__PURE__ */ jsxs(Fragment, { children: [
10745
- mission.status === "active" ? /* @__PURE__ */ jsxs(
10746
- Button,
10747
- {
10748
- size: "sm",
10749
- variant: "outline",
10750
- onClick: doPause,
10751
- disabled: busy,
10752
- children: [
10753
- /* @__PURE__ */ jsx(Pause, { className: "size-4" }),
10754
- " Pause"
10755
- ]
10756
- }
10757
- ) : /* @__PURE__ */ jsxs(
10758
- Button,
10985
+ 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";
10986
+ const activity = buildMissionActivity(mission, state.tasks, state.workers);
10987
+ const isActive = ACTIVE_MISSION_STATUSES.has(mission.status);
10988
+ const iterationPct = mission.maxIterations > 0 ? Math.min(100, mission.iteration / mission.maxIterations * 100) : 0;
10989
+ return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-1 flex-col overflow-hidden bg-muted/30", children: [
10990
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 px-5 pt-5 sm:px-6 sm:pt-6", children: /* @__PURE__ */ jsx(Card, { className: "border-border/60 bg-card shadow-sm", children: /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4 p-5 sm:p-6", children: [
10991
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
10992
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
10993
+ /* @__PURE__ */ jsx(
10994
+ "span",
10759
10995
  {
10760
- size: "sm",
10761
- variant: "outline",
10762
- onClick: doResume,
10763
- disabled: busy,
10764
- children: [
10765
- /* @__PURE__ */ jsx(Play, { className: "size-4" }),
10766
- " Resume"
10767
- ]
10996
+ className: `rounded-md border px-2 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-wider ${statusTone}`,
10997
+ children: mission.status
10768
10998
  }
10769
10999
  ),
10770
- /* @__PURE__ */ jsxs(
11000
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1.5", children: [
11001
+ /* @__PURE__ */ jsx("span", { className: "font-display text-2xl font-bold tracking-tight tabular-nums text-foreground", children: mission.iteration }),
11002
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground/70", children: [
11003
+ "/ ",
11004
+ mission.maxIterations
11005
+ ] }),
11006
+ /* @__PURE__ */ jsx("span", { className: "ml-1 text-[10px] uppercase tracking-wider text-muted-foreground/60", children: "iterations" })
11007
+ ] }),
11008
+ mission.lastEvaluationResult ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-muted-foreground/70", children: [
11009
+ /* @__PURE__ */ jsx("span", { className: "opacity-70", children: "last verdict" }),
11010
+ /* @__PURE__ */ 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 })
11011
+ ] }) : null
11012
+ ] }),
11013
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: [
11014
+ isActive ? /* @__PURE__ */ jsxs(Fragment, { children: [
11015
+ mission.status === "active" ? /* @__PURE__ */ jsxs(
11016
+ Button,
11017
+ {
11018
+ size: "sm",
11019
+ variant: "outline",
11020
+ onClick: doPause,
11021
+ disabled: busy,
11022
+ children: [
11023
+ /* @__PURE__ */ jsx(Pause, { className: "size-4" }),
11024
+ " Pause"
11025
+ ]
11026
+ }
11027
+ ) : /* @__PURE__ */ jsxs(
11028
+ Button,
11029
+ {
11030
+ size: "sm",
11031
+ variant: "outline",
11032
+ onClick: doResume,
11033
+ disabled: busy,
11034
+ children: [
11035
+ /* @__PURE__ */ jsx(Play, { className: "size-4" }),
11036
+ " Resume"
11037
+ ]
11038
+ }
11039
+ ),
11040
+ /* @__PURE__ */ jsxs(
11041
+ Button,
11042
+ {
11043
+ size: "sm",
11044
+ variant: "destructive",
11045
+ onClick: () => {
11046
+ setCancelCascade(false);
11047
+ setCancelOpen(true);
11048
+ },
11049
+ disabled: busy,
11050
+ children: [
11051
+ /* @__PURE__ */ jsx(Ban, { className: "size-4" }),
11052
+ " Cancel"
11053
+ ]
11054
+ }
11055
+ )
11056
+ ] }) : onNavigateBack ? /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: onNavigateBack, children: "Back" }) : null,
11057
+ /* @__PURE__ */ jsx(
10771
11058
  Button,
10772
11059
  {
11060
+ variant: "ghost",
10773
11061
  size: "sm",
10774
- variant: "destructive",
10775
- onClick: () => {
10776
- setCancelCascade(false);
10777
- setCancelOpen(true);
10778
- },
11062
+ onClick: () => void refresh(),
10779
11063
  disabled: busy,
10780
- children: [
10781
- /* @__PURE__ */ jsx(Ban, { className: "size-4" }),
10782
- " Cancel"
10783
- ]
11064
+ "aria-label": "Refresh",
11065
+ title: "Refresh",
11066
+ children: /* @__PURE__ */ jsx(RefreshCw, { className: "size-4" })
10784
11067
  }
10785
11068
  )
10786
- ] }) : onNavigateBack ? /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: onNavigateBack, children: "Back" }) : null })
10787
- ] }) }),
10788
- mission.lastEvaluationFeedback ? /* @__PURE__ */ jsxs(CardContent, { className: "space-y-2", children: [
10789
- /* @__PURE__ */ jsx("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: "Evaluator feedback" }),
10790
- /* @__PURE__ */ jsx("p", { className: "text-sm whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationFeedback }),
10791
- mission.lastEvaluationExplanation ? /* @__PURE__ */ jsx("p", { className: "text-xs text-foreground/70 whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationExplanation }) : null
10792
- ] }) : null
10793
- ] }),
10794
- /* @__PURE__ */ jsxs(Card, { children: [
10795
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { children: [
10796
- "Tasks (",
10797
- state.tasks.length,
10798
- ")"
10799
- ] }) }),
10800
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
10801
- ["in_flight", "blocked", "done", "failed_or_cancelled"].map((bucket) => {
10802
- const rows = taskBuckets[bucket];
10803
- if (rows.length === 0) return null;
10804
- const heading = {
10805
- in_flight: "In flight",
10806
- blocked: "Blocked",
10807
- done: "Done",
10808
- failed_or_cancelled: "Failed / cancelled"
10809
- }[bucket];
10810
- return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
10811
- /* @__PURE__ */ jsxs("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: [
10812
- heading,
10813
- " (",
10814
- rows.length,
10815
- ")"
10816
- ] }),
10817
- /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: rows.map((task) => /* @__PURE__ */ jsx(
10818
- "li",
10819
- {
10820
- className: "flex items-start justify-between gap-3 rounded border border-border/40 px-3 py-2 text-sm",
10821
- children: /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
10822
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10823
- task.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground/70", children: task.agentDefName }) : null,
10824
- task.attemptCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "text-xs text-foreground/70", children: [
10825
- "attempt ",
10826
- task.attemptCount,
10827
- "/",
10828
- task.maxAttempts
10829
- ] }) : null
10830
- ] }),
10831
- /* @__PURE__ */ jsx("div", { className: "text-sm wrap-break-word", children: task.goal }),
10832
- task.parentIds.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "text-xs text-foreground/70", children: [
10833
- "after:",
10834
- " ",
10835
- task.parentIds.map((p) => p.slice(0, 8)).join(", ")
10836
- ] }) : null,
10837
- task.result ? /* @__PURE__ */ 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,
10838
- task.resultMetadata ? /* @__PURE__ */ 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
10839
- ] })
10840
- },
10841
- task.id
10842
- )) })
10843
- ] }, bucket);
10844
- }),
10845
- state.tasks.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-sm text-foreground/70", children: "No tasks spawned yet." }) : null
10846
- ] })
10847
- ] }),
10848
- /* @__PURE__ */ jsxs(Card, { children: [
10849
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { children: [
10850
- "Live workers (",
10851
- state.workers.length,
10852
- ")"
10853
- ] }) }),
10854
- /* @__PURE__ */ jsx(CardContent, { children: state.workers.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-sm text-foreground/70", children: "No workers attached to this mission right now." }) : /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: state.workers.map((w) => {
10855
- const onTranscriptClick = (e) => {
10856
- if (onOpenTranscript) {
10857
- e.preventDefault();
10858
- onOpenTranscript(w.workerSessionId);
10859
- }
10860
- };
10861
- return /* @__PURE__ */ jsxs(
10862
- "li",
10863
- {
10864
- 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",
10865
- children: [
10866
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
10867
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10868
- /* @__PURE__ */ jsx(
10869
- Badge,
10870
- {
10871
- variant: "outline",
10872
- className: MISSION_WORKER_KIND_BADGE_CLASS[w.kind],
10873
- title: MISSION_WORKER_KIND_TOOLTIP[w.kind],
10874
- children: w.kind
10875
- }
10876
- ),
10877
- /* @__PURE__ */ jsx(Badge, { className: "text-foreground/70", children: w.kind === "task" ? w.taskStatus ?? "\u2014" : w.sessionStatus }),
10878
- w.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground/70", children: w.agentDefName }) : null
10879
- ] }),
10880
- /* @__PURE__ */ jsx("div", { className: "text-sm wrap-break-word", children: deriveMissionWorkerActivityLabel(w) }),
10881
- w.latestEventAt ? /* @__PURE__ */ jsx("div", { className: "text-xs text-foreground/70", children: new Date(w.latestEventAt).toLocaleTimeString() }) : null
10882
- ] }),
10883
- /* @__PURE__ */ jsx(
10884
- "a",
10885
- {
10886
- href: w.transcriptUrl,
10887
- target: "_blank",
10888
- rel: "noreferrer",
10889
- onClick: onTranscriptClick,
10890
- className: "text-xs text-primary hover:underline self-start",
10891
- children: "View session"
10892
- }
10893
- )
10894
- ]
10895
- },
10896
- w.workerSessionId
10897
- );
10898
- }) }) })
10899
- ] }),
10900
- /* @__PURE__ */ jsx(Separator, {}),
10901
- /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs text-foreground/70", children: [
10902
- /* @__PURE__ */ jsxs("span", { children: [
10903
- "Auto-refresh every ",
10904
- pollIntervalMs / 1e3,
10905
- "s while mission is active."
11069
+ ] })
10906
11070
  ] }),
10907
- /* @__PURE__ */ jsxs(
10908
- Button,
11071
+ /* @__PURE__ */ jsx(
11072
+ Progress,
10909
11073
  {
10910
- variant: "ghost",
10911
- size: "sm",
10912
- onClick: () => {
10913
- void refresh();
10914
- },
10915
- disabled: busy,
10916
- children: [
10917
- /* @__PURE__ */ jsx(RefreshCw, { className: "size-4" }),
10918
- " Refresh"
10919
- ]
11074
+ value: iterationPct,
11075
+ className: `h-1 ${isActive ? "" : "opacity-40"}`
10920
11076
  }
10921
- )
10922
- ] }),
11077
+ ),
11078
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
11079
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("h1", { className: "line-clamp-4 cursor-default font-display text-lg font-semibold leading-snug text-foreground wrap-break-word", children: mission.description }) }),
11080
+ mission.description.length > 240 ? /* @__PURE__ */ jsx(TooltipContent, { className: "max-w-lg", side: "bottom", children: /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs", children: mission.description }) }) : null
11081
+ ] }) }),
11082
+ /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border/60 bg-muted/40 px-3 py-2", children: [
11083
+ /* @__PURE__ */ jsx("div", { className: "mb-0.5 font-mono text-[9px] uppercase tracking-widest text-muted-foreground/70", children: "Rubric" }),
11084
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
11085
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("p", { className: "line-clamp-3 cursor-default text-sm leading-relaxed text-foreground/90 wrap-break-word", children: mission.rubric }) }),
11086
+ mission.rubric.length > 200 ? /* @__PURE__ */ jsx(TooltipContent, { className: "max-w-lg", side: "bottom", children: /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs", children: mission.rubric }) }) : null
11087
+ ] })
11088
+ ] })
11089
+ ] }) }) }),
11090
+ /* @__PURE__ */ jsxs(
11091
+ Tabs,
11092
+ {
11093
+ defaultValue: "activity",
11094
+ className: "mt-5 flex flex-1 flex-col overflow-hidden sm:mt-6",
11095
+ children: [
11096
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-border bg-background px-5 sm:px-6", children: /* @__PURE__ */ jsxs(TabsList, { variant: "line", children: [
11097
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "activity", children: [
11098
+ "Activity",
11099
+ /* @__PURE__ */ jsx(CountBadge, { n: activity.length })
11100
+ ] }),
11101
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "tasks", children: [
11102
+ "Tasks",
11103
+ /* @__PURE__ */ jsx(CountBadge, { n: state.tasks.length })
11104
+ ] }),
11105
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "workers", children: [
11106
+ "Workers",
11107
+ /* @__PURE__ */ jsx(CountBadge, { n: state.workers.length })
11108
+ ] }),
11109
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "metadata", children: "Metadata" })
11110
+ ] }) }),
11111
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto bg-background px-5 py-4 sm:px-6", children: [
11112
+ /* @__PURE__ */ jsx(TabsContent, { value: "activity", className: "mt-0", children: /* @__PURE__ */ jsx(ActivityTimeline, { entries: activity }) }),
11113
+ /* @__PURE__ */ jsx(TabsContent, { value: "tasks", className: "mt-0", children: /* @__PURE__ */ jsx(
11114
+ TasksList,
11115
+ {
11116
+ taskBuckets,
11117
+ totalTasks: state.tasks.length
11118
+ }
11119
+ ) }),
11120
+ /* @__PURE__ */ jsx(TabsContent, { value: "workers", className: "mt-0", children: /* @__PURE__ */ jsx(
11121
+ WorkersList,
11122
+ {
11123
+ workers: state.workers,
11124
+ onOpenTranscript
11125
+ }
11126
+ ) }),
11127
+ /* @__PURE__ */ jsx(TabsContent, { value: "metadata", className: "mt-0", children: /* @__PURE__ */ jsx(MetadataPane, { mission }) })
11128
+ ] })
11129
+ ]
11130
+ }
11131
+ ),
10923
11132
  /* @__PURE__ */ jsx(
10924
11133
  Dialog,
10925
11134
  {
@@ -10977,10 +11186,237 @@ function MissionDashboard({
10977
11186
  ] })
10978
11187
  }
10979
11188
  )
11189
+ ] }) });
11190
+ }
11191
+ function ActivityTimeline({ entries }) {
11192
+ if (entries.length === 0) {
11193
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No mission activity yet." });
11194
+ }
11195
+ return /* @__PURE__ */ jsx("ol", { className: "space-y-1", children: entries.map((e, i) => /* @__PURE__ */ jsxs(
11196
+ "li",
11197
+ {
11198
+ className: "flex items-start gap-3 rounded px-2 py-1.5 text-sm hover:bg-muted/30",
11199
+ children: [
11200
+ /* @__PURE__ */ jsx("span", { className: "w-20 shrink-0 font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(e.at) }),
11201
+ /* @__PURE__ */ jsx(
11202
+ "span",
11203
+ {
11204
+ className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${ACTIVITY_KIND_TONE[e.kind]}`,
11205
+ children: e.label
11206
+ }
11207
+ ),
11208
+ e.detail ? /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: e.detail }) : null
11209
+ ]
11210
+ },
11211
+ `${e.kind}-${e.at}-${i}`
11212
+ )) });
11213
+ }
11214
+ function TaskRow({ task }) {
11215
+ const [open, setOpen] = useState(false);
11216
+ const goalPreview = firstLine3(task.goal, 160);
11217
+ const hasMore = task.goal.length > 160 || Boolean(task.result) || Boolean(task.resultMetadata);
11218
+ 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";
11219
+ return /* @__PURE__ */ jsx(Collapsible, { open, onOpenChange: setOpen, asChild: true, children: /* @__PURE__ */ jsxs("li", { className: "rounded border border-border/40 text-sm", children: [
11220
+ /* @__PURE__ */ jsx(
11221
+ CollapsibleTrigger,
11222
+ {
11223
+ asChild: true,
11224
+ disabled: !hasMore,
11225
+ children: /* @__PURE__ */ jsxs(
11226
+ "button",
11227
+ {
11228
+ type: "button",
11229
+ className: "flex w-full items-start gap-3 px-3 py-2 text-left hover:bg-muted/30 disabled:hover:bg-transparent",
11230
+ children: [
11231
+ /* @__PURE__ */ jsx(
11232
+ ChevronRight,
11233
+ {
11234
+ className: `mt-0.5 size-3.5 shrink-0 text-muted-foreground/60 transition-transform ${open ? "rotate-90" : ""} ${hasMore ? "" : "opacity-0"}`
11235
+ }
11236
+ ),
11237
+ /* @__PURE__ */ jsx(
11238
+ "span",
11239
+ {
11240
+ className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${statusTone}`,
11241
+ children: task.status
11242
+ }
11243
+ ),
11244
+ task.agentDefName ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground/70", children: task.agentDefName }) : null,
11245
+ task.attemptCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: [
11246
+ "(",
11247
+ task.attemptCount,
11248
+ "/",
11249
+ task.maxAttempts,
11250
+ ")"
11251
+ ] }) : null,
11252
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: goalPreview })
11253
+ ]
11254
+ }
11255
+ )
11256
+ }
11257
+ ),
11258
+ /* @__PURE__ */ jsxs(CollapsibleContent, { className: "border-t border-border/40 px-3 py-2 text-xs", children: [
11259
+ /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
11260
+ /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Goal" }),
11261
+ /* @__PURE__ */ 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 })
11262
+ ] }),
11263
+ task.parentIds.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mb-2 text-[10px] text-muted-foreground/70", children: [
11264
+ "after: ",
11265
+ task.parentIds.map((p) => p.slice(0, 8)).join(", ")
11266
+ ] }) : null,
11267
+ task.result ? /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
11268
+ /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result" }),
11269
+ /* @__PURE__ */ 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 })
11270
+ ] }) : null,
11271
+ task.resultMetadata ? /* @__PURE__ */ jsxs("div", { children: [
11272
+ /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result metadata" }),
11273
+ /* @__PURE__ */ 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) })
11274
+ ] }) : null
11275
+ ] })
11276
+ ] }) });
11277
+ }
11278
+ function TasksList({
11279
+ taskBuckets,
11280
+ totalTasks
11281
+ }) {
11282
+ if (totalTasks === 0) {
11283
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No tasks spawned yet." });
11284
+ }
11285
+ const headings = {
11286
+ in_flight: "In flight",
11287
+ blocked: "Blocked",
11288
+ done: "Done",
11289
+ failed_or_cancelled: "Failed / cancelled"
11290
+ };
11291
+ return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: Object.keys(headings).map((bucket) => {
11292
+ const rows = taskBuckets[bucket];
11293
+ if (rows.length === 0) return null;
11294
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
11295
+ /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
11296
+ headings[bucket],
11297
+ " (",
11298
+ rows.length,
11299
+ ")"
11300
+ ] }),
11301
+ /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: rows.map((task) => /* @__PURE__ */ jsx(TaskRow, { task }, task.id)) })
11302
+ ] }, bucket);
11303
+ }) });
11304
+ }
11305
+ function WorkersList({
11306
+ workers,
11307
+ onOpenTranscript
11308
+ }) {
11309
+ if (workers.length === 0) {
11310
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No workers attached to this mission right now." });
11311
+ }
11312
+ return /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: workers.map((w) => {
11313
+ const onTranscriptClick = (e) => {
11314
+ if (onOpenTranscript) {
11315
+ e.preventDefault();
11316
+ onOpenTranscript(w.workerSessionId);
11317
+ }
11318
+ };
11319
+ return /* @__PURE__ */ jsxs(
11320
+ "li",
11321
+ {
11322
+ 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",
11323
+ children: [
11324
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
11325
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
11326
+ /* @__PURE__ */ jsx(
11327
+ Badge,
11328
+ {
11329
+ variant: "outline",
11330
+ className: MISSION_WORKER_KIND_BADGE_CLASS[w.kind],
11331
+ title: MISSION_WORKER_KIND_TOOLTIP[w.kind],
11332
+ children: w.kind
11333
+ }
11334
+ ),
11335
+ /* @__PURE__ */ jsx(Badge, { className: "text-foreground/70", children: w.kind === "task" ? w.taskStatus ?? "\u2014" : w.sessionStatus }),
11336
+ w.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/70", children: w.agentDefName }) : null,
11337
+ w.latestEventAt ? /* @__PURE__ */ jsx("span", { className: "ml-auto font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(w.latestEventAt) }) : null
11338
+ ] }),
11339
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm text-foreground/80", children: deriveMissionWorkerActivityLabel(w) })
11340
+ ] }),
11341
+ /* @__PURE__ */ jsx(
11342
+ "a",
11343
+ {
11344
+ href: w.transcriptUrl,
11345
+ target: "_blank",
11346
+ rel: "noreferrer",
11347
+ onClick: onTranscriptClick,
11348
+ className: "self-start text-xs text-primary hover:underline",
11349
+ children: "View session"
11350
+ }
11351
+ )
11352
+ ]
11353
+ },
11354
+ w.workerSessionId
11355
+ );
11356
+ }) });
11357
+ }
11358
+ function MetadataPane({ mission }) {
11359
+ const rows = [];
11360
+ rows.push({
11361
+ label: "Mission ID",
11362
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.id })
11363
+ });
11364
+ rows.push({
11365
+ label: "Session ID",
11366
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.sessionId })
11367
+ });
11368
+ rows.push({
11369
+ label: "Agent ID",
11370
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.agentId })
11371
+ });
11372
+ rows.push({ label: "Status", value: mission.status });
11373
+ rows.push({
11374
+ label: "Iteration",
11375
+ value: `${mission.iteration} / ${mission.maxIterations}`
11376
+ });
11377
+ rows.push({
11378
+ label: "Owner",
11379
+ value: mission.userId ? /* @__PURE__ */ jsxs(Fragment, { children: [
11380
+ "user ",
11381
+ /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.userId })
11382
+ ] }) : mission.serviceAccountId ? /* @__PURE__ */ jsxs(Fragment, { children: [
11383
+ "service account ",
11384
+ /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.serviceAccountId })
11385
+ ] }) : "\u2014"
11386
+ });
11387
+ rows.push({
11388
+ label: "Created",
11389
+ value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.createdAt).toLocaleString() })
11390
+ });
11391
+ rows.push({
11392
+ label: "Updated",
11393
+ value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.updatedAt).toLocaleString() })
11394
+ });
11395
+ if (mission.pausedReason) {
11396
+ rows.push({ label: "Paused reason", value: mission.pausedReason });
11397
+ }
11398
+ if (mission.cancelledReason) {
11399
+ rows.push({ label: "Cancelled reason", value: mission.cancelledReason });
11400
+ }
11401
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
11402
+ mission.lastEvaluationResult ? /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
11403
+ /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
11404
+ "Last verdict \u2014 ",
11405
+ mission.lastEvaluationResult
11406
+ ] }),
11407
+ mission.lastEvaluationFeedback ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm text-foreground/90", children: mission.lastEvaluationFeedback }) : null,
11408
+ mission.lastEvaluationExplanation ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs text-muted-foreground/70", children: mission.lastEvaluationExplanation }) : null
11409
+ ] }) : null,
11410
+ /* @__PURE__ */ jsxs("section", { children: [
11411
+ /* @__PURE__ */ jsx("div", { className: "mb-2 font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Identifiers" }),
11412
+ /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1 text-xs", children: rows.map((r) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
11413
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground/70", children: r.label }),
11414
+ /* @__PURE__ */ jsx("dd", { className: "break-all text-foreground/90", children: r.value })
11415
+ ] }, r.label)) })
11416
+ ] })
10980
11417
  ] });
10981
11418
  }
10982
11419
  var DEFAULT_POLL_INTERVAL_MS2 = 3e4;
10983
- var DEFAULT_STATUS = "active,paused";
10984
11420
  function fingerprint(items) {
10985
11421
  return items.map(
10986
11422
  (m) => `${m.id}:${m.status}:${m.iteration}:${m.lastEvaluationResult ?? ""}:${m.lastEvaluationAt ?? ""}:${m.pausedReason ?? ""}:${m.updatedAt}`
@@ -11106,7 +11542,7 @@ function MissionsPanel({
11106
11542
  adapter,
11107
11543
  agentId,
11108
11544
  title = "Missions",
11109
- status = DEFAULT_STATUS,
11545
+ status,
11110
11546
  hideHeader = false,
11111
11547
  pollIntervalMs = DEFAULT_POLL_INTERVAL_MS2,
11112
11548
  onMissionSelect,