@tangle-network/agent-app 0.42.4 → 0.42.6

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.
Files changed (48) hide show
  1. package/dist/{DesignCanvas-AOIVN3SJ.js → DesignCanvas-GUTCY763.js} +2 -2
  2. package/dist/{DesignCanvasEditor-QQNAZRJQ.js → DesignCanvasEditor-ZO4V7H6A.js} +4 -4
  3. package/dist/{TimelineEditor-Z7C6BFP5.js → TimelineEditor-SNOAGBV6.js} +2 -2
  4. package/dist/brand/index.d.ts +35 -0
  5. package/dist/brand/index.js +89 -0
  6. package/dist/brand/index.js.map +1 -0
  7. package/dist/{chunk-YYYXGLLQ.js → chunk-6JYDS34Y.js} +184 -54
  8. package/dist/chunk-6JYDS34Y.js.map +1 -0
  9. package/dist/{chunk-FJUOBNIY.js → chunk-A5Z53E3A.js} +3 -3
  10. package/dist/{chunk-V5XZKHCL.js → chunk-AFQXKJAE.js} +132 -2
  11. package/dist/chunk-AFQXKJAE.js.map +1 -0
  12. package/dist/{chunk-S6WS2B32.js → chunk-EX3LD5G6.js} +322 -122
  13. package/dist/chunk-EX3LD5G6.js.map +1 -0
  14. package/dist/{chunk-DTS5TZRN.js → chunk-MFI4ZM7W.js} +2 -2
  15. package/dist/chunk-MFI4ZM7W.js.map +1 -0
  16. package/dist/{chunk-YEWTVDDT.js → chunk-OVUQNKLM.js} +379 -323
  17. package/dist/chunk-OVUQNKLM.js.map +1 -0
  18. package/dist/chunk-ZN5J47UX.js +1 -0
  19. package/dist/chunk-ZN5J47UX.js.map +1 -0
  20. package/dist/{command-stack-CkjelfK_.d.ts → command-stack-CcWi_2bN.d.ts} +15 -0
  21. package/dist/design-canvas-react/engine.d.ts +2 -2
  22. package/dist/design-canvas-react/engine.js +5 -6
  23. package/dist/design-canvas-react/index.d.ts +61 -8
  24. package/dist/design-canvas-react/index.js +10 -9
  25. package/dist/design-canvas-react/lazy.d.ts +2 -2
  26. package/dist/design-canvas-react/lazy.js +1 -1
  27. package/dist/{lazy-BHHqS8-j.d.ts → lazy-2XBVp1_e.d.ts} +6 -2
  28. package/dist/sequences-react/index.d.ts +94 -2
  29. package/dist/sequences-react/index.js +12 -2
  30. package/dist/sequences-react/index.js.map +1 -1
  31. package/dist/studio/index.d.ts +1 -1
  32. package/dist/studio/index.js +1 -1
  33. package/dist/studio-react/index.js +1 -1
  34. package/dist/web-react/index.d.ts +73 -6
  35. package/dist/web-react/index.js +453 -210
  36. package/dist/web-react/index.js.map +1 -1
  37. package/package.json +14 -9
  38. package/dist/chunk-DTS5TZRN.js.map +0 -1
  39. package/dist/chunk-S6WS2B32.js.map +0 -1
  40. package/dist/chunk-SQV7NUEM.js +0 -136
  41. package/dist/chunk-SQV7NUEM.js.map +0 -1
  42. package/dist/chunk-V5XZKHCL.js.map +0 -1
  43. package/dist/chunk-YEWTVDDT.js.map +0 -1
  44. package/dist/chunk-YYYXGLLQ.js.map +0 -1
  45. /package/dist/{DesignCanvas-AOIVN3SJ.js.map → DesignCanvas-GUTCY763.js.map} +0 -0
  46. /package/dist/{DesignCanvasEditor-QQNAZRJQ.js.map → DesignCanvasEditor-ZO4V7H6A.js.map} +0 -0
  47. /package/dist/{TimelineEditor-Z7C6BFP5.js.map → TimelineEditor-SNOAGBV6.js.map} +0 -0
  48. /package/dist/{chunk-FJUOBNIY.js.map → chunk-A5Z53E3A.js.map} +0 -0
@@ -255,7 +255,7 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
255
255
  ]
256
256
  }
257
257
  ),
258
- open && /* @__PURE__ */ jsxs2("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-[420px] overflow-hidden rounded-xl border border-border bg-card shadow-lg", children: [
258
+ open && /* @__PURE__ */ jsxs2("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-[420px] max-w-[calc(100vw-2rem)] overflow-hidden rounded-xl border border-border bg-card shadow-lg", children: [
259
259
  /* @__PURE__ */ jsx2("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2", children: [
260
260
  /* @__PURE__ */ jsx2(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
261
261
  /* @__PURE__ */ jsx2(
@@ -290,16 +290,16 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
290
290
  ] })
291
291
  ] });
292
292
  }
293
- var EFFORT_LEVELS = [
293
+ var DEFAULT_EFFORT_LEVELS = [
294
294
  { id: "off", label: "Off" },
295
- { id: "low", label: "Low" },
296
- { id: "medium", label: "Medium" },
297
- { id: "high", label: "High" }
295
+ { id: "low", label: "Quick" },
296
+ { id: "medium", label: "Standard" },
297
+ { id: "high", label: "Extended" }
298
298
  ];
299
- function EffortPicker({ value, onChange }) {
299
+ function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label = "Thinking" }) {
300
300
  const [open, setOpen] = useState2(false);
301
301
  const { containerRef, triggerProps } = usePopover(open, setOpen);
302
- const selected = EFFORT_LEVELS.find((l) => l.id === value) ?? EFFORT_LEVELS[2];
302
+ const selected = levels.find((l) => l.id === value) ?? levels[2] ?? levels[0];
303
303
  return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
304
304
  /* @__PURE__ */ jsxs2(
305
305
  "button",
@@ -307,16 +307,22 @@ function EffortPicker({ value, onChange }) {
307
307
  type: "button",
308
308
  ...triggerProps,
309
309
  onClick: () => setOpen(!open),
310
- title: "Reasoning effort",
311
- className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
310
+ title: label ? `${label} \u2014 how hard the agent reasons before answering` : "Reasoning effort",
311
+ className: "inline-flex min-h-[36px] items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
312
312
  children: [
313
313
  /* @__PURE__ */ jsx2(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
314
- /* @__PURE__ */ jsx2("span", { children: selected.label }),
314
+ /* @__PURE__ */ jsxs2("span", { children: [
315
+ label ? /* @__PURE__ */ jsxs2("span", { className: "text-muted-foreground", children: [
316
+ label,
317
+ ": "
318
+ ] }) : null,
319
+ selected?.label
320
+ ] }),
315
321
  /* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
316
322
  ]
317
323
  }
318
324
  ),
319
- open && /* @__PURE__ */ jsx2("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 w-36 overflow-hidden rounded-xl border border-border bg-card p-1 shadow-lg", children: EFFORT_LEVELS.map((l) => /* @__PURE__ */ jsx2(
325
+ open && /* @__PURE__ */ jsx2("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 w-40 overflow-hidden rounded-xl border border-border bg-card p-1 shadow-lg", children: levels.map((l) => /* @__PURE__ */ jsx2(
320
326
  "button",
321
327
  {
322
328
  type: "button",
@@ -326,7 +332,7 @@ function EffortPicker({ value, onChange }) {
326
332
  onChange(l.id);
327
333
  setOpen(false);
328
334
  },
329
- className: `flex w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${l.id === value ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
335
+ className: `flex min-h-[40px] w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${l.id === value ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
330
336
  children: l.label
331
337
  },
332
338
  l.id
@@ -334,6 +340,24 @@ function EffortPicker({ value, onChange }) {
334
340
  ] });
335
341
  }
336
342
 
343
+ // src/web-react/brand-mark.tsx
344
+ import { lazy, Suspense } from "react";
345
+ import { jsx as jsx3 } from "react/jsx-runtime";
346
+ function MarkSpacer({ size = 24, className }) {
347
+ return /* @__PURE__ */ jsx3("span", { "aria-hidden": true, style: { display: "inline-block", width: size, height: size }, className });
348
+ }
349
+ var LazyKnot = lazy(async () => {
350
+ try {
351
+ const mod = await import("../brand/index.js");
352
+ return { default: mod.TangleKnot };
353
+ } catch {
354
+ return { default: MarkSpacer };
355
+ }
356
+ });
357
+ function BrandMark({ size = 24, className }) {
358
+ return /* @__PURE__ */ jsx3(Suspense, { fallback: /* @__PURE__ */ jsx3(MarkSpacer, { size, className }), children: /* @__PURE__ */ jsx3(LazyKnot, { size, className }) });
359
+ }
360
+
337
361
  // src/web-react/chat-stream.ts
338
362
  function dispatchChatStreamLine(line, cb) {
339
363
  let receivedContent = false;
@@ -461,7 +485,7 @@ async function streamChatTurn(opts) {
461
485
 
462
486
  // src/web-react/mission-activity.tsx
463
487
  import { useCallback, useEffect as useEffect3, useState as useState3 } from "react";
464
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
488
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
465
489
  var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "running"]);
466
490
  var OK_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "succeeded"]);
467
491
  var ERROR_STATUSES = /* @__PURE__ */ new Set(["failed", "error", "cancelled", "aborted"]);
@@ -508,15 +532,15 @@ function waterfallLayout(trace) {
508
532
  });
509
533
  }
510
534
  function ChevronGlyph({ className }) {
511
- return /* @__PURE__ */ jsx3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "m6 9 6 6 6-6" }) });
535
+ return /* @__PURE__ */ jsx4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx4("path", { d: "m6 9 6 6 6-6" }) });
512
536
  }
513
537
  function RefreshGlyph({ className }) {
514
- return /* @__PURE__ */ jsx3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6" }) });
538
+ return /* @__PURE__ */ jsx4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx4("path", { d: "M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6" }) });
515
539
  }
