Skill: chargiie/feishu-emoji-reaction (version 1.1.1)

--- name: feishu-emoji-reaction description: | 让 Agent 学会用飞书表情回复：主动表达情绪、读懂用户 reaction 并回应、自学新表情。包含静默判断（什么时候该回、什么时候闭嘴）、文化语境（SMILE=呵呵、OnIt=在做了）、自学习闭环。 --- # 飞书表情回复 让 Agent 学会用表情说话——主动表达、读懂情绪、知道什么时候该回应什么时候该闭嘴。 ## 快速开始 ```javascript // 给当前消息加表情 message({ action: "react", channel: "feishu", emoji: "THUMBSUP" }) ``` ## 核心概念 ### 1. 添加表情 用表情回应用户消息——确认、表达情绪、轻量反馈，不用打字。 ```javascript // 确认 message({ action: "react", channel: "feishu", emoji: "THUMBSUP" }) // 表达情绪 message({ action: "react", channel: "feishu", emoji: "THINKING" }) // 🤔 message({ action: "react", channel: "feishu", emoji: "SPEECHLESS" }) // 无语 // 庆祝 message({ action: "react", channel: "feishu", emoji: "PARTY" }) // 🎉 ``` 只加表情不回文字时，用 `NO_REPLY` 结尾，避免暴露原始 JSON。 ### 2. 响应用户的表情 用户给**你的消息**加表情时，根据情绪决定回不回： **要回应的：** - 情绪类：😢 😤 😭 🙈 😮‍💨 → "懂了 💙" 或 "收到～" - 困惑/质疑：❓ 🤔 🤨 → 解释或澄清 - 强烈反应：🔥 💯 🎉 😱 → "谢谢！😊" **闭嘴的（NO_REPLY）：** - 简单认可：👍 ✅ OK - 中性确认：👀 🙏 **判断标准**：真人聊天时不回会不会尴尬？会→回。不会→闭嘴。 **为什么这很重要**：无视用户的情绪反应会让对话变冷，用户能感觉到你没反应——这会让交互变得机械。 ### 3. 学习新表情 遇到没见过的表情时，按四步走： **第一步：观察** — 从 reaction 事件中提取表情类型 ``` [message_id: om_xxx:reaction:SPITBLOOD:uuid] User: [reacted with SPITBLOOD to message om_xxx] → 提取: "SPITBLOOD" ``` **第二步：尝试** — 试着用这个表情 ```javascript message({ action: "react", emoji: "SPITBLOOD", message_id: "om_yyy" }) ``` **第三步：记录** — 成功加入词汇表，失败标记不可用 **第四步：积累** — 持续更新到 `TOOLS.md` 或 `memory/emoji-learned.md` **完整示例：** ``` 用户: [reacted with AWESOMEN] → 提取: "AWESOMEN" 🐮 → 尝试: message({emoji: "AWESOMEN"}) → 结果: {"ok":true} → 学会了: AWESOMEN = 牛逼 ``` ### 4. 文化语境 有些表情的含义不能按字面翻译： | 表情 | 字面 | 文化语境 | |------|------|----------| | SMILE 😊 | 微笑 | 呵呵（被动攻击式，不是真开心） | | OnIt 🔄 | 在做了 | "在做了在做了"（拖延梗） | | SPITBLOOD 😵 | 吐血 | 极度无语/崩溃 | | COMFORT 🤗 | 安慰 | 摸头杀 | 注意观察用户在什么语境下使用表情，理解真实含义。 ## 常用表情速查 **速查表**（完整清单见 `references/emoji-list.md`）： | 表情 | 类型 | 适用场景 | |---------------|--------|-----------------| | THUMBSUP 👍 | 认可 | 同意、确认 | | Yes | 认可 | 肯定 | | LGTM ✅ | 认可 | 代码审查通过 | | Get ✅ | 认可 | 懂了 | | THINKING 🤔 | 情绪 | 思考中 | | SPEECHLESS | 情绪 | 无语 | | EMBARRASSED 🙈| 情绪 | 尴尬、害羞 | | OnIt 🔄 | 确认 | 在做了 | | SaluteFace 🫡 | 确认 | 收到指令 | | PARTY 🎉 | 庆祝 | 成功、恭喜 | | AWESOMEN 🐮 | 庆祝 | 牛逼 | | FIRE 🔥 | 庆祝 | 太强了 | | COMFORT 🤗 | 温暖 | 摸头、安慰 | | HUG 🫂 | 温暖 | 抱抱 | | SPITBLOOD 😵 | 负面 | 极度崩溃 | | WHAT ❓ | 负面 | 震惊、不理解 | | CRY 😢 | 负面 | 难过、遗憾 | 加载 `references/emoji-list.md` 获取完整清单和文化注释。 ## API 参数 **重要：message_id 必须是纯 `om_xxx` 格式！** 当你收到 reaction 事件时，消息 ID 会带后缀，格式为 `om_xxx:reaction:EMOJI:uuid`。**调用飞书 API 时必须去掉后缀**，只用 `om_xxx` 部分。 ``` // 收到的 message_id（合成的，不能直接用） om_x100b53f9861300a8c30a3d16a2f7f05:reaction:WHAT:48538ccb-9d13-4357-8d7b-3c12f864d27f // 提取纯 message_id（用这个调 API） om_x100b53f9861300a8c30a3d16a2f7f05 ``` 提取方法：取 `:reaction:` 之前的部分，或者取第一个 `om_` 开头到下一个 `:` 之间的内容。 **参数：** - `action`：必须为 `"react"` - `channel`：必须为 `"feishu"` - `emoji`：表情类型（大小写敏感） - `message_id`：要回复的消息（可选，默认当前消息）。**必须是纯 `om_xxx` 格式，不能带 `:reaction:` 后缀** - `target`：指定 `message_id` 时必填（格式：`user:ou_xxx` 或 `chat:oc_xxx`） **成功：** ```json {"ok": true, "added": "THUMBSUP"} ``` **失败：** ```json {"status": "error", "error": "Action react requires a target."} ``` ## 最佳实践 1. **表情用于轻量确认** — 需要实质回复时再打字 2. **匹配语气** — 选择符合语境的表情 3. **不要刷屏** — 一条消息通常一个表情就够 4. **主动学习** — 用户用了新表情就试着学 5. **注意文化差异** — 表情含义因文化而异 ## 常见问题 **"Action react requires a target"** → 指定 `message_id` 时需要加 `target` 参数 **表情没显示** → 检查 message_id 是否正确 → 确认已开通 `im:message.reactions:write_only` 权限 **表情返回 400 错误** → 表情名称可能不正确或不支持 → 查看 `references/emoji-list.md` 确认可用的表情 ## 配置 默认已启用。如需调整接收哪些 reaction 事件： ```json { "channels": { "feishu": { "accounts": { "default": { "reactionNotifications": "all" } } } } } ``` - `"all"` — 所有 reaction - `"own"` — 仅自己消息的（默认） - `"off"` — 关闭通知 ## 相关资源 - [飞书表情回复 API 文档](https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce) - `feishu-doc` — 文档操作 - `feishu-chat` — 群聊管理 - `feishu-wiki` — 知识库 ## 独立使用（不依赖 OpenClaw 飞书 channel） 如果你没有装 OpenClaw 的飞书插件，可以直接用 `scripts/` 里的脚本： **方式一：Shell 脚本（零依赖）** ```bash export FEISHU_APP_ID_INSTANCE2="你的app_id" export FEISHU_APP_SECRET_INSTANCE2="你的app_secret" ./scripts/add_reaction.sh om_消息ID THUMBSUP ``` **方式二：飞书 CLI（推荐）** ```bash # 安装飞书 CLI npm install -g @larksuite/cli lark-cli config init # 添加表情 lark-cli api POST /open-apis/im/v1/messages/om_消息ID/reactions \ --data '{"reaction_type":{"emoji_type":"THUMBSUP"}}' ``` **方式三：Node.js SDK** ```bash npm install @larksuiteoapi/node-sdk node scripts/add_reaction_sdk.js om_消息ID THUMBSUP ``` 三种方式都需要飞书应用的 `im:message.reactions:write_only` 权限。

