Files
oikos/plans/done/2026-07-14-activity-timeline.md
dtoro 104593de0c plans: review and archive all plans to done/
Architecture has changed drastically (hexagonal refactor, web client
extraction). Every active plan has been reviewed, annotated with
'Completed' or 'Won't do' status, and moved to plans/done/.

Completed (7): gaps-and-improvements, liveness-drift, gated-execution,
  nomos-code-review, codebase-cleanup, mascot-physics, backend-eval
Won't do (7): prometheus-lxc, control-room-webui, activity-gaps,
  activity-timeline, frontend-os-apps, haos-capability-gaps, arr-audit
2026-08-16 11:18:47 +02:00

136 lines
5.5 KiB
Markdown

# 2026-07-14 — Unified sidebar activity timeline
**Reviewed 2026-08-16 — Status: Won't do** — frontend plan superseded by web client extraction to separate repo.
**Status:** Planned
## Current state (broken)
The sidebar has three sections that appear/disappear independently:
| Section | When visible | Shows |
|---|---|---|
| Plan (top) | When `$planSteps.length > 0` | Plan step names with progress bar |
| Tool activity (middle) | When `toolCount > 0` | Compact tool list, grouped by turn |
| This session (bottom) | When `digest.total_executions > 0` | Post-hoc execution count + knowledge |
State changes cause sections to **pop in/out** as the agent moves between
planning → executing → done. The "0 tools · 0 running" counter flashes
briefly then vanishes. Tool activity appears/disappears between turns.
## Target: single unified timeline
One section, always present when a session is loaded. Every agent action
appears as an entry in reverse-chronological order (newest at top).
```
┌─ Activity ───────────────────────── ─┐
│ │
│ ✓ Task completed: "Upgraded 4 LXCs" │ ← newest
│ ◉ Running: apt upgrade on lxc:dns │
│ ✓ run: apt upgrade on lxc:gitea │ ← tool completed
│ ✓ Verified gitea: HTTP 200 │
│ ◉ Step 3/5 — Upgrade dns │ ← plan step running
│ ✓ Step 2/5 — Upgrade gitea │ ← plan step done
│ ✓ run: apt upgrade on lxc:nfs-export │
│ ◉ Step 1/5 — Upgrade nfs-export │
│ ✓ Knowledge recorded │
│ 📋 Plan set: 5 steps │ ← plan proposed
│ 🎯 Goal: Upgrade 4 low-risk LXCs │ ← goal set
│ │ ← oldest
└───────────────────────────────────────┘
```
### Entry types
| Type | Icon | Example description |
|---|---|---|
| `goal` | 🎯 | "Audit all LXCs for updates" |
| `plan` | 📋 | "Plan set: 5 steps" |
| `step_start` | ◉ spinner | "Step 2/5 — Upgrade gitea" |
| `step_done` | ✓ | "Step 2/5 — Upgrade gitea" |
| `tool_start` | ◉ spinner | "run: Upgrade nfs-export (21 pkgs)" |
| `tool_done` | ✓ | "run: 0 upgraded, 0 newly installed" |
| `tool_error` | ✗ | "run: SSH handshake failed" |
| `knowledge` | ✨ | "Recorded: How to run fleet upgrades" |
| `complete` | ✓ | "Task completed: success" |
| `question` | ❓ | "Asked: Which host for the LXC?" |
| `error` | ✗ | "Auto-resume failed: context deadline exceeded" |
### Data source
Entries come from all available sources, merged and deduplicated:
1. **`toolTimeline` store** (live tool_use/tool_result pairs)
2. **`planSteps` store** (step status transitions)
3. **Session digest API** (knowledge created, final outcome)
4. **`currentTask` store** (goal, status)
Deduplication: when a plan step links to a tool call via `execution_id`, show
them as one entry instead of two (e.g. "Step 3: Upgrade dns ◉ running" includes
the tool — don't show a separate "run: apt upgrade" entry).
### Behavior
- **Always visible** when `$currentSession` is set
- **Reverse chronological** — newest entries at top, scrolls naturally
- **Auto-expands** the entry for the currently-running tool/step
- **Collapses** completed entries to one line (expandable)
- **Polls** every 3s for live updates (same as current startPolling)
- **No flashing** — entries only change status in place (tool_start → tool_done), never removed
- **Persists** across page navigation (rehydrated from REST on load)
- **Empty state** when no session: "Open a session to see agent activity"
### What gets removed from chat
- **ToolCallGroup** — the compact tool counter. Tools live in the timeline now.
- **AgentIndicator at bottom** — partially. Keep it ONLY for the initial
"thinking" state (before any tools fire). Once the first tool fires, the
timeline is the source of truth and the chat indicator is redundant.
Actually: remove it entirely. The timeline IS the indicator.
### What stays in chat
- **Agent text responses** — the thinking, conclusions, reports
- **InlineApproval cards** — approvals need operator action, must be in chat
- **Inline tool renderers** — entity cards, health summary, etc. (informational)
- **User messages** — obviously
## Implementation
### 1. Data layer: `activityLog` derived store
Add to `chat.ts`:
```ts
export interface ActivityEntry {
id: string
type: 'goal' | 'plan' | 'step_start' | 'step_done' | 'step_failed' |
'tool_start' | 'tool_done' | 'tool_error' |
'knowledge' | 'complete' | 'question' | 'error'
description: string
detail?: string // tool result text, step detail, etc.
timestamp: number // Date.now() when created
seq?: number // plan step seq, for ordering
toolName?: string // for tool entries
status: 'running' | 'done' | 'failed'
collapsed: boolean // initial collapsed state (true for completed)
}
```
Derived reactively from `messages`, `planSteps`, `currentTask`, and session
digest data. Uses `$derived.by()` to recompute when any source changes.
### 2. New component: `ActivityTimeline.svelte`
Replaces all three sidebar sections. Renders `activityLog` entries as a
vertical timeline with connecting lines.
### 3. Remove from chat
- `<ToolCallGroup>` rendered in chat
- `<AgentIndicator>` at bottom
### 4. Update TaskContextPanel
Replace PlanProgress + SessionDigest with ActivityTimeline.