Files
nanobot-ts/memory-bank/systemPatterns.md

101 lines
3.6 KiB
Markdown

# System Patterns
## Type Definition Pattern
Every module that has runtime-validated data uses a dedicated `types.ts` file:
```
src/config/types.ts ← Zod schemas + `export type X = z.infer<typeof XSchema>`
src/bus/types.ts
src/session/types.ts
src/cron/types.ts
src/provider/types.ts
```
The implementation files (`loader.ts`, `manager.ts`, etc.) import types from the sibling `types.ts`.
## Tool Pattern
All tools implement the `Tool` interface from `src/agent/tools/base.ts`:
```ts
interface Tool {
name: string
description: string
parameters: Record<string, unknown> // JSON Schema object
execute(args: Record<string, unknown>): Promise<string>
}
```
`ToolRegistry` stores tools by name, exposes `getDefinitions()` (OpenAI function-calling format), and `execute(name, args)`.
## Message Bus Pattern
Inbound and outbound messages are passed through a typed `AsyncQueue<T>`. The queue uses a `Promise`-based dequeue that resolves when an item is available (mirrors Python `asyncio.Queue`).
## Provider Pattern
`LLMProvider` (`src/provider/index.ts`) wraps the Vercel AI SDK `generateText()`. It:
- Accepts a model string and resolves it to the correct AI SDK provider instance
- Implements `chatWithRetry()` with 3 attempts on transient errors (429, 5xx, timeout)
- Repairs malformed tool-call JSON with `jsonrepair`
- Returns a normalized `LLMResponse` type
## Config Pattern
- Config file: `~/.config/nanobot/config.json` (camelCase JSON)
- Loaded with `loadConfig()`, validated by Zod, returns inferred `Config` type
- `NANOBOT_` env vars can override fields (e.g. `NANOBOT_MODEL`)
## Mattermost Channel Pattern
- Inbound: native `WebSocket` connecting to `wss://{server}/api/v4/websocket`, auth via hello message
- Outbound: `fetch()` to `POST /api/v4/posts`
- Session key: `mattermost:{channelId}` (or `mattermost:{channelId}:{rootId}` when `replyInThread`)
## Session Key Convention
`{channel}:{chatId}` — e.g. `mattermost:abc123`, `cli:direct`
## Logging Pattern
Use `console.error` / `console.warn` / `console.info` / `console.debug` — no external logger. Color via `picocolors` in CLI output only.
## CLI Command Pattern
Each command is in its own file with a registration function:
```ts
// src/cli/agent.ts
export function agentCommand(program: Command, config: Config, workspace: string): void {
program.command('agent')
.description('...')
.option('-m, --message <text>', 'Single message to process')
.action(async (opts) => { /* ... */ })
}
// src/cli/commands.ts (bootstrap)
export function createCli(): Command {
const program = new Command('nanobot')...
const config = loadConfig(opts.config);
const workspace = resolveWorkspacePath(config.agent.workspacePath);
gatewayCommand(program, config, workspace);
agentCommand(program, config, workspace);
return program;
}
```
## File Layout
```
src/
config/types.ts + loader.ts
bus/types.ts + queue.ts
provider/types.ts + index.ts
session/types.ts + manager.ts
cron/types.ts + service.ts
heartbeat/service.ts
agent/
memory.ts
skills.ts
context.ts
loop.ts
subagent.ts
tools/base.ts + filesystem.ts + shell.ts + web.ts + message.ts + spawn.ts + cron.ts
channels/
base.ts + mattermost.ts + manager.ts
cli/
types.ts # CommandHandler type
commands.ts # Bootstrap - loads config, registers commands
agent.ts # agentCommand() - interactive/single-shot mode
gateway.ts # gatewayCommand() - full runtime with Mattermost
index.ts
templates/ (SOUL.md, AGENTS.md, USER.md, TOOLS.md, HEARTBEAT.md, memory/MEMORY.md)
skills/ (copied from Python repo)
```