@tangle-network/agent-app 0.42.17 → 0.42.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assistant/index.d.ts +619 -0
- package/dist/assistant/index.js +2706 -0
- package/dist/assistant/index.js.map +1 -0
- package/dist/chunk-WV2U5UIB.js +2158 -0
- package/dist/chunk-WV2U5UIB.js.map +1 -0
- package/dist/index.js +56 -56
- package/dist/web-react/index.d.ts +56 -2
- package/dist/web-react/index.js +36 -1839
- package/dist/web-react/index.js.map +1 -1
- package/package.json +6 -1
package/dist/web-react/index.js
CHANGED
|
@@ -1,1846 +1,43 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const dt = last == null ? 16 : Math.min(t - last, 100);
|
|
38
|
-
last = t;
|
|
39
|
-
const targetLen = lastTargetRef.current.length;
|
|
40
|
-
if (shownRef.current < targetLen) {
|
|
41
|
-
shownRef.current = nextRevealCount(shownRef.current, targetLen, dt, opts);
|
|
42
|
-
force((n) => n + 1);
|
|
43
|
-
raf = requestAnimationFrame(tick);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
raf = requestAnimationFrame(tick);
|
|
47
|
-
return () => cancelAnimationFrame(raf);
|
|
48
|
-
}, [enabled, target]);
|
|
49
|
-
return target.slice(0, Math.floor(shownRef.current));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/web-react/controls.tsx
|
|
53
|
-
import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
54
|
-
|
|
55
|
-
// src/web-react/provider-logo.tsx
|
|
56
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
57
|
-
var LOGOS = {
|
|
58
|
-
anthropic: { viewBox: "0 0 24 24", fill: "#D97757", paths: ["M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z"] },
|
|
59
|
-
google: { viewBox: "0 0 24 24", fill: "#8E75B2", paths: ["M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81"] },
|
|
60
|
-
deepseek: { viewBox: "0 0 24 24", fill: "#4D6BFE", paths: ["M23.748 4.651c-.254-.124-.364.113-.512.233-.051.04-.094.09-.137.137-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.155-.708-.311-.955-.65-.172-.24-.219-.509-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.094.172.187.129.323-.082.28-.18.553-.266.833-.055.179-.137.218-.328.14a5.5 5.5 0 0 1-1.737-1.179c-.857-.828-1.631-1.743-2.597-2.46a12 12 0 0 0-.689-.47c-.985-.957.13-1.743.387-1.836.27-.098.094-.433-.778-.428-.872.003-1.67.295-2.687.685a3 3 0 0 1-.465.136 9.6 9.6 0 0 0-2.883-.101c-1.885.21-3.39 1.1-4.497 2.622C.082 8.776-.231 10.854.152 13.02c.403 2.284 1.568 4.175 3.36 5.653 1.857 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.132-.284 4.994-1.86.47.234.962.328 1.78.398.629.058 1.235-.031 1.705-.129.735-.155.684-.836.418-.961-2.155-1.004-1.682-.595-2.112-.926 1.095-1.295 2.768-3.598 3.284-6.733.05-.346.115-.834.108-1.114-.004-.171.035-.238.23-.257a4.2 4.2 0 0 0 1.545-.475c1.397-.763 1.96-2.016 2.093-3.517.02-.23-.004-.467-.247-.588M11.58 18.168c-2.088-1.642-3.101-2.183-3.52-2.16-.39.024-.32.472-.234.763.09.288.207.487.371.74.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.168-1.361-.801-2.5-1.86-3.301-3.306-.775-1.393-1.225-2.888-1.299-4.482-.02-.385.094-.522.477-.592a4.7 4.7 0 0 1 1.53-.038c2.131.311 3.946 1.264 5.467 2.774.868.86 1.525 1.887 2.202 2.89.72 1.066 1.494 2.082 2.48 2.915.348.291.626.513.892.677-.802.09-2.14.109-3.055-.615zm1.001-6.44a.306.306 0 0 1 .415-.287.3.3 0 0 1 .113.074.3.3 0 0 1 .086.214c0 .17-.136.307-.308.307a.303.303 0 0 1-.306-.307m3.11 1.596c-.2.081-.4.151-.591.16a1.25 1.25 0 0 1-.798-.254c-.274-.23-.47-.358-.551-.758a1.7 1.7 0 0 1 .015-.588c.07-.327-.007-.537-.238-.727-.188-.156-.426-.199-.689-.199a.6.6 0 0 1-.254-.078.253.253 0 0 1-.114-.358 1 1 0 0 1 .192-.21c.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.392.451.462.576.685.915.176.264.336.536.446.848.066.194-.02.353-.25.45"] },
|
|
61
|
-
mistral: { viewBox: "0 0 24 24", fill: "#FA520F", paths: ["M17.143 3.429v3.428h-3.429v3.429h-3.428V6.857H6.857V3.43H3.43v13.714H0v3.428h10.286v-3.428H6.857v-3.429h3.429v3.429h3.429v-3.429h3.428v3.429h-3.428v3.428H24v-3.428h-3.43V3.429z"] },
|
|
62
|
-
xai: { viewBox: "0 0 24 24", fill: "#000000", paths: ["M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"] },
|
|
63
|
-
nvidia: { viewBox: "0 0 24 24", fill: "#76B900", paths: ["M8.948 8.798v-1.43a6.7 6.7 0 0 1 .424-.018c3.922-.124 6.493 3.374 6.493 3.374s-2.774 3.851-5.75 3.851c-.398 0-.787-.062-1.158-.185v-4.346c1.528.185 1.837.857 2.747 2.385l2.04-1.714s-1.492-1.952-4-1.952a6.016 6.016 0 0 0-.796.035m0-4.735v2.138l.424-.027c5.45-.185 9.01 4.47 9.01 4.47s-4.08 4.964-8.33 4.964c-.37 0-.733-.035-1.095-.097v1.325c.3.035.61.062.91.062 3.957 0 6.82-2.023 9.593-4.408.459.371 2.34 1.263 2.73 1.652-2.633 2.208-8.772 3.984-12.253 3.984-.335 0-.653-.018-.971-.053v1.864H24V4.063zm0 10.326v1.131c-3.657-.654-4.673-4.46-4.673-4.46s1.758-1.944 4.673-2.262v1.237H8.94c-1.528-.186-2.73 1.245-2.73 1.245s.68 2.412 2.739 3.11M2.456 10.9s2.164-3.197 6.5-3.533V6.201C4.153 6.59 0 10.653 0 10.653s2.35 6.802 8.948 7.42v-1.237c-4.84-.6-6.492-5.936-6.492-5.936z"] },
|
|
64
|
-
meta: { viewBox: "0 0 24 24", fill: "#0467DF", paths: ["M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z"] },
|
|
65
|
-
moonshotai: { viewBox: "0 0 24 24", fill: "#16191E", paths: ["m1.053 16.91 9.538 2.55a21 20.981 0 0 0 .06 2.031l5.956 1.592a12 11.99 0 0 1-15.554-6.172m-1.02-5.79 11.352 3.035a21 20.981 0 0 0-.469 2.01l10.817 2.89a12 11.99 0 0 1-1.845 2.004L.658 15.918a12 11.99 0 0 1-.625-4.796m1.593-5.146L13.573 9.17a21 20.981 0 0 0-1.01 1.874l11.297 3.02a21 20.981 0 0 1-.67 2.362l-11.55-3.087L.125 10.26a12 11.99 0 0 1 1.499-4.285ZM6.067 1.58l11.285 3.016a21 20.981 0 0 0-1.688 1.719l7.824 2.091a21 20.981 0 0 1 .513 2.664L2.107 5.218a12 11.99 0 0 1 3.96-3.638M21.68 4.866 7.222 1.003A12 11.99 0 0 1 21.68 4.866"] },
|
|
66
|
-
openai: { viewBox: "0 0 256 260", fill: "#10A37F", paths: ["M239.184 106.203a64.72 64.72 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.72 64.72 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.67 64.67 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.77 64.77 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483m-97.56 136.338a48.4 48.4 0 0 1-31.105-11.255l1.535-.87l51.67-29.825a8.6 8.6 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601M37.158 197.93a48.35 48.35 0 0 1-5.781-32.589l1.534.921l51.722 29.826a8.34 8.34 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803M23.549 85.38a48.5 48.5 0 0 1 25.58-21.333v61.39a8.29 8.29 0 0 0 4.195 7.316l62.874 36.272l-21.845 12.636a.82.82 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405zm179.466 41.695l-63.08-36.63L161.73 77.86a.82.82 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.54 8.54 0 0 0-4.4-7.213m21.742-32.69l-1.535-.922l-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.72.72 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391zM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87l-51.67 29.825a8.6 8.6 0 0 0-4.246 7.367zm11.868-25.58L128.067 97.3l28.188 16.218v32.434l-28.086 16.218l-28.188-16.218z"] }
|
|
67
|
-
};
|
|
68
|
-
var ALIASES = {
|
|
69
|
-
moonshot: "moonshotai",
|
|
70
|
-
deepseek_ai: "deepseek",
|
|
71
|
-
"x-ai": "xai",
|
|
72
|
-
"meta-llama": "meta"
|
|
73
|
-
};
|
|
74
|
-
var MONOGRAM = {
|
|
75
|
-
cohere: { bg: "#fae8ff", fg: "#c026d3" },
|
|
76
|
-
groq: { bg: "#fce7f3", fg: "#db2777" },
|
|
77
|
-
cerebras: { bg: "#ccfbf1", fg: "#0d9488" },
|
|
78
|
-
zai: { bg: "#ede9fe", fg: "#7c3aed" },
|
|
79
|
-
"z-ai": { bg: "#ede9fe", fg: "#7c3aed" },
|
|
80
|
-
tuner: { bg: "#dbeafe", fg: "#2563eb" }
|
|
81
|
-
};
|
|
82
|
-
function ProviderLogo({ provider, size = 16 }) {
|
|
83
|
-
const key = ALIASES[provider ?? ""] ?? provider ?? "";
|
|
84
|
-
const logo = LOGOS[key];
|
|
85
|
-
if (logo) {
|
|
86
|
-
return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: logo.viewBox, role: "img", "aria-label": key, children: logo.paths.map((d, i) => /* @__PURE__ */ jsx("path", { d, fill: logo.fill }, i)) });
|
|
87
|
-
}
|
|
88
|
-
const mono = MONOGRAM[key] ?? { bg: "#f3f4f6", fg: "#6b7280" };
|
|
89
|
-
return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 16 16", role: "img", "aria-label": key || "model", children: [
|
|
90
|
-
/* @__PURE__ */ jsx("rect", { width: "16", height: "16", rx: "4", fill: mono.bg }),
|
|
91
|
-
/* @__PURE__ */ jsx("text", { x: "8", y: "11.6", textAnchor: "middle", fill: mono.fg, fontSize: "9", fontWeight: "700", fontFamily: "system-ui, sans-serif", children: (key || "?").charAt(0).toUpperCase() })
|
|
92
|
-
] });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// src/web-react/controls.tsx
|
|
96
|
-
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
97
|
-
function ChevronDown({ className }) {
|
|
98
|
-
return /* @__PURE__ */ jsx2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" }) });
|
|
99
|
-
}
|
|
100
|
-
function SearchGlyph({ className }) {
|
|
101
|
-
return /* @__PURE__ */ jsxs2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
102
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "11", r: "8" }),
|
|
103
|
-
/* @__PURE__ */ jsx2("path", { d: "m21 21-4.3-4.3" })
|
|
104
|
-
] });
|
|
105
|
-
}
|
|
106
|
-
function SparkleGlyph({ className }) {
|
|
107
|
-
return /* @__PURE__ */ jsx2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("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" }) });
|
|
108
|
-
}
|
|
109
|
-
function usePopover(open, setOpen) {
|
|
110
|
-
const containerRef = useRef2(null);
|
|
111
|
-
const triggerRef = useRef2(null);
|
|
112
|
-
useEffect2(() => {
|
|
113
|
-
if (!open) return;
|
|
114
|
-
function onMouseDown(e) {
|
|
115
|
-
if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
|
|
116
|
-
}
|
|
117
|
-
function onKeyDown(e) {
|
|
118
|
-
if (e.key === "Escape") {
|
|
119
|
-
setOpen(false);
|
|
120
|
-
triggerRef.current?.focus();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
document.addEventListener("mousedown", onMouseDown);
|
|
124
|
-
document.addEventListener("keydown", onKeyDown);
|
|
125
|
-
return () => {
|
|
126
|
-
document.removeEventListener("mousedown", onMouseDown);
|
|
127
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
128
|
-
};
|
|
129
|
-
}, [open, setOpen]);
|
|
130
|
-
return {
|
|
131
|
-
containerRef,
|
|
132
|
-
triggerRef,
|
|
133
|
-
triggerProps: {
|
|
134
|
-
ref: triggerRef,
|
|
135
|
-
"aria-haspopup": true,
|
|
136
|
-
"aria-expanded": open
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
var POPOVER_OPTION_FOCUS = "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-card";
|
|
141
|
-
function usePending() {
|
|
142
|
-
const [pending, setPending] = useState2(false);
|
|
143
|
-
const inFlight = useRef2(false);
|
|
144
|
-
const mounted = useRef2(true);
|
|
145
|
-
useEffect2(() => {
|
|
146
|
-
mounted.current = true;
|
|
147
|
-
return () => {
|
|
148
|
-
mounted.current = false;
|
|
149
|
-
};
|
|
150
|
-
}, []);
|
|
151
|
-
const run = (action) => {
|
|
152
|
-
if (inFlight.current) return;
|
|
153
|
-
let result;
|
|
154
|
-
try {
|
|
155
|
-
result = action();
|
|
156
|
-
} catch {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (!(result instanceof Promise)) return;
|
|
160
|
-
inFlight.current = true;
|
|
161
|
-
setPending(true);
|
|
162
|
-
void result.finally(() => {
|
|
163
|
-
inFlight.current = false;
|
|
164
|
-
if (mounted.current) setPending(false);
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
return { pending, run };
|
|
168
|
-
}
|
|
169
|
-
function formatPrice(p) {
|
|
170
|
-
if (!p) return void 0;
|
|
171
|
-
const n = Number(p);
|
|
172
|
-
if (isNaN(n) || n === 0) return void 0;
|
|
173
|
-
const perM = n * 1e6;
|
|
174
|
-
return perM >= 1 ? `$${perM.toFixed(0)}/M` : `$${perM.toFixed(2)}/M`;
|
|
175
|
-
}
|
|
176
|
-
function formatContext(len) {
|
|
177
|
-
if (!len) return void 0;
|
|
178
|
-
if (len >= 1e6) return `${(len / 1e6).toFixed(1)}M ctx`;
|
|
179
|
-
if (len >= 1e3) return `${Math.round(len / 1e3)}K ctx`;
|
|
180
|
-
return `${len} ctx`;
|
|
181
|
-
}
|
|
182
|
-
function SectionHeader({ children }) {
|
|
183
|
-
return /* @__PURE__ */ jsx2("div", { className: "px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children });
|
|
184
|
-
}
|
|
185
|
-
function ModelRow({
|
|
186
|
-
model,
|
|
187
|
-
selected,
|
|
188
|
-
onSelect,
|
|
189
|
-
renderProviderBadge
|
|
190
|
-
}) {
|
|
191
|
-
const price = formatPrice(model.pricing?.prompt);
|
|
192
|
-
const ctx = formatContext(model.contextLength);
|
|
193
|
-
return /* @__PURE__ */ jsxs2(
|
|
194
|
-
"button",
|
|
195
|
-
{
|
|
196
|
-
type: "button",
|
|
197
|
-
onClick: onSelect,
|
|
198
|
-
className: `flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${selected ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
|
|
199
|
-
children: [
|
|
200
|
-
renderProviderBadge ? renderProviderBadge(model.provider) : /* @__PURE__ */ jsx2(ProviderLogo, { provider: model.provider, size: 16 }),
|
|
201
|
-
/* @__PURE__ */ jsx2("span", { className: "truncate", children: model.name }),
|
|
202
|
-
!model.supportsTools && /* @__PURE__ */ jsx2("span", { className: "shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: "no tools" }),
|
|
203
|
-
/* @__PURE__ */ jsxs2("span", { className: "ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground", children: [
|
|
204
|
-
ctx && /* @__PURE__ */ jsx2("span", { children: ctx }),
|
|
205
|
-
price && /* @__PURE__ */ jsx2("span", { children: price })
|
|
206
|
-
] })
|
|
207
|
-
]
|
|
208
|
-
}
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = "Recommended" }) {
|
|
212
|
-
const [open, setOpen] = useState2(false);
|
|
213
|
-
const [query, setQuery] = useState2("");
|
|
214
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
215
|
-
const inputRef = useRef2(null);
|
|
216
|
-
useEffect2(() => {
|
|
217
|
-
if (open) inputRef.current?.focus();
|
|
218
|
-
}, [open]);
|
|
219
|
-
const selected = models.find((m) => m.id === value);
|
|
220
|
-
const filtered = useMemo(() => {
|
|
221
|
-
const q = query.trim().toLowerCase();
|
|
222
|
-
if (!q) return null;
|
|
223
|
-
return models.filter(
|
|
224
|
-
(m) => m.id.toLowerCase().includes(q) || m.name.toLowerCase().includes(q) || (m.description?.toLowerCase() ?? "").includes(q) || m.provider.toLowerCase().includes(q)
|
|
225
|
-
);
|
|
226
|
-
}, [models, query]);
|
|
227
|
-
const sections = useMemo(() => {
|
|
228
|
-
const recommended = models.filter((m) => m.featured);
|
|
229
|
-
const byProvider = [];
|
|
230
|
-
for (const m of models) {
|
|
231
|
-
if (m.featured) continue;
|
|
232
|
-
const last = byProvider[byProvider.length - 1];
|
|
233
|
-
if (last && last.provider === m.provider) last.items.push(m);
|
|
234
|
-
else byProvider.push({ provider: m.provider, items: [m] });
|
|
235
|
-
}
|
|
236
|
-
return { recommended, byProvider };
|
|
237
|
-
}, [models]);
|
|
238
|
-
const select = (id) => {
|
|
239
|
-
onChange(id);
|
|
240
|
-
setOpen(false);
|
|
241
|
-
setQuery("");
|
|
242
|
-
};
|
|
243
|
-
return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
244
|
-
/* @__PURE__ */ jsxs2(
|
|
245
|
-
"button",
|
|
246
|
-
{
|
|
247
|
-
type: "button",
|
|
248
|
-
...triggerProps,
|
|
249
|
-
onClick: () => setOpen(!open),
|
|
250
|
-
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",
|
|
251
|
-
children: [
|
|
252
|
-
selected ? renderProviderBadge ? renderProviderBadge(selected.provider) : /* @__PURE__ */ jsx2(ProviderLogo, { provider: selected.provider, size: 16 }) : /* @__PURE__ */ jsx2(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
253
|
-
/* @__PURE__ */ jsx2("span", { className: "max-w-[160px] truncate", children: selected?.name ?? value }),
|
|
254
|
-
/* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
255
|
-
]
|
|
256
|
-
}
|
|
257
|
-
),
|
|
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
|
-
/* @__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
|
-
/* @__PURE__ */ jsx2(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
261
|
-
/* @__PURE__ */ jsx2(
|
|
262
|
-
"input",
|
|
263
|
-
{
|
|
264
|
-
ref: inputRef,
|
|
265
|
-
type: "text",
|
|
266
|
-
value: query,
|
|
267
|
-
onChange: (e) => setQuery(e.target.value),
|
|
268
|
-
placeholder: "Search models...",
|
|
269
|
-
className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
|
|
270
|
-
}
|
|
271
|
-
)
|
|
272
|
-
] }) }),
|
|
273
|
-
/* @__PURE__ */ jsxs2("div", { className: "max-h-[400px] overflow-y-auto p-1 pb-2", children: [
|
|
274
|
-
loading && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading models..." }),
|
|
275
|
-
!loading && filtered && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
276
|
-
filtered.length === 0 && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models match your search" }),
|
|
277
|
-
filtered.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
278
|
-
] }),
|
|
279
|
-
!loading && !filtered && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
280
|
-
sections.recommended.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
281
|
-
/* @__PURE__ */ jsx2(SectionHeader, { children: recommendedLabel }),
|
|
282
|
-
sections.recommended.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
283
|
-
] }),
|
|
284
|
-
sections.byProvider.map((g) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
285
|
-
/* @__PURE__ */ jsx2(SectionHeader, { children: g.provider }),
|
|
286
|
-
g.items.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
287
|
-
] }, g.provider))
|
|
288
|
-
] })
|
|
289
|
-
] })
|
|
290
|
-
] })
|
|
291
|
-
] });
|
|
292
|
-
}
|
|
293
|
-
var DEFAULT_EFFORT_LEVELS = [
|
|
294
|
-
{ id: "off", label: "Off" },
|
|
295
|
-
{ id: "low", label: "Quick" },
|
|
296
|
-
{ id: "medium", label: "Standard" },
|
|
297
|
-
{ id: "high", label: "Extended" }
|
|
298
|
-
];
|
|
299
|
-
function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label = "Thinking" }) {
|
|
300
|
-
const [open, setOpen] = useState2(false);
|
|
301
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
302
|
-
const selected = levels.find((l) => l.id === value) ?? levels[2] ?? levels[0];
|
|
303
|
-
return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
304
|
-
/* @__PURE__ */ jsxs2(
|
|
305
|
-
"button",
|
|
306
|
-
{
|
|
307
|
-
type: "button",
|
|
308
|
-
...triggerProps,
|
|
309
|
-
onClick: () => setOpen(!open),
|
|
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
|
-
children: [
|
|
313
|
-
/* @__PURE__ */ jsx2(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
314
|
-
/* @__PURE__ */ jsxs2("span", { children: [
|
|
315
|
-
label ? /* @__PURE__ */ jsxs2("span", { className: "text-muted-foreground", children: [
|
|
316
|
-
label,
|
|
317
|
-
": "
|
|
318
|
-
] }) : null,
|
|
319
|
-
selected?.label
|
|
320
|
-
] }),
|
|
321
|
-
/* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
322
|
-
]
|
|
323
|
-
}
|
|
324
|
-
),
|
|
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(
|
|
326
|
-
"button",
|
|
327
|
-
{
|
|
328
|
-
type: "button",
|
|
329
|
-
role: "menuitemradio",
|
|
330
|
-
"aria-checked": l.id === value,
|
|
331
|
-
onClick: () => {
|
|
332
|
-
onChange(l.id);
|
|
333
|
-
setOpen(false);
|
|
334
|
-
},
|
|
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"}`,
|
|
336
|
-
children: l.label
|
|
337
|
-
},
|
|
338
|
-
l.id
|
|
339
|
-
)) })
|
|
340
|
-
] });
|
|
341
|
-
}
|
|
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
|
-
|
|
361
|
-
// src/web-react/chat-stream.ts
|
|
362
|
-
function dispatchChatStreamLine(line, cb) {
|
|
363
|
-
let receivedContent = false;
|
|
364
|
-
let turnId;
|
|
365
|
-
if (!line.trim()) return { receivedContent };
|
|
366
|
-
let parsed;
|
|
367
|
-
try {
|
|
368
|
-
parsed = JSON.parse(line);
|
|
369
|
-
} catch {
|
|
370
|
-
return { receivedContent };
|
|
371
|
-
}
|
|
372
|
-
if (parsed.kind === "tool_result") {
|
|
373
|
-
cb.onToolResult?.({
|
|
374
|
-
toolCallId: parsed.toolCallId,
|
|
375
|
-
toolName: parsed.toolName,
|
|
376
|
-
label: parsed.label,
|
|
377
|
-
outcome: parsed.outcome ?? parsed.result
|
|
378
|
-
});
|
|
379
|
-
return { receivedContent: true };
|
|
380
|
-
}
|
|
381
|
-
const evt = parsed.kind === "event" ? parsed.event : parsed;
|
|
382
|
-
if (!evt || typeof evt !== "object") return { receivedContent };
|
|
383
|
-
switch (evt.type) {
|
|
384
|
-
case "turn":
|
|
385
|
-
if (typeof evt.turnId === "string") turnId = evt.turnId;
|
|
386
|
-
break;
|
|
387
|
-
case "text":
|
|
388
|
-
if (typeof evt.text === "string") {
|
|
389
|
-
cb.onText?.(evt.text);
|
|
390
|
-
receivedContent = true;
|
|
391
|
-
}
|
|
392
|
-
break;
|
|
393
|
-
case "reasoning":
|
|
394
|
-
if (typeof evt.text === "string") {
|
|
395
|
-
cb.onReasoning?.(evt.text);
|
|
396
|
-
receivedContent = true;
|
|
397
|
-
}
|
|
398
|
-
break;
|
|
399
|
-
case "tool_call": {
|
|
400
|
-
const call = evt.call ?? evt;
|
|
401
|
-
cb.onToolCall?.({
|
|
402
|
-
toolCallId: call.toolCallId ?? call.id,
|
|
403
|
-
toolName: String(call.toolName ?? call.name ?? "unknown"),
|
|
404
|
-
args: call.args ?? {}
|
|
405
|
-
});
|
|
406
|
-
receivedContent = true;
|
|
407
|
-
break;
|
|
408
|
-
}
|
|
409
|
-
case "tool_result":
|
|
410
|
-
cb.onToolResult?.({
|
|
411
|
-
toolCallId: evt.toolCallId,
|
|
412
|
-
toolName: evt.toolName,
|
|
413
|
-
label: evt.label,
|
|
414
|
-
outcome: evt.outcome ?? evt.result
|
|
415
|
-
});
|
|
416
|
-
receivedContent = true;
|
|
417
|
-
break;
|
|
418
|
-
case "usage": {
|
|
419
|
-
const u = evt.usage;
|
|
420
|
-
if (u) cb.onUsage?.({ promptTokens: u.promptTokens ?? 0, completionTokens: u.completionTokens ?? 0 });
|
|
421
|
-
break;
|
|
422
|
-
}
|
|
423
|
-
case "metadata":
|
|
424
|
-
cb.onMetadata?.(evt.data ?? {});
|
|
425
|
-
break;
|
|
426
|
-
case "error":
|
|
427
|
-
cb.onErrorEvent?.(String(evt.details ?? evt.error ?? "Unknown stream error"));
|
|
428
|
-
break;
|
|
429
|
-
default:
|
|
430
|
-
break;
|
|
431
|
-
}
|
|
432
|
-
return { turnId, receivedContent };
|
|
433
|
-
}
|
|
434
|
-
async function consumeChatStream(body, cb) {
|
|
435
|
-
const reader = body.getReader();
|
|
436
|
-
const decoder = new TextDecoder();
|
|
437
|
-
let buffer = "";
|
|
438
|
-
let turnId = null;
|
|
439
|
-
let receivedContent = false;
|
|
440
|
-
const handle = (line) => {
|
|
441
|
-
const r = dispatchChatStreamLine(line, cb);
|
|
442
|
-
if (r.turnId) {
|
|
443
|
-
turnId = r.turnId;
|
|
444
|
-
cb.onTurnId?.(r.turnId);
|
|
445
|
-
}
|
|
446
|
-
if (r.receivedContent) receivedContent = true;
|
|
447
|
-
};
|
|
448
|
-
for (; ; ) {
|
|
449
|
-
const { done, value } = await reader.read();
|
|
450
|
-
if (done) {
|
|
451
|
-
if (buffer.trim()) handle(buffer);
|
|
452
|
-
break;
|
|
453
|
-
}
|
|
454
|
-
buffer += decoder.decode(value, { stream: true });
|
|
455
|
-
const lines = buffer.split("\n");
|
|
456
|
-
buffer = lines.pop() ?? "";
|
|
457
|
-
for (const line of lines) handle(line);
|
|
458
|
-
}
|
|
459
|
-
return { turnId, receivedContent };
|
|
460
|
-
}
|
|
461
|
-
async function streamChatTurn(opts) {
|
|
462
|
-
const res = await opts.start();
|
|
463
|
-
if (!res.ok || !res.body) {
|
|
464
|
-
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
465
|
-
throw new Error(err.error ?? `HTTP ${res.status}`);
|
|
466
|
-
}
|
|
467
|
-
let turnId = null;
|
|
468
|
-
const cb = {
|
|
469
|
-
...opts.callbacks,
|
|
470
|
-
onTurnId: (id) => {
|
|
471
|
-
turnId = id;
|
|
472
|
-
opts.callbacks.onTurnId?.(id);
|
|
473
|
-
}
|
|
474
|
-
};
|
|
475
|
-
try {
|
|
476
|
-
return await consumeChatStream(res.body, cb);
|
|
477
|
-
} catch (transportErr) {
|
|
478
|
-
if (!turnId || !opts.resume) throw transportErr;
|
|
479
|
-
opts.onResetForResume?.();
|
|
480
|
-
const resumed = await opts.resume(turnId, 0);
|
|
481
|
-
if (!resumed.ok || !resumed.body) throw transportErr;
|
|
482
|
-
return await consumeChatStream(resumed.body, cb);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// src/web-react/mission-activity.tsx
|
|
487
|
-
import { useCallback, useEffect as useEffect3, useState as useState3 } from "react";
|
|
488
|
-
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
489
|
-
var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "running"]);
|
|
490
|
-
var OK_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "succeeded"]);
|
|
491
|
-
var ERROR_STATUSES = /* @__PURE__ */ new Set(["failed", "error", "cancelled", "aborted"]);
|
|
492
|
-
function activityTone(status) {
|
|
493
|
-
const s = status.toLowerCase();
|
|
494
|
-
if (LIVE_STATUSES.has(s)) return "live";
|
|
495
|
-
if (OK_STATUSES.has(s)) return "ok";
|
|
496
|
-
if (ERROR_STATUSES.has(s)) return "error";
|
|
497
|
-
return "neutral";
|
|
498
|
-
}
|
|
499
|
-
function formatActivityCost(costUsd) {
|
|
500
|
-
if (costUsd === void 0 || !isFinite(costUsd) || costUsd <= 0) return null;
|
|
501
|
-
return costUsd < 0.01 ? `$${costUsd.toFixed(4)}` : `$${costUsd.toFixed(2)}`;
|
|
502
|
-
}
|
|
503
|
-
function formatActivityDuration(durationMs) {
|
|
504
|
-
if (durationMs === void 0 || !isFinite(durationMs) || durationMs < 0) return null;
|
|
505
|
-
const totalSeconds = Math.round(durationMs / 1e3);
|
|
506
|
-
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
507
|
-
const minutes = Math.floor(totalSeconds / 60);
|
|
508
|
-
const seconds = totalSeconds % 60;
|
|
509
|
-
if (minutes < 60) return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
|
|
510
|
-
return `${Math.floor(minutes / 60)}h ${String(minutes % 60).padStart(2, "0")}m`;
|
|
511
|
-
}
|
|
512
|
-
function mergeActivityPages(existing, incoming) {
|
|
513
|
-
const byTask = /* @__PURE__ */ new Map();
|
|
514
|
-
for (const row of existing) byTask.set(row.taskId, row);
|
|
515
|
-
for (const row of incoming) byTask.set(row.taskId, row);
|
|
516
|
-
return [...byTask.values()].sort((a, b) => Date.parse(b.startedAt) - Date.parse(a.startedAt));
|
|
517
|
-
}
|
|
518
|
-
function waterfallLayout(trace) {
|
|
519
|
-
const total = trace.totalMs > 0 ? trace.totalMs : 1;
|
|
520
|
-
return [...trace.spans].sort((a, b) => a.startMs - b.startMs).map((span) => {
|
|
521
|
-
const meta = span.meta ?? {};
|
|
522
|
-
const failed = meta.ok === false || typeof meta.status === "string" && activityTone(meta.status) === "error";
|
|
523
|
-
return {
|
|
524
|
-
name: span.name,
|
|
525
|
-
kind: span.kind,
|
|
526
|
-
offsetPct: Math.max(0, Math.min(100, span.startMs / total * 100)),
|
|
527
|
-
widthPct: Math.max(0.5, Math.min(100, (span.endMs - span.startMs) / total * 100)),
|
|
528
|
-
durationLabel: `${((span.endMs - span.startMs) / 1e3).toFixed(1)}s${span.approx ? "~" : ""}`,
|
|
529
|
-
approx: span.approx === true,
|
|
530
|
-
ok: !failed
|
|
531
|
-
};
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
function ChevronGlyph({ className }) {
|
|
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" }) });
|
|
536
|
-
}
|
|
537
|
-
function RefreshGlyph({ className }) {
|
|
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" }) });
|
|
539
|
-
}
|
|
540
|
-
function CopyGlyph({ className }) {
|
|
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: [
|
|
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" })
|
|
544
|
-
] });
|
|
545
|
-
}
|
|
546
|
-
function TraceIdCopy({ traceId }) {
|
|
547
|
-
const [copied, setCopied] = useState3(false);
|
|
548
|
-
const copy = useCallback(() => {
|
|
549
|
-
void navigator.clipboard?.writeText(traceId).then(
|
|
550
|
-
() => {
|
|
551
|
-
setCopied(true);
|
|
552
|
-
setTimeout(() => setCopied(false), 1200);
|
|
553
|
-
},
|
|
554
|
-
() => {
|
|
555
|
-
}
|
|
556
|
-
);
|
|
557
|
-
}, [traceId]);
|
|
558
|
-
return /* @__PURE__ */ jsxs3(
|
|
559
|
-
"button",
|
|
560
|
-
{
|
|
561
|
-
type: "button",
|
|
562
|
-
onClick: copy,
|
|
563
|
-
title: "Copy trace id",
|
|
564
|
-
"aria-label": "Copy trace id",
|
|
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",
|
|
566
|
-
children: [
|
|
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" })
|
|
570
|
-
]
|
|
571
|
-
}
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
function StatusDot({ tone }) {
|
|
575
|
-
return /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center", children: [
|
|
576
|
-
/* @__PURE__ */ jsx4(
|
|
577
|
-
"span",
|
|
578
|
-
{
|
|
579
|
-
"aria-hidden": true,
|
|
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"}`
|
|
581
|
-
}
|
|
582
|
-
),
|
|
583
|
-
/* @__PURE__ */ jsx4("span", { className: "sr-only", children: tone })
|
|
584
|
-
] });
|
|
585
|
-
}
|
|
586
|
-
var BAR_CLASS = {
|
|
587
|
-
pipeline: "bg-muted-foreground/30",
|
|
588
|
-
model: "bg-primary/60",
|
|
589
|
-
tool: "bg-primary"
|
|
590
|
-
};
|
|
591
|
-
function FlowWaterfall({ trace }) {
|
|
592
|
-
const rows = waterfallLayout(trace);
|
|
593
|
-
if (rows.length === 0) return null;
|
|
594
|
-
const cost = formatActivityCost(trace.costUsd);
|
|
595
|
-
return /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
|
|
596
|
-
rows.map((row, i) => /* @__PURE__ */ jsxs3("div", { className: "grid grid-cols-[minmax(0,2fr)_minmax(0,3fr)_auto] items-center gap-2", children: [
|
|
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(
|
|
599
|
-
"div",
|
|
600
|
-
{
|
|
601
|
-
className: `absolute inset-y-0 rounded-sm ${row.ok ? BAR_CLASS[row.kind] : "bg-destructive/80"} ${row.approx ? "opacity-70" : ""}`,
|
|
602
|
-
style: { left: `${row.offsetPct}%`, width: `${row.widthPct}%` }
|
|
603
|
-
}
|
|
604
|
-
) }),
|
|
605
|
-
/* @__PURE__ */ jsx4("span", { className: "shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: row.durationLabel })
|
|
606
|
-
] }, i)),
|
|
607
|
-
/* @__PURE__ */ jsxs3("p", { className: "pt-0.5 text-right font-mono text-[10px] tabular-nums text-muted-foreground/60", children: [
|
|
608
|
-
(trace.totalMs / 1e3).toFixed(1),
|
|
609
|
-
"s",
|
|
610
|
-
cost ? ` \xB7 ${cost}` : ""
|
|
611
|
-
] })
|
|
612
|
-
] });
|
|
613
|
-
}
|
|
614
|
-
function MissionActivityLane({ activity, startedAt, nowMs }) {
|
|
615
|
-
const [expanded, setExpanded] = useState3(false);
|
|
616
|
-
if (activity.length === 0) return null;
|
|
617
|
-
return /* @__PURE__ */ jsxs3("div", { className: "mt-1 border-l border-border/50 pl-3", children: [
|
|
618
|
-
activity.map((run) => {
|
|
619
|
-
const tone = activityTone(run.status);
|
|
620
|
-
const cost = formatActivityCost(run.costUsd);
|
|
621
|
-
const duration = formatActivityDuration(run.durationMs);
|
|
622
|
-
return /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
|
|
623
|
-
/* @__PURE__ */ jsx4(StatusDot, { tone }),
|
|
624
|
-
/* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
625
|
-
/* @__PURE__ */ jsx4("span", { className: "font-medium", children: run.tool }),
|
|
626
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
|
|
627
|
-
" \u2014 ",
|
|
628
|
-
run.detail
|
|
629
|
-
] })
|
|
630
|
-
] }),
|
|
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 ") }),
|
|
632
|
-
/* @__PURE__ */ jsxs3("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: [
|
|
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 })
|
|
636
|
-
] })
|
|
637
|
-
] }, run.taskId);
|
|
638
|
-
}),
|
|
639
|
-
/* @__PURE__ */ jsxs3(
|
|
640
|
-
"button",
|
|
641
|
-
{
|
|
642
|
-
type: "button",
|
|
643
|
-
onClick: () => setExpanded((v) => !v),
|
|
644
|
-
className: "flex items-center gap-1 py-0.5 text-[10px] font-medium text-muted-foreground/70 transition hover:text-foreground",
|
|
645
|
-
children: [
|
|
646
|
-
/* @__PURE__ */ jsx4(ChevronGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
|
|
647
|
-
"timeline"
|
|
648
|
-
]
|
|
649
|
-
}
|
|
650
|
-
),
|
|
651
|
-
expanded && /* @__PURE__ */ jsx4("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx4(
|
|
652
|
-
FlowWaterfall,
|
|
653
|
-
{
|
|
654
|
-
trace: stepActivityFlowTrace(activity, {
|
|
655
|
-
...startedAt !== void 0 ? { startedAt } : {},
|
|
656
|
-
...nowMs !== void 0 ? { nowMs } : {}
|
|
657
|
-
})
|
|
658
|
-
}
|
|
659
|
-
) })
|
|
660
|
-
] });
|
|
661
|
-
}
|
|
662
|
-
function ActivityRow({
|
|
663
|
-
record,
|
|
664
|
-
renderMissionRef
|
|
665
|
-
}) {
|
|
666
|
-
const [open, setOpen] = useState3(false);
|
|
667
|
-
const tone = activityTone(record.status);
|
|
668
|
-
const cost = formatActivityCost(record.costUsd);
|
|
669
|
-
const duration = formatActivityDuration(record.durationMs);
|
|
670
|
-
return /* @__PURE__ */ jsxs3("div", { className: "rounded-lg border border-border/60 bg-card", children: [
|
|
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: [
|
|
672
|
-
/* @__PURE__ */ jsx4(StatusDot, { tone }),
|
|
673
|
-
/* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
674
|
-
/* @__PURE__ */ jsx4("span", { className: "font-medium", children: record.tool }),
|
|
675
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
|
|
676
|
-
" \u2014 ",
|
|
677
|
-
record.detail
|
|
678
|
-
] })
|
|
679
|
-
] }),
|
|
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(
|
|
682
|
-
"span",
|
|
683
|
-
{
|
|
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"}`,
|
|
685
|
-
children: record.status
|
|
686
|
-
}
|
|
687
|
-
),
|
|
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" : ""}` })
|
|
690
|
-
] }),
|
|
691
|
-
open && /* @__PURE__ */ jsxs3("div", { className: "space-y-2.5 border-t border-border/40 px-3 py-2.5", children: [
|
|
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]) }) }),
|
|
693
|
-
/* @__PURE__ */ jsxs3("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-[11px]", children: [
|
|
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() }),
|
|
698
|
-
duration && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
699
|
-
/* @__PURE__ */ jsx4("dt", { className: "text-muted-foreground/60", children: "duration" }),
|
|
700
|
-
/* @__PURE__ */ jsx4("dd", { className: "text-muted-foreground", children: duration })
|
|
701
|
-
] }),
|
|
702
|
-
record.traceId && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
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 }) })
|
|
705
|
-
] })
|
|
706
|
-
] }),
|
|
707
|
-
record.missionRef && renderMissionRef?.(record.missionRef, record)
|
|
708
|
-
] })
|
|
709
|
-
] });
|
|
710
|
-
}
|
|
711
|
-
function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent activity", emptyLabel = "No agent runs yet." }) {
|
|
712
|
-
const [rows, setRows] = useState3([]);
|
|
713
|
-
const [cursor, setCursor] = useState3(void 0);
|
|
714
|
-
const [loading, setLoading] = useState3(false);
|
|
715
|
-
const [error, setError] = useState3(null);
|
|
716
|
-
const load = useCallback(
|
|
717
|
-
async (from) => {
|
|
718
|
-
setLoading(true);
|
|
719
|
-
setError(null);
|
|
720
|
-
try {
|
|
721
|
-
const page = await fetchActivity(from);
|
|
722
|
-
setRows((prev) => mergeActivityPages(from === void 0 ? [] : prev, page.items));
|
|
723
|
-
setCursor(page.nextCursor);
|
|
724
|
-
} catch (e) {
|
|
725
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
726
|
-
} finally {
|
|
727
|
-
setLoading(false);
|
|
728
|
-
}
|
|
729
|
-
},
|
|
730
|
-
[fetchActivity]
|
|
731
|
-
);
|
|
732
|
-
useEffect3(() => {
|
|
733
|
-
void load();
|
|
734
|
-
}, [load]);
|
|
735
|
-
return /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
|
|
736
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
|
|
737
|
-
/* @__PURE__ */ jsx4("h2", { className: "flex-1 text-sm font-semibold", children: title }),
|
|
738
|
-
/* @__PURE__ */ jsx4(
|
|
739
|
-
"button",
|
|
740
|
-
{
|
|
741
|
-
type: "button",
|
|
742
|
-
onClick: () => void load(),
|
|
743
|
-
disabled: loading,
|
|
744
|
-
"aria-label": "Refresh",
|
|
745
|
-
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground disabled:opacity-50",
|
|
746
|
-
children: /* @__PURE__ */ jsx4(RefreshGlyph, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` })
|
|
747
|
-
}
|
|
748
|
-
)
|
|
749
|
-
] }),
|
|
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(
|
|
754
|
-
"button",
|
|
755
|
-
{
|
|
756
|
-
type: "button",
|
|
757
|
-
onClick: () => void load(cursor),
|
|
758
|
-
disabled: loading,
|
|
759
|
-
className: "w-full rounded-md border border-border bg-card px-3 py-1.5 text-xs font-medium text-muted-foreground transition hover:bg-accent/30 disabled:opacity-50",
|
|
760
|
-
children: "Older runs"
|
|
761
|
-
}
|
|
762
|
-
)
|
|
763
|
-
] });
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// src/web-react/sandbox-terminal.ts
|
|
767
|
-
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
|
|
768
|
-
var DEFAULT_PROVISION_POLL_INTERVAL_MS = 2e3;
|
|
769
|
-
var DEFAULT_PROVISION_POLL_TIMEOUT_MS = 9e4;
|
|
770
|
-
var DEFAULT_TOKEN_REFRESH_SKEW_MS = 12e4;
|
|
771
|
-
var EMPTY_CONNECTION = {
|
|
772
|
-
runtimeUrl: null,
|
|
773
|
-
sidecarUrl: null,
|
|
774
|
-
token: null,
|
|
775
|
-
expiresAt: null,
|
|
776
|
-
status: "idle",
|
|
777
|
-
error: null,
|
|
778
|
-
loading: false
|
|
779
|
-
};
|
|
780
|
-
function useSandboxTerminalConnection(opts) {
|
|
781
|
-
const [conn, setConn] = useState4(EMPTY_CONNECTION);
|
|
782
|
-
const mountedRef = useRef3(false);
|
|
783
|
-
const generationRef = useRef3(0);
|
|
784
|
-
const fetcher = opts.fetcher ?? fetch;
|
|
785
|
-
const pollIntervalMs = opts.provisionPollIntervalMs ?? DEFAULT_PROVISION_POLL_INTERVAL_MS;
|
|
786
|
-
const pollTimeoutMs = opts.provisionPollTimeoutMs ?? DEFAULT_PROVISION_POLL_TIMEOUT_MS;
|
|
787
|
-
const refreshSkewMs = opts.tokenRefreshSkewMs ?? DEFAULT_TOKEN_REFRESH_SKEW_MS;
|
|
788
|
-
const connectionUrl = useCallback2(() => {
|
|
789
|
-
if (typeof opts.connectionUrl === "function") return opts.connectionUrl(opts.workspaceId);
|
|
790
|
-
return opts.connectionUrl ?? `/api/workspaces/${encodeURIComponent(opts.workspaceId)}/sandbox/connection`;
|
|
791
|
-
}, [opts.connectionUrl, opts.workspaceId]);
|
|
792
|
-
const connect = useCallback2(async () => {
|
|
793
|
-
const generation = generationRef.current + 1;
|
|
794
|
-
generationRef.current = generation;
|
|
795
|
-
const isCurrent = () => mountedRef.current && generationRef.current === generation;
|
|
796
|
-
const setCurrentConn = (value) => {
|
|
797
|
-
if (!isCurrent()) return;
|
|
798
|
-
setConn(value);
|
|
799
|
-
};
|
|
800
|
-
setCurrentConn((current) => ({ ...current, loading: true, error: null }));
|
|
801
|
-
const deadline = Date.now() + pollTimeoutMs;
|
|
802
|
-
while (isCurrent()) {
|
|
803
|
-
try {
|
|
804
|
-
const res = await fetcher(connectionUrl());
|
|
805
|
-
const data = await res.json();
|
|
806
|
-
if (!isCurrent()) return;
|
|
807
|
-
const runtimeUrl = data.runtimeUrl ?? data.sidecarUrl;
|
|
808
|
-
if (res.ok && runtimeUrl && data.token && data.expiresAt) {
|
|
809
|
-
setCurrentConn({
|
|
810
|
-
runtimeUrl,
|
|
811
|
-
sidecarUrl: data.sidecarUrl ?? runtimeUrl,
|
|
812
|
-
token: data.token,
|
|
813
|
-
expiresAt: data.expiresAt,
|
|
814
|
-
status: data.status ?? "running",
|
|
815
|
-
error: null,
|
|
816
|
-
loading: false,
|
|
817
|
-
...data.sandboxId ? { sandboxId: data.sandboxId } : {}
|
|
818
|
-
});
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
if (res.ok) {
|
|
822
|
-
setCurrentConn({
|
|
823
|
-
runtimeUrl: null,
|
|
824
|
-
sidecarUrl: null,
|
|
825
|
-
token: null,
|
|
826
|
-
expiresAt: null,
|
|
827
|
-
loading: false,
|
|
828
|
-
error: "Sandbox connection response is missing required fields",
|
|
829
|
-
status: data.status ?? "error",
|
|
830
|
-
...data.sandboxId ? { sandboxId: data.sandboxId } : {}
|
|
831
|
-
});
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
if (res.status === 503 && Date.now() < deadline) {
|
|
835
|
-
setCurrentConn((current) => ({
|
|
836
|
-
...current,
|
|
837
|
-
loading: true,
|
|
838
|
-
status: data.status ?? "provisioning",
|
|
839
|
-
error: null
|
|
840
|
-
}));
|
|
841
|
-
await sleep(pollIntervalMs);
|
|
842
|
-
continue;
|
|
843
|
-
}
|
|
844
|
-
setCurrentConn((current) => ({
|
|
845
|
-
...current,
|
|
846
|
-
runtimeUrl: null,
|
|
847
|
-
sidecarUrl: null,
|
|
848
|
-
token: null,
|
|
849
|
-
expiresAt: null,
|
|
850
|
-
loading: false,
|
|
851
|
-
error: data.error ?? "Sandbox not available",
|
|
852
|
-
status: data.status ?? "error"
|
|
853
|
-
}));
|
|
854
|
-
return;
|
|
855
|
-
} catch (err) {
|
|
856
|
-
if (!isCurrent()) return;
|
|
857
|
-
if (Date.now() < deadline) {
|
|
858
|
-
await sleep(pollIntervalMs);
|
|
859
|
-
continue;
|
|
860
|
-
}
|
|
861
|
-
setCurrentConn((current) => ({
|
|
862
|
-
...current,
|
|
863
|
-
runtimeUrl: null,
|
|
864
|
-
sidecarUrl: null,
|
|
865
|
-
token: null,
|
|
866
|
-
expiresAt: null,
|
|
867
|
-
loading: false,
|
|
868
|
-
error: err instanceof Error ? err.message : "Connection failed"
|
|
869
|
-
}));
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
}, [connectionUrl, fetcher, pollIntervalMs, pollTimeoutMs]);
|
|
874
|
-
useEffect4(() => {
|
|
875
|
-
mountedRef.current = true;
|
|
876
|
-
return () => {
|
|
877
|
-
mountedRef.current = false;
|
|
878
|
-
generationRef.current += 1;
|
|
879
|
-
};
|
|
880
|
-
}, []);
|
|
881
|
-
useEffect4(() => {
|
|
882
|
-
void connect();
|
|
883
|
-
}, [connect]);
|
|
884
|
-
useEffect4(() => {
|
|
885
|
-
if (!conn.runtimeUrl || !conn.token || !conn.expiresAt) return;
|
|
886
|
-
const refreshAt = Date.parse(conn.expiresAt) - Date.now() - refreshSkewMs;
|
|
887
|
-
if (!Number.isFinite(refreshAt)) {
|
|
888
|
-
setConn((current) => ({
|
|
889
|
-
...current,
|
|
890
|
-
runtimeUrl: null,
|
|
891
|
-
sidecarUrl: null,
|
|
892
|
-
token: null,
|
|
893
|
-
expiresAt: null,
|
|
894
|
-
status: "error",
|
|
895
|
-
error: "Sandbox token expiry is invalid"
|
|
896
|
-
}));
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
const timer = window.setTimeout(() => {
|
|
900
|
-
void connect();
|
|
901
|
-
}, Math.max(1e3, refreshAt));
|
|
902
|
-
return () => window.clearTimeout(timer);
|
|
903
|
-
}, [conn.runtimeUrl, conn.token, conn.expiresAt, connect, refreshSkewMs]);
|
|
904
|
-
return { ...conn, connect };
|
|
905
|
-
}
|
|
906
|
-
function sleep(ms) {
|
|
907
|
-
return new Promise((resolve) => window.setTimeout(resolve, ms));
|
|
908
|
-
}
|
|
909
|
-
var DEFAULT_TERMINAL_CID_KEY = "agent-app:terminal-connection-id";
|
|
910
|
-
function newConnectionId() {
|
|
911
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
912
|
-
return `cid-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;
|
|
913
|
-
}
|
|
914
|
-
function tabTerminalConnectionId(storageKey = DEFAULT_TERMINAL_CID_KEY) {
|
|
915
|
-
try {
|
|
916
|
-
const store = globalThis.sessionStorage;
|
|
917
|
-
const existing = store?.getItem(storageKey);
|
|
918
|
-
if (existing) return existing;
|
|
919
|
-
const id = newConnectionId();
|
|
920
|
-
store?.setItem(storageKey, id);
|
|
921
|
-
return id;
|
|
922
|
-
} catch {
|
|
923
|
-
return newConnectionId();
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
// src/web-react/workspace-terminal-panel.tsx
|
|
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(
|
|
931
|
-
() => import("@tangle-network/sandbox-ui/terminal").then((m) => ({ default: m.TerminalView }))
|
|
932
|
-
);
|
|
933
|
-
var TONE_DOT = {
|
|
934
|
-
idle: "bg-muted-foreground/50",
|
|
935
|
-
connecting: "animate-pulse bg-warning",
|
|
936
|
-
connected: "bg-success",
|
|
937
|
-
error: "bg-destructive"
|
|
938
|
-
};
|
|
939
|
-
function defaultStatusDisplay(conn) {
|
|
940
|
-
if (conn.error) return { tone: "error", label: "Disconnected" };
|
|
941
|
-
if (conn.runtimeUrl && conn.token) return { tone: "connected", label: "Connected" };
|
|
942
|
-
if (conn.loading) return { tone: "connecting", label: conn.status === "provisioning" ? "Provisioning\u2026" : "Connecting\u2026" };
|
|
943
|
-
return { tone: "idle", label: "Idle" };
|
|
944
|
-
}
|
|
945
|
-
function WorkspaceTerminalPanel({
|
|
946
|
-
connection,
|
|
947
|
-
connectionId,
|
|
948
|
-
title = "Terminal",
|
|
949
|
-
subtitle,
|
|
950
|
-
isActive,
|
|
951
|
-
onRetry,
|
|
952
|
-
statusDisplay,
|
|
953
|
-
headerExtra,
|
|
954
|
-
className
|
|
955
|
-
}) {
|
|
956
|
-
const status = (statusDisplay ?? defaultStatusDisplay)(connection);
|
|
957
|
-
const apiUrl = connection.runtimeUrl ?? connection.sidecarUrl;
|
|
958
|
-
const ready = Boolean(apiUrl && connection.token);
|
|
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: [
|
|
960
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-3 border-b border-border px-4 py-2.5", children: [
|
|
961
|
-
/* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
|
|
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 })
|
|
964
|
-
] }),
|
|
965
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
|
|
966
|
-
/* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
967
|
-
/* @__PURE__ */ jsx5("span", { className: `h-1.5 w-1.5 rounded-full ${TONE_DOT[status.tone]}`, "aria-hidden": true }),
|
|
968
|
-
status.label
|
|
969
|
-
] }),
|
|
970
|
-
headerExtra
|
|
971
|
-
] })
|
|
972
|
-
] }),
|
|
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(
|
|
974
|
-
TerminalView,
|
|
975
|
-
{
|
|
976
|
-
apiUrl,
|
|
977
|
-
token: connection.token,
|
|
978
|
-
connectionId,
|
|
979
|
-
title,
|
|
980
|
-
subtitle,
|
|
981
|
-
isActive
|
|
982
|
-
}
|
|
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(
|
|
986
|
-
"button",
|
|
987
|
-
{
|
|
988
|
-
type: "button",
|
|
989
|
-
onClick: onRetry,
|
|
990
|
-
className: "mt-3 inline-flex items-center justify-center rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-muted",
|
|
991
|
-
children: "Reconnect"
|
|
992
|
-
}
|
|
993
|
-
)
|
|
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(
|
|
997
|
-
"button",
|
|
998
|
-
{
|
|
999
|
-
type: "button",
|
|
1000
|
-
onClick: onRetry,
|
|
1001
|
-
className: "mt-3 inline-flex items-center justify-center rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-muted",
|
|
1002
|
-
children: "Connect"
|
|
1003
|
-
}
|
|
1004
|
-
)
|
|
1005
|
-
] }) }) })
|
|
1006
|
-
] });
|
|
1007
|
-
}
|
|
1008
|
-
function TerminalMessage({ children }) {
|
|
1009
|
-
return /* @__PURE__ */ jsx5("div", { className: "absolute inset-0 flex flex-col items-center justify-center p-6 text-center", children });
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
// src/web-react/seat-paywall.tsx
|
|
1013
|
-
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1014
|
-
function CheckGlyph() {
|
|
1015
|
-
return /* @__PURE__ */ jsx6(
|
|
1016
|
-
"svg",
|
|
1017
|
-
{
|
|
1018
|
-
className: "h-4 w-4 shrink-0 text-primary",
|
|
1019
|
-
viewBox: "0 0 24 24",
|
|
1020
|
-
fill: "none",
|
|
1021
|
-
stroke: "currentColor",
|
|
1022
|
-
strokeWidth: "2.5",
|
|
1023
|
-
strokeLinecap: "round",
|
|
1024
|
-
strokeLinejoin: "round",
|
|
1025
|
-
"aria-hidden": true,
|
|
1026
|
-
children: /* @__PURE__ */ jsx6("path", { d: "M20 6 9 17l-5-5" })
|
|
1027
|
-
}
|
|
1028
|
-
);
|
|
1029
|
-
}
|
|
1030
|
-
function Benefit({ children }) {
|
|
1031
|
-
return /* @__PURE__ */ jsxs5("li", { className: "flex items-start gap-2.5 text-sm text-foreground", children: [
|
|
1032
|
-
/* @__PURE__ */ jsx6("span", { className: "mt-0.5", children: /* @__PURE__ */ jsx6(CheckGlyph, {}) }),
|
|
1033
|
-
/* @__PURE__ */ jsx6("span", { children })
|
|
1034
|
-
] });
|
|
1035
|
-
}
|
|
1036
|
-
function SeatPaywall({
|
|
1037
|
-
product,
|
|
1038
|
-
onCheckout,
|
|
1039
|
-
priceUsd = 100,
|
|
1040
|
-
includedUsageUsd = 50,
|
|
1041
|
-
tagline,
|
|
1042
|
-
ctaLabel,
|
|
1043
|
-
benefits,
|
|
1044
|
-
footnote
|
|
1045
|
-
}) {
|
|
1046
|
-
const { pending, run } = usePending();
|
|
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 }),
|
|
1049
|
-
/* @__PURE__ */ jsxs5("h1", { className: "mt-2 text-2xl font-semibold tracking-tight text-foreground", children: [
|
|
1050
|
-
"Unlock ",
|
|
1051
|
-
product
|
|
1052
|
-
] }),
|
|
1053
|
-
tagline && /* @__PURE__ */ jsx6("p", { className: "mt-2 text-sm text-muted-foreground", children: tagline }),
|
|
1054
|
-
/* @__PURE__ */ jsxs5("div", { className: "mt-6 flex items-baseline gap-1.5", children: [
|
|
1055
|
-
/* @__PURE__ */ jsxs5("span", { className: "text-3xl font-semibold text-foreground", children: [
|
|
1056
|
-
"$",
|
|
1057
|
-
priceUsd
|
|
1058
|
-
] }),
|
|
1059
|
-
/* @__PURE__ */ jsx6("span", { className: "text-sm text-muted-foreground", children: "/mo" })
|
|
1060
|
-
] }),
|
|
1061
|
-
/* @__PURE__ */ jsxs5("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
1062
|
-
"Includes $",
|
|
1063
|
-
includedUsageUsd,
|
|
1064
|
-
"/mo of AI usage"
|
|
1065
|
-
] }),
|
|
1066
|
-
/* @__PURE__ */ jsx6("ul", { className: "mt-6 space-y-2.5", children: (benefits ?? [
|
|
1067
|
-
`Full access to ${product}`,
|
|
1068
|
-
`$${includedUsageUsd}/mo of AI usage included, every month`
|
|
1069
|
-
]).map((benefit, i) => /* @__PURE__ */ jsx6(Benefit, { children: benefit }, i)) }),
|
|
1070
|
-
/* @__PURE__ */ jsx6(
|
|
1071
|
-
"button",
|
|
1072
|
-
{
|
|
1073
|
-
type: "button",
|
|
1074
|
-
disabled: pending,
|
|
1075
|
-
onClick: () => run(onCheckout),
|
|
1076
|
-
className: "mt-7 inline-flex w-full items-center justify-center rounded-xl bg-primary px-4 py-2.5 text-sm font-medium text-primary-foreground transition hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-70",
|
|
1077
|
-
children: pending ? "Opening checkout\u2026" : ctaLabel ?? `Unlock ${product}`
|
|
1078
|
-
}
|
|
1079
|
-
),
|
|
1080
|
-
footnote && /* @__PURE__ */ jsx6("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: footnote })
|
|
1081
|
-
] }) });
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
// src/web-react/agent-session-controls.tsx
|
|
1085
|
-
import { useMemo as useMemo2, useState as useState5 } from "react";
|
|
1086
|
-
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1087
|
-
var HARNESS_LABELS = {
|
|
1088
|
-
opencode: "OpenCode (any model)",
|
|
1089
|
-
"claude-code": "Claude Code (Anthropic)",
|
|
1090
|
-
codex: "Codex (OpenAI)",
|
|
1091
|
-
"kimi-code": "Kimi (Moonshot)",
|
|
1092
|
-
amp: "Amp",
|
|
1093
|
-
"factory-droids": "Factory Droids",
|
|
1094
|
-
cursor: "Cursor",
|
|
1095
|
-
hermes: "Hermes",
|
|
1096
|
-
forge: "Forge",
|
|
1097
|
-
pi: "Pi",
|
|
1098
|
-
openclaw: "OpenClaw",
|
|
1099
|
-
acp: "ACP",
|
|
1100
|
-
"cli-base": "CLI"
|
|
1101
|
-
};
|
|
1102
|
-
function harnessLabel(h) {
|
|
1103
|
-
return HARNESS_LABELS[h] ?? h;
|
|
1104
|
-
}
|
|
1105
|
-
function ChevronDown2({ className }) {
|
|
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" }) });
|
|
1107
|
-
}
|
|
1108
|
-
function GearGlyph({ className }) {
|
|
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: [
|
|
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" })
|
|
1112
|
-
] });
|
|
1113
|
-
}
|
|
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";
|
|
1115
|
-
function HarnessPicker({
|
|
1116
|
-
value,
|
|
1117
|
-
onChange,
|
|
1118
|
-
available
|
|
1119
|
-
}) {
|
|
1120
|
-
const [open, setOpen] = useState5(false);
|
|
1121
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
1122
|
-
const options = available ?? Object.keys(HARNESS_LABELS);
|
|
1123
|
-
return /* @__PURE__ */ jsxs6("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
1124
|
-
/* @__PURE__ */ jsxs6(
|
|
1125
|
-
"button",
|
|
1126
|
-
{
|
|
1127
|
-
type: "button",
|
|
1128
|
-
...triggerProps,
|
|
1129
|
-
onClick: () => setOpen(!open),
|
|
1130
|
-
title: "Agent backend",
|
|
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}`,
|
|
1132
|
-
children: [
|
|
1133
|
-
/* @__PURE__ */ jsx7("span", { className: "truncate", children: harnessLabel(value) }),
|
|
1134
|
-
/* @__PURE__ */ jsx7(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
1135
|
-
]
|
|
1136
|
-
}
|
|
1137
|
-
),
|
|
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(
|
|
1139
|
-
"button",
|
|
1140
|
-
{
|
|
1141
|
-
type: "button",
|
|
1142
|
-
role: "menuitemradio",
|
|
1143
|
-
"aria-checked": h === value,
|
|
1144
|
-
onClick: () => {
|
|
1145
|
-
onChange(h);
|
|
1146
|
-
setOpen(false);
|
|
1147
|
-
},
|
|
1148
|
-
className: `flex w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${FOCUS_RING} ${h === value ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
|
|
1149
|
-
children: harnessLabel(h)
|
|
1150
|
-
},
|
|
1151
|
-
h
|
|
1152
|
-
)) })
|
|
1153
|
-
] });
|
|
1154
|
-
}
|
|
1155
|
-
function useCoherentHandlers(props) {
|
|
1156
|
-
const { model, models, harness, onModelChange, onHarnessChange } = props;
|
|
1157
|
-
const canonicalIds = useMemo2(() => models.map((m) => m.id), [models]);
|
|
1158
|
-
const onModel = (next) => {
|
|
1159
|
-
onModelChange(next);
|
|
1160
|
-
const nextHarness = snapHarnessToModel(harness, next);
|
|
1161
|
-
if (nextHarness !== harness) onHarnessChange(nextHarness);
|
|
1162
|
-
};
|
|
1163
|
-
const onHarness = (next) => {
|
|
1164
|
-
onHarnessChange(next);
|
|
1165
|
-
const snapped = snapModelToHarness(next, model, canonicalIds);
|
|
1166
|
-
if (snapped !== model) onModelChange(snapped);
|
|
1167
|
-
};
|
|
1168
|
-
return { onModel, onHarness };
|
|
1169
|
-
}
|
|
1170
|
-
function AgentSessionControls(props) {
|
|
1171
|
-
const {
|
|
1172
|
-
models,
|
|
1173
|
-
modelsLoading,
|
|
1174
|
-
model,
|
|
1175
|
-
harness,
|
|
1176
|
-
availableHarnesses,
|
|
1177
|
-
effort,
|
|
1178
|
-
onEffortChange,
|
|
1179
|
-
layout = "inline",
|
|
1180
|
-
showHarness = true,
|
|
1181
|
-
renderProviderBadge,
|
|
1182
|
-
className
|
|
1183
|
-
} = props;
|
|
1184
|
-
const { onModel, onHarness } = useCoherentHandlers(props);
|
|
1185
|
-
const [open, setOpen] = useState5(false);
|
|
1186
|
-
const { containerRef: popoverRef, triggerProps } = usePopover(open, setOpen);
|
|
1187
|
-
const selectedModel = models.find((m) => m.id === model);
|
|
1188
|
-
const showEffort = selectedModel?.supportsReasoning ?? true;
|
|
1189
|
-
const modelPicker = /* @__PURE__ */ jsx7(
|
|
1190
|
-
ModelPicker,
|
|
1191
|
-
{
|
|
1192
|
-
value: model,
|
|
1193
|
-
onChange: onModel,
|
|
1194
|
-
models,
|
|
1195
|
-
loading: modelsLoading,
|
|
1196
|
-
renderProviderBadge
|
|
1197
|
-
}
|
|
1198
|
-
);
|
|
1199
|
-
if (layout === "inline") {
|
|
1200
|
-
return /* @__PURE__ */ jsxs6("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
1201
|
-
modelPicker,
|
|
1202
|
-
showHarness && /* @__PURE__ */ jsx7(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
1203
|
-
showEffort && /* @__PURE__ */ jsx7(EffortPicker, { value: effort, onChange: onEffortChange })
|
|
1204
|
-
] });
|
|
1205
|
-
}
|
|
1206
|
-
const hasAdvanced = showHarness || showEffort;
|
|
1207
|
-
return /* @__PURE__ */ jsxs6("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
1208
|
-
modelPicker,
|
|
1209
|
-
hasAdvanced && /* @__PURE__ */ jsxs6("div", { ref: popoverRef, className: "relative inline-flex", children: [
|
|
1210
|
-
/* @__PURE__ */ jsx7(
|
|
1211
|
-
"button",
|
|
1212
|
-
{
|
|
1213
|
-
type: "button",
|
|
1214
|
-
...triggerProps,
|
|
1215
|
-
onClick: () => setOpen(!open),
|
|
1216
|
-
title: "Model settings \u2014 pick the agent backend and how hard it thinks",
|
|
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}`,
|
|
1218
|
-
"data-state": open ? "open" : "closed",
|
|
1219
|
-
children: /* @__PURE__ */ jsx7(GearGlyph, { className: "h-4 w-4" })
|
|
1220
|
-
}
|
|
1221
|
-
),
|
|
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: [
|
|
1223
|
-
showHarness && /* @__PURE__ */ jsxs6("div", { className: "space-y-1.5", children: [
|
|
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." })
|
|
1227
|
-
] }),
|
|
1228
|
-
showEffort && /* @__PURE__ */ jsxs6("div", { className: "space-y-1.5", children: [
|
|
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." })
|
|
1232
|
-
] })
|
|
1233
|
-
] })
|
|
1234
|
-
] })
|
|
1235
|
-
] });
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
// src/web-react/index.tsx
|
|
1239
|
-
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1240
|
-
function formatModelCost(msg, models) {
|
|
1241
|
-
if (msg.promptTokens == null && msg.completionTokens == null) return null;
|
|
1242
|
-
const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing;
|
|
1243
|
-
if (!pricing) return null;
|
|
1244
|
-
const cost = (msg.promptTokens ?? 0) * Number(pricing.prompt ?? 0) + (msg.completionTokens ?? 0) * Number(pricing.completion ?? 0);
|
|
1245
|
-
if (!isFinite(cost) || cost <= 0) return null;
|
|
1246
|
-
return cost < 0.01 ? `$${cost.toFixed(4)}` : `$${cost.toFixed(2)}`;
|
|
1247
|
-
}
|
|
1248
|
-
function formatTokensPerSecond(msg) {
|
|
1249
|
-
if (msg.completionTokens == null || !msg.durationMs) return null;
|
|
1250
|
-
return `${Math.round(msg.completionTokens / (msg.durationMs / 1e3))} tok/s`;
|
|
1251
|
-
}
|
|
1252
|
-
function RunDrillIn({ run, onClose }) {
|
|
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: [
|
|
1254
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
|
|
1255
|
-
/* @__PURE__ */ jsx8(
|
|
1256
|
-
"span",
|
|
1257
|
-
{
|
|
1258
|
-
className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-warning" : run.status === "error" ? "bg-destructive" : "bg-success"}`
|
|
1259
|
-
}
|
|
1260
|
-
),
|
|
1261
|
-
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
|
|
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 })
|
|
1264
|
-
] }),
|
|
1265
|
-
/* @__PURE__ */ jsx8(
|
|
1266
|
-
"button",
|
|
1267
|
-
{
|
|
1268
|
-
type: "button",
|
|
1269
|
-
onClick: onClose,
|
|
1270
|
-
"aria-label": "Close",
|
|
1271
|
-
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground",
|
|
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" }) })
|
|
1273
|
-
}
|
|
1274
|
-
)
|
|
1275
|
-
] }),
|
|
1276
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
|
|
1277
|
-
run.steps.length === 0 && /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
|
|
1278
|
-
run.steps.map((step, i) => /* @__PURE__ */ jsxs7("div", { className: "rounded-lg border border-border/60 bg-background", children: [
|
|
1279
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
|
|
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() })
|
|
1283
|
-
] }),
|
|
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 })
|
|
1285
|
-
] }, i))
|
|
1286
|
-
] }),
|
|
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." })
|
|
1288
|
-
] });
|
|
1289
|
-
}
|
|
1290
|
-
function pendingApprovalOf(call) {
|
|
1291
|
-
const outcome = call.result;
|
|
1292
|
-
if (!outcome?.ok || outcome.result?.status !== "queued_for_approval" || !outcome.result.proposalId) return null;
|
|
1293
|
-
return { proposalId: outcome.result.proposalId };
|
|
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
|
-
}
|
|
1321
|
-
function ToolGlyph({ name, className }) {
|
|
1322
|
-
if (name.startsWith("sandbox_")) {
|
|
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: [
|
|
1324
|
-
/* @__PURE__ */ jsx8("polyline", { points: "4 17 10 11 4 5" }),
|
|
1325
|
-
/* @__PURE__ */ jsx8("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
|
|
1326
|
-
] });
|
|
1327
|
-
}
|
|
1328
|
-
if (name === "submit_proposal") {
|
|
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: [
|
|
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" })
|
|
1332
|
-
] });
|
|
1333
|
-
}
|
|
1334
|
-
if (name === "schedule_followup") {
|
|
1335
|
-
return /* @__PURE__ */ jsxs7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
|
|
1336
|
-
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "9" }),
|
|
1337
|
-
/* @__PURE__ */ jsx8("path", { d: "M12 7v5l3 3" })
|
|
1338
|
-
] });
|
|
1339
|
-
}
|
|
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: [
|
|
1341
|
-
/* @__PURE__ */ jsx8("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
|
|
1342
|
-
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "4" })
|
|
1343
|
-
] });
|
|
1344
|
-
}
|
|
1345
|
-
function toolOutcomeOf(call) {
|
|
1346
|
-
return call.result;
|
|
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
|
-
}
|
|
1354
|
-
function humanizeToolName(name) {
|
|
1355
|
-
const words = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
|
|
1356
|
-
if (!words) return name;
|
|
1357
|
-
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
1358
|
-
}
|
|
1359
|
-
function friendlyToolTitle(call) {
|
|
1360
|
-
const a = call.args ?? {};
|
|
1361
|
-
switch (call.name) {
|
|
1362
|
-
case "submit_proposal":
|
|
1363
|
-
return a.title ? `Approve: ${String(a.title)}?` : "Approve this action?";
|
|
1364
|
-
case "sandbox_create":
|
|
1365
|
-
return `Created sandbox (${String(a.environment ?? "universal")})`;
|
|
1366
|
-
case "sandbox_run_command":
|
|
1367
|
-
return `Ran ${String(a.command ?? "command")}`;
|
|
1368
|
-
case "sandbox_destroy":
|
|
1369
|
-
return `Destroyed sandbox ${String(a.sandbox_id ?? "")}`;
|
|
1370
|
-
case "schedule_followup":
|
|
1371
|
-
return `Scheduled: ${String(a.title ?? "follow-up")}`;
|
|
1372
|
-
case "render_ui":
|
|
1373
|
-
return `Rendered view \xB7 ${String(a.title ?? "")}`;
|
|
1374
|
-
case "add_citation":
|
|
1375
|
-
return `Cited ${String(a.path ?? "")}`;
|
|
1376
|
-
default:
|
|
1377
|
-
return humanizeToolName(call.name);
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
function proposalPreview(call) {
|
|
1381
|
-
const a = call.args ?? {};
|
|
1382
|
-
const asString = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
|
|
1383
|
-
const asList = (v) => Array.isArray(v) ? v.map((x) => typeof x === "string" ? x : null).filter((x) => !!x) : asString(v) ? [asString(v)] : [];
|
|
1384
|
-
const verbPhrase = asString(a.summary) ?? asString(a.description) ?? (asString(a.type) ? `${String(a.type).replace(/_/g, " ")}${asString(a.title) ? `: ${asString(a.title)}` : ""}` : null);
|
|
1385
|
-
const destinations = [
|
|
1386
|
-
...asList(a.destinations),
|
|
1387
|
-
...asList(a.channels),
|
|
1388
|
-
...asList(a.targets),
|
|
1389
|
-
...asList(a.platforms)
|
|
1390
|
-
];
|
|
1391
|
-
const dest = destinations.length ? ` to ${destinations.join(" and ")}` : "";
|
|
1392
|
-
const summary = verbPhrase ? `${verbPhrase}${dest}` : destinations.length ? `Publish to ${destinations.join(" and ")}` : null;
|
|
1393
|
-
const meta = [];
|
|
1394
|
-
const cost = a.cost ?? a.price ?? a.estimatedCost;
|
|
1395
|
-
if (typeof cost === "number" && cost > 0) meta.push(`~$${cost < 0.01 ? cost.toFixed(4) : cost.toFixed(2)}`);
|
|
1396
|
-
else if (asString(cost)) meta.push(asString(cost));
|
|
1397
|
-
const reach = a.reach ?? a.audience ?? a.estimatedReach;
|
|
1398
|
-
if (typeof reach === "number" && reach > 0) meta.push(`reaches ~${reach.toLocaleString()}`);
|
|
1399
|
-
else if (asString(reach)) meta.push(asString(reach));
|
|
1400
|
-
return { summary, meta };
|
|
1401
|
-
}
|
|
1402
|
-
function truncate(v, max = 240) {
|
|
1403
|
-
const s = typeof v === "string" ? v : JSON.stringify(v);
|
|
1404
|
-
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
1405
|
-
}
|
|
1406
|
-
function KvRows({ data }) {
|
|
1407
|
-
const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
|
|
1408
|
-
if (!entries.length) return null;
|
|
1409
|
-
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: [
|
|
1410
|
-
/* @__PURE__ */ jsx8("dt", { className: "font-mono text-[11px] text-muted-foreground", children: k }),
|
|
1411
|
-
/* @__PURE__ */ jsx8("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
|
|
1412
|
-
] }, k)) });
|
|
1413
|
-
}
|
|
1414
|
-
function ShellDetail({ call }) {
|
|
1415
|
-
const outcome = toolOutcomeOf(call);
|
|
1416
|
-
const r = outcome?.result ?? {};
|
|
1417
|
-
return /* @__PURE__ */ jsxs7("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
|
|
1418
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
|
|
1419
|
-
/* @__PURE__ */ jsx8("span", { className: "select-none text-zinc-500", children: "$" }),
|
|
1420
|
-
/* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
|
|
1421
|
-
r.exitCode != null && /* @__PURE__ */ jsxs7("span", { className: r.exitCode === 0 ? "text-success" : "text-destructive", children: [
|
|
1422
|
-
"exit ",
|
|
1423
|
-
r.exitCode
|
|
1424
|
-
] })
|
|
1425
|
-
] }),
|
|
1426
|
-
/* @__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)" })
|
|
1427
|
-
] });
|
|
1428
|
-
}
|
|
1429
|
-
function DefaultToolDetail({ call }) {
|
|
1430
|
-
const outcome = toolOutcomeOf(call);
|
|
1431
|
-
return /* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1432
|
-
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs7("div", { children: [
|
|
1433
|
-
/* @__PURE__ */ jsx8("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: "Called with" }),
|
|
1434
|
-
/* @__PURE__ */ jsx8(KvRows, { data: call.args })
|
|
1435
|
-
] }),
|
|
1436
|
-
outcome && /* @__PURE__ */ jsxs7("div", { children: [
|
|
1437
|
-
/* @__PURE__ */ jsx8("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: outcome.ok === false ? "Failed" : "Result" }),
|
|
1438
|
-
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) })
|
|
1439
|
-
] })
|
|
1440
|
-
] });
|
|
1441
|
-
}
|
|
1442
|
-
function ProposalCard({
|
|
1443
|
-
call,
|
|
1444
|
-
message,
|
|
1445
|
-
pending,
|
|
1446
|
-
approval,
|
|
1447
|
-
renderers
|
|
1448
|
-
}) {
|
|
1449
|
-
const [expanded, setExpanded] = useState6(false);
|
|
1450
|
-
const { summary, meta } = proposalPreview(call);
|
|
1451
|
-
const custom = renderers?.[call.name]?.(call, message);
|
|
1452
|
-
const { pending: deciding, run: decide } = usePending();
|
|
1453
|
-
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: [
|
|
1454
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex items-start gap-2.5 px-4 pt-3.5", children: [
|
|
1455
|
-
/* @__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" }) }),
|
|
1456
|
-
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
|
|
1457
|
-
/* @__PURE__ */ jsx8("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-warning-foreground", children: "Needs your approval" }),
|
|
1458
|
-
/* @__PURE__ */ jsx8("p", { className: "mt-0.5 text-[15px] font-semibold leading-snug text-foreground", children: friendlyToolTitle(call) }),
|
|
1459
|
-
summary && /* @__PURE__ */ jsx8("p", { className: "mt-1 text-[13px] leading-relaxed text-muted-foreground", children: summary }),
|
|
1460
|
-
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)) })
|
|
1461
|
-
] })
|
|
1462
|
-
] }),
|
|
1463
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-2 px-4 pb-3.5 pt-3", children: [
|
|
1464
|
-
approval ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1465
|
-
/* @__PURE__ */ jsx8(
|
|
1466
|
-
"button",
|
|
1467
|
-
{
|
|
1468
|
-
type: "button",
|
|
1469
|
-
disabled: deciding,
|
|
1470
|
-
onClick: () => decide(() => approval.onApprove(pending.proposalId, call.id)),
|
|
1471
|
-
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]",
|
|
1472
|
-
children: "Approve & run"
|
|
1473
|
-
}
|
|
1474
|
-
),
|
|
1475
|
-
/* @__PURE__ */ jsx8(
|
|
1476
|
-
"button",
|
|
1477
|
-
{
|
|
1478
|
-
type: "button",
|
|
1479
|
-
disabled: deciding,
|
|
1480
|
-
onClick: () => decide(() => approval.onReject(pending.proposalId, call.id)),
|
|
1481
|
-
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",
|
|
1482
|
-
children: "Reject"
|
|
1483
|
-
}
|
|
1484
|
-
)
|
|
1485
|
-
] }) : /* @__PURE__ */ jsx8("span", { className: "text-[12px] font-medium text-muted-foreground", children: "Awaiting approval\u2026" }),
|
|
1486
|
-
/* @__PURE__ */ jsxs7(
|
|
1487
|
-
"button",
|
|
1488
|
-
{
|
|
1489
|
-
type: "button",
|
|
1490
|
-
onClick: () => setExpanded((v) => !v),
|
|
1491
|
-
"aria-expanded": expanded,
|
|
1492
|
-
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",
|
|
1493
|
-
children: [
|
|
1494
|
-
expanded ? "Hide details" : "View details",
|
|
1495
|
-
/* @__PURE__ */ jsx8(ChevronDown, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
1496
|
-
]
|
|
1497
|
-
}
|
|
1498
|
-
)
|
|
1499
|
-
] }),
|
|
1500
|
-
expanded && /* @__PURE__ */ jsx8("div", { className: "border-t border-warning/20 px-4 py-3 text-xs", children: custom ?? /* @__PURE__ */ jsx8(DefaultToolDetail, { call }) })
|
|
1501
|
-
] });
|
|
1502
|
-
}
|
|
1503
|
-
function FollowupCard({ call }) {
|
|
1504
|
-
const a = call.args ?? {};
|
|
1505
|
-
const when = typeof a.when === "string" ? a.when : typeof a.at === "string" ? a.at : typeof a.schedule === "string" ? a.schedule : null;
|
|
1506
|
-
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: [
|
|
1507
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
|
|
1508
|
-
/* @__PURE__ */ jsx8(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-primary/80" }),
|
|
1509
|
-
/* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", children: friendlyToolTitle(call) })
|
|
1510
|
-
] }),
|
|
1511
|
-
when && /* @__PURE__ */ jsx8("p", { className: "mt-0.5 pl-[22px] text-[12px] text-muted-foreground", children: when })
|
|
1512
|
-
] });
|
|
1513
|
-
}
|
|
1514
|
-
function ToolCallCard({
|
|
1515
|
-
call,
|
|
1516
|
-
message,
|
|
1517
|
-
approval,
|
|
1518
|
-
onOpenRun,
|
|
1519
|
-
renderers
|
|
1520
|
-
}) {
|
|
1521
|
-
const [expanded, setExpanded] = useState6(false);
|
|
1522
|
-
const pending = call.status === "done" ? pendingApprovalOf(call) : null;
|
|
1523
|
-
const kind = blockKindOf(call);
|
|
1524
|
-
const failed = call.status === "error" || toolOutcomeOf(call)?.ok === false;
|
|
1525
|
-
const custom = renderers?.[call.name]?.(call, message);
|
|
1526
|
-
if (pending) {
|
|
1527
|
-
return /* @__PURE__ */ jsx8(
|
|
1528
|
-
ProposalCard,
|
|
1529
|
-
{
|
|
1530
|
-
call,
|
|
1531
|
-
message,
|
|
1532
|
-
pending,
|
|
1533
|
-
approval,
|
|
1534
|
-
renderers
|
|
1535
|
-
}
|
|
1536
|
-
);
|
|
1537
|
-
}
|
|
1538
|
-
if (kind === "followup" && !failed) {
|
|
1539
|
-
return /* @__PURE__ */ jsx8(FollowupCard, { call });
|
|
1540
|
-
}
|
|
1541
|
-
const isCommand = kind === "command";
|
|
1542
|
-
return /* @__PURE__ */ jsxs7(
|
|
1543
|
-
"div",
|
|
1544
|
-
{
|
|
1545
|
-
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"}`,
|
|
1546
|
-
children: [
|
|
1547
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex w-full items-center gap-2 px-3 py-2", children: [
|
|
1548
|
-
/* @__PURE__ */ jsxs7(
|
|
1549
|
-
"button",
|
|
1550
|
-
{
|
|
1551
|
-
type: "button",
|
|
1552
|
-
onClick: () => setExpanded((v) => !v),
|
|
1553
|
-
"aria-expanded": expanded,
|
|
1554
|
-
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",
|
|
1555
|
-
children: [
|
|
1556
|
-
/* @__PURE__ */ jsx8(
|
|
1557
|
-
"span",
|
|
1558
|
-
{
|
|
1559
|
-
className: `h-2 w-2 shrink-0 rounded-full ${call.status === "running" ? "animate-pulse bg-warning" : failed ? "bg-destructive" : "bg-success"}`
|
|
1560
|
-
}
|
|
1561
|
-
),
|
|
1562
|
-
/* @__PURE__ */ jsx8(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
1563
|
-
/* @__PURE__ */ jsx8(
|
|
1564
|
-
"span",
|
|
1565
|
-
{
|
|
1566
|
-
className: `min-w-0 flex-1 truncate ${isCommand ? "font-mono text-[12px] tracking-tight text-foreground/90" : "font-medium"}`,
|
|
1567
|
-
children: friendlyToolTitle(call)
|
|
1568
|
-
}
|
|
1569
|
-
)
|
|
1570
|
-
]
|
|
1571
|
-
}
|
|
1572
|
-
),
|
|
1573
|
-
/* @__PURE__ */ jsx8("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: call.status === "running" ? "running\u2026" : failed ? "failed" : "done" }),
|
|
1574
|
-
/* @__PURE__ */ jsx8(
|
|
1575
|
-
"button",
|
|
1576
|
-
{
|
|
1577
|
-
type: "button",
|
|
1578
|
-
onClick: () => setExpanded((v) => !v),
|
|
1579
|
-
"aria-label": expanded ? "Collapse details" : "Expand details",
|
|
1580
|
-
"aria-expanded": expanded,
|
|
1581
|
-
className: "shrink-0 rounded p-0.5 focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1582
|
-
children: /* @__PURE__ */ jsx8(ChevronDown, { className: `h-3 w-3 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
1583
|
-
}
|
|
1584
|
-
)
|
|
1585
|
-
] }),
|
|
1586
|
-
expanded && /* @__PURE__ */ jsxs7("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
|
|
1587
|
-
custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx8(ShellDetail, { call }) : /* @__PURE__ */ jsx8(DefaultToolDetail, { call })),
|
|
1588
|
-
onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx8(
|
|
1589
|
-
"button",
|
|
1590
|
-
{
|
|
1591
|
-
type: "button",
|
|
1592
|
-
onClick: () => onOpenRun(call, message),
|
|
1593
|
-
className: "mt-2 rounded border border-border bg-card px-2 py-1 text-[11px] font-medium transition hover:bg-accent/30",
|
|
1594
|
-
children: "Open full transcript \u2192"
|
|
1595
|
-
}
|
|
1596
|
-
)
|
|
1597
|
-
] })
|
|
1598
|
-
]
|
|
1599
|
-
}
|
|
1600
|
-
);
|
|
1601
|
-
}
|
|
1602
|
-
function StreamingCaret() {
|
|
1603
|
-
return /* @__PURE__ */ jsx8(
|
|
1604
|
-
"span",
|
|
1605
|
-
{
|
|
1606
|
-
className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70",
|
|
1607
|
-
"aria-hidden": true
|
|
1608
|
-
}
|
|
1609
|
-
);
|
|
1610
|
-
}
|
|
1611
|
-
function SegmentText({
|
|
1612
|
-
content,
|
|
1613
|
-
streaming,
|
|
1614
|
-
showCaret,
|
|
1615
|
-
renderBody
|
|
1616
|
-
}) {
|
|
1617
|
-
const text = useSmoothText(content, streaming);
|
|
1618
|
-
const body = useMemo3(() => renderBody(text), [renderBody, text]);
|
|
1619
|
-
if (!content.trim() && !showCaret) return null;
|
|
1620
|
-
return /* @__PURE__ */ jsxs7("div", { className: "text-base leading-[1.75]", children: [
|
|
1621
|
-
body,
|
|
1622
|
-
showCaret && /* @__PURE__ */ jsx8(StreamingCaret, {})
|
|
1623
|
-
] });
|
|
1624
|
-
}
|
|
1625
|
-
function SegmentedBody({
|
|
1626
|
-
segments,
|
|
1627
|
-
msg,
|
|
1628
|
-
streaming,
|
|
1629
|
-
renderBody,
|
|
1630
|
-
approval,
|
|
1631
|
-
onToolCallClick,
|
|
1632
|
-
toolRenderers
|
|
1633
|
-
}) {
|
|
1634
|
-
const lastIndex = segments.length - 1;
|
|
1635
|
-
const segmentToolIds = new Set(
|
|
1636
|
-
segments.flatMap((s) => s.kind === "tool" ? [s.call.id] : [])
|
|
1637
|
-
);
|
|
1638
|
-
const leftoverToolCalls = (msg.toolCalls ?? []).filter(
|
|
1639
|
-
(tc) => !segmentToolIds.has(tc.id)
|
|
1640
|
-
);
|
|
1641
|
-
const renderToolCard = (call) => /* @__PURE__ */ jsx8(
|
|
1642
|
-
ToolCallCard,
|
|
1643
|
-
{
|
|
1644
|
-
call,
|
|
1645
|
-
message: msg,
|
|
1646
|
-
approval,
|
|
1647
|
-
onOpenRun: onToolCallClick,
|
|
1648
|
-
renderers: toolRenderers
|
|
1649
|
-
},
|
|
1650
|
-
`tool-${call.id}`
|
|
1651
|
-
);
|
|
1652
|
-
return /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-2", children: [
|
|
1653
|
-
segments.map(
|
|
1654
|
-
(seg, i) => seg.kind === "text" ? /* @__PURE__ */ jsx8(
|
|
1655
|
-
SegmentText,
|
|
1656
|
-
{
|
|
1657
|
-
content: seg.content,
|
|
1658
|
-
streaming: streaming && i === lastIndex,
|
|
1659
|
-
showCaret: streaming && i === lastIndex,
|
|
1660
|
-
renderBody
|
|
1661
|
-
},
|
|
1662
|
-
`text-${i}`
|
|
1663
|
-
) : renderToolCard(seg.call)
|
|
1664
|
-
),
|
|
1665
|
-
leftoverToolCalls.map(renderToolCard),
|
|
1666
|
-
streaming && segments[lastIndex]?.kind === "tool" && /* @__PURE__ */ jsx8(StreamingCaret, {})
|
|
1667
|
-
] });
|
|
1668
|
-
}
|
|
1669
|
-
function AssistantMessageImpl({
|
|
1670
|
-
msg,
|
|
1671
|
-
streaming,
|
|
1672
|
-
models,
|
|
1673
|
-
agentLabel,
|
|
1674
|
-
renderBody,
|
|
1675
|
-
approval,
|
|
1676
|
-
onToolCallClick,
|
|
1677
|
-
toolRenderers,
|
|
1678
|
-
renderExtras
|
|
1679
|
-
}) {
|
|
1680
|
-
const content = useSmoothText(msg.content, streaming);
|
|
1681
|
-
const reasoning = useSmoothText(msg.reasoning ?? "", streaming);
|
|
1682
|
-
const body = useMemo3(() => renderBody(content), [renderBody, content]);
|
|
1683
|
-
const segments = msg.segments;
|
|
1684
|
-
const hasAnswerText = content !== "" || (segments?.some((s) => s.kind === "text" && s.content.trim() !== "") ?? false);
|
|
1685
|
-
const reasoningScrollRef = useRef4(null);
|
|
1686
|
-
const thinkStartRef = useRef4(null);
|
|
1687
|
-
const thinkMsRef = useRef4(null);
|
|
1688
|
-
if (streaming && reasoning && !hasAnswerText && thinkStartRef.current === null) {
|
|
1689
|
-
thinkStartRef.current = performance.now();
|
|
1690
|
-
}
|
|
1691
|
-
if (hasAnswerText && thinkStartRef.current !== null && thinkMsRef.current === null) {
|
|
1692
|
-
thinkMsRef.current = performance.now() - thinkStartRef.current;
|
|
1693
|
-
}
|
|
1694
|
-
useEffect5(() => {
|
|
1695
|
-
const el = reasoningScrollRef.current;
|
|
1696
|
-
if (el && streaming && !hasAnswerText) el.scrollTop = el.scrollHeight;
|
|
1697
|
-
}, [reasoning, streaming, hasAnswerText]);
|
|
1698
|
-
const thinkingSeconds = useThinkingSeconds(
|
|
1699
|
-
streaming && !!reasoning && !hasAnswerText
|
|
1700
|
-
);
|
|
1701
|
-
return /* @__PURE__ */ jsxs7("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
1702
|
-
/* @__PURE__ */ jsxs7("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground", children: [
|
|
1703
|
-
/* @__PURE__ */ jsx8("span", { className: "font-semibold uppercase", children: agentLabel }),
|
|
1704
|
-
msg.modelUsed && /* @__PURE__ */ jsx8("span", { className: "font-mono normal-case", children: msg.modelUsed }),
|
|
1705
|
-
formatTokensPerSecond(msg) && /* @__PURE__ */ jsx8("span", { children: formatTokensPerSecond(msg) }),
|
|
1706
|
-
formatModelCost(msg, models) && /* @__PURE__ */ jsx8("span", { children: formatModelCost(msg, models) })
|
|
1707
|
-
] }),
|
|
1708
|
-
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: [
|
|
1709
|
-
/* @__PURE__ */ jsx8("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !hasAnswerText ? /* @__PURE__ */ jsxs7("span", { className: "animate-pulse", children: [
|
|
1710
|
-
"Thinking",
|
|
1711
|
-
thinkingSeconds >= 3 ? ` \xB7 ${thinkingSeconds}s` : "\u2026"
|
|
1712
|
-
] }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
|
|
1713
|
-
/* @__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 })
|
|
1714
|
-
] }),
|
|
1715
|
-
segments && segments.length > 0 ? /* @__PURE__ */ jsx8(
|
|
1716
|
-
SegmentedBody,
|
|
1717
|
-
{
|
|
1718
|
-
segments,
|
|
1719
|
-
msg,
|
|
1720
|
-
streaming,
|
|
1721
|
-
renderBody,
|
|
1722
|
-
approval,
|
|
1723
|
-
onToolCallClick,
|
|
1724
|
-
toolRenderers
|
|
1725
|
-
}
|
|
1726
|
-
) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1727
|
-
/* @__PURE__ */ jsxs7("div", { className: "text-base leading-[1.75]", children: [
|
|
1728
|
-
body,
|
|
1729
|
-
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx8(StreamingCaret, {})
|
|
1730
|
-
] }),
|
|
1731
|
-
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(
|
|
1732
|
-
ToolCallCard,
|
|
1733
|
-
{
|
|
1734
|
-
call: tc,
|
|
1735
|
-
message: msg,
|
|
1736
|
-
approval,
|
|
1737
|
-
onOpenRun: onToolCallClick,
|
|
1738
|
-
renderers: toolRenderers
|
|
1739
|
-
},
|
|
1740
|
-
tc.id
|
|
1741
|
-
)) })
|
|
1742
|
-
] }),
|
|
1743
|
-
renderExtras?.(msg)
|
|
1744
|
-
] });
|
|
1745
|
-
}
|
|
1746
|
-
var AssistantMessage = memo(AssistantMessageImpl);
|
|
1747
|
-
function useThinkingSeconds(active) {
|
|
1748
|
-
const [seconds, setSeconds] = useState6(0);
|
|
1749
|
-
useEffect5(() => {
|
|
1750
|
-
if (!active) return;
|
|
1751
|
-
setSeconds(0);
|
|
1752
|
-
const id = setInterval(() => setSeconds((s) => s + 1), 1e3);
|
|
1753
|
-
return () => clearInterval(id);
|
|
1754
|
-
}, [active]);
|
|
1755
|
-
return seconds;
|
|
1756
|
-
}
|
|
1757
|
-
function ThinkingRow({ agentLabel }) {
|
|
1758
|
-
const seconds = useThinkingSeconds(true);
|
|
1759
|
-
return /* @__PURE__ */ jsxs7("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
1760
|
-
/* @__PURE__ */ jsx8("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: agentLabel }),
|
|
1761
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
|
|
1762
|
-
/* @__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" }) }),
|
|
1763
|
-
"Thinking",
|
|
1764
|
-
seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
|
|
1765
|
-
] })
|
|
1766
|
-
] });
|
|
1767
|
-
}
|
|
1768
|
-
function StreamErrorRow({ message, onRetry }) {
|
|
1769
|
-
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: [
|
|
1770
|
-
/* @__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: [
|
|
1771
|
-
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "9" }),
|
|
1772
|
-
/* @__PURE__ */ jsx8("path", { d: "M12 8v4m0 4h.01" })
|
|
1773
|
-
] }),
|
|
1774
|
-
/* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 break-words", children: message }),
|
|
1775
|
-
onRetry && /* @__PURE__ */ jsx8(
|
|
1776
|
-
"button",
|
|
1777
|
-
{
|
|
1778
|
-
type: "button",
|
|
1779
|
-
onClick: onRetry,
|
|
1780
|
-
className: `shrink-0 rounded border border-destructive/40 bg-card px-2 py-0.5 text-[11px] font-medium text-destructive transition hover:bg-destructive/10 ${POPOVER_OPTION_FOCUS}`,
|
|
1781
|
-
children: "Retry"
|
|
1782
|
-
}
|
|
1783
|
-
)
|
|
1784
|
-
] }) });
|
|
1785
|
-
}
|
|
1786
|
-
function ChatMessages({
|
|
1787
|
-
messages,
|
|
1788
|
-
models = [],
|
|
1789
|
-
renderMarkdown,
|
|
1790
|
-
renderExtras,
|
|
1791
|
-
userLabel = "User",
|
|
1792
|
-
agentLabel = "Agent",
|
|
1793
|
-
loading,
|
|
1794
|
-
approval,
|
|
1795
|
-
onToolCallClick,
|
|
1796
|
-
toolRenderers,
|
|
1797
|
-
error,
|
|
1798
|
-
onRetry,
|
|
1799
|
-
renderEmpty,
|
|
1800
|
-
emptyState,
|
|
1801
|
-
header
|
|
1802
|
-
}) {
|
|
1803
|
-
const renderBody = useMemo3(
|
|
1804
|
-
() => renderMarkdown ?? ((content) => /* @__PURE__ */ jsx8("p", { className: "whitespace-pre-wrap", children: content })),
|
|
1805
|
-
[renderMarkdown]
|
|
1806
|
-
);
|
|
1807
|
-
const lastIsUser = messages[messages.length - 1]?.role === "user";
|
|
1808
|
-
if (messages.length === 0 && !loading && !error) {
|
|
1809
|
-
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */ jsx8(ChatEmptyState, { ...emptyState });
|
|
1810
|
-
return /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1811
|
-
header,
|
|
1812
|
-
empty
|
|
1813
|
-
] });
|
|
1814
|
-
}
|
|
1815
|
-
return /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1816
|
-
header,
|
|
1817
|
-
messages.map(
|
|
1818
|
-
(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: [
|
|
1819
|
-
/* @__PURE__ */ jsx8("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: userLabel }),
|
|
1820
|
-
/* @__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 }) })
|
|
1821
|
-
] }) }, msg.id) : /* @__PURE__ */ jsx8(
|
|
1822
|
-
AssistantMessage,
|
|
1823
|
-
{
|
|
1824
|
-
msg,
|
|
1825
|
-
streaming: !!loading && msg.id === messages[messages.length - 1]?.id,
|
|
1826
|
-
models,
|
|
1827
|
-
agentLabel,
|
|
1828
|
-
renderBody,
|
|
1829
|
-
approval,
|
|
1830
|
-
onToolCallClick,
|
|
1831
|
-
toolRenderers,
|
|
1832
|
-
renderExtras
|
|
1833
|
-
},
|
|
1834
|
-
msg.id
|
|
1835
|
-
)
|
|
1836
|
-
),
|
|
1837
|
-
loading && lastIsUser && /* @__PURE__ */ jsx8(ThinkingRow, { agentLabel }),
|
|
1838
|
-
error && !loading && /* @__PURE__ */ jsx8(StreamErrorRow, { message: error, onRetry })
|
|
1839
|
-
] });
|
|
1840
|
-
}
|
|
2
|
+
AgentActivityPanel,
|
|
3
|
+
AgentSessionControls,
|
|
4
|
+
ChatComposer,
|
|
5
|
+
ChatEmptyState,
|
|
6
|
+
ChatMessages,
|
|
7
|
+
DEFAULT_EFFORT_LEVELS,
|
|
8
|
+
EffortPicker,
|
|
9
|
+
FlowWaterfall,
|
|
10
|
+
MissionActivityLane,
|
|
11
|
+
ModelPicker,
|
|
12
|
+
ProviderLogo,
|
|
13
|
+
RunDrillIn,
|
|
14
|
+
SeatPaywall,
|
|
15
|
+
WorkspaceTerminalPanel,
|
|
16
|
+
activityTone,
|
|
17
|
+
consumeChatStream,
|
|
18
|
+
dispatchChatStreamLine,
|
|
19
|
+
formatActivityCost,
|
|
20
|
+
formatActivityDuration,
|
|
21
|
+
formatModelCost,
|
|
22
|
+
formatTokensPerSecond,
|
|
23
|
+
mergeActivityPages,
|
|
24
|
+
nextRevealCount,
|
|
25
|
+
pendingApprovalOf,
|
|
26
|
+
streamChatTurn,
|
|
27
|
+
tabTerminalConnectionId,
|
|
28
|
+
usePending,
|
|
29
|
+
usePopover,
|
|
30
|
+
useSandboxTerminalConnection,
|
|
31
|
+
useSmoothText,
|
|
32
|
+
useThinkingSeconds,
|
|
33
|
+
waterfallLayout
|
|
34
|
+
} from "../chunk-WV2U5UIB.js";
|
|
35
|
+
import "../chunk-2QI7XV2T.js";
|
|
36
|
+
import "../chunk-E7QYOOON.js";
|
|
1841
37
|
export {
|
|
1842
38
|
AgentActivityPanel,
|
|
1843
39
|
AgentSessionControls,
|
|
40
|
+
ChatComposer,
|
|
1844
41
|
ChatEmptyState,
|
|
1845
42
|
ChatMessages,
|
|
1846
43
|
DEFAULT_EFFORT_LEVELS,
|