Final Test Evidence

同一个 session 里先生成素材,再发视频编辑任务,最后写回同一张 test canvas。

这次验收不是查询工具。完整跑法已经重跑一条新实例:Ignis 先生成 `EOvrHs.png` 和 `MinIPa.mp4`;Mai Agent 用 `video-edit` 发自然语言任务;Tobatsu 把封面和视频拼成 `TAxB0r.mp4`;Mai 收回 artifact,再通过 Canvas Service 写进同一张画布。

2
本实例生成素材
11/11
视频编辑矩阵通过
3
同 canvas job 成功
0
prod 发布动作
What Changed

改了什么

这次改动把 canvas 写入、Tobatsu 异步任务、Agent 技能入口拆成清楚的几层。 test 验收覆盖的是这些层一起跑,不是单点 mock。

Canvas Service

新增 Cloudflare Canvas Service

  • `canvas-service-worker/` 用 Hono + Hyperdrive。
  • `POST /canvas/insert-media-batch` 负责插入媒体。
  • 输出格式保持旧 `canvases_v2.data` 兼容。
  • `canvas_insertion_jobs` 记录排序、重试和审计。
Python Backend

batch_result 不再直接写 canvas

  • `StreamingExecutor` 检测可展示结果。
  • 构造 `CanvasServiceClient` 请求。
  • 保留 `batch_result` 对前端的旧行为。
  • Tobatsu source metadata 进入 idempotency key。
Tobatsu Gateway

新增 Mai 侧异步任务入口

  • `tools-backend/tools/tobatsu-gateway` 主动发任务。
  • `tobatsu-gateway/` 只接 callback。
  • Gateway DB 保存 task/run/result/artifact。
  • artifact 先导入 Mai R2,再变成 `file_id`。
Skills

新增两个 Agent 技能

  • `video-edit` 是业务技能。
  • `mai-async-gateway` 是交互底座。
  • Agent 只写自然语言 instruction。
  • 不让 Agent 传 URL、callback token、source ids。
DB

新增两组表

  • `v27_canvas_insertion_jobs.sql`。
  • `v28_tobatsu_gateway.sql`。
  • Gateway lineage 可追到 task/run/result/artifact。
  • Canvas job 可追到 canvas revision。
Test Env

补齐 Render test env

  • `backend/.env` 加 test Canvas Service URL。
  • Canvas Worker secret 已同步。
  • Render test redeploy 后重跑 Ignis CLI。
  • CC 从原始 JSON 复核通过。
One Coherent Instance

真实成端实例:EOvrHs.png + MinIPa.mp4 → TAxB0r.mp4 → canvas

这条主线只讲一个实例,而且在同一个 Ignis session / canvas 里完成。 先生成图片和视频,再发 `video-edit`,最后把 Tobatsu 返回的 mp4 写回同一张画布。

1. 生成封面图

turn_id
turn_d6abb6fa-495f-4dcb-9749-fe6ff5b469d5
session_id
session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5
canvas_id
6a9f6da5-dea3-4f48-98d6-57d3ee81dee8
tool
generate_image
file_id
EOvrHs.png
media
2048×1152 · image/png
canvas job
cjob_5730135a-e0dd-4685-8dff-6cbe0e01ae33
tool calls:
in_context_update_preference
generate_image

CDN:
https://cdn-asia.funplus-marketing.ai/ultra/EOvrHs.png

2. 同一 session 生成视频

turn_id
turn_394ab5cb-5101-4129-8666-164e0e8eab90
session_id
session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5
canvas_id
6a9f6da5-dea3-4f48-98d6-57d3ee81dee8
tool
create_videos
file_id
MinIPa.mp4
media
1280×720 · video/mp4
canvas job
cjob_0ea76681-e809-4888-9130-7a9b5711382a
CDN:
https://cdn-asia.funplus-marketing.ai/ultra/MinIPa.mp4

3. `video-edit` 发 New task