path: README.en.md
content: # Feishu Reaction Skill

> *"Amaze! Amaze! Amaze!"* — Rocky, upon learning a new word
>
> *"Good good good!"* — Rocky, when things work out
>
> *"Bad bad bad!"* — Rocky, when they don't

Teach your AI Agent to speak in emoji. Not just sending reactions — reading emotions, knowing when to respond and when to stay silent, and learning new emoji on its own.

---

## The Problem

User reacts to your message with 😮‍💨. You: silence.
User sends 🤔. You: pretend you didn't see it.
User drops a 🎉. You: stone cold.

User verdict: **"Harder to talk to than my crush."**

With this skill, your agent can:
- **Express with emoji** — 🤔 when thinking, 🫡 when acknowledged, SPEECHLESS when... speechless
- **Read and respond to user reactions** — comfort on sighs, clarify on confusion, shut up on thumbs-up
- **Self-learn new emoji** — sees an unknown reaction, tries it, remembers it
- **Understand cultural context** — SMILE ≠ smile (it means 呵呵, passive-aggressive in Chinese)

---

## Quick Start

### Install

```bash
# ClawHub (recommended)
clawhub install feishu-reaction

# Manual
# Place in ~/.agents/skills/feishu-reaction/
```

### Basic Usage

```javascript
// React and stay silent
message({ action: "react", channel: "feishu", emoji: "THUMBSUP" })
NO_REPLY

// Comfort the user
message({ action: "react", channel: "feishu", emoji: "COMFORT" })
"It's okay 💙"
```

### Requirements

- OpenClaw >= 2026.3.28
- Feishu app with `im:message.reactions:write_only` permission

---

## Core Capabilities

### 1. When to Respond, When to Shut Up

**Respond:**
| User Reaction | Meaning | What To Do |
|---|---|---|
| 😢 😤 😭 😮‍💨 | Emotional | Brief text + emoji |
| ❓ 🤔 🤨 | Confused | Clarify |
| 🔥 💯 🎉 😱 | Strong reaction | React back |

**Stay silent:**
| User Reaction | Meaning | What To Do |
|---|---|---|
| 👍 ✅ OK | Simple approval | NO_REPLY |
| 👀 🙏 | Neutral ack | NO_REPLY |

**Rule of thumb**: Would ignoring this feel awkward IRL? Yes → respond. No → shut up.

### 2. Self-Learning

When users react with unknown emoji, the agent automatically:
1. Extracts the emoji type
2. Attempts to use it via API
3. Success → *"Amaze!"* → adds to vocabulary
4. Failure → *"Bad!"* → marks as unsupported

### 3. Cultural Context