516
540
  function CopyGlyph({ className }) {
517
541
  return /* @__PURE__ */ jsxs3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
518
- /* @__PURE__ */ jsx3("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
519
- /* @__PURE__ */ jsx3("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
542
+ /* @__PURE__ */ jsx4("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
543
+ /* @__PURE__ */ jsx4("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
520
544
  ] });
521
545
  }
522
546
  function TraceIdCopy({ traceId }) {
@@ -540,23 +564,23 @@ function TraceIdCopy({ traceId }) {
540
564
  "aria-label": "Copy trace id",
541
565
  className: "inline-flex min-w-0 items-center gap-1.5 rounded text-left font-mono text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-card",
542
566
  children: [
543
- /* @__PURE__ */ jsx3("span", { className: "truncate", children: traceId }),
544
- /* @__PURE__ */ jsx3(CopyGlyph, { className: "h-3 w-3 shrink-0" }),
545
- copied && /* @__PURE__ */ jsx3("span", { className: "shrink-0 not-italic text-success", children: "copied" })
567
+ /* @__PURE__ */ jsx4("span", { className: "truncate", children: traceId }),
568
+ /* @__PURE__ */ jsx4(CopyGlyph, { className: "h-3 w-3 shrink-0" }),
569
+ copied && /* @__PURE__ */ jsx4("span", { className: "shrink-0 not-italic text-success", children: "copied" })
546
570
  ]
547
571
  }
548
572
  );
549
573
  }
550
574
  function StatusDot({ tone }) {
551
575
  return /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center", children: [
552
- /* @__PURE__ */ jsx3(
576
+ /* @__PURE__ */ jsx4(
553
577
  "span",
554
578
  {
555
579
  "aria-hidden": true,
556
580
  className: `h-2 w-2 shrink-0 rounded-full ${tone === "live" ? "animate-pulse bg-warning" : tone === "ok" ? "bg-success" : tone === "error" ? "bg-destructive" : "bg-muted-foreground/40"}`
557
581
  }
558
582
  ),
559
- /* @__PURE__ */ jsx3("span", { className: "sr-only", children: tone })
583
+ /* @__PURE__ */ jsx4("span", { className: "sr-only", children: tone })
560
584
  ] });
561
585
  }
562
586
  var BAR_CLASS = {
@@ -570,15 +594,15 @@ function FlowWaterfall({ trace }) {
570
594
  const cost = formatActivityCost(trace.costUsd);
571
595
  return /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
572
596
  rows.map((row, i) => /* @__PURE__ */ jsxs3("div", { className: "grid grid-cols-[minmax(0,2fr)_minmax(0,3fr)_auto] items-center gap-2", children: [
573
- /* @__PURE__ */ jsx3("span", { className: "truncate font-mono text-[11px] text-muted-foreground", title: row.name, children: row.name }),
574
- /* @__PURE__ */ jsx3("div", { className: "relative h-2 rounded-sm bg-muted/40", children: /* @__PURE__ */ jsx3(
597
+ /* @__PURE__ */ jsx4("span", { className: "truncate font-mono text-[11px] text-muted-foreground", title: row.name, children: row.name }),
598
+ /* @__PURE__ */ jsx4("div", { className: "relative h-2 rounded-sm bg-muted/40", children: /* @__PURE__ */ jsx4(
575
599
  "div",
576
600
  {
577
601
  className: `absolute inset-y-0 rounded-sm ${row.ok ? BAR_CLASS[row.kind] : "bg-destructive/80"} ${row.approx ? "opacity-70" : ""}`,
578
602
  style: { left: `${row.offsetPct}%`, width: `${row.widthPct}%` }
579
603
  }
580
604
  ) }),
581
- /* @__PURE__ */ jsx3("span", { className: "shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: row.durationLabel })
605
+ /* @__PURE__ */ jsx4("span", { className: "shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: row.durationLabel })
582
606
  ] }, i)),
583
607
  /* @__PURE__ */ jsxs3("p", { className: "pt-0.5 text-right font-mono text-[10px] tabular-nums text-muted-foreground/60", children: [
584
608
  (trace.totalMs / 1e3).toFixed(1),
@@ -596,19 +620,19 @@ function MissionActivityLane({ activity, startedAt, nowMs }) {
596
620
  const cost = formatActivityCost(run.costUsd);
597
621
  const duration = formatActivityDuration(run.durationMs);
598
622
  return /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
599
- /* @__PURE__ */ jsx3(StatusDot, { tone }),
623
+ /* @__PURE__ */ jsx4(StatusDot, { tone }),
600
624
  /* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1 truncate", children: [
601
- /* @__PURE__ */ jsx3("span", { className: "font-medium", children: run.tool }),
625
+ /* @__PURE__ */ jsx4("span", { className: "font-medium", children: run.tool }),
602
626
  /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
603
627
  " \u2014 ",
604
628
  run.detail
605
629
  ] })
606
630
  ] }),
607
- tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */ jsx3("span", { className: "shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 font-mono text-[10px] text-warning", children: [run.iteration !== void 0 ? `iter ${run.iteration}` : null, run.phase ?? null].filter(Boolean).join(" \xB7 ") }),
631
+ tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */ jsx4("span", { className: "shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 font-mono text-[10px] text-warning", children: [run.iteration !== void 0 ? `iter ${run.iteration}` : null, run.phase ?? null].filter(Boolean).join(" \xB7 ") }),
608
632
  /* @__PURE__ */ jsxs3("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: [
609
- tone !== "live" && tone !== "ok" && /* @__PURE__ */ jsx3("span", { children: run.status }),
610
- cost && /* @__PURE__ */ jsx3("span", { children: cost }),
611
- duration && /* @__PURE__ */ jsx3("span", { children: duration })
633
+ tone !== "live" && tone !== "ok" && /* @__PURE__ */ jsx4("span", { children: run.status }),
634
+ cost && /* @__PURE__ */ jsx4("span", { children: cost }),
635
+ duration && /* @__PURE__ */ jsx4("span", { children: duration })
612
636
  ] })
613
637
  ] }, run.taskId);
614
638
  }),
