--- name: henji-model-adaptation description: 面向 Henji-AI 的模型与供应商调研、文档整理、参数体验和适配工作流。用于“新增供应商”“给现有供应商新增模型”“模型和供应商都要新增”“核查 API/价格/平台别名”“校对参数顺序、通用交互、隐藏参数或默认请求值”这类需求;先输出确认清单,用户确认后再实施。普通模型 schema 会被标准画布节点自动读取,不因模型会出现在画布里而自动触发节点开发。 --- # Henji Model Adaptation 按最小上下文加载执行。 ## 1. 识别场景并路由 - 先读取 `references/intake-checklist.md`,输出精简确认清单并等待用户确认。 - 若用户需求是“新增供应商”,读取 `references/new-provider.md`。 - 若用户需求是“现有供应商新增模型”,读取 `references/new-model-existing-provider.md`。 - 若用户需求是“新模型且未接入对应供应商”,先读取 `references/new-provider.md`,再读取 `references/new-provider-and-model.md`。 ## 2. 按需补充读取 - 需要核对 API 字段、枚举、输入限制、端点、价格或异步/流式协议时,先读 `packages/ai-sdk/docs/model-adaptation/`——这是项目唯一资料源;其中 `文档采集手册.md` 是官方来源、事件契约、fixture/test 闭环与 SDK 首发顺序的唯一详细规范。旧的 `docs/api/` 已废弃删除,不要重建或引用。 - 涉及 API/价格调研、适配清单或模型文档整理时,必须先读取 `references/source-research-workflow.md`;按用户给定的平台矩阵控制范围,并完成模型别名、动态 Tab、价格与登录状态核验后再下结论。调研结论按该文件第 7 节的路径与命名约定落盘,并同步 `README.md` 清单。 - 先做“同模型多端点归并判定”: - 若 API 文档里的多个端点共享同一个模型名称/版本,只是输入素材或子能力不同,默认按“一个模型”处理,不默认拆成多个模型文件。 - 只有在名称/版本相同但计费、轮询契约、结果结构、核心参数集合明显不同,且无法通过 schema + `endpoints.selector` + `request.builder` 在一个模型内稳定表达时,才考虑拆分成多个模型。 - 先做“功能能力来源”判定: - 不要把“功能标签/筛选项”与“独立端点/独立 mode”混为一谈。 - 某个功能(例如首尾帧)即使没有独立端点、没有显式 `mode`,只要 API 文档表明它可通过同一端点内的可选字段激活(例如第 2 张图映射为 `end_image`),也应视为该模型具备此功能。 - 这类能力需要同时落到 3 处: - `meta.tags`:保证模型能被功能筛选命中; - `inputLimits` / `requirements`:保证输入数量与约束正确; - `request.builder`:把 UI/上传素材转换成 API 所需字段。 - 先做“自动切换 vs 显式 mode”判定: - 若路由差异仅由是否上传图片/视频、上传数量(如 0/1/2 张)决定,且用户侧不需要主动选择子能力,优先做自动切换,不新增 `mode` 参数。 - 若路由虽然可由素材数量自动判定,但为了让用户清楚当前处于哪个子模式,允许保留一个可见的 `mode` 参数,并通过 linkage/autoSwitch 自动更新其值;这类情况按“显式展示 + 自动切换”处理,不算纯手动模式。 - 若存在 3 种及以上子能力、允许多张参考图、同时支持视频编辑/参考生视频/延长视频等复杂分支,或不同分支的参数显隐/约束/价格差异明显,必须显式设计 `mode` 参数。 - 若仅有“文生图 + 图像编辑”两种能力,且差异只在“有无上传图片”,默认自动切换。 - 若仅有“文生视频 + 首帧图生视频 + 首尾帧视频”三种能力,且可由上传图片数量 0/1/2 张唯一确定,默认可采用两种方案: - 简单场景:纯自动切换,不暴露 `mode`; - 更重视用户心智可见性时:暴露 `mode`,默认显示“文/图生视频”,上传 2 张图后自动切到“首尾帧”。 - 一旦再引入“多参考图”“视频编辑”“视频参考”这类分支,则升级为显式 `mode` 主导。 - 设计参数顺序、分组、特殊面板或“高级设置”时,读取 `references/param-order-patterns.md`;先保留跨模型通用参数的标准交互,再收纳模型特有或低频参数。 - 参数涉及遮罩、区域选择、深度/控制图等需要基于其他素材创建的派生媒体时,读取 `references/derived-media-authoring.md`;先设计“创建/编辑/继续编辑”闭环,再决定提交时的媒体路径与上传转换。 - 若实施需要新增/改造 `.tsx` 参数面板,按项目规则同时使用 `henji-ui-surface`;这仍属于共享参数呈现,不因它也会出现在画布里而自动变成画布节点任务。 - 处理“不展示参数/固定默认请求值”时,读取 `references/hidden-default-params.md`。 - 判断图片/视频/音频差异时,读取 `references/modality-differences.md`。 - 涉及比例/分辨率时,优先执行“智能比例 + 本地转具体值”的规则(见 `references/param-order-patterns.md`)。 ## 3. 执行规则 - 当前 Henji-AI 的宿主基线是 Electron + Node/TS;可移植的供应商执行、上传、轮询与结果解析位于 `packages/ai-sdk/src/{providers,upload,protocols}/`,`electron/main/services/ai-runtime/**` 只保留日志、落盘、取消、进度与 IPC 等宿主薄壳。 - Henji-AI 是 SDK 主开发仓库与首发验证宿主。先按 `文档采集手册.md` 完成官方资料和事件契约,再在本项目实现、验证、打包回装并发布;消费项目只接入已验证的精确版本。资料不足时暂停,不在消费项目猜协议。 - SDK 发布后读取 `packages/ai-sdk/docs/consumers.md`,按变更的实际影响逐个同步消费者;未使用的新能力不进入宿主。外部消费者精确锁定版本与 integrity,并把 commit、验证状态和接入边界回写清单。 - 在输出确认清单前,先自行归纳: - 这是“一个模型多个端点”还是“多个独立模型”; - 应采用“自动路由”“显式展示 + 自动切换”还是“显式 `mode`”; - 依据是什么(输入素材种类/数量、参数差异、价格差异、轮询契约差异); - 各项“功能筛选标签”来自哪里:独立端点 / 显式 mode / 同端点内可选字段。 - 输出确认清单时,默认带上你的预判结论,用户只需要改例外项,不需要从头重复描述。 - 信息不足时,停止编码并向用户补充最小必要信息。 - 若用户未提供价格或计费规则,必须先追问价格,再继续模型实现。 - 优先复用同供应商、同模态、同模型家族的现有模型定义;仅将其作为起点,以官方 API 文档为准。 - 供应商模型文件只填写 `meta.canonicalModelId`,禁止填写 `meta.description`。适配前先检查 `src/core/modelCatalog/generationModelDescriptions.ts`:已有同一通用模型标识就直接引用;不存在就新增空描述条目,并在交付时明确告诉用户需要在该文件补充这个模型的定性描述。通用描述只写模型擅长方向或相对定位,不重复 tags 已表达的固有能力。 - 对接已接入的 provider 时,先核对该 provider 在仓库里的既有 route 写法与 runtime 约定,再决定 `endpoints` 填什么;不要只按文档标题猜路径,也不要漏掉现有 provider 统一前缀(例如部分 PPIO 路由实际要走 `/async/...`)。 - 参数展示层可以做统一交互,但最终请求参数必须转换为 API 文档要求的字段和值。 - 参数展示补丁中的 `description` 是给智能助手、能力反射与语义检索使用的参数说明,正式参数界面不得渲染它;给用户看的解释、限制和操作后果必须写入 `tooltip`,并按 `henji-ui-surface` 通过标签旁的说明入口呈现。两者受众不同,可以同时存在,界面不得用 `description` 兜底 `tooltip`。 - API 的媒体/文件字段即使名为 `*_url`,参数面板也禁止呈现手动 URL 文本框。普通已有素材(角色图、风格参考图、视频、音频、PDF 等)使用对应上传类型或现有上传按钮;由 Electron 主进程调用当前供应商官方上传服务并把返回 URL 写入请求,业务 UI 不直连上传 API。 - 遮罩、区域选择等需要用户基于另一份素材现场制作的**派生媒体**,不得把普通上传按钮作为主操作,也不得要求用户去外部软件制作后再次上传。主操作必须按状态显示“绘制”/“编辑”并打开项目内共享编辑器;确认后生成受管媒体供提交链路上传,已有结果再次进入时必须能够继续编辑。上传或导入只能在产品明确需要兼容外部成品时作为次级入口。 - 特殊请求字段(如 `cref` / `sref` / `dref` / `mask_url` / `pdf_url`)必须通过 `runtimeConstraints.mediaFields` 声明媒体类型,让公共预处理层识别并上传;禁止在上传运行时添加模型 ID 分支。若供应商没有对应官方上传能力,不得让用户自行填写公网链接,应暂停该能力并向用户确认。 - 上传参数的新 schema 值使用数组结构,builder 仅可为旧工程兼容读取历史字符串 URL;兼容路径不能重新暴露 URL 输入框。对话/工具面板 `ParamRenderer` 与画布 `NodeParamControl` 必须能消费同一上传 schema。 - 参数压缩不能破坏用户已经形成的跨模型心智:比例、分辨率、时长、数量、质量等高频通用参数,优先保持同模态模型已有的名称、控件类型、顶层位置和交互方式;不得仅为了“参数更少”把它们吞进供应商/模型专属高级面板。标准交互不等于统一 options/default,合法值和默认值仍以当前 API 契约为准。 - 模型特有、低频或需要强联动解释的参数才进入 `composite` / 特殊面板;面板内部仍复用现有 `Ui*`、标准参数控件、上传与排序能力,不重做比例选择器、下拉、开关或文件上传。 - 同一供应商、同一模型家族、同一模态下,仅因端点、渠道或子能力不同而拆出的模型,默认优先合并为一个产品入口,用顶层 `mode` / `channel` 明示切换;独立模态、完全不同的用户目标或无法共存的生命周期才保留多个模型卡片。平台文档分成多页不等于产品必须分成多个模型。 - 模型存在产品级渠道切换时,渠道参数**必须同时满足两点**:显式声明 `role: 'channel'`,且字段名写 `sharedFieldText('apiChannel')`(显示为“渠道”)。二者是双向绑定,缺一边都会被 `modelParamConventionValidator` 在模型注册时拦下。生成面板只按 `role` 决定主选择器提前渲染,不再从参数名文案反推。渠道参数必须严格排在所有其他参数之前,包括分辨率、比例和模式;这条规则优先于“模式优先”。 - **渠道的选项文案不做约束**,由模型自己定义:选项是供应商自己的产品叫法(ext / VIP / CL / VT / 4K-VIP…),共享的 `sharedOptionText('regular' | 'official')` 只在恰好两档、且正好是“第三方 vs 官方”时才对得上(目前只有 APIMart 三个模型适用),不是通用约定,不要硬套。 - 模式 / 版本 / 变体这类主选择器同样要显式声明 `role: 'mode'`(不要求 order 为 1,字段名不受上面那条约束)。音频“声道”不属于产品渠道,不要声明 role。 - 合并或重命名模型时,旧 ID 放进 `meta.aliases` 只是第一步:旧入口隐含的模式/渠道写入 `meta.aliasParamDefaults`,旧参数 ID 迁移写入 `meta.aliasParamMappings`。四个消费方必须一起验证:生成页初始值、模型切换迁移、画布节点参数、主进程 RequestBuilder;禁止出现“能解析旧 ID,但旧工程悄悄换了渠道或丢参数”。 - 标准生成节点通过 `GenerationNodeShell -> NodeInputRows -> NodeParamRows` 自动读取模型 schema。只改模型参数定义、显隐、联动、计价或请求映射时,默认不修改 `src/features/canvas/**`,也不加载 `canvas-node-builder`。只有新增/改造节点 DOM、端口、节点注册、节点专属交互,或现有 `ParamRenderer` / `NodeParamControl` 无法共同表达新参数类型时,才进入画布节点工作流。 - 新增或调整复合/特殊参数面板时,必须确认对话/工具面板的 `ParamRenderer` 与画布的 `NodeParamControl` 都能消费同一 schema 和同一值结构;优先修正共享参数面板能力,不为画布复制一份模型专属实现。 - 派生媒体的来源关系、编辑器类型、创建/编辑状态和输出要求必须由共享展示契约声明并由各参数消费方共同读取;禁止在 UI 中按模型 ID 或供应商写分支。运行时参数仍只接收可上传的规范媒体值,应用专属的编辑文档与交互配置不要反向塞进 SDK 请求契约。 - Henji-AI 当前产品约定:新增模型默认不暴露 `output_format` / `outputFormat`,也不向 API 传递该字段;即使文档支持,也先按“不显示且不请求”处理,除非用户后续明确推翻这条约定。 - 若参数显隐/联动/计价依赖“是否已上传图片/视频”,必须同时覆盖三种执行场景各自的运行时字段名,不能只查一个:生成提交时是 `uploadedFilePaths`/`uploadedVideoFilePaths`,画布节点实时值是 `images`/`videos`,对话/工具面板实时上传状态是 `uploadedImages`/`uploadedVideos`。只查其中一个键会导致另外两个场景判断错误(参数该隐藏没隐藏、画布里 mode 自动切换不触发、计价按错分支)。优先复用 `packages/ai-sdk/src/catalog/shared/mediaPresence.ts` 的 `hasUploadedImage`/`hasUploadedVideo`/`countUploadedImages`/`countUploadedVideos`(KIE/PPIO 模型可从同目录 `./mediaSources` 导入,已重导出)。 - 严格走项目主链路:`GenerationService -> src/commands/aiRuntime.ts -> src/platform/* -> electron/preload/index.ts -> electron/main/ipc/ai-runtime.ts -> electron/main/services/ai-runtime/**` 宿主薄壳 `-> @henjicc/ai-sdk`。 - 禁止在业务 UI 写模型/供应商硬编码分支。 - runtime 直接消费 `packages/ai-sdk/src/catalog/` 的真实 `endpoints.selector` 与 `request.builder`,两者都允许同步或异步返回;共享 helper 可以正常 import,但必须位于 SDK 内且满足可移植性检查,禁止反向依赖应用层。 - 判断改动是否真的生效:运行 `npm run gen:catalog`,并对 catalog 中的真实模型执行 selector/builder 请求契约测试;异步 builder 必须在测试和主进程调用侧统一 `await`。 - 多端点模型除“自动切路由”外,还要检查“分支参数契约”: - 文档只在部分端点定义的参数,应只在对应分支显示/发送; - 不要把分支不支持的参数继续展示在 UI 上,再靠 builder 静默忽略; - 文档未定义字段默认不发送。 - 无论是否多端点,都要单独检查“功能筛选一致性”: - `meta.tags` 是否完整覆盖模型对外宣称的能力(如 `start-end-frame`、`reference-mode`、`motion-control`); - 文案、筛选标签、输入约束、builder 映射是否一致; - 不要出现“请求层已支持某能力,但 tags 没标,导致功能筛选缺失”的情况。 - 改动参数默认值后,必须做一次“首屏默认值一致性”检查: - 模型 schema 的 `default` 与 UI 首次渲染显示值必须一致; - 若出现“默认值回到首项”的现象,优先排查下拉组件回退策略是否错误地回退到首个 option,而不是 `param.default`; - 同时检查 linkage 的 `autoSwitch/reset` 是否在初始化阶段覆盖了默认值。 ## 4. 完成标准 - **改了 `.model.ts` 的参数、枚举、输入限制或价格,必须在同一次改动里同步 `packages/ai-sdk/docs/model-adaptation/<模型名>/<模型名>_<供应商名>.md`**,并更新该文件与 `README.md` 头部的「最后更新」;下线模型时同步删除文档并从 `README.md` 清单表移除。只改代码不改文档,等于给下一次调研留下错误依据。 - **新增或改动请求/响应、轮询、SSE、WebSocket、流式 parser,必须按 `文档采集手册.md` 同步官方 fixture、事件矩阵、正反精确测试与断牙验证**;格式和目录约定见 `packages/ai-sdk/tests/fixtures/README.md`,不得凭空手写样本。 - 代码注释里引用的价格/字段来源,必须与对应文档「原始链接索引」里的条目一致;调研中新发现的来源先回填文档再在代码里引用,不允许代码引用一个文档里查不到的出处。 - 按 `docs/rules/testing.md` 选择最小验证:模型定义改动通常运行 catalog 生成、model i18n 与对应参数/请求构建精确测试,不默认跑全量 lint。 - 只有改到 Electron 主进程/runtime/provider/upload 的共享契约时才追加主进程类型检查或相关 lint;先跑精确测试,影响边界不清时再升级。 - 只有需要验证完整 Electron 类型链路、产物或发布链路时,再跑 `npm run electron:build`;构建后需要验收真实桌面能力时再跑 `npm run electron:smoke`。 - 新增能力不引入跨层调用与 UI 直连模型 API。 - 新增参数满足顺序约定,并明确“显示/请求”策略。 - 新增媒体参数已区分“已有素材上传”与“基于前置素材创作”;派生媒体必须在应用内完成创建、确认、重新进入继续编辑和前置素材变化后的失效处理,不能以“可以上传文件”代替用户任务闭环。 - 参数 `description` 已作为助手语义保留但未进入正式界面,所有用户可见说明均通过 `tooltip` 呈现。 - 需要验证运行中的 Electron 进程已加载新 catalog:重新构建 SDK,并重启 `npm run electron:dev`。 - 默认值改动需通过“冷启动可见验证”:重启开发进程后确认参数面板初始显示值正确(不是仅看请求 builder 兜底)。