@tangle-network/agent-app 0.10.1 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,9 @@
1
+ import {
2
+ stepActivityFlowTrace
3
+ } from "../chunk-AFDROJ64.js";
4
+
1
5
  // src/web-react/index.tsx
2
- import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
6
+ import { useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState3 } from "react";
3
7
 
4
8
  // src/web-react/provider-logo.tsx
5
9
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -206,23 +210,264 @@ async function streamChatTurn(opts) {
206
210
  }
207
211
  }
208
212
 
209
- // src/web-react/index.tsx
213
+ // src/web-react/mission-activity.tsx
214
+ import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
210
215
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
211
- function ChevronDown({ className }) {
216
+ var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "running"]);
217
+ var OK_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "succeeded"]);
218
+ var ERROR_STATUSES = /* @__PURE__ */ new Set(["failed", "error", "cancelled", "aborted"]);
219
+ function activityTone(status) {
220
+ const s = status.toLowerCase();
221
+ if (LIVE_STATUSES.has(s)) return "live";
222
+ if (OK_STATUSES.has(s)) return "ok";
223
+ if (ERROR_STATUSES.has(s)) return "error";
224
+ return "neutral";
225
+ }
226
+ function formatActivityCost(costUsd) {
227
+ if (costUsd === void 0 || !isFinite(costUsd) || costUsd <= 0) return null;
228
+ return costUsd < 0.01 ? `$${costUsd.toFixed(4)}` : `$${costUsd.toFixed(2)}`;
229
+ }
230
+ function formatActivityDuration(durationMs) {
231
+ if (durationMs === void 0 || !isFinite(durationMs) || durationMs < 0) return null;
232
+ const totalSeconds = Math.round(durationMs / 1e3);
233
+ if (totalSeconds < 60) return `${totalSeconds}s`;
234
+ const minutes = Math.floor(totalSeconds / 60);
235
+ const seconds = totalSeconds % 60;
236
+ if (minutes < 60) return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
237
+ return `${Math.floor(minutes / 60)}h ${String(minutes % 60).padStart(2, "0")}m`;
238
+ }
239
+ function mergeActivityPages(existing, incoming) {
240
+ const byTask = /* @__PURE__ */ new Map();
241
+ for (const row of existing) byTask.set(row.taskId, row);
242
+ for (const row of incoming) byTask.set(row.taskId, row);
243
+ return [...byTask.values()].sort((a, b) => Date.parse(b.startedAt) - Date.parse(a.startedAt));
244
+ }
245
+ function waterfallLayout(trace) {
246
+ const total = trace.totalMs > 0 ? trace.totalMs : 1;
247
+ return [...trace.spans].sort((a, b) => a.startMs - b.startMs).map((span) => {
248
+ const meta = span.meta ?? {};
249
+ const failed = meta.ok === false || typeof meta.status === "string" && activityTone(meta.status) === "error";
250
+ return {
251
+ name: span.name,
252
+ kind: span.kind,
253
+ offsetPct: Math.max(0, Math.min(100, span.startMs / total * 100)),
254
+ widthPct: Math.max(0.5, Math.min(100, (span.endMs - span.startMs) / total * 100)),
255
+ durationLabel: `${((span.endMs - span.startMs) / 1e3).toFixed(1)}s${span.approx ? "~" : ""}`,
256
+ approx: span.approx === true,
257
+ ok: !failed
258
+ };
259
+ });
260
+ }
261
+ function ChevronGlyph({ className }) {
212
262
  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" }) });
213
263
  }
