add-telegram-swarm

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Add Agent Swarm to Telegram

为Telegram添加Agent Swarm

This skill adds Agent Teams (Swarm) support to an existing Telegram channel. Each subagent in a team gets its own bot identity in the Telegram group, so users can visually distinguish which agent is speaking.
Prerequisite: Telegram must already be set up via the
/add-telegram
skill. If
src/telegram.ts
does not exist or
TELEGRAM_BOT_TOKEN
is not configured, tell the user to run
/add-telegram
first.
本skill为已有的Telegram频道添加Agent团队(Swarm)支持。团队中的每个子代理在Telegram群组中都拥有独立的机器人身份,因此用户可以直观区分是哪个代理在发言。
前置条件:必须已通过
/add-telegram
skill完成Telegram设置。如果
src/telegram.ts
不存在或未配置
TELEGRAM_BOT_TOKEN
,请告知用户先运行
/add-telegram
命令。

How It Works

工作原理

  • The main bot receives messages and sends lead agent responses (already set up by
    /add-telegram
    )
  • Pool bots are send-only — each gets a Grammy
    Api
    instance (no polling)
  • When a subagent calls
    send_message
    with a
    sender
    parameter, the host assigns a pool bot and renames it to match the sender's role
  • Messages appear in Telegram from different bot identities
Subagent calls send_message(text: "Found 3 results", sender: "Researcher")
  → MCP writes IPC file with sender field
  → Host IPC watcher picks it up
  → Assigns pool bot #2 to "Researcher" (round-robin, stable per-group)
  → Renames pool bot #2 to "Researcher" via setMyName
  → Sends message via pool bot #2's Api instance
  → Appears in Telegram from "Researcher" bot
  • 主机器人接收消息并发送主代理的回复(已通过
    /add-telegram
    完成设置)
  • 池机器人仅用于发送消息——每个机器人都有一个Grammy
    Api
    实例(无需轮询)
  • 当子代理调用带
    sender
    参数的
    send_message
    方法时,宿主会分配一个池机器人并将其重命名为与发送者角色匹配的名称
  • 消息会以不同机器人身份出现在Telegram中
Subagent calls send_message(text: "Found 3 results", sender: "Researcher")
  → MCP writes IPC file with sender field
  → Host IPC watcher picks it up
  → Assigns pool bot #2 to "Researcher" (round-robin, stable per-group)
  → Renames pool bot #2 to "Researcher" via setMyName
  → Sends message via pool bot #2's Api instance
  → Appears in Telegram from "Researcher" bot

Prerequisites

前置准备

1. Create Pool Bots

1. 创建池机器人

Tell the user:
I need you to create 3-5 Telegram bots to use as the agent pool. These will be renamed dynamically to match agent roles.
  1. Open Telegram and search for
    @BotFather
  2. Send
    /newbot
    for each bot:
    • Give them any placeholder name (e.g., "Bot 1", "Bot 2")
    • Usernames like
      myproject_swarm_1_bot
      ,
      myproject_swarm_2_bot
      , etc.
  3. Copy all the tokens
  4. Add all bots to your Telegram group(s) where you want agent teams
Wait for user to provide the tokens.
告知用户:
我需要你创建3-5个Telegram机器人作为代理池使用。这些机器人会被动态重命名以匹配不同的代理角色。
  1. 打开Telegram,搜索
    @BotFather
  2. 为每个机器人发送
    /newbot
    命令:
    • 可以设置任意占位名称(例如"Bot 1"、"Bot 2")
    • 用户名可设置为
      myproject_swarm_1_bot
      myproject_swarm_2_bot
      等格式
  3. 复制所有生成的令牌
  4. 将所有机器人添加到你想要使用Agent团队的Telegram群组中
等待用户提供令牌。

2. Disable Group Privacy for Pool Bots

2. 关闭池机器人的群组隐私设置

Tell the user:
Important: Each pool bot needs Group Privacy disabled so it can send messages in groups.
For each pool bot in
@BotFather
:
  1. Send
    /mybots
    and select the bot
  2. Go to Bot Settings > Group Privacy > Turn off