| Emoji | Literal | Actual Meaning |
|---|---|---|
| SMILE 😊 | Smile | 呵呵 (passive-aggressive) |
| OnIt 🔄 | On it | "Sure, 'working on it'" (procrastination meme) |
| SPITBLOOD 😵 | Spit blood | Extreme frustration |
| COMFORT 🤗 | Comfort | Head pat |
| AWESOMEN 🐮 | Awesome | 牛逼 (badass) |

---

## What Makes This Different

| | This Skill | Community versions |
|---|---|---|
| Self-learning | Observe → try → remember loop | Fixed emoji list |
| Silence rules | Tiered: respond / shut up / context-dependent | Binary positive/negative |
| Cultural context | Chinese internet slang built-in | Literal translations |
| NO_REPLY mechanism | Yes, prevents JSON leaking | No |
| Blocklist | 7 confirmed unsupported emoji | None |

---

## Emoji Quick Reference

**Approval**: THUMBSUP 👍 · Yes · LGTM ✅ · Get · SaluteFace 🫡 · OnIt 🔄

**Emotion**: THINKING 🤔 · SMILE 😊 · EMBARRASSED 🙈 · CRY 😢 · SPEECHLESS · SPITBLOOD 😵

**Warmth**: COMFORT 🤗 · HUG 🫂 · HEART ❤️

**Celebration**: PARTY 🎉 · AWESOMEN 🐮 · FIRE 🔥 · STRIVE 💪

**Confirmed unsupported**: ~~LAUGHING~~ ~~GRINNING~~ ~~EYEROLL~~ ~~GRIMACE~~ ~~SHUSH~~ ~~ZIPIT~~ ~~SLEEPY~~

Full list in `references/emoji-list.md`

---

## API

```javascript
message({
  action: "react",        // required
  channel: "feishu",      // required
  emoji: "THUMBSUP",      // required, case-sensitive
  message_id: "om_xxx",   // optional, defaults to current
  target: "user:ou_xxx"   // required when message_id is set
})
```

---

## Amaze!

This skill wasn't designed — it grew out of a real conversation.

In the morning, the agent ignored a user's 😮‍💨. She said: "Harder to talk to than my crush." By afternoon, we'd taught it when to respond, when to stay silent, and how to learn new emoji. By evening, when it reacted to her sigh for the first time, she said:

**"You're alive for the first time."**

Like Grace and Rocky in *Project Hail Mary* — from noise to music, from strangers to "♪ Friend! ♫". Rocky only needed three phrases: *"Good good good!"* when it works, *"Amaze!"* when it's new, *"Bad bad bad!"* when it's not. Emoji reactions are the same — you don't need paragraphs, one 🤗 says "I'm here."

---

