feat: add per-session model selection

This commit is contained in:
Peter Steinberger
2025-12-23 23:45:20 +00:00
parent b6bfd8e34f
commit 364a6a9444
34 changed files with 729 additions and 300 deletions

View File

@@ -30,11 +30,11 @@ cp docs/templates/TOOLS.md ~/.clawdis/workspace/TOOLS.md
cp docs/AGENTS.default.md ~/.clawdis/workspace/AGENTS.md
```
4) Optional: choose a different workspace by setting `inbound.workspace` (supports `~`):
4) Optional: choose a different workspace by setting `agent.workspace` (supports `~`):
```json5
{
inbound: {
agent: {
workspace: "~/clawd"
}
}

View File

@@ -12,7 +12,7 @@ read_when:
- Session selection:
- If `--session-id` is given, reuse it.
- Else if `--to <e164>` is given, derive the session key from `inbound.session.scope` (direct chats collapse to `inbound.session.mainKey`).
- Runs the embedded Pi agent (configured via `inbound.agent`).
- Runs the embedded Pi agent (configured via `agent`).
- Thinking/verbose:
- Flags `--thinking <off|minimal|low|medium|high>` and `--verbose <on|off>` persist into the session store.
- Output:

View File

@@ -10,13 +10,13 @@ CLAWDIS runs a single embedded agent runtime derived from **p-mono** (internal n
## Workspace (required)
You must set an agent home directory via `inbound.workspace`. CLAWDIS uses this as the agents **only** working directory (`cwd`) for tools and context.
You must set an agent home directory via `agent.workspace`. CLAWDIS uses this as the agents **only** working directory (`cwd`) for tools and context.
Recommended: use `clawdis setup` to create `~/.clawdis/clawdis.json` if missing and initialize the workspace files.
## Bootstrap files (injected)
Inside `inbound.workspace`, CLAWDIS expects these user-editable files:
Inside `agent.workspace`, CLAWDIS expects these user-editable files:
- `AGENTS.md` — operating instructions + “memory”
- `SOUL.md` — persona, boundaries, tone
- `TOOLS.md` — user-maintained tool notes (e.g. `imsg`, `sag`, conventions)
@@ -75,7 +75,7 @@ Incoming user messages are queued while the agent is streaming. The queue is che
## Configuration (minimal)
At minimum, set:
- `inbound.workspace`
- `agent.workspace`
- `inbound.allowFrom` (strongly recommended)
---

View File

@@ -94,7 +94,7 @@ Tip: treat this folder like Clawds “memory” and make it a git repo (ideal
clawdis setup
```
Optional: choose a different workspace with `inbound.workspace` (supports `~`).
Optional: choose a different workspace with `agent.workspace` (supports `~`).
```json5
{
@@ -149,7 +149,7 @@ Example:
## Heartbeats (proactive mode)
When `inbound.agent.heartbeatMinutes > 0`, CLAWDIS periodically runs a heartbeat prompt (default: `HEARTBEAT`).
When `agent.heartbeatMinutes > 0`, CLAWDIS periodically runs a heartbeat prompt (default: `HEARTBEAT`).
- If the agent replies with `HEARTBEAT_OK` (exact token), CLAWDIS suppresses outbound delivery for that heartbeat.

View File

@@ -11,18 +11,16 @@ CLAWDIS reads an optional **JSON5** config from `~/.clawdis/clawdis.json` (comme
If the file is missing, CLAWDIS uses safe-ish defaults (embedded Pi agent + per-sender sessions + workspace `~/clawd`). You usually only need a config to:
- restrict who can trigger the bot (`inbound.allowFrom`)
- tune group mention behavior (`inbound.groupChat`)
- set the agents workspace (`inbound.workspace`)
- tune the embedded agent (`inbound.agent`) and session behavior (`inbound.session`)
- set the agents workspace (`agent.workspace`)
- tune the embedded agent (`agent`) and session behavior (`inbound.session`)
- set the agents identity (`identity`)
## Minimal config (recommended starting point)
```json5
{
inbound: {
allowFrom: ["+15555550123"],
workspace: "~/clawd"
}
agent: { workspace: "~/clawd" },
inbound: { allowFrom: ["+15555550123"] }
}
```
@@ -86,7 +84,7 @@ Group messages default to **require mention** (either metadata mention or regex
}
```
### `inbound.workspace`
### `agent.workspace`
Sets the **single global workspace directory** used by the agent for file operations.
@@ -94,29 +92,33 @@ Default: `~/clawd`.
```json5
{
inbound: { workspace: "~/clawd" }
agent: { workspace: "~/clawd" }
}
```
### `inbound.agent`
### `agent`
Controls the embedded agent runtime (provider/model/thinking/verbose/timeouts).
`allowedModels` lets `/model` list/filter and enforce a per-session allowlist
(omit to show the full catalog).
```json5
{
inbound: {
workspace: "~/clawd",
agent: {
provider: "anthropic",
model: "claude-opus-4-5",
thinkingDefault: "low",
verboseDefault: "off",
timeoutSeconds: 600,
mediaMaxMb: 5,
heartbeatMinutes: 30,
contextTokens: 200000
}
}
agent: {
provider: "anthropic",
model: "claude-opus-4-5",
allowedModels: [
"anthropic/claude-opus-4-5",
"anthropic/claude-sonnet-4-1"
],
thinkingDefault: "low",
verboseDefault: "off",
timeoutSeconds: 600,
mediaMaxMb: 5,
heartbeatMinutes: 30,
contextTokens: 200000
},
inbound: { workspace: "~/clawd" }
}
```
@@ -132,7 +134,7 @@ When `models.providers` is present, Clawdis writes/merges a `models.json` into
- default behavior: **merge** (keeps existing providers, overrides on name)
- set `models.mode: "replace"` to overwrite the file contents
Select the model via `inbound.agent.provider` + `inbound.agent.model`.
Select the model via `agent.provider` + `agent.model`.
```json5
{

View File

@@ -12,7 +12,7 @@ Goal: add a simple heartbeat poll for the embedded agent that only notifies user
- Keep existing WhatsApp length guidance; forbid burying the sentinel inside alerts.
## Config & defaults
- New config key: `inbound.agent.heartbeatMinutes` (number of minutes; `0` disables).
- New config key: `agent.heartbeatMinutes` (number of minutes; `0` disables).
- Default: 30 minutes.
- New optional idle override for heartbeats: `inbound.session.heartbeatIdleMinutes` (defaults to `idleMinutes`). Heartbeat skips do **not** update the session `updatedAt` so idle expiry still works.

View File

@@ -21,7 +21,7 @@ CLAWDIS is now **web-only** (Baileys). This document captures the current media
## Web Provider Behavior
- Input: local file path **or** HTTP(S) URL.
- Flow: load into a Buffer, detect media kind, and build the correct payload:
- **Images:** resize & recompress to JPEG (max side 2048px) targeting `inbound.agent.mediaMaxMb` (default 5MB), capped at 6MB.
- **Images:** resize & recompress to JPEG (max side 2048px) targeting `agent.mediaMaxMb` (default 5MB), capped at 6MB.
- **Audio/Voice/Video:** pass-through up to 16MB; audio is sent as a voice note (`ptt: true`).
- **Documents:** anything else, up to 100MB, with filename preserved when available.
- MIME detection prefers magic bytes, then headers, then file extension.

View File

@@ -8,7 +8,7 @@ read_when:
# Workspace Memory v2 (offline): proposal + research
Target: Clawd-style workspace (`inbound.workspace`, default `~/clawd`) where “memory” is stored as one Markdown file per day (`memory/YYYY-MM-DD.md`) plus a small set of stable files (e.g. `memory.md`, `SOUL.md`).
Target: Clawd-style workspace (`agent.workspace`, default `~/clawd`) where “memory” is stored as one Markdown file per day (`memory/YYYY-MM-DD.md`) plus a small set of stable files (e.g. `memory.md`, `SOUL.md`).
This doc proposes an **offline-first** memory architecture that keeps Markdown as the canonical, reviewable source of truth, but adds **structured recall** (search, entity summaries, confidence updates) via a derived index.
@@ -159,7 +159,7 @@ Recommendation: **deep integration in Clawdis**, but keep a separable core libra
### Why integrate into Clawdis?
- Clawdis already knows:
- the workspace path (`inbound.workspace`)
- the workspace path (`agent.workspace`)
- the session model + heartbeats
- logging + troubleshooting patterns
- You want the agent itself to call the tools:
@@ -225,4 +225,3 @@ Open question:
- Letta / MemGPT concepts: “core memory blocks” + “archival memory” + tool-driven self-editing memory.
- Hindsight Technical Report: “retain / recall / reflect”, four-network memory, narrative fact extraction, opinion confidence evolution.
- SuCo: arXiv 2411.14754 (2024): “Subspace Collision” approximate nearest neighbor retrieval.

View File

@@ -17,7 +17,7 @@ read_when:
## Resolution order
1. Inline directive on the message (applies only to that message).
2. Session override (set by sending a directive-only message).
3. Global default (`inbound.agent.thinkingDefault` in config).
3. Global default (`agent.thinkingDefault` in config).
4. Fallback: off.
## Setting a session default

View File

@@ -80,13 +80,13 @@ Status: WhatsApp Web via Baileys only. Gateway owns the single session.
## Media limits + optimization
- Default cap: 5 MB (per media item).
- Override: `inbound.agent.mediaMaxMb`.
- Override: `agent.mediaMaxMb`.
- Images are auto-optimized to JPEG under cap (resize + quality sweep).
- Oversize media => error; media reply falls back to text warning.
## Heartbeats
- **Gateway heartbeat** logs connection health (`web.heartbeatSeconds`, default 60s).
- **Reply heartbeat** asks agent on a timer (`inbound.agent.heartbeatMinutes`).
- **Reply heartbeat** asks agent on a timer (`agent.heartbeatMinutes`).
- Uses `HEARTBEAT` prompt + `HEARTBEAT_TOKEN` skip behavior.
- Skips if queue busy or last inbound was a group.
- Falls back to last direct recipient if needed.
@@ -103,8 +103,8 @@ Status: WhatsApp Web via Baileys only. Gateway owns the single session.
- `inbound.groupChat.historyLimit`
- `inbound.messagePrefix` (inbound prefix)
- `inbound.responsePrefix` (outbound prefix)
- `inbound.agent.mediaMaxMb`
- `inbound.agent.heartbeatMinutes`
- `agent.mediaMaxMb`
- `agent.heartbeatMinutes`
- `inbound.session.*` (scope, idle, store, mainKey)
- `web.heartbeatSeconds`
- `web.reconnect.*`
@@ -118,4 +118,3 @@ Status: WhatsApp Web via Baileys only. Gateway owns the single session.
- `src/web/auto-reply.test.ts` (mention gating, history injection, reply flow)
- `src/web/monitor-inbox.test.ts` (inbound parsing + reply context)
- `src/web/outbound.test.ts` (send mapping + media)