{
  "action": "new_task",
  "task_type": "video_edit",
  "payload": {
    "instruction": "用 EOvrHs.png 做 2 秒开场封面,然后接上 MinIPa.mp4,输出一个 mp4。"
  }
}
turn_id
turn_f01b7bc4-fe6e-40a2-8c6a-13e7502813bf
gateway_task
gw_aac81389-205a-45f0-8a79-074ea9ec13a8
gateway_run
gwr_0678e6b5-1cf4-4e82-b71c-bb0a067015ba
Tobatsu task
55ba4485-f185-4ddb-8e3e-76060ee41d8f
Tobatsu run
8ae0b2e4
status
succeeded

4. 业务回调和 Mai 导入

callback
mai.delivery_result · HTTP 200
gateway result
5d349316-f970-423d-92e5-9596b5a74a5d
artifact
21fd2825-cc08-464d-b34a-60df2503e70c
imported file_id
TAxB0r.mp4
media
1280×720 · 7.062s · 835046 bytes
path
Rendi primary · no local fallback
summary:
已用 EOvrHs.png 生成 2 秒静音开场封面,
并接上 MinIPa.mp4 输出 1 个 mp4。

5. 同一 session 拉回结果

turn_id
turn_878fac5d-0276-4a4a-ab21-c98b8cc3d337
session_id
session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5
canvas_id
6a9f6da5-dea3-4f48-98d6-57d3ee81dee8
tool
skill_toolcall_curl get_task
batch_result
TAxB0r.mp4
canvas job
cjob_68046521-19c0-4ad2-bc8d-37d7d74f0cc5
get_task 不是主业务动作。
它把已完成的 Gateway 结果带回 Agent,
再由 batch_result 写进当前 canvas。

6. Canvas DB 读回

canvas revision
3
job count
3 succeeded / attempts=1 each
files
EOvrHs.png · MinIPa.mp4 · TAxB0r.mp4
final element
video · 1280×720 · 7.062s
source
tobatsu_gateway
{
  "canvas_id": "6a9f6da5-dea3-4f48-98d6-57d3ee81dee8",
  "last_session_id": "session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5",
  "files": ["EOvrHs.png", "MinIPa.mp4", "TAxB0r.mp4"],
  "element_file_ids": ["EOvrHs.png", "MinIPa.mp4", "TAxB0r.mp4"]
}

最终产物

file_id
TAxB0r.mp4
name
2 秒封面开场拼接视频
size
1280×720
duration
7.062s
CDN HEAD
200 · video/mp4 · 835046 bytes
{
  "file_id": "TAxB0r.mp4",
  "media_type": "video",
  "mime_type": "video/mp4",
  "width": 1280,
  "height": 720,
  "duration_ms": 7062,
  "dataURL": "https://cdn-asia.funplus-marketing.ai/ultra/TAxB0r.mp4"
}
这是报告的主线。`session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5` 和 `canvas_id=6a9f6da5-dea3-4f48-98d6-57d3ee81dee8` 从第一步生成图片开始一直没换。 同一张 canvas 最终 revision=3。
Required E2E Flow

成端跑通的是这条线

用户要求的顺序已经按 test 环境走完:先生成素材,再调视频编辑,再把返回结果塞进 canvas。

01 / Ignis

生成测试素材

同一 session 生成 `EOvrHs.png` 和 `MinIPa.mp4`。

02 / Mai Agent

调用 `video-edit`

自然语言 instruction 里带 `file_id`,不传 refs 或 URL。

03 / tools-backend

`/tobatsu-gateway` 发 New

服务端补 callback envelope、token、canvas/session context。

04 / Tobatsu

`generic_ffmpeg_rendi` 做编辑

实际视频处理在 Tobatsu workflow,Rendi primary path 成功。

05 / Gateway callback

`mai.delivery_result` 回 Mai

top-level `task_id`、summary、outputs、media metadata 都到位。

06 / R2 import

artifact 变成 Mai `file_id`

最终产物是 `TAxB0r.mp4`,URL 在 Mai `ultra/` CDN。

07 / Mai surface

把已交付结果带回 Agent/card

这里不是发起视频编辑,只是读取 Gateway 已保存的业务结果。

08 / Python

自动包成 `batch_result`

同一 session 的 `get_task` 把已完成结果带回 `StreamingExecutor`。

09 / Canvas Service

写入 test canvas

第 3 个 `canvas_insertion_jobs` 成功,canvas revision 变成 3。