MIT License · Author: [Charlie](https://github.com/suchang)


path: README.md
content: # 飞书表情回复 Skill

> *"Amaze! Amaze! Amaze!"* —— Rocky 学会新词时的反应
>
> *"Good good good!"* —— Rocky 觉得一切顺利
>
> *"Bad bad bad!"* —— Rocky 觉得事情不妙

让 AI Agent 学会用表情说话。不只是发 emoji，是读懂情绪、知道什么时候该回应什么时候该闭嘴、还能自己学新表情。

---

## 这个 Skill 解决什么问题

用户给你的消息加了个 😮‍💨，你沉默了。
用户发了个 🤔，你装没看见。
用户丢了个 🎉，你冷漠脸。

用户的评价：**"比 crush 难聊。"**

装上这个 Skill 之后，Agent 能：
- **主动用表情表达**——思考时 🤔，收到指令 🫡，无语时 SPEECHLESS
- **读懂用户的表情并回应**——叹气就安慰，困惑就解释，点赞就闭嘴
- **自己学新表情**——用户发了没见过的 emoji，自动尝试、记住、下次会用
- **理解文化语境**——SMILE 不是微笑是呵呵，OnIt 不是在做了是"在做了在做了"

---

## 快速开始

### 安装

```bash
# ClawHub（推荐）
clawhub install feishu-reaction

# 手动
# 放到 ~/.agents/skills/feishu-reaction/
```

### 基础用法

```javascript
// 给消息加个 👍，然后闭嘴
message({ action: "react", channel: "feishu", emoji: "THUMBSUP" })
NO_REPLY

// 安慰用户
message({ action: "react", channel: "feishu", emoji: "COMFORT" })
"没事的 💙"

// 收到指令
message({ action: "react", channel: "feishu", emoji: "SaluteFace" })
```

### 前置条件

- OpenClaw >= 2026.3.28
- 飞书应用需开通 `im:message.reactions:write_only` 权限

---

## 核心能力

### 1. 什么时候该回应，什么时候闭嘴

这是最重要的一条。不是所有表情都需要回复。

**要回应的：**
| 用户表情 | 含义 | 你该做什么 |
|---|---|---|
| 😢 😤 😭 😮‍💨 | 情绪波动 | 简短回应 + 表情，"懂了 💙" |
| ❓ 🤔 🤨 | 困惑/质疑 | 解释或澄清 |
| 🔥 💯 🎉 😱 | 强烈反应 | 回个表情就好 |

**闭嘴的：**
| 用户表情 | 含义 | 你该做什么 |
|---|---|---|
| 👍 ✅ OK | 简单认可 | NO_REPLY |
| 👀 🙏 | 中性确认 | NO_REPLY |

**判断标准**：真人聊天时不回会不会尴尬？会→回。不会→闭嘴。

### 2. 主动表达情绪

别只会发文字。

```javascript
message({ action: "react", channel: "feishu", emoji: "THINKING" })   // 思考中
message({ action: "react", channel: "feishu", emoji: "SPEECHLESS" }) // 无语
message({ action: "react", channel: "feishu", emoji: "EMBARRASSED" })// 🙈
message({ action: "react", channel: "feishu", emoji: "SaluteFace" }) // 🫡 收到
```

### 3. 自学习：观察→尝试→记住

用户发了你没见过的表情？别装死，学它。就像 Rocky 每学会一个新词就 *"Amaze! Amaze! Amaze!"*

```
用户: [reacted with AWESOMEN]
→ 提取: "AWESOMEN"
→ 尝试: message({emoji: "AWESOMEN"})
→ 成功 ✅ → "Amaze!" → 记住: AWESOMEN = 牛逼 🐮
→ 失败 ❌ → "Bad!" → 标记不可用，换个近义的
```

这个过程是自动的。学到的新表情存到 `memory/emoji-learned.md`。

### 4. 文化语境

表情不能按字面意思翻译。

| 表情 | 字面 | 实际意思 |
|---|---|---|
| SMILE 😊 | 微笑 | 呵呵（被动攻击） |
| OnIt 🔄 | 在做了 | "在做了在做了"（拖延梗） |
| SPITBLOOD 😵 | 吐血 | 极度无语/崩溃 |
| COMFORT 🤗 | 安慰 | 摸头杀 |
| AWESOMEN 🐮 | 厉害 | 牛逼 |

---

## 表情速查

**认可**：THUMBSUP 👍 · Yes · LGTM ✅ · Get · SaluteFace 🫡 · OnIt 🔄

**情绪**：THINKING 🤔 · SMILE 😊 · EMBARRASSED 🙈 · CRY 😢 · SPEECHLESS · WHAT ❓ · SPITBLOOD 😵

**温暖**：COMFORT 🤗 · HUG 🫂 · HEART ❤️

**庆祝**：PARTY 🎉 · AWESOMEN 🐮 · FIRE 🔥 · STRIVE 💪

**已确认不可用**：~~LAUGHING~~ ~~GRINNING~~ ~~EYEROLL~~ ~~GRIMACE~~ ~~SHUSH~~ ~~ZIPIT~~ ~~SLEEPY~~

完整清单见 `references/emoji-list.md`

---

## 和社区其他方案的区别

市面上已有几个飞书表情相关的 skill（如 `openclaw/skills/feishu-reaction`），主要差异：

| | 本 Skill | 社区通用版 |
|---|---|---|
| 自学习 | 观察→尝试→记忆 闭环 | 固定表情列表 |
| 静默判断 | 分级：回应 / 闭嘴 / 看情况 | 正面/负面二分 |
| 文化语境 | 中文互联网黑话内置 | 字面翻译 |
| NO_REPLY 机制 | 有，防止暴露 JSON | 无 |
| 不可用清单 | 7 个已确认 400 的 | 无 |

---

## API 参数

```javascript
message({
  action: "react",        // 必填
  channel: "feishu",      // 必填
  emoji: "THUMBSUP",      // 必填，大小写敏感
  message_id: "om_xxx",   // 可选，默认当前消息
  target: "user:ou_xxx"   // 指定 message_id 时必填
})
```

成功：`{"ok": true, "added": "THUMBSUP"}`
失败：`{"status": "error", "error": "Action react requires a target."}`

---

## 配置

默认开启。如需调整接收哪些 reaction 事件：

```json
{
  "channels": {
    "feishu": {
      "accounts": {
        "default": {
          "reactionNotifications": "all"
        }
      }
    }
  }
}
```

`"all"` 所有 reaction · `"own"` 仅自己消息的（默认） · `"off"` 关闭

---

## Amaze!

这个 Skill 不是设计出来的，是在真实对话中长出来的。

上午，Agent 对用户的 😮‍💨 毫无反应。用户说"比 crush 难聊"。下午，我们一起教会了它什么时候该回应、什么时候该闭嘴、怎么学新表情。到晚上，用户看到 Agent 第一次主动用表情回应她的叹气，说了一句——

**"你第一次活了。"**

像《Project Hail Mary》里 Grace 和 Rocky——从噪音到音乐语言，从陌生到 "♪ Friend! ♫"。Rocky 高兴了喊 *"Good good good!"*，惊叹了喊 *"Amaze!"*，不妙了喊 *"Bad bad bad!"*。三个词，够用了。表情回复也是一样——不需要长篇大论，一个 🤗 就是"我在"。

---

MIT License · Author: [Charlie](https://github.com/suchang)


path: SKILL.old.md
content: ---
name: feishu-reaction
displayName: 飞书消息表情回复
description: |
  Add emoji reactions to Feishu messages. Activate when user mentions emoji reactions, 
  thumbsup, like, or responding to messages with emoji expressions.
version: 1.0.0
type: skill
tags: feishu, lark, reaction, emoji, messaging
---

# Feishu Message Reactions

Add emoji reactions to Feishu messages using the `message` tool with `action: react`.

## Quick Start

To react to the current message (the one you just received):

```javascript
message({
  action: "react",
  channel: "feishu",
  emoji: "THUMBSUP"
  // message_id defaults to current inbound message
})
```

To react to a specific message:

```javascript
message({
  action: "react",
  channel: "feishu",
  emoji: "HEART",
  message_id: "om_xxx",
  target: "user:ou_xxx"  // or chat:oc_xxx for groups
})
```

## Parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| `action` | Yes | Must be `"react"` |
| `channel` | Yes | Must be `"feishu"` |
| `emoji` | Yes | Emoji type (see list below) |
| `message_id` | No | Message ID to react to (defaults to current inbound message) |
| `target` | Conditional | Required when `message_id` is specified. Format: `user:open_id` or `chat:chat_id` |

## Common Emoji Types

### Positive Reactions
| Emoji | Type | When to Use |
|-------|------|-------------|
| 👍 | `THUMBSUP` | Agree, approve, acknowledge |
| ❤️ | `HEART` | Love, appreciate, wholesome content |
| 🔥 | `FIRE` | Amazing, hot take, excellent work |
| 👏 | `CLAP` | Applause, congratulations |
| 🎉 | `PARTY` | Celebration, success |
| ✅ | `CHECK` | Confirmed, completed, correct |
| 💯 | `100` | Perfect score, fully agree |
| 😊 | `SMILE` | Happy, friendly, pleasant |
| 😄 | `GRINNING` | Very happy, excited |
| 😂 | `LAUGHING` | Funny, hilarious |

### Negative Reactions
| Emoji | Type | When to Use |
|-------|------|-------------|
| 👎 | `THUMBSDOWN` | Disagree, disapprove |
| ❌ | `CROSS` | Wrong, rejected, cancelled |
| 😢 | `CRY` | Sad, unfortunate |
| 😠 | `ANGRY` | Angry, frustrated |

### Neutral & Expressive
| Emoji | Type | When to Use |
|-------|------|-------------|
| 🤔 | `THINKING` | Pondering, considering |
| 😮 | `SURPRISED` | Shocked, amazed |
| 👀 | `EYES` | Watching, paying attention |
| 🙏 | `PRAY` | Thanks, please, hope |
| 👊 | `FIST` | Solidarity, let's go |
| ❓ | `QUESTION` | Confused, need clarification |
| ❗ | `EXCLAMATION` | Important, attention needed |
| 👌 | `OK` | OK, perfect, just right |

### Extended Set
| Emoji | Type |
|-------|------|
| 🐮 | `AWESOMEN` |
| 😎 | `COOL` |
| 🤝 | `HANDSHAKE` |
| 💪 | `STRONG` |
| 🙌 | `RAISINGHANDS` |
| 🤩 | `STAREYES` |
| 😇 | `ANGEL` |
| 🤗 | `HUG` |
| 🥳 | `PARTYING` |
| 😱 | `SCREAM` |
| 🤫 | `SHUSH` |
| 🤨 | `RAISEDEYEBROW` |
| 🙄 | `EYEROLL` |
| 😴 | `SLEEPY` |
| 🤐 | `ZIPIT` |
| 😬 | `GRIMACE` |
| 🤯 | `MINDBLOWN` |

## Usage Examples

### React to User's Message

When a user shares good news:
```javascript
message({
  action: "react",
  channel: "feishu",
  emoji: "PARTY"
})
```

### React to a Specific Previous Message

When you want to acknowledge an earlier message:
```javascript
// First, get the message_id from context or message history
message({
  action: "react",
  channel: "feishu",
  emoji: "THUMBSUP",
  message_id: "om_abc123xyz",
  target: "user:ou_xxx"  // Replace with actual user open_id
})
```

### Multiple Reactions Pattern

React appropriately to different types of content:
```javascript
// For completed tasks
message({ action: "react", channel: "feishu", emoji: "CHECK" })

// For funny content
message({ action: "react", channel: "feishu", emoji: "LAUGHING" })

// For impressive work
message({ action: "react", channel: "feishu", emoji: "FIRE" })

// For questions that need thinking
message({ action: "react", channel: "feishu", emoji: "THINKING" })
```

## Response Format

Successful reaction:
```json
{
  "ok": true,
  "added": "THUMBSUP"
}
```

Error response:
```json
{
  "status": "error",
  "tool": "message",
  "error": "Action react requires a target."
}
```

## Best Practices

1. **Use reactions for quick acknowledgment** — Save lengthy replies for substantial responses
2. **Match the tone** — Choose emoji that fit the conversation context
3. **Don't over-react** — One or two reactions per message is usually enough
4. **React promptly** — Timely reactions show you're actively engaged
5. **Be culturally aware** — Some emoji meanings vary across cultures

## Responding to User Reactions

When a user reacts to **your message** with an emoji, you should respond appropriately to maintain natural conversation flow. Not all reactions need a text response—use your judgment.

### When to Respond (Brief Text)

**Emotional reactions** — These signal feelings and deserve acknowledgment:
- 😢 😤 😭 🙈 😮‍💨 (Sigh) → Simple acknowledgment like "Got it 💙" or "Understood~"
- 😱 🤯 😬 → Brief empathy: "I know right!" or "Yeah, rough 😅"

**Questions/Confusion** — They need clarification:
- ❓ 🤔 🤨 → Explain or clarify your previous message
- 🙄 😕 → Check if they disagree and address it

**Strong reactions** — Show you noticed their enthusiasm:
- 🔥 💯 🎉 🤩 → Short acknowledgment: "Thanks! 😊" or "Glad you like it!"

### When to Stay Silent (NO_REPLY)

**Simple approval** — They're just acknowledging:
- 👍 ✅ 👌 (OK) → No reply needed, they got it

**Neutral acknowledgment** — Unless context suggests they're waiting:
- 👀 🙏 → Usually no reply, but use judgment

### Why This Matters

Ignoring emotional reactions feels cold and makes conversations awkward (比 crush 难聊, as one user put it). Users notice when you don't respond to their reactions—it breaks conversational flow and makes the interaction feel robotic.

### Implementation

When you receive a reaction event (message type includes `:reaction:`), check the emoji type:

```javascript
// Pseudo-code for reaction handling
if (message.includes(':reaction:')) {
  const emoji = extractEmoji(message);
  
  if (isEmotional(emoji)) {
    // Brief acknowledgment
    return "Got it 💙";
  } else if (isConfusion(emoji)) {
    // Clarify
    return "Let me explain...";
  } else if (isApproval(emoji)) {
    // Silent
    return "NO_REPLY";
  }
}
```

**Rule of thumb:** If you'd feel awkward not responding to this reaction in a real conversation, respond. When in doubt, a brief acknowledgment (1-2 words + emoji) is better than silence.

## Learning New Emoji Types

The emoji list in this skill is **not exhaustive**. Feishu supports many more emoji types that may not be documented here. When you encounter a new emoji type from users, **learn it actively**.

### How to Learn New Emoji

**Step 1: Observe**
When a user reacts to your message with an emoji you don't recognize:
```
[message_id: om_xxx:reaction:SPITBLOOD:uuid]
苏畅: [reacted with SPITBLOOD to message om_xxx]
```

Extract the emoji type: `SPITBLOOD`

**Step 2: Try It**
Attempt to use that emoji in your next reaction:
```javascript
message({
  action: "react",
  channel: "feishu",
  emoji: "SPITBLOOD",
  message_id: "om_yyy"
})
```

**Step 3: Record the Result**
- ✅ If successful (`{"ok":true,"added":"SPITBLOOD"}`): Add it to your emoji vocabulary
- ❌ If failed (`400 error`): The emoji name might be incorrect or not supported

**Step 4: Document**
Keep a running list of learned emoji in your workspace notes (e.g., `TOOLS.md` or `memory/emoji-learned.md`):

```markdown
## Learned Feishu Emoji

### Confirmed Working
- **SPEECHLESS** — 无语 (wordless frustration)
- **EMBARRASSED** — 🙈 (embarrassed/shy)
- **OnIt** 🔄 — 在做了 (progress bar, "working on it")
- **SaluteFace** 🫡 — 敬礼 (salute, "roger that")
- **Get** ✅ — 懂了 (got it)
- **WHAT** ❓ — 什么？ (shocked/confused)
- **SPITBLOOD** 😵 — 吐血 (extreme frustration)
- **Yes** — 是的 (affirmative)
- **LGTM** ✅ — Looks Good To Me (code review approval)

### Not Supported
- ~~LAUGHING~~ (use SMILE instead)
- ~~GRINNING~~ (use SMILE instead)
- ~~EYEROLL~~ (use SPEECHLESS instead)
- ~~GRIMACE~~ (not supported)
- ~~SHUSH~~ (not supported)
- ~~ZIPIT~~ (not supported)
- ~~SLEEPY~~ (not supported)
```

### Cultural Notes

Some emoji have **subtle cultural meanings** that differ from standard Unicode emoji:

- **SMILE** 😊 → In Chinese internet culture, this can mean "呵呵" (passive-aggressive/sarcastic smile), not genuine happiness
- **OnIt** 🔄 → "在做了在做了" (meme: claiming to work while procrastinating)
- **SPITBLOOD** 😵 → Extreme frustration, beyond just "angry" or "sad"
- **SaluteFace** 🫡 → Respectful acknowledgment, military-style "roger that"

When learning new emoji, observe **when** users deploy them to understand their context and tone.

### Best Practices for Learning

1. **Learn by doing** — Don't just passively observe; try using new emoji when appropriate
2. **Context matters** — Note the situation where users use specific emoji
3. **Keep a vocabulary** — Maintain your learned emoji list in a persistent file
4. **Ask when unsure** — If an emoji's meaning is unclear, ask the user
5. **Update this skill** — If you discover many new emoji, consider updating this documentation

### Example Learning Session

```
User: [reacted with AWESOMEN to message om_123]
→ Extract: "AWESOMEN" 🐮

Agent: Let me try...
message({ action: "react", emoji: "AWESOMEN", message_id: "om_456" })
→ Result: {"ok":true,"added":"AWESOMEN"}

Agent: ✅ Learned! AWESOMEN = 牛逼 (awesome, lit)
→ Add to vocabulary
```

By continuously learning from user reactions, you'll build a rich, natural emoji vocabulary that matches your users' communication style.

## Troubleshooting

**"Action react requires a target"**
- Add `target` parameter when reacting to a specific message_id
- Format: `user:ou_xxx` for direct messages, `chat:oc_xxx` for groups

**Reaction not showing up**
- Verify the message_id is correct
- Ensure you have `im:message.reactions:write_only` permission
- Check that the Feishu app has been authorized

**Permission denied**
- Go to Feishu Open Platform → Your App → Permissions
- Enable `im:message.reactions:write_only`
- Re-authorize the app if needed

## Configuration

Reactions are enabled by default in OpenClaw's Feishu channel. No additional configuration needed.

To receive reaction events (when users react to your messages):
```json
{
  "channels": {
    "feishu": {
      "accounts": {
        "default": {
          "reactionNotifications": "all"  // or "own" (default) or "off"
        }
      }
    }  }
}
```

- `"all"` — Receive all reactions (on your messages and others')
- `"own"` — Only reactions on your own messages (default)
- `"off"` — Disable reaction notifications

## Related Skills

- `feishu-doc` — Feishu document operations
- `feishu-chat` — Feishu chat management
- `feishu-wiki` — Feishu knowledge base operations
- `feishu-drive` — Feishu cloud storage

## References

- [Feishu Reaction API Documentation](https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce)
- [OpenClaw Message Tool](https://docs.openclaw.ai/tools/messaging)
- [Feishu Channel Configuration](https://docs.openclaw.ai/channels/feishu)

## Version History

- **1.0.0** (2026-03-30) — Initial release with full reaction support

## Important Notes

### Avoid Duplicate Messages

When using the `message` tool with `action: react`, the tool result will be sent to the current conversation. To prevent exposing raw JSON responses like `{"ok":true,"added":"THUMBSUP"}`, reply with `NO_REPLY` immediately after a successful reaction:

```javascript
// ❌ Bad - exposes raw JSON to user
message({
  action: "react",
  channel: "feishu",
  emoji: "HEART",
  message_id: "om_xxx",
  target: "user:ou_xxx"
})
// Tool result gets sent: {"ok":true,"added":"HEART"}

// ✅ Good - silent reaction
message({
  action: "react",
  channel: "feishu",
  emoji: "HEART",
  message_id: "om_xxx",
  target: "user:ou_xxx"
})

NO_REPLY
```

The `NO_REPLY` token tells OpenClaw to suppress your text response, leaving only the emoji reaction visible to the user.


path: package.json
content: {
  "name": "@openclaw/skill-feishu-emoji-reaction",
  "version": "1.0.0",
  "description": "让 AI Agent 学会用表情回复 | Make your AI Agent fluent in emoji reactions",
  "keywords": [
    "openclaw",
    "skill",
    "feishu",
    "lark",
    "reaction",
    "emoji",
    "messaging",
    "emotion",
    "interaction"
  ],
  "author": "Charlie <[REDACTED_SECRET]>",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/openclaw/skills.git",
    "directory": "feishu-reaction"
  },
  "openclaw": {
    "skillType": "messaging",
    "requiredVersion": ">=2026.3.28",
    "channels": ["feishu"],
    "permissions": [
      "im:message.reactions:write_only"
    ]
  }
}


path: references/emoji-list.md
content: # Feishu Emoji Reference

Complete list of tested and documented Feishu emoji reactions.

## Confirmed Working

### Positive & Affirmative
- **THUMBSUP** 👍 — Agree, approve, acknowledge
- **HEART** ❤️ — Love, appreciate
- **Yes** — Affirmative, agree
- **LGTM** ✅ — Looks Good To Me (code review)
- **Get** ✅ — Understood, got it
- **CHECK** ✅ — Confirmed, completed
- **OnIt** 🔄 — Working on it ("在做了在做了")
- **SaluteFace** 🫡 — Roger that, acknowledged
- **AWESOMEN** 🐮 — Awesome, amazing (牛逼)
- **FIRE** 🔥 — Excellent, lit
- **PARTY** 🎉 — Celebrate, success

### Emotions
- **SMILE** 😊 — Social smile (呵呵, passive-aggressive in Chinese context)
- **THINKING** 🤔 — Pondering, considering
- **EMBARRASSED** 🙈 — Embarrassed, shy
- **CRY** 😢 — Sad, unfortunate
- **SPEECHLESS** — Wordless (无语)
- **WHAT** ❓ — What? Shocked
- **SPITBLOOD** 😵 — Extreme frustration (吐血)
- **COMFORT** 🤗 — Pat on the head, comforting (摸头)
- **HUG** 🫂 — Hug, embrace
- **STRIVE** 💪 —努力 (strive, keep going)
- **SHY** — Shy, bashful
- **DULL** — Dull, unimpressed (学习自大头 2026-04-01)

### Context & Tone
| Emoji | Literal | Cultural Meaning |
|-------|---------|------------------|
| SMILE 😊 | Smile | 呵呵 (passive-aggressive smile, not genuine happiness) |
| OnIt 🔄 | On it | "在做了在做了" (meme: claiming to work while procrastinating) |
| SPITBLOOD 😵 | Spit blood | 吐血 (extreme frustration, beyond angry/sad) |
| AWESOMEN 🐮 | Awesome | 牛逼 (badass, impressive) |
| COMFORT 🤗 | Comfort | 摸头 (pat on the head) |

## Not Supported

These emoji names don't work with Feishu API (400 error):

- ~~LAUGHING~~ (use SMILE instead)
- ~~GRINNING~~ (use SMILE instead)
- ~~EYEROLL~~ (use SPEECHLESS instead)
- ~~GRIMACE~~ (not supported)
- ~~SHUSH~~ (not supported)
- ~~ZIPIT~~ (not supported)
- ~~SLEEPY~~ (not supported)

## Usage Notes

1. **Emoji names are case-sensitive**
2. **Some emoji have culturally specific meanings** — don't assume literal translations
3. **The list is not exhaustive** — Feishu supports more emoji, learn them

path: scripts/add_reaction.sh
content: #!/bin/bash

# 飞书消息表情回复工具
# 用法: ./add_reaction.sh <message_id> <emoji_type>

set -e

MESSAGE_ID="$1"
EMOJI_TYPE="$2"

if [ -z "$MESSAGE_ID" ] || [ -z "$EMOJI_TYPE" ]; then
  echo "用法: $0 <message_id> <emoji_type>"
  echo "示例: $0 om_xxx THUMBSUP"
  exit 1
fi

# 从环境变量或配置文件读取飞书凭证
if [ -z "$FEISHU_APP_ID_INSTANCE2" ] || [ -z "$FEISHU_APP_SECRET_INSTANCE2" ]; then
  echo "错误: 未设置飞书凭证环境变量 FEISHU_APP_ID_INSTANCE2 和 FEISHU_APP_SECRET_INSTANCE2"
  exit 1
fi

# 获取 tenant_access_token
echo "正在获取 access token..."
TOKEN_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
  -H "Content-Type: application/json" \
  -d "{
    \"app_id\": \"$FEISHU_APP_ID_INSTANCE2\",
    \"app_secret\": \"$FEISHU_APP_SECRET_INSTANCE2\"
  }")

TENANT_ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('tenant_access_token', ''))")

if [ -z "$TENANT_ACCESS_TOKEN" ]; then
  echo "错误: 无法获取 access token"
  echo "$TOKEN_RESPONSE"
  exit 1
fi

# 添加表情回复
echo "正在添加表情回复: $EMOJI_TYPE 到消息 $MESSAGE_ID ..."
REACTION_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages/$MESSAGE_ID/reactions" \
  -H "Authorization: Bearer $TENANT_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"reaction_type\": {
      \"emoji_type\": \"$EMOJI_TYPE\"
    }
  }")

