@lloyal-labs/dev-tools 0.4.3 → 0.5.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +143 -57
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +214 -21
- package/dist/index.js.map +1 -1
- package/dist/ink.d.ts +20 -1
- package/dist/ink.d.ts.map +1 -1
- package/dist/ink.js +51 -11
- package/dist/ink.js.map +1 -1
- package/dist/react.d.ts +8 -6
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +267 -83
- package/dist/react.js.map +1 -1
- package/dist/store.d.ts +5 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js.map +1 -1
- package/package.json +3 -7
- package/dist/node.d.ts +0 -6
- package/dist/node.d.ts.map +0 -1
- package/dist/node.js +0 -78
- package/dist/node.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -17,7 +17,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
17
17
|
*/
|
|
18
18
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
19
19
|
import { useStore } from 'zustand';
|
|
20
|
-
import { pressureStrip, pressurePercent, readConfigPath, lanePpl, isLive,
|
|
20
|
+
import { pressureStrip, pressurePercent, readConfigPath, lanePpl, isLive, configRows, configCommand, liveConfigKeys, changing, } from './index.js';
|
|
21
21
|
import { devStoreFor, EDGE_STEP } from './store.js';
|
|
22
22
|
// ── palette: monochrome chrome, color reserved for data ──
|
|
23
23
|
const C = {
|
|
@@ -246,7 +246,7 @@ function runEndS(m) {
|
|
|
246
246
|
return m.runStartAt === null ? 0 : Math.max(0, (end - m.runStartAt) / 1000);
|
|
247
247
|
}
|
|
248
248
|
// ═══════════════════════════════════════════════════════════════
|
|
249
|
-
export function DevPane({ bridge,
|
|
249
|
+
export function DevPane({ bridge, config, title, runCommands = {}, framing, children }) {
|
|
250
250
|
// The store is a per-bridge SINGLETON: a remount reattaches to the running
|
|
251
251
|
// fold (full history intact) instead of restarting it and desyncing. It is
|
|
252
252
|
// deliberately NOT destroyed on unmount — it lives with the page, like the
|
|
@@ -328,10 +328,13 @@ export function DevPane({ bridge, controls = [], title, runCommands = {}, framin
|
|
|
328
328
|
} }), m.clarifying ? '?' : liveCount > 0 ? liveCount : '!'] })), _jsx("span", { children: summary })] }), toast && _jsx(Notice, { at: toastAt, text: toast }), _jsx("span", { style: { flex: 1 } }), _jsxs("span", { "aria-hidden": "true", style: { display: 'inline-flex', alignItems: 'center', gap: 14 }, children: [_jsx(MiniSpark, { heading: "context", color: C.agent, values: barStrip.map((p) => p.pct), value: barPct === null ? '—' : `${barPct}%` }), _jsx(MiniSpark, { heading: "cpu", color: HOST_CPU, values: barHost.map((h) => h.cpu), value: barLast ? `${barLast.cpu}%` : '—' }), _jsx(MiniSpark, { heading: "mem", color: "#9aa0a6", values: barHost.filter((h) => h.memUsedMb !== null).map((h) => h.memUsedMb), value: barLast && barLast.memUsedMb !== null && barLast.memTotalMb > 0
|
|
329
329
|
? `${(barLast.memUsedMb / 1024).toFixed(1)} / ${Math.round(barLast.memTotalMb / 1024)}G` : '—' }), _jsx(MiniSpark, { heading: "harness", color: "#5f6368", values: barHost.map((h) => h.rssMb), value: barLast ? `${(barLast.rssMb / 1024).toFixed(1)}G` : '—' })] }), _jsx("span", { style: { flex: 1 } }), _jsx("span", { style: { color: C.faint }, "aria-hidden": "true", children: "click to expand" })] }));
|
|
330
330
|
}
|
|
331
|
-
return shell(_jsx(Pane, { store: store, m: m, rev: rev,
|
|
331
|
+
return shell(_jsx(Pane, { store: store, m: m, rev: rev, config: config, title: title, runCommands: runCommands, onClose: () => setOpen(false),
|
|
332
|
+
// Thumbnails resolve through the bridge when the harness exposes a
|
|
333
|
+
// content route; the pane never learns the transport, only the URL.
|
|
334
|
+
mediaUrl: bridge.representationUrl ? (d, i) => bridge.representationUrl(d, i) : undefined }));
|
|
332
335
|
}
|
|
333
336
|
// ═══ the docked pane ═══
|
|
334
|
-
function Pane({ store, m, rev,
|
|
337
|
+
function Pane({ store, m, rev, config, title, runCommands, onClose, mediaUrl }) {
|
|
335
338
|
const [tab, setTab] = useState('timeline');
|
|
336
339
|
const [selAgent, setSelAgent] = useState(null);
|
|
337
340
|
const [feedW, setFeedW] = useState(feedWidthPref);
|
|
@@ -401,7 +404,7 @@ function Pane({ store, m, rev, controls, title, runCommands, onClose }) {
|
|
|
401
404
|
: 'finish up — agents wrap up and report; the trajectory is kept', style: m.pausedAt !== null || m.windingDownAt !== null
|
|
402
405
|
? { ...runBtn, opacity: 0.4, cursor: 'default' } : runBtn, children: m.windingDownAt !== null ? 'finishing…' : 'finish up' })), runCommands.stop && (_jsx("button", { onClick: () => store.send({ type: 'stop' }), title: "halt the run", style: { ...runBtn, color: C.fail, borderColor: '#f0c4c1' }, children: "stop" }))] })), _jsxs("span", { style: { fontFamily: mono, display: 'inline-flex', alignItems: 'center', gap: 7 }, children: [_jsx("span", { style: { width: 7, height: 7, borderRadius: '50%', background: live ? (m.pausedAt !== null ? C.warn : C.ok) : C.faint } }), live
|
|
403
406
|
? (m.pausedAt !== null ? 'paused' : m.windingDownAt !== null ? 'finishing' : 'live')
|
|
404
|
-
: m.runStartAt === null ? 'idle' : 'run complete'] }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "collapse to the cog", children: "\u2715" })] })] }), tab === 'timeline' && (_jsxs("div", { style: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Timeline, { m: m, rev: rev, store: store, selAgent: selAgent, onSelect: setSelAgent, toolColor: toolColor }), selAgent
|
|
407
|
+
: m.runStartAt === null ? 'idle' : 'run complete'] }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "collapse to the cog", children: "\u2715" })] })] }), tab === 'timeline' && (_jsxs("div", { style: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Timeline, { m: m, rev: rev, store: store, selAgent: selAgent, onSelect: setSelAgent, toolColor: toolColor }), selAgent === 'spine' && m.spine && (_jsxs(_Fragment, { children: [_jsx(FeedResizer, { width: feedW, onWidth: (w) => { feedWidthPref = w; setFeedW(w); } }), _jsx(SpineFeed, { m: m, onClose: () => setSelAgent(null), width: feedW, mediaUrl: mediaUrl, toolColor: toolColor })] })), selAgent === 'trunk' && m.trunk.length > 0 && (_jsxs(_Fragment, { children: [_jsx(FeedResizer, { width: feedW, onWidth: (w) => { feedWidthPref = w; setFeedW(w); } }), _jsx(TrunkFeed, { m: m, onClose: () => setSelAgent(null), width: feedW, mediaUrl: mediaUrl })] })), typeof selAgent === 'number' && m.lanes.has(selAgent) && (_jsxs(_Fragment, { children: [_jsx(FeedResizer, { width: feedW, onWidth: (w) => { feedWidthPref = w; setFeedW(w); } }), _jsx(AgentFeed, { m: m, lane: m.lanes.get(selAgent), toolColor: toolColor, onClose: () => setSelAgent(null), onJump: setSelAgent, nowMs: store.getState().paintedAt, width: feedW, send: (c) => store.send(c), canCancel: !!runCommands.cancelAgent })] }))] })), tab === 'sources' && _jsx(Sources, { m: m, toolColor: toolColor }), tab === 'settings' && _jsx(Settings, { m: m, config: config, send: (c) => store.send(c) }), _jsxs("div", { style: {
|
|
405
408
|
height: 24, display: 'flex', alignItems: 'center', gap: 14, padding: '0 12px',
|
|
406
409
|
borderTop: `1px solid ${C.border}`, background: '#f8f9fa', fontSize: 10.5, color: C.dim, flex: 'none',
|
|
407
410
|
}, children: [_jsxs("span", { style: { fontFamily: mono }, children: [m.runStartAt === null
|
|
@@ -492,11 +495,121 @@ function Timeline({ m, rev, store, selAgent, onSelect, toolColor }) {
|
|
|
492
495
|
};
|
|
493
496
|
const onMouseUp = () => { drag.current = null; };
|
|
494
497
|
return (_jsxs("div", { style: { flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', minHeight: 0 }, children: [_jsxs("div", { style: { height: 54, borderBottom: `1px solid ${C.border}`, display: 'flex', flex: 'none' }, children: [_jsx(MetricCell, { heading: "context", color: C.agent, values: strip.slice(-60).map((p) => p.pct), value: pct === null ? '—' : `${pct}% · ${m.pressure[m.pressure.length - 1]?.cellsUsed.toLocaleString()} / ${m.pressure[m.pressure.length - 1]?.nCtx.toLocaleString()}`, title: "kv cells used \u2014 context pressure on the model side" }), _jsx(MetricCell, { heading: "cpu", color: HOST_CPU, values: host.slice(-60).map((h) => h.cpu), value: lastHost ? `${lastHost.cpu}%` : '—', title: "this process's cpu, % of the whole machine" }), _jsx(MetricCell, { heading: "mem", color: "#9aa0a6", values: host.slice(-60).filter((h) => h.memUsedMb !== null).map((h) => h.memUsedMb), value: lastHost && lastHost.memUsedMb !== null && lastHost.memTotalMb > 0
|
|
495
|
-
? `${(lastHost.memUsedMb / 1024).toFixed(1)} / ${Math.round(lastHost.memTotalMb / 1024)}G` : '—', title: "machine memory in use, honestly counted (vm_stat / MemAvailable)" }), _jsx(MetricCell, { heading: "harness", color: "#5f6368", last: true, values: host.slice(-60).map((h) => h.rssMb), value: lastHost ? `${(lastHost.rssMb / 1024).toFixed(1)}G` : '—', title: "this process's resident memory \u2014 weights + KV + runtime" })] }), _jsxs("div", { style: { height: 20, display: 'flex', borderBottom: `1px solid ${C.border}`, flex: 'none' }, children: [_jsx("div", { style: { width: GUTTER, flex: 'none', padding: '4px 0 0 14px' }, children: _jsx("span", { style: label, children: lanes.length ? `${lanes.length} agents` : '' }) }), _jsx("div", { style: { flex: 1, position: 'relative', fontFamily: mono }, children: ticks.map((t) => (_jsx("span", { style: { position: 'absolute', left: px(t) - GUTTER, fontSize: 9, color: C.faint }, children: t >= 60 ? `${Math.floor(t / 60)}m${t % 60 ? String(t % 60).padStart(2, '0') : ''}` : `${t}s` }, t))) })] }), _jsxs("div", { ref: trackRef, style: { flex: 1, position: 'relative', overflowY: 'auto', overflowX: 'hidden', cursor: drag.current ? 'grabbing' : undefined }, onMouseDown: onMouseDown, onMouseMove: onMouseMove, onMouseUp: onMouseUp, onMouseLeave: onMouseUp, onDoubleClick: () => { setFollow(true); setPanWindow(null); }, children: [m.runStartAt === null && (_jsx("div", { style: { position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', color: C.faint, fontSize: 11.5, pointerEvents: 'none' }, children: "run a query \u2014 agents appear here live" })), !follow && live && (_jsx("button", { onClick: (e) => { e.stopPropagation(); setFollow(true); setPanWindow(null); }, style: {
|
|
498
|
+
? `${(lastHost.memUsedMb / 1024).toFixed(1)} / ${Math.round(lastHost.memTotalMb / 1024)}G` : '—', title: "machine memory in use, honestly counted (vm_stat / MemAvailable)" }), _jsx(MetricCell, { heading: "harness", color: "#5f6368", last: true, values: host.slice(-60).map((h) => h.rssMb), value: lastHost ? `${(lastHost.rssMb / 1024).toFixed(1)}G` : '—', title: "this process's resident memory \u2014 weights + KV + runtime" })] }), _jsxs("div", { style: { height: 20, display: 'flex', borderBottom: `1px solid ${C.border}`, flex: 'none' }, children: [_jsx("div", { style: { width: GUTTER, flex: 'none', padding: '4px 0 0 14px' }, children: _jsx("span", { style: label, children: lanes.length ? `${lanes.length} agents` : '' }) }), _jsx("div", { style: { flex: 1, position: 'relative', overflow: 'hidden', fontFamily: mono }, children: ticks.map((t) => (_jsx("span", { style: { position: 'absolute', left: px(t) - GUTTER, fontSize: 9, color: C.faint }, children: t >= 60 ? `${Math.floor(t / 60)}m${t % 60 ? String(t % 60).padStart(2, '0') : ''}` : `${t}s` }, t))) })] }), _jsxs("div", { ref: trackRef, style: { flex: 1, position: 'relative', overflowY: 'auto', overflowX: 'hidden', cursor: drag.current ? 'grabbing' : undefined }, onMouseDown: onMouseDown, onMouseMove: onMouseMove, onMouseUp: onMouseUp, onMouseLeave: onMouseUp, onDoubleClick: () => { setFollow(true); setPanWindow(null); }, children: [m.runStartAt === null && (_jsx("div", { style: { position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', color: C.faint, fontSize: 11.5, pointerEvents: 'none' }, children: "run a query \u2014 agents appear here live" })), !follow && live && (_jsx("button", { onClick: (e) => { e.stopPropagation(); setFollow(true); setPanWindow(null); }, style: {
|
|
496
499
|
position: 'absolute', top: 6, right: 10, zIndex: 3, cursor: 'pointer',
|
|
497
500
|
fontSize: 10.5, padding: '3px 10px', borderRadius: 12, border: `1px solid ${C.border}`,
|
|
498
501
|
background: '#fff', color: C.agentDark, fontWeight: 600, boxShadow: '0 1px 4px rgba(32,33,36,.12)',
|
|
499
|
-
}, children: "\u27F3 follow live" })), _jsxs("div", { style: { position: 'absolute', left: GUTTER, right: 0, top: 0, bottom: 0, pointerEvents: 'none' }, children: [ticks.map((t) => (_jsx("div", { style: { position: 'absolute', left: px(t) - GUTTER, top: 0, bottom: 0, width: 1, background: t % (step * 3) === 0 ? C.border : C.hair } }, t))), live && on(nowS) && (_jsxs(_Fragment, { children: [_jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, right: 0, top: 0, bottom: 0, background: C.panelBg } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 0, bottom: 0, width: 1, background: C.text, zIndex: 1 } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 2, transform: 'translateX(-50%)', fontSize: 8.5, background: C.text, color: '#fff', padding: '0 5px', borderRadius: 2, zIndex: 2, fontFamily: mono }, children: "now" })] }))] }),
|
|
502
|
+
}, children: "\u27F3 follow live" })), _jsxs("div", { style: { position: 'absolute', left: GUTTER, right: 0, top: 0, bottom: 0, pointerEvents: 'none' }, children: [ticks.map((t) => (_jsx("div", { style: { position: 'absolute', left: px(t) - GUTTER, top: 0, bottom: 0, width: 1, background: t % (step * 3) === 0 ? C.border : C.hair } }, t))), live && on(nowS) && (_jsxs(_Fragment, { children: [_jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, right: 0, top: 0, bottom: 0, background: C.panelBg } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 0, bottom: 0, width: 1, background: C.text, zIndex: 1 } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 2, transform: 'translateX(-50%)', fontSize: 8.5, background: C.text, color: '#fff', padding: '0 5px', borderRadius: 2, zIndex: 2, fontFamily: mono }, children: "now" })] }))] }), (() => {
|
|
503
|
+
// Fork topology, drawn. Pure px()/ROW_H geometry — no DOM reads —
|
|
504
|
+
// and absolutely positioned INSIDE the scroll container, so curves
|
|
505
|
+
// ride with their rows through scroll, pan, and every resize.
|
|
506
|
+
const rows = [];
|
|
507
|
+
if (m.trunk.length > 0)
|
|
508
|
+
rows.push('session');
|
|
509
|
+
if (m.spine)
|
|
510
|
+
rows.push('spine');
|
|
511
|
+
for (const l of lanes)
|
|
512
|
+
rows.push(l.agentId);
|
|
513
|
+
const rowIdx = new Map(rows.map((r, i) => [r, i]));
|
|
514
|
+
const yMid = (r) => rowIdx.get(r) * ROW_H + 19;
|
|
515
|
+
const paths = [];
|
|
516
|
+
if (m.spine && rowIdx.has('spine')) {
|
|
517
|
+
const sx = px(secOf(m.spine.spineAt ?? m.spine.at));
|
|
518
|
+
// Warm lineage: the session's conversation feeds the spine.
|
|
519
|
+
if (rowIdx.has('session') && (m.spine.inherited ?? 0) > 0 && sx >= GUTTER) {
|
|
520
|
+
const sy = rowIdx.get('session') * ROW_H + 22;
|
|
521
|
+
const ty = rowIdx.get('spine') * ROW_H + 19;
|
|
522
|
+
const e = sx - 10;
|
|
523
|
+
const r = 4;
|
|
524
|
+
paths.push(_jsx("path", { d: `M ${sx} ${sy} L ${e + r} ${sy} Q ${e} ${sy} ${e} ${sy + r} L ${e} ${ty - r} Q ${e} ${ty} ${e + r} ${ty} L ${sx - 2} ${ty}`, stroke: "#9aa0a6", strokeWidth: "1.3", fill: "none" }, "warm"));
|
|
525
|
+
}
|
|
526
|
+
// Every lane hangs off the spine at its true spawn moment.
|
|
527
|
+
const spineRow = rowIdx.get('spine');
|
|
528
|
+
for (const l of lanes) {
|
|
529
|
+
// Only lanes that forked AFTER the spine existed hang off it —
|
|
530
|
+
// a planner forks from the session, and the pane draws no
|
|
531
|
+
// parentage it does not know.
|
|
532
|
+
if (m.spine.spineAt === null || l.spawnedAt + 250 < m.spine.spineAt)
|
|
533
|
+
continue;
|
|
534
|
+
const x = px(secOf(l.spawnedAt));
|
|
535
|
+
if (x < GUTTER || !on(secOf(l.spawnedAt)))
|
|
536
|
+
continue;
|
|
537
|
+
const laneRow = rowIdx.get(l.agentId);
|
|
538
|
+
// Nested elbows: drop at a small left offset (wider for deeper
|
|
539
|
+
// rows, so simultaneous forks read as nested guides), rounded
|
|
540
|
+
// corner, horizontal entry into the bar's left edge.
|
|
541
|
+
const off = 8 + (laneRow - spineRow - 1) * 5;
|
|
542
|
+
const sy = spineRow * ROW_H + 23;
|
|
543
|
+
const ty = laneRow * ROW_H + 19;
|
|
544
|
+
const e = x - off;
|
|
545
|
+
const r = 4;
|
|
546
|
+
paths.push(_jsx("path", { d: `M ${x} ${sy} L ${e + r} ${sy} Q ${e} ${sy} ${e} ${sy + r} L ${e} ${ty - r} Q ${e} ${ty} ${e + r} ${ty} L ${x - 2} ${ty}`, stroke: "#9aa0a6", strokeWidth: "1.3", fill: "none" }, `f${l.agentId}`));
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
// DAG dependency edges — declared by the orchestrator, never inferred.
|
|
550
|
+
for (const l of lanes) {
|
|
551
|
+
for (const dep of l.after ?? []) {
|
|
552
|
+
const d = m.lanes.get(dep);
|
|
553
|
+
if (!d || d.doneAt === null || !rowIdx.has(dep))
|
|
554
|
+
continue;
|
|
555
|
+
const x2 = px(secOf(l.spawnedAt));
|
|
556
|
+
if (x2 < GUTTER)
|
|
557
|
+
continue;
|
|
558
|
+
const x1 = Math.max(px(secOf(d.doneAt)), GUTTER);
|
|
559
|
+
const y1 = yMid(dep);
|
|
560
|
+
const y2 = yMid(l.agentId);
|
|
561
|
+
const e = Math.max(x2 - 8, x1 + 4);
|
|
562
|
+
const r = 4;
|
|
563
|
+
const vdir = y2 > y1 ? 1 : -1;
|
|
564
|
+
paths.push(_jsx("path", { d: `M ${x1} ${y1} L ${e - r} ${y1} Q ${e} ${y1} ${e} ${y1 + r * vdir} L ${e} ${y2 - r * vdir} Q ${e} ${y2} ${e + r} ${y2} L ${x2} ${y2}`, stroke: "#9aa0a6", strokeWidth: "1.2", strokeDasharray: "4 3", fill: "none" }, `d${dep}-${l.agentId}`));
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (paths.length === 0)
|
|
568
|
+
return null;
|
|
569
|
+
return (_jsx("svg", { width: "100%", height: rows.length * ROW_H, style: { position: 'absolute', left: 0, top: 0, pointerEvents: 'none', zIndex: 1 }, children: paths }));
|
|
570
|
+
})(), m.trunk.length > 0 && (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => onSelect(selAgent === 'trunk' ? null : 'trunk'), onKeyDown: keyActivate(() => onSelect(selAgent === 'trunk' ? null : 'trunk')), style: {
|
|
571
|
+
position: 'relative', height: ROW_H, display: 'flex', cursor: 'pointer',
|
|
572
|
+
borderBottom: `1px solid ${C.hair}`,
|
|
573
|
+
background: selAgent === 'trunk' ? C.chromeBg : undefined,
|
|
574
|
+
boxShadow: selAgent === 'trunk' ? `inset 3px 0 0 ${C.text}` : undefined,
|
|
575
|
+
}, children: [_jsxs("div", { style: { width: GUTTER, flex: 'none', display: 'flex', alignItems: 'baseline', gap: 6, padding: '12px 0 0 14px', fontSize: 11.5 }, children: [_jsx("span", { style: { fontWeight: 600 }, children: "session" }), _jsxs("span", { style: { color: C.dim, fontSize: 10.5, fontFamily: mono }, children: [m.trunk.length, " turn", m.trunk.length === 1 ? '' : 's'] })] }), _jsx("div", { style: { flex: 1, position: 'relative', overflow: 'hidden' }, children: m.trunk.map((t, i) => {
|
|
576
|
+
const s = secOf(t.at);
|
|
577
|
+
if (!on(s))
|
|
578
|
+
return null;
|
|
579
|
+
// One diamond per side, colored by who spoke; a committed
|
|
580
|
+
// exchange ('turn') lands both at once and shows the pair.
|
|
581
|
+
const sides = t.speaker === 'turn' ? [TRUNK_QUERY, TRUNK_RESPONSE]
|
|
582
|
+
: t.speaker === 'user' ? [TRUNK_QUERY]
|
|
583
|
+
: t.speaker === 'tool' ? [TRUNK_TOOL]
|
|
584
|
+
: [TRUNK_RESPONSE];
|
|
585
|
+
return (_jsxs("span", { title: (t.query ?? t.content).slice(0, 200), children: [sides.map((c, j) => (_jsx("span", { style: {
|
|
586
|
+
position: 'absolute', left: px(s) - GUTTER - 5 + j * 9, top: 13, width: 10, height: 10,
|
|
587
|
+
borderRadius: 2, transform: 'rotate(45deg)', background: c, display: 'inline-block',
|
|
588
|
+
} }, j))), t.attachments.length > 0 && (_jsxs("span", { style: { position: 'absolute', left: px(s) - GUTTER + (sides.length > 1 ? 17 : 8), top: 11, fontSize: 9.5, color: C.dim }, children: ["\uD83D\uDCCE", t.attachments.length] }))] }, i));
|
|
589
|
+
}) })] })), m.spine && (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => onSelect(selAgent === 'spine' ? null : 'spine'), onKeyDown: keyActivate(() => onSelect(selAgent === 'spine' ? null : 'spine')), style: {
|
|
590
|
+
position: 'relative', height: ROW_H, display: 'flex', cursor: 'pointer',
|
|
591
|
+
borderBottom: `1px solid ${C.hair}`,
|
|
592
|
+
background: selAgent === 'spine' ? C.chromeBg : undefined,
|
|
593
|
+
boxShadow: selAgent === 'spine' ? `inset 3px 0 0 ${C.text}` : undefined,
|
|
594
|
+
}, children: [_jsxs("div", { style: { width: GUTTER, flex: 'none', display: 'flex', alignItems: 'baseline', gap: 6, padding: '12px 0 0 14px', fontSize: 11.5 }, children: [_jsx("span", { style: { fontWeight: 600 }, children: "spine" }), _jsx("span", { style: { color: C.dim, fontSize: 10.5, fontFamily: mono }, children: (m.spine.spineCells || m.spine.headerTokens) > 0
|
|
595
|
+
? `${(m.spine.spineCells || m.spine.headerTokens).toLocaleString()} tokens` : 'seeding…' })] }), _jsx("div", { style: { flex: 1, position: 'relative', overflow: 'hidden' }, children: (() => {
|
|
596
|
+
// The spine as a BAR — alive for the whole run — with a tick
|
|
597
|
+
// wherever it grew (the seed, then each extension).
|
|
598
|
+
const s0 = secOf(m.spine.spineAt ?? m.spine.at);
|
|
599
|
+
const x0 = Math.max(px(s0), GUTTER);
|
|
600
|
+
const x1 = Math.max(px(Math.min(endS, w1)), x0 + 4);
|
|
601
|
+
if (px(s0) > px(w1))
|
|
602
|
+
return null;
|
|
603
|
+
return (_jsxs("span", { title: (m.spine.query ?? '').slice(0, 200), children: [_jsx("span", { style: {
|
|
604
|
+
position: 'absolute', top: 15, height: 8, left: x0 - GUTTER, width: x1 - x0,
|
|
605
|
+
background: '#e3e6ea', borderRadius: 4, border: `1px solid ${C.hair}`, display: 'inline-block',
|
|
606
|
+
} }), m.spine.growth.map((g, gi) => {
|
|
607
|
+
const gs = secOf(g.at);
|
|
608
|
+
if (!on(gs))
|
|
609
|
+
return null;
|
|
610
|
+
return (_jsx("span", { title: `+${g.tokens.toLocaleString()} tokens`, style: { position: 'absolute', left: px(gs) - GUTTER, top: 13, width: 2, height: 12, background: C.text } }, gi));
|
|
611
|
+
}), m.spine.attachments.length > 0 && (_jsxs("span", { style: { position: 'absolute', left: x0 - GUTTER + 6, top: 11, fontSize: 9.5, color: C.dim }, children: ["\uD83D\uDCCE", m.spine.attachments.length] }))] }));
|
|
612
|
+
})() })] })), lanes.map((l) => (_jsx(Lane, { m: m, l: l, px: px, on: on, secOf: secOf, nowS: nowS, live: live, selected: selAgent === l.agentId, toolColor: toolColor, onClick: () => onSelect(selAgent === l.agentId ? null : l.agentId), gutter: GUTTER, windowEnd: w1 }, l.agentId)))] })] }));
|
|
500
613
|
}
|
|
501
614
|
const label = {
|
|
502
615
|
fontSize: 10, fontWeight: 600, letterSpacing: '.06em', textTransform: 'uppercase', color: '#b0b6c2',
|
|
@@ -542,7 +655,7 @@ function Lane({ m, l, px, on, secOf, nowS, live, selected, toolColor, onClick, g
|
|
|
542
655
|
: l.outcome === 'failed' ? `${l.failReason ?? l.dropReason ?? 'failed'} · ${fmtS(e - s)}` : fmtS(e - s);
|
|
543
656
|
const endColor = l.outcome === 'failed' ? C.fail : l.outcome === 'recovered' ? C.agent : '#3c4043';
|
|
544
657
|
return (_jsxs("div", { onClick: onClick, role: "button", tabIndex: 0, onKeyDown: keyActivate(onClick), "aria-label": `open agent ${l.agentId}`, style: {
|
|
545
|
-
display: 'flex', height:
|
|
658
|
+
display: 'flex', height: ROW_H, borderTop: `1px solid ${C.hair}`, position: 'relative', cursor: 'pointer',
|
|
546
659
|
background: selected ? C.chromeBg : cancelled ? 'rgba(179,38,30,.05)' : undefined,
|
|
547
660
|
boxShadow: selected ? `inset 3px 0 0 ${C.text}` : undefined,
|
|
548
661
|
}, children: [cancelled && (_jsx("span", { style: {
|
|
@@ -812,7 +925,125 @@ function AgentFeed({ m, lane, toolColor, onClose, onJump, nowMs, width, send, ca
|
|
|
812
925
|
}, children: [_jsxs("div", { style: {
|
|
813
926
|
height: 30, flex: 'none', display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px',
|
|
814
927
|
borderBottom: `1px solid ${C.border}`, background: '#f8f9fa',
|
|
815
|
-
}, children: [_jsxs("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: [lane.role ?? 'agent', " #", lane.agentId] }), lane.parentAgentId !== null && m.lanes.has(lane.parentAgentId) && (_jsxs("span", { style: chip, children: ["forked from #", lane.parentAgentId] })), _jsxs("span", { style: chip, children: [lane.outcome, lane.doneAt !== null && m.runStartAt !== null ? ` · ${fmtS((lane.doneAt - lane.spawnedAt) / 1000)}` : ''] }), _jsx("span", { style: { flex: 1 } }), canCancel && lane.doneAt === null && (_jsx("button", { onClick: () => send({ type: 'cancel_agent', agentId: lane.agentId }), "aria-label": "cancel this agent", title: "cancel this agent \u2014 its branch is reclaimed; siblings continue. Works while paused: evaluate trajectories, cull, play", style: { ...runBtn, color: C.fail, borderColor: '#f0c4c1', padding: '2px 7px', display: 'inline-flex', alignItems: 'center' }, children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("polyline", { points: "3 6 5 6 21 6" }), _jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), _jsx("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), _jsx("line", { x1: "14", y1: "11", x2: "14", y2: "17" })] }) })), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: [_jsx(EpistemicsChart, { m: m, lane: lane, nowMs: nowMs }), lane.prompt && (_jsxs("div", { style: { borderBottom: `1px solid ${C.border}`, padding: '4px 12px 6px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => toggle('prompt'), onKeyDown: keyActivate(() => toggle('prompt')), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the compiled prompt suffix that seeded this agent. In shared-spine mode the system + tool header lives on the spine PREFIX (inherited via fork) and is not repeated here; recursive agents inherit further parent context the same way", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: expanded.has('prompt') ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "prompt" }), _jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [lane.prompt.tokenCount.toLocaleString(), " tok"] })] }), expanded.has('prompt') && _jsx(JsonBlock, { text: lane.prompt.text, raw: true })] })), (lane.failReason || lane.dropReason) && (_jsxs("div", { style: { display: 'flex', alignItems: 'baseline', padding: '6px 12px', gap: 8 }, children: [_jsx("span", { style: { color: C.dim, width: 92, flex: 'none' }, children: "pool said" }), _jsx("span", { style: { fontFamily: mono, fontSize: 11 }, children: lane.dropReason ?? lane.failReason })] })), items.map((it) => it.el), planView, lane.role !== 'planner' && (lane.report !== null || lane.outcome === 'failed') && (_jsxs("div", { style: feedItem, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 7, cursor: 'pointer' }, onClick: () => toggle('report'), children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: reportOpen ? '▾' : '▸' }), _jsx("b", { style: { fontSize: 11 }, children: "report" }), _jsx("span", { style: { color: C.faint }, children: lane.report === null ? 'not delivered' : lane.reportSource === 'recovery' ? 'extracted by recovery' : 'delivered' })] }), reportOpen && lane.report !== null && (
|
|
928
|
+
}, children: [_jsxs("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: [lane.role ?? 'agent', " #", lane.agentId] }), lane.parentAgentId !== null && m.lanes.has(lane.parentAgentId) && (_jsxs("span", { style: chip, children: ["forked from #", lane.parentAgentId] })), _jsxs("span", { style: chip, children: [lane.outcome, lane.doneAt !== null && m.runStartAt !== null ? ` · ${fmtS((lane.doneAt - lane.spawnedAt) / 1000)}` : ''] }), _jsx("span", { style: { flex: 1 } }), canCancel && lane.doneAt === null && (_jsx("button", { onClick: () => send({ type: 'cancel_agent', agentId: lane.agentId }), "aria-label": "cancel this agent", title: "cancel this agent \u2014 its branch is reclaimed; siblings continue. Works while paused: evaluate trajectories, cull, play", style: { ...runBtn, color: C.fail, borderColor: '#f0c4c1', padding: '2px 7px', display: 'inline-flex', alignItems: 'center' }, children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("polyline", { points: "3 6 5 6 21 6" }), _jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), _jsx("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), _jsx("line", { x1: "14", y1: "11", x2: "14", y2: "17" })] }) })), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: [_jsx(EpistemicsChart, { m: m, lane: lane, nowMs: nowMs }), lane.prompt && (_jsxs("div", { style: { borderBottom: `1px solid ${C.border}`, padding: '4px 12px 6px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => toggle('prompt'), onKeyDown: keyActivate(() => toggle('prompt')), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the compiled prompt suffix that seeded this agent. In shared-spine mode the system + tool header lives on the spine PREFIX (inherited via fork) and is not repeated here; recursive agents inherit further parent context the same way", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: expanded.has('prompt') ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "prompt" }), _jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [lane.prompt.tokenCount.toLocaleString(), " tok"] })] }), expanded.has('prompt') && _jsx(JsonBlock, { text: lane.prompt.text, raw: true })] })), (lane.failReason || lane.dropReason) && (_jsxs("div", { style: { display: 'flex', alignItems: 'baseline', padding: '6px 12px', gap: 8 }, children: [_jsx("span", { style: { color: C.dim, width: 92, flex: 'none' }, children: "pool said" }), _jsx("span", { style: { fontFamily: mono, fontSize: 11 }, children: lane.dropReason ?? lane.failReason })] })), items.map((it) => it.el), planView, lane.role !== 'planner' && (lane.report !== null || lane.outcome === 'failed') && (_jsxs("div", { style: feedItem, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 7, cursor: 'pointer' }, onClick: () => toggle('report'), children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: reportOpen ? '▾' : '▸' }), _jsx("b", { style: { fontSize: 11 }, children: "report" }), _jsx("span", { style: { color: C.faint }, children: lane.report === null ? 'not delivered' : lane.reportSource === 'recovery' ? 'extracted by recovery' : 'delivered' })] }), reportOpen && lane.report !== null && (() => {
|
|
929
|
+
// Raw <think> never renders — the report splits into the
|
|
930
|
+
// shared reasoning box + what the agent actually said.
|
|
931
|
+
const { reasoning, said } = splitThink(lane.report);
|
|
932
|
+
return (_jsxs("div", { style: { margin: '6px 0 2px 16px' }, children: [reasoning && _jsx(Reasoning, { text: reasoning, open: expanded.has('report-reasoning'), onToggle: () => toggle('report-reasoning') }), _jsx("div", { style: { lineHeight: 1.5, color: '#3c4043', whiteSpace: 'pre-wrap' }, children: said })] }));
|
|
933
|
+
})()] }))] })] }));
|
|
934
|
+
}
|
|
935
|
+
/** One timeline row — session, spine, and every lane share it. The
|
|
936
|
+
* connector overlay derives its geometry from this same constant, which is
|
|
937
|
+
* what makes curves survive any resize without DOM measurement. */
|
|
938
|
+
const ROW_H = 38;
|
|
939
|
+
/** Trunk marker colors — one per conversation side, same family as the
|
|
940
|
+
* lanes: the query is the deep blue everything forks from, the response the
|
|
941
|
+
* light one. Tools are grey. */
|
|
942
|
+
const TRUNK_QUERY = '#174ea6';
|
|
943
|
+
const TRUNK_RESPONSE = '#5f8fd9';
|
|
944
|
+
const TRUNK_TOOL = '#9aa0a6';
|
|
945
|
+
/** Split verbatim model text into its reasoning and its said text. The pane
|
|
946
|
+
* never renders raw `<think>` markup anywhere — reasoning is shown behind
|
|
947
|
+
* {@link Reasoning}. An unclosed block (a cut stream) still splits clean. */
|
|
948
|
+
function splitThink(text) {
|
|
949
|
+
const parts = text.split(/<think>([\s\S]*?)(?:<\/think>|$)/);
|
|
950
|
+
return {
|
|
951
|
+
reasoning: parts.filter((_, k) => k % 2 === 1).join('\n').trim(),
|
|
952
|
+
said: parts.filter((_, k) => k % 2 === 0).join('').trim(),
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
/** The expandable reasoning box — one look for every surface that carries
|
|
956
|
+
* model thinking (trunk turns, agent reports). Collapsed by default. */
|
|
957
|
+
function Reasoning({ text, open, onToggle }) {
|
|
958
|
+
return (_jsxs("div", { style: { margin: '0 0 4px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: onToggle, onKeyDown: keyActivate(onToggle), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: open ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "reasoning" })] }), open && (_jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: C.dim, fontFamily: mono, fontSize: 10.5, maxHeight: 240, overflowY: 'auto', margin: '2px 0 0 16px' }, children: text }))] }));
|
|
959
|
+
}
|
|
960
|
+
/** The spine's feed — the run's root: the user's instruction verbatim
|
|
961
|
+
* (only when the harness declared where it lives — see
|
|
962
|
+
* {@link RunFraming.instruction}), then the compiled header that seeded
|
|
963
|
+
* position 0. This is where a prompt survives when a run fails. */
|
|
964
|
+
function SpineFeed({ m, onClose, width, mediaUrl, toolColor }) {
|
|
965
|
+
// Substance visible by default — only the raw bytes stay behind a click.
|
|
966
|
+
const [headerOpen, setHeaderOpen] = useState(true);
|
|
967
|
+
const [compiledOpen, setCompiledOpen] = useState(false);
|
|
968
|
+
const k = m.spine;
|
|
969
|
+
if (!k)
|
|
970
|
+
return null;
|
|
971
|
+
return (_jsxs("div", { style: {
|
|
972
|
+
width, flex: 'none', borderLeft: '1px solid #d9dce1', display: 'flex',
|
|
973
|
+
flexDirection: 'column', minHeight: 0, background: C.panelBg,
|
|
974
|
+
}, children: [_jsxs("div", { style: {
|
|
975
|
+
height: 30, flex: 'none', display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px',
|
|
976
|
+
borderBottom: `1px solid ${C.border}`, background: '#f8f9fa',
|
|
977
|
+
}, children: [_jsx("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: "spine" }), _jsx("span", { style: chip, children: "shared agent memory" }), k.inherited !== undefined && (_jsx("span", { style: chip, children: k.inherited > 0 ? `warm · ${k.inherited.toLocaleString()} tok from trunk` : 'cold start' })), k.headerTokens > 0 && (() => {
|
|
978
|
+
const nCtx = m.pressure.length > 0 ? m.pressure[m.pressure.length - 1].nCtx : 0;
|
|
979
|
+
const pct = nCtx > 0 ? Math.round((k.headerTokens / nCtx) * 1000) / 10 : null;
|
|
980
|
+
return _jsxs("span", { style: chip, children: [k.headerTokens.toLocaleString(), " tok", pct !== null ? ` · ${pct}% ctx` : ''] });
|
|
981
|
+
})(), _jsx("span", { style: { flex: 1 } }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: [k.query !== null && (_jsx("div", { style: feedItem, children: _jsxs("div", { style: { background: 'rgba(26,115,232,.05)', borderRadius: 4, padding: '6px 9px' }, children: [_jsxs("div", { style: { display: 'flex', gap: 7, alignItems: 'baseline', marginBottom: 3 }, children: [_jsx("b", { style: { fontSize: 11, color: TRUNK_QUERY }, children: "query" }), _jsx("span", { style: { fontSize: 10.5, color: C.faint }, children: "the user's instruction, as submitted" })] }), k.attachments.length > 0 && (_jsx("div", { style: { display: 'flex', gap: 6, flexWrap: 'wrap', margin: '2px 0 6px' }, children: k.attachments.map((a, j) => mediaUrl ? (_jsx("img", { src: mediaUrl(a.digest), alt: a.digest.slice(0, 12), title: `${a.digest.slice(0, 19)}\u2026`, style: { height: 72, maxWidth: 160, objectFit: 'cover', borderRadius: 4, border: `1px solid ${C.border}` } }, j)) : (_jsxs("span", { style: chip, title: a.digest, children: [a.digest.slice(0, 19), "\\u2026"] }, j))) })), _jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: '#3c4043', fontSize: 11.5, maxHeight: 200, overflowY: 'auto' }, children: k.query })] }) })), (k.tools && k.tools.length > 0) || k.systemText || k.headerText ? (_jsxs("div", { style: { borderBottom: `1px solid ${C.border}`, padding: '4px 12px 6px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => setHeaderOpen((v) => !v), onKeyDown: keyActivate(() => setHeaderOpen((v) => !v)), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the shared header prefilled at position 0 \u2014 every agent inherits it via fork", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: headerOpen ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "system + tools" })] }), headerOpen && (_jsxs("div", { style: { margin: '4px 0 2px 16px', display: 'flex', flexDirection: 'column', gap: 8 }, children: [k.tools && k.tools.length > 0 && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: k.tools.map((t2) => (_jsxs("div", { style: { display: 'flex', gap: 8, alignItems: 'baseline' }, children: [_jsx("span", { style: { flex: 'none', transform: 'translateY(2px)' }, children: _jsx(Badge, { color: toolColor(t2.name), letter: letterOf(t2.name), size: 14 }) }), _jsx("b", { style: { fontFamily: mono, fontSize: 10.5, flex: 'none' }, children: t2.name }), _jsx("span", { style: { color: C.dim, fontSize: 11, lineHeight: 1.4, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }, title: t2.description, children: t2.description })] }, t2.name))) })), k.systemText && (_jsxs("div", { children: [_jsx("div", { style: { color: C.faint, fontSize: 10, marginBottom: 2 }, children: "system" }), _jsx("div", { style: { lineHeight: 1.5, color: '#3c4043', whiteSpace: 'pre-wrap', fontSize: 11.5, maxHeight: 220, overflowY: 'auto' }, children: k.systemText })] })), k.headerText && (_jsxs("div", { children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => setCompiledOpen((v) => !v), onKeyDown: keyActivate(() => setCompiledOpen((v) => !v)), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the exact rendered template \u2014 what position 0 actually holds", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: compiledOpen ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "compiled" })] }), compiledOpen && _jsx(JsonBlock, { text: k.headerText, raw: true })] }))] })), (() => {
|
|
982
|
+
// Full accrual: what every fork inherited for free, minus the
|
|
983
|
+
// one shared copy actually prefilled this run. Correct for
|
|
984
|
+
// chain extensions, warm trunk inheritance, and recursive
|
|
985
|
+
// forks — parallel degenerates to header × (n − 1).
|
|
986
|
+
// Only lanes that actually forked the spine count as sharers —
|
|
987
|
+
// the same attribution the connectors draw. A pre-spine lane
|
|
988
|
+
// (the planner) never inherited it and never shows here.
|
|
989
|
+
// Saved follows the cache-read convention: every token an agent
|
|
990
|
+
// forked instead of prefilling counts. The spine's own build is
|
|
991
|
+
// the cache write — never netted out of the headline.
|
|
992
|
+
const sharers = [...m.lanes.values()].filter((l2) => l2.inherited !== undefined);
|
|
993
|
+
const saved = sharers.reduce((n2, l2) => n2 + (l2.inherited ?? 0), 0);
|
|
994
|
+
if (saved <= 0 && sharers.length < 2)
|
|
995
|
+
return null;
|
|
996
|
+
return (_jsxs("div", { style: { padding: '5px 0 1px 16px', fontSize: 11, color: C.dim }, children: [sharers.length >= 2 && (_jsxs(_Fragment, { children: ["shared by ", _jsx("span", { style: { fontFamily: mono }, children: sharers.length }), " agents", saved > 0 ? ' · ' : ''] })), saved > 0 && (_jsxs(_Fragment, { children: ["tokens saved ", _jsx("span", { style: { fontFamily: mono }, children: saved.toLocaleString() })] }))] }));
|
|
997
|
+
})()] })) : null] })] }));
|
|
998
|
+
}
|
|
999
|
+
/** The trunk's feed — the same panel grammar as {@link AgentFeed}, for the
|
|
1000
|
+
* session's own conversation: each `warmDelta` turn verbatim, its KV cost,
|
|
1001
|
+
* and the media that entered with it (thumbnails when the bridge exposes a
|
|
1002
|
+
* content resolver, digest chips otherwise). */
|
|
1003
|
+
function TrunkFeed({ m, onClose, width, mediaUrl }) {
|
|
1004
|
+
const [thinkOpen, setThinkOpen] = useState(() => new Set());
|
|
1005
|
+
// Responses default COLLAPSED — stats stay visible, the body (reasoning +
|
|
1006
|
+
// text) expands on click. A committed exchange's response half can be a
|
|
1007
|
+
// whole brief; the feed must not pay its render until asked.
|
|
1008
|
+
const [respOpen, setRespOpen] = useState(() => new Set());
|
|
1009
|
+
const toggleResp = (i) => {
|
|
1010
|
+
setRespOpen((prev) => {
|
|
1011
|
+
const next = new Set(prev);
|
|
1012
|
+
if (next.has(i))
|
|
1013
|
+
next.delete(i);
|
|
1014
|
+
else
|
|
1015
|
+
next.add(i);
|
|
1016
|
+
return next;
|
|
1017
|
+
});
|
|
1018
|
+
};
|
|
1019
|
+
const toggleThink = (i) => {
|
|
1020
|
+
setThinkOpen((prev) => {
|
|
1021
|
+
const next = new Set(prev);
|
|
1022
|
+
if (next.has(i))
|
|
1023
|
+
next.delete(i);
|
|
1024
|
+
else
|
|
1025
|
+
next.add(i);
|
|
1026
|
+
return next;
|
|
1027
|
+
});
|
|
1028
|
+
};
|
|
1029
|
+
return (_jsxs("div", { style: {
|
|
1030
|
+
width, flex: 'none', borderLeft: '1px solid #d9dce1', display: 'flex',
|
|
1031
|
+
flexDirection: 'column', minHeight: 0, background: C.panelBg,
|
|
1032
|
+
}, children: [_jsxs("div", { style: {
|
|
1033
|
+
height: 30, flex: 'none', display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px',
|
|
1034
|
+
borderBottom: `1px solid ${C.border}`, background: '#f8f9fa',
|
|
1035
|
+
}, children: [_jsx("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: "session" }), _jsx("span", { style: chip, children: "the conversation" }), _jsx("span", { style: { flex: 1 } }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsx("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: m.trunk.map((t, i) => {
|
|
1036
|
+
// Query and response render as their OWN blocks — a committed
|
|
1037
|
+
// exchange (`speaker: 'turn'`) carries both halves structurally,
|
|
1038
|
+
// and single-sided deltas carry one. Raw <think> never renders:
|
|
1039
|
+
// the response side splits into the shared reasoning box.
|
|
1040
|
+
const isTurn = t.speaker === 'turn';
|
|
1041
|
+
const q = isTurn ? (t.query ?? '') : t.speaker === 'user' ? t.content : '';
|
|
1042
|
+
const rRaw = isTurn ? (t.response ?? '') : (t.speaker === 'assistant' || t.speaker === 'tool' || t.speaker === undefined) ? t.content : '';
|
|
1043
|
+
const { reasoning, said } = splitThink(rRaw);
|
|
1044
|
+
const meta = (_jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [t.cells.toLocaleString(), " tokens"] }));
|
|
1045
|
+
return (_jsxs("div", { style: feedItem, children: [(q || t.attachments.length > 0) && (_jsxs("div", { style: { background: 'rgba(26,115,232,.05)', borderRadius: 4, padding: '6px 9px', margin: '0 0 6px' }, children: [_jsxs("div", { style: { display: 'flex', gap: 7, alignItems: 'baseline', marginBottom: 3 }, children: [_jsx("b", { style: { fontSize: 11, color: C.agentDark }, children: "query" }), meta] }), t.attachments.length > 0 && (_jsx("div", { style: { display: 'flex', gap: 6, flexWrap: 'wrap', margin: '2px 0 6px' }, children: t.attachments.map((a, j) => mediaUrl ? (_jsx("img", { src: mediaUrl(a.digest), alt: a.mediaType ?? a.digest.slice(0, 12), title: `${a.mediaType ?? 'media'} · ${a.digest.slice(0, 19)}…`, style: { height: 72, maxWidth: 160, objectFit: 'cover', borderRadius: 4, border: `1px solid ${C.border}` } }, j)) : (_jsxs("span", { style: chip, title: a.digest, children: [a.mediaType ?? 'media', " \u00B7 ", a.digest.slice(0, 19), "\u2026"] }, j))) })), q && (_jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: '#3c4043', fontFamily: mono, fontSize: 10.5, maxHeight: 200, overflowY: 'auto' }, children: q }))] })), rRaw && (_jsxs("div", { children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => toggleResp(i), onKeyDown: keyActivate(() => toggleResp(i)), style: { display: 'flex', gap: 7, alignItems: 'baseline', marginBottom: 3, cursor: 'pointer' }, children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: respOpen.has(i) ? '\u25be' : '\u25b8' }), _jsx("b", { style: { fontSize: 11, color: TRUNK_RESPONSE }, children: t.speaker === 'tool' ? 'tool' : 'response' }), !q && meta, (t.agentTokens ?? 0) > 0 && (_jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [t.agentTokens.toLocaleString(), " tokens"] })), t.wallMs !== undefined && (_jsx("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: fmtS(t.wallMs / 1000) }))] }), respOpen.has(i) && (_jsxs("div", { style: { margin: '0 0 0 16px' }, children: [reasoning && _jsx(Reasoning, { text: reasoning, open: thinkOpen.has(i), onToggle: () => toggleThink(i) }), said && (_jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: '#3c4043', fontFamily: mono, fontSize: 10.5, maxHeight: 300, overflowY: 'auto' }, children: said }))] }))] }))] }, i));
|
|
1046
|
+
}) })] }));
|
|
816
1047
|
}
|
|
817
1048
|
const feedItem = { padding: '7px 12px', borderTop: '1px solid #eceef1' };
|
|
818
1049
|
const chip = {
|
|
@@ -901,69 +1132,19 @@ const cutline = {
|
|
|
901
1132
|
borderTop: '1px dashed #dadce0', marginTop: 6,
|
|
902
1133
|
};
|
|
903
1134
|
// ═══ Settings: category nav → harness (master list + detail) · ability pages ═══
|
|
904
|
-
/** What the detail panel knows about each well-known harness key: what it is,
|
|
905
|
-
* and how to change it. Prose is product copy — one clause per sentence. */
|
|
906
|
-
/** Config path → the ConfigOrigin field carrying its rung, so the
|
|
907
|
-
* exception note (env/cli overrode the manifest) fires for read-only rows
|
|
908
|
-
* too — full-rung provenance display stays demoted by design. */
|
|
909
|
-
const ORIGIN_KEYS = {
|
|
910
|
-
'model.path': 'modelPath',
|
|
911
|
-
'model.reranker': 'reranker',
|
|
912
|
-
'model.nCtx': 'nCtx',
|
|
913
|
-
'model.gpu': 'gpu',
|
|
914
|
-
'sources.outputDir': 'outputDir',
|
|
915
|
-
'defaults.reasoningMode': 'reasoningMode',
|
|
916
|
-
};
|
|
917
|
-
const SETTING_META = {
|
|
918
|
-
'defaults.effort': {
|
|
919
|
-
desc: 'Run effort preset — agent budget, planner breadth, recovery cap.',
|
|
920
|
-
how: 'Change it here; it applies to your next run and is remembered locally. The committed default lives in harness.yml → defaults.effort.',
|
|
921
|
-
},
|
|
922
|
-
'defaults.reasoningMode': {
|
|
923
|
-
desc: 'flat runs one research wave over the plan; deep lets agents recurse into sub-plans.',
|
|
924
|
-
how: 'Change it here; it applies to your next run.',
|
|
925
|
-
},
|
|
926
|
-
'sources.outputDir': {
|
|
927
|
-
desc: 'Where per-query run-dirs and the session trace are written. Empty means where the harness started.',
|
|
928
|
-
how: 'Edit harness.yml → sources.outputDir; the next run picks it up.',
|
|
929
|
-
},
|
|
930
|
-
'defaults.maxTurns': {
|
|
931
|
-
desc: 'Turn cap per agent run.',
|
|
932
|
-
how: 'Edit harness.yml → defaults.maxTurns; the next run picks it up.',
|
|
933
|
-
},
|
|
934
|
-
'model.path': {
|
|
935
|
-
desc: 'Filesystem path or catalog id of the reasoning model.',
|
|
936
|
-
how: 'Saved changes load at the next start; this run keeps the model it booted with.',
|
|
937
|
-
},
|
|
938
|
-
'model.reranker': {
|
|
939
|
-
desc: 'The admission judge — a pointwise yes/no reranker that gates what enters the context.',
|
|
940
|
-
how: 'Saved changes load at the next start.',
|
|
941
|
-
},
|
|
942
|
-
'model.nCtx': {
|
|
943
|
-
desc: 'Context window of the one shared llama_context — every branch leases cells out of this budget.',
|
|
944
|
-
how: 'Edit harness.yml → model.llm.context, then restart.',
|
|
945
|
-
},
|
|
946
|
-
'model.branches': {
|
|
947
|
-
desc: 'Concurrent sequences — createContext takes it as nSeqMax. Each sequence holds its own KV lease.',
|
|
948
|
-
how: 'Edit harness.yml → model.llm.branches, then restart.',
|
|
949
|
-
},
|
|
950
|
-
'model.kvCache': {
|
|
951
|
-
desc: 'KV cache type for the attention layers — raise for precision, lower for memory.',
|
|
952
|
-
how: 'Edit harness.yml → model.llm.kvCache, then restart.',
|
|
953
|
-
},
|
|
954
|
-
'model.gpu': {
|
|
955
|
-
desc: 'Which native backend the process loaded — picked once at start. A configured backend fails loud if unavailable, never silently CPU.',
|
|
956
|
-
how: 'A deploy choice: set harness.yml → model.llm.gpu (or LLOYAL_GPU), then restart.',
|
|
957
|
-
},
|
|
958
|
-
};
|
|
959
1135
|
const TIER_NOTE = {
|
|
960
1136
|
session: 'applies to the next run',
|
|
961
1137
|
reload: 'saved now — a restart loads it',
|
|
962
1138
|
boot: 'fixed for this run',
|
|
963
1139
|
};
|
|
964
|
-
function Settings({ m,
|
|
1140
|
+
function Settings({ m, config, send }) {
|
|
965
1141
|
const [cat, setCat] = useState('harness');
|
|
966
|
-
|
|
1142
|
+
// With a table the rows are the application's own keys; without one, whatever config the harness announced.
|
|
1143
|
+
const rows = config
|
|
1144
|
+
? configRows(config)
|
|
1145
|
+
: liveConfigKeys(m.config).map((key) => ({ key, applies: 'session', values: null }));
|
|
1146
|
+
// Open on the first thing that can be changed now, else the first that can be changed at all.
|
|
1147
|
+
const [selKey, setSelKey] = useState((rows.find((r) => r.values && r.applies === 'session') ?? rows.find((r) => r.values) ?? rows[0])?.key ?? '');
|
|
967
1148
|
// The nav lists INSTALLED abilities (`abilities:state` descriptors) — not
|
|
968
1149
|
// merely configured ones, or the page you'd use to configure an ability
|
|
969
1150
|
// could never appear. Harnesses that don't emit descriptors degrade to the
|
|
@@ -983,38 +1164,41 @@ function Settings({ m, controls, send }) {
|
|
|
983
1164
|
borderLeft: on ? `3px solid ${C.text}` : '3px solid transparent',
|
|
984
1165
|
}, children: name }, name));
|
|
985
1166
|
return (_jsxs("div", { style: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsxs("div", { style: { width: 148, flex: 'none', borderRight: '1px solid #d9dce1', paddingTop: 10, background: C.panelBg, overflowY: 'auto' }, children: [navItem('harness', cat === 'harness'), abilities.length > 0 && _jsx("div", { style: { ...label, padding: '12px 16px 3px' }, children: "abilities" }), abilities.map((a) => navItem(a, cat === a))] }), cat === 'harness'
|
|
986
|
-
? _jsx(HarnessSettings, { m: m,
|
|
1167
|
+
? _jsx(HarnessSettings, { m: m, rows: rows, tiered: config !== undefined, send: send, selKey: selKey, onSelect: setSelKey })
|
|
987
1168
|
: _jsx(AbilityPage, { m: m, name: cat, send: send })] }));
|
|
988
1169
|
}
|
|
989
|
-
function HarnessSettings({ m,
|
|
1170
|
+
function HarnessSettings({ m, rows, tiered, send, selKey, onSelect }) {
|
|
990
1171
|
const config = m.config;
|
|
991
|
-
const byTier = (tier) =>
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
return null; // skip-if-absent: basic has no defaults block
|
|
1172
|
+
const byTier = (tier) => rows.filter((r) => r.applies === tier);
|
|
1173
|
+
const row = (r) => {
|
|
1174
|
+
const { key } = r;
|
|
1175
|
+
const raw = readConfigPath(config, key); // a declared key the harness never set is still a row: its value is —
|
|
1176
|
+
// A value that is itself a table (an app's own structured key) is shown as it is written.
|
|
1177
|
+
const value = raw === undefined || raw === null ? undefined : typeof raw === 'object' ? JSON.stringify(raw) : String(raw);
|
|
998
1178
|
const selected = selKey === key;
|
|
1179
|
+
// Choosing the value already in force is a selection, never a command: on a reload row the command would
|
|
1180
|
+
// end the session to apply nothing.
|
|
1181
|
+
const choose = (v) => { onSelect(key); if (v === value)
|
|
1182
|
+
return; const command = configCommand(r, v); if (command)
|
|
1183
|
+
send(command); };
|
|
999
1184
|
return (_jsxs("div", { onClick: () => onSelect(key), role: "button", tabIndex: 0, onKeyDown: keyActivate(() => onSelect(key)), style: {
|
|
1000
1185
|
display: 'flex', alignItems: 'center', gap: 8, padding: '5px 14px 5px 11px', minHeight: 36,
|
|
1001
1186
|
borderLeft: selected ? `3px solid ${C.text}` : '3px solid transparent', cursor: 'pointer',
|
|
1002
1187
|
background: selected ? C.chromeBg : undefined,
|
|
1003
|
-
}, children: [_jsx("span", { style: { fontFamily: mono, fontSize: 11.5, fontWeight: 500 }, children: key }), _jsx("span", { style: { flex: 1 } }),
|
|
1188
|
+
}, children: [_jsx("span", { style: { fontFamily: mono, fontSize: 11.5, fontWeight: 500 }, children: key }), _jsx("span", { style: { flex: 1 } }), r.values ? (_jsx("span", { style: { display: 'flex', border: '1px solid #dadce0', borderRadius: 4, overflow: 'hidden', width: 276, flex: 'none' }, children: r.values.map((v) => (_jsx("span", { onClick: (e) => { e.stopPropagation(); choose(v); }, role: "button", tabIndex: 0, "aria-pressed": v === value, onKeyDown: keyActivate(() => choose(v)), style: {
|
|
1004
1189
|
flex: 1, fontSize: 11, padding: '5px 0', textAlign: 'center', cursor: 'pointer',
|
|
1005
1190
|
background: v === value ? C.text : '#fff', color: v === value ? '#fff' : C.dim,
|
|
1006
1191
|
fontWeight: v === value ? 500 : 400, borderLeft: '1px solid #e8eaed',
|
|
1007
|
-
}, children: v }, v))) })) : (_jsxs("span", { style: { fontFamily: mono, fontSize: 11, color: C.dim, maxWidth: 300, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [value === undefined || value ===
|
|
1192
|
+
}, children: v }, v))) })) : (_jsxs("span", { style: { fontFamily: mono, fontSize: 11, color: C.dim, maxWidth: 300, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [value === undefined || value === '' ? '—' : value, key === 'model.branches' && _jsx("span", { style: { color: C.faint }, children: " \u2192 nSeqMax" })] }))] }, key));
|
|
1008
1193
|
};
|
|
1009
1194
|
const head = (t) => (_jsxs("div", { style: { display: 'flex', alignItems: 'baseline', gap: 8, padding: '13px 14px 3px' }, children: [_jsx("span", { style: label, children: t }), _jsx("span", { style: { color: C.faint, fontSize: 10.5 }, children: TIER_NOTE[t] })] }));
|
|
1010
|
-
const
|
|
1011
|
-
const tier =
|
|
1195
|
+
const selected = rows.find((r) => r.key === selKey);
|
|
1196
|
+
const tier = tiered ? selected?.applies : undefined;
|
|
1012
1197
|
// The exception case, surfaced exactly when true: something outside the
|
|
1013
|
-
// manifest set this value. No badges anywhere else.
|
|
1014
|
-
const
|
|
1015
|
-
const origin = originKey && m.origin ? m.origin[originKey] : undefined;
|
|
1198
|
+
// manifest set this value. No badges anywhere else. Provenance is keyed by the config path itself.
|
|
1199
|
+
const origin = m.origin ? m.origin[selKey] : undefined;
|
|
1016
1200
|
const overridden = origin === 'env' || origin === 'cli';
|
|
1017
|
-
return (_jsxs(_Fragment, { children: [
|
|
1201
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { style: { flex: 1, minWidth: 0, overflowY: 'auto', paddingBottom: 10 }, children: tiered ? ['session', 'reload', 'boot'].map((t) => byTier(t).length > 0 && (_jsxs("div", { children: [head(t), byTier(t).map(row)] }, t))) : rows.map(row) }), _jsxs("div", { style: { width: 400, flex: 'none', borderLeft: '1px solid #d9dce1', overflowY: 'auto', padding: '16px 20px', background: C.panelBg }, children: [selected ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: { fontFamily: mono, fontSize: 13, fontWeight: 500 }, children: selKey }), tier && _jsx("span", { style: chip, children: TIER_NOTE[tier] })] }), selected.describe && (_jsx("p", { style: { maxWidth: 340, margin: '8px 0 0', fontSize: 12, lineHeight: 1.55, color: '#3c4043' }, children: selected.describe })), tiered && (_jsxs(_Fragment, { children: [_jsx("div", { style: { ...label, marginTop: 16 }, children: "changing it" }), _jsx("p", { style: { maxWidth: 340, margin: '6px 0 0', fontSize: 12, lineHeight: 1.55, color: '#3c4043' }, children: changing(selected) })] })), overridden && (_jsxs("div", { style: {
|
|
1018
1202
|
display: 'flex', alignItems: 'baseline', gap: 8, padding: '8px 11px', marginTop: 14,
|
|
1019
1203
|
background: C.warnBg, border: `1px solid ${C.warnBorder}`, borderRadius: 4, fontSize: 11, maxWidth: 360,
|
|
1020
1204
|
}, children: [_jsx("b", { children: "currently overridden" }), _jsxs("span", { style: { color: C.dim }, children: [origin === 'env' ? 'an environment variable' : 'a command-line flag', " is overriding the manifest \u2014 the value shown is the one in effect."] })] }))] })) : (_jsx("span", { style: { color: C.faint }, children: "select a setting" })), m.lastSavedTo !== undefined && (_jsx("div", { style: { marginTop: 18, fontFamily: mono, fontSize: 10.5, color: C.dim }, children: m.lastSavedTo === null
|