feat(agent): home composer creation controls + agent-chosen image model
PR: #4389 feat(agent): home composer creation controls + agent-chosen image model
source_automation: “voyager-merged-pr” run_date: “2026-07-09” anchor_pr_number: 4389 pr_number: 4389 pr_title: “feat(agent): home composer creation controls + agent-chosen image model” pr_url: “https://github.com/adastralab-ai/voyager/pull/4389 ↗” author: “Horcrux / magicismight” merged_at: “2026-07-09T04:38:27Z” modules: [“backend/workers/agent/src”,“agent-eval/cases”,“packages/common/src/agentChat”,“packages/common/src/design”,“packages/site/src/app/(main)/_agent”,“packages/site/src/app/(main)/home”,“packages/admin/src/app/(admin)/templates”] files_changed: 70 learning_tags: [“agent-runtime”,“creation-directive”,“home-composer”,“image-model-routing”,“terminal-failure”,“agent-eval”,“protocol-boundary”] business_line: null related_prs: [4314,4344,4309,4516,4390] line_stage: null open_questions: [] feishu_doc_url: “https://my.feishu.cn/docx/BwxxdF648oSmqwxMb2Bc927Dngd ↗”#
正文来源:飞书学习文档 ↗。以下为通过个人 Feishu API 获取并转换后的完整 Markdown 正文。
Voyager Merged PR 学习 - 2026-07-09 - PR #4389#
PR:#4389 feat(agent): home composer creation controls + agent-chosen image model ↗
**作者:**Horcrux / magicismight
**Merge 时间:**2026-07-09T04:38:27Z(2026-07-09 14:38:27 Australia/Melbourne)
**模块:**agent runtime、home composer、agent chat protocol、image generation、page commit tools、agent-eval
**学习标签:**agent-runtime、creation-directive、home-composer、image-model-routing、terminal-failure、agent-eval、protocol-boundary
今日选择#
选择 PR #4389。它把首页的创作类型、尺寸/比例/分辨率、图片模型选择转成可传给 agent 的结构化 creation directive,并同步处理固定尺寸 design 的预建页、图片模型升级策略、保存失败终态语义和 eval 覆盖。
为什么值得学#
- 它把 UI 选择提升为协议,而不是只做前端状态。
ChatMessageMetadata.creation让同一条消息 regenerate 时能重放同一个 directive,避免“用户首页选了 poster,agent 只看到自由文本”的漂移。 - 它在 agent 边界显式区分“用户已绑定的意图”和“agent 可推理的部分”。类型、preset、ratio 是硬约束;Auto 尺寸仍交给 agent 问或判断。
- 它把模型成本/质量策略放在工具 schema 和运行时 fallback 中,而不是暴露成全局模型选择器。普通图默认低成本,显式 2K/4K 或 exact text/photorealistic 才升级。
- 它延续昨天 #4516 的终态失败语义:保存页时的后端/导出服务故障返回 failed result,并给模型停止指令;Go 4xx 仍抛给模型修正。
关键代码#
1. 首页选择变成 wire protocol#
export type ChatMessageMetadata = {
// ...
// Kept on the message so regenerating it replays the same directive.
creation?: CreationDirective;
};
export const creationDirectiveSchema = z.discriminatedUnion("kind", [
z.object({ kind: z.literal("design"), presetId: z.enum(CREATION_PRESET_IDS).optional() }),
z.object({ kind: z.literal("image"), aspectRatio: z.enum(IMAGE_ASPECT_RATIOS).optional() }),
]);plaintext设计点:creation directive 挂在消息 metadata 上,说明它是用户本轮请求的一部分,不是某个页面组件的临时状态。这样 retry/regenerate、agent worker、eval 都能使用同一份输入。
2. Directive prompt 把已选创作类型变成硬约束#
return [
`The user chose to create a "${preset.label}" before this conversation. Treat this as binding.`,
"",
`- Skip target selection — the creation type is already chosen: call \`load_creation_target\` with exactly \`${target.id}\` before target-specific work.`,
`- A blank \`${presetId}\` page (...) was already created ... Build into it ... via \`update_design\`; do not insert a new page.`,
];plaintext设计点:这里没有让模型“参考”用户选择,而是要求跳过 target selection,并绑定到预建的 selected page。这解决了 fixed-size design 打开后 agent 又 insert_page,用户仍停在空白页的问题。
3. 图片模型升级由工具边界兜底#
const wantsAboveLiteCeiling =
input.resolution != null && input.resolution !== "1K";
const modelId =
imageModelId ??
input.modelId ??
(wantsAboveLiteCeiling
? HIGH_RESOLUTION_IMAGE_MODEL_ID
: DEFAULT_IMAGE_GENERATION_SETTINGS.modelId);
return {
resolution: modelId === NANO_BANANA_LITE_IMAGE_MODEL_ID ? "1K" : ...,
modelId,
};plaintext设计点:schema/prompt 告诉模型什么时候升级,但运行时仍保证 2K/4K 不会被 Lite 静默压成 1K。用户或 chat-level 显式模型选择优先,默认 fallback 才按分辨率升级。
4. Page commit 故障复用终态结果模式#
if (output.status === "failed") {
return { type: "text", value: "... Stop here — do not retry ..." };
}
if (!isServiceOutage(error)) throw error;
logger.capture(error, { tags: { scope: "page-commit", tool: toolName } });
return { status: "failed", reason: "service_unavailable" };plaintext设计点:服务故障不再作为 retryable throw 交给模型无限重发;原始错误进 Sentry,模型只看到产品化、无内部细节的失败结果。4xx 仍抛出,保留模型修正错误调用的空间。
和最近学习记录的关系#
强相关。最近几条学习记录从 #4314(AI Gateway image provider 边界)、#4344(referenceAssetIds 进入 agent tool schema)、#4309(新增 Nano Banana Lite 的跨层契约)、#4516(图片终态失败作为 result)一路推进。#4389 是这条链路的上层收束:把首页入口的用户选择变成 agent 可执行协议,并把图片模型路由和 page commit 失败语义纳入同一套 agent runtime 规则。
我会怎么吸收#
- 用户在入口处做出的选择,如果会影响 agent 行为,应进入协议/metadata,而不是留在 UI state 或 prompt 文本里。
- LLM 工具的“建议策略”要有运行时 guardrail:schema 描述负责引导,工具实现负责兜底,eval 负责防回退。
- 对有副作用的工具,区分可纠正调用错误和不可立即重试的服务故障;后者应返回终态 result,让模型停止,而不是抛成 retryable error。
边界/风险#
主要风险是 PR 面很宽:home composer、协议、agent prompt、工具失败语义、eval、UI chip 都在一个 PR 里改,review 成本高。好处是它用多组 agent-eval 把关键行为钉住,包括固定画布不 insert_page、服务故障不重试、图片模型升级、回复语言和失败话术。未看到明显缺失的核心风险,但后续需要继续观察实际数据里 agent 是否过度升级到 gpt-image-2,以及 Auto preset 是否在更多创作类型里保持语义清晰。
候选说明#
今天(Australia/Melbourne 2026-07-09)查到 4 个已 merge 到 main 且未在本地日志记录过的候选:#4546、#4543、#4539、#4389。#4546 是 context menu 子菜单关闭语义,#4543/#4539 是 docs 编辑器行为;都可学习,但工程跨度和近期主题关联不如 #4389。昨天窗口还有若干已 merge PR,其中 #4516 已在 2026-07-08 学过并被去重跳过。
飞书文档#
本文档即本次学习记录。