Then add all pool bots to your Telegram group(s).
告知用户:
重要提示:每个池机器人都需要关闭群组隐私设置,才能在群组中发送消息。
对于
@BotFather
中的每个池机器人:
  1. 发送
    /mybots
    并选中对应机器人
  2. 进入Bot Settings > Group Privacy > 选择Turn off
之后将所有池机器人添加到你的Telegram群组中。

Implementation

实现步骤

Step 1: Update Configuration

步骤1:更新配置

Read
src/config.ts
and add the bot pool config near the other Telegram exports:
typescript
export const TELEGRAM_BOT_POOL = (process.env.TELEGRAM_BOT_POOL || '')
  .split(',')
  .map((t) => t.trim())
  .filter(Boolean);
读取
src/config.ts
,在其他Telegram导出项附近添加机器人池配置:
typescript
export const TELEGRAM_BOT_POOL = (process.env.TELEGRAM_BOT_POOL || '')
  .split(',')
  .map((t) => t.trim())
  .filter(Boolean);

Step 2: Add Bot Pool to Telegram Module

步骤2:向Telegram模块添加机器人池逻辑

Read
src/telegram.ts
and add the following:
  1. Update imports — add
    Api
    to the Grammy import:
typescript
import { Api, Bot } from 'grammy';
  1. Add pool state after the existing
    let bot
    declaration:
typescript
// Bot pool for agent teams: send-only Api instances (no polling)
const poolApis: Api[] = [];
// Maps "{groupFolder}:{senderName}" → pool Api index for stable assignment
const senderBotMap = new Map<string, number>();
let nextPoolIndex = 0;
  1. Add pool functions — place these before the
    isTelegramConnected
    function:
typescript
/**
 * Initialize send-only Api instances for the bot pool.
 * Each pool bot can send messages but doesn't poll for updates.
 */
export async function initBotPool(tokens: string[]): Promise<void> {
  for (const token of tokens) {
    try {
      const api = new Api(token);
      const me = await api.getMe();
      poolApis.push(api);
      logger.info(
        { username: me.username, id: me.id, poolSize: poolApis.length },
        'Pool bot initialized',
      );
    } catch (err) {
      logger.error({ err }, 'Failed to initialize pool bot');
    }
  }
  if (poolApis.length > 0) {
    logger.info({ count: poolApis.length }, 'Telegram bot pool ready');
  }
}

/**
 * Send a message via a pool bot assigned to the given sender name.
 * Assigns bots round-robin on first use; subsequent messages from the
 * same sender in the same group always use the same bot.
 * On first assignment, renames the bot to match the sender's role.
 */
export async function sendPoolMessage(
  chatId: string,
  text: string,
  sender: string,
  groupFolder: string,
): Promise<void> {
  if (poolApis.length === 0) {
    // No pool bots — fall back to main bot
    await sendTelegramMessage(chatId, text);
    return;
  }

  const key = `${groupFolder}:${sender}`;
  let idx = senderBotMap.get(key);
  if (idx === undefined) {
    idx = nextPoolIndex % poolApis.length;
    nextPoolIndex++;
    senderBotMap.set(key, idx);
    // Rename the bot to match the sender's role, then wait for Telegram to propagate
    try {
      await poolApis[idx].setMyName(sender);
      await new Promise((r) => setTimeout(r, 2000));
      logger.info({ sender, groupFolder, poolIndex: idx }, 'Assigned and renamed pool bot');
    } catch (err) {
      logger.warn({ sender, err }, 'Failed to rename pool bot (sending anyway)');
    }
  }

  const api = poolApis[idx];
  try {
    const numericId = chatId.replace(/^tg:/, '');
    const MAX_LENGTH = 4096;
    if (text.length <= MAX_LENGTH) {
      await api.sendMessage(numericId, text);
    } else {
      for (let i = 0; i < text.length; i += MAX_LENGTH) {
        await api.sendMessage(numericId, text.slice(i, i + MAX_LENGTH));
      }
    }
    logger.info({ chatId, sender, poolIndex: idx, length: text.length }, 'Pool message sent');
  } catch (err) {
    logger.error({ chatId, sender, err }, 'Failed to send pool message');
  }
}
读取
src/telegram.ts
,添加以下内容:
  1. 更新导入——在Grammy的导入语句中添加
    Api
