Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
3e6ed4f
✨ feat(agents): add cherry-claw agent type to type system
vaayne Mar 9, 2026
5e6c0b5
🌐 feat(i18n): add CherryClaw agent i18n keys
vaayne Mar 9, 2026
a175b9f
♻️ refactor(agents): introduce AgentServiceRegistry for multi-type di…
vaayne Mar 9, 2026
d85d0a8
✨ feat(agents): add cherry-claw to agent-type dispatch points
vaayne Mar 9, 2026
721a1d9
✨ feat(agents): implement CherryClawService with SoulReader and Heart…
vaayne Mar 9, 2026
3836f7b
✨ feat(agents): implement SchedulerService for CherryClaw autonomous …
vaayne Mar 9, 2026
65db465
🔧 feat(agents): wire SchedulerService into app lifecycle and agent CRUD
vaayne Mar 9, 2026
33e2399
✨ feat(ui): add agent type selector to creation modal
vaayne Mar 9, 2026
f3f2dd3
✨ feat(ui): add CherryClaw settings tabs (soul, scheduler, heartbeat,…
vaayne Mar 9, 2026
a63b60a
✨ feat(ui): differentiate CherryClaw agents in agent list
vaayne Mar 9, 2026
9558cd4
✅ test(agents): add unit tests for CherryClaw components
vaayne Mar 9, 2026
3267e0f
🐛 fix(agents): resolve type errors and lint issues
vaayne Mar 9, 2026
51f1005
✨ feat(agents): auto-create default CherryClaw agent and pin to top
vaayne Mar 10, 2026
985f153
♻️ refactor(ui): simplify CherryClaw agent settings tabs
vaayne Mar 10, 2026
2a11a17
✨ feat(scheduler): task-based scheduler with management UI
vaayne Mar 10, 2026
d644804
✨ feat(claw): add internal cron MCP tool for autonomous task management
vaayne Mar 10, 2026
91d8628
🐛 fix(claw): fix MCP server 500 on GET and disable SDK builtin cron t…
vaayne Mar 10, 2026
c6e6926
♻️ refactor(claw): rename internal MCP server from 'cherry-claw' to '…
vaayne Mar 10, 2026
3ddb492
✨ feat(channels): add channel abstraction layer for CherryClaw agents
vaayne Mar 10, 2026
a0b7681
✨ feat(channels): add Telegram adapter using grammy long polling
vaayne Mar 10, 2026
bc55754
✨ feat(channels): wire ChannelManager into app lifecycle and agent ha…
vaayne Mar 10, 2026
541c0e8
✨ feat(channels): add typed Telegram channel config and enabled guard
vaayne Mar 10, 2026
3941fc6
✨ feat(channels): add channel settings UI for CherryClaw agents
vaayne Mar 10, 2026
c8ec688
✅ test(channels): add tests for ChannelMessageHandler, ChannelManager…
vaayne Mar 10, 2026
5592725
♻️ refactor(channels): redesign settings UI as catalog with inline co…
vaayne Mar 10, 2026
103a08c
✨ feat(channels): stream responses via sendMessageDraft with typing i…
vaayne Mar 10, 2026
555c97e
🐛 fix(channels): persist headless messages to DB for channels and sch…
vaayne Mar 10, 2026
3ff9899
🐛 fix(channels): use replace instead of append for cumulative text-delta
vaayne Mar 10, 2026
090a5f7
🔧 feat(cherry-claw): disable builtin tools not suited for autonomous …
vaayne Mar 10, 2026
0db7b8e
🔒 feat(cherry-claw): add basic sandbox mode with PreToolUse path enfo…
vaayne Mar 10, 2026
5dd2609
✨ feat(cherry-claw): add notify tool to claw MCP and scheduler notifi…
vaayne Mar 10, 2026
54154e1
✨ feat(cherry-claw): add manual task run button and update handoff
vaayne Mar 10, 2026
96dc076
✨ feat(cherry-claw): add session resume and claw MCP tool auto-allow
vaayne Mar 10, 2026
3a4999f
✨ feat(cherry-claw): add skills MCP tool and fix per-session server l…
vaayne Mar 10, 2026
e75fb6f
✨ feat(cherry-claw): add custom system prompt and memory MCP tool
vaayne Mar 10, 2026
8aeddae
🐛 fix(cherry-claw): case-insensitive file resolution for memory files
vaayne Mar 10, 2026
61e792b
📝 fix(cherry-claw): add file layout to system prompt for memory paths
vaayne Mar 10, 2026
8e8808f
♻️ refactor(cherry-claw): use in-memory MCP server instead of HTTP
vaayne Mar 10, 2026
ce3d4c6
♻️ refactor(cherry-claw): simplify system prompt with template-based …
vaayne Mar 10, 2026
c3dfd96
🔥 refactor(cherry-claw): remove sandbox feature
vaayne Mar 10, 2026
23de00e
📝 docs(cherry-claw): add CherryClaw reference docs and tool guidance …
vaayne Mar 10, 2026
ee21ccd
♻️ refactor(cherry-claw): redesign heartbeat as auto-created schedule…
vaayne Mar 10, 2026
b393444
🎨 feat(cherry-claw): add proper CherryClaw avatar and doc icon
vaayne Mar 10, 2026
149f17c
feat: add support for Feishu and Telegram channels (#13385)
vaayne Mar 12, 2026
52379e4
feat(cherry-claw): add QQ channel adapter (#13381)
vaayne Mar 12, 2026
1a54999
Squash merge main into feat/cherry-claw-agent
vaayne Mar 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/ISSUE_TEMPLATE/0_bug_report.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: 🐛 Bug Report
description: Create a report to help us improve
title: '[Bug]: '
labels: ['BUG']
title: "[Bug]: "
labels: []
type: Bug
body:
- type: markdown
attributes:
Expand Down
5 changes: 3 additions & 2 deletions .github/ISSUE_TEMPLATE/1_feature_request.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: 💡 Feature Request
description: Suggest an idea for this project
title: '[Feature]: '
labels: ['feature']
title: "[Feature]: "
labels: []
type: Feature
body:
- type: markdown
attributes:
Expand Down
139 changes: 139 additions & 0 deletions docs/zh/references/cherryclaw/channels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# CherryClaw 频道系统

频道系统为 CherryClaw 提供 IM 集成能力,允许用户通过 Telegram 等即时通讯平台与代理交互。系统采用抽象适配器模式,支持未来扩展到 Discord、Slack 等平台。

## 架构

```
ChannelManager (单例, 生命周期管理)
├── adapters Map<key, ChannelAdapter> — 活跃的适配器实例
├── notifyChannels Set<key> — 标记为通知接收者的频道
├── start() → 加载所有 CherryClaw agent,为启用的频道创建适配器
├── stop() → 断开所有适配器
└── syncAgent(agentId) → 断开旧适配器,根据当前配置重建

ChannelAdapter (抽象 EventEmitter)
├── connect() / disconnect()
├── sendMessage(chatId, text, opts?)
├── sendMessageDraft(chatId, draftId, text) — 流式草稿更新
├── sendTypingIndicator(chatId)
└── Events: 'message' → ChannelMessageEvent
'command' → ChannelCommandEvent

ChannelMessageHandler (单例, 无状态消息路由)
├── handleIncoming(adapter, message) — 路由到代理 session
├── handleCommand(adapter, command) — 处理 /new /compact /help
└── sessionTracker Map<agentId, sessionId> — 每个 agent 的活跃 session
```

## 适配器注册

适配器通过 `registerAdapterFactory(type, factory)` 自注册。导入适配器模块即触发注册:

```typescript
// src/main/services/agents/services/channels/adapters/TelegramAdapter.ts
registerAdapterFactory('telegram', (channel, agentId) => {
return new TelegramAdapter({ channelId: channel.id, agentId, channelConfig: channel.config })
})
```

`ChannelManager` 启动时导入所有适配器模块(通过 `channels/index.ts`),适配器的 `registerAdapterFactory` 调用作为模块副作用执行。

## 消息处理流程

### 用户消息

```
用户在 Telegram 发送消息
→ TelegramAdapter 触发 'message' 事件
→ ChannelManager 转发给 ChannelMessageHandler.handleIncoming()
1. resolveSession(agentId)
→ 检查 sessionTracker → 查询已有 session → 创建新 session
2. 发送 typing indicator(每 4s 刷新一次)
3. 生成随机 draftId
4. collectStreamResponse(session, text, abort, onDraft):
- 创建 session message(persist: true)
- 读取 stream:
text-delta → 更新 currentBlockText(块内累积)
text-end → 提交到 completedText,重置当前块
- 每 500ms 通过 sendMessageDraft 发送草稿
5. sendMessage(chatId, finalText) — 超过 4096 字符自动分块
```

### 命令处理

| 命令 | 行为 |
|---|---|
| `/new` | 创建新 session,更新 sessionTracker |
| `/compact` | 向当前 session 发送 `/compact`,收集响应 |
| `/help` | 返回代理名称、描述和可用命令列表 |

## 流式响应

CherryClaw 的流式响应遵循以下规则:

- `text-delta` 事件在同一个文本块内是**累积的**——每个事件包含到目前为止的完整文本,而非增量
- `ChannelMessageHandler` 在块内使用 `text = value.text`(替换),在 `text-end` 时提交
- 草稿通过 `sendMessageDraft` 以 500ms 节流频率发送
- typing indicator 每 4s 刷新一次

## Telegram 适配器

### 配置

```typescript
{
type: 'telegram',
id: 'unique-channel-id',
enabled: true,
is_notify_receiver: true, // 是否接收通知
config: {
bot_token: 'YOUR_BOT_TOKEN',
allowed_chat_ids: ['123456789'] // 授权的 chat ID 列表
}
}
```

### 特性

- 使用 **grammY** 库,仅支持长轮询(桌面应用在 NAT 后面,不支持 webhook)
- **授权守卫**:第一个中间件检查 chat ID 是否在白名单中,未授权消息直接丢弃
- **消息分块**:超过 4096 字符的消息自动按段落/行/硬分割发送
- **草稿流式**:通过 Telegram 的 `sendMessageDraft` API 实现实时响应流式展示
- **通知目标**:`notifyChatIds` 等于 `allowed_chat_ids`,所有授权的 chat 都接收通知

### 已知限制

| 限制 | 说明 |
|---|---|
| 速率限制 | `sendMessage` 全局 30/s,每 chat 1/s。草稿节流 500ms,typing 4s |
| 纯文本输出 | 代理响应以纯文本发送(无 `parse_mode`),避免 MarkdownV2 转义问题 |
| 仅长轮询 | 桌面应用无法接收 webhook |

## 通知频道

`ChannelManager` 通过 `notifyChannels` Set 跟踪哪些适配器的频道配置了 `is_notify_receiver: true`。`getNotifyAdapters(agentId)` 返回指定 agent 的所有通知适配器,供 `notify` MCP 工具和调度器任务通知使用。

## 生命周期

- **启动**: `channelManager.start()` 在应用就绪时与调度器一起调用
- **停止**: `channelManager.stop()` 在应用退出时调用
- **同步**: `channelManager.syncAgent(agentId)` 在 agent 更新/删除时调用,断开旧适配器并根据新配置重建

## 扩展新频道

添加新的频道类型只需:

1. 实现 `ChannelAdapter` 抽象类
2. 在模块中调用 `registerAdapterFactory(type, factory)`
3. 在 `channels/index.ts` 中导入该模块

## 关键文件

| 文件 | 说明 |
|---|---|
| `src/main/services/agents/services/channels/ChannelAdapter.ts` | 抽象接口 + 事件类型 |
| `src/main/services/agents/services/channels/ChannelManager.ts` | 生命周期管理 + 适配器工厂注册 |
| `src/main/services/agents/services/channels/ChannelMessageHandler.ts` | 消息路由 + 流式响应收集 |
| `src/main/services/agents/services/channels/adapters/TelegramAdapter.ts` | Telegram 适配器实现 |
| `src/main/services/agents/services/channels/index.ts` | 公开导出 + 适配器模块导入 |
Binary file added docs/zh/references/cherryclaw/cherryclaw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
183 changes: 183 additions & 0 deletions docs/zh/references/cherryclaw/mcp-claw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Claw MCP 服务器

Claw MCP 服务器是一个内置的 MCP(Model Context Protocol)服务器,自动注入到每个 CherryClaw 会话中。它为代理提供了四个自主管理工具:`cron`(任务调度)、`notify`(通知)、`skills`(技能管理)和 `memory`(记忆管理)。

## 架构

```
CherryClawService.invoke()
→ 创建 ClawServer 实例(每次调用一个新实例)
→ 注入为内存中的 MCP 服务器:
_internalMcpServers = { claw: { type: 'inmem', instance: clawServer.mcpServer } }
→ ClaudeCodeService 合并到 SDK options.mcpServers
→ SDK 自动发现工具: mcp__claw__cron, mcp__claw__notify, mcp__claw__skills, mcp__claw__memory
```

ClawServer 使用 `@modelcontextprotocol/sdk` 的 `McpServer` 类,以内存模式运行(无需 HTTP 传输)。每个 CherryClaw 会话调用时创建新实例,绑定到当前 agent 的 ID。

## 工具白名单

当 agent 配置了显式的 `allowed_tools` 白名单时,`CherryClawService` 自动追加 `mcp__claw__*` 通配符,确保 SDK 不会过滤掉内部 MCP 工具。当 `allowed_tools` 为 undefined(无限制)时,所有工具已可用,无需注入。

---

## cron 工具

管理代理的调度任务。代理可以自主创建、查看和删除定期执行的任务。

### 动作

#### `add` — 创建任务

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `name` | string | 是 | 任务名称 |
| `message` | string | 是 | 执行时的提示词/指令 |
| `cron` | string | 三选一 | cron 表达式,如 `0 9 * * 1-5` |
| `every` | string | 三选一 | 持续时间,如 `30m`、`2h`、`1h30m` |
| `at` | string | 三选一 | RFC3339 时间戳,用于一次性任务 |
| `session_mode` | string | 否 | `reuse`(默认,保留对话历史)或 `new`(每次新会话) |

`cron`、`every`、`at` 三者只能选一个。`every` 格式支持 `30m`、`2h`、`1h30m` 等人类友好的时间表示,内部转换为分钟数。

调度类型映射:
- `cron` → `schedule_type: 'cron'`
- `every` → `schedule_type: 'interval'`(值为分钟数)
- `at` → `schedule_type: 'once'`(值为 ISO 时间戳)

会话模式映射:
- `reuse` → `context_mode: 'session'`
- `new` → `context_mode: 'isolated'`

#### `list` — 列出任务

无参数。返回当前 agent 的所有调度任务(上限 100 条),JSON 格式。

#### `remove` — 删除任务

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | string | 是 | 任务 ID |

---

## notify 工具

通过已连接的频道(如 Telegram)向用户发送通知消息。代理可以主动通知用户任务结果、状态更新或其他重要信息。

### 参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `message` | string | 是 | 通知内容 |
| `channel_id` | string | 否 | 仅发送到指定频道(省略则发送到所有通知频道) |

### 行为

1. 获取当前 agent 的所有 `is_notify_receiver: true` 的频道适配器
2. 如果指定了 `channel_id`,过滤到该频道
3. 向每个适配器的所有 `notifyChatIds` 发送消息
4. 返回发送数量和可能的错误

如果没有配置通知频道,返回提示信息而非报错。

---

## skills 工具

管理代理工作区中的 Claude 技能。支持从市场搜索、安装、卸载和列出已安装的技能。

### 动作

#### `search` — 搜索技能

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `query` | string | 是 | 搜索关键词 |

查询公开市场 API(`claude-plugins.dev/api/skills`),返回匹配的技能列表,包含 `name`、`description`、`author`、`identifier`(用于安装)和 `installs` 数量。搜索词中的 `-` 和 `_` 会被替换为空格以提高匹配率。

#### `install` — 安装技能

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `identifier` | string | 是 | 市场技能标识符,格式 `owner/repo/skill-name` |

内部构造 `marketplace:skill:{identifier}` 路径,委托给 `PluginService.install()` 完成安装。

#### `remove` — 卸载技能

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `name` | string | 是 | 技能文件夹名称(从 list 结果获取) |

委托给 `PluginService.uninstall()` 完成卸载。

#### `list` — 列出已安装技能

无参数。返回当前 agent 已安装的所有技能,包含 `name`、`folder` 和 `description`。

---

## memory 工具

管理跨会话的持久化记忆。这是 CherryClaw 记忆系统的写入接口(读取通过系统提示词中的内联内容实现)。

### 设计原则

工具描述中编码了记忆决策逻辑:

> 写入 FACT.md 之前,问自己:这个信息 6 个月后还重要吗?如果不是,用 append 代替。

### 动作

#### `update` — 更新 FACT.md

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | string | 是 | FACT.md 的完整 markdown 内容 |

原子写入:先写临时文件,再通过 `rename` 替换。确保不会出现写入中途崩溃导致的文件损坏。

文件路径支持大小写不敏感匹配。如果 `memory/` 目录不存在会自动创建。

**注意**:此操作是全量覆盖,不是增量编辑。代理需要先读取现有内容,修改后再写回完整内容。

#### `append` — 追加日志条目

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `text` | string | 是 | 日志条目文本 |
| `tags` | string[] | 否 | 标签列表 |

追加一行 JSON 到 `memory/JOURNAL.jsonl`,格式:

```json
{"ts":"2026-03-10T12:00:00.000Z","tags":["deploy","production"],"text":"部署 v2.1 到生产环境"}
```

时间戳自动生成。适用于一次性事件、已完成任务、会话摘要等短期信息。

#### `search` — 搜索日志

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `query` | string | 否 | 大小写不敏感的子串匹配 |
| `tag` | string | 否 | 按标签过滤 |
| `limit` | integer | 否 | 最大返回数量(默认 20) |

返回匹配的日志条目,按时间倒序排列。`query` 和 `tag` 可以组合使用。

---

## 错误处理

所有工具调用在内部 try-catch 中执行。当发生错误时,返回 `{ isError: true }` 的 MCP 响应,包含错误消息。错误同时记录到 `loggerService`。

## 关键文件

| 文件 | 说明 |
|---|---|
| `src/main/mcpServers/claw.ts` | ClawServer 完整实现(4 个工具 + 辅助函数) |
| `src/main/mcpServers/__tests__/claw.test.ts` | 37 个单元测试 |
| `src/main/services/agents/services/cherryclaw/index.ts` | MCP 服务器注入逻辑 |
Loading