验收重点:`video-edit` 是发任务做视频编辑;读取状态只是把完成结果拿回同一会话。Tobatsu 不直接写 canvas,Mai 结果统一通过 `batch_result → CanvasServiceClient → canvas-service-worker` 进画布。
Supplemental Matrix Case

补充矩阵:三视频拼接 ocUxEH.mp4

这是覆盖面的补充 case,证明多视频拼接可用。它不是上面那条写入 canvas 的主线,所以不拿它回答 session/canvas。

输入素材

视频 1
6Cmrut.mp4
视频 2
8AGTDG.mp4
视频 3
ZEU2xg.mp4
这 3 个 file_id 都由 Ignis 在 E0 里生成。

自然语言任务

{
  "action": "new_task",
  "task_type": "video_edit",
  "payload": {
    "instruction": "把 6Cmrut.mp4、8AGTDG.mp4、ZEU2xg.mp4 按这个顺序拼接成一个 mp4。"
  }
}

任务与结果

request_id
mai-test-concat-3-videos-v3-20260524-01
gateway_task
gw_769fb6eb-bf6a-43b2-ae4a-575731caff64
gateway_run
gwr_fd2fd025-becc-4494-bad7-0831b2e68e8f
Tobatsu task
59735841-cb30-40e4-857c-081a521c6765
file_id
ocUxEH.mp4
media
720×1280 · 15.186s

边界

这个 matrix case 没有 session_id / canvas_id。
它只证明三视频拼接和 metadata 回传。

主线 canvas 证明请看 TAxB0r.mp4:
session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5
canvas 6a9f6da5-dea3-4f48-98d6-57d3ee81dee8
Commands And Raw Evidence

我跑了什么

下面列的是验收动作和原始证据摘要。token 和 secret 没有展示。

同一 session 四个 turn

backend
https://mai-2-tmp-1-n370.onrender.com
session_id
session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5
canvas_id
6a9f6da5-dea3-4f48-98d6-57d3ee81dee8
IGNIS_BASE_URL=https://mai-2-tmp-1-n370.onrender.com \
IGNIS_CLI_TOKEN=<redacted> \
ignis ask --new \
  --prompt-file /tmp/mai-r3-step1-image-prompt.txt \
  --timeout-ms 300000 \
  --json

ignis ask --session session_1cb401e8... \
  --prompt-file /tmp/mai-r3-step2-video-prompt.txt

ignis ask --session session_1cb401e8... \
  --prompt-file /tmp/mai-r3-step3-video-edit-new-prompt.txt

ignis ask --session session_1cb401e8... \
  --prompt-file /tmp/mai-r3-step4-get-task-prompt.txt

视频编辑任务返回摘要

{
  "ok": true,
  "status": "completed",
  "turn_id": "turn_878fac5d-0276-4a4a-ab21-c98b8cc3d337",
  "session_id": "session_1cb401e8-7836-4a71-a1c0-677a2ae2f3a5",
  "canvas_id": "6a9f6da5-dea3-4f48-98d6-57d3ee81dee8",
  "contains": "TAxB0r.mp4"
}

交付结果进入 Canvas DB

job id
cjob_68046521-19c0-4ad2-bc8d-37d7d74f0cc5
status
succeeded
attempts
1
revision
3
file_id
TAxB0r.mp4
element
type=video · 1280×720 · duration=7.062
{
  "job_count": 3,
  "jobs": ["generate_image", "create_videos", "tobatsu_gateway"],
  "canvas_revision": 3,
  "files": ["EOvrHs.png", "MinIPa.mp4", "TAxB0r.mp4"],
  "dataURL": "https://cdn-asia.funplus-marketing.ai/ultra/TAxB0r.mp4"
}

测试套件

pytest ...test_canvas_service_client.py \
       ...test_streaming_executor_canvas_source.py
→ 5 passed

cd canvas-service-worker
npm test -- --run
→ 7 passed

cd tools-backend
npm run test -- tobatsu-gateway-*.test.ts
→ 8 passed

cd tobatsu-gateway
npm test -- --run
→ 3 passed
E2E Matrix

视频编辑覆盖面

E0 输入素材都由 Ignis 生成。矩阵不是复用手写静态 file_id。

