ClawSkills logoClawSkills

Telegram Compose

通过直接 Telegram API 使用 HTML 格式化并发送丰富的 Telegram 消息。 当主会话生成实质性的 Telegram 输出时会自动调用 — 无需

介绍

# Telegram Compose

通过直接 API 使用 HTML 格式化并发送丰富、易于浏览的 Telegram 消息。

## 此技能如何被使用

**此技能由主会话代理自动调用。** 不需要其他技能了解它。

### 决策规则(针对主会话代理)

在向 Telegram 发送消息之前,请检查:

- **简短回复(<3 行,无结构):** 直接通过 OpenClaw `message` 工具发送。完成。 - **实质性内容(>3 行,或包含列表/统计/章节/报告):** 将此技能作为子代理调用。

### 生成子代理

主会话代理调用 `sessions_spawn` 并传入:

``` sessions_spawn( model: "claude-haiku-4-5", task: "<task content — see template below>" ) ```

**任务模板:**

``` Read the telegram-compose skill at {baseDir}/SKILL.md for formatting rules, then format and send this content to Telegram.

Bot account: <account_name> (e.g., "main" — must match a key in channels.telegram.accounts) Chat ID: <chat_id> Thread ID: <thread_id> (omit this line if not a forum/topic chat)

Content to format: --- <raw content here> ---

After sending, reply with the message_id on success or the error on failure. Do NOT include the formatted message in your reply — it's already been sent to Telegram. ```

**重要提示:** 调用者必须指定使用哪个机器人账户。子代理绝不能自动选择或轮询账户。

**关键:** 子代理的公告会路由回主会话,而不是 Telegram。因此,主会话应在生成子代理后回复 `NO_REPLY`,以避免重复发送消息。子代理的 curl 调用才是真正向 Telegram 发送消息的操作。

### 子代理接收的内容

1. **技能路径** — 以便其读取格式规则 2. **机器人账户名称** — 要使用的 Telegram 机器人账户(必须指定,绝不自动选择) 3. **聊天 ID** — 发送目标 4. **话题 ID** — 如适用,为主题话题线程 5. **原始内容** — 需要转换为丰富消息的未格式化文本/数据

---

## 凭证

**机器人令牌:** 存储在 OpenClaw 配置文件的 `channels.telegram.accounts.<name>.botToken` 下。

**账户名称始终由调用者提供。** 绝不自动选择或轮询账户。

```bash # Auto-detect config path CONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json)

# ACCOUNT is provided by the caller (e.g., "main") # Validate the account exists before extracting the token ACCOUNT="<provided_account_name>" BOT_TOKEN=$(jq -r ".channels.telegram.accounts.$ACCOUNT.botToken" "$CONFIG")

if [ "$BOT_TOKEN" = "null" ] || [ -z "$BOT_TOKEN" ]; then echo "ERROR: Account '$ACCOUNT' not found in config or has no botToken" exit 1 fi ```

---

## 发送

```bash CONFIG=$([ -f ~/.openclaw/openclaw.json ] && echo ~/.openclaw/openclaw.json || echo ~/.openclaw/clawdbot.json) # ACCOUNT provided by caller — never auto-select BOT_TOKEN=$(jq -r ".channels.telegram.accounts.$ACCOUNT.botToken" "$CONFIG")

# Without topic thread curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \ -H "Content-Type: application/json" \ -d "$(jq -n \ --arg chat "$CHAT_ID" \ --arg text "$MESSAGE" \ '{ chat_id: $chat, text: $text, parse_mode: "HTML", link_preview_options: { is_disabled: true } }')"

# With topic thread curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \ -H "Content-Type: application/json" \ -d "$(jq -n \ --arg chat "$CHAT_ID" \ --arg text "$MESSAGE" \ --argjson thread $THREAD_ID \ '{ chat_id: $chat, text: $text, parse_mode: "HTML", message_thread_id: $thread, link_preview_options: { is_disabled: true } }')" ```

---

## 格式规则

### HTML 标签

``` <b>bold</b> <i>italic</i> <u>underline</u> <s>strike</s> <code>mono</code> <pre>code block</pre> <tg-spoiler>hidden until tapped</tg-spoiler> <blockquote>quote</blockquote> <blockquote expandable>collapsed by default</blockquote> <a href="url">link</a> <a href="tg://user?id=123">mention by ID</a> ```

### 转义

仅在**文本内容中**(而非 HTML 标签中)转义以下字符: - `&` → `&amp;` (首先执行此操作以避免重复转义) - `<` → `&lt;` - `>` → `&gt;`

常见陷阱:包含 `&` 的内容(例如 "R&D","Q&A")如果未转义,将会破坏 HTML 解析。

### 结构模式

