Joye Dev

Back

feat(agent): add Nano Banana Lite image model

PR: feat(agent): add Nano Banana Lite image model (#4309)


正文来源:飞书学习文档。以下为通过个人 Feishu API 获取并转换后的完整 Markdown 正文。

今日选择#

PR: feat(agent): add Nano Banana Lite image model (#4309)

作者: Whitewater / lawvs

Merge 时间: 2026-07-07T04:01:01Z(2026-07-07 14:01:01 AEST)

链接: https://github.com/adastralab-ai/voyager/pull/4309

模块: idl/typespec/services/image.tsp; backend/go/apps/api/handler/image.go; backend/go/internal/image; backend/workers/agent/src/tools/imageGenerationTool.ts; packages/common/src/agentChat/models.ts; packages/site/src/app/(main)/_agent/chat; generated API clients

学习标签: image-generation, agent-runtime, api-contract, generated-client, model-capability-validation, local-dev-gate, task-worker-boundary

为什么值得学#

  • 它把一个新模型作为跨层契约处理,而不是只在前端下拉框里加选项:TypeSpec enum、Go generated types、agent worker、site UI、admin/site generated client 都同步变更。
  • 它区分了两个边界的责任:公开 API 对非法请求硬拒绝,agent tool 对模型能力做归一化,避免 LLM/用户选择把不支持的 4K 传入任务系统。
  • 它把发布风险控制在 UI 层:后端和 worker 已经支持 nano-banana-lite,但普通站点客户端只在 local development 暴露入口。
  • 它延续了最近 image generation 系列 PR 的方向:稳定公共模型 ID,内部再映射到具体 provider model。

关键代码#

API 契约声明模型能力#

idl/typespec/services/image.tsp:197-204

@extension("x-oapi-codegen-extra-tags",
  #{binding: "required,oneof=nano-banana-pro nano-banana-2 nano-banana-lite gpt-image-2"}
)
@doc("""
Image generation model. `nano-banana-lite` only supports `resolution: "1K"`;
requests using higher resolutions are rejected.
""")
modelId: GenerationModelId;
plaintext

设计点:能力约束写进 API source of truth,而不是散落在客户端 copy 或 handler 注释里;后续 codegen 会把同一 enum 推到 Go 和 TS 客户端。

公开 API 保持硬边界#

backend/go/apps/api/handler/image.go:322-325

if req.ModelId == api.NanoBananaLite && req.Resolution != api.GenerationResolution1K {
    _ = c.Error(bizerrors.BadRequest("nano-banana-lite only supports 1K resolution", nil))
    return
}
plaintext

设计点:外部 API 不替调用者猜测,避免一个显式 4K 请求被悄悄降级成 1K。这对 API 可预期性和错误排查更友好。

Agent runtime 主动归一化#

backend/workers/agent/src/tools/imageGenerationTool.ts:42-56, 90-99

function resolveImageGenerationSettings(
  input: Pick<ImageGenerationInput, "resolution" | "modelId">,
  imageModelId: ImageModelId | undefined,
): Pick<ImageGenerationRequest, "resolution" | "modelId"> {
  const modelId =
    input.modelId ?? imageModelId ?? DEFAULT_IMAGE_GENERATION_SETTINGS.modelId;

  return {
    resolution:
      modelId === NANO_BANANA_LITE_IMAGE_MODEL_ID
        ? "1K"
        : (input.resolution ?? DEFAULT_IMAGE_GENERATION_SETTINGS.resolution),
    modelId,
  };
}
plaintext

设计点:agent tool 是模型选择进入任务系统前的适配层。这里选择 normalize,是因为 agent 的 per-call 参数可能来自 LLM 或 chat-level default,用户体验上更像“选了 Lite 就按 Lite 能力执行”。

UI 入口只在本地暴露#

packages/site/src/app/(main)/_agent/chat-composer/_lib/chatComposerConstants.tsx:26-50

export const IMAGE_MODEL_OPTIONS: {
  id: ImageModelId;
  name: string;
  icon: React.ReactNode;
}[] = (
  [
    { id: "gpt-image-2", name: "GPT Image 2", icon: <GptImage2Icon className="size-4" /> },
    { id: "nano-banana-pro", name: "Nano Banana Pro", icon: <NanaBananaProIcon className="size-4" /> },
    { id: NANO_BANANA_LITE_IMAGE_MODEL_ID, name: "Nano Banana Lite", icon: <NanaBananaProIcon className="size-4" /> },
  ] satisfies { id: ImageModelId; name: string; icon: React.ReactNode }[]
).filter(
  (model) => isLocalDevelopment || model.id !== NANO_BANANA_LITE_IMAGE_MODEL_ID,
);
plaintext

设计点:能力先在后端打通,入口再按环境开关暴露。satisfies 也让 UI option 的 ID 跟共享 ImageModelId 类型保持一致。

和最近学习记录的关系#

有直接关系。#4314 把 gpt-image-2 的 provider 调用迁到 AI Gateway/OpenAI route,#4344 把附件图以 referenceAssetIds 传过 agent tool 边界,#4390 把 image generation tool-part UI 拆成 registry 和 presentational components。#4309 接在这条线上:它继续扩展 image generation 的模型契约,同时把“模型能力差异”分别落在 API validation、agent normalization 和 UI gate 三个层面。

我会怎么吸收#

  • 新增 provider/model 时先问“公共 ID、provider ID、UI 可见性、能力限制”四件事,不要把它们混在一个 if 里。
  • 公开 API 和 agent runtime 可以有不同处理策略:API 保持显式错误,agent 可以为体验做受控归一化,但必须有测试固定行为。
  • 生成代码存在时,真正要改的是 TypeSpec/source schema;generated files 只是同步结果,review 时要重点看 source contract 和边界代码。

边界/风险#

未看到明显高风险。主要残留是产品发布边界:后端已经接受 nano-banana-lite,普通 UI 入口暂时隐藏;如果外部 API 或持久化 chat state 传入该 modelId,服务端会执行,但 2K/4K 会被拒绝。测试覆盖了 agent tool 把显式 4K 归一化到 1K,也覆盖了 Go provider mapping;没有看到公开 API bad-request 分支的专门 handler 测试。

候选说明#

今天(Australia/Melbourne 2026-07-07)窗口内看到 8 个 merged PR;昨天窗口有 14 个。今天未因去重跳过已记录 PR。#4455 的 agent suggestion eval/provider 切换和 #4311 的 sheet paste formatting 都有学习价值;最终选 #4309,是因为它同时覆盖 API 契约、runtime normalization、UI rollout gate,并且和最近几天的 image generation/agent boundary 学习链路最直接。

🗂️ 这是知识库中的🔬 研究。

内容可能仍在补充或修订中。

← Back