✨ feat(agents): add CherryClaw autonomous agent type#13359
Draft
✨ feat(agents): add CherryClaw autonomous agent type#13359
Conversation
- Add 'cherry-claw' to AgentTypeSchema enum - Define CherryClawConfiguration, SchedulerType, CherryClawChannel types - Add DEFAULT_CHERRY_CLAW_CONFIG with bypassPermissions default - Add cherry-claw avatar placeholder - Update OpenAPI spec and Swagger docs with new agent type Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Add all CherryClaw-related UI strings for soul, scheduler, heartbeat, channels (placeholder), agent type names, and bypass warning. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…spatch - Create AgentServiceRegistry mapping AgentType → AgentServiceInterface - Refactor SessionMessageService to use registry instead of hardcoded ClaudeCodeService - Register ClaudeCodeService for 'claude-code' in services module init Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Update BaseService.listMcpTools, BaseService.listSlashCommands, and SessionService.listSlashCommands to handle cherry-claw alongside claude-code. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…beatReader - SoulReader: reads soul.md from workspace with mtime-based caching - HeartbeatReader: reads heartbeat.md on demand with path traversal protection - CherryClawService: delegates to claude-code with soul-enhanced system prompt - Register cherry-claw in AgentServiceRegistry Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…operation - Add cron-parser dependency for cron expression parsing - Implement SchedulerService with cron/interval/one-time scheduling - Per-agent tick guard prevents overlapping invocations - Pause after 3 consecutive errors - Restore schedulers on app boot via restoreSchedulers() - Deliver heartbeat content to most recent session on each tick Signed-off-by: Vaayne <liu.vaayne@gmail.com>
- Restore schedulers on app startup (after API server init) - Stop all schedulers on app quit - Stop scheduler when agent is deleted - Restart scheduler when cherry-claw agent is updated/patched Signed-off-by: Vaayne <liu.vaayne@gmail.com>
- Add type dropdown (Claude Code / CherryClaw) in creation modal - Auto-apply CherryClaw defaults when cherry-claw type is selected - Show bypassPermissions warning for CherryClaw agents - Type selection only shown during creation (not editing) Signed-off-by: Vaayne <liu.vaayne@gmail.com>
… channels) - Add SoulSettings, SchedulerSettings, HeartbeatSettings, ChannelsSettings components - Conditionally show CherryClaw-specific tabs in AgentSettingsPopup - Add cherry-claw to SettingsPopupTab type union - Add cherry-claw label to getAgentTypeLabel Signed-off-by: Vaayne <liu.vaayne@gmail.com>
- CherryClaw agents show 🦞 default emoji instead of ⭐️ - Agent name falls back to type label which returns 'CherryClaw' Signed-off-by: Vaayne <liu.vaayne@gmail.com>
- AgentServiceRegistry: 4 tests (register, getService, hasService, overwrite) - SchedulerService: 9 tests (start/stop, tick guard, status, lifecycle) - SoulReader: 4 tests (read, missing file, mtime cache, re-read) - HeartbeatReader: 5 tests (read, missing, custom file, path traversal, defaults) Signed-off-by: Vaayne <liu.vaayne@gmail.com>
- Fix cron-parser import (CronExpressionParser.parse instead of parseExpression) - Fix logger error arg types in soul.ts and heartbeat.ts - Fix oxlint consistent-type-imports in test files - Apply biome formatting Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Auto-create a default CherryClaw agent on first list if none exists, using the first available Anthropic model. Cherry-claw agents are always sorted to the top of the agent list response. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Remove soul, scheduler, heartbeat, prompt, and permission mode tabs for CherryClaw agents. Rename "Tools & MCP" to "MCP" with a new lean McpSettings component that only shows external MCP server config. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Replace per-agent setTimeout scheduler with a poll-loop architecture inspired by nanoclaw. Tasks are now first-class DB entities that users can create, edit, pause, and delete through the agent settings UI. - Add scheduled_tasks + task_run_logs Drizzle tables with FK cascades - Add TaskService with CRUD, getDueTasks, drift-resistant computeNextRun - Rewrite SchedulerService as 60s poll loop querying DB for due tasks - Add REST API routes: /agents/:agentId/tasks (CRUD + logs) - Add AgentApiClient task methods and SWR hooks (useTasks, etc.) - Add Tasks tab in CherryClaw agent settings (replaces Channels) - Add TaskFormModal, TaskListItem, TaskLogsModal UI components - Update i18n with properly nested task UI strings (11 locales) - Rewrite SchedulerService tests for poll-loop API Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Add an internal MCP server auto-injected into CherryClaw agent sessions, exposing a `cron` tool (add/list/remove) that lets the agent autonomously create and manage its own scheduled tasks without human intervention. - New ClawServer in src/main/mcpServers/claw.ts with cron tool - Streamable HTTP route at /v1/claw/:agentId/claw-mcp - CherryClawService injects _internalMcpServers before delegation - ClaudeCodeService merges internal MCPs into SDK options - 12 unit tests for tool actions, duration parsing, and validation Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…ools Two issues preventing the claw MCP cron tool from working: 1. GET requests (SSE streaming) to the claw MCP route caused a 500 because req.body is undefined for GET/DELETE — only parse JSON-RPC body for POST requests, let transport handle GET/DELETE natively. 2. The Claude Code SDK has builtin CronCreate/CronDelete/CronList tools that shadow our MCP cron tool. Add disallowedTools to suppress them so the agent uses our persistent DB-backed cron tool instead. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…claw' Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Add ChannelAdapter (abstract base), ChannelMessageHandler (message routing, session tracking, stream response collection), ChannelManager (lifecycle, adapter factory registry), and barrel exports. No existing files modified. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Implements TelegramAdapter with auth middleware (allowed_chat_ids), command handlers (/new, /compact, /help), message forwarding, typing indicators, and message chunking at 4096 chars. Self-registers via adapter factory pattern. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…ndlers Start channel adapters on app ready (after scheduler), stop on quit. Sync channels on agent update (PUT/PATCH) and delete. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Add TelegramChannelConfigSchema with bot_token and allowed_chat_ids. Update CherryClawChannelSchema with enum type, enabled field, and typed config union. Enable the channel enabled guard in ChannelManager. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Add ChannelsSettings tab with list view, add/edit modal (bot token, allowed chat IDs), enable/disable toggle, and delete with confirmation. Includes ChannelListItem and ChannelFormModal components following existing TasksSettings patterns. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…, and TelegramAdapter 21 tests covering: stream response accumulation, message chunking, slash commands (/new, /compact, /help), session tracking, adapter lifecycle, agent sync, disabled channel filtering, auth middleware, and event emission. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…nfig Replace CRUD list + modal pattern with a catalog of available channel types. Each type is a card with enable switch and inline config fields (blur-to-save). Delete ChannelFormModal and ChannelListItem components. Add notify receiver checkbox. Future channels shown as "coming soon". Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…ndicators Use Telegram's sendMessageDraft API to progressively stream agent responses instead of sending a single message at completion. Typing indicators run every 4s throughout the request to signal the agent is working during tool-use gaps. Also fixes multi-turn accumulation: text-delta values are cumulative within a block, so each turn's text is committed on text-end and concatenated across turns to preserve all response content. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…eduler Channel (Telegram) and scheduler callers of createSessionMessage() never persisted messages because persistence was entirely UI-driven via IPC. - Add `persist` option to SessionMessageService.createSessionMessage() - When true, build minimal AgentPersistedMessage payloads and call persistExchange() on stream complete - Use `agent-session:` prefixed topicId so UI routes correctly - Drain stream in SchedulerService so completion promise resolves - Update tests to match new call signatures Signed-off-by: Vaayne <liu.vaayne@gmail.com>
TextStreamAccumulator used `+=` for text-delta events, but the transform layer emits cumulative deltas (each contains full text so far). This caused persisted assistant messages to contain all intermediate states concatenated together. Use `=` (replace) to match ChannelMessageHandler. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…operation Disable TodoWrite, AskUserQuestion, EnterPlanMode, ExitPlanMode, EnterWorktree, and NotebookEdit via _disallowedTools for CherryClaw agents. These tools require interactive user input or are irrelevant for autonomous agent operation. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…rcement Add sandbox_enabled toggle to CherryClaw agent settings that restricts filesystem access to the workspace path via two layers: 1. PreToolUse hook in ClaudeCodeService inspects every tool call's target paths and denies access outside allowed directories. Works regardless of permissionMode (including bypassPermissions) since hooks always fire before permission checks. 2. SDK OS-level sandbox (sandbox.enabled, allowUnsandboxedCommands: false) as a fallback for Bash command isolation. Tool path extraction covers Read, Edit, Write, MultiEdit, NotebookEdit (file_path/notebook_path), Glob, Grep (path field), and Bash (regex extraction of absolute paths from command string). Note: This is a basic restriction for well-behaved agents, not a security boundary. Bash regex has known bypasses (relative paths, variable expansion, subshells). Needs hardening in follow-up work. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…cations Add a `notify` MCP tool so CherryClaw agents can proactively send messages to users through channels marked with `is_notify_receiver`. Wire the scheduler to automatically notify users after task completion or failure with task name, duration, and error details. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Add POST /:taskId/run API endpoint with SchedulerService.runTaskNow() for manually triggering scheduled tasks. Wire through API client, hook, and "Run" button in task settings UI. Update handoff.md with Phase 11 (notify tool) and Phase 12 (manual task run) progress. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
- Capture SDK session_id from init message in ClaudeCodeService and store on AgentStream.sdkSessionId for headless callers to persist - SessionMessageService reads sdkSessionId on stream complete and passes to persistHeadlessExchange for resume on next scheduler run - CherryClawService auto-appends mcp__claw__cron and mcp__claw__notify to allowed_tools when agent has explicit tool whitelist - Add debug logging for MCP injection and session ID resolution Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…ifecycle Add `skills` tool to claw MCP server with search/install/remove/list actions. Reuses PluginService for install/uninstall/list and queries the marketplace API (claude-plugins.dev) for search via net.fetch. Fix MCP session lifecycle: the SDK Server class only supports one transport at a time (connect() throws if already connected). Changed from per-agent server caching to per-session Server+Transport pairs to prevent "No such tool available" errors on reconnect. - Add SKILLS_TOOL definition with search/install/remove/list actions - Add SkillSearchResult type and buildSkillIdentifier() helper - Delegate to PluginService.install/uninstall/listInstalled - Add mcp__claw__skills to auto-allow list in CherryClawService - Refactor claw-mcp.ts: per-session ClawServer+Transport pairs - Add 10 new tests for skills tool (27 total claw tests) Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Replace Claude Code preset system prompt with a full custom prompt assembled by PromptBuilder from workspace files. Add memory MCP tool for persistent knowledge management across sessions. - PromptBuilder reads system.md (optional override), soul.md, user.md, and memory/FACT.md with mtime-based caching, assembles anna-style XML-tagged memories section with exclusive scope documentation - memory MCP tool with update (atomic FACT.md write), append (JOURNAL.jsonl timestamped entries with tags), and search (case-insensitive, tag filter) - _systemPrompt field on EnhancedSessionFields for full system prompt replacement in ClaudeCodeService (falls back to preset+append for regular claude-code agents) - system.md only overrides the preset/basic part; memories section is always appended regardless Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Add resolveFile/resolveFileCI helpers (inspired by anna's resolveFile) that scan directories with case-insensitive matching. Applied to all workspace file lookups: system.md, soul.md, user.md, FACT.md, and JOURNAL.jsonl. Exact match is preferred; falls back to directory scan. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Include explicit file layout diagram in the memories section so the agent knows exactly where each file lives and how to update it. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Replace the HTTP-based claw MCP connection with an in-memory McpServer
instance, eliminating the network round-trip for tool calls.
- Refactor ClawServer to use McpServer (high-level API) instead of
low-level Server, exposing mcpServer property
- Add InternalMcpInMemServerConfig type alongside existing HTTP config
- Map inmem configs to SDK's { type: 'sdk', instance } format in
ClaudeCodeService merge logic
- CherryClawService now instantiates ClawServer directly instead of
connecting over HTTP via apiConfigService
Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…memories section Replace lines.push() pattern with template literals and consolidate per-file subsections into a single Memories section with a table layout for clearer file purpose and update method documentation. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Remove all sandbox-related code including path enforcement in PreToolUse hook, sandbox settings UI toggle, configuration type fields, and default config values. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…in system prompt Add Chinese reference documentation for CherryClaw covering overall design, scheduler, channels, and MCP claw tools. Add a CherryClaw Tools section to the system prompt so the agent knows to use mcp__claw__* tools, and update the Memories section to reference mcp__claw__memory by exact name. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
…d task Heartbeat is now a special scheduled task (name='heartbeat') managed by the existing TaskService + SchedulerService poll loop, replacing the old file-prepend approach. - HeartbeatReader simplified: always reads heartbeat.md, trims content, returns undefined for empty/missing files - SchedulerService.runTask() detects heartbeat tasks and reads heartbeat.md from workspace; wraps content with context prompt - SchedulerService.ensureHeartbeatTask() creates/updates heartbeat task on agent create and config update - TaskService.listTasks() excludes heartbeat tasks by default - CherryClawConfiguration: heartbeat_file replaced with heartbeat_interval (minutes, default 30) - UI: HeartbeatSection (toggle + interval) added to Tasks settings page - Agent handlers sync heartbeat task on create/update/patch - i18n: simplified heartbeat keys (enabled, enabledHelper, interval, intervalHelper) across all 11 locale files Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Replace placeholder cherry-claw.png with proper lobster+cherries icon. Add square 768x768 icon to overview doc header. Signed-off-by: Vaayne <liu.vaayne@gmail.com>
### What this PR does Before this PR: - Cherry Claw Feishu and Telegram channels did not support `/whoami`. - Users had to guess or manually inspect chat identifiers before populating `allow_ids`. After this PR: - Adds `/whoami` support for Feishu and Telegram Cherry Claw channels. - Returns the current chat ID in chat so users can copy it into `allow_ids`. - Extends channel command tests for Feishu, Telegram, and shared command handling. Fixes # N/A ### Why we need it and why it was done in this way - Channel setup depends on knowing the exact chat ID format each adapter receives. - Reusing the shared channel command handler keeps the `/whoami` response consistent across adapters. The following tradeoffs were made: - Feishu still relies on slash-prefixed text parsing because it does not expose native bot commands like Telegram. The following alternatives were considered: - Documentation-only guidance, but that would still force users to leave the chat and manually copy IDs from another surface. Links to places where the discussion took place: None ### Breaking changes None. If this PR introduces breaking changes, please describe the changes and the impact on users. ### Special notes for your reviewer - `pnpm lint` passes. - Focused channel tests pass. - Repo-wide `pnpm test` still fails in this workspace due the pre-existing renderer `@vitest/web-worker` module resolution issue. ### Checklist This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR. Approvers are expected to review this list. - [x] PR: The PR description is expressive enough and will help future contributors - [x] Code: [Write code that humans can understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans) and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle) - [x] Refactor: You have [left the code cleaner than you found it (Boy Scout Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html) - [ ] Upgrade: Impact of this change on upgrade flows was considered and addressed if required - [x] Documentation: A [user-guide update](https://docs.cherry-ai.com) was considered and is present (link) or not required. Check this only when the PR introduces or changes a user-facing feature or behavior. - [x] Self-review: I have reviewed my own code (e.g., via [`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`, or GitHub UI) before requesting review from others ### Release note ```release-note Added `/whoami` support for Cherry Claw Feishu and Telegram channels so users can retrieve the current chat ID and add it to `allow_ids` for notifications. ``` --------- Signed-off-by: Vaayne <liu.vaayne@gmail.com>
### What this PR does Before this PR: CherryClaw only supported Telegram as a channel adapter for receiving and sending messages. After this PR: CherryClaw now supports QQ Bot as an additional channel adapter, allowing users to connect their autonomous agents to QQ messaging platform. Fixes # N/A ### Why we need it and why it was done in this way The following tradeoffs were made: - **No streaming support**: QQ Bot API has no native draft/streaming API like Telegram's `sendMessageDraft`, so streaming responses are not supported. Full responses are sent as final messages only. - **No typing indicator**: QQ Bot API doesn't support typing indicators for most message types, so `sendTypingIndicator` is a no-op. - **WebSocket over long polling**: Uses WebSocket gateway (like the reference implementation) for better reliability and lower latency. The following alternatives were considered: - Using the `@sliverp/qqbot` package directly: Decided against this as it's designed as an OpenClaw plugin with heavy dependencies. Instead, implemented a standalone adapter following the same patterns. Links to places where the discussion took place: - Reference implementation: https://github.com/sliverp/qqbot ### Breaking changes None. This is an additive feature. ### Special notes for your reviewer - The adapter follows the same pattern as TelegramAdapter - Supports 4 message types: c2c (private), group, guild (channel), and dm - Includes sandbox mode toggle for testing with QQ's sandbox API - All main process tests pass (38 files, 528 tests) ### Checklist - [x] PR: The PR description is expressive enough and will help future contributors - [x] Code: Write code that humans can understand and Keep it simple - [x] Refactor: You have left the code cleaner than you found it (Boy Scout Rule) - [x] Upgrade: Impact of this change on upgrade flows was considered and addressed if required - [ ] Documentation: A user-guide update was considered and is present (link) or not required - [x] Self-review: I have reviewed my own code before requesting review from others ### Release note ```release-note Add QQ channel adapter for CherryClaw agents - connect your autonomous agent to QQ messaging platform via the official QQ Bot API ``` --------- Signed-off-by: Vaayne <liu.vaayne@gmail.com> Co-authored-by: kangfenmao <kangfenmao@qq.com>
871fe21 to
1a54999
Compare
409c071 to
78603a2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Before this PR:
Cherry Studio only supports
claude-codeas an agent type. Agents have no autonomous scheduling, no IM channel integration, and no soul/personality system.After this PR:
Introduces CherryClaw — a new autonomous agent type with:
crontool (add/list/remove) auto-injected into CherryClaw sessions for autonomous task managementWhy we need it and why it was done in this way
CherryClaw enables Cherry Studio agents to operate autonomously — executing scheduled tasks and responding to IM messages without user interaction. This is the foundation for "always-on" AI assistants.
The following tradeoffs were made:
ClaudeCodeServiceinSessionMessageServicewith a registry mappingAgentType→ service. Extensible for future agent types.crontool is served as a standard MCP server at/v1/claw/:agentId/claw-mcp. This lets the agent discover and use it naturally.ChannelAdapter+ factory registration enables future Discord/Slack adapters without touching core routing logic.The following alternatives were considered:
Breaking changes
None. This is a new agent type (
cherry-claw) alongside the existingclaude-codetype. No existing behavior is modified.Special notes for your reviewer
0003_wise_meltdown.sqladdsscheduled_tasksandtask_run_logstables (agents DB only, not IndexedDB)cron-parser^5.5.0,grammy^1.41cherry-claw.pngis currently a copy ofclaude.png— needs a proper distinct imagehandoff.mdfile in the repo root contains full architectural context and decisionsChecklist
/gh-pr-review,gh pr diff, or GitHub UI) before requesting review from othersRelease note