@@ -619,12 +643,12 @@ function MissionActivityLane({ activity, startedAt, nowMs }) {
619
643
  onClick: () => setExpanded((v) => !v),
620
644
  className: "flex items-center gap-1 py-0.5 text-[10px] font-medium text-muted-foreground/70 transition hover:text-foreground",
621
645
  children: [
622
- /* @__PURE__ */ jsx3(ChevronGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
646
+ /* @__PURE__ */ jsx4(ChevronGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
623
647
  "timeline"
624
648
  ]
625
649
  }
626
650
  ),
627
- expanded && /* @__PURE__ */ jsx3("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx3(
651
+ expanded && /* @__PURE__ */ jsx4("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx4(
628
652
  FlowWaterfall,
629
653
  {
630
654
  trace: stepActivityFlowTrace(activity, {
@@ -645,39 +669,39 @@ function ActivityRow({
645
669
  const duration = formatActivityDuration(record.durationMs);
646
670
  return /* @__PURE__ */ jsxs3("div", { className: "rounded-lg border border-border/60 bg-card", children: [
647
671
  /* @__PURE__ */ jsxs3("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm", children: [
648
- /* @__PURE__ */ jsx3(StatusDot, { tone }),
672
+ /* @__PURE__ */ jsx4(StatusDot, { tone }),
649
673
  /* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1 truncate", children: [
650
- /* @__PURE__ */ jsx3("span", { className: "font-medium", children: record.tool }),
674
+ /* @__PURE__ */ jsx4("span", { className: "font-medium", children: record.tool }),
651
675
  /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
652
676
  " \u2014 ",
653
677
  record.detail
654
678
  ] })
655
679
  ] }),
656
- tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */ jsx3("span", { className: "shrink-0 rounded-full bg-warning/10 px-2 py-0.5 font-mono text-[10px] text-warning", children: [record.iteration !== void 0 ? `iter ${record.iteration}` : null, record.phase ?? null].filter(Boolean).join(" \xB7 ") }),
657
- /* @__PURE__ */ jsx3(
680
+ tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */ jsx4("span", { className: "shrink-0 rounded-full bg-warning/10 px-2 py-0.5 font-mono text-[10px] text-warning", children: [record.iteration !== void 0 ? `iter ${record.iteration}` : null, record.phase ?? null].filter(Boolean).join(" \xB7 ") }),
681
+ /* @__PURE__ */ jsx4(
658
682
  "span",
659
683
  {
660
684
  className: `shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium ${tone === "ok" ? "bg-success/10 text-success" : tone === "error" ? "bg-destructive/10 text-destructive" : tone === "live" ? "bg-warning/10 text-warning" : "bg-muted/60 text-muted-foreground"}`,
661
685
  children: record.status
662
686
  }
663
687
  ),
664
- cost && /* @__PURE__ */ jsx3("span", { className: "shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground", children: cost }),
665
- /* @__PURE__ */ jsx3(ChevronGlyph, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })
688
+ cost && /* @__PURE__ */ jsx4("span", { className: "shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground", children: cost }),
689
+ /* @__PURE__ */ jsx4(ChevronGlyph, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })
666
690
  ] }),
667
691
  open && /* @__PURE__ */ jsxs3("div", { className: "space-y-2.5 border-t border-border/40 px-3 py-2.5", children: [
668
- record.durationMs !== void 0 && /* @__PURE__ */ jsx3("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx3(FlowWaterfall, { trace: stepActivityFlowTrace([record]) }) }),
692
+ record.durationMs !== void 0 && /* @__PURE__ */ jsx4("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx4(FlowWaterfall, { trace: stepActivityFlowTrace([record]) }) }),
669
693
  /* @__PURE__ */ jsxs3("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-[11px]", children: [
670
- /* @__PURE__ */ jsx3("dt", { className: "text-muted-foreground/60", children: "task" }),
671
- /* @__PURE__ */ jsx3("dd", { className: "truncate text-muted-foreground", children: record.taskId }),
672
- /* @__PURE__ */ jsx3("dt", { className: "text-muted-foreground/60", children: "started" }),
673
- /* @__PURE__ */ jsx3("dd", { className: "text-muted-foreground", children: new Date(record.startedAt).toLocaleString() }),
694
+ /* @__PURE__ */ jsx4("dt", { className: "text-muted-foreground/60", children: "task" }),
695
+ /* @__PURE__ */ jsx4("dd", { className: "truncate text-muted-foreground", children: record.taskId }),
696
+ /* @__PURE__ */ jsx4("dt", { className: "text-muted-foreground/60", children: "started" }),
697
+ /* @__PURE__ */ jsx4("dd", { className: "text-muted-foreground", children: new Date(record.startedAt).toLocaleString() }),
674
698
  duration && /* @__PURE__ */ jsxs3(Fragment2, { children: [
675
- /* @__PURE__ */ jsx3("dt", { className: "text-muted-foreground/60", children: "duration" }),
676
- /* @__PURE__ */ jsx3("dd", { className: "text-muted-foreground", children: duration })
699
+ /* @__PURE__ */ jsx4("dt", { className: "text-muted-foreground/60", children: "duration" }),
700
+ /* @__PURE__ */ jsx4("dd", { className: "text-muted-foreground", children: duration })
677
701
  ] }),
678
702
  record.traceId && /* @__PURE__ */ jsxs3(Fragment2, { children: [
679
- /* @__PURE__ */ jsx3("dt", { className: "text-muted-foreground/60", children: "trace" }),
680
- /* @__PURE__ */ jsx3("dd", { className: "min-w-0", children: /* @__PURE__ */ jsx3(TraceIdCopy, { traceId: record.traceId }) })
703
+ /* @__PURE__ */ jsx4("dt", { className: "text-muted-foreground/60", children: "trace" }),
704
+ /* @__PURE__ */ jsx4("dd", { className: "min-w-0", children: /* @__PURE__ */ jsx4(TraceIdCopy, { traceId: record.traceId }) })
681
705
  ] })
682
706
  ] }),
683
707
  record.missionRef && renderMissionRef?.(record.missionRef, record)
@@ -710,8 +734,8 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
710
734
  }, [load]);
711
735
  return /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
712
736
  /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
713
- /* @__PURE__ */ jsx3("h2", { className: "flex-1 text-sm font-semibold", children: title }),
714
- /* @__PURE__ */ jsx3(
737
+ /* @__PURE__ */ jsx4("h2", { className: "flex-1 text-sm font-semibold", children: title }),
738
+ /* @__PURE__ */ jsx4(
715
739
  "button",
716
740
  {
717
741
  type: "button",
@@ -719,14 +743,14 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
719
743
  disabled: loading,
720
744
  "aria-label": "Refresh",
721
745
  className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground disabled:opacity-50",
722
- children: /* @__PURE__ */ jsx3(RefreshGlyph, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` })
746
+ children: /* @__PURE__ */ jsx4(RefreshGlyph, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` })
723
747
  }
724
748
  )
725
749
  ] }),
726
- error && /* @__PURE__ */ jsx3("p", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: error }),
727
- !error && rows.length === 0 && !loading && /* @__PURE__ */ jsx3("p", { className: "px-1 text-sm text-muted-foreground", children: emptyLabel }),
728
- /* @__PURE__ */ jsx3("div", { className: "space-y-1.5", children: rows.map((record) => /* @__PURE__ */ jsx3(ActivityRow, { record, renderMissionRef }, record.taskId)) }),
729
- cursor && /* @__PURE__ */ jsx3(
750
+ error && /* @__PURE__ */ jsx4("p", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: error }),
751
+ !error && rows.length === 0 && !loading && /* @__PURE__ */ jsx4("p", { className: "px-1 text-sm text-muted-foreground", children: emptyLabel }),
752
+ /* @__PURE__ */ jsx4("div", { className: "space-y-1.5", children: rows.map((record) => /* @__PURE__ */ jsx4(ActivityRow, { record, renderMissionRef }, record.taskId)) }),
753
+ cursor && /* @__PURE__ */ jsx4(
730
754
  "button",
731
755
  {
732
756
  type: "button",
@@ -901,9 +925,9 @@ function tabTerminalConnectionId(storageKey = DEFAULT_TERMINAL_CID_KEY) {
901
925
  }
902
926
 
903
927
  // src/web-react/workspace-terminal-panel.tsx
904
- import { lazy, Suspense } from "react";
905
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
906
- var TerminalView = lazy(
928
+ import { lazy as lazy2, Suspense as Suspense2 } from "react";
929
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
930
+ var TerminalView = lazy2(
907
931
  () => import("@tangle-network/sandbox-ui/terminal").then((m) => ({ default: m.TerminalView }))
908
932
  );
909
933
  var TONE_DOT = {
@@ -935,18 +959,18 @@ function WorkspaceTerminalPanel({
935
959
  return /* @__PURE__ */ jsxs4("div", { className: `flex h-full min-h-0 flex-col overflow-hidden rounded-xl border border-border bg-card ${className ?? ""}`, children: [
936
960
  /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-3 border-b border-border px-4 py-2.5", children: [
937
961
  /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
938
- /* @__PURE__ */ jsx4("p", { className: "truncate text-sm font-medium text-foreground", children: title }),
939
- subtitle && /* @__PURE__ */ jsx4("p", { className: "truncate text-xs text-muted-foreground", children: subtitle })
962
+ /* @__PURE__ */ jsx5("p", { className: "truncate text-sm font-medium text-foreground", children: title }),
963
+ subtitle && /* @__PURE__ */ jsx5("p", { className: "truncate text-xs text-muted-foreground", children: subtitle })
940
964
  ] }),
941
965
  /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
942
966
  /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
943
- /* @__PURE__ */ jsx4("span", { className: `h-1.5 w-1.5 rounded-full ${TONE_DOT[status.tone]}`, "aria-hidden": true }),
967
+ /* @__PURE__ */ jsx5("span", { className: `h-1.5 w-1.5 rounded-full ${TONE_DOT[status.tone]}`, "aria-hidden": true }),
944
968
  status.label
945
969
  ] }),
946
970
  headerExtra
947
971
  ] })
948
972
  ] }),