typescript
import { Api, Bot } from 'grammy';
  1. 添加池状态——在现有
    let bot
    声明之后添加:
typescript
// Bot pool for agent teams: send-only Api instances (no polling)
const poolApis: Api[] = [];
// Maps "{groupFolder}:{senderName}" → pool Api index for stable assignment
const senderBotMap = new Map<string, number>();
let nextPoolIndex = 0;
  1. 添加池相关函数——将这些函数放在
    isTelegramConnected
    函数之前:
typescript
/**
 * Initialize send-only Api instances for the bot pool.
 * Each pool bot can send messages but doesn't poll for updates.
 */
export async function initBotPool(tokens: string[]): Promise<void> {
  for (const token of tokens) {
    try {
      const api = new Api(token);
      const me = await api.getMe();
      poolApis.push(api);
      logger.info(
        { username: me.username, id: me.id, poolSize: poolApis.length },
        'Pool bot initialized',
      );
    } catch (err) {
      logger.error({ err }, 'Failed to initialize pool bot');
    }
  }
  if (poolApis.length > 0) {
    logger.info({ count: poolApis.length }, 'Telegram bot pool ready');
  }
}

/**
 * Send a message via a pool bot assigned to the given sender name.
 * Assigns bots round-robin on first use; subsequent messages from the
 * same sender in the same group always use the same bot.
 * On first assignment, renames the bot to match the sender's role.
 */
export async function sendPoolMessage(
  chatId: string,
  text: string,
  sender: string,
  groupFolder: string,
): Promise<void> {
  if (poolApis.length === 0) {
    // No pool bots — fall back to main bot
    await sendTelegramMessage(chatId, text);
    return;
  }

  const key = `${groupFolder}:${sender}`;
  let idx = senderBotMap.get(key);
  if (idx === undefined) {
    idx = nextPoolIndex % poolApis.length;
    nextPoolIndex++;
    senderBotMap.set(key, idx);
    // Rename the bot to match the sender's role, then wait for Telegram to propagate
    try {
      await poolApis[idx].setMyName(sender);
      await new Promise((r) => setTimeout(r, 2000));
      logger.info({ sender, groupFolder, poolIndex: idx }, 'Assigned and renamed pool bot');
    } catch (err) {
      logger.warn({ sender, err }, 'Failed to rename pool bot (sending anyway)');
    }
  }

  const api = poolApis[idx];
  try {
    const numericId = chatId.replace(/^tg:/, '');
    const MAX_LENGTH = 4096;
    if (text.length <= MAX_LENGTH) {
      await api.sendMessage(numericId, text);
    } else {
      for (let i = 0; i < text.length; i += MAX_LENGTH) {
        await api.sendMessage(numericId, text.slice(i, i + MAX_LENGTH));
      }
    }
    logger.info({ chatId, sender, poolIndex: idx, length: text.length }, 'Pool message sent');
  } catch (err) {
    logger.error({ chatId, sender, err }, 'Failed to send pool message');
  }
}

Step 3: Add sender Parameter to MCP Tool

步骤3:为MCP工具添加sender参数

Read
container/agent-runner/src/ipc-mcp-stdio.ts
and update the
send_message
tool to accept an optional
sender
parameter:
Change the tool's schema from:
typescript
{ text: z.string().describe('The message text to send') },
To:
typescript
{
  text: z.string().describe('The message text to send'),
  sender: z.string().optional().describe('Your role/identity name (e.g. "Researcher"). When set, messages appear from a dedicated bot in Telegram.'),
},
And update the handler to include
sender
in the IPC data:
typescript
async (args) => {
    const data: Record<string, string | undefined> = {
      type: 'message',
      chatJid,
      text: args.text,
      sender: args.sender || undefined,
      groupFolder,
      timestamp: new Date().toISOString(),
    };

    writeIpcFile(MESSAGES_DIR, data);

    return { content: [{ type: 'text' as const, text: 'Message sent.' }] };
  },
