Conversation
飞书把图片以 "[图片: img_xxx]" 的形式塞在 content 文本里。入站处理用
content.match() 取 key——没有 g 标志,只返回第一个匹配——随后把**整个
content 覆盖**成那一张的路径:
const imageKeyMatch = content.match(/\[(?:Image|图片):\s*(img_[^\]]+)\]/);
if (imageKeyMatch && messageId) {
const imageKey = imageKeyMatch[1];
const filePath = await downloadFeishuMedia(messageId, "image", imageKey);
content = filePath ? `[图片] ${filePath}` : `[图片: ${imageKey}]`;
}
于是一条「文字 + 6 张图」的富文本到达 agent 时只剩 "[图片] <第一张路径>",
文字和其余 5 张静默消失。用户侧的表现是「一次发六张图,对面只收到第一张」,
而且没有任何错误或日志——后 5 张根本没被下载过。
改动:
- 抽出 resolveImagePlaceholders(content, download):用 matchAll 遍历全部占位符,
逐个**就地**替换成 "[图片] <路径>",占位符以外的文字原样保留
- 单张下载失败只保留该张的原占位符,不牵连同条消息里其它图片
- download 以参数注入,函数无 IO 依赖,可直接测试
- handleMessage 改用它;检测用不带 g 的常量正则,遍历时另建带 g 的副本,
避免共享 lastIndex 导致漏匹配
测试 hub-server/feishu-media-placeholders.test.ts(6 个):
- 单张占位符替换为路径
- 多张全部替换,且下载按序对每个 key 各调一次
- 图文混排时占位符以外的文字原样保留
- 兼容英文 [Image: ...] 形式
- 某张下载失败时保留该张占位符,其余照常替换
- 不含占位符的纯文字原样返回,且一次下载都不发起
验证:
- (cd hub-server && bun test) → 356 pass / 0 fail
- bun hub-test-harness/harness.ts → 8/8
- bunx tsc --noEmit:改动前后均只有既有的 channels/feishu.ts 缺
@larksuiteoapi/node-sdk 一条,未新增
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017pGyNVmhbA1Z1vRoxLZbFe
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.
动机
飞书把图片以
[图片: img_xxx]的形式塞在content文本里。入站处理只取第一个 key,然后把整个 content 覆盖成那一张的路径:两层问题叠在一起:
content.match()没有g标志,只返回第一个匹配于是一条「文字 + 6 张图」的富文本消息到达 agent 时,只剩下
[图片] <第一张的路径>——文字和其余 5 张图静默消失。复现:在飞书里发一条包含文字和多张图片的消息(一条富文本,不是分开发的多条)。实际结果:agent 只收到第一张图的路径,文字和后续图片全部丢失。预期结果:文字保留,每张图都替换成本地路径。补充一点,后 5 张根本没有被下载过——媒体目录里只落盘一个文件。所以这不是"下载了但没透出",是解析阶段就丢了。整个过程没有任何错误或告警。
改动概要
抽出一个纯函数:
matchAll遍历全部占位符,逐个就地替换成[图片] <路径>,占位符以外的文字原样保留download以参数注入,函数本身无 IO 依赖,可直接测试g的常量正则,遍历时另建带g的副本——共享带g的正则会因lastIndex残留而漏匹配hub-server/feishu-media-placeholders.test.ts,6 个用例:[Image: ...]形式最后一条是防回归:如果哪天改成无条件调用下载,它会失败。
影响范围
hub-server/channels/feishu-lark-cli.ts的入站图片分支和一个新测试文件;文件、语音分支与出站路径不变,其他通道不涉及。ChannelPlugin/InboundMessage等公共契约。self-test 结果
bunx tsc --noEmit在改动前后各跑一次做对照,两次都只有既有的一条channels/feishu.ts缺@larksuiteoapi/node-sdk,本 PR 未新增类型错误。grep -rE '@im\.wechat|ou_[a-f0-9]{16,}|sk-ant-…|sk-…|[0-9]{9,10}:[A-Za-z0-9_-]{35}'对本 PR 改动文件 → 无命中。