303 lines
9.4 KiB
Markdown
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
|