diff --git a/docs/design/launcher_wails_migration.md b/docs/design/launcher_wails_migration.md new file mode 100644 index 000000000..28f2f0f33 --- /dev/null +++ b/docs/design/launcher_wails_migration.md @@ -0,0 +1,50 @@ +# PicoClaw Launcher — Wails v2 Migration + +## Overview + +Desktop GUI for PicoClaw using Wails v2, replacing the previous HTTP server + browser approach. + +## Architecture + +``` +cmd/picoclaw-launcher/ +├── main.go # Wails bootstrap +├── app.go # App struct with Go↔JS bindings +├── helpers.go # Gateway process management +├── tray.go # System tray integration +├── wails.json # Wails project config +├── frontend/ +│ ├── index.html # Single-file UI (3 tabs) +│ └── wailsjs/ # Auto-generated bindings +└── internal/server/ + ├── setup.go # Config setup helpers + └── setup_chat.go # AI chat server +``` + +## UI: 3-Tab Layout + +| Tab | Features | +|-----|----------| +| **Status** | Gateway start/stop/restart, real-time status | +| **Chat** | AI chat interface, first-run setup questionnaire | +| **Settings** | Model/channel/API key config, save/reload | + +## Key Design Choices + +- **Wails bindings** instead of HTTP: `window.go.main.App.GetConfig()` replaces `fetch('/api/config')` +- **System tray**: minimize-to-tray on close, right-click menu for gateway control +- **First-run setup**: guided overlay when no config exists → AI chat questionnaire +- **Single index.html**: intentional for v1 (no build toolchain), will split if complexity grows + +## Build + +```bash +go tool wails build -o picoclaw-launcher +# or via Taskfile: +task build-launcher +``` + +## Dependencies + +- Wails v2 (declared as `tool` in go.mod, not linked into picoclaw binary) +- WebView2 (Windows, auto-installed), GTK/WebKit (Linux), WebKit (macOS) diff --git a/docs/design/runtime_builtin_cmd.md b/docs/design/runtime_builtin_cmd.md new file mode 100644 index 000000000..c4a1aa4fa --- /dev/null +++ b/docs/design/runtime_builtin_cmd.md @@ -0,0 +1,39 @@ +# Runtime Commands + +## Slash Commands + +All commands start with `/`, handled synchronously by `Reflector.HandleCommand()`. + +| Command | Usage | Description | +|---------|-------|-------------| +| `/help` | `/help` | List all commands | +| `/memory list` | `/memory list` | Show recent memories | +| `/memory add` | `/memory add #tags` | Add a memory | +| `/memory delete` | `/memory delete ` | Delete by ID | +| `/memory search` | `/memory search ` | Search by tags | +| `/memory stats` | `/memory stats` | Memory statistics | +| `/cot feedback` | `/cot feedback <1\|0\|-1>` | Rate last CoT strategy | +| `/cot stats` | `/cot stats` | CoT performance stats | +| `/cot history` | `/cot history [N]` | Recent CoT usage | +| `/shell` | `/shell [args]` | Execute shell command | +| `/show model` | `/show model` | Current model | +| `/list agents` | `/list agents` | List agents | +| `/switch model to` | `/switch model to ` | Switch model | +| `/runtime status` | `/runtime status` | Runtime diagnostics | + +## /shell Architecture + +``` +/shell + ├─ Built-in (pure Go, cross-platform) + │ ls, cat, head, tail, grep, wc, find, diff, tree, + │ stat, pwd, echo, touch, mkdir, cp, mv + └─ Dev Tool Passthrough (via exec tool) + go, git, node, python, npm, cargo, make, jq, rg +``` + +## Security + +- Built-in: Go stdlib only, auto-skip `.git`/`node_modules`, output capped at 4000 chars +- Passthrough: whitelist + deny patterns (`| sh`, `$()`, etc.) + ExecTool workspace restriction +- Unknown commands: rejected \ No newline at end of file diff --git a/docs/design/runtime_loop_design.md b/docs/design/runtime_loop_design.md new file mode 100644 index 000000000..6dd7b336c --- /dev/null +++ b/docs/design/runtime_loop_design.md @@ -0,0 +1,77 @@ +# Runtime Loop Design + +> Status: Implemented | Date: 2026-03-02 + +## Architecture + +``` +Message ──→ Phase 1 (Analyse) ──→ Phase 2 (Execute) ──→ Phase 3 (Reflect) +``` + +| Phase | File | Responsibility | +|-------|------|----------------| +| **Analyse** | `analyser.go` | Lightweight LLM → intent, tags, CoT prompt | +| **Execute** | `executor.go` | LLM iteration loop + tool calling | +| **Reflect** | `reflector.go` | Turn scoring, TurnRecord persistence, slash commands | + +## Turn Definition + +One Turn = user message + Phase 1 result + all Phase 2 iterations + Phase 3 output. +Multiple tool-call iterations within Phase 2 count as **one Turn**. + +## Phase 1: Analyse + +- Uses configurable `analyser_model` (fast/cheap model, falls back to main model) +- Inputs: user message, Active Context, available tags, CoT learning data +- Outputs: `intent`, `tags[]`, `cot_prompt` +- After analysis: memory retrieval by tags, CoT injection into system prompt + +## Phase 2: Execute + +- LLM → tool call → tool result loop until no more tool calls +- Retry logic for context window overflow with automatic compression +- Reasoning output forwarded to dedicated channels + +## Phase 3: Reflect + +- **SyncPhase3** (< 2ms, before response sent): turn scoring + Active Context update +- **AsyncPhase3** (after response): `go turnStore.Insert(record)` → SQLite +- Slash commands: `/memory`, `/cot`, `/shell`, `/show`, `/list`, `/switch`, `/help` + +## Scoring Rules + +| Condition | Score | +|-----------|-------| +| Has tool calls | +3 | +| Write/edit tools | +2 | +| intent = task/code/debug | +3 | +| Reply > 500 chars | +2 | +| Short exchange < 80 chars | -2 | + +## Memory Hierarchy + +| Layer | Lifetime | Purpose | +|-------|----------|---------| +| Instant Memory | Per-turn | Dynamic window from TurnStore (score + tag filtering) | +| Active Context | Per-session | `CurrentFiles` + `RecentErrors`, injected into user prompt | +| Long-term Memory | Persistent | MemoryDigest batch extraction → `memory.db` | + +## Multi-Model Support + +| Config Field | Phase | Fallback | +|-------------|-------|----------| +| `model_name` | Phase 2 | — | +| `analyser_model` | Phase 1 | → `model_name` | +| `digest_model` | MemoryDigest | → `model_name` | + +## Message Ordering (KV Cache Friendly) + +``` +[system_prompt] → always cached +[long_term_memory by tags] → cached when same tags +[always_keep turns (score≥7)] → fixed position, append-only +[recent turns] → rolling window +[current user message] → new each turn +``` + +Active Context injected as **user message** (not system prompt) to keep system prompt prefix stable. diff --git a/docs/design/runtime_loop_task.md b/docs/design/runtime_loop_task.md new file mode 100644 index 000000000..6893eb986 --- /dev/null +++ b/docs/design/runtime_loop_task.md @@ -0,0 +1,55 @@ +# Runtime Loop Implementation Tasks + +> Design ref: `docs/design/picoclaw_runtime_loop_design.md` + +## Design Decisions + +| Decision | Conclusion | +|----------|------------| +| Turn storage | SQLite `turns.db` | +| Active Context fields | `CurrentFiles` + `RecentErrors` only | +| Phase 1 short-circuit | No — short messages need Active Context most | +| Async write | Direct `go insert()`, no channel buffer | +| Token budget check | Periodic time-based archival instead | +| Tag-gated tools | Deferred until tool count > 15 | +| KV Cache | Fixed ordering (high-score first, by ID ASC) | + +## Milestones + +### M1: Turn Score + Phase 3 Timing — ✅ + +- [x] `score.go`: `CalcTurnScore(input) int` +- [x] Split `RunPostLLM` → `SyncPhase3` (sync, < 2ms) + `AsyncPhase3` (goroutine) +- [x] Adjust `runAgentLoop` timing: score → publish → async write + +### M2: Active Context — ✅ + +- [x] `active_context.go`: per `channel:chatID` store +- [x] Fields: `CurrentFiles` (5), `RecentErrors` (3) +- [x] Injected as user message (not system prompt) for KV cache stability +- [x] Flush to JSON on shutdown, load on startup + +### M3: TurnStore — ✅ + +- [x] `turn_store.go`: SQLite `turns.db` with WAL mode +- [x] Methods: Insert, QueryPending, QueryByScore, QueryByTags, QueryRecent, ArchiveOldProcessed +- [x] Async insert via goroutine in AsyncPhase3 + +### M4: MemoryDigest — ✅ + +- [x] `memory_digest.go`: background worker (5min interval) +- [x] QueryPending → group by channel → LLM batch extraction → MemoryStore +- [x] Removed `MemoryExtractor` and `CotEvaluator` processors (kept `ErrorTracker`) + +### M5: Instant Memory + KV Cache Ordering — ✅ + +- [x] `instant_memory.go`: dynamic window from TurnStore +- [x] Cache-friendly message ordering: system → memory → high-score → recent → current +- [x] Legacy SessionManager kept as fallback + +## Deferred + +| Item | Reason | +|------|--------| +| Tag-gated tool loading | Tool count < 10 currently | +| Summary Anchor | Fixed ordering sufficient for v1 | \ No newline at end of file