跳到正文
技术博客 / 长期维护

给 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 包结构,而是直接:

Bash
1git clone https://github.com/chenhg5/cc-connect.git
2cd cc-connect
3make build

编译完成后,把二进制替换掉当前 npm 安装目录里的 `bin/cc-connect`,再重启我原来常驻的 `tmux` 会话。

这套方式的优点是非常直接:

• 不需要重新设计运行方式

• 不影响原来的 `config.toml`

• 出问题时也能快速回滚到备份二进制

对于这种“只补一个本地能力”的场景,我更喜欢这种低摩擦替换,而不是把整个安装链路重做一遍。

这次改完以后,链路终于顺了

补上这个能力之后,我这套 `Discord + cc-connect + Codex` 的使用边界就清楚多了:

• 文本消息继续走原来的会话

• Discord 图片现在也能真正进到 Codex

• 每轮图片会自动清掉,不需要我手动善后

对我来说,这种改动很典型:它不会让界面上多出什么新按钮,但会让一条本来“差一点就能用”的链路,变成真正能放进日常工作流里的东西。

如果后面还要继续补,我最想做的下一步不是加更多平台,而是把这种桥接层里的“最后一跳”继续补齐。因为真正影响体验的,往往不是大功能,而是这些本来只差一点点的小断点。

公开评论

讨论区

0

这里保留已经通过审核的公开评论。补充经验、纠错或提出不同判断都可以。

还没有公开展示的评论。如果你有补充经验或不同看法,欢迎留下第一条。

参与讨论

发表评论

提交后会先进入后台审核,通过后才会显示在文章下方;短时间内频繁提交会被限制。

会公开显示在评论里。
提交后会先进入审核,再公开展示。最多 500 字
通常会在审核后显示在这里。