feat: pct_create action, ToolCallGroup collapse+animation, inline chat approval
- Add pct_create to request_execution (MCP) and executeApprovedAction (httpapi) Parses JSON config: vmid, hostname, cores, memory, disk_gb, ip, gw, storage, template, privileged, nesting, mounts, nameserver, searchdomain. Creates entity (state=provisioning), hosts relationship, entity_status on success. Fixes action string parsing to use Index instead of SplitN (colons in JSON). - Rewrite ToolCallGroup.svelte: bits-ui Collapsible replaces native <details>. Collapsed by default. Animated header shows live tool count + running tool name while streaming. Auto-expands during streaming, auto-collapses on done. - Add InlineApproval component: parses 'execution UUID queued' from agent response, renders Approve/Deny buttons inline in chat, calls decideApproval. - Document pct_create in nomos/SOUL.md with params, risk class, and approval flow. - Add session-review skill at .agents/skills/session-review/SKILL.md. - Add plan: 2026-07-09-session-execution-and-ux-fixes.md.
This commit is contained in:
156
plans/2026-07-09-session-execution-and-ux-fixes.md
Normal file
156
plans/2026-07-09-session-execution-and-ux-fixes.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# 2026-07-09 — Session execution, UX, and learning improvements
|
||||
|
||||
**Status:** Planned
|
||||
|
||||
## Goal
|
||||
|
||||
Fix the hard blocker and UX issues found in the latest production Nomos session
|
||||
(`b9c5de7c-e0b5-424c-9149-9fd45b2e7011` — "deploy TypeType as an LXC on strong").
|
||||
The user asked Nomos to deploy an LXC; Nomos gathered data, proposed a plan, but
|
||||
at the final step ("run all yourself") said it *couldn't* — `request_execution`
|
||||
has no `pct_create` action. The user's objective was not achieved.
|
||||
|
||||
## Session analysis
|
||||
|
||||
10 messages (5 user / 5 assistant), 150 tool calls, zero LXC created.
|
||||
|
||||
| Msg | Role | Tool calls | Top tools | Summary |
|
||||
|-----|------|-----------|-----------|---------|
|
||||
| 0 | user | 0 | — | "deploy TypeType on strong as LXC" |
|
||||
| 1 | assistant | 40 | get_entity(20), search_knowledge(12) | Fleet scan, entity detail per host/LXC |
|
||||
| 2 | user | 0 | — | "it's github.com/Priveetee/TypeType, use tube.hubris.network" |
|
||||
| 3 | assistant | 2 | search_knowledge(2) | MCP has no web fetch tool → couldn't read GitHub |
|
||||
| 4 | user | 0 | — | "I think you can figure out those" |
|
||||
| 5 | assistant | 60 | search_knowledge(32), request_execution(14) | Built the plan, tried provisioning, failed silently |
|
||||
| 6 | user | 0 | — | "connect to strong media disk, no youtube login, proceed" |
|
||||
| 7 | assistant | 44 | search_knowledge(10), get_entity(10), request_execution(8) | Full deployment plan laid out |
|
||||
| 8 | user | 0 | — | "run all yourself" |
|
||||
| 9 | assistant | 4 | request_execution(4) | **"I can't run pct create — only pct_exec, systemctl, restart, apt_upgrade"** — failure |
|
||||
|
||||
## Findings
|
||||
|
||||
### 1. HARD BLOCKER: `pct_create` missing from `request_execution`
|
||||
|
||||
`request_execution` (`internal/mcp/server.go:264-376`) supports `restart`,
|
||||
`systemctl`, `pct_exec`, `apt_upgrade`. The actuator has `ProvisionLXC()`
|
||||
(`internal/actuator/actuator.go:209`) that calls `pct create` via SSH, but it
|
||||
is only wired into the auto-act signal pipeline — Nomos has no way to invoke
|
||||
it through MCP.
|
||||
|
||||
Nomos's final response laid out the exact `pct create` command the operator
|
||||
needs to run manually on the Proxmox host. That's a dead end for the user, who
|
||||
expected the agent to execute from chat.
|
||||
|
||||
**Fix:**
|
||||
- Add `pct_create` action to `request_execution` handler.
|
||||
- Wire it to the existing `ProvisionLXC()` function.
|
||||
- Classification: `config_mutation` — requires operator approval. Once approved
|
||||
(from the Ops page or Matrix), the actuator picks it up and provisions the
|
||||
LXC with the step callback reporting progress.
|
||||
- Alternatively (for the "run from chat" expectation): add a chat-level approval
|
||||
flow — when Nomos proposes `request_execution` with `pct_create`, the frontend
|
||||
renders an inline "Approve" button in the chat bubble. Operator clicks → it runs.
|
||||
This is the UX the user described: "allow the agent to run things directly from
|
||||
the chat I'm in."
|
||||
|
||||
### 2. UI: ToolCallGroup expanded by default during streaming — no status animation
|
||||
|
||||
`ToolCallGroup.svelte` uses `<details open>` when `active=true`. During a
|
||||
streaming turn with 40+ tool calls, the collapsed group fills the viewport
|
||||
with raw JSON. The summary header shows only a static icon and "N tools" text.
|
||||
|
||||
**What happens now:**
|
||||
- Streaming starts → group opens and stays open → all tool results visible as raw JSON.
|
||||
- When streaming ends → auto-collapses. No animation.
|
||||
- Header shows `WrenchIcon` pulsing OR `CheckIcon` OR `XIcon` — but no live
|
||||
running count, no per-tool status in the collapsed summary bar.
|
||||
|
||||
**What should happen:**
|
||||
- Group starts **collapsed** by default. The summary header shows a live animated
|
||||
status: "⠋ Running get_lxc_state (caddy)… [2/40 done]" with the active tool
|
||||
name + a progress fraction, updating in real time.
|
||||
- When a tool completes, the header briefly reflects it ("✓ get_lxc_state (caddy)")
|
||||
before moving to the next.
|
||||
- Clicking the summary expands the group with a smooth animated open/close
|
||||
(replacing native `<details>` with bits-ui `Collapsible` + CSS transition).
|
||||
- On load from history (not streaming), always starts collapsed.
|
||||
|
||||
**Fix:**
|
||||
- Replace `<details open>` with bits-ui `Collapsible` component (already in
|
||||
`web/src/lib/components/ui/collapsible/`).
|
||||
- Add `animate-pulse` to the chevron icon during streaming (user sees motion).
|
||||
- Add a `statusText` derived that shows the in-progress tool name + count.
|
||||
- CSS animation: `Collapsible.Content` supports `forceMount` with transitions.
|
||||
|
||||
### 3. No web-fetch tool → Nomos can't read GitHub READMEs
|
||||
|
||||
Msg 3: Nomos needed to inspect `github.com/Priveetee/TypeType` to understand the
|
||||
stack. It used `search_knowledge` (DB FTS), which returned nothing because the
|
||||
repo isn't in the DB. The agent had no way to fetch external URLs.
|
||||
|
||||
The MCP has 27 tools (21 listed in AGENTS.md + 6 more added since), but none
|
||||
for HTTP/web fetching. Nomos can only query the DB or execute SSH commands on
|
||||
existing hosts.
|
||||
|
||||
This forced the human to provide context that should have been machine-read.
|
||||
|
||||
**Fix options (non-blocking):**
|
||||
- Add an `http_get` MCP tool that returns sanitized body text (strip scripts,
|
||||
truncate to 8KB). Rate-limited per-turn.
|
||||
- Or: add `web_fetch` as a first-class action in the MCP gateway itself, since
|
||||
the gateway container already makes outbound HTTP calls to OpenRouter.
|
||||
|
||||
### 4. Task: Bulk-tool awareness already in SOUL.md but not enough
|
||||
|
||||
The SOUL.md already says "prefer `list_lxcs` over `get_lxc_state` for fleet-wide"
|
||||
(line 27-28). But msg 1 still made 40 calls. The issue:
|
||||
|
||||
- `get_entity` was called 20 times (one per entity found by `list_entities`).
|
||||
`list_entities` already returns all entities; the agent wanted per-entity
|
||||
detail, which is redundant since `explain` or `get_state_snapshot` gives the
|
||||
same info in one call.
|
||||
|
||||
**Fix (already planned in `2026-07-09-chat-sessions-improvements.md` finding 3):**
|
||||
- Enrich `list_lxcs` with CPU/memory utilization so the model doesn't feel it
|
||||
needs `get_lxc_state` per container.
|
||||
- Add `get_tools_summary` to SOUL.md preamble that lists each tool's intended
|
||||
use and warns about N+1 call patterns.
|
||||
|
||||
### 5. Skill gaps
|
||||
|
||||
| Missing | Why | Where to add |
|
||||
|---------|-----|-------------|
|
||||
| `http_get` / `web_fetch` | Agent can't read external URLs | MCP tool in `internal/mcp/server.go` |
|
||||
| `session-review` skill | No way to learn from failed sessions | `.agents/skills/session-review/SKILL.md` |
|
||||
| `pct_create` action | Can't provision new LXCs from chat | `internal/mcp/server.go` + `internal/actuator/` |
|
||||
| `request_execution` approval from chat | Operator must switch to Ops page | Inline chat approval component |
|
||||
|
||||
## Implementation order
|
||||
|
||||
1. **Add `pct_create` to `request_execution`** (`internal/mcp/server.go`) —
|
||||
hard blocker, needed for the session's objective.
|
||||
2. **ToolCallGroup: collapse by default + animated status header**
|
||||
(`web/src/lib/components/ToolCallGroup.svelte`) — immediate UX win, the user
|
||||
explicitly asked for this.
|
||||
3. **Inline chat approval for `request_execution`** — renders an "Approve"/"Deny"
|
||||
button inside the chat when an execution is queued for approval. Lets the
|
||||
operator approve from the same chat.
|
||||
4. **`session-review` local skill** — lives in `.agents/skills/`, loads when
|
||||
examining chat sessions for failure patterns.
|
||||
5. **`http_get` MCP tool** — non-blocking but addresses a real gap seen in this
|
||||
session.
|
||||
|
||||
## Verification
|
||||
|
||||
- Re-run the TypeType deploy prompt against the patched agent. Confirm:
|
||||
- Agent proposes plan as before (keep plan-proposal behavior).
|
||||
- When user says "run all", agent calls `request_execution(target=lxc:typetype,
|
||||
action=pct_create, params=<json>)`.
|
||||
- Approval fires → operator sees inline approval in chat → approves → LXC created.
|
||||
- ToolCallGroup: start a session that triggers 5+ tool calls. Confirm:
|
||||
- Group starts collapsed.
|
||||
- Summary header shows animated status: tool name + count updating in real time.
|
||||
- Clicking expands smoothly.
|
||||
- On session reload (history), stays collapsed.
|
||||
- Load `session-review` skill and ask it to analyze the TypeType failure session;
|
||||
confirm it identifies the missing action as the root cause.
|
||||
Reference in New Issue
Block a user