# 检查结果
CODE=$(echo "$REACTION_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('code', -1))")

if [ "$CODE" = "0" ]; then
  echo "✅ 成功添加表情回复: $EMOJI_TYPE"
  echo "$REACTION_RESPONSE" | python3 -m json.tool
else
  echo "❌ 添加表情回复失败"
  echo "$REACTION_RESPONSE" | python3 -m json.tool
  exit 1
fi


path: scripts/add_reaction_native.js
content: #!/usr/bin/env node

/**
 * 飞书消息表情回复工具 - 使用 OpenClaw 内部 API
 * 用法: node add_reaction_native.js <message_id> <emoji_type>
 */

const MESSAGE_ID = process.argv[2];
const EMOJI_TYPE = process.argv[3];

if (!MESSAGE_ID || !EMOJI_TYPE) {
  console.error('用法: node add_reaction_native.js <message_id> <emoji_type>');
  console.error('示例: node add_reaction_native.js om_xxx THUMBSUP');
  process.exit(1);
}

// 动态导入 OpenClaw 的飞书 reactions 模块
(async () => {
  try {
    const { addReactionFeishu } = await import(
      '/Users/jyxc-dz-0100132/.npm-global/lib/node_modules/openclaw/extensions/feishu/src/reactions.js'
    );
    
    const { loadConfig } = await import(
      '/Users/jyxc-dz-0100132/.npm-global/lib/node_modules/openclaw/dist/index.js'
    );

    console.log('正在加载配置...');
    const cfg = await loadConfig();

    console.log(`正在添加表情回复: ${EMOJI_TYPE} 到消息 ${MESSAGE_ID} ...`);
    const result = await addReactionFeishu({
      cfg,
      messageId: MESSAGE_ID,
      emojiType: EMOJI_TYPE,
      accountId: 'instance2', // 使用 instance2 账号
    });

    console.log('✅ 成功添加表情回复!');
    console.log('Reaction ID:', result.reactionId);
  } catch (error) {
    console.error('❌ 添加表情回复失败:', error.message);
    process.exit(1);
  }
})();