264
+ function RefreshGlyph({ className }) {
265
+ 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: "M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6" }) });
266
+ }
267
+ function StatusDot({ tone }) {
268
+ return /* @__PURE__ */ jsx2(
269
+ "span",
270
+ {
271
+ className: `h-2 w-2 shrink-0 rounded-full ${tone === "live" ? "animate-pulse bg-yellow-500" : tone === "ok" ? "bg-green-500" : tone === "error" ? "bg-red-500" : "bg-muted-foreground/40"}`
272
+ }
273
+ );
274
+ }
275
+ var BAR_CLASS = {
276
+ pipeline: "bg-muted-foreground/30",
277
+ model: "bg-primary/60",
278
+ tool: "bg-primary"
279
+ };
280
+ function FlowWaterfall({ trace }) {
281
+ const rows = waterfallLayout(trace);
282
+ if (rows.length === 0) return null;
283
+ const cost = formatActivityCost(trace.costUsd);
284
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
285
+ rows.map((row, i) => /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-[minmax(0,2fr)_minmax(0,3fr)_auto] items-center gap-2", children: [
286
+ /* @__PURE__ */ jsx2("span", { className: "truncate font-mono text-[11px] text-muted-foreground", title: row.name, children: row.name }),
287
+ /* @__PURE__ */ jsx2("div", { className: "relative h-2 rounded-sm bg-muted/40", children: /* @__PURE__ */ jsx2(
288
+ "div",
289
+ {
290
+ className: `absolute inset-y-0 rounded-sm ${row.ok ? BAR_CLASS[row.kind] : "bg-red-500/80"} ${row.approx ? "opacity-70" : ""}`,
291
+ style: { left: `${row.offsetPct}%`, width: `${row.widthPct}%` }
292
+ }
293
+ ) }),
294
+ /* @__PURE__ */ jsx2("span", { className: "shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: row.durationLabel })
295
+ ] }, i)),
296
+ /* @__PURE__ */ jsxs2("p", { className: "pt-0.5 text-right font-mono text-[10px] tabular-nums text-muted-foreground/60", children: [
297
+ (trace.totalMs / 1e3).toFixed(1),
298
+ "s",
299
+ cost ? ` \xB7 ${cost}` : ""
300
+ ] })
301
+ ] });
302
+ }
303
+ function MissionActivityLane({ activity, startedAt, nowMs }) {
304
+ const [expanded, setExpanded] = useState2(false);
305
+ if (activity.length === 0) return null;
306
+ return /* @__PURE__ */ jsxs2("div", { className: "mt-1 border-l border-border/50 pl-3", children: [
307
+ activity.map((run) => {
308
+ const tone = activityTone(run.status);
309
+ const cost = formatActivityCost(run.costUsd);
310
+ const duration = formatActivityDuration(run.durationMs);
311
+ return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
312
+ /* @__PURE__ */ jsx2(StatusDot, { tone }),
313
+ /* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1 truncate", children: [
314
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: run.tool }),
315
+ /* @__PURE__ */ jsxs2("span", { className: "text-muted-foreground", children: [
316
+ " \u2014 ",
317
+ run.detail
318
+ ] })
319
+ ] }),
320
+ tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */ jsx2("span", { className: "shrink-0 rounded-full bg-yellow-500/10 px-1.5 py-0.5 font-mono text-[10px] text-yellow-700 dark:text-yellow-400", children: [run.iteration !== void 0 ? `iter ${run.iteration}` : null, run.phase ?? null].filter(Boolean).join(" \xB7 ") }),
321
+ /* @__PURE__ */ jsxs2("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: [
322
+ tone !== "live" && tone !== "ok" && /* @__PURE__ */ jsx2("span", { children: run.status }),
323
+ cost && /* @__PURE__ */ jsx2("span", { children: cost }),
324
+ duration && /* @__PURE__ */ jsx2("span", { children: duration })
325
+ ] })
326
+ ] }, run.taskId);
327
+ }),
328
+ /* @__PURE__ */ jsxs2(
329
+ "button",
330
+ {
331
+ type: "button",
332
+ onClick: () => setExpanded((v) => !v),
333
+ className: "flex items-center gap-1 py-0.5 text-[10px] font-medium text-muted-foreground/70 transition hover:text-foreground",
334
+ children: [
335
+ /* @__PURE__ */ jsx2(ChevronGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
336
+ "timeline"
337
+ ]
338
+ }
339
+ ),
340
+ expanded && /* @__PURE__ */ jsx2("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx2(
341
+ FlowWaterfall,
342
+ {
343
+ trace: stepActivityFlowTrace(activity, {
344
+ ...startedAt !== void 0 ? { startedAt } : {},
345
+ ...nowMs !== void 0 ? { nowMs } : {}
346
+ })
347
+ }
348
+ ) })
349
+ ] });
350
+ }
351
+ function ActivityRow({
352
+ record,
353
+ renderMissionRef
354
+ }) {
355
+ const [open, setOpen] = useState2(false);
356
+ const tone = activityTone(record.status);
357
+ const cost = formatActivityCost(record.costUsd);
358
+ const duration = formatActivityDuration(record.durationMs);
359
+ return /* @__PURE__ */ jsxs2("div", { className: "rounded-lg border border-border/60 bg-card", children: [
360
+ /* @__PURE__ */ jsxs2("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: [
361
+ /* @__PURE__ */ jsx2(StatusDot, { tone }),
362
+ /* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1 truncate", children: [
363
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: record.tool }),
364
+ /* @__PURE__ */ jsxs2("span", { className: "text-muted-foreground", children: [
365
+ " \u2014 ",
366
+ record.detail
367
+ ] })
368
+ ] }),
369
+ tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */ jsx2("span", { className: "shrink-0 rounded-full bg-yellow-500/10 px-2 py-0.5 font-mono text-[10px] text-yellow-700 dark:text-yellow-400", children: [record.iteration !== void 0 ? `iter ${record.iteration}` : null, record.phase ?? null].filter(Boolean).join(" \xB7 ") }),
370
+ /* @__PURE__ */ jsx2(
371
+ "span",
372
+ {
373
+ className: `shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium ${tone === "ok" ? "bg-green-500/10 text-green-700 dark:text-green-400" : tone === "error" ? "bg-red-500/10 text-red-700 dark:text-red-400" : tone === "live" ? "bg-yellow-500/10 text-yellow-700 dark:text-yellow-400" : "bg-muted/60 text-muted-foreground"}`,
374
+ children: record.status
375
+ }
376
+ ),
377
+ cost && /* @__PURE__ */ jsx2("span", { className: "shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground", children: cost }),
378
+ /* @__PURE__ */ jsx2(ChevronGlyph, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })
379
+ ] }),
380
+ open && /* @__PURE__ */ jsxs2("div", { className: "space-y-1.5 border-t border-border/40 px-3 py-2.5", children: [
381
+ /* @__PURE__ */ jsxs2("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-[11px]", children: [
382
+ /* @__PURE__ */ jsx2("dt", { className: "text-muted-foreground/60", children: "task" }),
383
+ /* @__PURE__ */ jsx2("dd", { className: "truncate text-muted-foreground", children: record.taskId }),
384
+ /* @__PURE__ */ jsx2("dt", { className: "text-muted-foreground/60", children: "started" }),
385
+ /* @__PURE__ */ jsx2("dd", { className: "text-muted-foreground", children: new Date(record.startedAt).toLocaleString() }),
386
+ duration && /* @__PURE__ */ jsxs2(Fragment, { children: [
387
+ /* @__PURE__ */ jsx2("dt", { className: "text-muted-foreground/60", children: "duration" }),
388
+ /* @__PURE__ */ jsx2("dd", { className: "text-muted-foreground", children: duration })
389
+ ] }),
390
+ record.traceId && /* @__PURE__ */ jsxs2(Fragment, { children: [
391
+ /* @__PURE__ */ jsx2("dt", { className: "text-muted-foreground/60", children: "trace" }),
392
+ /* @__PURE__ */ jsx2("dd", { className: "truncate text-muted-foreground", children: record.traceId })
393
+ ] })
394
+ ] }),
395
+ record.missionRef && renderMissionRef?.(record.missionRef, record)
396
+ ] })
397
+ ] });
398
+ }
399
+ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent activity", emptyLabel = "No agent runs yet." }) {
400
+ const [rows, setRows] = useState2([]);
401
+ const [cursor, setCursor] = useState2(void 0);
402
+ const [loading, setLoading] = useState2(false);
403
+ const [error, setError] = useState2(null);
404
+ const load = useCallback(
405
+ async (from) => {
406
+ setLoading(true);
407
+ setError(null);
408
+ try {
409
+ const page = await fetchActivity(from);
410
+ setRows((prev) => mergeActivityPages(from === void 0 ? [] : prev, page.items));
411
+ setCursor(page.nextCursor);
412
+ } catch (e) {
413
+ setError(e instanceof Error ? e.message : String(e));
414
+ } finally {
415
+ setLoading(false);
416
+ }
417
+ },
418
+ [fetchActivity]
419
+ );
420
+ useEffect2(() => {
421
+ void load();
422
+ }, [load]);
423
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
424
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
425
+ /* @__PURE__ */ jsx2("h2", { className: "flex-1 text-sm font-semibold", children: title }),
426
+ /* @__PURE__ */ jsx2(
427
+ "button",
428
+ {
429
+ type: "button",
430
+ onClick: () => void load(),
431
+ disabled: loading,
432
+ "aria-label": "Refresh",
433
+ className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground disabled:opacity-50",
434
+ children: /* @__PURE__ */ jsx2(RefreshGlyph, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` })
435
+ }
436
+ )
437
+ ] }),
438
+ error && /* @__PURE__ */ jsx2("p", { className: "rounded-md border border-red-300/60 bg-red-500/5 px-3 py-2 text-xs text-red-600", children: error }),
439
+ !error && rows.length === 0 && !loading && /* @__PURE__ */ jsx2("p", { className: "px-1 text-sm text-muted-foreground", children: emptyLabel }),
440
+ /* @__PURE__ */ jsx2("div", { className: "space-y-1.5", children: rows.map((record) => /* @__PURE__ */ jsx2(ActivityRow, { record, renderMissionRef }, record.taskId)) }),
441
+ cursor && /* @__PURE__ */ jsx2(
442
+ "button",
443
+ {
444
+ type: "button",
445
+ onClick: () => void load(cursor),
446
+ disabled: loading,
447
+ 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",
448
+ children: "Older runs"
449
+ }
450
+ )
451
+ ] });
452
+ }
453
+
454
+ // src/web-react/index.tsx
455
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
456
+ function ChevronDown({ className }) {
457
+ return /* @__PURE__ */ jsx3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "m6 9 6 6 6-6" }) });
458
+ }
214
459
  function SearchGlyph({ className }) {
215
- return /* @__PURE__ */ jsxs2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
216
- /* @__PURE__ */ jsx2("circle", { cx: "11", cy: "11", r: "8" }),
217
- /* @__PURE__ */ jsx2("path", { d: "m21 21-4.3-4.3" })
460
+ return /* @__PURE__ */ jsxs3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
461
+ /* @__PURE__ */ jsx3("circle", { cx: "11", cy: "11", r: "8" }),
462
+ /* @__PURE__ */ jsx3("path", { d: "m21 21-4.3-4.3" })
218
463
  ] });
219
464
  }
220
465
  function SparkleGlyph({ className }) {
221
- 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" }) });
466
+ return /* @__PURE__ */ jsx3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "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" }) });
222
467
  }
223
468
  function useClickOutside(onOutside) {
224
469
  const ref = useRef2(null);
225
- useEffect2(() => {
470
+ useEffect3(() => {
226
471
  function handler(e) {
227
472
  if (ref.current && !ref.current.contains(e.target)) onOutside();
228
473
  }
@@ -257,7 +502,7 @@ function formatContext(len) {
257
502
  return `${len} ctx`;
258
503
  }
259
504
  function SectionHeader({ children }) {
260
- return /* @__PURE__ */ jsx2("div", { className: "px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground/70", children });
505
+ return /* @__PURE__ */ jsx3("div", { className: "px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground/70", children });
261
506
  }
262
507
  function ModelRow({
263
508
  model,
@@ -267,30 +512,30 @@ function ModelRow({
267
512
  }) {
268
513
  const price = formatPrice(model.pricing?.prompt);
269
514
  const ctx = formatContext(model.contextLength);
270
- return /* @__PURE__ */ jsxs2(
515
+ return /* @__PURE__ */ jsxs3(
271
516
  "button",
272
517
  {
273
518
  type: "button",
274
519
  onClick: onSelect,
275
520
  className: `flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${selected ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
276
521
  children: [
277
- renderProviderBadge ? renderProviderBadge(model.provider) : /* @__PURE__ */ jsx2(ProviderLogo, { provider: model.provider, size: 16 }),
278
- /* @__PURE__ */ jsx2("span", { className: "truncate", children: model.name }),
279
- !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" }),
280
- /* @__PURE__ */ jsxs2("span", { className: "ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground", children: [
281
- ctx && /* @__PURE__ */ jsx2("span", { children: ctx }),
282
- price && /* @__PURE__ */ jsx2("span", { children: price })
522
+ renderProviderBadge ? renderProviderBadge(model.provider) : /* @__PURE__ */ jsx3(ProviderLogo, { provider: model.provider, size: 16 }),
523
+ /* @__PURE__ */ jsx3("span", { className: "truncate", children: model.name }),
524
+ !model.supportsTools && /* @__PURE__ */ jsx3("span", { className: "shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: "no tools" }),
525
+ /* @__PURE__ */ jsxs3("span", { className: "ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground", children: [
526
+ ctx && /* @__PURE__ */ jsx3("span", { children: ctx }),
527
+ price && /* @__PURE__ */ jsx3("span", { children: price })
283
528
  ] })
284
529
  ]
285
530
  }
286
531
  );
287
532
  }
288
533
  function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = "Recommended" }) {
289
- const [open, setOpen] = useState2(false);
290
- const [query, setQuery] = useState2("");
534
+ const [open, setOpen] = useState3(false);
535
+ const [query, setQuery] = useState3("");
291
536
  const containerRef = useClickOutside(() => setOpen(false));
292
537
  const inputRef = useRef2(null);
293
- useEffect2(() => {
538
+ useEffect3(() => {
294
539
  if (open) inputRef.current?.focus();
295
540
  }, [open]);
296
541
  const selected = models.find((m) => m.id === value);
@@ -317,24 +562,24 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
317
562
  setOpen(false);
318
563
  setQuery("");
319
564
  };
320
- return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
321
- /* @__PURE__ */ jsxs2(
565
+ return /* @__PURE__ */ jsxs3("div", { ref: containerRef, className: "relative inline-flex", children: [
566
+ /* @__PURE__ */ jsxs3(
322
567
  "button",
323
568
  {
324
569
  type: "button",
325
570
  onClick: () => setOpen((v) => !v),
326
571
  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",
327
572
  children: [
328
- 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" }),
329
- /* @__PURE__ */ jsx2("span", { className: "max-w-[160px] truncate", children: selected?.name ?? value }),
330
- /* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
573
+ selected ? renderProviderBadge ? renderProviderBadge(selected.provider) : /* @__PURE__ */ jsx3(ProviderLogo, { provider: selected.provider, size: 16 }) : /* @__PURE__ */ jsx3(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
574
+ /* @__PURE__ */ jsx3("span", { className: "max-w-[160px] truncate", children: selected?.name ?? value }),
575
+ /* @__PURE__ */ jsx3(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
331
576
  ]
332
577
  }
333
578
  ),
334
- open && /* @__PURE__ */ jsxs2("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-[420px] overflow-hidden rounded-xl border border-border bg-card shadow-lg", children: [
335
- /* @__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: [
336
- /* @__PURE__ */ jsx2(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
337
- /* @__PURE__ */ jsx2(
579
+ open && /* @__PURE__ */ jsxs3("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-[420px] overflow-hidden rounded-xl border border-border bg-card shadow-lg", children: [
580
+ /* @__PURE__ */ jsx3("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2", children: [
581
+ /* @__PURE__ */ jsx3(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
582
+ /* @__PURE__ */ jsx3(
338
583
  "input",
339
584
  {
340
585
  ref: inputRef,
@@ -346,20 +591,20 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
346
591
  }
347
592
  )
348
593
  ] }) }),
349
- /* @__PURE__ */ jsxs2("div", { className: "max-h-[400px] overflow-y-auto p-1 pb-2", children: [
350
- loading && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading models..." }),
351
- !loading && filtered && /* @__PURE__ */ jsxs2(Fragment, { children: [
352
- filtered.length === 0 && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models match your search" }),
353
- filtered.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
594
+ /* @__PURE__ */ jsxs3("div", { className: "max-h-[400px] overflow-y-auto p-1 pb-2", children: [
595
+ loading && /* @__PURE__ */ jsx3("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading models..." }),
596
+ !loading && filtered && /* @__PURE__ */ jsxs3(Fragment2, { children: [
597
+ filtered.length === 0 && /* @__PURE__ */ jsx3("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models match your search" }),
598
+ filtered.map((m) => /* @__PURE__ */ jsx3(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
354
599
  ] }),
355
- !loading && !filtered && /* @__PURE__ */ jsxs2(Fragment, { children: [
356
- sections.recommended.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
357
- /* @__PURE__ */ jsx2(SectionHeader, { children: recommendedLabel }),
358
- sections.recommended.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
600
+ !loading && !filtered && /* @__PURE__ */ jsxs3(Fragment2, { children: [
601
+ sections.recommended.length > 0 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
602
+ /* @__PURE__ */ jsx3(SectionHeader, { children: recommendedLabel }),
603
+ sections.recommended.map((m) => /* @__PURE__ */ jsx3(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
359
604
  ] }),
360
- sections.byProvider.map((g) => /* @__PURE__ */ jsxs2("div", { children: [
361
- /* @__PURE__ */ jsx2(SectionHeader, { children: g.provider }),
362
- g.items.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
605
+ sections.byProvider.map((g) => /* @__PURE__ */ jsxs3("div", { children: [
606
+ /* @__PURE__ */ jsx3(SectionHeader, { children: g.provider }),
607
+ g.items.map((m) => /* @__PURE__ */ jsx3(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
363
608
  ] }, g.provider))
364
609
  ] })
365
610
  ] })
@@ -373,11 +618,11 @@ var EFFORT_LEVELS = [
373
618
  { id: "high", label: "High" }
374
619
  ];
375
620
  function EffortPicker({ value, onChange }) {
376
- const [open, setOpen] = useState2(false);
621
+ const [open, setOpen] = useState3(false);
377
622
  const containerRef = useClickOutside(() => setOpen(false));
378
623
  const selected = EFFORT_LEVELS.find((l) => l.id === value) ?? EFFORT_LEVELS[2];
379
- return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
380
- /* @__PURE__ */ jsxs2(
624
+ return /* @__PURE__ */ jsxs3("div", { ref: containerRef, className: "relative inline-flex", children: [
625
+ /* @__PURE__ */ jsxs3(
381
626
  "button",
382
627
  {
383
628
  type: "button",
@@ -385,13 +630,13 @@ function EffortPicker({ value, onChange }) {
385
630
  title: "Reasoning effort",
386
631
  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",
387
632
  children: [
388
- /* @__PURE__ */ jsx2(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
389
- /* @__PURE__ */ jsx2("span", { children: selected.label }),
390
- /* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
633
+ /* @__PURE__ */ jsx3(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
634
+ /* @__PURE__ */ jsx3("span", { children: selected.label }),
635
+ /* @__PURE__ */ jsx3(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
391
636
  ]
392
637
  }
393
638
  ),
394
- open && /* @__PURE__ */ jsx2("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-36 overflow-hidden rounded-xl border border-border bg-card p-1 shadow-lg", children: EFFORT_LEVELS.map((l) => /* @__PURE__ */ jsx2(
639
+ open && /* @__PURE__ */ jsx3("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-36 overflow-hidden rounded-xl border border-border bg-card p-1 shadow-lg", children: EFFORT_LEVELS.map((l) => /* @__PURE__ */ jsx3(
395
640
  "button",
396
641
  {
397
642
  type: "button",
@@ -407,41 +652,41 @@ function EffortPicker({ value, onChange }) {
407
652
  ] });
408
653
  }
409
654
  function RunDrillIn({ run, onClose }) {
410
- return /* @__PURE__ */ jsxs2("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: [
411
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
412
- /* @__PURE__ */ jsx2(
655
+ return /* @__PURE__ */ jsxs3("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: [
656
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
657
+ /* @__PURE__ */ jsx3(
413
658
  "span",
414
659
  {
415
660
  className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-yellow-500" : run.status === "error" ? "bg-red-500" : "bg-green-500"}`
416
661
  }
417
662
  ),
418
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
419
- /* @__PURE__ */ jsx2("p", { className: "truncate text-sm font-semibold", children: run.title }),
420
- /* @__PURE__ */ jsx2("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
663
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
664
+ /* @__PURE__ */ jsx3("p", { className: "truncate text-sm font-semibold", children: run.title }),
665
+ /* @__PURE__ */ jsx3("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
421
666
  ] }),
422
- /* @__PURE__ */ jsx2(
667
+ /* @__PURE__ */ jsx3(
423
668
  "button",
424
669
  {
425
670
  type: "button",
426
671
  onClick: onClose,
427
672
  "aria-label": "Close",
428
673
  className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground",
429
- children: /* @__PURE__ */ jsx2("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "M18 6 6 18M6 6l12 12" }) })
674
+ children: /* @__PURE__ */ jsx3("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "M18 6 6 18M6 6l12 12" }) })
430
675
  }
431
676
  )
432
677
  ] }),
433
- /* @__PURE__ */ jsxs2("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
434
- run.steps.length === 0 && /* @__PURE__ */ jsx2("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
435
- run.steps.map((step, i) => /* @__PURE__ */ jsxs2("div", { className: "rounded-lg border border-border/60 bg-background", children: [
436
- /* @__PURE__ */ jsxs2("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
437
- /* @__PURE__ */ jsx2("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-red-600" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
438
- /* @__PURE__ */ jsx2("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
439
- /* @__PURE__ */ jsx2("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: new Date(step.at).toLocaleTimeString() })
678
+ /* @__PURE__ */ jsxs3("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
679
+ run.steps.length === 0 && /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
680
+ run.steps.map((step, i) => /* @__PURE__ */ jsxs3("div", { className: "rounded-lg border border-border/60 bg-background", children: [
681
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
682
+ /* @__PURE__ */ jsx3("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-red-600" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
683
+ /* @__PURE__ */ jsx3("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
684
+ /* @__PURE__ */ jsx3("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: new Date(step.at).toLocaleTimeString() })
440
685
  ] }),
441
- step.detail && /* @__PURE__ */ jsx2("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 })
686
+ step.detail && /* @__PURE__ */ jsx3("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 })
442
687
  ] }, i))
443
688
  ] }),
444
- /* @__PURE__ */ jsx2("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground/60", children: "Readonly drill-in. Follow up in the main chat." })
689
+ /* @__PURE__ */ jsx3("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground/60", children: "Readonly drill-in. Follow up in the main chat." })
445
690
  ] });
446
691
  }
447
692
  function pendingApprovalOf(call) {
@@ -451,26 +696,26 @@ function pendingApprovalOf(call) {
451
696
  }
452
697
  function ToolGlyph({ name, className }) {
453
698
  if (name.startsWith("sandbox_")) {
454
- return /* @__PURE__ */ jsxs2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
455
- /* @__PURE__ */ jsx2("polyline", { points: "4 17 10 11 4 5" }),
456
- /* @__PURE__ */ jsx2("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
699
+ return /* @__PURE__ */ jsxs3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
700
+ /* @__PURE__ */ jsx3("polyline", { points: "4 17 10 11 4 5" }),
701
+ /* @__PURE__ */ jsx3("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
457
702
  ] });
458
703
  }
459
704
  if (name === "submit_proposal") {
460
- return /* @__PURE__ */ jsxs2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
461
- /* @__PURE__ */ jsx2("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
462
- /* @__PURE__ */ jsx2("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
705
+ return /* @__PURE__ */ jsxs3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
706
+ /* @__PURE__ */ jsx3("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
707
+ /* @__PURE__ */ jsx3("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
463
708
  ] });
464
709
  }
465
710
  if (name === "schedule_followup") {
466
- return /* @__PURE__ */ jsxs2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
467
- /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "9" }),
468
- /* @__PURE__ */ jsx2("path", { d: "M12 7v5l3 3" })
711
+ return /* @__PURE__ */ jsxs3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
712
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "9" }),
713
+ /* @__PURE__ */ jsx3("path", { d: "M12 7v5l3 3" })
469
714
  ] });
470
715
  }
471
- return /* @__PURE__ */ jsxs2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
472
- /* @__PURE__ */ jsx2("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
473
- /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "4" })
716
+ return /* @__PURE__ */ jsxs3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
717
+ /* @__PURE__ */ jsx3("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
718
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "4" })
474
719
  ] });
475
720
  }
476
721
  function toolOutcomeOf(call) {
@@ -504,36 +749,36 @@ function truncate(v, max = 240) {
504
749
  function KvRows({ data }) {
505
750
  const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
506
751
  if (!entries.length) return null;
507
- return /* @__PURE__ */ jsx2("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs2("div", { className: "contents", children: [
508
- /* @__PURE__ */ jsx2("dt", { className: "font-mono text-[11px] text-muted-foreground/70", children: k }),
509
- /* @__PURE__ */ jsx2("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
752
+ return /* @__PURE__ */ jsx3("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs3("div", { className: "contents", children: [
753
+ /* @__PURE__ */ jsx3("dt", { className: "font-mono text-[11px] text-muted-foreground/70", children: k }),
754
+ /* @__PURE__ */ jsx3("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
510
755
  ] }, k)) });
511
756
  }
512
757
  function ShellDetail({ call }) {
513
758
  const outcome = toolOutcomeOf(call);
514
759
  const r = outcome?.result ?? {};
515
- return /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
516
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
517
- /* @__PURE__ */ jsx2("span", { className: "select-none text-zinc-500", children: "$" }),
518
- /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
519
- r.exitCode != null && /* @__PURE__ */ jsxs2("span", { className: r.exitCode === 0 ? "text-emerald-400" : "text-red-400", children: [
760
+ return /* @__PURE__ */ jsxs3("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
761
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
762
+ /* @__PURE__ */ jsx3("span", { className: "select-none text-zinc-500", children: "$" }),
763
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
764
+ r.exitCode != null && /* @__PURE__ */ jsxs3("span", { className: r.exitCode === 0 ? "text-emerald-400" : "text-red-400", children: [
520
765
  "exit ",
521
766
  r.exitCode
522
767
  ] })
523
768
  ] }),
524
- /* @__PURE__ */ jsx2("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)" })
769
+ /* @__PURE__ */ jsx3("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)" })
525
770
  ] });
526
771
  }
527
772
  function DefaultToolDetail({ call }) {
528
773
  const outcome = toolOutcomeOf(call);
529
- return /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
530
- call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs2("div", { children: [
531
- /* @__PURE__ */ jsx2("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: "Called with" }),
532
- /* @__PURE__ */ jsx2(KvRows, { data: call.args })
774
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
775
+ call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs3("div", { children: [
776
+ /* @__PURE__ */ jsx3("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: "Called with" }),
777
+ /* @__PURE__ */ jsx3(KvRows, { data: call.args })
533
778
  ] }),
534
- outcome && /* @__PURE__ */ jsxs2("div", { children: [
535
- /* @__PURE__ */ jsx2("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: outcome.ok === false ? "Failed" : "Result" }),
536
- outcome.ok === false ? /* @__PURE__ */ jsx2("p", { className: "text-xs text-red-600", children: outcome.message ?? "Tool failed" }) : outcome.result && typeof outcome.result === "object" ? /* @__PURE__ */ jsx2(KvRows, { data: outcome.result }) : /* @__PURE__ */ jsx2("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(outcome.result) })
779
+ outcome && /* @__PURE__ */ jsxs3("div", { children: [
780
+ /* @__PURE__ */ jsx3("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50", children: outcome.ok === false ? "Failed" : "Result" }),
781
+ outcome.ok === false ? /* @__PURE__ */ jsx3("p", { className: "text-xs text-red-600", children: outcome.message ?? "Tool failed" }) : outcome.result && typeof outcome.result === "object" ? /* @__PURE__ */ jsx3(KvRows, { data: outcome.result }) : /* @__PURE__ */ jsx3("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(outcome.result) })
537
782
  ] })
538
783
  ] });
539
784
  }
@@ -544,32 +789,32 @@ function ToolCallCard({
544
789
  onOpenRun,
545
790
  renderers
546
791
  }) {
547
- const [expanded, setExpanded] = useState2(false);
792
+ const [expanded, setExpanded] = useState3(false);
548
793
  const pending = call.status === "done" ? pendingApprovalOf(call) : null;
549
794
  const failed = call.status === "error" || toolOutcomeOf(call)?.ok === false;
550
795
  const custom = renderers?.[call.name]?.(call, message);
551
- return /* @__PURE__ */ jsxs2(
796
+ return /* @__PURE__ */ jsxs3(
552
797
  "div",
553
798
  {
554
799
  className: `w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${pending ? "border-amber-300/60 bg-amber-500/5" : failed ? "border-red-300/60 bg-red-500/5" : "border-border/60 bg-muted/20"}`,
555
800
  children: [
556
- /* @__PURE__ */ jsxs2(
801
+ /* @__PURE__ */ jsxs3(
557
802
  "button",
558
803
  {
559
804
  type: "button",
560
805
  onClick: () => setExpanded((v) => !v),
561
806
  className: "flex w-full items-center gap-2 px-3 py-2 text-left",
562
807
  children: [
563
- /* @__PURE__ */ jsx2(
808
+ /* @__PURE__ */ jsx3(
564
809
  "span",
565
810
  {
566
811
  className: `h-2 w-2 shrink-0 rounded-full ${call.status === "running" ? "animate-pulse bg-yellow-500" : pending ? "bg-amber-500" : failed ? "bg-red-500" : "bg-green-500"}`
567
812
  }
568
813
  ),
569
- /* @__PURE__ */ jsx2(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
570
- /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate font-medium", children: friendlyToolTitle(call) }),
571
- pending && approval && /* @__PURE__ */ jsxs2("span", { className: "flex shrink-0 items-center gap-1", onClick: (e) => e.stopPropagation(), children: [
572
- /* @__PURE__ */ jsx2(
814
+ /* @__PURE__ */ jsx3(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
815
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate font-medium", children: friendlyToolTitle(call) }),
816
+ pending && approval && /* @__PURE__ */ jsxs3("span", { className: "flex shrink-0 items-center gap-1", onClick: (e) => e.stopPropagation(), children: [
817
+ /* @__PURE__ */ jsx3(
573
818
  "button",
574
819
  {
575
820
  type: "button",
@@ -578,7 +823,7 @@ function ToolCallCard({
578
823
  children: "Approve"
579
824
  }
580
825
  ),
581
- /* @__PURE__ */ jsx2(
826
+ /* @__PURE__ */ jsx3(
582
827
  "button",
583
828
  {
584
829
  type: "button",
@@ -588,14 +833,14 @@ function ToolCallCard({
588
833
  }
589
834
  )
590
835
  ] }),
591
- /* @__PURE__ */ jsx2("span", { className: "shrink-0 text-[11px] text-muted-foreground/70", children: call.status === "running" ? "running\u2026" : pending ? "awaiting approval" : failed ? "failed" : "done" }),
592
- /* @__PURE__ */ jsx2(ChevronDown, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
836
+ /* @__PURE__ */ jsx3("span", { className: "shrink-0 text-[11px] text-muted-foreground/70", children: call.status === "running" ? "running\u2026" : pending ? "awaiting approval" : failed ? "failed" : "done" }),
837
+ /* @__PURE__ */ jsx3(ChevronDown, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
593
838
  ]
594
839
  }
595
840
  ),
596
- expanded && /* @__PURE__ */ jsxs2("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
597
- custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx2(ShellDetail, { call }) : /* @__PURE__ */ jsx2(DefaultToolDetail, { call })),
598
- onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx2(
841
+ expanded && /* @__PURE__ */ jsxs3("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
842
+ custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx3(ShellDetail, { call }) : /* @__PURE__ */ jsx3(DefaultToolDetail, { call })),
843
+ onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx3(
599
844
  "button",
600
845
  {
601
846
  type: "button",
@@ -631,26 +876,26 @@ function AssistantMessage({
631
876
  if (content && thinkStartRef.current !== null && thinkMsRef.current === null) {
632
877
  thinkMsRef.current = performance.now() - thinkStartRef.current;
633
878
  }
634
- useEffect2(() => {
879
+ useEffect3(() => {
635
880
  const el = reasoningScrollRef.current;
636
881
  if (el && streaming && !content) el.scrollTop = el.scrollHeight;
637
882
  }, [reasoning, streaming, content]);
638
- return /* @__PURE__ */ jsxs2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
639
- /* @__PURE__ */ jsxs2("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60", children: [
640
- /* @__PURE__ */ jsx2("span", { className: "font-semibold uppercase", children: agentLabel }),
641
- msg.modelUsed && /* @__PURE__ */ jsx2("span", { className: "font-mono normal-case", children: msg.modelUsed }),
642
- formatTokensPerSecond(msg) && /* @__PURE__ */ jsx2("span", { children: formatTokensPerSecond(msg) }),
643
- formatModelCost(msg, models) && /* @__PURE__ */ jsx2("span", { children: formatModelCost(msg, models) })
883
+ return /* @__PURE__ */ jsxs3("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
884
+ /* @__PURE__ */ jsxs3("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60", children: [
885
+ /* @__PURE__ */ jsx3("span", { className: "font-semibold uppercase", children: agentLabel }),
886
+ msg.modelUsed && /* @__PURE__ */ jsx3("span", { className: "font-mono normal-case", children: msg.modelUsed }),
887
+ formatTokensPerSecond(msg) && /* @__PURE__ */ jsx3("span", { children: formatTokensPerSecond(msg) }),
888
+ formatModelCost(msg, models) && /* @__PURE__ */ jsx3("span", { children: formatModelCost(msg, models) })
644
889
  ] }),
645
- reasoning && /* @__PURE__ */ jsxs2("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !content, children: [
646
- /* @__PURE__ */ jsx2("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !content ? /* @__PURE__ */ jsx2("span", { className: "animate-pulse", children: "Thinking\u2026" }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
647
- /* @__PURE__ */ jsx2("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground/70", children: reasoning })
890
+ reasoning && /* @__PURE__ */ jsxs3("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !content, children: [
891
+ /* @__PURE__ */ jsx3("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !content ? /* @__PURE__ */ jsx3("span", { className: "animate-pulse", children: "Thinking\u2026" }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
892
+ /* @__PURE__ */ jsx3("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground/70", children: reasoning })
648
893
  ] }),
649
- /* @__PURE__ */ jsxs2("div", { className: "text-base leading-[1.75]", children: [
894
+ /* @__PURE__ */ jsxs3("div", { className: "text-base leading-[1.75]", children: [
650
895
  renderBody(content),
651
- streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx2("span", { className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70", "aria-hidden": true })
896
+ streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx3("span", { className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70", "aria-hidden": true })
652
897
  ] }),
653
- msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx2("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx2(
898
+ msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx3("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx3(
654
899
  ToolCallCard,
655
900
  {
656
901
  call: tc,
@@ -665,15 +910,15 @@ function AssistantMessage({
665
910
  ] });
666
911
  }
667
912
  function ThinkingRow({ agentLabel }) {
668
- const [seconds, setSeconds] = useState2(0);
669
- useEffect2(() => {
913
+ const [seconds, setSeconds] = useState3(0);
914
+ useEffect3(() => {
670
915
  const id = setInterval(() => setSeconds((s) => s + 1), 1e3);
671
916
  return () => clearInterval(id);
672
917
  }, []);
673
- return /* @__PURE__ */ jsxs2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
674
- /* @__PURE__ */ jsx2("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: agentLabel }),
675
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
676
- /* @__PURE__ */ jsx2("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
918
+ return /* @__PURE__ */ jsxs3("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
919
+ /* @__PURE__ */ jsx3("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: agentLabel }),
920
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
921
+ /* @__PURE__ */ jsx3("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
677
922
  "Thinking",
678
923
  seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
679
924
  ] })
@@ -691,14 +936,14 @@ function ChatMessages({
691
936
  onToolCallClick,
692
937
  toolRenderers
693
938
  }) {
694
- const renderBody = renderMarkdown ?? ((content) => /* @__PURE__ */ jsx2("p", { className: "whitespace-pre-wrap", children: content }));
939
+ const renderBody = renderMarkdown ?? ((content) => /* @__PURE__ */ jsx3("p", { className: "whitespace-pre-wrap", children: content }));
695
940
  const lastIsUser = messages[messages.length - 1]?.role === "user";
696
- return /* @__PURE__ */ jsxs2(Fragment, { children: [
941
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
697
942
  messages.map(
698
- (msg) => msg.role === "user" ? /* @__PURE__ */ jsx2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs2("div", { className: "ml-auto w-fit max-w-[85%]", children: [
699
- /* @__PURE__ */ jsx2("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: userLabel }),
700
- /* @__PURE__ */ jsx2("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx2("p", { className: "whitespace-pre-wrap", children: msg.content }) })
701
- ] }) }, msg.id) : /* @__PURE__ */ jsx2(
943
+ (msg) => msg.role === "user" ? /* @__PURE__ */ jsx3("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs3("div", { className: "ml-auto w-fit max-w-[85%]", children: [
944
+ /* @__PURE__ */ jsx3("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: userLabel }),
945
+ /* @__PURE__ */ jsx3("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx3("p", { className: "whitespace-pre-wrap", children: msg.content }) })
946
+ ] }) }, msg.id) : /* @__PURE__ */ jsx3(
702
947
  AssistantMessage,
703
948
  {
704
949
  msg,
@@ -714,22 +959,30 @@ function ChatMessages({
714
959
  msg.id
715
960
  )
716
961
  ),
717
- loading && lastIsUser && /* @__PURE__ */ jsx2(ThinkingRow, { agentLabel })
962
+ loading && lastIsUser && /* @__PURE__ */ jsx3(ThinkingRow, { agentLabel })
718
963
  ] });
719
964
  }
720
965
  export {
966
+ AgentActivityPanel,
721
967
  ChatMessages,
722
968
  EffortPicker,
969
+ FlowWaterfall,
970
+ MissionActivityLane,
723
971
  ModelPicker,
724
972
  ProviderLogo,
725
973
  RunDrillIn,
974
+ activityTone,
726
975
  consumeChatStream,
727
976
  dispatchChatStreamLine,
977
+ formatActivityCost,
978
+ formatActivityDuration,
728
979
  formatModelCost,
729
980
  formatTokensPerSecond,
981
+ mergeActivityPages,
730
982
  nextRevealCount,
731
983
  pendingApprovalOf,
732
984
  streamChatTurn,
733
- useSmoothText
985
+ useSmoothText,
986
+ waterfallLayout
734
987
  };
735
988
  //# sourceMappingURL=index.js.map