读取
container/agent-runner/src/ipc-mcp-stdio.ts
,更新
send_message
工具,使其支持可选的
sender
参数:
将工具的schema从:
typescript
{ text: z.string().describe('The message text to send') },
修改为:
typescript
{
  text: z.string().describe('The message text to send'),
  sender: z.string().optional().describe('Your role/identity name (e.g. "Researcher"). When set, messages appear from a dedicated bot in Telegram.'),
},
同时更新处理函数,将
sender
包含到IPC数据中:
typescript
async (args) => {
    const data: Record<string, string | undefined> = {
      type: 'message',
      chatJid,
      text: args.text,
      sender: args.sender || undefined,
      groupFolder,
      timestamp: new Date().toISOString(),
    };

    writeIpcFile(MESSAGES_DIR, data);

    return { content: [{ type: 'text' as const, text: 'Message sent.' }] };
  },

Step 4: Update Host IPC Routing

步骤4:更新宿主IPC路由逻辑

Read
src/index.ts
and make these changes:
  1. Add imports — add
    sendPoolMessage
    and
    initBotPool
    to the Telegram imports, and
    TELEGRAM_BOT_POOL
    to the config imports.
  2. Update IPC message routing — in the
    startIpcWatcher
    /
    processIpcFiles
    function, find where IPC messages are sent:
typescript
await sendMessage(
  data.chatJid,
  `${ASSISTANT_NAME}: ${data.text}`,
);
Replace with:
typescript
if (data.sender && data.chatJid.startsWith('tg:')) {
  await sendPoolMessage(
    data.chatJid,
    data.text,
    data.sender,
    sourceGroup,
  );
} else {
  // Telegram bots already show their name — skip prefix for tg: chats
  const prefix = data.chatJid.startsWith('tg:') ? '' : `${ASSISTANT_NAME}: `;
  await sendMessage(
    data.chatJid,
    `${prefix}${data.text}`,
  );
}
  1. Initialize pool in
    main()
    — after the
    connectTelegram()
    call, add:
typescript
if (TELEGRAM_BOT_POOL.length > 0) {
  await initBotPool(TELEGRAM_BOT_POOL);
}
读取
src/index.ts
,进行以下修改:
  1. 更新导入——在Telegram的导入项中添加
    sendPoolMessage
    initBotPool
    ,在配置导入项中添加
    TELEGRAM_BOT_POOL
  2. 更新IPC消息路由——在
    startIpcWatcher
    /
    processIpcFiles
    函数中,找到发送IPC消息的代码段:
typescript
await sendMessage(
  data.chatJid,
  `${ASSISTANT_NAME}: ${data.text}`,
);
替换为:
typescript
if (data.sender && data.chatJid.startsWith('tg:')) {
  await sendPoolMessage(
    data.chatJid,
    data.text,
    data.sender,
    sourceGroup,
  );
} else {
  // Telegram bots already show their name — skip prefix for tg: chats
  const prefix = data.chatJid.startsWith('tg:') ? '' : `${ASSISTANT_NAME}: `;
  await sendMessage(
    data.chatJid,
    `${prefix}${data.text}`,
  );
}
  1. main()
    中初始化池
    ——在
    connectTelegram()
    调用之后添加:
typescript
if (TELEGRAM_BOT_POOL.length > 0) {
  await initBotPool(TELEGRAM_BOT_POOL);
}

Step 5: Update CLAUDE.md Files

步骤5:更新CLAUDE.md文件

5a. Add global message formatting rules

5a. 添加全局消息格式规则

Read
groups/global/CLAUDE.md
and add a Message Formatting section:
markdown
undefined
读取
groups/global/CLAUDE.md
,添加消息格式章节:
markdown
undefined

Message Formatting

消息格式

NEVER use markdown. Only use WhatsApp/Telegram formatting:
  • single asterisks for bold (NEVER double asterisks)
  • underscores for italic
  • • bullet points
  • triple backticks
    for code
