Voyager 业务线学习:Agent 图片任务的源资产解析、可恢复执行与终态错误契约
这条业务线解决的是 Agent 在聊天中处理图片时的“输入资产不是普通 workspace asset”问题,同时把一次图片任务变成可恢复、可去重、可正确反馈的运行时流程
source_automation: voyager-merged-pr run_date: 2026-08-03 anchor_pr_number: 5507 pr_number: 5507 pr_title: “Handle missing source assets in image tasks gracefully” pr_url: https://github.com/adastralab-ai/voyager/pull/5507 ↗ author: “Jason Tan / banchichen” merged_at: “2026-08-03T03:20:58Z” modules:
- backend/workers/agent/src/goApi.ts
- backend/workers/agent/src/goApi.test.ts
- backend/workers/agent/src/tools/imageTaskTool.ts
- backend/workers/agent/src/tools/imageTaskTool.test.ts files_changed: 4 changed_files:
- backend/workers/agent/src/goApi.test.ts
- backend/workers/agent/src/goApi.ts
- backend/workers/agent/src/tools/imageTaskTool.test.ts
- backend/workers/agent/src/tools/imageTaskTool.ts learning_tags:
- agent-runtime
- image-task
- source-asset-lifecycle
- attachment-promotion
- terminal-result
- no-retry
- idempotency
- billing-safety
- api-error-contract
- image-delivery
- test-strategy business_line: “Agent 图片任务的源资产解析、可恢复执行与终态错误契约” related_prs: [4318, 4516, 5422, 5461, 5506] related_prior_prs: [4516] line_stage: “请求内容哈希重挂接 (#4318) -> 终态失败由 throw 改为结构化 result (#4516) -> 图片结果统一 delivery seam (#5422) -> refs/source op 统一分类 (#5461) -> remove_background 补 attachment promotion (#5506) -> 缺失 source asset 在提交门禁处可纠正终止 (#5507)” open_questions:
- “toSubmitResult 是多个 image endpoint 共用的 notFound 映射;当前依赖坏 reference 会被 Go 包装成 500 的实现细节,未来若 reference 直接返回 code 102,可能被误标成 source_asset_not_found。”
- “未知 referenceAssetId 当前仍可能走 wrapped APIError -> 500 并记录 server fault;需把 reference lookup 前置到 Go submit 之前,并避免 debit + refund 循环。”
- “source asset 在任务已 submitted 后被删除或权限变化时,当前主要靠 wait 的 terminal error 或 resolve failure 处理;需要验证 delivery slot、pending record 和用户提示的组合。”
- “#5506 的 attachment promoter 在 uploadAsset 成功与 attachmentAssetStore.set 之间缺少跨重启的原子性证明;重复同一上传是否可能铸造多个 workspace asset 仍待运行时验证。”
- “#5507 单测覆盖 Go 404 映射与 shared gate,但没有 workerd/Go deployed contract、真实 Agent tool -> 404/503、或 reference 404 的集成覆盖。”
- “promoteAttachment 只支持 PNG/JPEG/WebP;用户上传 SVG/GIF/AVIF 或附件丢失时,模型提示与产品 UI 是否都能稳定给出可操作降级仍待验证。” feishu_doc_url: null github_repository: joyehuang/ai-agent-field-notes github_path: outputs/voyager-daily-pr-study/2026-08-03-pr-5507-agent-image-source-asset-recovery.md voyager_merge_commit: 5d8c482006df6b21535c76653f516115946e3446 voyager_origin_main_snapshot: 26c7c2c4b81511e3bced4da1c3b0438fb41150d9
业务线概览#
这条业务线解决的是 Agent 在聊天中处理图片时的“输入资产不是普通 workspace asset”问题,同时把一次图片任务变成可恢复、可去重、可正确反馈的运行时流程。
用户看到的是一个图片工具调用,但代码里至少存在三个不同的 ID 域:
- 聊天上传附件的 ID,模型通过 /mnt/attachments/ 路径看到;
- workspace asset ID,Go 图片 API 的 assetId 以 UUID 形式消费;
- 图片任务 ID,提交后用于轮询、解析结果并交给统一的 delivery seam。
如果把第 1 种 ID 直接送给第 2 种接口,Go API 返回 404/code 102。此前这类异常会以裸异常逃出 tool execute,AI SDK 可能把它视为可重试的 tool error;模型既拿不到“这个 ID 不存在”的可纠正信息,也可能重复调用甚至触发额外的扣费/退款路径。
本次锚点 #5507 没有扩大到新的图片能力,而是补上提交阶段的最后一个错误边界:把“source asset 不存在”从服务故障改成结构化终态结果,在任务尚未创建之前结束本次调用,并向模型提供如何修正 ID 的明确提示。它依赖 #5506 刚完成的附件提升,也继承 #4318、#4516、#5422、#5461 建立的任务恢复、结果契约、输出交付和统一工具形状。
今日锚点#
| 项目 | 内容 |
|---|---|
| PR | #5507 ↗ |
| 标题 | Handle missing source assets in image tasks gracefully |
| 作者 | Jason Tan / banchichen |
| 合并时间 | 2026-08-03 13:20:58(Australia/Melbourne,UTC 03:20:58) |
| Voyager merge commit | 5d8c482006df6b21535c76653f516115946e3446 |
| 改动文件 | 4 个:Go API 结果映射、Go API 测试、图片任务执行器及其测试 |
| 选择理由 | 它是当天 Melbourne 窗口内尚未学习的业务线 PR,并且直接承接前一天 #5506 的 attachment promotion;改动同时触及 API 错误契约、任务生命周期和模型纠正提示,能自然串起至少 5 个有实质关系的 PR。 |
PR body 给出的验证结果是 pnpm vitest run --project agent-worker 通过 19 个文件、163 个测试。本报告把它作为 PR 提供的验证证据,不把它冒充为本次运行重新执行的结果;本次运行只读检查了已合入 origin/main 的真实代码和 diff。
演进时间线:输入域、任务生命周期和输出交付逐层收敛#
| 阶段 | PR 与合并时间 | 代码证据 | 改变的层 |
|---|---|---|---|
| 前置基础 | #4318 ↗,2026-07-04 | backend/workers/agent/src/tools/imageTaskTool.ts 引入基于 task type + payload 的 SHA-256 key;PendingTaskStore 按 key 保存、读取和删除 task ID。 | 从 tool call 标识切换到业务请求内容标识,使 Agent 重试能重新挂接 orphaned task,避免重复提交和重复扣费。该 PR 距锚点已超过默认 30 天,但它是当前“submit 前不写 pending、submit 后才能复用”的直接底层前提。 |
| 结果契约 | #4516 ↗,2026-07-08 | runResumableImageTask 对 terminal failure 删除 pending 后返回 { status: "failed" },不再抛出 ImageTaskFailedError;tool schema 增加 credits/resolution/no_image/error reason。 | 把用户/模型可处理的失败从异常通道移到结构化业务结果,阻断 AI SDK 将最终失败误当成 retryable tool error。 |
| 输出交付 | #5422 ↗,2026-07-30 | backend/workers/agent/src/imageDelivery.ts 的 withImageDelivery 统一 hold slot、运行任务、成功后放置结果、失败时 fail slot。 | 生成、编辑、去背景共享结果落位和模型可见输出的单一路径,避免各工具分别放置导致重复放置或状态不一致。 |
| 工具形状 | #5461 ↗,2026-07-31 | imageMode.ts 用一次 image_generation 调用的 prompt/refs/size 形状决定 generate、edit 或 upscale;resolveImageRefs 和 runSourceOp 统一 source operation。 | 用户入口和运行时分派收敛;同一套 attachment/reference 解析、幂等 key 和 delivery seam 可以覆盖多个图片操作,但 remove_background 仍保留独立的 API 语义。 |
| 输入修复 | #5506 ↗,2026-08-02 | removeBackgroundTool.ts 在计算幂等 key、建立 canvas slot 前调用共享 promoteAttachment;工具 schema 明确接受 workspace asset ID 或 /mnt/attachments/<id>。 | 把聊天附件先提升为 workspace asset,修复 raw attachment ID 直接进入 Go remove-background API 的 404。 |
| 今日锚点 | #5507 ↗,2026-08-03 | goApi.ts:727-733 把未找到 source asset 的 code 102 映射为 source_asset_not_found;imageTaskTool.ts:179-186 返回可纠正的 failed result,并明确不要原样重发 ID。 | 在“提交任务”这个 runtime boundary 上完成错误分类:没有任务就没有 pending record、wait 或 resolve,也不会把模型输入错误包装成服务故障。 |
当前架构与数据流#
flowchart LR
U["Chat upload"] --> R["Agent attachment R2 + attachmentsById"]
R --> P["<submitted> /mnt/attachments/<id>"]
P --> T["image tool call"]
T --> D["decideImageRequest / remove_background"]
D --> N["shared promoteAttachment"]
N --> A["workspace assetId"]
A --> K["SHA-256 task idempotency key"]
K --> S["runResumableImageTask"]
S --> G["Go image API"]
G -->|404 code 102| F["source_asset_not_found result"]
G -->|submitted| W["pending store + wait"]
W --> Q["resolve result asset"]
Q --> E["withImageDelivery: source node or new slot"]
F --> M["model gets correction; no same-id retry"]plaintext按代码路径拆开,当前流程是:
- 用户入口与输入上下文。 Agent prompt 把聊天上传放在
<submitted>,并以/mnt/attachments/<id>暴露给模型;它和用户当前查看的<context>场景是不同的数据域。模型可把上传 ID 传给图片工具,但工具不能假定它已经是 workspace asset。 - 统一提升。
tools/index.ts为一次 Agent turn 创建一个共享的promoteAttachment,传给image_generation、cutout_generation和remove_background。attachmentAssets.ts对已是 workspace asset 的值返回原 ID,对支持的上传格式把附件写入/提升为 workspace asset,并用 in-flight map 和跨 turn store 避免同一附件在同一执行链中重复提升。#5506 将这个 seam 接入 remove_background。 - API 契约边界。 TypeSpec 的
RemoveBackgroundRequest仍只声明assetId: string;Go handler 将其按 UUID 解析,再创建 image task。因此/mnt/attachments/<id>不应穿透到 Go 层,真正的附件 ID 到 workspace asset ID 的转换必须在 Agent worker 完成。 - 幂等与可恢复执行。 提升后的
assetId和 operation payload 进入imageTaskIdempotencyKey,用请求内容的 SHA-256 作为 pending key。#4318 的设计让提交前没有旧 task 时正常 submit,提交后才写 pending;轮询临时失败时保留记录,终态失败/取消/成功解析后删除。 - 提交阶段错误。 #5507 的
toSubmitResult是多个 image submit endpoint 共用的结果映射。Go 返回 404/code 102 时,当前 source-asset 语义被转成source_asset_not_found;runResumableImageTask在此处立即返回 failed result,既不store.set,也不 wait/resolve。 - 结果交付。 正常 submitted 任务通过
withImageDelivery统一处理:成功结果放入预留 slot 或复用 source node,失败则使 slot 进入失败状态。#5507 的 submit-before-task 失败会走同一层的失败收口,但不会产生远端 task 或 pending 状态。
这里有一个必须保留的边界:PR #5507 的 comment 明确指出,坏的 referenceAssetId 会在 resolveExtraSourceSpec 中包裹 Go API 错误,之后 Gin middleware 的 concrete-type 判断会把它作为 500;因此当前 code 102 映射只安全覆盖“source asset ID 直接在 submit API 返回 not found”的路径,不等价于所有引用资产错误都已治理。
关键代码与设计点#
以下行号均基于本次只读抓取后的 Voyager origin/main snapshot 26c7c2c4b81511e3bced4da1c3b0438fb41150d9;PR 编号和 diff 位置同时给出,避免把工作分支的旧行号当成主线证据。
1. #4318:pending key 绑定业务请求,而不是绑定一次 tool call#
代码事实: #4318 diff ↗,backend/workers/agent/src/tools/imageTaskTool.ts 的 diff 在新增 imageTaskIdempotencyKey 与 runResumableImageTask 附近。
const imageTaskIdempotencyKey = (taskType, payload) =>
taskType + ":" + sha256(JSON.stringify(payload));
const pendingTaskId = await store.get(idempotencyKey);
if (pendingTaskId) {
return waitAndResolve(pendingTaskId);
}
const taskId = await submit();
await store.set(idempotencyKey, taskId);plaintext设计点: 重试时相同的业务请求仍能找到 orphaned task;而 #5507 在 submit 之前发现 source asset 不存在时不会写 pending。这个顺序是 billing safety 的关键:未提交的错误不应该伪造一个可恢复 task,也不应该让下一次重试挂到不存在的 task 上。
2. #4516:终态业务失败改走 result,而不是异常#
代码事实: #4516 diff ↗,当前 backend/workers/agent/src/tools/imageTaskTool.ts:211-221 对 terminal failure 删除 pending 后返回失败结果;对应的 tool schema 在 toolDefs.ts 使用 succeeded | failed discriminated union。
if (outcome.status === "failed") {
await store.delete(idempotencyKey);
return {
status: "failed",
reason: "error",
...(outcome.errorCode != null ? { errorCode: outcome.errorCode } : {}),
};
}plaintext设计点: “模型输入导致的不可恢复失败”和“服务/网络异常”不再共用 throw 通道。#5507 不是另起一个异常类型,而是把 source asset 缺失继续落到这条已存在的结构化失败协议上。
3. #5506:先把附件提升为 workspace asset,再计算幂等 key#
代码事实: #5506 diff ↗,当前 backend/workers/agent/src/tools/removeBackgroundTool.ts:48-73 的顺序是 promotion -> abort check -> idempotency key -> delivery/task execution。
const assetId = (await promoteAttachment(sourceId, abortSignal)) ?? sourceId;
abortSignal?.throwIfAborted();
const idempotencyKey = await imageTaskIdempotencyKey("remove_background", {
assetId,
});
return withImageDelivery(
go,
delivery,
{ slotId: idempotencyKey, source: { assetId } },
() => runResumableImageTask({
signal: abortSignal,
idempotencyKey,
store: pendingStore,
submit: () => submitRemoveBackground(go, { assetId }, abortSignal),
wait: ...,
resolve: ...,
}),
abortSignal,
);plaintext设计点: 幂等身份必须描述 Go API 实际消费的资源,而不是模型最初给出的路径字符串。这样同一个上传在提升前后的 ID 变化不会造成两个语义上相同但 key 不同的任务;如果提升失败,错误也在远端任务创建前结束。
4. #5507:Go 的 404/code 102 变成可纠正的 source-specific result#
代码事实: #5507 diff ↗,backend/workers/agent/src/goApi.ts:662-664 的 shared toSubmitResult 说明 billing/plan gate 或“source ID 指向不存在对象”属于终态业务结果,goApi.ts:727-733 实际映射:
// A wrong id is the model's to correct, not a service fault. Only a
// source-asset id reaches here: a bad reference arrives wrapped, as a 500.
if (result.error.code === GO_API_ERROR_CODE.notFound) {
return { status: "source_asset_not_found" };
}
throwGoApiFailure(result);plaintext这里的 SubmitImageTaskResult union(goApi.ts:174-186)新增了 { status: "source_asset_not_found" },所以调用方不需要从 error message 中猜测业务含义。
5. #5507:在 pending、wait、resolve 之前给模型可操作的纠正#
代码事实: 当前 backend/workers/agent/src/tools/imageTaskTool.ts:179-186:
if (submitResult.status === "source_asset_not_found") {
return {
status: "failed",
reason: "error",
errorCode: "source_asset_not_found",
message:
"No image asset has that id, and it names no upload in this chat either. " +
"A chat upload's id is the file name in its /mnt/attachments/<id> path, " +
"and the image tools take that id as it is. Do not re-send the same id.",
};
}plaintext测试 tools/imageTaskTool.test.ts:10-51 验证了四个重要负面断言:wait 不调用、resolve 不调用、store.set 不调用,模型输出包含 “Do not re-send the same id”。这比只断言错误字符串更接近 runtime contract。
6. #5422:所有成功/失败结果最终穿过同一 delivery seam#
代码事实: 当前 backend/workers/agent/src/imageDelivery.ts:295-332 的 withImageDelivery 先 hold slot、运行任务;若结果是带 assetId 的 succeeded 才放置,否则 fail slot。
const slot = await holdImageSlot(delivery, slotId, source);
const result = await run();
if (!slot) return result;
if (result.status === "succeeded" && result.assetId) {
await placeImageInSlot(delivery, slot, result.assetId);
} else {
await failImageSlot(delivery, slot);
}
return result;plaintext推断: #5506 通过这个 seam 把 remove_background 纳入统一交付;#5507 的早期失败会让 slot 失败收口,但因为没有 submitted task,所以不会留下需要恢复的远端状态。这里的 slot 状态仍应通过真实 Agent/workerd 场景验证,当前新增测试只覆盖 runResumableImageTask 的 gate。
工程取舍#
边界和复用#
- 错误归属清晰。 一个模型生成的错误 source ID 是输入可纠正问题,不是 Go/服务不可用;因此在共享 Go submit 映射处转成 union result,再由 Agent tool 给出修正建议。
- 复用既有协议。 #5507 复用 #4516 的
failed + reason + errorCode,没有新增异常传播、retry policy 或第二套 UI 协议。#5506 复用promoteAttachment,没有让 remove_background 单独解析 R2 附件。 - 边界仍依赖隐含前提。
toSubmitResult被多个 image endpoint 共用,但notFound到source_asset_not_found的语义依赖“这里只有 source asset 的未包装 404”。这是当前代码 comment 已明确写出的约束,不应被理解为通用 404 分类器。
兼容性与数据模型#
- Go API 的 TypeSpec/handler 仍消费 workspace asset ID,兼容性修复发生在 Agent worker,不改变后端接口的输入模型。
- 工具 schema 同时允许 workspace asset ID 和
/mnt/attachments/<id>,把“用户/模型可见的输入域”与“后端可执行的资源域”隔开。 - promotion 当前只覆盖 PNG、JPEG、WebP;其他格式不应静默假定可用。未知附件格式、附件已删除、workspace asset 不存在都需要产品层面的降级文案与观测。
性能、可靠性与计费安全#
- 业务请求哈希会让重试复用已提交任务,避免重复执行;它也意味着 payload 的字段变化会形成新任务,后续扩展字段时要评估兼容语义。
- #5506 在算 key 和 hold slot 前做 promotion,避免把同一附件的临时 ID 当成任务身份;共享 promoter 的 in-flight map 降低同一 turn 的重复上传。
- #5507 在远端 submit 前结束,不轮询、不 resolve、不写 pending,减少无意义 I/O,并阻断由输入错误引发的自动 retry/重复扣费。
- 代价是错误分类必须精确。若把真正的服务错误归为终态,Agent 会停止恢复;若仍把模型 ID 错误当异常,AI SDK 可能继续重试。当前实现把 source direct 404 和 wrapped reference 404 分开,但后者仍是缺口。
测试策略#
| 覆盖 | 证据 | 尚未覆盖 |
|---|---|---|
| 提交 API 的 404/code 102 映射 | #5507 goApi.test.ts:130-148 模拟 404 JSON,并断言 source_asset_not_found | 真实 Go 服务/部署契约和不同 image endpoint 的 code 102 语义 |
| tool gate 的运行时顺序 | #5507 imageTaskTool.test.ts:10-51 断言不 wait、不 resolve、不 set,并检查模型提示 | 真实 Agent tool、delivery slot 和 workerd 路由组合 |
| terminal failure 不抛异常 | #4516 的 unit/eval 变更 | 客户端/模型是否始终停止同 ID 重试 |
| orphaned task 恢复 | #4318 的 pending store/idempotency 测试 | 进程重启、promotion store 与 pending store 跨重启的一致性 |
| 共享结果交付 | #5422 的 image delivery 测试/调用方接入 | submit-before-task 失败时实际 canvas slot 的状态转移 |
PR body 报告的 19 files/163 tests 是合并前的 agent-worker 验证;本次没有在 Voyager 工作区运行命令,也没有修改依赖或生成文件。
和最近学习记录的关系#
- 目标仓库已有 #4516 的报告,重点是“图片任务终态失败不再 throw,避免 AI SDK 重试”。本次不是重复该结论,而是继续向前追一层:具体的 source asset 404 如何在 submit boundary 变成这个结构化协议,以及在任务尚未创建时哪些副作用必须为零。
- #4344 的报告 已讨论 Agent reference image 与附件上下文。本次新增的视角是 ID 域分离:附件路径不是 workspace asset;#5506 的 promotion 修复输入转换,#5507 处理转换后仍指向不存在 source 的终态。
- 最近一次自动化报告是 #5496 的 Durable Object transient/503 恢复线。两者共享“错误分类决定是否重试”的可靠性原则,但本次边界更窄:#5507 专门把模型可纠正的资源 ID 错误从 transient/service-fault 通道移出,避免沿用 DO/网络错误的恢复策略。
我会怎么吸收#
- 先画清 ID/数据域,再定义接口。 让 prompt 中的附件路径、工具 schema 的输入、Go API 的 workspace asset UUID 和任务 ID 在命名与转换点上显式可见;不要让一个
assetId变量跨域隐式复用。 - 用业务请求内容做幂等身份。 tool call 是一次交互事件,
{taskType, payload}才是重试时需要恢复的业务意图;对图片任务尤其要在资源规范化之后计算 key。 - 把可纠正输入错误设计成终态 result。 result 应携带稳定的
errorCode和模型可执行的下一步,并且测试“不会 submit 后续副作用”,而不只是测试错误文本。 - 集中收口副作用。 任务提交/轮询/解析和 canvas delivery 分层;生成、编辑、去背景共享 delivery seam,单个工具只负责描述 source 与 operation。
- 在测试中断言负面路径。 对错误分支同时断言不写 pending、不 wait、不 resolve、不重复调用;这类断言直接保护可靠性和计费边界。
边界、风险与未解问题#
已由代码验证的边界#
- #5507 只处理 submit 结果中未包装的 Go 404/code 102;PR comment 明确说坏 reference 会被包装并当前走 500。
- #5507 只在 runResumableImageTask gate 返回失败;它不处理任务已经 submitted 后 source asset 被删除、权限变化或 resolve 失败的所有组合。
- #5506 的 promoter 支持 PNG/JPEG/WebP;工具 schema 接受两类 ID 不代表所有附件格式都能提升。
- 本次锚点和相关 PR 的 merge commits 均已进入 origin/main;没有把仍在分支上的 PR 当作演进证据。
仍待确认的问题#
- reference asset 的 404 是否应被前置分类。 当前 wrapped error 会被当作 500 并记录 server fault;正确修复可能需要把 reference lookup 放在 task submit 前,这还涉及 debit + refund 的顺序和一致性。
- 共享 notFound 映射的未来漂移。 若另一个 image endpoint 直接返回同一 code 102,shared
toSubmitResult可能把它误命名为 source asset not found;应考虑让 submit API 返回更具体的错误域,或在调用方传入 operation context。 - 提升的持久化一致性。
uploadAsset成功和attachmentAssetStore.set之间若进程重启,重试是否可能创建多个 workspace asset,需通过真实存储/重启测试确认。 - 已提交任务的资源失效。 需要验证 wait 期间资源删除时 pending 清理、delivery slot 失败、模型消息和 billing 状态是否一致。
- 生产契约与可观测性。 当前新增单测没有覆盖 workerd 到 Go 的真实 404 响应、完整 Agent tool 调用或 reference 404;应补一个不付费/可清理的集成测试,并区分模型输入错误与服务 fault 的 Sentry 统计。
候选说明#
本次先按 Australia/Melbourne 的当天合并窗口查找候选。#5507 在 2026-08-03 13:20 合并,未出现在既有锚点学习日志中;#5503 同日合并但属于聊天 reconnect 失败策略,和上一轮 #5496 的 Durable Object transient 可靠性线更接近,新增工程视角较少。#5501 的语言提示、#5482 的 billing、#5372 的登录账号预劫持和 #5385 的文档侧改动都不能自然串起本次图片任务链,因此没有拼入报告。
#5506 是昨天的直接前置,作为相关 PR 保留而没有重复选作锚点。#4318 超过默认 30 天,但它定义了当前 PendingTaskStore 与内容哈希恢复 seam;如果去掉它,#5507 的“不写 pending、只在 submitted 后保存 task”就失去代码上的前置解释,因此报告明确标注了保留原因。其余关联 PR 均在近 30 天内,且通过相同目录、相同任务生命周期、相同 API/resource boundary 或统一 delivery path 进行代码关联,而不是只依据标题关键词。
GitHub 文档#
- 报告文件:
outputs/voyager-daily-pr-study/2026-08-03-pr-5507-agent-image-source-asset-recovery.md - 目标仓库:joyehuang/ai-agent-field-notes ↗
- Voyager PR: #5507 — Handle missing source assets in image tasks gracefully ↗
- Voyager merge commit:
5d8c482006df6b21535c76653f516115946e3446 - 本报告随本次目标仓库 main 推送提交;最终目标仓库 commit 以本次自动化日志的
githubCommit字段和任务回复为准。 feishu_doc_url: null;本任务不创建外部学习文档。