949
- /* @__PURE__ */ jsx4("div", { className: "relative min-h-0 flex-1", children: ready ? /* @__PURE__ */ jsx4(Suspense, { fallback: /* @__PURE__ */ jsx4(TerminalMessage, { children: "Loading terminal\u2026" }), children: /* @__PURE__ */ jsx4(
973
+ /* @__PURE__ */ jsx5("div", { className: "relative min-h-0 flex-1", children: ready ? /* @__PURE__ */ jsx5(Suspense2, { fallback: /* @__PURE__ */ jsx5(TerminalMessage, { children: "Loading terminal\u2026" }), children: /* @__PURE__ */ jsx5(
950
974
  TerminalView,
951
975
  {
952
976
  apiUrl,
@@ -956,9 +980,9 @@ function WorkspaceTerminalPanel({
956
980
  subtitle,
957
981
  isActive
958
982
  }
959
- ) }) : /* @__PURE__ */ jsx4(TerminalMessage, { children: connection.error ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
960
- /* @__PURE__ */ jsx4("p", { className: "text-sm text-destructive", children: connection.error }),
961
- onRetry && /* @__PURE__ */ jsx4(
983
+ ) }) : /* @__PURE__ */ jsx5(TerminalMessage, { children: connection.error ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
984
+ /* @__PURE__ */ jsx5("p", { className: "text-sm text-destructive", children: connection.error }),
985
+ onRetry && /* @__PURE__ */ jsx5(
962
986
  "button",
963
987
  {
964
988
  type: "button",
@@ -967,9 +991,9 @@ function WorkspaceTerminalPanel({
967
991
  children: "Reconnect"
968
992
  }
969
993
  )
970
- ] }) : connection.loading ? /* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground", children: connection.status === "provisioning" ? "Provisioning sandbox\u2026" : "Connecting\u2026" }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
971
- /* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground", children: "Terminal not connected." }),
972
- onRetry && /* @__PURE__ */ jsx4(
994
+ ] }) : connection.loading ? /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: connection.status === "provisioning" ? "Provisioning sandbox\u2026" : "Connecting\u2026" }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
995
+ /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: "Terminal not connected." }),
996
+ onRetry && /* @__PURE__ */ jsx5(
973
997
  "button",
974
998
  {
975
999
  type: "button",
@@ -982,13 +1006,13 @@ function WorkspaceTerminalPanel({
982
1006
  ] });
983
1007
  }
984
1008
  function TerminalMessage({ children }) {
985
- return /* @__PURE__ */ jsx4("div", { className: "absolute inset-0 flex flex-col items-center justify-center p-6 text-center", children });
1009
+ return /* @__PURE__ */ jsx5("div", { className: "absolute inset-0 flex flex-col items-center justify-center p-6 text-center", children });
986
1010
  }
987
1011
 
988
1012
  // src/web-react/seat-paywall.tsx
989
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1013
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
990
1014
  function CheckGlyph() {
991
- return /* @__PURE__ */ jsx5(
1015
+ return /* @__PURE__ */ jsx6(
992
1016
  "svg",
993
1017
  {
994
1018
  className: "h-4 w-4 shrink-0 text-primary",
@@ -999,14 +1023,14 @@ function CheckGlyph() {
999
1023
  strokeLinecap: "round",
1000
1024
  strokeLinejoin: "round",
1001
1025
  "aria-hidden": true,
1002
- children: /* @__PURE__ */ jsx5("path", { d: "M20 6 9 17l-5-5" })
1026
+ children: /* @__PURE__ */ jsx6("path", { d: "M20 6 9 17l-5-5" })
1003
1027
  }
1004
1028
  );
1005
1029
  }
1006
1030
  function Benefit({ children }) {
1007
1031
  return /* @__PURE__ */ jsxs5("li", { className: "flex items-start gap-2.5 text-sm text-foreground", children: [
1008
- /* @__PURE__ */ jsx5("span", { className: "mt-0.5", children: /* @__PURE__ */ jsx5(CheckGlyph, {}) }),
1009
- /* @__PURE__ */ jsx5("span", { children })
1032
+ /* @__PURE__ */ jsx6("span", { className: "mt-0.5", children: /* @__PURE__ */ jsx6(CheckGlyph, {}) }),
1033
+ /* @__PURE__ */ jsx6("span", { children })
1010
1034
  ] });
1011
1035
  }
1012
1036
  function SeatPaywall({
@@ -1020,30 +1044,30 @@ function SeatPaywall({
1020
1044
  footnote
1021
1045
  }) {
1022
1046
  const { pending, run } = usePending();
1023
- return /* @__PURE__ */ jsx5("div", { className: "flex min-h-[60vh] w-full items-center justify-center p-6", children: /* @__PURE__ */ jsxs5("div", { className: "w-full max-w-md rounded-2xl border border-border bg-card p-8 shadow-sm", children: [
1024
- /* @__PURE__ */ jsx5("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: product }),
1047
+ return /* @__PURE__ */ jsx6("div", { className: "flex min-h-[60vh] w-full items-center justify-center p-6", children: /* @__PURE__ */ jsxs5("div", { className: "w-full max-w-md rounded-2xl border border-border bg-card p-8 shadow-sm", children: [
1048
+ /* @__PURE__ */ jsx6("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: product }),
1025
1049
  /* @__PURE__ */ jsxs5("h1", { className: "mt-2 text-2xl font-semibold tracking-tight text-foreground", children: [
1026
1050
  "Unlock ",
1027
1051
  product
1028
1052
  ] }),
1029
- tagline && /* @__PURE__ */ jsx5("p", { className: "mt-2 text-sm text-muted-foreground", children: tagline }),
1053
+ tagline && /* @__PURE__ */ jsx6("p", { className: "mt-2 text-sm text-muted-foreground", children: tagline }),
1030
1054
  /* @__PURE__ */ jsxs5("div", { className: "mt-6 flex items-baseline gap-1.5", children: [
1031
1055
  /* @__PURE__ */ jsxs5("span", { className: "text-3xl font-semibold text-foreground", children: [
1032
1056
  "$",
1033
1057
  priceUsd
1034
1058
  ] }),
1035
- /* @__PURE__ */ jsx5("span", { className: "text-sm text-muted-foreground", children: "/mo" })
1059
+ /* @__PURE__ */ jsx6("span", { className: "text-sm text-muted-foreground", children: "/mo" })
1036
1060
  ] }),
1037
1061
  /* @__PURE__ */ jsxs5("p", { className: "mt-1 text-sm text-muted-foreground", children: [
1038
1062
  "Includes $",
1039
1063
  includedUsageUsd,
1040
1064
  "/mo of AI usage"
1041
1065
  ] }),
1042
- /* @__PURE__ */ jsx5("ul", { className: "mt-6 space-y-2.5", children: (benefits ?? [
1066
+ /* @__PURE__ */ jsx6("ul", { className: "mt-6 space-y-2.5", children: (benefits ?? [
1043
1067
  `Full access to ${product}`,
1044
1068
  `$${includedUsageUsd}/mo of AI usage included, every month`
1045
- ]).map((benefit, i) => /* @__PURE__ */ jsx5(Benefit, { children: benefit }, i)) }),
1046
- /* @__PURE__ */ jsx5(
1069
+ ]).map((benefit, i) => /* @__PURE__ */ jsx6(Benefit, { children: benefit }, i)) }),
1070
+ /* @__PURE__ */ jsx6(
1047
1071
  "button",
1048
1072
  {
1049
1073
  type: "button",
@@ -1053,13 +1077,13 @@ function SeatPaywall({
1053
1077
  children: pending ? "Opening checkout\u2026" : ctaLabel ?? `Unlock ${product}`
1054
1078
  }
1055
1079
  ),
1056
- footnote && /* @__PURE__ */ jsx5("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: footnote })
1080
+ footnote && /* @__PURE__ */ jsx6("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: footnote })
1057
1081
  ] }) });
1058
1082
  }
1059
1083
 
1060
1084
  // src/web-react/agent-session-controls.tsx
1061
1085
  import { useMemo as useMemo2, useState as useState5 } from "react";
1062
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1086
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1063
1087
  var HARNESS_LABELS = {
1064
1088
  opencode: "OpenCode (any model)",
1065
1089
  "claude-code": "Claude Code (Anthropic)",
@@ -1079,12 +1103,12 @@ function harnessLabel(h) {
1079
1103
  return HARNESS_LABELS[h] ?? h;
1080
1104
  }
1081
1105
  function ChevronDown2({ className }) {
1082
- return /* @__PURE__ */ jsx6("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx6("path", { d: "m6 9 6 6 6-6" }) });
1106
+ return /* @__PURE__ */ jsx7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "m6 9 6 6 6-6" }) });
1083
1107
  }
1084
1108
  function GearGlyph({ className }) {
1085
1109
  return /* @__PURE__ */ jsxs6("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1086
- /* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "3" }),
1087
- /* @__PURE__ */ jsx6("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
1110
+ /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "3" }),
1111
+ /* @__PURE__ */ jsx7("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
1088
1112
  ] });
1089
1113
  }
1090
1114
  var FOCUS_RING = "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background";
@@ -1106,12 +1130,12 @@ function HarnessPicker({
1106
1130
  title: "Agent backend",
1107
1131
  className: `inline-flex w-full items-center justify-between gap-1.5 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30 ${FOCUS_RING}`,
1108
1132
  children: [
1109
- /* @__PURE__ */ jsx6("span", { className: "truncate", children: harnessLabel(value) }),
1110
- /* @__PURE__ */ jsx6(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
1133
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: harnessLabel(value) }),
1134
+ /* @__PURE__ */ jsx7(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
1111
1135
  ]
1112
1136
  }
1113
1137
  ),
1114
- open && /* @__PURE__ */ jsx6("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 max-h-64 w-full min-w-[220px] overflow-y-auto rounded-xl border border-border bg-card p-1 shadow-lg", children: options.map((h) => /* @__PURE__ */ jsx6(
1138
+ open && /* @__PURE__ */ jsx7("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 max-h-64 w-full min-w-[220px] overflow-y-auto rounded-xl border border-border bg-card p-1 shadow-lg", children: options.map((h) => /* @__PURE__ */ jsx7(
1115
1139
  "button",
1116
1140
  {
1117
1141
  type: "button",
@@ -1162,7 +1186,7 @@ function AgentSessionControls(props) {
1162
1186
  const { containerRef: popoverRef, triggerProps } = usePopover(open, setOpen);
1163
1187
  const selectedModel = models.find((m) => m.id === model);
1164
1188
  const showEffort = selectedModel?.supportsReasoning ?? true;
1165
- const modelPicker = /* @__PURE__ */ jsx6(
1189
+ const modelPicker = /* @__PURE__ */ jsx7(
1166
1190
  ModelPicker,
1167
1191
  {
1168
1192
  value: model,
@@ -1175,15 +1199,15 @@ function AgentSessionControls(props) {
1175
1199
  if (layout === "inline") {
1176
1200
  return /* @__PURE__ */ jsxs6("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
1177
1201
  modelPicker,
1178
- showHarness && /* @__PURE__ */ jsx6(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
1179
- showEffort && /* @__PURE__ */ jsx6(EffortPicker, { value: effort, onChange: onEffortChange })
1202
+ showHarness && /* @__PURE__ */ jsx7(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
1203
+ showEffort && /* @__PURE__ */ jsx7(EffortPicker, { value: effort, onChange: onEffortChange })
1180
1204
  ] });
1181
1205
  }
1182
1206
  const hasAdvanced = showHarness || showEffort;
1183
1207
  return /* @__PURE__ */ jsxs6("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
1184
1208
  modelPicker,
1185
1209
  hasAdvanced && /* @__PURE__ */ jsxs6("div", { ref: popoverRef, className: "relative inline-flex", children: [
1186
- /* @__PURE__ */ jsx6(
1210
+ /* @__PURE__ */ jsx7(
1187
1211
  "button",
1188
1212
  {
1189
1213
  type: "button",
@@ -1192,19 +1216,19 @@ function AgentSessionControls(props) {
1192
1216
  title: "Model settings \u2014 pick the agent backend and how hard it thinks",
1193
1217
  className: `flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground data-[state=open]:bg-muted ${FOCUS_RING}`,
1194
1218
  "data-state": open ? "open" : "closed",
1195
- children: /* @__PURE__ */ jsx6(GearGlyph, { className: "h-4 w-4" })
1219
+ children: /* @__PURE__ */ jsx7(GearGlyph, { className: "h-4 w-4" })
1196
1220
  }
1197
1221
  ),
1198
1222
  open && /* @__PURE__ */ jsxs6("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-72 space-y-3 rounded-xl border border-border bg-card p-3 shadow-lg", children: [
1199
1223
  showHarness && /* @__PURE__ */ jsxs6("div", { className: "space-y-1.5", children: [
1200
- /* @__PURE__ */ jsx6("p", { className: "text-xs font-medium text-foreground", children: "Agent backend" }),
1201
- /* @__PURE__ */ jsx6(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
1202
- /* @__PURE__ */ jsx6("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "The engine that runs the agent. Switching it keeps your model choice compatible." })
1224
+ /* @__PURE__ */ jsx7("p", { className: "text-xs font-medium text-foreground", children: "Agent backend" }),
1225
+ /* @__PURE__ */ jsx7(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
1226
+ /* @__PURE__ */ jsx7("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "The engine that runs the agent. Switching it keeps your model choice compatible." })
1203
1227
  ] }),
1204
1228
  showEffort && /* @__PURE__ */ jsxs6("div", { className: "space-y-1.5", children: [
1205
- /* @__PURE__ */ jsx6("p", { className: "text-xs font-medium text-foreground", children: "Reasoning effort" }),
1206
- /* @__PURE__ */ jsx6(EffortPicker, { value: effort, onChange: onEffortChange }),
1207
- /* @__PURE__ */ jsx6("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "How hard the agent thinks before answering. Higher is slower but more thorough." })
1229
+ /* @__PURE__ */ jsx7("p", { className: "text-xs font-medium text-foreground", children: "Thinking" }),
1230
+ /* @__PURE__ */ jsx7(EffortPicker, { value: effort, onChange: onEffortChange, label: "" }),
1231
+ /* @__PURE__ */ jsx7("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "How hard the agent thinks before answering. Higher is slower but more thorough." })
1208
1232
  ] })
1209
1233
  ] })
1210
1234
  ] })
@@ -1212,7 +1236,7 @@ function AgentSessionControls(props) {
1212
1236
  }
1213
1237
 
1214
1238
  // src/web-react/index.tsx
1215
- import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1239
+ import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1216
1240
  function formatModelCost(msg, models) {
1217
1241
  if (msg.promptTokens == null && msg.completionTokens == null) return null;
1218
1242
  const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing;
@@ -1228,39 +1252,39 @@ function formatTokensPerSecond(msg) {
1228
1252
  function RunDrillIn({ run, onClose }) {
1229
1253
  return /* @__PURE__ */ jsxs7("div", { className: "fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-border bg-card shadow-xl", children: [
1230
1254
  /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
1231
- /* @__PURE__ */ jsx7(
1255
+ /* @__PURE__ */ jsx8(
1232
1256
  "span",
1233
1257
  {
1234
1258
  className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-warning" : run.status === "error" ? "bg-destructive" : "bg-success"}`
1235
1259
  }
1236
1260
  ),
1237
1261
  /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
1238
- /* @__PURE__ */ jsx7("p", { className: "truncate text-sm font-semibold", children: run.title }),
1239
- /* @__PURE__ */ jsx7("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
1262
+ /* @__PURE__ */ jsx8("p", { className: "truncate text-sm font-semibold", children: run.title }),
1263
+ /* @__PURE__ */ jsx8("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
1240
1264
  ] }),
1241
- /* @__PURE__ */ jsx7(
1265
+ /* @__PURE__ */ jsx8(
1242
1266
  "button",
1243
1267
  {
1244
1268
  type: "button",
1245
1269
  onClick: onClose,
1246
1270
  "aria-label": "Close",
1247
1271
  className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground",
1248
- children: /* @__PURE__ */ jsx7("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "M18 6 6 18M6 6l12 12" }) })
1272
+ children: /* @__PURE__ */ jsx8("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx8("path", { d: "M18 6 6 18M6 6l12 12" }) })
1249
1273
  }
1250
1274
  )
1251
1275
  ] }),
1252
1276
  /* @__PURE__ */ jsxs7("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
1253
- run.steps.length === 0 && /* @__PURE__ */ jsx7("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
1277
+ run.steps.length === 0 && /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
1254
1278
  run.steps.map((step, i) => /* @__PURE__ */ jsxs7("div", { className: "rounded-lg border border-border/60 bg-background", children: [
1255
1279
  /* @__PURE__ */ jsxs7("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
1256
- /* @__PURE__ */ jsx7("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-destructive" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
1257
- /* @__PURE__ */ jsx7("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
1258
- /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: new Date(step.at).toLocaleTimeString() })
1280
+ /* @__PURE__ */ jsx8("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-destructive" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
1281
+ /* @__PURE__ */ jsx8("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
1282
+ /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: new Date(step.at).toLocaleTimeString() })
1259
1283
  ] }),
1260
- step.detail && /* @__PURE__ */ jsx7("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: step.detail })
1284
+ step.detail && /* @__PURE__ */ jsx8("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: step.detail })
1261
1285
  ] }, i))
1262
1286
  ] }),
1263
- /* @__PURE__ */ jsx7("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground", children: "Readonly drill-in. Follow up in the main chat." })
1287
+ /* @__PURE__ */ jsx8("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground", children: "Readonly drill-in. Follow up in the main chat." })
1264
1288
  ] });
1265
1289
  }
1266
1290
  function pendingApprovalOf(call) {
@@ -1268,54 +1292,108 @@ function pendingApprovalOf(call) {
1268
1292
  if (!outcome?.ok || outcome.result?.status !== "queued_for_approval" || !outcome.result.proposalId) return null;
1269
1293
  return { proposalId: outcome.result.proposalId };
1270
1294
  }
1295
+ function ChatEmptyState({
1296
+ productName = "Agent",
1297
+ headline = "Ask the agent to do something",
1298
+ subline = "Describe the outcome you want. The agent works through it step by step, and pauses for your approval before anything irreversible.",
1299
+ doors
1300
+ }) {
1301
+ return /* @__PURE__ */ jsxs7("div", { className: "mx-auto flex w-full max-w-2xl flex-col items-center px-6 py-12 text-center sm:py-20", children: [
1302
+ /* @__PURE__ */ jsx8("span", { className: "mb-5 inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 ring-1 ring-primary/15", children: /* @__PURE__ */ jsx8(BrandMark, { size: 32, className: "shrink-0" }) }),
1303
+ /* @__PURE__ */ jsx8("p", { className: "text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground", children: productName }),
1304
+ /* @__PURE__ */ jsx8("h2", { className: "mt-1.5 text-balance text-2xl font-semibold leading-tight text-foreground sm:text-[28px]", children: headline }),
1305
+ subline && /* @__PURE__ */ jsx8("p", { className: "mt-3 max-w-md text-[15px] leading-relaxed text-muted-foreground", children: subline }),
1306
+ doors && doors.length > 0 && /* @__PURE__ */ jsx8("div", { className: "mt-7 grid w-full gap-2.5 sm:grid-cols-3", children: doors.slice(0, 3).map((door, i) => /* @__PURE__ */ jsxs7(
1307
+ "button",
1308
+ {
1309
+ type: "button",
1310
+ onClick: door.onSelect,
1311
+ className: "group flex min-h-[44px] flex-col items-start rounded-xl border border-border bg-card px-4 py-3 text-left transition hover:border-primary/40 hover:bg-accent/30 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1312
+ children: [
1313
+ /* @__PURE__ */ jsx8("span", { className: "text-sm font-semibold text-foreground", children: door.label }),
1314
+ door.description && /* @__PURE__ */ jsx8("span", { className: "mt-0.5 text-[12px] leading-snug text-muted-foreground", children: door.description })
1315
+ ]
1316
+ },
1317
+ i
1318
+ )) })
1319
+ ] });
1320
+ }
1271
1321
  function ToolGlyph({ name, className }) {
1272
1322
  if (name.startsWith("sandbox_")) {
1273
1323
  return /* @__PURE__ */ jsxs7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1274
- /* @__PURE__ */ jsx7("polyline", { points: "4 17 10 11 4 5" }),
1275
- /* @__PURE__ */ jsx7("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
1324
+ /* @__PURE__ */ jsx8("polyline", { points: "4 17 10 11 4 5" }),
1325
+ /* @__PURE__ */ jsx8("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
1276
1326
  ] });
1277
1327
  }
1278
1328
  if (name === "submit_proposal") {
1279
1329
  return /* @__PURE__ */ jsxs7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1280
- /* @__PURE__ */ jsx7("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
1281
- /* @__PURE__ */ jsx7("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
1330
+ /* @__PURE__ */ jsx8("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
1331
+ /* @__PURE__ */ jsx8("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
1282
1332
  ] });
1283
1333
  }
1284
1334
  if (name === "schedule_followup") {
1285
1335
  return /* @__PURE__ */ jsxs7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
1286
- /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "9" }),
1287
- /* @__PURE__ */ jsx7("path", { d: "M12 7v5l3 3" })
1336
+ /* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "9" }),
1337
+ /* @__PURE__ */ jsx8("path", { d: "M12 7v5l3 3" })
1288
1338
  ] });
1289
1339
  }
1290
1340
  return /* @__PURE__ */ jsxs7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1291
- /* @__PURE__ */ jsx7("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
1292
- /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "4" })
1341
+ /* @__PURE__ */ jsx8("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
1342
+ /* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "4" })
1293
1343
  ] });
1294
1344
  }
1295
1345
  function toolOutcomeOf(call) {
1296
1346
  return call.result;
1297
1347
  }
1348
+ function blockKindOf(call) {
1349
+ if (call.name === "submit_proposal") return "proposal";
1350
+ if (call.name === "schedule_followup") return "followup";
1351
+ if (call.name.startsWith("sandbox_")) return "command";
1352
+ return "generic";
1353
+ }
1298
1354
  function friendlyToolTitle(call) {
1299
1355
  const a = call.args ?? {};
1300
1356
  switch (call.name) {
1301
1357
  case "submit_proposal":
1302
- return `Proposal \xB7 ${String(a.type ?? "")}${a.title ? `: ${String(a.title)}` : ""}`;
1358
+ return a.title ? `Approve: ${String(a.title)}?` : "Approve this action?";
1303
1359
  case "sandbox_create":
1304
- return `Create sandbox (${String(a.environment ?? "universal")})`;
1360
+ return `Created sandbox (${String(a.environment ?? "universal")})`;
1305
1361
  case "sandbox_run_command":
1306
- return `$ ${String(a.command ?? "")}`;
1362
+ return `Ran ${String(a.command ?? "command")}`;
1307
1363
  case "sandbox_destroy":
1308
- return `Destroy sandbox ${String(a.sandbox_id ?? "")}`;
1364
+ return `Destroyed sandbox ${String(a.sandbox_id ?? "")}`;
1309
1365
  case "schedule_followup":
1310
- return `Follow-up \xB7 ${String(a.title ?? "")}`;
1366
+ return `Scheduled: ${String(a.title ?? "follow-up")}`;
1311
1367
  case "render_ui":
1312
- return `Render view \xB7 ${String(a.title ?? "")}`;
1368
+ return `Rendered view \xB7 ${String(a.title ?? "")}`;
1313
1369
  case "add_citation":
1314
- return `Citation \xB7 ${String(a.path ?? "")}`;
1370
+ return `Cited ${String(a.path ?? "")}`;
1315
1371
  default:
1316
1372
  return call.name;
1317
1373
  }
1318
1374
  }
1375
+ function proposalPreview(call) {
1376
+ const a = call.args ?? {};
1377
+ const asString = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
1378
+ const asList = (v) => Array.isArray(v) ? v.map((x) => typeof x === "string" ? x : null).filter((x) => !!x) : asString(v) ? [asString(v)] : [];
1379
+ const verbPhrase = asString(a.summary) ?? asString(a.description) ?? (asString(a.type) ? `${String(a.type).replace(/_/g, " ")}${asString(a.title) ? `: ${asString(a.title)}` : ""}` : null);
1380
+ const destinations = [
1381
+ ...asList(a.destinations),
1382
+ ...asList(a.channels),
1383
+ ...asList(a.targets),
1384
+ ...asList(a.platforms)
1385
+ ];
1386
+ const dest = destinations.length ? ` to ${destinations.join(" and ")}` : "";
1387
+ const summary = verbPhrase ? `${verbPhrase}${dest}` : destinations.length ? `Publish to ${destinations.join(" and ")}` : null;
1388
+ const meta = [];
1389
+ const cost = a.cost ?? a.price ?? a.estimatedCost;
1390
+ if (typeof cost === "number" && cost > 0) meta.push(`~$${cost < 0.01 ? cost.toFixed(4) : cost.toFixed(2)}`);
1391
+ else if (asString(cost)) meta.push(asString(cost));
1392
+ const reach = a.reach ?? a.audience ?? a.estimatedReach;
1393
+ if (typeof reach === "number" && reach > 0) meta.push(`reaches ~${reach.toLocaleString()}`);
1394
+ else if (asString(reach)) meta.push(asString(reach));
1395
+ return { summary, meta };
1396
+ }
1319
1397
  function truncate(v, max = 240) {
1320
1398
  const s = typeof v === "string" ? v : JSON.stringify(v);
1321
1399
  return s.length > max ? `${s.slice(0, max)}\u2026` : s;
@@ -1323,9 +1401,9 @@ function truncate(v, max = 240) {
1323
1401
  function KvRows({ data }) {
1324
1402
  const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
1325
1403
  if (!entries.length) return null;
1326
- return /* @__PURE__ */ jsx7("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs7("div", { className: "contents", children: [
1327
- /* @__PURE__ */ jsx7("dt", { className: "font-mono text-[11px] text-muted-foreground", children: k }),
1328
- /* @__PURE__ */ jsx7("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
1404
+ return /* @__PURE__ */ jsx8("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs7("div", { className: "contents", children: [
1405
+ /* @__PURE__ */ jsx8("dt", { className: "font-mono text-[11px] text-muted-foreground", children: k }),
1406
+ /* @__PURE__ */ jsx8("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
1329
1407
  ] }, k)) });
1330
1408
  }
1331
1409
  function ShellDetail({ call }) {
@@ -1333,29 +1411,101 @@ function ShellDetail({ call }) {
1333
1411
  const r = outcome?.result ?? {};
1334
1412
  return /* @__PURE__ */ jsxs7("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
1335
1413
  /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
1336
- /* @__PURE__ */ jsx7("span", { className: "select-none text-zinc-500", children: "$" }),
1337
- /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
1414
+ /* @__PURE__ */ jsx8("span", { className: "select-none text-zinc-500", children: "$" }),
1415
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
1338
1416
  r.exitCode != null && /* @__PURE__ */ jsxs7("span", { className: r.exitCode === 0 ? "text-success" : "text-destructive", children: [
1339
1417
  "exit ",
1340
1418
  r.exitCode
1341
1419
  ] })
1342
1420
  ] }),
1343
- /* @__PURE__ */ jsx7("pre", { className: "max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300", children: outcome?.ok === false ? outcome.message ?? "failed" : [r.stdout, r.stderr].filter(Boolean).join("\n") || "(no output)" })
1421
+ /* @__PURE__ */ jsx8("pre", { className: "max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300", children: outcome?.ok === false ? outcome.message ?? "failed" : [r.stdout, r.stderr].filter(Boolean).join("\n") || "(no output)" })
1344
1422
  ] });
1345
1423
  }
1346
1424
  function DefaultToolDetail({ call }) {
1347
1425
  const outcome = toolOutcomeOf(call);
1348
1426
  return /* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
1349
1427
  call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs7("div", { children: [
1350
- /* @__PURE__ */ jsx7("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: "Called with" }),
1351
- /* @__PURE__ */ jsx7(KvRows, { data: call.args })
1428
+ /* @__PURE__ */ jsx8("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: "Called with" }),
1429
+ /* @__PURE__ */ jsx8(KvRows, { data: call.args })
1352
1430
  ] }),
1353
1431
  outcome && /* @__PURE__ */ jsxs7("div", { children: [
1354
- /* @__PURE__ */ jsx7("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: outcome.ok === false ? "Failed" : "Result" }),
1355
- outcome.ok === false ? /* @__PURE__ */ jsx7("p", { className: "text-xs text-destructive", children: outcome.message ?? "Tool failed" }) : outcome.result && typeof outcome.result === "object" ? /* @__PURE__ */ jsx7(KvRows, { data: outcome.result }) : /* @__PURE__ */ jsx7("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(outcome.result) })
1432
+ /* @__PURE__ */ jsx8("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: outcome.ok === false ? "Failed" : "Result" }),
1433
+ outcome.ok === false ? /* @__PURE__ */ jsx8("p", { className: "text-xs text-destructive", children: outcome.message ?? "Tool failed" }) : outcome.result && typeof outcome.result === "object" ? /* @__PURE__ */ jsx8(KvRows, { data: outcome.result }) : /* @__PURE__ */ jsx8("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(outcome.result) })
1356
1434
  ] })
1357
1435
  ] });
1358
1436
  }
1437
+ function ProposalCard({
1438
+ call,
1439
+ message,
1440
+ pending,
1441
+ approval,
1442
+ renderers
1443
+ }) {
1444
+ const [expanded, setExpanded] = useState6(false);
1445
+ const { summary, meta } = proposalPreview(call);
1446
+ const custom = renderers?.[call.name]?.(call, message);
1447
+ const { pending: deciding, run: decide } = usePending();
1448
+ return /* @__PURE__ */ jsxs7("div", { className: "w-full max-w-full rounded-xl border border-warning/50 bg-warning/[0.06] text-sm shadow-sm ring-1 ring-warning/10", children: [
1449
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-start gap-2.5 px-4 pt-3.5", children: [
1450
+ /* @__PURE__ */ jsx8("span", { className: "mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-warning/15 text-warning", children: /* @__PURE__ */ jsx8(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5" }) }),
1451
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
1452
+ /* @__PURE__ */ jsx8("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-warning-foreground", children: "Needs your approval" }),
1453
+ /* @__PURE__ */ jsx8("p", { className: "mt-0.5 text-[15px] font-semibold leading-snug text-foreground", children: friendlyToolTitle(call) }),
1454
+ summary && /* @__PURE__ */ jsx8("p", { className: "mt-1 text-[13px] leading-relaxed text-muted-foreground", children: summary }),
1455
+ meta.length > 0 && /* @__PURE__ */ jsx8("div", { className: "mt-1.5 flex flex-wrap items-center gap-1.5", children: meta.map((m, i) => /* @__PURE__ */ jsx8("span", { className: "rounded-full bg-muted/60 px-2 py-0.5 text-[11px] font-medium text-muted-foreground", children: m }, i)) })
1456
+ ] })
1457
+ ] }),
1458
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-2 px-4 pb-3.5 pt-3", children: [
1459
+ approval ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
1460
+ /* @__PURE__ */ jsx8(
1461
+ "button",
1462
+ {
1463
+ type: "button",
1464
+ disabled: deciding,
1465
+ onClick: () => decide(() => approval.onApprove(pending.proposalId, call.id)),
1466
+ className: "inline-flex min-h-[40px] flex-1 items-center justify-center rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground shadow-sm transition hover:bg-primary/90 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card disabled:cursor-not-allowed disabled:opacity-60 sm:flex-none sm:min-w-[160px]",
1467
+ children: "Approve & run"
1468
+ }
1469
+ ),
1470
+ /* @__PURE__ */ jsx8(
1471
+ "button",
1472
+ {
1473
+ type: "button",
1474
+ disabled: deciding,
1475
+ onClick: () => decide(() => approval.onReject(pending.proposalId, call.id)),
1476
+ className: "inline-flex min-h-[40px] items-center justify-center rounded-lg border border-border bg-transparent px-4 py-2 text-sm font-medium text-muted-foreground transition hover:bg-accent/30 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card disabled:cursor-not-allowed disabled:opacity-60",
1477
+ children: "Reject"
1478
+ }
1479
+ )
1480
+ ] }) : /* @__PURE__ */ jsx8("span", { className: "text-[12px] font-medium text-muted-foreground", children: "Awaiting approval\u2026" }),
1481
+ /* @__PURE__ */ jsxs7(
1482
+ "button",
1483
+ {
1484
+ type: "button",
1485
+ onClick: () => setExpanded((v) => !v),
1486
+ "aria-expanded": expanded,
1487
+ className: "ml-auto inline-flex items-center gap-1 rounded text-[12px] font-medium text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1488
+ children: [
1489
+ expanded ? "Hide details" : "View details",
1490
+ /* @__PURE__ */ jsx8(ChevronDown, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` })
1491
+ ]
1492
+ }
1493
+ )
1494
+ ] }),
1495
+ expanded && /* @__PURE__ */ jsx8("div", { className: "border-t border-warning/20 px-4 py-3 text-xs", children: custom ?? /* @__PURE__ */ jsx8(DefaultToolDetail, { call }) })
1496
+ ] });
1497
+ }
1498
+ function FollowupCard({ call }) {
1499
+ const a = call.args ?? {};
1500
+ const when = typeof a.when === "string" ? a.when : typeof a.at === "string" ? a.at : typeof a.schedule === "string" ? a.schedule : null;
1501
+ return /* @__PURE__ */ jsxs7("div", { className: "w-fit min-w-[260px] max-w-full rounded-lg border border-border/60 border-l-2 border-l-primary/60 bg-muted/20 px-3 py-2 text-sm", children: [
1502
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
1503
+ /* @__PURE__ */ jsx8(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-primary/80" }),
1504
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", children: friendlyToolTitle(call) })
1505
+ ] }),
1506
+ when && /* @__PURE__ */ jsx8("p", { className: "mt-0.5 pl-[22px] text-[12px] text-muted-foreground", children: when })
1507
+ ] });
1508
+ }
1359
1509
  function ToolCallCard({
1360
1510
  call,
1361
1511
  message,
@@ -1365,13 +1515,29 @@ function ToolCallCard({
1365
1515
  }) {
1366
1516
  const [expanded, setExpanded] = useState6(false);
1367
1517
  const pending = call.status === "done" ? pendingApprovalOf(call) : null;
1518
+ const kind = blockKindOf(call);
1368
1519
  const failed = call.status === "error" || toolOutcomeOf(call)?.ok === false;
1369
1520
  const custom = renderers?.[call.name]?.(call, message);
1370
- const { pending: deciding, run: decide } = usePending();
1521
+ if (pending) {
1522
+ return /* @__PURE__ */ jsx8(
1523
+ ProposalCard,
1524
+ {
1525
+ call,
1526
+ message,
1527
+ pending,
1528
+ approval,
1529
+ renderers
1530
+ }
1531
+ );
1532
+ }
1533
+ if (kind === "followup" && !failed) {
1534
+ return /* @__PURE__ */ jsx8(FollowupCard, { call });
1535
+ }
1536
+ const isCommand = kind === "command";
1371
1537
  return /* @__PURE__ */ jsxs7(
1372
1538
  "div",
1373
1539
  {
1374
- className: `w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${pending ? "border-warning/40 bg-warning/5" : failed ? "border-destructive/40 bg-destructive/5" : "border-border/60 bg-muted/20"}`,
1540
+ className: `w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${failed ? "border-destructive/40 bg-destructive/5" : "border-border/60 bg-muted/20"}`,
1375
1541
  children: [
1376
1542
  /* @__PURE__ */ jsxs7("div", { className: "flex w-full items-center gap-2 px-3 py-2", children: [
1377
1543
  /* @__PURE__ */ jsxs7(
@@ -1382,41 +1548,25 @@ function ToolCallCard({
1382
1548
  "aria-expanded": expanded,
1383
1549
  className: "flex min-w-0 flex-1 items-center gap-2 rounded text-left focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1384
1550
  children: [
1385
- /* @__PURE__ */ jsx7(
1551
+ /* @__PURE__ */ jsx8(
1386
1552
  "span",
1387
1553
  {
1388
- className: `h-2 w-2 shrink-0 rounded-full ${call.status === "running" ? "animate-pulse bg-warning" : pending ? "bg-warning" : failed ? "bg-destructive" : "bg-success"}`
1554
+ className: `h-2 w-2 shrink-0 rounded-full ${call.status === "running" ? "animate-pulse bg-warning" : failed ? "bg-destructive" : "bg-success"}`
1389
1555
  }
1390
1556
  ),
1391
- /* @__PURE__ */ jsx7(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1392
- /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate font-medium", children: friendlyToolTitle(call) })
1557
+ /* @__PURE__ */ jsx8(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1558
+ /* @__PURE__ */ jsx8(
1559
+ "span",
1560
+ {
1561
+ className: `min-w-0 flex-1 truncate ${isCommand ? "font-mono text-[12px] tracking-tight text-foreground/90" : "font-medium"}`,
1562
+ children: friendlyToolTitle(call)
1563
+ }
1564
+ )
1393
1565
  ]
1394
1566
  }
1395
1567
  ),
1396
- pending && approval && /* @__PURE__ */ jsxs7("span", { className: "flex shrink-0 items-center gap-1", children: [
1397
- /* @__PURE__ */ jsx7(
1398
- "button",
1399
- {
1400
- type: "button",
1401
- disabled: deciding,
1402
- onClick: () => decide(() => approval.onApprove(pending.proposalId, call.id)),
1403
- className: "rounded bg-success px-2 py-0.5 text-[11px] font-semibold text-success-foreground transition hover:bg-success/90 disabled:cursor-not-allowed disabled:opacity-60",
1404
- children: "Approve"
1405
- }
1406
- ),
1407
- /* @__PURE__ */ jsx7(
1408
- "button",
1409
- {
1410
- type: "button",
1411
- disabled: deciding,
1412
- onClick: () => decide(() => approval.onReject(pending.proposalId, call.id)),
1413
- className: "rounded border border-border bg-card px-2 py-0.5 text-[11px] font-medium text-foreground transition hover:bg-accent/30 disabled:cursor-not-allowed disabled:opacity-60",
1414
- children: "Reject"
1415
- }
1416
- )
1417
- ] }),
1418
- /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: call.status === "running" ? "running\u2026" : pending ? "awaiting approval" : failed ? "failed" : "done" }),
1419
- /* @__PURE__ */ jsx7(
1568
+ /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: call.status === "running" ? "running\u2026" : failed ? "failed" : "done" }),
1569
+ /* @__PURE__ */ jsx8(
1420
1570
  "button",
1421
1571
  {
1422
1572
  type: "button",
@@ -1424,13 +1574,13 @@ function ToolCallCard({
1424
1574
  "aria-label": expanded ? "Collapse details" : "Expand details",
1425
1575
  "aria-expanded": expanded,
1426
1576
  className: "shrink-0 rounded p-0.5 focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1427
- children: /* @__PURE__ */ jsx7(ChevronDown, { className: `h-3 w-3 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
1577
+ children: /* @__PURE__ */ jsx8(ChevronDown, { className: `h-3 w-3 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
1428
1578
  }
1429
1579
  )
1430
1580
  ] }),
1431
1581
  expanded && /* @__PURE__ */ jsxs7("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
1432
- custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx7(ShellDetail, { call }) : /* @__PURE__ */ jsx7(DefaultToolDetail, { call })),
1433
- onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx7(
1582
+ custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx8(ShellDetail, { call }) : /* @__PURE__ */ jsx8(DefaultToolDetail, { call })),
1583
+ onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx8(
1434
1584
  "button",
1435
1585
  {
1436
1586
  type: "button",
@@ -1444,6 +1594,73 @@ function ToolCallCard({
1444
1594
  }
1445
1595
  );
1446
1596
  }
1597
+ function StreamingCaret() {
1598
+ return /* @__PURE__ */ jsx8(
1599
+ "span",
1600
+ {
1601
+ className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70",
1602
+ "aria-hidden": true
1603
+ }
1604
+ );
1605
+ }
1606
+ function SegmentText({
1607
+ content,
1608
+ streaming,
1609
+ showCaret,
1610
+ renderBody
1611
+ }) {
1612
+ const text = useSmoothText(content, streaming);
1613
+ const body = useMemo3(() => renderBody(text), [renderBody, text]);
1614
+ if (!content.trim() && !showCaret) return null;
1615
+ return /* @__PURE__ */ jsxs7("div", { className: "text-base leading-[1.75]", children: [
1616
+ body,
1617
+ showCaret && /* @__PURE__ */ jsx8(StreamingCaret, {})
1618
+ ] });
1619
+ }
1620
+ function SegmentedBody({
1621
+ segments,
1622
+ msg,
1623
+ streaming,
1624
+ renderBody,
1625
+ approval,
1626
+ onToolCallClick,
1627
+ toolRenderers
1628
+ }) {
1629
+ const lastIndex = segments.length - 1;
1630
+ const segmentToolIds = new Set(
1631
+ segments.flatMap((s) => s.kind === "tool" ? [s.call.id] : [])
1632
+ );
1633
+ const leftoverToolCalls = (msg.toolCalls ?? []).filter(
1634
+ (tc) => !segmentToolIds.has(tc.id)
1635
+ );
1636
+ const renderToolCard = (call) => /* @__PURE__ */ jsx8(
1637
+ ToolCallCard,
1638
+ {
1639
+ call,
1640
+ message: msg,
1641
+ approval,
1642
+ onOpenRun: onToolCallClick,
1643
+ renderers: toolRenderers
1644
+ },
1645
+ `tool-${call.id}`
1646
+ );
1647
+ return /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-2", children: [
1648
+ segments.map(
1649
+ (seg, i) => seg.kind === "text" ? /* @__PURE__ */ jsx8(
1650
+ SegmentText,
1651
+ {
1652
+ content: seg.content,
1653
+ streaming: streaming && i === lastIndex,
1654
+ showCaret: streaming && i === lastIndex,
1655
+ renderBody
1656
+ },
1657
+ `text-${i}`
1658
+ ) : renderToolCard(seg.call)
1659
+ ),
1660
+ leftoverToolCalls.map(renderToolCard),
1661
+ streaming && segments[lastIndex]?.kind === "tool" && /* @__PURE__ */ jsx8(StreamingCaret, {})
1662
+ ] });
1663
+ }
1447
1664
  function AssistantMessageImpl({
1448
1665
  msg,
1449
1666
  streaming,
@@ -1458,45 +1675,60 @@ function AssistantMessageImpl({
1458
1675
  const content = useSmoothText(msg.content, streaming);
1459
1676
  const reasoning = useSmoothText(msg.reasoning ?? "", streaming);
1460
1677
  const body = useMemo3(() => renderBody(content), [renderBody, content]);
1678
+ const segments = msg.segments;
1679
+ const hasAnswerText = content !== "" || (segments?.some((s) => s.kind === "text" && s.content.trim() !== "") ?? false);
1461
1680
  const reasoningScrollRef = useRef4(null);
1462
1681
  const thinkStartRef = useRef4(null);
1463
1682
  const thinkMsRef = useRef4(null);
1464
- if (streaming && reasoning && !content && thinkStartRef.current === null) {
1683
+ if (streaming && reasoning && !hasAnswerText && thinkStartRef.current === null) {
1465
1684
  thinkStartRef.current = performance.now();
1466
1685
  }
1467
- if (content && thinkStartRef.current !== null && thinkMsRef.current === null) {
1686
+ if (hasAnswerText && thinkStartRef.current !== null && thinkMsRef.current === null) {
1468
1687
  thinkMsRef.current = performance.now() - thinkStartRef.current;
1469
1688
  }
1470
1689
  useEffect5(() => {
1471
1690
  const el = reasoningScrollRef.current;
1472
- if (el && streaming && !content) el.scrollTop = el.scrollHeight;
1473
- }, [reasoning, streaming, content]);
1691
+ if (el && streaming && !hasAnswerText) el.scrollTop = el.scrollHeight;
1692
+ }, [reasoning, streaming, hasAnswerText]);
1474
1693
  return /* @__PURE__ */ jsxs7("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
1475
1694
  /* @__PURE__ */ jsxs7("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground", children: [
1476
- /* @__PURE__ */ jsx7("span", { className: "font-semibold uppercase", children: agentLabel }),
1477
- msg.modelUsed && /* @__PURE__ */ jsx7("span", { className: "font-mono normal-case", children: msg.modelUsed }),
1478
- formatTokensPerSecond(msg) && /* @__PURE__ */ jsx7("span", { children: formatTokensPerSecond(msg) }),
1479
- formatModelCost(msg, models) && /* @__PURE__ */ jsx7("span", { children: formatModelCost(msg, models) })
1480
- ] }),
1481
- reasoning && /* @__PURE__ */ jsxs7("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !content, children: [
1482
- /* @__PURE__ */ jsx7("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !content ? /* @__PURE__ */ jsx7("span", { className: "animate-pulse", children: "Thinking\u2026" }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
1483
- /* @__PURE__ */ jsx7("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground", children: reasoning })
1695
+ /* @__PURE__ */ jsx8("span", { className: "font-semibold uppercase", children: agentLabel }),
1696
+ msg.modelUsed && /* @__PURE__ */ jsx8("span", { className: "font-mono normal-case", children: msg.modelUsed }),
1697
+ formatTokensPerSecond(msg) && /* @__PURE__ */ jsx8("span", { children: formatTokensPerSecond(msg) }),
1698
+ formatModelCost(msg, models) && /* @__PURE__ */ jsx8("span", { children: formatModelCost(msg, models) })
1484
1699
  ] }),
1485
- /* @__PURE__ */ jsxs7("div", { className: "text-base leading-[1.75]", children: [
1486
- body,
1487
- streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx7("span", { className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70", "aria-hidden": true })
1700
+ reasoning && /* @__PURE__ */ jsxs7("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !hasAnswerText, children: [
1701
+ /* @__PURE__ */ jsx8("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !hasAnswerText ? /* @__PURE__ */ jsx8("span", { className: "animate-pulse", children: "Thinking\u2026" }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
1702
+ /* @__PURE__ */ jsx8("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground", children: reasoning })
1488
1703
  ] }),
1489
- msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx7(
1490
- ToolCallCard,
1704
+ segments && segments.length > 0 ? /* @__PURE__ */ jsx8(
1705
+ SegmentedBody,
1491
1706
  {
1492
- call: tc,
1493
- message: msg,
1707
+ segments,
1708
+ msg,
1709
+ streaming,
1710
+ renderBody,
1494
1711
  approval,
1495
- onOpenRun: onToolCallClick,
1496
- renderers: toolRenderers
1497
- },
1498
- tc.id
1499
- )) }),
1712
+ onToolCallClick,
1713
+ toolRenderers
1714
+ }
1715
+ ) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
1716
+ /* @__PURE__ */ jsxs7("div", { className: "text-base leading-[1.75]", children: [
1717
+ body,
1718
+ streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx8(StreamingCaret, {})
1719
+ ] }),
1720
+ msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx8("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx8(
1721
+ ToolCallCard,
1722
+ {
1723
+ call: tc,
1724
+ message: msg,
1725
+ approval,
1726
+ onOpenRun: onToolCallClick,
1727
+ renderers: toolRenderers
1728
+ },
1729
+ tc.id
1730
+ )) })
1731
+ ] }),
1500
1732
  renderExtras?.(msg)
1501
1733
  ] });
1502
1734
  }
@@ -1508,22 +1740,22 @@ function ThinkingRow({ agentLabel }) {
1508
1740
  return () => clearInterval(id);
1509
1741
  }, []);
1510
1742
  return /* @__PURE__ */ jsxs7("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
1511
- /* @__PURE__ */ jsx7("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: agentLabel }),
1743
+ /* @__PURE__ */ jsx8("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: agentLabel }),
1512
1744
  /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
1513
- /* @__PURE__ */ jsx7("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
1745
+ /* @__PURE__ */ jsx8("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx8("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
1514
1746
  "Thinking",
1515
1747
  seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
1516
1748
  ] })
1517
1749
  ] });
1518
1750
  }
1519
1751
  function StreamErrorRow({ message, onRetry }) {
1520
- return /* @__PURE__ */ jsx7("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs7("div", { role: "alert", className: "flex items-start gap-2.5 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2.5 text-sm text-destructive", children: [
1752
+ return /* @__PURE__ */ jsx8("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs7("div", { role: "alert", className: "flex items-start gap-2.5 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2.5 text-sm text-destructive", children: [
1521
1753
  /* @__PURE__ */ jsxs7("svg", { className: "mt-0.5 h-4 w-4 shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1522
- /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "9" }),
1523
- /* @__PURE__ */ jsx7("path", { d: "M12 8v4m0 4h.01" })
1754
+ /* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "9" }),
1755
+ /* @__PURE__ */ jsx8("path", { d: "M12 8v4m0 4h.01" })
1524
1756
  ] }),
1525
- /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 break-words", children: message }),
1526
- onRetry && /* @__PURE__ */ jsx7(
1757
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 break-words", children: message }),
1758
+ onRetry && /* @__PURE__ */ jsx8(
1527
1759
  "button",
1528
1760
  {
1529
1761
  type: "button",
@@ -1547,20 +1779,29 @@ function ChatMessages({
1547
1779
  toolRenderers,
1548
1780
  error,
1549
1781
  onRetry,
1550
- renderEmpty
1782
+ renderEmpty,
1783
+ emptyState,
1784
+ header
1551
1785
  }) {
1552
1786
  const renderBody = useMemo3(
1553
- () => renderMarkdown ?? ((content) => /* @__PURE__ */ jsx7("p", { className: "whitespace-pre-wrap", children: content })),
1787
+ () => renderMarkdown ?? ((content) => /* @__PURE__ */ jsx8("p", { className: "whitespace-pre-wrap", children: content })),
1554
1788
  [renderMarkdown]
1555
1789
  );
1556
1790
  const lastIsUser = messages[messages.length - 1]?.role === "user";
1557
- if (messages.length === 0 && !loading && !error && renderEmpty) return /* @__PURE__ */ jsx7(Fragment4, { children: renderEmpty() });
1791
+ if (messages.length === 0 && !loading && !error) {
1792
+ const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */ jsx8(ChatEmptyState, { ...emptyState });
1793
+ return /* @__PURE__ */ jsxs7(Fragment4, { children: [
1794
+ header,
1795
+ empty
1796
+ ] });
1797
+ }
1558
1798
  return /* @__PURE__ */ jsxs7(Fragment4, { children: [
1799
+ header,
1559
1800
  messages.map(
1560
- (msg) => msg.role === "user" ? /* @__PURE__ */ jsx7("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs7("div", { className: "ml-auto w-fit max-w-[85%]", children: [
1561
- /* @__PURE__ */ jsx7("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: userLabel }),
1562
- /* @__PURE__ */ jsx7("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx7("p", { className: "whitespace-pre-wrap", children: msg.content }) })
1563
- ] }) }, msg.id) : /* @__PURE__ */ jsx7(
1801
+ (msg) => msg.role === "user" ? /* @__PURE__ */ jsx8("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs7("div", { className: "ml-auto w-fit max-w-[85%]", children: [
1802
+ /* @__PURE__ */ jsx8("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: userLabel }),
1803
+ /* @__PURE__ */ jsx8("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx8("p", { className: "whitespace-pre-wrap", children: msg.content }) })
1804
+ ] }) }, msg.id) : /* @__PURE__ */ jsx8(
1564
1805
  AssistantMessage,
1565
1806
  {
1566
1807
  msg,
@@ -1576,14 +1817,16 @@ function ChatMessages({
1576
1817
  msg.id
1577
1818
  )
1578
1819
  ),
1579
- loading && lastIsUser && /* @__PURE__ */ jsx7(ThinkingRow, { agentLabel }),
1580
- error && !loading && /* @__PURE__ */ jsx7(StreamErrorRow, { message: error, onRetry })
1820
+ loading && lastIsUser && /* @__PURE__ */ jsx8(ThinkingRow, { agentLabel }),
1821
+ error && !loading && /* @__PURE__ */ jsx8(StreamErrorRow, { message: error, onRetry })
1581
1822
  ] });
1582
1823
  }
1583
1824
  export {
1584
1825
  AgentActivityPanel,
1585
1826
  AgentSessionControls,
1827
+ ChatEmptyState,
1586
1828
  ChatMessages,
1829
+ DEFAULT_EFFORT_LEVELS,
1587
1830
  EffortPicker,
1588
1831
  FlowWaterfall,
1589
1832
  MissionActivityLane,