camelagi 0.5.0 → 0.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +241 -104
- package/dist/agent/agent-sdk.js +136 -65
- package/dist/agent/agent-sdk.js.map +1 -1
- package/dist/agent.js +4 -1
- package/dist/agent.js.map +1 -1
- package/dist/bootstrap.js +148 -331
- package/dist/bootstrap.js.map +1 -1
- package/dist/channels/handler.js +109 -1
- package/dist/channels/handler.js.map +1 -1
- package/dist/cli/cmd-agents.js +186 -24
- package/dist/cli/cmd-agents.js.map +1 -1
- package/dist/cli/cmd-bootstrap.js +4 -4
- package/dist/cli/cmd-bootstrap.js.map +1 -1
- package/dist/cli/cmd-install.js +80 -0
- package/dist/cli/cmd-install.js.map +1 -0
- package/dist/cli/cmd-pairing.js +14 -15
- package/dist/cli/cmd-pairing.js.map +1 -1
- package/dist/cli/cmd-reset.js +10 -12
- package/dist/cli/cmd-reset.js.map +1 -1
- package/dist/cli/cmd-sessions.js +10 -13
- package/dist/cli/cmd-sessions.js.map +1 -1
- package/dist/cli/cmd-status.js +67 -0
- package/dist/cli/cmd-status.js.map +1 -0
- package/dist/cli/cmd-uninstall.js +79 -0
- package/dist/cli/cmd-uninstall.js.map +1 -0
- package/dist/cli/cmd-update.js +47 -0
- package/dist/cli/cmd-update.js.map +1 -0
- package/dist/cli.js +44 -26
- package/dist/cli.js.map +1 -1
- package/dist/core/config.js +53 -8
- package/dist/core/config.js.map +1 -1
- package/dist/core/log.js +33 -13
- package/dist/core/log.js.map +1 -1
- package/dist/core/update-check.js +11 -13
- package/dist/core/update-check.js.map +1 -1
- package/dist/core/version.js +4 -0
- package/dist/core/version.js.map +1 -0
- package/dist/runtime/orchestrate.js +25 -15
- package/dist/runtime/orchestrate.js.map +1 -1
- package/dist/serve.js +22 -7
- package/dist/serve.js.map +1 -1
- package/dist/setup.js +259 -231
- package/dist/setup.js.map +1 -1
- package/dist/telegram/admin-bot.js +325 -1
- package/dist/telegram/admin-bot.js.map +1 -1
- package/dist/telegram/agent-bot.js +143 -2
- package/dist/telegram/agent-bot.js.map +1 -1
- package/dist/telegram/resolve.js +11 -2
- package/dist/telegram/resolve.js.map +1 -1
- package/dist/telegram/wizards.js +361 -12
- package/dist/telegram/wizards.js.map +1 -1
- package/dist/telegram.js +2 -0
- package/dist/telegram.js.map +1 -1
- package/dist/usage.js +106 -0
- package/dist/usage.js.map +1 -1
- package/dist/workspace.js +20 -0
- package/dist/workspace.js.map +1 -1
- package/package.json +7 -4
- package/dist/agent/agent-openai.js +0 -206
- package/dist/agent/agent-openai.js.map +0 -1
- package/dist/approval-forward.js +0 -42
- package/dist/approval-forward.js.map +0 -1
- package/dist/approvals.js +0 -151
- package/dist/approvals.js.map +0 -1
- package/dist/camelagi-gateway.mjs +0 -93611
- package/dist/camelagi-gateway.mjs.map +0 -7
- package/dist/compact.js +0 -92
- package/dist/compact.js.map +0 -1
- package/dist/config.js +0 -153
- package/dist/config.js.map +0 -1
- package/dist/constants.js +0 -21
- package/dist/constants.js.map +0 -1
- package/dist/cron.js +0 -81
- package/dist/cron.js.map +0 -1
- package/dist/errors.js +0 -5
- package/dist/errors.js.map +0 -1
- package/dist/hooks.js +0 -72
- package/dist/hooks.js.map +0 -1
- package/dist/lanes.js +0 -62
- package/dist/lanes.js.map +0 -1
- package/dist/policy.js +0 -22
- package/dist/policy.js.map +0 -1
- package/dist/queue.js +0 -45
- package/dist/queue.js.map +0 -1
- package/dist/retry.js +0 -96
- package/dist/retry.js.map +0 -1
- package/dist/runs.js +0 -83
- package/dist/runs.js.map +0 -1
- package/dist/skills.js +0 -89
- package/dist/skills.js.map +0 -1
- package/dist/subagent.js +0 -71
- package/dist/subagent.js.map +0 -1
- package/dist/telegram-admin.js +0 -800
- package/dist/telegram-admin.js.map +0 -1
- package/dist/tools/edit.js +0 -29
- package/dist/tools/edit.js.map +0 -1
- package/dist/tools/exec.js +0 -38
- package/dist/tools/exec.js.map +0 -1
- package/dist/tools/fetch.js +0 -28
- package/dist/tools/fetch.js.map +0 -1
- package/dist/tools/index.js +0 -16
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/read.js +0 -26
- package/dist/tools/read.js.map +0 -1
- package/dist/tools/search.js +0 -62
- package/dist/tools/search.js.map +0 -1
- package/dist/tools/subagent.js +0 -48
- package/dist/tools/subagent.js.map +0 -1
- package/dist/tools/write.js +0 -22
- package/dist/tools/write.js.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026
|
|
3
|
+
Copyright (c) 2026 Nawaf Almutairi & Brickell Lab, Kuwait
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -16,27 +16,186 @@
|
|
|
16
16
|
|
|
17
17
|
<br>
|
|
18
18
|
|
|
19
|
-
CamelAGI is a self-hosted AI assistant that runs on your server and puts you in full control from your phone. One command to
|
|
19
|
+
CamelAGI is a self-hosted AI assistant that runs on your server and puts you in full control from your phone. One command to install, then manage everything — create agents, switch models, approve tools, monitor usage — all from Telegram, Discord, or your terminal.
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
22
|
-
<
|
|
22
|
+
<img src="assets/Claude_Logo.png" alt="Claude Logo" width="200" />
|
|
23
|
+
</p>
|
|
24
|
+
<p align="center">
|
|
25
|
+
Powered by <a href="https://platform.claude.com/docs/en/agent-sdk/overview">Claude Agent SDK</a> — the same runtime behind Claude Code.
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<a href="https://camelagi.net"><strong>camelagi.net</strong></a>
|
|
23
30
|
</p>
|
|
24
31
|
|
|
25
32
|
## Contents
|
|
26
33
|
|
|
27
|
-
- [Built on Claude Agent SDK](#built-on-claude-agent-sdk)
|
|
28
|
-
- [Admin Bot — BotFather for Your AI Server](#admin-bot--botfather-for-your-ai-server)
|
|
29
|
-
- [Claude Agent SDK vs pi-agent](#claude-agent-sdk-vs-pi-agent)
|
|
30
34
|
- [Quick Start](#quick-start)
|
|
31
35
|
- [Features](#features)
|
|
32
|
-
- [
|
|
33
|
-
- [
|
|
34
|
-
- [
|
|
36
|
+
- [Channels](#channels)
|
|
37
|
+
- [Admin Bot Commands](#admin-bot-commands)
|
|
38
|
+
- [Agent Bot Commands](#agent-bot-commands)
|
|
39
|
+
- [CLI Commands](#cli-commands)
|
|
40
|
+
- [Built on Claude Agent SDK](#built-on-claude-agent-sdk)
|
|
41
|
+
- [Claude Agent SDK vs pi-agent](#claude-agent-sdk-vs-pi-agent)
|
|
42
|
+
- [Configuration](#configuration)
|
|
43
|
+
- [Architecture](#architecture)
|
|
35
44
|
- [Documentation](#documentation)
|
|
45
|
+
- [Roadmap](#roadmap)
|
|
36
46
|
- [License](#license)
|
|
37
47
|
|
|
38
48
|
<br>
|
|
39
49
|
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
**Install** (no Node.js required)
|
|
53
|
+
```bash
|
|
54
|
+
curl -fsSL https://raw.githubusercontent.com/inawafalm/CamelAGI/main/install.sh | bash
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Setup & Run**
|
|
58
|
+
```bash
|
|
59
|
+
camel bootstrap # Full setup: admin bot + pairing + API config
|
|
60
|
+
camel serve # Start the gateway server
|
|
61
|
+
camel chat # Terminal UI
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`bootstrap` walks you through everything: create a Telegram admin bot, pair your account with OTP, pick your AI provider and model. After that, use `/newagent` in Telegram to create your first AI agent.
|
|
65
|
+
|
|
66
|
+
<br>
|
|
67
|
+
|
|
68
|
+
## Features
|
|
69
|
+
|
|
70
|
+
> 3 channels, 18 CLI commands, 10 built-in tools — terminal, Telegram, or Discord.
|
|
71
|
+
|
|
72
|
+
| | Feature | Description |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| 🤖 | **Telegram — Admin Bot** | BotFather for AI agents. Create, configure, clone, and manage agents entirely from Telegram — instant commands, zero tokens |
|
|
75
|
+
| 💬 | **Telegram — Agent Bots** | Each agent gets its own Telegram bot. Message it like any chat — it runs tools, reads files, remembers context |
|
|
76
|
+
| 🎮 | **Discord Bots** | Per-agent Discord bots with mention-only mode, role filtering, and channel restrictions |
|
|
77
|
+
| ⌨️ | **Terminal UI** | Full TUI with streaming, slash commands, model switching, session management, and markdown rendering |
|
|
78
|
+
| 🧠 | **Agent Memory** | Isolated two-tier memory per agent — curated MEMORY.md + daily auto-journaling with recency-boosted search |
|
|
79
|
+
| 🎙️ | **Voice Transcription** | Send voice messages to agent bots — transcribed via Groq, OpenAI, or Deepgram and processed as text |
|
|
80
|
+
| 🔌 | **MCP Servers** | Connect external tool servers (stdio, HTTP, SSE). Global or per-agent. Add/remove from Telegram with `/mcp` |
|
|
81
|
+
| 💭 | **Extended Thinking** | Claude reasons step by step before answering. Configure depth: off, low, medium, high |
|
|
82
|
+
| ⏰ | **Cron Jobs** | Schedule AI tasks — daily summaries, monitoring, automations. Intervals, cron expressions, or one-shot timers |
|
|
83
|
+
| 📋 | **Brief Mode** | Toggle short text-message-style replies per chat or per agent — ideal for Telegram |
|
|
84
|
+
| 📊 | **Usage Tracking** | Per-agent token usage and cost breakdown — input, output, cache reads, API calls |
|
|
85
|
+
| 🧬 | **Agent Cloning** | Clone an existing agent with all its config, personality, memory, and MCP servers |
|
|
86
|
+
| 🔐 | **Secure Pairing** | OTP-based user verification. No hardcoded IDs — pairing code + 5-digit OTP from Telegram |
|
|
87
|
+
| 🔁 | **Multi-Provider** | Anthropic, OpenAI, OpenRouter, Ollama — any OpenAI-compatible endpoint. Zero vendor lock-in |
|
|
88
|
+
| 🛡️ | **Tool Approvals** | Human-in-the-loop safety. Approve dangerous operations from Telegram with inline buttons |
|
|
89
|
+
| 🪝 | **Skills & Hooks** | Teach agents skills via Markdown. Run shell/JS hooks before and after tool calls |
|
|
90
|
+
| 🔄 | **Auto Compaction** | Summarizes old turns at 80% capacity. Flushes facts to memory first — nothing is lost |
|
|
91
|
+
| ⚙️ | **Same Engine** | All channels run the same agent loop, same tools, same memory. Switch freely between them |
|
|
92
|
+
|
|
93
|
+
<br>
|
|
94
|
+
|
|
95
|
+
## Channels
|
|
96
|
+
|
|
97
|
+
CamelAGI runs across three channels — all sharing the same agent runtime, tools, and memory.
|
|
98
|
+
|
|
99
|
+
### Telegram
|
|
100
|
+
|
|
101
|
+
Two bot types work together:
|
|
102
|
+
|
|
103
|
+
- **Admin Bot** — A non-AI command bot (zero tokens burned). Create agents, manage config, approve users, monitor sessions, configure MCP servers, set up voice — all from Telegram. Think [@BotFather](https://t.me/BotFather), but for your entire AI infrastructure.
|
|
104
|
+
- **Agent Bots** — Each agent gets its own Telegram bot. Message it like any contact — it runs tools, reads files, remembers context, and supports voice messages.
|
|
105
|
+
|
|
106
|
+
### Discord
|
|
107
|
+
|
|
108
|
+
Per-agent Discord bots with:
|
|
109
|
+
- **Mention-only mode** — responds only to @mentions in guild channels, all messages in DMs
|
|
110
|
+
- **Role filtering** — optional allowlist of Discord roles
|
|
111
|
+
- **Channel restrictions** — optional allowlist of channels
|
|
112
|
+
|
|
113
|
+
### Terminal
|
|
114
|
+
|
|
115
|
+
`camel chat` gives you a full TUI with streaming, slash commands, keyboard shortcuts, model switching, session management, and one-shot mode (`camel "your question"`).
|
|
116
|
+
|
|
117
|
+
<br>
|
|
118
|
+
|
|
119
|
+
## Admin Bot Commands
|
|
120
|
+
|
|
121
|
+
The Admin Bot is a non-AI Telegram bot for managing your entire CamelAGI server.
|
|
122
|
+
|
|
123
|
+
| Category | Command | Description |
|
|
124
|
+
|----------|---------|-------------|
|
|
125
|
+
| **Setup** | `/setup` | Configure API provider, key, model |
|
|
126
|
+
| | `/config` | View configuration |
|
|
127
|
+
| | `/config <key> <value>` | Update config |
|
|
128
|
+
| **Agents** | `/newagent` | Create agent wizard |
|
|
129
|
+
| | `/agents` | List all agents |
|
|
130
|
+
| | `/agent` | View/edit agent config |
|
|
131
|
+
| | `/deleteagent` | Delete an agent |
|
|
132
|
+
| | `/soul` | View/edit agent personality |
|
|
133
|
+
| **Tools** | `/mcp` | Manage MCP servers (add/list/remove) |
|
|
134
|
+
| | `/voice` | Configure voice transcription provider |
|
|
135
|
+
| **Monitor** | `/status` | System health & stats |
|
|
136
|
+
| | `/sessions` | List & manage sessions |
|
|
137
|
+
| | `/usage` | Per-agent usage & cost summary |
|
|
138
|
+
| | `/restart` | Restart agent bots |
|
|
139
|
+
| **Security** | `/pairing` | Manage access requests |
|
|
140
|
+
| **Utility** | `/help` | List all commands |
|
|
141
|
+
| | `/cancel` | Cancel active wizard |
|
|
142
|
+
|
|
143
|
+
<br>
|
|
144
|
+
|
|
145
|
+
## Agent Bot Commands
|
|
146
|
+
|
|
147
|
+
Each agent bot supports these commands in Telegram:
|
|
148
|
+
|
|
149
|
+
| Category | Command | Description |
|
|
150
|
+
|----------|---------|-------------|
|
|
151
|
+
| **Chat** | `/clear` | Clear this chat's history |
|
|
152
|
+
| | `/compact` | Force compaction of chat history |
|
|
153
|
+
| | `/brief` | Toggle brief response mode |
|
|
154
|
+
| | `/export` | Export session as markdown file |
|
|
155
|
+
| **Model** | `/model` | Switch model for this chat |
|
|
156
|
+
| | `/think` | Set thinking level (off/low/medium/high) |
|
|
157
|
+
| | `/effort` | Set effort level (low/medium/high/max) |
|
|
158
|
+
| **Session** | `/session` | Show or switch session |
|
|
159
|
+
| | `/status` | Show model, message count, token usage |
|
|
160
|
+
| | `/usage` | Token usage for this session |
|
|
161
|
+
| **Tools** | `/skills` | List active skills |
|
|
162
|
+
| | `/mcp` | Manage MCP tool servers |
|
|
163
|
+
| | `/voice` | Voice transcription info |
|
|
164
|
+
| **Utility** | `/help` | List commands and current config |
|
|
165
|
+
|
|
166
|
+
<br>
|
|
167
|
+
|
|
168
|
+
## CLI Commands
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
camel <command> [options]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
| Category | Command | Description |
|
|
175
|
+
|----------|---------|-------------|
|
|
176
|
+
| **Getting Started** | `bootstrap` | First-time setup wizard |
|
|
177
|
+
| | `setup` | Interactive setup (re-run anytime) |
|
|
178
|
+
| | `chat` | Interactive terminal UI |
|
|
179
|
+
| **Server** | `serve` | Start the gateway server |
|
|
180
|
+
| | `daemon` | Manage launchd daemon (install/uninstall/status) |
|
|
181
|
+
| | `logs` | Tail server request log |
|
|
182
|
+
| | `status` | System health overview |
|
|
183
|
+
| **Agents & Sessions** | `agents` | List configured agents |
|
|
184
|
+
| | `soul` | View/edit agent SOUL.md in $EDITOR |
|
|
185
|
+
| | `sessions` | List saved sessions |
|
|
186
|
+
| | `pairing` | List and approve/deny pending requests |
|
|
187
|
+
| **Configuration** | `config` | View/edit config (get/set/list) |
|
|
188
|
+
| | `cron` | Manage cron jobs (list/add/rm/run) |
|
|
189
|
+
| **Maintenance** | `doctor` | Run health checks |
|
|
190
|
+
| | `reset` | Delete all config, sessions, agents |
|
|
191
|
+
| | `install` | Install to ~/.camelagi/versions/ and add to PATH |
|
|
192
|
+
| | `uninstall` | Remove CamelAGI completely |
|
|
193
|
+
| | `update` | Update to the latest version |
|
|
194
|
+
|
|
195
|
+
One-shot mode: `camel "your question"` — spins up an ephemeral gateway and answers inline.
|
|
196
|
+
|
|
197
|
+
<br>
|
|
198
|
+
|
|
40
199
|
## Built on Claude Agent SDK
|
|
41
200
|
|
|
42
201
|
<p align="center">
|
|
@@ -99,123 +258,101 @@ CamelAGI uses **Claude Agent SDK**. OpenClaw uses **pi-agent-core**. Here's why
|
|
|
99
258
|
|
|
100
259
|
<br>
|
|
101
260
|
|
|
102
|
-
##
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
261
|
+
## Configuration
|
|
262
|
+
|
|
263
|
+
CamelAGI uses a single YAML config file at `~/.camelagi/config.yaml`, validated with Zod.
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
# Provider & Model
|
|
267
|
+
provider: anthropic # anthropic | openai | openrouter | ollama
|
|
268
|
+
model: claude-sonnet-4-20250514
|
|
269
|
+
anthropicApiKey: sk-ant-...
|
|
270
|
+
|
|
271
|
+
# Telegram
|
|
272
|
+
telegramBotToken: "123456:ABC..."
|
|
273
|
+
allowedTelegramUsers: [123456789]
|
|
274
|
+
|
|
275
|
+
# Agents
|
|
276
|
+
agents:
|
|
277
|
+
coder:
|
|
278
|
+
model: claude-sonnet-4-20250514
|
|
279
|
+
thinkingLevel: medium
|
|
280
|
+
briefMode: true
|
|
281
|
+
telegramBotToken: "654321:XYZ..."
|
|
282
|
+
mcp:
|
|
283
|
+
servers:
|
|
284
|
+
github:
|
|
285
|
+
type: stdio
|
|
286
|
+
command: npx
|
|
287
|
+
args: ["-y", "@modelcontextprotocol/server-github"]
|
|
288
|
+
|
|
289
|
+
# MCP Servers (global)
|
|
290
|
+
mcp:
|
|
291
|
+
servers:
|
|
292
|
+
supabase:
|
|
293
|
+
type: http
|
|
294
|
+
url: https://mcp.supabase.com/...
|
|
107
295
|
```
|
|
108
296
|
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
npm install -g camelagi
|
|
112
|
-
```
|
|
297
|
+
Environment variables override file values: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `CAMELAGI_MODEL`, `CAMELAGI_PROVIDER`, `CAMELAGI_TOKEN`, `TELEGRAM_BOT_TOKEN`.
|
|
113
298
|
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
camel bootstrap # Full setup: admin bot + pairing + API config
|
|
117
|
-
camel serve # Start the gateway (after bootstrap)
|
|
118
|
-
camel chat # Terminal UI
|
|
119
|
-
```
|
|
299
|
+
See [featuresDocs/configuration.md](featuresDocs/configuration.md) for the full configuration reference.
|
|
120
300
|
|
|
121
301
|
<br>
|
|
122
302
|
|
|
123
|
-
##
|
|
124
|
-
|
|
125
|
-
Create agents, manage config, approve users, monitor sessions, restart bots — all from Telegram. The Admin Bot is a **non-AI Telegram bot** — no LLM calls, no tokens burned, just instant commands. Think [@BotFather](https://t.me/BotFather), but for your entire AI infrastructure.
|
|
126
|
-
|
|
127
|
-
### Getting Started
|
|
128
|
-
|
|
129
|
-
1. Create a bot with [@BotFather](https://t.me/BotFather) on Telegram
|
|
130
|
-
2. Run `camel bootstrap` and paste the bot token
|
|
131
|
-
3. Send a message to your bot on Telegram — the CLI detects you
|
|
132
|
-
4. Approve yourself in the CLI, then enter the OTP in Telegram
|
|
133
|
-
5. Pick your AI provider and model (or skip and do it later via `/setup` in Telegram)
|
|
134
|
-
6. Done — use `/newagent` in Telegram to create your first AI agent
|
|
135
|
-
|
|
136
|
-
### Commands
|
|
137
|
-
|
|
138
|
-
| Category | Command | Description |
|
|
139
|
-
|----------|---------|-------------|
|
|
140
|
-
| **Agents** | `/newagent` | Create agent wizard |
|
|
141
|
-
| | `/agents` | List all agents |
|
|
142
|
-
| | `/deleteagent` | Delete an agent |
|
|
143
|
-
| | `/soul` | View/edit agent personality |
|
|
144
|
-
| **Config** | `/config` | View configuration |
|
|
145
|
-
| | `/config <key> <value>` | Update config |
|
|
146
|
-
| | `/setup` | API provider wizard |
|
|
147
|
-
| **Monitor** | `/status` | System health & stats |
|
|
148
|
-
| | `/sessions` | List & manage sessions |
|
|
149
|
-
| | `/restart` | Restart agent bots |
|
|
150
|
-
| **Security** | `/pairing` | Manage access requests |
|
|
303
|
+
## Architecture
|
|
151
304
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
305
|
+
```
|
|
306
|
+
~/.camelagi/
|
|
307
|
+
├── config.yaml ← Single config file
|
|
308
|
+
├── workspace/ ← Default agent workspace
|
|
309
|
+
│ ├── SOUL.md ← Default personality
|
|
310
|
+
│ ├── MEMORY.md ← Default curated memory
|
|
311
|
+
│ └── memory/ ← Daily notes
|
|
312
|
+
├── agents/ ← Per-agent isolated directories
|
|
313
|
+
│ └── <agent-id>/
|
|
314
|
+
│ ├── SOUL.md
|
|
315
|
+
│ ├── TOOLS.md
|
|
316
|
+
│ ├── MEMORY.md
|
|
317
|
+
│ └── memory/
|
|
318
|
+
├── sessions/ ← JSONL conversation history
|
|
319
|
+
├── skills/ ← Markdown skill files
|
|
320
|
+
└── usage/ ← Token usage data
|
|
321
|
+
```
|
|
155
322
|
|
|
156
|
-
|
|
323
|
+
**Request flow:**
|
|
157
324
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
| 💭 | **Extended Thinking** | Claude reasons step by step before answering. Configure depth: off, low, medium, high |
|
|
168
|
-
| 🔌 | **Multi-Provider** | Anthropic, OpenAI, OpenRouter, Ollama — any OpenAI-compatible endpoint. Zero vendor lock-in |
|
|
169
|
-
| 🔐 | **Secure Pairing** | OTP-based user verification. No hardcoded IDs — pairing code + 5-digit OTP from Telegram |
|
|
170
|
-
| 🪝 | **Skills & Hooks** | Teach agents skills via Markdown. Run shell/JS hooks before and after tool calls |
|
|
171
|
-
| 🔄 | **Auto Compaction** | Summarizes old turns at 80% capacity. Flushes facts to memory first — nothing is lost |
|
|
325
|
+
```
|
|
326
|
+
Inbound message (TUI / REST / WS / Telegram / Discord)
|
|
327
|
+
→ Queue check (per-session, prevents concurrent runs)
|
|
328
|
+
→ Lane acquisition (concurrency limits: main/cron/subagent)
|
|
329
|
+
→ History loading + compaction (summarize at 80% of maxTokens)
|
|
330
|
+
→ Agent execution with retry (classify error → backoff or compact → retry)
|
|
331
|
+
→ Message persistence (JSONL sessions)
|
|
332
|
+
→ Cleanup (release lane, drain queued messages)
|
|
333
|
+
```
|
|
172
334
|
|
|
173
335
|
<br>
|
|
174
336
|
|
|
175
|
-
##
|
|
176
|
-
|
|
177
|
-
Don't want to use Telegram? `camel chat` gives you a full terminal interface with the same agent capabilities.
|
|
178
|
-
|
|
179
|
-
- Streaming responses with markdown rendering
|
|
180
|
-
- Slash commands (`/model`, `/sessions`, `/tools`, `/compact`, `/status`, `/context`)
|
|
181
|
-
- Model selector overlay (`Ctrl+L`), session switcher (`Ctrl+P`)
|
|
182
|
-
- Tool output toggle (`Ctrl+O`), abort with `Escape`
|
|
183
|
-
- Shell execution with `!command`
|
|
184
|
-
- Agent creation wizard, SOUL.md editing
|
|
185
|
-
- Thinking indicators, subagent progress, approval overlay
|
|
186
|
-
- One-shot mode: `camel "your question"` for quick answers
|
|
187
|
-
|
|
188
|
-
<br>
|
|
337
|
+
## Documentation
|
|
189
338
|
|
|
190
|
-
|
|
339
|
+
| Document | Description |
|
|
340
|
+
|----------|-------------|
|
|
341
|
+
| [DOCS.md](DOCS.md) | Full reference documentation |
|
|
342
|
+
| [GUIDE.md](GUIDE.md) | User guide with examples |
|
|
343
|
+
| [featuresDocs/](featuresDocs/) | Deep-dive feature docs |
|
|
191
344
|
|
|
192
|
-
|
|
193
|
-
|---|---|---|
|
|
194
|
-
| **Codebase size** | ~10K LOC | ~700K+ LOC |
|
|
195
|
-
| **AI Agent runtime** | [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) — fully documented by Anthropic, easy to extend | pi-agent & custom abstractions |
|
|
345
|
+
Feature docs cover: [agent system](featuresDocs/agent-system.md), [memory](featuresDocs/memory-system.md), [Telegram bots](featuresDocs/telegram-bots.md), [gateway server](featuresDocs/gateway-server.md), [runtime](featuresDocs/runtime.md), [tools](featuresDocs/tools.md), [extensions](featuresDocs/extensions.md), [configuration](featuresDocs/configuration.md), [CLI](featuresDocs/cli-commands.md), [TUI](featuresDocs/tui.md), [pairing](featuresDocs/pairing-otp.md).
|
|
196
346
|
|
|
197
347
|
<br>
|
|
198
348
|
|
|
199
349
|
## Roadmap
|
|
200
350
|
|
|
201
|
-
We're building CamelAGI to be the most capable open-source AI platform — for individuals and businesses alike.
|
|
202
|
-
|
|
203
351
|
| | Feature | Description |
|
|
204
352
|
|---|---|---|
|
|
205
|
-
| 📡 | **More Channels** | WhatsApp,
|
|
206
|
-
| 🧩 | **ClawHub Skills** | Browse and install community skills from [clawhub.io](https://clawhub.io) — one command to add new capabilities
|
|
207
|
-
|
|
|
208
|
-
| 🏢 | **Business Ready** | Deploy CamelAGI for your business — finance, accounting, operations, customer support. AI agents that understand your workflows |
|
|
209
|
-
|
|
210
|
-
<br>
|
|
211
|
-
|
|
212
|
-
## Documentation
|
|
213
|
-
|
|
214
|
-
| Document | Description |
|
|
215
|
-
|----------|-------------|
|
|
216
|
-
| [DOCS.md](DOCS.md) | Full reference documentation |
|
|
217
|
-
| [GUIDE.md](GUIDE.md) | User guide with examples |
|
|
218
|
-
| [featuresDocs/](featuresDocs/) | Deep-dive feature docs |
|
|
353
|
+
| 📡 | **More Channels** | WhatsApp, Slack — connect your AI agents to every platform your team already uses |
|
|
354
|
+
| 🧩 | **ClawHub Skills** | Browse and install community skills from [clawhub.io](https://clawhub.io) — one command to add new capabilities |
|
|
355
|
+
| 🏢 | **Business Ready** | Deploy for your business — finance, operations, customer support. AI agents that understand your workflows |
|
|
219
356
|
|
|
220
357
|
<br>
|
|
221
358
|
|
package/dist/agent/agent-sdk.js
CHANGED
|
@@ -32,6 +32,16 @@ const BUILTIN_TOOLS = [
|
|
|
32
32
|
"WebSearch", "WebFetch",
|
|
33
33
|
"Agent",
|
|
34
34
|
];
|
|
35
|
+
/** Extract text from an SDK "assistant" message's content blocks */
|
|
36
|
+
function extractAssistantText(msg) {
|
|
37
|
+
if (msg.type !== "assistant" || !msg.message?.content)
|
|
38
|
+
return "";
|
|
39
|
+
const parts = Array.isArray(msg.message.content) ? msg.message.content : [];
|
|
40
|
+
return parts
|
|
41
|
+
.filter((b) => b.type === "text" && b.text)
|
|
42
|
+
.map((b) => b.text)
|
|
43
|
+
.join("");
|
|
44
|
+
}
|
|
35
45
|
export async function runAgentSdk(apiKey, model, systemPrompt, history, userMessage, opts) {
|
|
36
46
|
// Build effective prompt: if resuming, just use user message.
|
|
37
47
|
// Otherwise, prepend history as structured context in the prompt itself
|
|
@@ -130,80 +140,141 @@ export async function runAgentSdk(apiKey, model, systemPrompt, history, userMess
|
|
|
130
140
|
}
|
|
131
141
|
let result = "";
|
|
132
142
|
let sdkSessionId;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
},
|
|
143
|
+
// Build options object step-by-step to isolate any spread errors
|
|
144
|
+
const mcpServers = { camelagi: mcpServer, ...(opts?.mcpServers ?? {}) };
|
|
145
|
+
const allowedTools = [
|
|
146
|
+
...BUILTIN_TOOLS,
|
|
147
|
+
"mcp__camelagi__*",
|
|
148
|
+
...Object.keys(opts?.mcpServers ?? {}).map(name => `mcp__${name}__*`),
|
|
149
|
+
];
|
|
150
|
+
const envVars = { ...(process.env ?? {}), ...buildSdkEnv(apiKey, opts?.provider, opts?.baseUrl) };
|
|
151
|
+
const queryOptions = {
|
|
152
|
+
model,
|
|
153
|
+
systemPrompt,
|
|
154
|
+
allowedTools,
|
|
155
|
+
mcpServers,
|
|
156
|
+
maxTurns: opts?.maxTurns ?? DEFAULT_MAX_TURNS,
|
|
157
|
+
permissionMode: "bypassPermissions",
|
|
158
|
+
allowDangerouslySkipPermissions: true,
|
|
159
|
+
cwd: process.cwd(),
|
|
160
|
+
env: envVars,
|
|
161
|
+
thinking,
|
|
162
|
+
includePartialMessages: !!emit,
|
|
163
|
+
settingSources: ["project"],
|
|
164
|
+
hooks: {
|
|
165
|
+
PreToolUse: [{ matcher: ".*", hooks: [preToolHook] }],
|
|
166
|
+
PostToolUse: [{ matcher: ".*", hooks: [postToolHook] }],
|
|
157
167
|
},
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
else if (sysMsg.subtype === "task_notification") {
|
|
185
|
-
emit({ type: "subagent_done", agentId: sysMsg.agent_id ?? "subagent", toolUseId: sysMsg.tool_use_id });
|
|
168
|
+
};
|
|
169
|
+
if (disallowedTools)
|
|
170
|
+
queryOptions.disallowedTools = disallowedTools;
|
|
171
|
+
if (opts?.effort)
|
|
172
|
+
queryOptions.effort = opts.effort;
|
|
173
|
+
if (opts?.maxBudgetUsd)
|
|
174
|
+
queryOptions.maxBudgetUsd = opts.maxBudgetUsd;
|
|
175
|
+
if (opts?.resumeSessionId)
|
|
176
|
+
queryOptions.resume = opts.resumeSessionId;
|
|
177
|
+
if (abortController)
|
|
178
|
+
queryOptions.abortController = abortController;
|
|
179
|
+
const q = query({ prompt: effectivePrompt, options: queryOptions });
|
|
180
|
+
// The for-await loop may throw if the SDK subprocess exits unexpectedly
|
|
181
|
+
// (e.g. non-Claude models via OpenRouter). If we already captured a result
|
|
182
|
+
// from "assistant" messages, we still want to return it.
|
|
183
|
+
try {
|
|
184
|
+
for await (const message of q) {
|
|
185
|
+
const msg = message;
|
|
186
|
+
// "assistant" messages: non-Claude models (via OpenRouter) emit these
|
|
187
|
+
// with the response text instead of a final "result" message.
|
|
188
|
+
const assistantText = extractAssistantText(msg);
|
|
189
|
+
if (assistantText) {
|
|
190
|
+
result = assistantText;
|
|
191
|
+
if (msg.session_id)
|
|
192
|
+
sdkSessionId = msg.session_id;
|
|
186
193
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
194
|
+
if (message.type === "result") {
|
|
195
|
+
const resultMsg = message;
|
|
196
|
+
// Only overwrite if non-empty (non-Claude models return text via
|
|
197
|
+
// "assistant" messages; the trailing "result" may be empty).
|
|
198
|
+
if (resultMsg.result) {
|
|
199
|
+
result = resultMsg.result;
|
|
200
|
+
}
|
|
201
|
+
sdkSessionId = resultMsg.session_id ?? sdkSessionId;
|
|
202
|
+
if (resultMsg.usage && emit) {
|
|
203
|
+
emit({ type: "usage", inputTokens: resultMsg.usage.input_tokens ?? 0, outputTokens: resultMsg.usage.output_tokens ?? 0, cacheReadTokens: resultMsg.usage.cache_read_input_tokens, cacheWriteTokens: resultMsg.usage.cache_creation_input_tokens });
|
|
204
|
+
}
|
|
205
|
+
if (resultMsg.usage && opts?.sessionId) {
|
|
206
|
+
recordUsage(opts.sessionId, { inputTokens: resultMsg.usage.input_tokens ?? 0, outputTokens: resultMsg.usage.output_tokens ?? 0, cacheReadTokens: resultMsg.usage.cache_read_input_tokens ?? 0, cacheWriteTokens: resultMsg.usage.cache_creation_input_tokens ?? 0 });
|
|
207
|
+
}
|
|
208
|
+
emit?.({ type: "chunk", text: result });
|
|
193
209
|
}
|
|
194
|
-
else if (
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
emit({ type: "
|
|
210
|
+
else if (message.type === "system" && emit) {
|
|
211
|
+
const sysMsg = message;
|
|
212
|
+
if (sysMsg.subtype === "init" && sysMsg.session_id) {
|
|
213
|
+
sdkSessionId = sysMsg.session_id;
|
|
214
|
+
emit({ type: "init", sessionId: sysMsg.session_id });
|
|
215
|
+
}
|
|
216
|
+
else if (sysMsg.subtype === "task_started") {
|
|
217
|
+
emit({ type: "subagent_start", agentId: sysMsg.agent_id ?? "subagent", taskId: sysMsg.task_id });
|
|
218
|
+
}
|
|
219
|
+
else if (sysMsg.subtype === "task_progress") {
|
|
220
|
+
emit({ type: "subagent_progress", agentId: sysMsg.agent_id ?? "subagent", toolCount: sysMsg.tool_count, duration: sysMsg.duration_ms ? Math.round(sysMsg.duration_ms / 1000) : undefined });
|
|
221
|
+
}
|
|
222
|
+
else if (sysMsg.subtype === "task_notification") {
|
|
223
|
+
emit({ type: "subagent_done", agentId: sysMsg.agent_id ?? "subagent", toolUseId: sysMsg.tool_use_id });
|
|
224
|
+
}
|
|
199
225
|
}
|
|
200
|
-
else if (
|
|
201
|
-
|
|
226
|
+
else if (message.type === "stream_event" && emit) {
|
|
227
|
+
const streamMsg = message;
|
|
228
|
+
const event = streamMsg.event;
|
|
229
|
+
if (event.type === "content_block_start" && event.content_block?.type === "thinking") {
|
|
230
|
+
emit({ type: "thinking", state: "start" });
|
|
231
|
+
}
|
|
232
|
+
else if (event.type === "content_block_delta") {
|
|
233
|
+
if (event.delta?.type === "text_delta" && event.delta.text)
|
|
234
|
+
emit({ type: "stream_text", text: event.delta.text });
|
|
235
|
+
else if (event.delta?.type === "thinking_delta" && event.delta.thinking)
|
|
236
|
+
emit({ type: "thinking_delta", text: event.delta.thinking });
|
|
237
|
+
}
|
|
238
|
+
else if (event.type === "content_block_stop") {
|
|
239
|
+
emit({ type: "thinking", state: "end" });
|
|
240
|
+
}
|
|
202
241
|
}
|
|
203
242
|
}
|
|
204
243
|
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
// If the subprocess exited but we already have a response, return it.
|
|
246
|
+
// Otherwise, re-throw so the retry/error handling picks it up.
|
|
247
|
+
if (!result)
|
|
248
|
+
throw err;
|
|
249
|
+
}
|
|
205
250
|
const userMsg = { role: "user", content: userMessage };
|
|
206
251
|
const aiMsg = { role: "assistant", content: result };
|
|
207
252
|
return { response: result, newMessages: [userMsg, aiMsg], usage: null, sessionId: sdkSessionId };
|
|
208
253
|
}
|
|
254
|
+
/** Build environment variables for the SDK subprocess based on provider */
|
|
255
|
+
function buildSdkEnv(apiKey, provider, baseUrl) {
|
|
256
|
+
// OpenRouter: use ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN
|
|
257
|
+
if (baseUrl?.includes("openrouter")) {
|
|
258
|
+
// SDK expects /api not /api/v1
|
|
259
|
+
const sdkBaseUrl = baseUrl.replace(/\/v1\/?$/, "");
|
|
260
|
+
return {
|
|
261
|
+
ANTHROPIC_BASE_URL: sdkBaseUrl,
|
|
262
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
263
|
+
ANTHROPIC_API_KEY: "",
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
// Direct Anthropic
|
|
267
|
+
if (provider === "anthropic" || !provider) {
|
|
268
|
+
return { ANTHROPIC_API_KEY: apiKey };
|
|
269
|
+
}
|
|
270
|
+
// Custom base URL (non-OpenRouter)
|
|
271
|
+
if (baseUrl) {
|
|
272
|
+
return {
|
|
273
|
+
ANTHROPIC_API_KEY: apiKey,
|
|
274
|
+
ANTHROPIC_BASE_URL: baseUrl,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
// Default
|
|
278
|
+
return { ANTHROPIC_API_KEY: apiKey };
|
|
279
|
+
}
|
|
209
280
|
//# sourceMappingURL=agent-sdk.js.map
|