151 lines
7.3 KiB
Markdown
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` |
|