Mai × Tobatsu · WS Mailbox · Test evidence

不用 Redis,前端照样收到完成提醒

这页只讲一件事:Tobatsu 回调成功后,Mai 已经能写画布、写 session_messages,再用一个轻量 mailbox 把同一条结果推给在线 WS。 如果 WS 断了,事实数据也不会丢。

0Redis Pub/Sub 代码残留
5sbackend 只查在线 session
1真实 test 任务已跑通
0prod 改动
What changed

现在这条提醒怎么走

业务事实还是 DB 和 canvas。WS 只是在线提醒,不再承担保存结果的责任。

01

Tobatsu callback

workflow 完成后发 mai.delivery_result

02

Gateway 落库

写 result、artifact、session_messages

03

Canvas 写入

同一回调把可展示文件插入 canvas。

04

Mailbox 暂存

KV 里按 session_id 放一条 WS payload。

05

Backend 拉取

每个 worker 只查自己握着的在线 session。

06

WS 推给前端

payload 和 session_messages.message_data 对齐。

Why mailbox

为什么不是 Redis Pub/Sub

uvicorn 多进程下,WS 连接在哪个 worker 手里是不固定的。

Redis 只能喊一声

听到的人不一定握着目标 session 的 WS。多进程一起听,又容易重复推。

DB 扫描太重

需要 cursor、状态、补账规则。为了一个在线提醒,不值得把状态做重。

Mailbox 刚好够用

只存 Tobatsu 结果提醒。backend 有在线 session 才拉,拉到就推,拉不到也不影响事实数据。

Frontend shape

前端看到的格式

WS 外壳多了 type/session_id/message_id。里面的 data 就是 session message 的结果数据。

{
  "type": "tobatsu_result",
  "session_id": "session_e7a43964-04b9-4880-8f20-781f29ef8b45",
  "message_id": "tobatsu_result_93fbf209...",
  "sequence_num": 285518,
  "created_at": "2026-05-28T13:24:18.033Z",
  "data": {
    "event_kind": "tobatsu_result",
    "gateway_task_id": "gw_9cac14bb-2e71-4830-be2d-fe3e4d7033bc",
    "gateway_run_id": "gwr_a13853b0-0ac6-408e-9c88-7992a8109b05",
    "gateway_result_id": "2cec163a-4079-44ce-ae51-1070c0b8e7fe",
    "task_type": "video_edit",
    "status": "succeeded",
    "file_ids": ["3q5sM2.mp4"],
    "canvas_id": "187d8a3f-dc73-423e-9950-7b9fe6632aa6"
  }
}
Real test run

真实跑过的 test 例子

这条是最终通过的复验。不是查询结果拼出来的,是在线 WS 文件里抓到的事件。

项目说明
Canvas 打开 test canvas 画布里插入了 3q5sM2.mp4
Agent 对话 session_e7a43964-04b9-4880-8f20-781f29ef8b45 同一个 session 发起任务、收 WS、下一轮读 SystemReminder。
Mai 任务 gw_9cac14bb-2e71-4830-be2d-fe3e4d7033bc 这是产品侧 task id。Tobatsu id 只做 debug。
Tobatsu 任务 1ba5077b-f73b-4e34-b9eb-53aa074076b7 下游确认 generic_ffmpeg_rendi v6,Rendi primary,fallback=false。
输出文件 3q5sM2.mp4 CDN HEAD: 200, video/mp4, 495972 bytes。
WS 证据 /tmp/mai-ws-mailbox-test2-ws-events.jsonl line 13 收到 type=tobatsu_result,message_id 和 DB 一样。
SystemReminder /tmp/mai-ws-mailbox-test2-followup-wait.json 下一轮 tool_summary.count=0,agent 直接说任务完成。
What broke once

中间为什么没推出来

不是 Tobatsu 失败,也不是 canvas 失败。是我把 backend 的 consume URL 配到了不适合 internal 访问的 test 域名。

错误配置

tobatsu-gateway-test.fpai.io/internal/... 对 consume 路径返回 503 Service Unavailable。Gateway 里已经 queued,但 Python backend 拉不到。

修复配置

test backend 改用 tobatsu-gateway-test.adtech-videogen.workers.dev/internal/...。同 payload 返回 200,复验已通过。

commits on origin/test
077093d  Remove Tobatsu result Redis WS notifier
7b6cda2  Add Tobatsu result mailbox WS notifier
f215902  Fix test Tobatsu mailbox consume URL
52009f9  Document WS mailbox test evidence
Acceptance

现在算过的点

这几个点对应你一开始要的用户体验:不主动查,完成就提醒,下一轮 agent 能知道。

前端体验一致

在线时收到 WS。刷新后仍从历史消息和 canvas 读事实数据。

不会重复插画布

get_task 不返回 batch result。画布只由 callback-time Canvas Service 写。

agent 能继续

下一轮从 SystemReminder 看到结果,无需自动 poll。