feat(activity,api,settings): activity panel v0 over conversation events sse

This commit is contained in:
hh
2026-08-28 17:01:02 +02:00
parent 755a475f27
commit a1bf4db905
12 changed files with 1179 additions and 153 deletions
+29 -12
View File
@@ -2,20 +2,37 @@
[![AI Slop Inside](https://sladge.net/badge.svg)](https://sladge.net)
Sends the current note to Beaver's `markdown frontend` (`POST /chat` on `beaver-gateway`) and writes the agent's reply back into the file. Skips the Obsidian Sync round-trip by POSTing the buffer contents directly.
Two things:
- **Send the current note** to Beaver's `markdown frontend` (`POST /chat/stream` on `beaver-gateway`) and stream the agent's reply back into the buffer. Skips the Obsidian Sync round-trip by POSTing the buffer contents directly.
- **Activity panel** (v0): a side view that follows the active note's `conversation_id` and shows, live over SSE, what the agent is doing — tool calls, subagents as a tree, turn status, usage of each turn.
## Commands
Both commands appear in the command palette only when the active note's YAML frontmatter has an `agent:` field:
- **Beaver: Send using selected agent** — uses `frontmatter.agent`. Only when the active note has an `agent:` field.
- **Beaver: Send using different agent** — fetches the agent list from the gateway and opens a fuzzy picker. Same condition.
- **Beaver: Open chat in panel** — reveals the activity panel in the right sidebar (creates it on first use) and points it at the active note.
- **Beaver: Send using selected agent** — uses `frontmatter.agent`.
- **Beaver: Send using different agent** — fetches the agent list from the gateway and opens a fuzzy picker.
## Activity panel
Subscribes to `GET /api/conversations/{id}/events` (SSE, bearer) where `{id}` is the `conversation_id` from the active note's frontmatter. Switching notes switches the subscription; a note without `conversation_id` shows a hint instead. On connect it fetches `GET /api/conversations/{id}` for the snapshot (title, agent, kind, status, whether a turn is running), then renders bus events:
- `turn.start` / `turn.end` — a turn block with status (running / done / interrupted / error), origin (`user` / `inject`), start time, duration and usage (`in · out · cache read/write · $ · time`).
- `tool` / `tool.result` — a tool row (name, input summary, result status); clicking it expands the raw input and the result preview. Rows with `parent_tool_use_id` nest under the `Task`/`Agent` tool that spawned the subagent.
- `stream` `content_block_start` of type `tool_use` — pre-creates the row so a long-running tool shows up before its input is complete.
- `say` — text the dispatcher sent out of an inject turn.
The stream reconnects with exponential backoff (1 s → 30 s, jittered) and resets on `hello`. `401`/`403`/`404` are not retried: the panel shows the error and waits for you to fix the token or the id. When it reconnects and the snapshot says nothing is running, turns still shown as running are marked interrupted — their `turn.end` was lost with the connection.
Plain DOM and CSS on Obsidian's theme variables; no framework. It is the v0 of the panel from `архитектура.md` §2 — the full Svelte UI (M5) replaces it.
## Settings
- **Base URL** — markdown-frontend root, e.g. `http://localhost:62993`.
- **Bearer token** — a token with the `messages` scope (mint via the admin frontend or `BOOTSTRAP_TOKENS`).
- **Test connection** — calls `GET /agents`.
- **Base URL** — markdown-frontend root, e.g. `http://localhost:62993` or `https://host/md`.
- **API origin** — where `/api/…` lives, e.g. `http://localhost:62994` or `https://host`. Empty = derived from Base URL (`…/md``…`, port `62993``62994`).
- **Bearer token** — needs the `messages` scope for sending and the `api` scope for the panel; a `*` bootstrap token covers both.
- **Vault subpath** — folder in this vault that maps to the gateway's vault root.
- **Test connection** / **Test API**`GET /agents` on the markdown frontend, `GET /api/agents` on the API origin.
## Note format
@@ -29,27 +46,27 @@ agent: beaver-opus-medium
hi there
```
The gateway parses `### User:` / `### Assistant:` markers; a note with no markers is treated as a single user turn. After a successful send, the gateway returns the new file content (including an `### Assistant:` block and a fresh `### User:` scaffold), and the plugin writes it back to the buffer.
The gateway parses `### User:` / `### Assistant:` markers; a note with no markers is treated as a single user turn. After the first turn the gateway adds `conversation_id` to the frontmatter — that is what the activity panel keys off.
## Install
```
make install VAULT=~/Obsidian/my-vault # build + copy manifest.json + main.js into <vault>/.obsidian/plugins/beaver
make install VAULT=~/Obsidian/my-vault # build + copy manifest.json, main.js, styles.css, versions.json into <vault>/.obsidian/plugins/beaver
make zip # build → beaver-plugin-<version>.zip you can carry to any vault
```
Then enable **Beaver** in Settings → Community plugins.
Then enable **Beaver** in Settings → Community plugins (or reload it if it was already enabled).
### Mobile
The plugin is desktop-and-mobile (`isDesktopOnly: false`). Two things to get right on a phone:
- The base URL in plugin settings has to be reachable from the phone — `http://localhost:62993` won't work; use the gateway's LAN IP, a tunnel, or a public hostname.
- The base URL / API origin in plugin settings have to be reachable from the phone — `http://localhost:` won't work; use the gateway's LAN IP, a tunnel, or a public hostname.
- Get the plugin files onto the phone vault via Obsidian Sync (toggle "Installed community plugins" in your sync settings) or any file-sync tool you already use (Working Copy, Syncthing, etc.). `make install` only knows how to write to a local path.
### Hand-rolled
Three files are all Obsidian needs — `manifest.json`, `main.js`, `versions.json`. Drop them in `<vault>/.obsidian/plugins/beaver/` however you like (unzip, `scp`, `rsync`, your own git, …).
Four files are all Obsidian needs — `manifest.json`, `main.js`, `styles.css`, `versions.json`. Drop them in `<vault>/.obsidian/plugins/beaver/` however you like (unzip, `scp`, `rsync`, your own git, …).
## Bumping the version