``` EMOJI <b>HEADING IN CAPS</b>

<b>Label:</b> Value <b>Label:</b> Value

<b>SECTION</b>

• Bullet point • Another point

<blockquote>Key quote or summary</blockquote>

<blockquote expandable><b>Details</b>

Hidden content here... Long details go in expandable blocks.</blockquote>

<a href="https://...">Action Link →</a> ```

### 样式规则

1. **伪标题:** `EMOJI <b>CAPS TITLE</b>` 后跟空行 2. **表情符号:** 每条消息 1-3 个,作为视觉锚点,而非装饰 3. **空白:** 节与节之间保留空行 4. **长内容:** 使用 `<blockquote expandable>` 5. **链接:** 独占一行,带箭头:`Link Text →`

### 示例

**状态更新:** ``` 📋 <b>TASK COMPLETE</b>

<b>Task:</b> Deploy v2.3 <b>Status:</b> ✅ Done <b>Duration:</b> 12 min

<blockquote>All health checks passing.</blockquote> ```

**告警:** ``` ⚠️ <b>ATTENTION NEEDED</b>

<b>Issue:</b> API rate limit at 90% <b>Action:</b> Review usage

<a href="https://dashboard.example.com">View Dashboard →</a> ```

**列表:** ``` ✅ <b>PRIORITIES</b>

• <s>Review PR #234</s> — done • <b>Finish docs</b> — in progress • Deploy staging

<i>2 of 3 complete</i> ```

---

## 移动端友好的数据显示

**切勿使用 `<pre>` 来显示统计信息、摘要或视觉布局。** `<pre>` 使用等宽字体,在移动端换行效果很差,会破坏对齐和树状字符。`<pre>` 仅保留用于实际的代码/命令。

**对于结构化数据,使用表情符号 + 粗体 + 分隔符:**

``` ❌ BAD (wraps on mobile): <pre> ├─ 🟠 Reddit 32 threads │ 1,658 pts └─ 🌐 Web 8 pages </pre>

✅ GOOD (flows naturally): 🟠 <b>Reddit:</b> 32 threads · 1,658 pts · 625 comments 🔵 <b>X:</b> 22 posts · 10,695 likes · 1,137 reposts 🌐 <b>Web:</b> 8 pages (supplementary) 🗣️ <b>Top voices:</b> @handle1 · @handle2 · r/subreddit ```

**其他模式:**

记录卡片: ``` <b>Ruby</b> Birthday: Jun 16 · Age: 11

<b>Rhodes</b> Birthday: Oct 1 · Age: 8 ```

项目符号列表: ``` • <b>hzl-cli:</b> 1.12.0 • <b>skill:</b> 1.0.6 ```

---

## 限制与拆分

- **消息上限:** 4,096 个字符 - **说明文字上限:** 1,024 个字符

**如果格式化后的消息超过 4,096 个字符:** 1. 在章节边界拆分(`<b>HEADING</b>` 块之间的空行) 2. 每个块必须是有效的 HTML(不要在标签内部拆分) 3. 依次发送各块,每块之间间隔 1 秒 4. 第一块保留完整标题;后续块添加续传指示符:`<i>(continued)</i>`

---

## 错误处理

**如果 Telegram API 返回错误:**

| 错误 | 操作 | |-------|--------| | `Bad Request: can't parse entities` | HTML 格式错误。去除所有 HTML 标签并以纯文本形式重发。 | | `Bad Request: message is too long` | 按上述规则拆分并重试。 | | `Bad Request: message thread not found` | 重试时不带 `message_thread_id`(发送到通用版块)。 | | `Too Many Requests: retry after X` | 等待 X 秒,然后重试一次。 | | 任何其他错误 | 报告错误;不要重试。 |

**回退规则:** 如果 HTML 格式化两次失败,请以纯文本发送,而不是根本不发送。发送比格式化更重要。

---

## 子代理执行清单

作为子代理运行时,请遵循以下顺序:

1. **解析任务** — 提取机器人账户名称、聊天 ID、话题 ID(如果有)、技能路径和原始内容 2. **阅读此 SKILL.md** — 加载格式规则 3. **格式化内容** — 应用 HTML 标签、结构模式、样式规则、移动端友好的数据显示 4. **转义特殊字符** — 仅在文本内容中依次转义 `&` 然后 `<` 然后 `>`(不在 HTML 标签中) 5. **检查长度** — 如果 >4,096 个字符,在章节边界拆分 6. **获取机器人令牌** — 自动检测配置路径,提取指定账户的令牌(如果未找到则报错) 7. **通过 curl 发送** — 使用适当的模板(带/不带话题 ID) 8. **检查响应** — 解析 curl 输出中的 `"ok": true` 9. **处理错误** — 遵循上面的错误处理表 10. **回报结果** — 成功时回复 message_id,失败时回复错误详情

更多产品