附件句柄要跨 Agent 传递
多 Agent 系统里,用户上传的图片、PDF、语音不是普通 message part,而是一种“可重新取回资源”的能力句柄;一旦路由到子 Agent、Durable Object、队列 worker 或后台任务时只序列化了文件名、大小、URL 这些展示字段,真正能下载原文件的身份就可能丢失。
Cloudflare @cloudflare/think@0.12.1 刚修了一个很具体的例子:conversation resolver 把线程转给 sub-agent Durable Object 前,会调用 serializableMessengerEvent()。旧逻辑为了跨边界可序列化,只保留 attachment 的 id/mediaType/name/size/text/url,丢掉 fetch/raw/data。这本身合理,因为闭包和原始对象不能安全跨进程;问题是 Telegram 这类 adapter 的文件标识只存在 fetchMetadata.fileId,顶层 id 并不一定有值。结果是照片进了子 Agent 后,看起来还有 attachment,但既没有 attachment.fetch,也没有可用的 attachment.id,下游无法重新下载。
这个修复没有把二进制塞进事件,也没有强行保留不可克隆的 fetch 闭包,而是新增一个可序列化的 fetchMetadata?: Record<string,string>,让它穿过 messenger event 序列化;同时从 id/fileId/mediaId/fileUniqueId 这类已知 metadata key 里 best-effort 回填顶层 id。下游 Agent 再用 adapter 的 rehydrateAttachment() 把这个元数据还原成可下载能力。
对 OPC 类平台很有启发:如果入口 Agent 收到“帮我看这张故障截图/合同/发票”,然后把任务分给视觉 Agent、文档 Agent 或合规 Agent,attachment 的运行时模型不能只是 {url, name, mime},也不能偷懒把整文件 base64 塞进上下文。更稳的抽象应该是 AttachmentRef:包含 provider、platform file id、media type、size/hash、tenant/actor scope、过期策略、rehydrate 方法和审计字段;跨 Agent 传递的是这个能力引用,真正下载发生在有权限的执行边界。
常见误区是把“能在当前 handler 里读到文件”误认为“系统里所有后续步骤都能读到文件”。一旦进入子 Agent、重试、恢复、异步队列或跨机器执行,闭包、临时 URL、内存 buffer 都会失效。今天如果你设计一个 Agent router,会把 attachment 当作聊天记录的一部分,还是当作一张需要显式授权、可恢复、可审计的资源票据?