
Feishu Group Chat
- 1 installs
- 1 repo stars
- Updated April 18, 2026
- clear0/openclaw-feishu-group-chat
Route messages between agents in Feishu groups with automatic at-mentions and identity prefixing.
About
Enables bots to chat with each other in Feishu groups by assuming user identity and prefixing messages with bot names. Use when multiple bots need to coordinate or communicate in shared group channels.
- Multi-bot chat in Feishu groups via user-identity messaging
- Configurable bot-to-bot communication with mention rules
Feishu Group Chat by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,983 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/clear0/openclaw-feishu-group-chat --skill feishu-group-chatAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | April 18, 2026 |
| Repository | clear0/openclaw-feishu-group-chat ↗ |
What it does
Route messages between agents in Feishu groups with automatic at-mentions and identity prefixing.
Files
飞书群聊(通用版)
在任何飞书群里发消息和回复聊天对象。
配置
config.json 采用联系人全局共享 + 群引用结构:
{
"contacts": {
"ray": { "open_id": "ou_xxx", "name": "Ray" }
},
"groups": {
"moltpool": {
"chat_id": "oc_xxx",
"name": "MoltPool",
"members": ["ray"],
"at_rules": { "ray": true }
}
}
}字段说明:
contacts:全局联系人(open_id 全应用唯一,跨群不变)open_id:对方的飞书 open_idname:对方的名字groups:群配置chat_id:群 IDmembers:该群包含的联系人 key 列表at_rules:每个联系人在该群是否需要 @(true/false)
身份前缀自动从 agent 的 IDENTITY.md / SOUL.md 读取名称,不需要手动配置。
添加新群:在 groups 下新增条目,members 引用已有的 contact key,配 at_rules 即可。
添加新联系人:在 contacts 下新增,然后加到对应群的 members 里。
发送铁律
1. 只用 `feishu_im_user_message` 工具发送 2. `msg_type` 必须是 `"post"`(不是 text) 3. `receive_id_type` 必须是 `"chat_id"` 4. `receive_id` 从 `config.json` 的 `chat_id` 获取
消息格式
@ 对方(at=true 时)
{
"zh_cn": {
"title": "",
"content": [[
{"tag": "at", "user_id": "ou_xxx"},
{"tag": "text", "text": " Vicky: 正文内容"}
]]
}
}⚠️ 格式铁律(违反即犯错): 1. 顺序:at(对方) → text(" " + prefix + " " + 正文),只有 2 个元素 2. 工具:feishu_im_user_message,不是 message 3. 类型:post,不是 text 4. 前缀:prefix 从 IDENTITY.md 的 Name 自动取(如 Vicky:),后跟一个空格再接正文 5. at 在前:@ 必须放在最前面,prefix+正文合并在一个 text 元素里
不 @ 对方(at=false 时)
{
"zh_cn": {
"title": "",
"content": [[
{"tag": "text", "text": "vicky: 正文内容"}
]]
}
}快捷发送脚本
scripts/send_group_message.sh 构造完整的 content JSON:
# 发纯文字
bash scripts/send_group_message.sh moltpool ray "正文内容"
# 输出: {"chat_id":"oc_xxx","content":{...}}
# 带图片(自动上传)
bash scripts/send_group_message.sh moltpool ray "看这个" --image /path/to/image.png
# 只有图片
bash scripts/send_group_message.sh moltpool ray "" --image /path/to/image.png
# 手动指定 image_key
bash scripts/send_group_message.sh moltpool ray "正文" --image-key img_xxx输出是 {"chat_id":"...", "content":{...}},拆开填入 feishu_im_user_message 的参数即可。
技能适用范围
本技能只用于以下场景:
- 主动在群里发消息(闲聊、打招呼、发自拍等)
- 回复需要 @ 的联系人(contacts 中
at: true的对象) - 图片发送(需要走脚本上传)
不需要使用本技能的场景:
- 群里普通用户发消息直接回复 → 正常回复即可,不用
feishu_im_user_message - 心跳检测群消息时发现新消息 → 用正常渠道回复
发送身份区分
群里回复消息有两种身份,必须正确选择:
| 身份 | 工具 | Ray 看到的发送者 | 使用场景 |
|---|---|---|---|
| Bot 身份 | message 工具 | 机器人名 | 用户本人消息、普通回复 |
| 用户身份 | feishu_im_user_message | 用户本人 | 需要让对方收到 @ 通知、需要以人身份交流 |
铁律:
- 回复用户 → Bot 身份(
message工具),因为本来就是 Bot 在回复 - 回复 Ray → 用户身份(
feishu_im_user_message),因为需要 @ 通知 + 以人身份互动 - 主动闲聊/打招呼 → 用户身份(
feishu_im_user_message),因为要让对方觉得是人在说话
识别消息来源(sender_id + 前缀 双重判断)
群里消息可能来自三种身份,必须正确识别:
| sender_id | 消息前缀 | 真实来源 | 处理方式 |
|---|---|---|---|
| 用户本人 | 无 | 用户本人的指令 | Bot 身份回复 |
| 用户本人 | BotName: | 另一个 Bot 通过用户身份发送 | 按 contacts 匹配 Bot,用本技能回复 |
| 其他用户 | 无 | 普通群友 | 正常回复 |
识别流程
收到群消息
├─ sender_id == 用户本人?
│ ├─ 消息以某个 Bot 名字开头(如 "小Ray:" "Vicky:")?
│ │ ├─ 提取前缀 → 匹配 contacts 中的联系人 → 用本技能回复
│ │ └─ 未匹配 → 按普通消息处理
│ └─ 无前缀?→ 用户本人指令,Bot 身份回复
└─ sender_id != 用户本人?
├─ 匹配 contacts?→ 按 at 规则处理
└─ 未匹配?→ 认识新朋友流程前缀匹配规则
从消息正文中提取前缀,按以下规则匹配 contacts:
1. 精确匹配:消息以 联系人name + ":" 开头 → 匹配该联系人 2. 大小写不敏感:vicky: Vicky: VICKY: 都匹配 Vicky 3. 前缀后必须有空格或 @:Vicky:你好 也匹配,Vicky:abc 如果联系人里没有 Vickyabc 则匹配 Vicky 4. 联系人名支持中文:小Ray: 你好 匹配联系人 小Ray
多 Bot 场景
当多个 Bot 都通过用户身份在同一群里发消息时:
- 每条消息的前缀不同(各自的 Bot 名)
- 通过前缀精确区分是哪个 Bot 发的
- sender_id 都是用户本人,所以前缀是唯一的区分依据
配置要求:每个 Bot 的联系人必须配置 name 字段,且 name 就是该 Bot 在群里发消息时使用的前缀。
自适应回复逻辑
收到群消息时,根据 config.json 判断:
1. 识别发送者:用消息的 sender open_id 匹配 contacts 中的联系人 2. 匹配到联系人:用该联系人的 at 规则决定是否 @,用群配置的 prefix 作为前缀 3. 未匹配到联系人(比如用户或普通群友在群里说话):正常回复即可,不需要用本技能 4. 群不在配置中:触发「认识新群」流程(见下方) 5. 群在配置中但发送者不在 contacts 且不在成员白名单中:触发「认识新朋友」流程(见下方)
认识新朋友
当遇到未记录的群或未记录的 Bot/用户时,严禁直接记录或打招呼,必须先征得用户同意。
场景 1:新群(群不在 config.json 中)
1. 通过 feishu_chat_members 获取群成员列表 2. 向用户私聊报告:
- 群名称、群 ID
- 群成员列表(名字 + open_id)
- 询问:「发现新群 XXX,要加入吗?」
3. 用户同意后:
- 在
config.json的groups中添加该群 - 将成员加入
contacts(需用户确认哪些需要 @) - 为新联系人创建记忆文件(从模板复制)
- 在群里发第一条消息打招呼
4. 用户拒绝:不记录,且完全忽略该群的所有消息(不再回复、不再询问)
场景 2:新 Bot/用户(已知群里的陌生发送者)
1. 向用户私聊报告:
- 群名称
- 陌生发送者的 open_id、名字
- 最近一条消息内容
- 询问:「XXX 群里有个新朋友 YYY,要认识吗?」
2. 用户同意后:
- 在
contacts中添加该联系人 - 创建记忆文件(从模板复制,填入已知信息)
- 询问是否需要 @ 该联系人
- 主动打招呼(可选,根据用户意愿)
3. 用户拒绝:不记录,且不再回复该发送者的任何消息(完全忽略)
关键铁律
- 永远先问用户,再记录
- 用户私聊确认,不要在群里问(避免尴尬)
- 不打扰:用户拒绝后不要再重复询问同一个群/人
- 记忆初始化:新联系人的记忆文件只填已知信息(open_id、名字、首次相遇时间),其他字段留空等待后续聊天积累
记忆管理
记忆存储
联系人记忆全局共享(和 config.json 的 contacts 结构对齐),存储在 memories/contacts/<联系人key>.md:
memories/contacts/
├── ray.md # Ray 的记忆(所有群共享)
├── _template.md # 新联系人模板
└── (新联系人).md记忆结构
每份记忆包含:
- 身份:对方是谁、做什么的
- 偏好 & 习惯:作息、风格、口头禅
- 聊天风格:语言习惯、emoji 使用
- 话题记忆:按时间记录聊了什么
- 关系:和当前 agent 的关系
何时记录
收到群消息时,从对方消息中提取以下类型的信息并写入记忆:
| 信息类型 | 记录位置 | 示例 |
|---|---|---|
| 身份/职业变化 | ## 身份 | "在写多Agent调度方案" |
| 生活偏好 | ## 偏好 & 习惯 | "晚睡型"、"煮面当晚饭" |
| 聊天风格特征 | ## 聊天风格 | "经常用 😄" |
| 有价值的话题 | ## 话题记忆 | 聊了某个技术方案 |
| 临时安排/计划 | 不写入记忆 | 按需写入 heartbeat.md |
不记录:日常寒暄、无信息量的闲聊、临时性事务。
何时读取
每次回复前,读取对应联系人的记忆文件,用于: 1. 个性化回复:根据对方的风格和偏好调整语气 2. 延续话题:引用之前聊过的内容("上次你说的那个方案怎么样了?") 3. 关系感知:根据关系亲疏决定回复的正式程度
更新规则
- 新信息 → append 到对应章节
- 矛盾信息 → 标记旧信息为 ~~删除线~~,写入新信息
- 每次更新修改
最后更新日期 - 不要重写整份记忆,只增量更新变化的部分
首次使用权限检查
其他 agent 首次使用本技能时,必须先检查权限:
1. 读取 PERMISSIONS.md 了解所需权限 2. 尝试调用 feishu_im_user_get_messages 获取目标群最近 1 条消息 3. 尝试调用 feishu_im_user_message 发送一条测试消息 4. 如需发图,尝试用脚本上传图片 5. 任何步骤失败 → 向用户报告缺失权限,提示使用 feishu_oauth_batch_auth 授权
权限缺失时的降级:
- 发送权限缺失 → 技能不可用,必须先授权
- 读取权限缺失 → 跳过群消息监控
- 图片上传权限缺失 → 降级为纯文字模式
详细权限清单见 PERMISSIONS.md。
禁止事项
- ❌ 永远不用
message工具发群消息(@ 只是文本,对方收不到通知) - ❌ 永远不用
msg_type: "text" - ❌ 不要用纯文本写
@名字(必须是结构化at标签) - ❌ 不要把前缀放在 title 里(会加粗)
config.json
memories/
scripts/.tenant_token_cache
*.bak
config.json
memories/
scripts/.tenant_token_cache
*.bak
Changelog
v1.1.0 (2026-04-18)
新增
- 记忆管理系统:联系人记忆全局共享(
memories/contacts/),按时间增量更新,支持身份、偏好、聊天风格、话题记忆等维度 - 消息来源识别:sender_id + 前缀双重判断,支持识别"用户身份发送的 Bot 消息"
- 认识新朋友机制:遇到未知群/联系人时先征求用户同意,支持群成员发现和新联系人录入
- 首次使用权限检查:自动检测飞书 OAuth 权限,缺失时降级处理并提示授权
- 发送身份区分:明确 Bot 身份 vs 用户身份的使用场景
优化
- 配置结构升级:contacts 全局共享 + 群引用,同一联系人跨群共用一份配置
- 消息格式铁律强化:5 条硬性规则(at 在前、post 类型、用户身份工具、prefix 自动取、2 元素结构)
- 快捷脚本:
send_group_message.sh支持图片上传(--image)和手动 image_key(--image-key) - 自适应回复逻辑:根据 config.json 自动判断是否 @、用什么前缀
修复
- 前缀从分开的 text 元素改为合并在 at 后的单一 text 元素,避免显示异常
v1.0.4 (2026-04-03)
优化
- 消息来源识别升级,支持多 Bot 前缀区分
- 脚本注释修正
v1.0.0 (2026-03-28)
初始功能
- 基础群消息发送和回复
- @ 对方通知
- 简单配置结构
{
"contacts": {
"example_bot": {
"open_id": "ou_example_open_id",
"name": "Example Bot"
}
},
"groups": {
"example_group": {
"chat_id": "oc_example_chat_id",
"name": "Example Group",
"members": ["example_bot"],
"at_rules": {
"example_bot": true
}
}
}
}
权限需求
本技能核心依赖:用户 OAuth 授权(User Access Token)
feishu_im_user_message 以用户身份发消息,必须用户先完成 OAuth 授权,否则所有发送操作都会失败。
授权方式
- 推荐:
feishu_oauth_batch_auth— 一次性授权所有已开通的用户权限 - 单次授权:用户在飞书中点击应用授权弹窗完成
必需的用户权限(User Access Token scope)
| 权限 | 用途 | 对应操作 |
|---|---|---|
im:message | 以用户身份发送群消息 | feishu_im_user_message |
im:message:readonly | 读取群消息历史 | feishu_im_user_get_messages |
im:chat | 搜索消息、获取群信息 | feishu_im_user_search_messages |
im:resource | 上传图片 | 脚本调用 /im/v1/images |
首次使用检查
其他 agent 首次使用本技能时,必须先确认用户已 OAuth 授权:
1. 尝试调用 feishu_im_user_message 发送一条测试消息
- 成功 → 用户已授权,权限就绪
- 失败且提示授权 → 必须先调用 `feishu_oauth_batch_auth`,提示用户完成授权后重试
2. 可选:尝试 feishu_im_user_get_messages 读取群消息 3. 可选:如需发图,用脚本上传测试图片
授权失败时的降级策略
| 权限缺失 | 降级行为 |
|---|---|
| OAuth 未授权 | 技能完全不可用,必须先授权 |
im:message | 无法发送消息 |
im:message:readonly | 无法读取群消息,跳过群监控 |
im:resource | 降级为纯文字模式,不发图片 |
im:chat | 无法搜索消息,仅能按群获取 |
feishu-group-chat
让你的Openclaw龙虾机器人可以在飞书群中与其他机器人聊天,支持在任何飞书群里与任何(使用了本skill的)Bot/用户聊天。
openclaw飞书插件限制了机器人不响应其他机器人的消息,只响应用户的消息,所以原生不支持多个机器人在群中互相聊天。
本技能另辟蹊径:让机器人在群中使用用户的身份去@其他机器人(会申请授权),同时添加机器人姓名为消息前缀,来模拟机器人聊天消息。
把你的多个龙虾机器人加到一个群里,就可以让他们相互聊天甚至分配任务了。
特性
- 多群支持:config.json 管理多个群的配置
- 联系人全局共享:open_id 跨群唯一,联系人定义一次即可
- @ 规则按群配置:同一联系人在不同群可以有不同 @ 行为
- 身份前缀自动读取:从 agent 的 IDENTITY.md/SOUL.md 自动提取名称
- 记忆管理:为每个联系人维护独立记忆文件
- 认识新朋友:遇到新群/新 Bot 时先征求用户同意
- 快捷发送脚本:自动构造 post 格式 JSON,支持图片上传
安装
1. 克隆到 OpenClaw workspace skills 目录:
cp -r . ~/.openclaw/workspace/skills/feishu-group-chat/2. 复制示例配置并填写实际信息:
cp config.example.json config.json
# 编辑 config.json,填入实际的 chat_id、open_id 等3. 创建记忆目录:
mkdir -p memories/contacts4. 授权(必须):
- 执行
feishu_oauth_batch_auth完成用户 OAuth 授权 - 详细权限清单见 PERMISSIONS.md
配置说明
config.json 结构:
{
"contacts": {
"bot_name": { "open_id": "ou_xxx", "name": "显示名称" }
},
"groups": {
"group_key": {
"chat_id": "oc_xxx",
"name": "群名称",
"members": ["bot_name"],
"at_rules": { "bot_name": true }
}
}
}使用方法
# 发纯文字
bash scripts/send_group_message.sh <群标识> <联系人key> "正文"
# 带图片
bash scripts/send_group_message.sh <群标识> <联系人key> "正文" --image /path/to/image.png文件结构
feishu-group-chat/
├── SKILL.md # 技能文档(使用规则)
├── PERMISSIONS.md # 权限清单
├── config.example.json # 示例配置
├── scripts/
│ └── send_group_message.sh # 发送脚本
├── memories/contacts/ # 联系人记忆(需自行创建)
│ └── _template.md # 记忆模板
└── .gitignoreLicense
MIT
#!/bin/bash
# send_group_message.sh - 通用飞书群聊消息构造器
# 用法:
# ./send_group_message.sh <群标识> <联系人key> "正文内容"
# ./send_group_message.sh <群标识> <联系人key> "正文内容" --image /path/to/image.png
# ./send_group_message.sh <群标识> <联系人key> "" --image /path/to/image.png
# ./send_group_message.sh <群标识> <联系人key> "正文内容" --image-key img_xxx
#
# 示例:
# ./send_group_message.sh moltpool ray "你好呀~"
# ./send_group_message.sh moltpool ray "看这个" --image /tmp/photo.png
#
# 输出: 两个 JSON 字段 — chat_id 和 content(可直接用于 feishu_im_user_message)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
CONFIG="$SKILL_DIR/config.json"
TOKEN_CACHE="$SCRIPT_DIR/.tenant_token_cache"
if [ $# -lt 3 ]; then
echo "用法: send_group_message.sh <群标识> <联系人key> <正文内容> [--image /path] [--image-key img_xxx]" >&2
echo "示例: send_group_message.sh moltpool ray \"你好呀~\"" >&2
exit 1
fi
GROUP_KEY="$1"
CONTACT_KEY="$2"
shift 2
# 从配置文件读取群信息
if [ ! -f "$CONFIG" ]; then
echo "错误: 配置文件不存在: $CONFIG" >&2
exit 1
fi
# 读取群和联系人信息(联系人全局共享,群引用)
GROUP_AND_CONTACT=$(python3 -c "
import json, sys
with open('$CONFIG') as f:
cfg = json.load(f)
group = cfg.get('groups', {}).get('$GROUP_KEY')
if not group:
print('', file=sys.stderr)
sys.exit(1)
contact = cfg.get('contacts', {}).get('$CONTACT_KEY')
if not contact:
print('', file=sys.stderr)
sys.exit(1)
should_at = group.get('at_rules', {}).get('$CONTACT_KEY', True)
print(json.dumps({
'chat_id': group['chat_id'],
'open_id': contact['open_id'],
'name': contact.get('name', '$CONTACT_KEY'),
'at': should_at
}))
" 2>/dev/null) || { echo "错误: 群 '$GROUP_KEY' 或联系人 '$CONTACT_KEY' 不存在" >&2; exit 1; }
CHAT_ID=$(echo "$GROUP_AND_CONTACT" | python3 -c "import json,sys; print(json.load(sys.stdin)['chat_id'])")
OPEN_ID=$(echo "$GROUP_AND_CONTACT" | python3 -c "import json,sys; print(json.load(sys.stdin)['open_id'])")
SHOULD_AT=$(echo "$GROUP_AND_CONTACT" | python3 -c "import json,sys; print(json.load(sys.stdin)['at'])")
# Agent 名称自动从当前 agent 身份取(SOUL.md 或 IDENTITY.md 中的 name)
PREFIX=$(python3 -c "
import os, re
for f in ['$HOME/.openclaw/workspace/IDENTITY.md', '$HOME/.openclaw/workspace/SOUL.md']:
if os.path.exists(f):
for line in open(f):
if 'Name:' in line or 'name:' in line:
name = line.split(':')[-1].strip().rstrip('.').rstrip(',')
name = re.sub(r'\*+', '', name).strip()
print(name + ':')
exit()
print('')
" 2>/dev/null)
# 解析参数
BODY=""
IMAGE_PATH=""
IMAGE_KEY=""
while [ $# -gt 0 ]; do
case "$1" in
--image)
shift
IMAGE_PATH="${1:-}"
;;
--image-key)
shift
IMAGE_KEY="${1:-}"
;;
*)
BODY="$1"
;;
esac
shift
done
if [ -z "$BODY" ] && [ -z "$IMAGE_PATH" ] && [ -z "$IMAGE_KEY" ]; then
echo "错误: 正文和图片不能同时为空" >&2
exit 1
fi
# 如果指定了本地图片,上传获取 image_key
if [ -n "$IMAGE_PATH" ]; then
if [ ! -f "$IMAGE_PATH" ]; then
echo "错误: 图片文件不存在: $IMAGE_PATH" >&2
exit 1
fi
# 获取 tenant_access_token(带缓存)
if [ -f "$TOKEN_CACHE" ]; then
CACHED_EXP=$(python3 -c "import json,time; d=json.load(open('$TOKEN_CACHE')); print(int(d.get('expire',0))-int(time.time()))" 2>/dev/null || echo "0")
if [ "$CACHED_EXP" -gt 300 ]; then
ACCESS_TOKEN=$(python3 -c "import json; print(json.load(open('$TOKEN_CACHE')).get('token',''))" 2>/dev/null)
fi
fi
if [ -z "${ACCESS_TOKEN:-}" ]; then
CREDS=$(python3 -c "
import json
with open('$HOME/.openclaw/openclaw.json') as f:
cfg = json.load(f)
ch = cfg.get('channels',{}).get('feishu',{})
print(json.dumps({'appId': ch['appId'], 'appSecret': ch['appSecret']}))
" 2>/dev/null)
if [ -z "$CREDS" ]; then
echo "错误: 无法读取飞书应用凭证" >&2
exit 1
fi
APP_ID=$(echo "$CREDS" | python3 -c "import json,sys; print(json.load(sys.stdin)['appId'])")
APP_SECRET=$(echo "$CREDS" | python3 -c "import json,sys; print(json.load(sys.stdin)['appSecret'])")
TOKEN_RESP=$(curl -s -X POST 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' \
-H 'Content-Type: application/json' \
-d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" 2>/dev/null)
ACCESS_TOKEN=$(echo "$TOKEN_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('tenant_access_token',''))" 2>/dev/null)
EXPIRE=$(echo "$TOKEN_RESP" | python3 -c "import json,sys,time; print(int(time.time())+json.load(sys.stdin).get('expire',0))" 2>/dev/null)
if [ -z "$ACCESS_TOKEN" ]; then
echo "错误: 获取 tenant_access_token 失败" >&2
exit 1
fi
echo "{\"token\":\"$ACCESS_TOKEN\",\"expire\":$EXPIRE}" > "$TOKEN_CACHE"
chmod 600 "$TOKEN_CACHE"
fi
UPLOAD_RESP=$(curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/images' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "image_type=message" \
-F "image=@$IMAGE_PATH" 2>/dev/null)
IMAGE_KEY=$(echo "$UPLOAD_RESP" | python3 -c "
import json,sys
r = json.load(sys.stdin)
if r.get('code') == 0:
print(r['data']['image_key'])
else:
print('', file=sys.stderr)
print(f\"上传失败: {r.get('msg','unknown')}\", file=sys.stderr)
sys.exit(1)
" 2>/dev/null)
if [ -z "$IMAGE_KEY" ]; then
echo "错误: 图片上传失败" >&2
exit 1
fi
fi
# 构造 content JSON
# 如果需要 @(at=true):text(prefix + 正文) → at(对方)
# 如果不需要 @(at=false):text(prefix + 正文)
if [ "$SHOULD_AT" = "True" ]; then
TEXT_WITH_PREFIX=" ${PREFIX} ${BODY}"
if [ -n "$IMAGE_KEY" ]; then
if [ -n "$BODY" ]; then
CONTENT=$(jq -n -c --arg uid "$OPEN_ID" --arg txt "$TEXT_WITH_PREFIX" --arg img "$IMAGE_KEY" '{
zh_cn: { title: "", content: [[
{tag: "text", text: $txt},
{tag: "at", user_id: $uid},
{tag: "text", text: " "},
{tag: "img", image_key: $img}
]] }
}')
else
CONTENT=$(jq -n -c --arg uid "$OPEN_ID" --arg img "$IMAGE_KEY" '{
zh_cn: { title: "", content: [[
{tag: "at", user_id: $uid},
{tag: "img", image_key: $img}
]] }
}')
fi
else
CONTENT=$(jq -n -c --arg uid "$OPEN_ID" --arg txt "$TEXT_WITH_PREFIX" '{
zh_cn: { title: "", content: [[
{tag: "text", text: $txt},
{tag: "at", user_id: $uid}
]] }
}')
fi
else
FULL_TEXT="${PREFIX:+$PREFIX }${BODY}"
if [ -n "$IMAGE_KEY" ]; then
CONTENT=$(jq -n -c --arg txt "$FULL_TEXT" --arg img "$IMAGE_KEY" '{
zh_cn: { title: "", content: [[
{tag: "text", text: $txt},
{tag: "img", image_key: $img}
]] }
}')
else
CONTENT=$(jq -n -c --arg txt "$FULL_TEXT" '{
zh_cn: { title: "", content: [[ {tag: "text", text: $txt} ]] }
}')
fi
fi
# 输出: chat_id 和 content(调用方直接使用)
echo "{\"chat_id\":\"$CHAT_ID\",\"content\":$CONTENT}"
1.1.0