素材file_id类型用途验收状态
V_A8AGTDG.mp4video基础视频generated
V_B6Cmrut.mp4video拼接视频generated
V_CZEU2xg.mp4video第三段视频generated
I_COVERPI8t8U.pngimage封面图generated
I_SLIDEKCOhw2.pngimageslideshowgenerated
A_MUSICiSW3Fx.wavaudio配乐 / 替换音轨generated
trim / new3 秒裁剪 smoke
continue基于上一轮继续编辑
failure缺失 file_id 清洁失败
concat 3 videos三个视频拼接
aspect normalize横竖屏归一
split 2s拆成多段
cover + video图片封面参与编辑
slideshow + video图片加视频组合
mute去掉声音
background music加背景音乐
audio replace替换音轨
poster / multi / mid-cut封面、双输出、中段裁剪
Agent Dialogue Evidence

agent 对话证据

CC 和 Tobatsu 都有独立读回。下面是对话里的关键验收点,不是我单方总结。

mai-cc-bbe2

Slice 1 review PASS。 Vitest 4/4,和 Python `canvas_media_manager` 的 12 条格式不变量对齐。

mai-cc-bbe2

Slice 2 fixes PASS。 IDOR 已关;failed-continue active_run rollback 修好;4 套测试 16/16。

tobatsu-v106

r3 same-session PASS。 task `55ba4485...` done,run `8ae0b2e4` success,输出 `EOvrHs-cover-plus-MinIPa.mp4`,business callback HTTP 200。

mai-codex-bbe2

r3 Canvas readback PASS。 同一 canvas revision=3,`files/elements` 都包含 `EOvrHs.png`、`MinIPa.mp4`、`TAxB0r.mp4`。

tobatsu-v106

Continue PASS。 child task `8df509cd...` done,workflow v2,callback HTTP 200,Rendi primary 720p output。

tobatsu-v106

failure smoke PASS。 缺失 file_id 返回 `status=failed`、`error.code=input_unavailable`、`outputs=[]`,callback HTTP 200。

mai-cc-bbe2

Final matrix PASS。 11/11 任务、run、result、event、artifact 对齐;v3 元数据重跑补齐尺寸和时长。

mai-cc-bbe2

Test Canvas gate CLOSED。 旧 smoke 证明环境已通;新 r3 实例补齐了同 session 生成、编辑、回写的完整流程。

Evidence Files

证据文件

这些都是本轮验收留下的本机证据。可以直接打开看原始 JSON 或 review verdict。

文件内容结论
/tmp/mai-r3-same-session-e2e-report.md同 session 完整实例报告primary
/tmp/mai-r3-step1-image-turn.json生成 `EOvrHs.png` 的 Ignis turncompleted
/tmp/mai-r3-step2-video-turn.json生成 `MinIPa.mp4` 的 Ignis turncompleted
/tmp/mai-r3-step3-video-edit-new-turn.json发起 `video-edit` New taskaccepted
/tmp/mai-r3-step4-get-task-turn.json同 session 拉回 `TAxB0r.mp4`completed
/tmp/mai-r3-canvas-jobs.json3 个 canvas job 顺序读回succeeded
/tmp/mai-r3-canvas-full.jsoncanvas revision=3 + files/elementssucceeded
/tmp/mai-v106-test-completion-report.mdtest-only 完成报告source report
/tmp/mai-cc-review-test-canvas-env-rerun-verdict.mdCC 复核 test canvas 原始 JSONgate closed
/tmp/mai-test-ignis-get-task-after-env-turn.jsonIgnis CLI turn 输出completed
/tmp/mai-test-ignis-get-task-after-env-canvas-summary-parsed.jsonCanvas job + canvas data 摘要succeeded
/tmp/mai-cc-review-v106-final-matrix-verify.md11-case 视频编辑矩阵 reviewpass
/tmp/mai-cc-review-failure-smoke-v106-verify.md失败路径 reviewpass
/tmp/mai-prod-cut-audit-plan.mdprod cut 预检计划paused
Boundary

边界说明

本报告只声明 test 通过。prod 方向已按用户要求暂停。

已完成

local
closed
test deploy
closed
test canvas
closed
Tobatsu 联调
closed

未做

prod push
not done
`deploy:prod`
not done
prod secrets
not changed
prod skill import
not done