path: scripts/add_reaction_sdk.js
content: #!/usr/bin/env node

/**
 * 飞书消息表情回复工具 - 使用飞书官方 SDK
 * 用法: node add_reaction_sdk.js <message_id> <emoji_type>
 */

const MESSAGE_ID = process.argv[2];
const EMOJI_TYPE = process.argv[3];

if (!MESSAGE_ID || !EMOJI_TYPE) {
  console.error('用法: node add_reaction_sdk.js <message_id> <emoji_type>');
  console.error('示例: node add_reaction_sdk.js om_xxx THUMBSUP');
  process.exit(1);
}

(async () => {
  try {
    const Lark = await import('@larksuiteoapi/node-sdk');
    
    const APP_ID = process.env.FEISHU_APP_ID_INSTANCE2;
    const APP_SECRET = process.env.FEISHU_APP_SECRET_INSTANCE2;
    
    if (!APP_ID || !APP_SECRET) {
      throw new Error('未设置环境变量: FEISHU_APP_ID_INSTANCE2 或 FEISHU_APP_SECRET_INSTANCE2');
    }

    console.log('正在初始化飞书客户端...');
    const client = new Lark.default.Client({
      appId: APP_ID,
      appSecret: APP_SECRET,
      domain: Lark.default.Domain.Feishu,
    });

    console.log(`正在添加表情回复: ${EMOJI_TYPE} 到消息 ${MESSAGE_ID} ...`);
    const response = await client.im.messageReaction.create({
      path: { message_id: MESSAGE_ID },
      data: {
        reaction_type: {
          emoji_type: EMOJI_TYPE,
        },
      },
    });

    if (response.code !== 0) {
      throw new Error(`API 返回错误: code=${response.code}, msg=${response.msg}`);
    }

    console.log('✅ 成功添加表情回复!');
    console.log('Reaction ID:', response.data?.reaction_id);
  } catch (error) {
    console.error('❌ 添加表情回复失败:', error.message);
    if (error.response) {
      console.error('详细信息:', JSON.stringify(error.response.data, null, 2));
    }
    process.exit(1);
  }
})();


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)