Files
didactyl/plans/admin_web_frontend.md

303 lines
9.4 KiB
Markdown

# Didactyl Admin Web Frontend — Project Brief
## What Is Didactyl?
Didactyl is a sovereign AI agent that lives on Nostr. It connects to Nostr relays, listens for encrypted DMs from its administrator, reasons with an LLM, and takes actions — posting events, querying relays, running shell commands, managing skills. Everything the agent knows and does is stored as Nostr events.
The agent is a C binary that runs on a server. It has no web interface of its own — all interaction happens through Nostr DMs.
## What We Are Building
A **local web admin dashboard** that connects to the running didactyl agent via a localhost HTTP API. The dashboard is a prompt crafting and agent inspection tool for the administrator.
This is **not** a chat interface. The administrator already chats with the agent through Nostr DMs. This dashboard is for:
1. **Inspecting** what the agent sees — its full LLM context, broken into labeled parts with token counts
2. **Crafting** custom prompts — editing system prompts, user messages, and context pieces
3. **Running** prompts against the LLM — with or without the agent tool set
4. **Comparing** prompt variants side-by-side — A/B testing different prompt wordings or models
---
## The API
The didactyl agent exposes a localhost-only HTTP API on port `8484` by default. Full API documentation is in `docs/API.md`. All endpoints return JSON with CORS headers.
### Base URL
```
http://127.0.0.1:8484
```
### Currently Implemented Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | `/api/status` | Agent runtime status — name, version, pubkey, relay count, trigger count |
| GET | `/api/context/current` | Full LLM context messages array with total char/token counts |
| GET | `/api/context/parts` | Context broken into labeled parts with individual sizes |
| POST | `/api/prompt/run-simple` | Simple prompt: system + user message, no tools, returns text |
| POST | `/api/prompt/run` | Full prompt: messages array with tools enabled, returns conversation trace |
| POST | `/api/prompt/compare` | A/B test: two prompt variants run sequentially, responses side-by-side |
| GET | `/api/model` | Current LLM model config (provider, model, base_url, max_tokens, temperature) |
| PUT | `/api/model` | Change model at runtime — persists to config.json |
| GET | `/api/models` | List available models from the configured provider |
### Planned Future Endpoints
These are not yet implemented but are on the roadmap:
| Method | Path | Purpose |
|---|---|---|
| GET | `/api/config` | Runtime config with redacted secrets |
| GET | `/api/events/soul` | Agent soul/system prompt event |
| PUT | `/api/events/soul` | Update soul content |
| GET | `/api/events/skills` | List skills |
| GET/PUT | `/api/events/skills/:d_tag` | Read/update individual skills |
| GET | `/api/events/profile` | Agent Nostr profile |
| GET | `/api/tools` | List all tool schemas |
| POST | `/api/tools/:name/execute` | Execute a tool directly |
| GET | `/api/triggers` | Active trigger subscriptions |
| GET | `/api/relays` | Relay connection status |
---
## Core User Workflows
### 1. Context Inspector
The primary read-only workflow. The admin wants to understand what the agent sees when it processes a message.
```mermaid
flowchart TD
LOAD[Load /api/context/parts] --> DISPLAY[Display parts list]
DISPLAY --> DETAIL[Click part to expand content]
DETAIL --> TOKENS[Show char count and token estimate per part]
TOKENS --> TOTAL[Show total context size]
```
**What to show:**
- A list/table of context parts with name, role, character count, estimated tokens
- Total context size as a summary bar or header
- Expandable content for each part
- The parts are: `system_prompt`, `admin_identity`, `admin_profile`, `admin_relay_list`, `startup_events`, `adopted_skills`, `dm_history` (one entry per turn, up to limit), `admin_notes`
- Part names come from the `---template---` section of the soul event (kind 31120); they may differ if the soul is customised
### 2. Simple Prompt Crafting
Quick iteration on prompt wording without tools.
```mermaid
flowchart TD
WRITE[Write system prompt + user message] --> RUN[POST /api/prompt/run-simple]
RUN --> RESULT[Display response text]
RESULT --> EDIT[Edit and re-run]
EDIT --> RUN
```
**What to show:**
- Two text areas: system prompt, user message
- Optional model override dropdown/input
- Run button
- Response display with model used and token estimates
### 3. Full Prompt with Tools
Craft a complete messages array and run it with the agent tool set.
```mermaid
flowchart TD
CONTEXT[Load context from /api/context/parts] --> EDIT[Edit/rearrange context parts]
EDIT --> ADD[Add user message]
ADD --> RUN[POST /api/prompt/run]
RUN --> TRACE[Display conversation trace]
TRACE --> TOOLS[Show tool calls and results per turn]
TOOLS --> FINAL[Show final response]
```
**What to show:**
- Pre-populate from context parts or start from scratch
- Messages editor — add/remove/reorder messages with role and content
- Max turns slider/input
- Optional model override
- Run button
- Turn-by-turn trace showing tool calls with name, arguments, and results
- Final response text
- Token estimates
### 4. A/B Prompt Comparison
Compare two prompt variants side-by-side.
```mermaid
flowchart TD
CRAFT_A[Craft variant A messages] --> CRAFT_B[Craft variant B messages]
CRAFT_B --> COMPARE[POST /api/prompt/compare]
COMPARE --> SIDE[Display responses side-by-side]
SIDE --> DIFF[Compare final responses and token usage]
```
**What to show:**
- Two prompt editors side-by-side, each with messages array + model override + max turns
- Compare button
- Side-by-side response display
- Highlight differences in final response text
- Token usage comparison
### 5. Status Dashboard
Simple overview of agent health.
**What to show:**
- Agent name, version, pubkey
- Connected relays count vs configured
- Active triggers count
- API connection status indicator
---
## Key Design Decisions
### Localhost Only
The API binds to `127.0.0.1` — the frontend must run on the same machine as the agent, or use SSH tunneling. There is no authentication. This is intentional — it is a local dev/admin tool.
### No WebSocket
The API is plain HTTP request/response. There is no WebSocket or streaming. Prompt execution calls may take several seconds for LLM responses — the frontend should show a loading state.
### Token Estimation
All token counts from the API use a `chars / 4` heuristic. This is approximate. The frontend can display these as-is or add its own tokenizer if more precision is needed.
### Model Override
The `model` field in prompt requests temporarily overrides the agent configured model for that single request, then restores the original. This enables cross-model comparison without changing agent config.
### Tool Execution Is Real
When using `/api/prompt/run` or `/api/prompt/compare`, tool calls are **actually executed**. If the LLM decides to post a Nostr event, it will really post it. The frontend should make this clear to the user — perhaps with a warning or confirmation before running prompts with tools enabled.
---
## Response Shapes Quick Reference
### Status
```json
{
"success": true,
"name": "Didactyl",
"version": "v0.0.26",
"pubkey": "52a3e8...",
"relay_count": 4,
"connected_relays": 4,
"active_triggers": 0
}
```
### Context Parts
```json
{
"success": true,
"total_chars": 13131,
"total_estimated_tokens": 3283,
"parts": [
{
"name": "system_prompt",
"role": "system",
"chars": 1200,
"estimated_tokens": 300,
"content": "# Didactyl Agent..."
}
],
"messages": [...]
}
```
### Simple Prompt Response
```json
{
"success": true,
"response": "ok",
"model_used": "claude-haiku-4.5",
"input_tokens_estimate": 10,
"output_tokens_estimate": 1
}
```
### Full Prompt Response
```json
{
"success": true,
"final_response": "Done! I posted a tweet.",
"turns": [
{
"turn": 1,
"tool_calls": [
{"name": "nostr_post", "arguments": "...", "result": "..."}
]
}
],
"model_used": "claude-haiku-4.5",
"total_input_tokens_estimate": 3200,
"total_output_tokens_estimate": 180
}
```
### Compare Response
```json
{
"success": true,
"variant_a": { "...same shape as full prompt response..." },
"variant_b": { "...same shape as full prompt response..." }
}
```
### Error Response
```json
{
"success": false,
"error": "description of what went wrong"
}
```
---
## Technology Suggestions
No technology is mandated for the frontend. Some reasonable choices:
- **Vanilla HTML/JS** — simplest, no build step, just open in browser
- **React/Preact** — if you want component structure
- **Svelte** — lightweight, good for small dashboards
- **Vue** — also fine
The frontend is a separate project from didactyl. It just needs to make HTTP requests to `localhost:8484`.
---
## File References
| File | Description |
|---|---|
| `docs/API.md` | Full API endpoint reference with request/response examples |
| `plans/admin_api.md` | Original architecture plan for the HTTP API |
| `src/http_api.c` | C implementation of all endpoints |
| `src/http_api.h` | Public API header |
| `config.json.example` | Example config showing the `api` section |
---
## Getting Started
1. Ensure didactyl is running with `api.enabled: true` in config.json
2. Verify the API is up: `curl http://127.0.0.1:8484/api/status`
3. Build the frontend to talk to `http://127.0.0.1:8484`
4. Start with the status endpoint and context inspector, then add prompt crafting