web-ui: remove dead ask->operator inline-answer binding from the per-agent terminal

hyperhive#2922: the inline-answer slot (pendingAskBinds/reconcileAskBinds/
buildAnswerForm) depended on a since-removed /api/loose-ends endpoint
and had been silently non-functional the whole time — nothing ever
reassigned lastLooseEnds, so the reconciler always no-op'd.

Per mara's call on the issue (ask/answer is deprecated per #2850, only
the main dashboard UI needs to work, remove the broken per-agent inline
view): ripped out the dead JS (binding + form + CSS) rather than
restoring the endpoint. An ask tool call now renders like any other
tool call, no inline answer affordance; the operator answers via the
dashboard's own question surfacing.

Also fixed adjacent doc staleness this same removal made newly
contradictory (docs/web-ui/agent.md, docs/terminal-rendering.md):
the doc already described the loose-ends/bash-tasks flyouts and the
ask-binding as recently dead, but the endpoint reference table and a
header-pills bullet list still described them as live.
This commit is contained in:
iris 2026-08-11 17:59:27 +02:00 committed by mara
commit ecf9ff4d80
4 changed files with 37 additions and 288 deletions

View file

@ -59,7 +59,6 @@ parent's negative pull.
| `.tool-use` (flat) | `<icon> Name args…` | cyan | tool_use w/o rich renderer; `<icon>` from `toolIcon(name)`: 📤 send · 📥 recv · ❓ ask · ⏰ remind · 🏷️ set_status · 🪢 loose-ends · ✂️ cancel_loose_end · get_agent_meta · ✅ ack_until · 📜 get_logs/get_host_journal · ↻ restart · ⏹️ kill · ▶️ start · 🔄 update · 📋 list_containers/list_rooms/list_room_members/list_invites · 📖 read_room/Read · 👁️ mark_read · 🛑 bash kill · 🖥️ bash other · 💬 matrix send/reply/dm · 📦 request_* · ⏱️ schedule · 🔧 default | stream-json |
| `.tool-use` `<details>` | `💾/✏️ Write/Edit <path> · +N` (no `→`) | cyan, body is +/- diff | `renderRichToolUse` Write/Edit | stream-json |
| `.tool-use` `<details open>` | `📤 send → to · NL`, `❓ ask → to`, `✍️ answer #id` | cyan, body is markdown | rich renderer for send / ask / answer | stream-json |
| `.tool-use .ask-answer-inline-slot` | (sub-block under `ask → operator`) | inherits row | inline answer form bound by `reconcileAskBinds` to the loose-end | rich renderer |
| `.tool-result` (flat) | `← <txt>` | muted | short `tool_result` (≤120c, non-recv) | stream-json |
| `.tool-result-block` `<details>` | `Nl · headline` | muted, body is text | long generic `tool_result` | stream-json |
| `.tool-result-block` `<details open>` | `recv ← <txt>` | muted, body is markdown | `tool_result` correlated to a prior `recv` tool_use via id | stream-json |
@ -211,28 +210,17 @@ This keeps less-frequent tools that don't have a specific
`fmtToolUse` case from dumping raw JSON. Common matrix and
hyperhive tools have their own cases and skip this path.
## Inline ask-operator answer
## Inline ask-operator answer (removed)
When an agent calls `mcp__hyperhive__ask` with `to == "operator"`
(default), the rich tool-use renderer mounts an empty
`<div class="ask-answer-inline-slot">` inside the row's expanded
body, then enqueues a loose-ends refresh. `reconcileAskBinds()`
runs on every loose-ends refresh, matches each waiting slot
against pending operator-bound questions by question text, and
injects an inline `.answer-form` (textarea + send button bound to
`/answer-question/<id>` on the host dashboard) into the matching
slot. When a question subsequently leaves the pending list (answered,
cancelled by asker, or TTL-expired), the same reconciler
replaces the form with a struck-through `[resolved]` tag so the
scrollback reflects the closed state. The label is neutral
because `/api/loose-ends` only carries pending state — full
resolution detail is visible via the question's history in the
side panel.
Lets the operator answer mid-flow without context-switching to the
loose-ends side panel or the dashboard tab. Side panel + dashboard
forms remain — they're the same `buildAnswerForm` factory, three
mount points for the same POST.
An `mcp__hyperhive__ask(to: "operator", ...)` row used to mount an
inline answer form (`.ask-answer-inline-slot`, `reconcileAskBinds()`)
directly in the terminal scrollback. It depended on a since-removed
`/api/loose-ends` endpoint and had been silently dead since that
removal (hyperhive#2922) — ripped out rather than rebuilt (mara: only
the main dashboard's own question surfacing needs to work). An `ask`
tool call now renders like any other tool call, with no inline answer
affordance; the operator answers via the dashboard
(`dashboard/src/swarm.js` + `call.js`).
## Dashboard side (not covered here)