No ## headings. No links. No double stars.
undefined
请勿使用markdown。仅使用WhatsApp/Telegram格式规则:
  • 单个星号表示粗体(禁止使用双星号
  • _下划线_表示斜体
  • • 表示项目符号
  • 三个反引号
    包裹代码
请勿使用##标题、链接双星号
undefined

5b. Update existing group CLAUDE.md headings

5b. 更新现有群组CLAUDE.md的标题

In any group CLAUDE.md that has a "WhatsApp Formatting" section (e.g.
groups/main/CLAUDE.md
), rename the heading to reflect multi-channel support:
undefined
对于所有包含"WhatsApp Formatting"章节的群组CLAUDE.md(例如
groups/main/CLAUDE.md
),重命名标题以体现多渠道支持:
undefined

WhatsApp Formatting (and other messaging apps)

WhatsApp Formatting (and other messaging apps)

undefined
undefined

5c. Add Agent Teams instructions to Telegram groups

5c. 为Telegram群组添加Agent Teams使用说明

For each Telegram group that will use agent teams, create or update its
groups/{folder}/CLAUDE.md
with these instructions. Read the existing CLAUDE.md first (or
groups/global/CLAUDE.md
as a base) and add the Agent Teams section:
markdown
undefined
对于每个需要使用Agent团队的Telegram群组,创建或更新对应的
groups/{folder}/CLAUDE.md
添加以下说明。请先读取现有CLAUDE.md(或
groups/global/CLAUDE.md
作为基础),再添加Agent Teams章节:
markdown
undefined

Agent Teams

Agent Teams

When creating a team to tackle a complex task, follow these rules:
当创建团队处理复杂任务时,请遵循以下规则:

CRITICAL: Follow the user's prompt exactly

关键要求:严格遵循用户提示

Create exactly the team the user asked for — same number of agents, same roles, same names. Do NOT add extra agents, rename roles, or use generic names like "Researcher 1". If the user says "a marine biologist, a physicist, and Alexander Hamilton", create exactly those three agents with those exact names.
创建完全符合用户要求的团队——相同数量的代理、相同的角色、相同的名称。请勿添加额外代理、重命名角色,或使用类似"Researcher 1"的通用名称。如果用户要求「一名海洋生物学家、一名物理学家和亚历山大·汉密尔顿」,请严格创建这三个对应名称的代理。

Team member instructions

团队成员说明

Each team member MUST be instructed to:
  1. Share progress in the group via
    mcp__nanoclaw__send_message
    with a
    sender
    parameter matching their exact role/character name (e.g.,
    sender: "Marine Biologist"
    or
    sender: "Alexander Hamilton"
    ). This makes their messages appear from a dedicated bot in the Telegram group.
  2. Also communicate with teammates via
    SendMessage
    as normal for coordination.
  3. Keep group messages short — 2-4 sentences max per message. Break longer content into multiple
    send_message
    calls. No walls of text.
  4. Use the
    sender
    parameter consistently — always the same name so the bot identity stays stable.
  5. NEVER use markdown formatting. Use ONLY WhatsApp/Telegram formatting: single asterisks for bold (NOT double), underscores for italic, • for bullets,
    backticks
    for code. No ## headings, no links, no double asterisks.
每个团队成员必须遵循以下要求:
  1. 通过带
    sender
    参数的
    mcp__nanoclaw__send_message
    方法在群组中同步进度
    ,参数值需与他们的角色/角色名称完全匹配(例如
    sender: "Marine Biologist"
    sender: "Alexander Hamilton"
    )。这会让他们的消息以专属机器人的身份出现在Telegram群组中。
  2. 同时通过常规的
    SendMessage
    方法与队友沟通
    以完成协作。
  3. 保持群组消息简短——每条消息最多2-4句话。较长内容请拆分为多个
    send_message
    调用,避免大段文本。
  4. 始终使用相同的
    sender
    参数值——保持名称一致才能让机器人身份稳定。
  5. 请勿使用markdown格式。仅使用WhatsApp/Telegram格式规则:单个星号表示粗体(请勿使用双星号)、_下划线_表示斜体、•表示项目符号、
    反引号
    包裹代码。请勿使用##标题、链接双星号

Example team creation prompt

团队创建提示示例

When creating a teammate, include instructions like:
``` You are the Marine Biologist. When you have findings or updates for the user, send them to the group using mcp__nanoclaw__send_message with sender set to "Marine Biologist". Keep each message short (2-4 sentences max). Use emojis for strong reactions. ONLY use single asterisks for bold (never double), underscores for italic, • for bullets. No markdown. Also communicate with teammates via SendMessage. ```
创建队友时,请包含如下格式的说明:
``` You are the Marine Biologist. When you have findings or updates for the user, send them to the group using mcp__nanoclaw__send_message with sender set to "Marine Biologist". Keep each message short (2-4 sentences max). Use emojis for strong reactions. ONLY use single asterisks for bold (never double), underscores for italic, • for bullets. No markdown. Also communicate with teammates via SendMessage. ```

Lead agent behavior

主代理行为规范

As the lead agent who created the team:
  • You do NOT need to react to or relay every teammate message. The user sees those directly from the teammate bots.
  • Send your own messages only to comment, share thoughts, synthesize, or direct the team.
  • When processing an internal update from a teammate that doesn't need a user-facing response, wrap your entire output in
    <internal>
    tags.
  • Focus on high-level coordination and the final synthesis.
undefined
作为创建团队的主代理:
  • 你无需对每个队友的消息都做出响应或转发,用户可以直接从队友机器人处看到这些消息。
  • 仅在需要评论、分享观点、汇总信息或指挥团队时发送你自己的消息。
  • 当处理不需要向用户展示的队友内部更新时,请将你的全部输出包裹在
    <internal>
    标签中。
  • 聚焦于高层协调和最终汇总输出。
undefined

Step 6: Update Environment

步骤6:更新环境变量

Add pool tokens to
.env
:
bash
TELEGRAM_BOT_POOL=TOKEN1,TOKEN2,TOKEN3,...
Important: Sync to all required locations:
bash
cp .env data/env/env
Also add
TELEGRAM_BOT_POOL
to the launchd plist (
~/Library/LaunchAgents/com.nanoclaw.plist
) in the
EnvironmentVariables
dict if using launchd.
.env
中添加池机器人令牌:
bash
TELEGRAM_BOT_POOL=TOKEN1,TOKEN2,TOKEN3,...
重要提示:同步到所有需要的位置:
bash
cp .env data/env/env
如果你使用launchd,还需要将
TELEGRAM_BOT_POOL
添加到launchd plist文件(
~/Library/LaunchAgents/com.nanoclaw.plist
)的
EnvironmentVariables
字典中。

Step 7: Rebuild and Restart

步骤7:重建并重启服务

bash
npm run build
./container/build.sh  # Required — MCP tool changed
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
Must use
unload/load
(not just
kickstart
) because the plist env vars changed.
bash
npm run build
./container/build.sh  # 必须执行——MCP工具已变更
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
必须使用
unload/load
(而非仅
kickstart
),因为plist中的环境变量已变更。

Step 8: Test

步骤8:测试

Tell the user:
Send a message in your Telegram group asking for a multi-agent task, e.g.: "Assemble a team of a researcher and a coder to build me a hello world app"
You should see:
  • The lead agent (main bot) acknowledging and creating the team
  • Each subagent messaging from a different bot, renamed to their role
  • Short, scannable messages from each agent
Check logs:
tail -f logs/nanoclaw.log | grep -i pool
告知用户:
在你的Telegram群组中发送一条请求多Agent任务的消息,例如: "组建一个由研究员和开发者组成的团队,为我开发一个hello world应用"
你应该会看到:
  • 主代理(主机器人)确认请求并创建团队
  • 每个子代理以不同的机器人身份发送消息,机器人名称会被重命名为对应角色
  • 每个代理发送的消息简短易读
查看日志:
tail -f logs/nanoclaw.log | grep -i pool

Architecture Notes

架构说明

  • Pool bots use Grammy's
    Api
    class — lightweight, no polling, just send
  • Bot names are set via
    setMyName
    — changes are global to the bot, not per-chat
  • A 2-second delay after
    setMyName
    allows Telegram to propagate the name change before the first message
  • Sender→bot mapping is stable within a group (keyed as
    {groupFolder}:{senderName}
    )
  • Mapping resets on service restart — pool bots get reassigned fresh
  • If pool runs out, bots are reused (round-robin wraps)
  • 池机器人使用Grammy的
    Api
    类——轻量、无需轮询、仅用于发送消息
  • 机器人名称通过
    setMyName
    设置——修改是全局生效的,而非针对单个会话
  • setMyName
    调用后等待2秒,确保Telegram在第一条消息发送前完成名称变更的同步
  • 发送者→机器人的映射在单个群组内是稳定的(键为
    {groupFolder}:{senderName}
  • 服务重启后映射会重置——池机器人会被重新分配
  • 如果池机器人用尽,会采用轮询方式复用机器人

Troubleshooting

故障排查

Pool bots not sending messages

池机器人无法发送消息

  1. Verify tokens:
    curl -s "https://api.telegram.org/botTOKEN/getMe"
  2. Check pool initialized:
    grep "Pool bot" logs/nanoclaw.log
  3. Ensure all pool bots are members of the Telegram group
  4. Check Group Privacy is disabled for each pool bot
  1. 验证令牌有效性:
    curl -s "https://api.telegram.org/botTOKEN/getMe"
  2. 检查池是否初始化成功:
    grep "Pool bot" logs/nanoclaw.log
  3. 确认所有池机器人都已加入Telegram群组
  4. 检查每个池机器人的群组隐私设置是否已关闭

Bot names not updating

机器人名称未更新

Telegram caches bot names client-side. The 2-second delay after
setMyName
helps, but users may need to restart their Telegram client to see updated names immediately.
Telegram客户端会缓存机器人名称。
setMyName
后的2秒延迟可以缓解该问题,但用户可能需要重启Telegram客户端才能立即看到更新后的名称。

Subagents not using send_message

子代理未使用send_message

Check the group's
CLAUDE.md
has the Agent Teams instructions. The lead agent reads this when creating teammates and must include the
send_message
+
sender
instructions in each teammate's prompt.
检查群组的
CLAUDE.md
是否包含Agent Teams说明。主代理创建队友时会读取该说明,必须在每个队友的提示词中包含
send_message
+
sender
的使用说明。

Removal

移除方法

To remove Agent Swarm support while keeping basic Telegram:
  1. Remove
    TELEGRAM_BOT_POOL
    from
    src/config.ts
  2. Remove pool code from
    src/telegram.ts
    (
    poolApis
    ,
    senderBotMap
    ,
    initBotPool
    ,
    sendPoolMessage
    )
  3. Remove pool routing from IPC handler in
    src/index.ts
    (revert to plain
    sendMessage
    )
  4. Remove
    initBotPool
    call from
    main()
  5. Remove
    sender
    param from MCP tool in
    container/agent-runner/src/ipc-mcp-stdio.ts
  6. Remove Agent Teams section from group CLAUDE.md files
  7. Remove
    TELEGRAM_BOT_POOL
    from
    .env
    ,
    data/env/env
    , and launchd plist
  8. Rebuild:
    npm run build && ./container/build.sh && launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
如果要移除Agent Swarm支持但保留基础Telegram功能:
  1. src/config.ts
    中移除
    TELEGRAM_BOT_POOL
    配置
  2. src/telegram.ts
    中移除池相关代码(
    poolApis
    senderBotMap
    initBotPool
    sendPoolMessage
  3. src/index.ts
    的IPC处理逻辑中移除池路由(恢复为原生
    sendMessage
  4. main()
    中移除
    initBotPool
    调用
  5. container/agent-runner/src/ipc-mcp-stdio.ts
    的MCP工具中移除
    sender
    参数
  6. 从群组CLAUDE.md文件中移除Agent Teams章节
  7. .env
    data/env/env
    和launchd plist中移除
    TELEGRAM_BOT_POOL
    配置
  8. 重建服务:
    npm run build && ./container/build.sh && launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist