@tangle-network/agent-app 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,13 @@
1
1
  import {
2
2
  stepActivityFlowTrace
3
3
  } from "../chunk-AFDROJ64.js";
4
+ import {
5
+ snapHarnessToModel,
6
+ snapModelToHarness
7
+ } from "../chunk-5VXPDXZJ.js";
4
8
 
5
9
  // src/web-react/index.tsx
6
- import { useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState3 } from "react";
10
+ import { useEffect as useEffect5, useMemo as useMemo2, useRef as useRef3, useState as useState5 } from "react";
7
11
 
8
12
  // src/web-react/provider-logo.tsx
9
13
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -451,6 +455,132 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
451
455
  ] });
452
456
  }
453
457
 
458
+ // src/web-react/sandbox-terminal.ts
459
+ import { useCallback as useCallback2, useEffect as useEffect3, useState as useState3 } from "react";
460
+ var DEFAULT_PROVISION_POLL_INTERVAL_MS = 2e3;
461
+ var DEFAULT_PROVISION_POLL_TIMEOUT_MS = 9e4;
462
+ var DEFAULT_TOKEN_REFRESH_SKEW_MS = 12e4;
463
+ var EMPTY_CONNECTION = {
464
+ runtimeUrl: null,
465
+ sidecarUrl: null,
466
+ token: null,
467
+ expiresAt: null,
468
+ status: "idle",
469
+ error: null,
470
+ loading: false
471
+ };
472
+ function useSandboxTerminalConnection(opts) {
473
+ const [conn, setConn] = useState3(EMPTY_CONNECTION);
474
+ const fetcher = opts.fetcher ?? fetch;
475
+ const pollIntervalMs = opts.provisionPollIntervalMs ?? DEFAULT_PROVISION_POLL_INTERVAL_MS;
476
+ const pollTimeoutMs = opts.provisionPollTimeoutMs ?? DEFAULT_PROVISION_POLL_TIMEOUT_MS;
477
+ const refreshSkewMs = opts.tokenRefreshSkewMs ?? DEFAULT_TOKEN_REFRESH_SKEW_MS;
478
+ const connectionUrl = useCallback2(() => {
479
+ if (typeof opts.connectionUrl === "function") return opts.connectionUrl(opts.workspaceId);
480
+ return opts.connectionUrl ?? `/api/workspaces/${encodeURIComponent(opts.workspaceId)}/sandbox/connection`;
481
+ }, [opts.connectionUrl, opts.workspaceId]);
482
+ const connect = useCallback2(async () => {
483
+ setConn((current) => ({ ...current, loading: true, error: null }));
484
+ const deadline = Date.now() + pollTimeoutMs;
485
+ while (true) {
486
+ try {
487
+ const res = await fetcher(connectionUrl());
488
+ const data = await res.json();
489
+ const runtimeUrl = data.runtimeUrl ?? data.sidecarUrl;
490
+ if (res.ok && runtimeUrl && data.token && data.expiresAt) {
491
+ setConn({
492
+ runtimeUrl,
493
+ sidecarUrl: runtimeUrl,
494
+ token: data.token,
495
+ expiresAt: data.expiresAt,
496
+ status: data.status ?? "running",
497
+ error: null,
498
+ loading: false,
499
+ ...data.sandboxId ? { sandboxId: data.sandboxId } : {}
500
+ });
501
+ return;
502
+ }
503
+ if (res.ok) {
504
+ setConn({
505
+ runtimeUrl: null,
506
+ sidecarUrl: null,
507
+ token: null,
508
+ expiresAt: null,
509
+ loading: false,
510
+ error: "Sandbox connection response is missing required fields",
511
+ status: data.status ?? "error",
512
+ ...data.sandboxId ? { sandboxId: data.sandboxId } : {}
513
+ });
514
+ return;
515
+ }
516
+ if (res.status === 503 && Date.now() < deadline) {
517
+ setConn((current) => ({
518
+ ...current,
519
+ loading: true,
520
+ status: data.status ?? "provisioning",
521
+ error: null
522
+ }));
523
+ await sleep(pollIntervalMs);
524
+ continue;
525
+ }
526
+ setConn((current) => ({
527
+ ...current,
528
+ runtimeUrl: null,
529
+ sidecarUrl: null,
530
+ token: null,
531
+ expiresAt: null,
532
+ loading: false,
533
+ error: data.error ?? "Sandbox not available",
534
+ status: data.status ?? "error"
535
+ }));
536
+ return;
537
+ } catch (err) {
538
+ if (Date.now() < deadline) {
539
+ await sleep(pollIntervalMs);
540
+ continue;
541
+ }
542
+ setConn((current) => ({
543
+ ...current,
544
+ runtimeUrl: null,
545
+ sidecarUrl: null,
546
+ token: null,
547
+ expiresAt: null,
548
+ loading: false,
549
+ error: err instanceof Error ? err.message : "Connection failed"
550
+ }));
551
+ return;
552
+ }
553
+ }
554
+ }, [connectionUrl, fetcher, pollIntervalMs, pollTimeoutMs]);
555
+ useEffect3(() => {
556
+ void connect();
557
+ }, [connect]);
558
+ useEffect3(() => {
559
+ if (!conn.runtimeUrl || !conn.token || !conn.expiresAt) return;
560
+ const refreshAt = Date.parse(conn.expiresAt) - Date.now() - refreshSkewMs;
561
+ if (!Number.isFinite(refreshAt)) {
562
+ setConn((current) => ({
563
+ ...current,
564
+ runtimeUrl: null,
565
+ sidecarUrl: null,
566
+ token: null,
567
+ expiresAt: null,
568
+ status: "error",
569
+ error: "Sandbox token expiry is invalid"
570
+ }));
571
+ return;
572
+ }
573
+ const timer = window.setTimeout(() => {
574
+ void connect();
575
+ }, Math.max(1e3, refreshAt));
576
+ return () => window.clearTimeout(timer);
577
+ }, [conn.runtimeUrl, conn.token, conn.expiresAt, connect, refreshSkewMs]);
578
+ return { ...conn, connect };
579
+ }
580
+ function sleep(ms) {
581
+ return new Promise((resolve) => window.setTimeout(resolve, ms));
582
+ }
583
+
454
584
  // src/web-react/seat-paywall.tsx
455
585
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
456
586
  function CheckGlyph() {
@@ -527,23 +657,184 @@ function SeatPaywall({
527
657
  ] }) });
528
658
  }
529
659
 
530
- // src/web-react/index.tsx
531
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
660
+ // src/web-react/agent-session-controls.tsx
661
+ import { useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState4 } from "react";
662
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
663
+ var HARNESS_LABELS = {
664
+ opencode: "OpenCode (any model)",
665
+ "claude-code": "Claude Code (Anthropic)",
666
+ codex: "Codex (OpenAI)",
667
+ "kimi-code": "Kimi (Moonshot)",
668
+ amp: "Amp",
669
+ "factory-droids": "Factory Droids",
670
+ cursor: "Cursor",
671
+ hermes: "Hermes",
672
+ forge: "Forge",
673
+ pi: "Pi",
674
+ openclaw: "OpenClaw",
675
+ acp: "ACP",
676
+ "cli-base": "CLI"
677
+ };
678
+ function harnessLabel(h) {
679
+ return HARNESS_LABELS[h] ?? h;
680
+ }
532
681
  function ChevronDown({ className }) {
533
682
  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" }) });
534
683
  }
535
- function SearchGlyph({ className }) {
684
+ function GearGlyph({ className }) {
536
685
  return /* @__PURE__ */ jsxs4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
537
- /* @__PURE__ */ jsx4("circle", { cx: "11", cy: "11", r: "8" }),
538
- /* @__PURE__ */ jsx4("path", { d: "m21 21-4.3-4.3" })
686
+ /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "3" }),
687
+ /* @__PURE__ */ jsx4("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" })
688
+ ] });
689
+ }
690
+ function useClickOutside(active, onOutside) {
691
+ const ref = useRef2(null);
692
+ useEffect4(() => {
693
+ if (!active) return;
694
+ function handler(e) {
695
+ if (ref.current && !ref.current.contains(e.target)) onOutside();
696
+ }
697
+ document.addEventListener("mousedown", handler);
698
+ return () => document.removeEventListener("mousedown", handler);
699
+ }, [active, onOutside]);
700
+ return ref;
701
+ }
702
+ function HarnessPicker({
703
+ value,
704
+ onChange,
705
+ available
706
+ }) {
707
+ const [open, setOpen] = useState4(false);
708
+ const containerRef = useClickOutside(open, () => setOpen(false));
709
+ const options = available ?? Object.keys(HARNESS_LABELS);
710
+ return /* @__PURE__ */ jsxs4("div", { ref: containerRef, className: "relative inline-flex", children: [
711
+ /* @__PURE__ */ jsxs4(
712
+ "button",
713
+ {
714
+ type: "button",
715
+ onClick: () => setOpen((v) => !v),
716
+ title: "Agent backend",
717
+ 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",
718
+ children: [
719
+ /* @__PURE__ */ jsx4("span", { className: "truncate", children: harnessLabel(value) }),
720
+ /* @__PURE__ */ jsx4(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
721
+ ]
722
+ }
723
+ ),
724
+ open && /* @__PURE__ */ jsx4("div", { 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__ */ jsx4(
725
+ "button",
726
+ {
727
+ type: "button",
728
+ onClick: () => {
729
+ onChange(h);
730
+ setOpen(false);
731
+ },
732
+ className: `flex w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${h === value ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
733
+ children: harnessLabel(h)
734
+ },
735
+ h
736
+ )) })
737
+ ] });
738
+ }
739
+ function useCoherentHandlers(props) {
740
+ const { model, models, harness, onModelChange, onHarnessChange } = props;
741
+ const canonicalIds = useMemo(() => models.map((m) => m.id), [models]);
742
+ const onModel = (next) => {
743
+ onModelChange(next);
744
+ const nextHarness = snapHarnessToModel(harness, next);
745
+ if (nextHarness !== harness) onHarnessChange(nextHarness);
746
+ };
747
+ const onHarness = (next) => {
748
+ onHarnessChange(next);
749
+ const snapped = snapModelToHarness(next, model, canonicalIds);
750
+ if (snapped !== model) onModelChange(snapped);
751
+ };
752
+ return { onModel, onHarness };
753
+ }
754
+ function AgentSessionControls(props) {
755
+ const {
756
+ models,
757
+ modelsLoading,
758
+ model,
759
+ harness,
760
+ availableHarnesses,
761
+ effort,
762
+ onEffortChange,
763
+ layout = "inline",
764
+ showHarness = true,
765
+ renderProviderBadge,
766
+ className
767
+ } = props;
768
+ const { onModel, onHarness } = useCoherentHandlers(props);
769
+ const [open, setOpen] = useState4(false);
770
+ const popoverRef = useClickOutside(open, () => setOpen(false));
771
+ const selectedModel = models.find((m) => m.id === model);
772
+ const showEffort = selectedModel?.supportsReasoning ?? true;
773
+ const modelPicker = /* @__PURE__ */ jsx4(
774
+ ModelPicker,
775
+ {
776
+ value: model,
777
+ onChange: onModel,
778
+ models,
779
+ loading: modelsLoading,
780
+ renderProviderBadge
781
+ }
782
+ );
783
+ if (layout === "inline") {
784
+ return /* @__PURE__ */ jsxs4("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
785
+ modelPicker,
786
+ showHarness && /* @__PURE__ */ jsx4(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
787
+ showEffort && /* @__PURE__ */ jsx4(EffortPicker, { value: effort, onChange: onEffortChange })
788
+ ] });
789
+ }
790
+ const hasAdvanced = showHarness || showEffort;
791
+ return /* @__PURE__ */ jsxs4("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
792
+ modelPicker,
793
+ hasAdvanced && /* @__PURE__ */ jsxs4("div", { ref: popoverRef, className: "relative inline-flex", children: [
794
+ /* @__PURE__ */ jsx4(
795
+ "button",
796
+ {
797
+ type: "button",
798
+ onClick: () => setOpen((v) => !v),
799
+ title: "Model settings \u2014 pick the agent backend and how hard it thinks",
800
+ 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",
801
+ "data-state": open ? "open" : "closed",
802
+ children: /* @__PURE__ */ jsx4(GearGlyph, { className: "h-4 w-4" })
803
+ }
804
+ ),
805
+ open && /* @__PURE__ */ jsxs4("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: [
806
+ showHarness && /* @__PURE__ */ jsxs4("div", { className: "space-y-1.5", children: [
807
+ /* @__PURE__ */ jsx4("p", { className: "text-xs font-medium text-foreground", children: "Agent backend" }),
808
+ /* @__PURE__ */ jsx4(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
809
+ /* @__PURE__ */ jsx4("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "The engine that runs the agent. Switching it keeps your model choice compatible." })
810
+ ] }),
811
+ showEffort && /* @__PURE__ */ jsxs4("div", { className: "space-y-1.5", children: [
812
+ /* @__PURE__ */ jsx4("p", { className: "text-xs font-medium text-foreground", children: "Reasoning effort" }),
813
+ /* @__PURE__ */ jsx4(EffortPicker, { value: effort, onChange: onEffortChange }),
814
+ /* @__PURE__ */ jsx4("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "How hard the agent thinks before answering. Higher is slower but more thorough." })
815
+ ] })
816
+ ] })
817
+ ] })
818
+ ] });
819
+ }
820
+
821
+ // src/web-react/index.tsx
822
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
823
+ function ChevronDown2({ className }) {
824
+ return /* @__PURE__ */ jsx5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx5("path", { d: "m6 9 6 6 6-6" }) });
825
+ }
826
+ function SearchGlyph({ className }) {
827
+ return /* @__PURE__ */ jsxs5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
828
+ /* @__PURE__ */ jsx5("circle", { cx: "11", cy: "11", r: "8" }),
829
+ /* @__PURE__ */ jsx5("path", { d: "m21 21-4.3-4.3" })
539
830
  ] });
540
831
  }
541
832
  function SparkleGlyph({ className }) {
542
- 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: "M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1" }) });
833
+ return /* @__PURE__ */ jsx5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx5("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1" }) });
543
834
  }
544
- function useClickOutside(onOutside) {
545
- const ref = useRef2(null);
546
- useEffect3(() => {
835
+ function useClickOutside2(onOutside) {
836
+ const ref = useRef3(null);
837
+ useEffect5(() => {
547
838
  function handler(e) {
548
839
  if (ref.current && !ref.current.contains(e.target)) onOutside();
549
840
  }
@@ -578,7 +869,7 @@ function formatContext(len) {
578
869
  return `${len} ctx`;
579
870
  }
580
871
  function SectionHeader({ children }) {
581
- return /* @__PURE__ */ jsx4("div", { className: "px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground/70", children });
872
+ return /* @__PURE__ */ jsx5("div", { className: "px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground/70", children });
582
873
  }
583
874
  function ModelRow({
584
875
  model,
@@ -588,41 +879,41 @@ function ModelRow({
588
879
  }) {
589
880
  const price = formatPrice(model.pricing?.prompt);
590
881
  const ctx = formatContext(model.contextLength);
591
- return /* @__PURE__ */ jsxs4(
882
+ return /* @__PURE__ */ jsxs5(
592
883
  "button",
593
884
  {
594
885
  type: "button",
595
886
  onClick: onSelect,
596
887
  className: `flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${selected ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
597
888
  children: [
598
- renderProviderBadge ? renderProviderBadge(model.provider) : /* @__PURE__ */ jsx4(ProviderLogo, { provider: model.provider, size: 16 }),
599
- /* @__PURE__ */ jsx4("span", { className: "truncate", children: model.name }),
600
- !model.supportsTools && /* @__PURE__ */ jsx4("span", { className: "shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: "no tools" }),
601
- /* @__PURE__ */ jsxs4("span", { className: "ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground", children: [
602
- ctx && /* @__PURE__ */ jsx4("span", { children: ctx }),
603
- price && /* @__PURE__ */ jsx4("span", { children: price })
889
+ renderProviderBadge ? renderProviderBadge(model.provider) : /* @__PURE__ */ jsx5(ProviderLogo, { provider: model.provider, size: 16 }),
890
+ /* @__PURE__ */ jsx5("span", { className: "truncate", children: model.name }),
891
+ !model.supportsTools && /* @__PURE__ */ jsx5("span", { className: "shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: "no tools" }),
892
+ /* @__PURE__ */ jsxs5("span", { className: "ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground", children: [
893
+ ctx && /* @__PURE__ */ jsx5("span", { children: ctx }),
894
+ price && /* @__PURE__ */ jsx5("span", { children: price })
604
895
  ] })
605
896
  ]
606
897
  }
607
898
  );
608
899
  }
609
900
  function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = "Recommended" }) {
610
- const [open, setOpen] = useState3(false);
611
- const [query, setQuery] = useState3("");
612
- const containerRef = useClickOutside(() => setOpen(false));
613
- const inputRef = useRef2(null);
614
- useEffect3(() => {
901
+ const [open, setOpen] = useState5(false);
902
+ const [query, setQuery] = useState5("");
903
+ const containerRef = useClickOutside2(() => setOpen(false));
904
+ const inputRef = useRef3(null);
905
+ useEffect5(() => {
615
906
  if (open) inputRef.current?.focus();
616
907
  }, [open]);
617
908
  const selected = models.find((m) => m.id === value);
618
- const filtered = useMemo(() => {
909
+ const filtered = useMemo2(() => {
619
910
  const q = query.trim().toLowerCase();
620
911
  if (!q) return null;
621
912
  return models.filter(
622
913
  (m) => m.id.toLowerCase().includes(q) || m.name.toLowerCase().includes(q) || (m.description?.toLowerCase() ?? "").includes(q) || m.provider.toLowerCase().includes(q)
623
914
  );
624
915
  }, [models, query]);
625
- const sections = useMemo(() => {
916
+ const sections = useMemo2(() => {
626
917
  const recommended = models.filter((m) => m.featured);
627
918
  const byProvider = [];
628
919
  for (const m of models) {
@@ -638,24 +929,24 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
638
929
  setOpen(false);
639
930
  setQuery("");
640
931
  };
641
- return /* @__PURE__ */ jsxs4("div", { ref: containerRef, className: "relative inline-flex", children: [
642
- /* @__PURE__ */ jsxs4(
932
+ return /* @__PURE__ */ jsxs5("div", { ref: containerRef, className: "relative inline-flex", children: [
933
+ /* @__PURE__ */ jsxs5(
643
934
  "button",
644
935
  {
645
936
  type: "button",
646
937
  onClick: () => setOpen((v) => !v),
647
938
  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",
648
939
  children: [
649
- selected ? renderProviderBadge ? renderProviderBadge(selected.provider) : /* @__PURE__ */ jsx4(ProviderLogo, { provider: selected.provider, size: 16 }) : /* @__PURE__ */ jsx4(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
650
- /* @__PURE__ */ jsx4("span", { className: "max-w-[160px] truncate", children: selected?.name ?? value }),
651
- /* @__PURE__ */ jsx4(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
940
+ selected ? renderProviderBadge ? renderProviderBadge(selected.provider) : /* @__PURE__ */ jsx5(ProviderLogo, { provider: selected.provider, size: 16 }) : /* @__PURE__ */ jsx5(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
941
+ /* @__PURE__ */ jsx5("span", { className: "max-w-[160px] truncate", children: selected?.name ?? value }),
942
+ /* @__PURE__ */ jsx5(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
652
943
  ]
653
944
  }
654
945
  ),
655
- open && /* @__PURE__ */ jsxs4("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: [
656
- /* @__PURE__ */ jsx4("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2", children: [
657
- /* @__PURE__ */ jsx4(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
658
- /* @__PURE__ */ jsx4(
946
+ open && /* @__PURE__ */ jsxs5("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: [
947
+ /* @__PURE__ */ jsx5("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2", children: [
948
+ /* @__PURE__ */ jsx5(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
949
+ /* @__PURE__ */ jsx5(
659
950
  "input",
660
951
  {
661
952
  ref: inputRef,
@@ -667,20 +958,20 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
667
958
  }
668
959
  )
669
960
  ] }) }),
670
- /* @__PURE__ */ jsxs4("div", { className: "max-h-[400px] overflow-y-auto p-1 pb-2", children: [
671
- loading && /* @__PURE__ */ jsx4("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading models..." }),
672
- !loading && filtered && /* @__PURE__ */ jsxs4(Fragment2, { children: [
673
- filtered.length === 0 && /* @__PURE__ */ jsx4("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models match your search" }),
674
- filtered.map((m) => /* @__PURE__ */ jsx4(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
961
+ /* @__PURE__ */ jsxs5("div", { className: "max-h-[400px] overflow-y-auto p-1 pb-2", children: [
962
+ loading && /* @__PURE__ */ jsx5("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading models..." }),
963
+ !loading && filtered && /* @__PURE__ */ jsxs5(Fragment2, { children: [
964
+ filtered.length === 0 && /* @__PURE__ */ jsx5("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models match your search" }),
965
+ filtered.map((m) => /* @__PURE__ */ jsx5(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
675
966
  ] }),
676
- !loading && !filtered && /* @__PURE__ */ jsxs4(Fragment2, { children: [
677
- sections.recommended.length > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
678
- /* @__PURE__ */ jsx4(SectionHeader, { children: recommendedLabel }),
679
- sections.recommended.map((m) => /* @__PURE__ */ jsx4(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
967
+ !loading && !filtered && /* @__PURE__ */ jsxs5(Fragment2, { children: [
968
+ sections.recommended.length > 0 && /* @__PURE__ */ jsxs5(Fragment2, { children: [
969
+ /* @__PURE__ */ jsx5(SectionHeader, { children: recommendedLabel }),
970
+ sections.recommended.map((m) => /* @__PURE__ */ jsx5(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
680
971
  ] }),
681
- sections.byProvider.map((g) => /* @__PURE__ */ jsxs4("div", { children: [
682
- /* @__PURE__ */ jsx4(SectionHeader, { children: g.provider }),
683
- g.items.map((m) => /* @__PURE__ */ jsx4(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
972
+ sections.byProvider.map((g) => /* @__PURE__ */ jsxs5("div", { children: [
973
+ /* @__PURE__ */ jsx5(SectionHeader, { children: g.provider }),
974
+ g.items.map((m) => /* @__PURE__ */ jsx5(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
684
975
  ] }, g.provider))
685
976
  ] })
686
977
  ] })
@@ -694,11 +985,11 @@ var EFFORT_LEVELS = [
694
985
  { id: "high", label: "High" }
695
986
  ];
696
987
  function EffortPicker({ value, onChange }) {
697
- const [open, setOpen] = useState3(false);
698
- const containerRef = useClickOutside(() => setOpen(false));
988
+ const [open, setOpen] = useState5(false);
989
+ const containerRef = useClickOutside2(() => setOpen(false));
699
990
  const selected = EFFORT_LEVELS.find((l) => l.id === value) ?? EFFORT_LEVELS[2];
700
- return /* @__PURE__ */ jsxs4("div", { ref: containerRef, className: "relative inline-flex", children: [
701
- /* @__PURE__ */ jsxs4(
991
+ return /* @__PURE__ */ jsxs5("div", { ref: containerRef, className: "relative inline-flex", children: [
992
+ /* @__PURE__ */ jsxs5(
702
993
  "button",
703
994
  {
704
995
  type: "button",
@@ -706,13 +997,13 @@ function EffortPicker({ value, onChange }) {
706
997
  title: "Reasoning effort",
707
998
  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",
708
999
  children: [
709
- /* @__PURE__ */ jsx4(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
710
- /* @__PURE__ */ jsx4("span", { children: selected.label }),
711
- /* @__PURE__ */ jsx4(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
1000
+ /* @__PURE__ */ jsx5(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
1001
+ /* @__PURE__ */ jsx5("span", { children: selected.label }),
1002
+ /* @__PURE__ */ jsx5(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
712
1003
  ]
713
1004
  }
714
1005
  ),
715
- open && /* @__PURE__ */ jsx4("div", { 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__ */ jsx4(
1006
+ open && /* @__PURE__ */ jsx5("div", { 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__ */ jsx5(
716
1007
  "button",
717
1008
  {
718
1009
  type: "button",
@@ -728,41 +1019,41 @@ function EffortPicker({ value, onChange }) {
728
1019
  ] });
729
1020
  }
730
1021
  function RunDrillIn({ run, onClose }) {
731
- return /* @__PURE__ */ jsxs4("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: [
732
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
733
- /* @__PURE__ */ jsx4(
1022
+ return /* @__PURE__ */ jsxs5("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: [
1023
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
1024
+ /* @__PURE__ */ jsx5(
734
1025
  "span",
735
1026
  {
736
1027
  className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-yellow-500" : run.status === "error" ? "bg-red-500" : "bg-green-500"}`
737
1028
  }
738
1029
  ),
739
- /* @__PURE__ */ jsxs4("div", { className: "min-w-0 flex-1", children: [
740
- /* @__PURE__ */ jsx4("p", { className: "truncate text-sm font-semibold", children: run.title }),
741
- /* @__PURE__ */ jsx4("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
1030
+ /* @__PURE__ */ jsxs5("div", { className: "min-w-0 flex-1", children: [
1031
+ /* @__PURE__ */ jsx5("p", { className: "truncate text-sm font-semibold", children: run.title }),
1032
+ /* @__PURE__ */ jsx5("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
742
1033
  ] }),
743
- /* @__PURE__ */ jsx4(
1034
+ /* @__PURE__ */ jsx5(
744
1035
  "button",
745
1036
  {
746
1037
  type: "button",
747
1038
  onClick: onClose,
748
1039
  "aria-label": "Close",
749
1040
  className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground",
750
- children: /* @__PURE__ */ jsx4("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx4("path", { d: "M18 6 6 18M6 6l12 12" }) })
1041
+ children: /* @__PURE__ */ jsx5("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx5("path", { d: "M18 6 6 18M6 6l12 12" }) })
751
1042
  }
752
1043
  )
753
1044
  ] }),
754
- /* @__PURE__ */ jsxs4("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
755
- run.steps.length === 0 && /* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
756
- run.steps.map((step, i) => /* @__PURE__ */ jsxs4("div", { className: "rounded-lg border border-border/60 bg-background", children: [
757
- /* @__PURE__ */ jsxs4("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
758
- /* @__PURE__ */ jsx4("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-red-600" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
759
- /* @__PURE__ */ jsx4("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
760
- /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: new Date(step.at).toLocaleTimeString() })
1045
+ /* @__PURE__ */ jsxs5("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
1046
+ run.steps.length === 0 && /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
1047
+ run.steps.map((step, i) => /* @__PURE__ */ jsxs5("div", { className: "rounded-lg border border-border/60 bg-background", children: [
1048
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
1049
+ /* @__PURE__ */ jsx5("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-red-600" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
1050
+ /* @__PURE__ */ jsx5("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
1051
+ /* @__PURE__ */ jsx5("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: new Date(step.at).toLocaleTimeString() })
761
1052
  ] }),
762
- step.detail && /* @__PURE__ */ jsx4("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 })
1053
+ step.detail && /* @__PURE__ */ jsx5("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 })
763
1054
  ] }, i))
764
1055
  ] }),
765
- /* @__PURE__ */ jsx4("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground/60", children: "Readonly drill-in. Follow up in the main chat." })
1056
+ /* @__PURE__ */ jsx5("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground/60", children: "Readonly drill-in. Follow up in the main chat." })
766
1057
  ] });
767
1058
  }
768
1059
  function pendingApprovalOf(call) {
@@ -772,26 +1063,26 @@ function pendingApprovalOf(call) {
772
1063
  }
773
1064
  function ToolGlyph({ name, className }) {
774
1065
  if (name.startsWith("sandbox_")) {
775
- return /* @__PURE__ */ jsxs4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
776
- /* @__PURE__ */ jsx4("polyline", { points: "4 17 10 11 4 5" }),
777
- /* @__PURE__ */ jsx4("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
1066
+ return /* @__PURE__ */ jsxs5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1067
+ /* @__PURE__ */ jsx5("polyline", { points: "4 17 10 11 4 5" }),
1068
+ /* @__PURE__ */ jsx5("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
778
1069
  ] });
779
1070
  }
780
1071
  if (name === "submit_proposal") {
781
- return /* @__PURE__ */ jsxs4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
782
- /* @__PURE__ */ jsx4("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
783
- /* @__PURE__ */ jsx4("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
1072
+ return /* @__PURE__ */ jsxs5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1073
+ /* @__PURE__ */ jsx5("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
1074
+ /* @__PURE__ */ jsx5("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
784
1075
  ] });
785
1076
  }
786
1077
  if (name === "schedule_followup") {
787
- return /* @__PURE__ */ jsxs4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
788
- /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "9" }),
789
- /* @__PURE__ */ jsx4("path", { d: "M12 7v5l3 3" })
1078
+ return /* @__PURE__ */ jsxs5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
1079
+ /* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "9" }),
1080
+ /* @__PURE__ */ jsx5("path", { d: "M12 7v5l3 3" })
790
1081
  ] });
791
1082
  }
792
- return /* @__PURE__ */ jsxs4("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
793
- /* @__PURE__ */ jsx4("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
794
- /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "4" })
1083
+ return /* @__PURE__ */ jsxs5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1084
+ /* @__PURE__ */ jsx5("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
1085
+ /* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "4" })
795
1086
  ] });
796
1087
  }
797
1088
  function toolOutcomeOf(call) {
@@ -825,36 +1116,36 @@ function truncate(v, max = 240) {
825
1116
  function KvRows({ data }) {
826
1117
  const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
827
1118
  if (!entries.length) return null;
828
- return /* @__PURE__ */ jsx4("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs4("div", { className: "contents", children: [
829
- /* @__PURE__ */ jsx4("dt", { className: "font-mono text-[11px] text-muted-foreground/70", children: k }),
830
- /* @__PURE__ */ jsx4("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
1119
+ return /* @__PURE__ */ jsx5("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs5("div", { className: "contents", children: [
1120
+ /* @__PURE__ */ jsx5("dt", { className: "font-mono text-[11px] text-muted-foreground/70", children: k }),
1121
+ /* @__PURE__ */ jsx5("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
831
1122
  ] }, k)) });
832
1123
  }
833
1124
  function ShellDetail({ call }) {
834
1125
  const outcome = toolOutcomeOf(call);
835
1126
  const r = outcome?.result ?? {};
836
- return /* @__PURE__ */ jsxs4("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
837
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
838
- /* @__PURE__ */ jsx4("span", { className: "select-none text-zinc-500", children: "$" }),
839
- /* @__PURE__ */ jsx4("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
840
- r.exitCode != null && /* @__PURE__ */ jsxs4("span", { className: r.exitCode === 0 ? "text-emerald-400" : "text-red-400", children: [
1127
+ return /* @__PURE__ */ jsxs5("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
1128
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
1129
+ /* @__PURE__ */ jsx5("span", { className: "select-none text-zinc-500", children: "$" }),
1130
+ /* @__PURE__ */ jsx5("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
1131
+ r.exitCode != null && /* @__PURE__ */ jsxs5("span", { className: r.exitCode === 0 ? "text-emerald-400" : "text-red-400", children: [
841
1132
  "exit ",
842
1133
  r.exitCode
843
1134
  ] })
844
1135
  ] }),
845
- /* @__PURE__ */ jsx4("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)" })
1136
+ /* @__PURE__ */ jsx5("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)" })
846
1137
  ] });
847
1138
  }
848
1139
  function DefaultToolDetail({ call }) {
849
1140
  const outcome = toolOutcomeOf(call);
850
- return /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
851
- call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs4("div", { children: [
852
- /* @__PURE__ */ jsx4("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: "Called with" }),
853
- /* @__PURE__ */ jsx4(KvRows, { data: call.args })
1141
+ return /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
1142
+ call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs5("div", { children: [
1143
+ /* @__PURE__ */ jsx5("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: "Called with" }),
1144
+ /* @__PURE__ */ jsx5(KvRows, { data: call.args })
854
1145
  ] }),
855
- outcome && /* @__PURE__ */ jsxs4("div", { children: [
856
- /* @__PURE__ */ jsx4("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: outcome.ok === false ? "Failed" : "Result" }),
857
- outcome.ok === false ? /* @__PURE__ */ jsx4("p", { className: "text-xs text-red-600", children: outcome.message ?? "Tool failed" }) : outcome.result && typeof outcome.result === "object" ? /* @__PURE__ */ jsx4(KvRows, { data: outcome.result }) : /* @__PURE__ */ jsx4("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(outcome.result) })
1146
+ outcome && /* @__PURE__ */ jsxs5("div", { children: [
1147
+ /* @__PURE__ */ jsx5("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: outcome.ok === false ? "Failed" : "Result" }),
1148
+ outcome.ok === false ? /* @__PURE__ */ jsx5("p", { className: "text-xs text-red-600", children: outcome.message ?? "Tool failed" }) : outcome.result && typeof outcome.result === "object" ? /* @__PURE__ */ jsx5(KvRows, { data: outcome.result }) : /* @__PURE__ */ jsx5("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(outcome.result) })
858
1149
  ] })
859
1150
  ] });
860
1151
  }
@@ -865,32 +1156,32 @@ function ToolCallCard({
865
1156
  onOpenRun,
866
1157
  renderers
867
1158
  }) {
868
- const [expanded, setExpanded] = useState3(false);
1159
+ const [expanded, setExpanded] = useState5(false);
869
1160
  const pending = call.status === "done" ? pendingApprovalOf(call) : null;
870
1161
  const failed = call.status === "error" || toolOutcomeOf(call)?.ok === false;
871
1162
  const custom = renderers?.[call.name]?.(call, message);
872
- return /* @__PURE__ */ jsxs4(
1163
+ return /* @__PURE__ */ jsxs5(
873
1164
  "div",
874
1165
  {
875
1166
  className: `w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${pending ? "border-amber-300/60 bg-amber-500/5" : failed ? "border-red-300/60 bg-red-500/5" : "border-border/60 bg-muted/20"}`,
876
1167
  children: [
877
- /* @__PURE__ */ jsxs4(
1168
+ /* @__PURE__ */ jsxs5(
878
1169
  "button",
879
1170
  {
880
1171
  type: "button",
881
1172
  onClick: () => setExpanded((v) => !v),
882
1173
  className: "flex w-full items-center gap-2 px-3 py-2 text-left",
883
1174
  children: [
884
- /* @__PURE__ */ jsx4(
1175
+ /* @__PURE__ */ jsx5(
885
1176
  "span",
886
1177
  {
887
1178
  className: `h-2 w-2 shrink-0 rounded-full ${call.status === "running" ? "animate-pulse bg-yellow-500" : pending ? "bg-amber-500" : failed ? "bg-red-500" : "bg-green-500"}`
888
1179
  }
889
1180
  ),
890
- /* @__PURE__ */ jsx4(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
891
- /* @__PURE__ */ jsx4("span", { className: "min-w-0 flex-1 truncate font-medium", children: friendlyToolTitle(call) }),
892
- pending && approval && /* @__PURE__ */ jsxs4("span", { className: "flex shrink-0 items-center gap-1", onClick: (e) => e.stopPropagation(), children: [
893
- /* @__PURE__ */ jsx4(
1181
+ /* @__PURE__ */ jsx5(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1182
+ /* @__PURE__ */ jsx5("span", { className: "min-w-0 flex-1 truncate font-medium", children: friendlyToolTitle(call) }),
1183
+ pending && approval && /* @__PURE__ */ jsxs5("span", { className: "flex shrink-0 items-center gap-1", onClick: (e) => e.stopPropagation(), children: [
1184
+ /* @__PURE__ */ jsx5(
894
1185
  "button",
895
1186
  {
896
1187
  type: "button",
@@ -899,7 +1190,7 @@ function ToolCallCard({
899
1190
  children: "Approve"
900
1191
  }
901
1192
  ),
902
- /* @__PURE__ */ jsx4(
1193
+ /* @__PURE__ */ jsx5(
903
1194
  "button",
904
1195
  {
905
1196
  type: "button",
@@ -909,14 +1200,14 @@ function ToolCallCard({
909
1200
  }
910
1201
  )
911
1202
  ] }),
912
- /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-[11px] text-muted-foreground/70", children: call.status === "running" ? "running\u2026" : pending ? "awaiting approval" : failed ? "failed" : "done" }),
913
- /* @__PURE__ */ jsx4(ChevronDown, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
1203
+ /* @__PURE__ */ jsx5("span", { className: "shrink-0 text-[11px] text-muted-foreground/70", children: call.status === "running" ? "running\u2026" : pending ? "awaiting approval" : failed ? "failed" : "done" }),
1204
+ /* @__PURE__ */ jsx5(ChevronDown2, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
914
1205
  ]
915
1206
  }
916
1207
  ),
917
- expanded && /* @__PURE__ */ jsxs4("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
918
- custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx4(ShellDetail, { call }) : /* @__PURE__ */ jsx4(DefaultToolDetail, { call })),
919
- onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx4(
1208
+ expanded && /* @__PURE__ */ jsxs5("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
1209
+ custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx5(ShellDetail, { call }) : /* @__PURE__ */ jsx5(DefaultToolDetail, { call })),
1210
+ onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx5(
920
1211
  "button",
921
1212
  {
922
1213
  type: "button",
@@ -943,35 +1234,35 @@ function AssistantMessage({
943
1234
  }) {
944
1235
  const content = useSmoothText(msg.content, streaming);
945
1236
  const reasoning = useSmoothText(msg.reasoning ?? "", streaming);
946
- const reasoningScrollRef = useRef2(null);
947
- const thinkStartRef = useRef2(null);
948
- const thinkMsRef = useRef2(null);
1237
+ const reasoningScrollRef = useRef3(null);
1238
+ const thinkStartRef = useRef3(null);
1239
+ const thinkMsRef = useRef3(null);
949
1240
  if (streaming && reasoning && !content && thinkStartRef.current === null) {
950
1241
  thinkStartRef.current = performance.now();
951
1242
  }
952
1243
  if (content && thinkStartRef.current !== null && thinkMsRef.current === null) {
953
1244
  thinkMsRef.current = performance.now() - thinkStartRef.current;
954
1245
  }
955
- useEffect3(() => {
1246
+ useEffect5(() => {
956
1247
  const el = reasoningScrollRef.current;
957
1248
  if (el && streaming && !content) el.scrollTop = el.scrollHeight;
958
1249
  }, [reasoning, streaming, content]);
959
- return /* @__PURE__ */ jsxs4("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
960
- /* @__PURE__ */ jsxs4("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60", children: [
961
- /* @__PURE__ */ jsx4("span", { className: "font-semibold uppercase", children: agentLabel }),
962
- msg.modelUsed && /* @__PURE__ */ jsx4("span", { className: "font-mono normal-case", children: msg.modelUsed }),
963
- formatTokensPerSecond(msg) && /* @__PURE__ */ jsx4("span", { children: formatTokensPerSecond(msg) }),
964
- formatModelCost(msg, models) && /* @__PURE__ */ jsx4("span", { children: formatModelCost(msg, models) })
1250
+ return /* @__PURE__ */ jsxs5("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
1251
+ /* @__PURE__ */ jsxs5("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60", children: [
1252
+ /* @__PURE__ */ jsx5("span", { className: "font-semibold uppercase", children: agentLabel }),
1253
+ msg.modelUsed && /* @__PURE__ */ jsx5("span", { className: "font-mono normal-case", children: msg.modelUsed }),
1254
+ formatTokensPerSecond(msg) && /* @__PURE__ */ jsx5("span", { children: formatTokensPerSecond(msg) }),
1255
+ formatModelCost(msg, models) && /* @__PURE__ */ jsx5("span", { children: formatModelCost(msg, models) })
965
1256
  ] }),
966
- reasoning && /* @__PURE__ */ jsxs4("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !content, children: [
967
- /* @__PURE__ */ jsx4("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !content ? /* @__PURE__ */ jsx4("span", { className: "animate-pulse", children: "Thinking\u2026" }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
968
- /* @__PURE__ */ jsx4("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground/70", children: reasoning })
1257
+ reasoning && /* @__PURE__ */ jsxs5("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !content, children: [
1258
+ /* @__PURE__ */ jsx5("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !content ? /* @__PURE__ */ jsx5("span", { className: "animate-pulse", children: "Thinking\u2026" }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
1259
+ /* @__PURE__ */ jsx5("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground/70", children: reasoning })
969
1260
  ] }),
970
- /* @__PURE__ */ jsxs4("div", { className: "text-base leading-[1.75]", children: [
1261
+ /* @__PURE__ */ jsxs5("div", { className: "text-base leading-[1.75]", children: [
971
1262
  renderBody(content),
972
- streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx4("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 })
1263
+ streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx5("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 })
973
1264
  ] }),
974
- msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx4("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx4(
1265
+ msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx5("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx5(
975
1266
  ToolCallCard,
976
1267
  {
977
1268
  call: tc,
@@ -986,15 +1277,15 @@ function AssistantMessage({
986
1277
  ] });
987
1278
  }
988
1279
  function ThinkingRow({ agentLabel }) {
989
- const [seconds, setSeconds] = useState3(0);
990
- useEffect3(() => {
1280
+ const [seconds, setSeconds] = useState5(0);
1281
+ useEffect5(() => {
991
1282
  const id = setInterval(() => setSeconds((s) => s + 1), 1e3);
992
1283
  return () => clearInterval(id);
993
1284
  }, []);
994
- return /* @__PURE__ */ jsxs4("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
995
- /* @__PURE__ */ jsx4("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: agentLabel }),
996
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
997
- /* @__PURE__ */ jsx4("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx4("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
1285
+ return /* @__PURE__ */ jsxs5("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
1286
+ /* @__PURE__ */ jsx5("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: agentLabel }),
1287
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
1288
+ /* @__PURE__ */ jsx5("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx5("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
998
1289
  "Thinking",
999
1290
  seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
1000
1291
  ] })
@@ -1012,14 +1303,14 @@ function ChatMessages({
1012
1303
  onToolCallClick,
1013
1304
  toolRenderers
1014
1305
  }) {
1015
- const renderBody = renderMarkdown ?? ((content) => /* @__PURE__ */ jsx4("p", { className: "whitespace-pre-wrap", children: content }));
1306
+ const renderBody = renderMarkdown ?? ((content) => /* @__PURE__ */ jsx5("p", { className: "whitespace-pre-wrap", children: content }));
1016
1307
  const lastIsUser = messages[messages.length - 1]?.role === "user";
1017
- return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1308
+ return /* @__PURE__ */ jsxs5(Fragment2, { children: [
1018
1309
  messages.map(
1019
- (msg) => msg.role === "user" ? /* @__PURE__ */ jsx4("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs4("div", { className: "ml-auto w-fit max-w-[85%]", children: [
1020
- /* @__PURE__ */ jsx4("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: userLabel }),
1021
- /* @__PURE__ */ jsx4("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx4("p", { className: "whitespace-pre-wrap", children: msg.content }) })
1022
- ] }) }, msg.id) : /* @__PURE__ */ jsx4(
1310
+ (msg) => msg.role === "user" ? /* @__PURE__ */ jsx5("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs5("div", { className: "ml-auto w-fit max-w-[85%]", children: [
1311
+ /* @__PURE__ */ jsx5("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: userLabel }),
1312
+ /* @__PURE__ */ jsx5("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx5("p", { className: "whitespace-pre-wrap", children: msg.content }) })
1313
+ ] }) }, msg.id) : /* @__PURE__ */ jsx5(
1023
1314
  AssistantMessage,
1024
1315
  {
1025
1316
  msg,
@@ -1035,11 +1326,12 @@ function ChatMessages({
1035
1326
  msg.id
1036
1327
  )
1037
1328
  ),
1038
- loading && lastIsUser && /* @__PURE__ */ jsx4(ThinkingRow, { agentLabel })
1329
+ loading && lastIsUser && /* @__PURE__ */ jsx5(ThinkingRow, { agentLabel })
1039
1330
  ] });
1040
1331
  }
1041
1332
  export {
1042
1333
  AgentActivityPanel,
1334
+ AgentSessionControls,
1043
1335
  ChatMessages,
1044
1336
  EffortPicker,
1045
1337
  FlowWaterfall,
@@ -1059,6 +1351,7 @@ export {
1059
1351
  nextRevealCount,
1060
1352
  pendingApprovalOf,
1061
1353
  streamChatTurn,
1354
+ useSandboxTerminalConnection,
1062
1355
  useSmoothText,
1063
1356
  waterfallLayout
1064
1357
  };