196 lines
9.5 KiB
Markdown
196 lines
9.5 KiB
Markdown
# Per-agent terminal: row taxonomy + inconsistencies
|
|
|
|
Snapshot of how the per-agent web UI's live pane renders each
|
|
event kind today, written up so the next coherence pass has a
|
|
reference to work from. Source of truth lives in
|
|
`hive-ag3nt/assets/app.js` (`renderStream`,
|
|
`fmtToolUse`, `renderRichToolUse`, `renderToolResult`,
|
|
`renderTaskEvent`) + `hive-fr0nt/assets/terminal.css` (the
|
|
shared `.live .<class>` styling).
|
|
|
|
## Row taxonomy
|
|
|
|
| CSS class | Prefix glyph | Color | Triggered by | Source |
|
|
|---|---|---|---|---|
|
|
| `.turn-start` | `◆ TURN ← <from>` | amber, bold, top-margin, amber left rule | `LiveEvent::TurnStart` | harness wake |
|
|
| `.turn-body` | (inline under turn-start) | fg dimmed 85% | same | the wake-prompt body |
|
|
| `.turn-end-ok` | `✓ turn ok` | green, green left rule | `LiveEvent::TurnEnd { ok: true }` | harness |
|
|
| `.turn-end-fail` | `✗ turn fail — note` | red, red left rule | `LiveEvent::TurnEnd { ok: false }` | harness |
|
|
| `.text` | none | fg/white, indented | claude `assistant.content[].text` | stream-json |
|
|
| `.thinking` | `·` or `· thinking …` | muted, italic | claude `assistant.content[].thinking` | stream-json |
|
|
| `.tool-use` | `→ Name args…` | cyan | `assistant.content[].tool_use` | stream-json |
|
|
| `.tool-use` `<details>` | `→ Name path · +N` | cyan, body is diff | rich tool_use (Write/Edit) | renderRichToolUse |
|
|
| `.tool-use` `<details>` | `→ send → to · headline` | cyan, body is text | mcp__hyperhive__send | renderRichToolUse |
|
|
| `.tool-result` | `← <txt>` | muted | short `user.content[].tool_result` (≤120c) | stream-json |
|
|
| `.tool-result-block` `<details>` | `▸ ← Nl · headline` | muted, body is text | long `tool_result` (>120c) | stream-json |
|
|
| `.tool-use` | `⌁ task <id> started · <desc> [type]` | cyan | claude Task-tool subagent event | renderTaskEvent |
|
|
| `.turn-end-ok` / `.turn-end-fail` / `.tool-result` | `⌁ task <id> ✓/✗/◌ <status> · <desc> · → <output_file>` | green / red / muted | claude Task-tool result | renderTaskEvent |
|
|
| `.note` | `· <text>` | muted | `LiveEvent::Note` (harness chatter, /cancel /compact /new-session, stderr lines, etc.) | harness |
|
|
| **`.sys`** | `· {json…}` | **muted** | **anything `renderStream` doesn't recognise** | catch-all |
|
|
| `.result` | (defined, never emitted today) | green | — | — |
|
|
| Banner shimmer | mauve | turn in flight (ref-counted) | `setBannerActive` |
|
|
|
|
## Where the inconsistencies live
|
|
|
|
1. **Glyph vocabulary drifts**:
|
|
- tool_use uses `→`
|
|
- tool_result uses `←`
|
|
- thinking uses `·`
|
|
- notes use `·`
|
|
- turn-end ok/fail use `✓ / ✗`
|
|
- turn-start uses `◆`
|
|
- task events use `⌁`
|
|
- The `·` glyph is overloaded across thinking, notes, sys.
|
|
|
|
2. **What gets a `<details>` block vs a flat row** is per-tool
|
|
ad-hoc: Write/Edit always expand, send always expands, every
|
|
other tool_use is flat regardless of input size.
|
|
`tool_result` is flat if ≤120 chars otherwise `<details>`.
|
|
|
|
3. **Stderr handling**: claude's stderr lines come through as
|
|
`LiveEvent::Note` with `text: "stderr: <line>"` — they
|
|
render as muted `· stderr: …`, identical styling to harness
|
|
notes about /compact / /model. No red-tinted "this is an
|
|
error" affordance for stderr.
|
|
|
|
4. **Catch-all `.sys` rows** are visually identical to `.note`
|
|
rows — both muted, both `·` prefix. They look like normal
|
|
notes despite usually being "an event renderStream couldn't
|
|
classify". Unmatched stream shapes (rate limit warnings under
|
|
odd type/subtype combos, future claude additions, etc.)
|
|
silently fall through.
|
|
|
|
5. **`.tool-use` ranges from one-liner (`Read foo.md`) to
|
|
multi-page collapsed diff** — same color, same prefix glyph,
|
|
very different visual weight. A small marker on the collapsed
|
|
`<details>` summary would help (the `▸` is present in
|
|
`.tool-result-block` summaries but absent in tool-use
|
|
`<details>` summaries).
|
|
|
|
6. **Cancel/compact/new-session notes** are styled the same as
|
|
autonomous harness chatter; nothing flags them as "operator
|
|
initiated."
|
|
|
|
7. **Turn-start / turn-end are visually overweight**: the
|
|
triggering event row + the closing row both get bold text,
|
|
top margins, and a full coloured background tint. The
|
|
coloured left rule alone already says "this is a turn
|
|
boundary" — the heavy chrome adds noise without information.
|
|
Drop the bold/margin/tint, keep the left rule.
|
|
|
|
8. **Left-alignment is incoherent across row types**: the `▸`
|
|
disclosure marker on expandable rows doesn't sit in the
|
|
same column as flat-row prefix glyphs (`→`, `←`, `·`), so
|
|
the prefix column wanders by row kind. Expandable tool_use
|
|
(`→ Name …`) and expandable tool_result (`▸ ← Nl …`) use
|
|
different layouts from each other too. Pick one prefix
|
|
column and align every row kind into it; the disclosure
|
|
marker should be visually inside that column, not pushed
|
|
to the side.
|
|
|
|
9. **Continuation lines aren't inset**: when a row's body
|
|
wraps (e.g. `→ foo bar baz quux …`), the second visual
|
|
line starts at column 0 rather than under the `f` of
|
|
`foo`, so wrapped content blurs into the next row. Want a
|
|
`text-indent` / hanging-indent rule so continuation lines
|
|
align with the start of the body, not the prefix glyph.
|
|
|
|
10. **Most message-bearing rows are collapsed by default**
|
|
even when the body is the whole point: `send`, `recv`,
|
|
`ask`, and friends hide their text behind a `<details>`
|
|
summary. The summary headline is rarely enough context.
|
|
Want these expanded by default, with collapse reserved
|
|
for genuinely heavy payloads (multi-page diffs, long
|
|
tool_result blocks).
|
|
|
|
11. **Tools from extra MCP servers aren't pretty-printed**:
|
|
`renderRichToolUse` only special-cases the built-in
|
|
hyperhive tools (Write/Edit/send). Anything coming from
|
|
`extraMcpServers` (matrix, bitburner, …) falls through
|
|
to the generic `→ Name args…` JSON dump. Either a
|
|
plugin-style hook in the renderer map, or at minimum a
|
|
nicer generic args-pretty-printer that handles common
|
|
shapes (single string arg, single dict arg, etc.).
|
|
|
|
12. **No markdown rendering on message bodies**: `send` /
|
|
`recv` / `ask` / `answer` / agent text content all
|
|
arrive as markdown-flavoured prose (bullets, fenced
|
|
code, bold, links) but render as raw text. Want a
|
|
minimal markdown pass — at least lists, fenced code,
|
|
inline code, bold/italic, links — applied to message
|
|
bodies and probably to the `assistant.content[].text`
|
|
`.text` row.
|
|
|
|
## Suggested coherence pass
|
|
|
|
Pick one scheme and audit all renderers to match. A concrete
|
|
proposal:
|
|
|
|
- **`→` cyan**: outbound action (tool_use, send)
|
|
- **`←` muted**: inbound result (tool_result)
|
|
- **`◆` amber**: turn framing (turn_start)
|
|
- **`✓ / ✗`**: success / failure, green / red (turn_end,
|
|
task_notification)
|
|
- **`⌁` mauve**: subagent / background event (task_*)
|
|
- **`·` muted**: ambient note, italic for thinking
|
|
- **`!` orange**: caught error (stderr lines, .sys catch-all
|
|
that landed something the renderer didn't recognise)
|
|
|
|
Plus: every tool_use `<details>` summary gets `▸` so collapsed
|
|
content is visually announced. Operator-initiated notes get a
|
|
distinct prefix (`op·` or similar) so they're easier to spot in
|
|
the scrollback.
|
|
|
|
The `.sys` catch-all should escalate visually — a louder
|
|
"unrecognised event" rendering surfaces silently-dropped event
|
|
shapes for future fix-up rather than hiding them in the muted
|
|
note stream.
|
|
|
|
### Layout rules to apply uniformly
|
|
|
|
- **One prefix column for every row kind** — flat rows and
|
|
expandable rows alike. The disclosure marker (`▸`) lives
|
|
inside that column, not as a separate gutter, so glyph
|
|
alignment doesn't shift between row types.
|
|
- **Hanging indent on wrapped bodies** so continuation lines
|
|
start under the first character of the body, not under the
|
|
prefix glyph. Probably `display: grid` with
|
|
`grid-template-columns: <prefix-col> 1fr` per row, or
|
|
`text-indent`/`padding-left` with negative `text-indent`.
|
|
- **Turn boundaries are rule-only** — drop the bold + margin
|
|
+ tint on `.turn-start` / `.turn-body` / `.turn-end-*`.
|
|
The coloured left rule alone carries the boundary signal.
|
|
- **Default-expanded message rows**: `send`, `recv`, `ask`,
|
|
`answer`, and short-ish `text` rows render their body
|
|
inline (no `<details>`). Reserve collapse for genuinely
|
|
heavy bodies — multi-page diffs, long tool_results,
|
|
thinking blocks past N lines.
|
|
|
|
### Renderer surface for extra MCP tools
|
|
|
|
`renderRichToolUse` currently switches on hard-coded tool
|
|
names. Replace with a registry keyed by
|
|
`mcp__<server>__<tool>` (and the built-in claude tool names)
|
|
that maps to a `(toolUse) -> Node` renderer. Per-agent extra
|
|
MCPs can register their own renderers via a small JS hook
|
|
(loaded the same way `extra-mcp.json` is loaded server-side);
|
|
the fallback is a generic args-pretty-printer that handles
|
|
single-string and single-dict shapes nicely instead of dumping
|
|
raw JSON.
|
|
|
|
### Markdown rendering
|
|
|
|
Apply a minimal markdown pass to message bodies (`send` /
|
|
`recv` / `ask` / `answer`) and to assistant `text` rows.
|
|
Scope: paragraphs, lists, fenced + inline code, bold/italic,
|
|
links. No HTML passthrough, no images, no tables —
|
|
explicitly bounded so we don't import a kitchen-sink parser
|
|
into the per-agent page. A small handwritten pass or a tiny
|
|
dep (e.g. `micromark` / `marked`) both work.
|
|
|
|
## Dashboard side (not covered here)
|
|
|
|
The main dashboard's message-flow pane is a different beast:
|
|
broker messages render as `.msgrow` grid lines (ts / arrow /
|
|
from / → / to / body) with separate styling. The current file
|
|
focuses only on the per-agent terminal.
|