Files
nanobot-ts/docs/Architecture.md
2026-03-13 12:24:20 -06:00

151 lines
7.3 KiB
Markdown

# Architecture
## Tech Stack
| Layer | Technology |
|-------|------------|
| Runtime | Bun (v1.0+) |
| Language | TypeScript (strict mode) |
| LLM Abstraction | Vercel AI SDK v6 |
| Validation | Zod v4 |
| CLI | Commander |
| Colors | picocolors |
| Formatting | oxfmt (single quotes) |
| Linting | oxlint |
## Folder Structure
```
nanobot-ts/
├── index.ts # Entry point
├── src/
│ ├── agent/
│ │ ├── loop.ts # AgentLoop: LLM ↔ tool execution loop
│ │ ├── context.ts # ContextBuilder: system prompt assembly
│ │ ├── memory.ts # MemoryConsolidator: token management
│ │ ├── skills.ts # Skill loader from workspace
│ │ ├── subagent.ts # SubagentManager: background tasks
│ │ └── tools/
│ │ ├── base.ts # Tool interface + ToolRegistry
│ │ ├── filesystem.ts # read_file, write_file, edit_file, list_dir
│ │ ├── shell.ts # exec
│ │ ├── web.ts # web_search, web_fetch
│ │ ├── message.ts # message
│ │ ├── spawn.ts # spawn
│ │ └── cron.ts # cron
│ ├── channels/
│ │ ├── base.ts # BaseChannel abstract class
│ │ ├── mattermost.ts # Mattermost WebSocket + REST
│ │ └── manager.ts # ChannelManager lifecycle
│ ├── bus/
│ │ ├── types.ts # InboundMessage, OutboundMessage schemas
│ │ └── queue.ts # AsyncQueue, MessageBus
│ ├── provider/
│ │ ├── types.ts # LLMResponse, ToolCall, ChatOptions
│ │ └── index.ts # LLMProvider (AI SDK wrapper)
│ ├── session/
│ │ ├── types.ts # SessionMessage, SessionMeta schemas
│ │ └── manager.ts # Session persistence (JSONL)
│ ├── cron/
│ │ ├── types.ts # CronJob, CronSchedule schemas
│ │ └── service.ts # CronService
│ ├── heartbeat/
│ │ └── service.ts # HeartbeatService
│ ├── config/
│ │ ├── types.ts # Zod config schemas
│ │ └── loader.ts # loadConfig, env overrides
│ └── cli/
│ └── commands.ts # gateway + agent commands
├── templates/ # Default workspace files
│ ├── SOUL.md # Agent personality
│ ├── USER.md # User preferences
│ ├── TOOLS.md # Tool documentation
│ ├── AGENTS.md # Agent behavior rules
│ ├── HEARTBEAT.md # Periodic tasks
│ └── memory/MEMORY.md # Long-term memory
└── skills/ # Bundled skills
```
## Data Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ Gateway Mode │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Mattermost ──► BaseChannel ──► MessageBus ──► AgentLoop │
│ ▲ │ │ │
│ │ ▼ ▼ │
│ │ OutboundQueue LLMProvider │
│ │ │ │ │
│ └───────────────────────────────┘ ▼ │
│ ToolRegistry │
│ │ │
│ ▼ │
│ Tool.execute() │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Agent Mode │
├─────────────────────────────────────────────────────────────────┤
│ │
│ CLI stdin ──► processDirect() ──► AgentLoop ──► Response │
│ │
└─────────────────────────────────────────────────────────────────┘
```
## Key Components
### AgentLoop
The core orchestrator. Consumes inbound messages, runs the LLM tool-calling loop, and publishes responses.
1. Receives `InboundMessage` from bus
2. Loads/creates session by key
3. Builds context (system prompt + history)
4. Calls LLM with tools
5. Executes tool calls, appends results
6. Repeats until no tool calls or max iterations
7. Saves session, publishes response
### MessageBus
An async queue system for decoupling channels from the agent loop.
- `publishInbound()` / `consumeInbound()`: messages from channels to agent
- `publishOutbound()` / `consumeOutbound()`: responses from agent to channels
### LLMProvider
Wraps Vercel AI SDK `generateText()` with:
- Model string resolution (e.g., `openrouter/anthropic/claude-sonnet-4-5`)
- Retry logic (3 attempts, exponential backoff)
- Malformed JSON repair
- Normalized `LLMResponse` type
### SessionManager
Persists conversation history to JSONL files in `~/.nanobot/sessions/`.
- Key format: `{channel}:{chatId}` (e.g., `mattermost:abc123`)
- Supports history truncation for context window limits
### ToolRegistry
Stores tools by name, provides OpenAI-compatible function definitions to the LLM.
### MemoryConsolidator
When session history exceeds token limits, summarizes old messages and archives to `memory/MEMORY.md`.
## Configuration
- File: `~/.nanobot/config.json`
- Validation: Zod schemas in `src/config/types.ts`
- Env overrides: `NANOBOT_MODEL`, `NANOBOT_WORKSPACE`, `NANOBOT_CONFIG`
## Session Key Convention
| Channel | Key Format | Example |
|---------|-----------|----------|
| Mattermost | `mattermost:{channelId}` | `mattermost:abc123` |
| Mattermost (thread) | `mattermost:{channelId}:{rootId}` | `mattermost:abc:def456` |
| CLI | `cli:{chatId}` | `cli:interactive` |
| System | `system:{source}` | `system:heartbeat` |