给 cc-connect 补上 Discord 图片到 Codex 的链路
记录我把 cc-connect 的 Discord 图片消息真正转给 Codex 的过程:定位缺口、改造参数传递、处理临时图片清理,以及替换线上二进制。
- gebimaster
- 5 分钟
前面把 `cc-connect` 接到 `Discord + Codex` 之后,文本消息已经能顺畅工作,但还有一个明显缺口:我在 Discord 里发图片,`cc-connect` 能收到,`Codex` 却看不到。
这个问题看起来像是“Codex 不支持图片”,但真正翻源码以后,结论其实更简单:`cc-connect` 的 `Discord` 侧已经把图片附件下载下来了,`Codex CLI` 也已经支持 `--image`,只是中间这一跳还没接起来。
所以这次我做的,不是重写一套多模态能力,而是把已经存在的两端真正接上。
先确认问题卡在哪一层
当时我先把链路拆成了三段来看:
• `Discord` 有没有把图片附件传进来
• `cc-connect` 有没有把图片留在消息结构里
• `Codex CLI` 有没有图片入口
结果很清楚:
• `platform/discord/discord.go` 已经会把图片附件下载到内存,并塞进 `core.ImageAttachment`
• `agent/codex/session.go` 里却直接把图片忽略掉了
• 本机 `codex exec --help` 和 `codex exec resume --help` 已经都能看到 `--image <FILE>` 参数
也就是说,这不是平台能力不够,而是适配层还没补完。
改造思路其实不复杂
我最后保留的思路只有三步:
1. 收到 Discord 图片后,先写入临时目录 2. 调用 `codex exec` 或 `codex exec resume` 时,追加 `--image <path>` 3. 这轮请求结束后,把临时图片删掉
这里最关键的不是“怎么存图片”,而是“什么时候删图片”。
如果删得太早,`Codex` 可能还没来得及读取;如果完全不删,服务器跑久了临时目录迟早会堆脏。
所以我最后把清理时机放在:
• 进程启动失败时,立刻清理
• 子进程正常退出后,再统一清理
• 每一轮消息单独使用一个临时目录,避免多轮会话互相影响
这套策略很朴素,但对这种桥接层最稳。
我实际改了什么
核心改动都在 `agent/codex/session.go`:
• 新增 `saveImages()`,把 `core.ImageAttachment` 批量写入临时目录
• 按文件名扩展名或 `MimeType` 推断图片后缀
• 在 `args` 里逐个追加 `--image <path>`
• 把清理逻辑挂到 `cmd.Start()` 失败和 `cmd.Wait()` 返回两个阶段
我额外做了两个细节处理:
• 图片目录不是直接扔到固定路径,而是用每轮独立的临时目录,避免残留和串轮
• 文件权限用了更保守的方式,尽量只让当前用户可读
这类改动的价值不在“代码多漂亮”,而在于后面维护时不容易出脏状态。
临时图片清理为什么要单独认真做
这次我最在意的其实不是“能看图了”,而是“图片不要留在机器上”。
因为这台服务器后面要长期跑 `cc-connect`,如果图片只是能传、不能稳定清,问题只会延后爆出来:
• `/tmp` 会越来越脏
• 敏感截图可能长时间残留
• 出故障时很难判断哪些文件还在被用
所以我最后把清理目标定得很明确:
• 一轮请求结束,就删掉这轮图片
• 启动失败,也删
• 不依赖人工巡检 `/tmp`
实际检查时,生成过的 `cc-connect-codex-images-*` 临时目录在这一轮结束后已经能自动消失,这样我才觉得这条链路算真正闭合了。
我怎么验证这次改动
这次我没有把验证建立在“肉眼看 Discord 有没有回复”上,而是分成了两层:
1. 先做本地单元测试
我补了一个假的 `codex` 可执行文件,用来验证两件事:
• `cc-connect` 调 `codex` 时,确实带上了 `--image`
• 假 `codex` 进程退出后,临时图片确实被清掉了
这样做的好处是,清理时机这种细节可以先在本地定死,不用每次都去 Discord 里来回试。
2. 再做实际冒烟测试
我又单独跑了一次 `codex exec --image`,确认本机的 `Codex CLI` 本身就能识别图片。
最后再把补丁版 `cc-connect` 替换进线上进程,重启 `tmux` 里的常驻服务,用实际图片做了一次对话级测试,链路才算真正打通。
部署方式我还是保持最简单的路线
我没有改 npm 包结构,而是直接:
1git clone https://github.com/chenhg5/cc-connect.git2cd cc-connect3make build
编译完成后,把二进制替换掉当前 npm 安装目录里的 `bin/cc-connect`,再重启我原来常驻的 `tmux` 会话。
这套方式的优点是非常直接:
• 不需要重新设计运行方式
• 不影响原来的 `config.toml`
• 出问题时也能快速回滚到备份二进制
对于这种“只补一个本地能力”的场景,我更喜欢这种低摩擦替换,而不是把整个安装链路重做一遍。
这次改完以后,链路终于顺了
补上这个能力之后,我这套 `Discord + cc-connect + Codex` 的使用边界就清楚多了:
• 文本消息继续走原来的会话
• Discord 图片现在也能真正进到 Codex
• 每轮图片会自动清掉,不需要我手动善后
对我来说,这种改动很典型:它不会让界面上多出什么新按钮,但会让一条本来“差一点就能用”的链路,变成真正能放进日常工作流里的东西。
如果后面还要继续补,我最想做的下一步不是加更多平台,而是把这种桥接层里的“最后一跳”继续补齐。因为真正影响体验的,往往不是大功能,而是这些本来只差一点点的小断点。
讨论区
这里保留已经通过审核的公开评论。补充经验、纠错或提出不同判断都可以。
发表评论
提交后会先进入后台审核,通过后才会显示在文章下方;短时间内频繁提交会被限制。