新增外部去背景 API、MCP 工具与异步队列契约 补齐来源归属、媒体类型、幂等重放和画布原子持久化校验 修复 provenance 重建、assetKindOverride 门禁与 revision retry 竞态 同步 Python helper、Skill、OpenAPI 及项目文档 --------- Co-authored-by: kdletters <kdletters@qq.com> Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/184 Co-authored-by: suzmii <suzmii@foxmail.com> Co-committed-by: suzmii <suzmii@foxmail.com>
31 KiB
外部 OpenAPI 与 API Key 接入方案
背景
外部调用方需要通过稳定 HTTP 契约或托管式远程 MCP 使用图片画布编辑器内的素材生成、编辑和管理能力,并能创建项目、保存画板布局和管理账号级素材库。不支持 MCP 的 Agent 还需要可发现、可校验、可完整下载的 Skill 包,而不是只有一份 OpenAPI JSON。全部入口必须走 server-rs + Axum + SpacetimeDB 正式链路,不能把 API Key、画板状态、素材状态、生成任务或生成结果放到前端临时状态中。
v1 范围
本期新增外部 API 命名空间:
/api/external/v1
v1 只开放以下能力:
POST /api/external/v1/assets/direct-upload-tickets:创建素材直传 OSS 凭证。POST /api/external/v1/assets/objects/confirm:确认已上传素材对象,ownerUserId固定为 API Key 所属账号。GET /api/external/v1/assets/read-url:获取私有素材读取签名 URL。GET /api/external/v1/editor/projects:列出当前 API Key 所属账号的图片画布项目;view=full|summary,REST 默认full,MCP 固定使用summary。POST /api/external/v1/editor/projects:创建图片画布项目。GET /api/external/v1/editor/projects/recent:读取当前账号最近图片画布项目。GET /api/external/v1/editor/projects/{projectId}:读取项目与默认画布。PATCH /api/external/v1/editor/projects/{projectId}/metadata:更新图片画布项目标题。DELETE /api/external/v1/editor/projects/{projectId}:删除图片画布项目,并级联清理默认画布和项目资源元数据。PATCH /api/external/v1/editor/projects/{projectId}/canvas:保存默认画布的 viewport 和 layers。POST /api/external/v1/editor/projects/{projectId}/resources:创建项目画布资源记录。GET /api/external/v1/editor/assets/library:读取账号级编辑器素材库。POST /api/external/v1/editor/assets/folders:创建素材文件夹。PATCH /api/external/v1/editor/assets/folders/{folderId}:更新素材文件夹名称或折叠状态。DELETE /api/external/v1/editor/assets/folders/{folderId}:删除素材文件夹并返回最新素材库。POST /api/external/v1/editor/assets:创建素材记录。PATCH /api/external/v1/editor/assets/{assetId}:更新素材名称或所在文件夹。DELETE /api/external/v1/editor/assets/{assetId}:删除素材记录。POST /api/external/v1/editor/images/generations:异步提交编辑器图片素材生成;通过kind支持普通图、规范图spec、角色图character、快速编辑参考图quick-edit、UI 设计图ui-design和宣发素材publication-material。External v1 当前不开放结构化游戏场景生成,kind = scene与assetKind = scene均在入队前返回400。POST /api/external/v1/editor/images/edits:异步提交已有图片重绘 / 调整。POST /api/external/v1/editor/images/background-removals:异步提交已有静态图片去背景;只接受当前账号拥有的稳定 objectKey、项目资源 ID 或素材 ID。可选assetKind必须与权威来源类型一致,视频、音频、动画和图片序列类型在入队前返回400;拒绝taskId与其它未声明字段。POST /api/external/v1/editor/icon-spritesheets/generations:异步提交规范图驱动的图标 spritesheet 生成和拆分。POST /api/external/v1/editor/ui-designs/assets/extractions:异步提交 UI 设计图素材提取 / 拆分。POST /api/external/v1/editor/character-animations/generations:异步提交角色动画预览和帧序列生成。POST /api/external/v1/editor/videos/generations:异步提交编辑器视频生成,支持现有 Seedance / Kling / Veo 模型参数和参考媒体限制。POST /api/external/v1/editor/audios/sound-effects/generations:异步提交编辑器音效生成。POST /api/external/v1/editor/audios/background-music/generations:异步提交编辑器背景音乐生成。GET /api/external/v1/generations/{operationId}:按 API Key owner 查询异步生成状态;completed时返回 compact 稳定结果引用,跨 owner 按不存在处理。GET /api/external/v1/openapi.json:导出本版本 OpenAPI 3.1 JSON。GET /api/external/v1/agent-integration.json:公开导出 Agent 集成发现 manifest,声明 MCP、OpenAPI、Skill 入口、完整 Skill archive、archive SHA-256 和包内文件清单。GET /api/external/v1/skill/SKILL.md:公开读取 Skill 原始入口。GET /api/external/v1/skill.zip:公开下载完整 Skill 包。POST /api/external/v1/mcp:使用相同 Bearer API Key 的托管式 Streamable HTTP MCP;对外暴露本节 OpenAPI operation tools 以及使用说明、OpenAPI、Skill 入口SKILL.md和逐个 Skill reference 文档,不开放内部 SpacetimeDB MCP。
九类生成 POST 全部要求 Idempotency-Key,成功只返回 HTTP 202 Accepted、operationId、kind、status、statusUrl、pollAfterMs 和 updatedAtMicros。调用方不得把 202 当作媒体生成完成,也不得在网络结果不确定时换一个幂等键重新提交。
图片生成、图标 spritesheet 和 UI 素材提取的 completed compact result 可携带可选结构化 warning { code, reason };任务查询顶层 warning 是可直接展示的有界摘要。外部 OpenAPI 当前公开四个稳定 code:
postprocess-failed-source-preserved:生成成功,但透明处理、像素规整等后处理未完成,接口保留仍可使用的原图或进入该步骤前的结果。dimension-restore-fallback:该告警只描述进入可选pixelArt处理前的交付尺寸归一结果;无法安全归一时,在该处理边界保留 provider 回图尺寸。它不描述或约束pixelArt成功后的最终尺寸;若随后像素规整成功,最终产物是整数倍放大后的 PNG,不能据此推断最终宽高等于 provider 回图。unsupported-image-style:请求的图片后处理风格未知或不适用于当前生成类型,接口按无风格继续生成。multiple-generation-warnings:同一成功响应合并了不同code的多条非阻断告警,具体原因按顺序拼接在reason。
手工调用 POST /api/external/v1/editor/assets 或 POST /api/external/v1/editor/projects/{projectId}/resources 创建 assetKind=character-animation 记录时,generationInputs 只保存可重放的生成输入,不接受 characterAnimation、frames、previewVideoPath、frameCount、fps、durationSeconds 等旧运行字段;完整正式帧序列和总时长必须分别写入 imageSequenceFrames 与 imageSequenceDurationMs。screenColorHex、mattingProvider、mattingModel 属于内部处理审计字段,External v1 会在持久化前移除。角色动作生成接口已经直接返回正式 resource / asset,正常调用方不应再手工复制第一帧创建重复记录。
provider 原图已保存但透明背景处理最终失败时,worker 保留原图稳定引用,不返回不存在的透明处理图,图标和 UI 也不继续拆分;有 projectId + canvasCompletion 时由原图完成画布写回。调用方应展示告警,但不得把 completed 任务改判为失败。该降级只覆盖透明背景处理的最终失败,phase 上报、原图或透明处理图持久化、画布写回失败仍使任务失败。图标 / UI 已成功生成透明图、只有自动拆分失败时继续使用既有 sliceWarning。通用 warning 与 sliceWarning 只在「透明背景最终失败」这一条上互斥;风格归一化或像素规整产生的通用 warning 可以与 sliceWarning 并存,compact result 不得丢弃任一条。
异步提交、查询与幂等
外部生成不受 GENARRATIVE_EXTERNAL_GENERATION_MODE=inline 影响:无论站内本地排障模式如何配置,External v1 都只持久化入队并返回 202,不在 API 请求中同步执行 provider。正式状态源是既有 external_generation_job;生成核心、计费、OSS、画布写回、lease 续租和 fencing 继续由现役 worker 链路负责。
调用规则:
- 调用方为一次逻辑生成分配
1-128字节、无空格的可打印 ASCIIIdempotency-Key。 - 服务端以 owner、job kind、幂等键和规范请求建立稳定去重身份;同一请求的传输重试必须复用原键。
202响应通过Location/statusUrl指向/api/external/v1/generations/{operationId},并提供Retry-After/pollAfterMs。queued/running返回 phase、进度与下一次建议轮询间隔;completed返回result;failed返回脱敏error。调用方自己的轮询超时不改变任务状态。result只保留稳定objectKey、resourceId、assetId、assetObjectId、尺寸、媒体类型、taskId、warning 等轻量引用;禁止持久化完整 project/canvas、大型布局快照、Data URL、Blob URL、过期 signed URL、worker lease/fencing 字段和内部 provider 诊断。- 需要完整项目或素材库状态时,调用方在 completed 后重新读取项目或素材库;需要下载媒体时,用稳定
objectKey调/assets/read-url获取短期签名 URL。
结果查询使用 API Key owner 过滤。任务不存在、已删除或属于其他 owner 时统一返回 404,不能通过差异错误枚举他人 operationId。
托管远程 MCP
/api/external/v1/mcp 是 Genarrative 托管的远程端点,Agent 只需配置 URL 和现有 API Key,不安装本地 MCP server。首版兼容 MCP 2025-11-25 initialize 生命周期,使用 JSON-RPC 2.0 和 Streamable HTTP,支持 initialize、notifications/initialized、ping、tools/list、tools/call、resources/list、resources/read。服务端使用无协议 session 的 JSON direct 模式,不依赖 sticky session,也不把 Mcp-Session-Id 作为业务身份。
MCP transport 的 DNS rebinding 防护必须同时允许正式入口 www.genarrative.world / genarrative.world、开发入口 dev.genarrative.world 和本机开发入口;对应 HTTPS Origin 也必须与公开环境同步登记。新增公开环境域名时,必须在发布前使用该域名的真实 Host 和 Origin 执行 initialize 回归,不能只用 localhost 单测证明端点可用。
MCP tools 从同一份 OpenAPI operation 自动形成 snake_case 名称,并在进程内复用 External REST router,因此鉴权、scope、owner、入参、幂等、计费和结果查询契约只有一份。MCP bridge 从 operation 或 path 的 required Idempotency-Key header 参数自动推导 idempotencyKey 工具参数和转发头,不维护独立的生成 operation 白名单;因此新增异步生成 operation 时,OpenAPI 契约本身就是 MCP 幂等注册来源。MCP transport 的 Authorization 头不能代替逐次业务幂等键。工具结果使用 structuredContent;业务失败使用 isError=true 的结构化安全错误,协议不可路由时才返回 JSON-RPC error。
list_editor_projects 是项目选择工具,服务端固定以 view=summary 调用项目列表,不允许因 OpenAPI 的 REST 默认值退回完整视图。摘要逐项目只返回 projectId、title、updatedAt 和可空 cover,不携带 canvas、viewport、layers、resources 或图片正文;选定目标后再用 get_editor_project 读取完整权威状态。cover 只包含最新项目封面快照的 resourceId、稳定 objectKey、尺寸与 updatedAt,没有封面时为 null。需要展示封面时,以 objectKey 调用 /api/external/v1/assets/read-url 获取短期签名 URL;列表不得内嵌 Data URL、图片二进制或临时签名 URL,也不得把签名 URL 当作持久引用。
MCP 暴露下列稳定文本资源:
genarrative://external-editor/usage:关键工作流和异步轮询规则。genarrative://external-editor/openapi:完整 External v1 OpenAPI。genarrative://external-editor/skill:Skill 入口原文;保留首版已声明的稳定 URI。genarrative://external-editor/skill/references/capability-routing.md:能力选路与场景边界。genarrative://external-editor/skill/references/api-operations.md:公开 API 操作、必填字段与调用顺序。genarrative://external-editor/skill/references/authentication-and-safety.md:API Key 鉴权、幂等与安全边界。genarrative://external-editor/skill/references/requests-and-outputs.md:异步提交、状态轮询与 compact 结果语义。
Skill 日后新增 references/ 文档时,MCP 必须按包内相对路径逐个增加 genarrative://external-editor/skill/references/<name> resource,不得只暴露 SKILL.md 而让 Agent 无法读取其引用。当前稳定 reference 精确为上述四篇,不得声明不存在的 reference。MCP Agent 直接调用托管 tools,不下载或安装 Python CLI;scripts/、tests/ 和 .github/workflows/ 不作为 MCP resources。
MCP 必须始终复用 require_external_api_key,owner 从 ExternalApiPrincipal 获取,不接受请求参数伪造 owner。禁止透传内部 external_generation_job procedure、worker controller、SpacetimeDB MCP 或 lease/fencing 控制面。
MCP 缺少、格式错误或无法验证 Bearer API Key 时仍返回 HTTP 401,但不能只返回通用“未授权访问”。响应必须附带 WWW-Authenticate: Bearer realm="genarrative-external-editor",并在安全 JSON details.guide 中给出稳定 reason=MCP_AUTHENTICATION_REQUIRED、action=CONFIGURE_BEARER_API_KEY、Authorization: Bearer <tnr_sk_...> 格式、登录后前往「开发者 API Key」创建密钥、原始密钥只显示一次、不得粘贴到聊天或写入仓库、配置后重试 initialize 的结构化信息,以及公开 manifest、Skill 入口和 OpenAPI 地址。三种失败使用同一响应,不得通过文案或结构差异枚举 Key 是否存在;引导不得匿名暴露 tools、resources 或 owner 信息。agent-integration.json 的 mcp.credentialSetup 同步提供 action、Header 值格式、导航标签和公开 Skill 引导地址,不编造未纳入公开契约的账户页面 URL。
Agent 集成发现与完整 Skill 包
agent-integration.json 是机器可读的统一发现入口。支持远程 MCP 的 Agent 读取其中 mcp.transport/url/authentication,通过 MCP resources 读取 Skill 入口和所需 references,直接调用 MCP tools,不安装 CLI。仅不支持 MCP,或需要在 Agent 所在机器上编排本地文件上传的调用方下载 skill.archive,核对 archiveSha256,解压后从 genarrative-external-editor-api/SKILL.md 进入。
Skill archive 必须至少包含:
SKILL.mdreferences/capability-routing.mdreferences/api-operations.mdreferences/authentication-and-safety.mdreferences/requests-and-outputs.mdscripts/genarrative_external_api.pyagents/openai.yaml
包由 api-server 直接从仓库同源文件构建,不能只返回光秃秃的 OpenAPI JSON,也不能把个人 API Key、环境配置或本机路径写入包。完整 skill.zip 只服务不支持 MCP 或需要本地文件编排的 Agent,不是 MCP resource catalog 的压缩包镜像。Python helper 对上层保持便利的同步函数外观,但内部必须执行“异步提交 → 保存 operationId → 按 pollAfterMs 查询 → completed 返回 result”,查询超时应保留 operationId 供后续继续,不得换键重提。
api-server 使用 include_str! 嵌入 OpenAPI 与 Skill 源文件;容器构建阶段必须同时复制 docs/openapi/ 和 .codex/skills/genarrative-external-editor-api/,不能只复制 server-rs/,否则本地 Cargo 验证虽可通过,隔离镜像构建会在编译期找不到同源资源。
管理 API Key 的登录态接口保留在站内个人中心链路,但不写入外部 OpenAPI JSON:
GET /api/profile/api-keys
POST /api/profile/api-keys
DELETE /api/profile/api-keys/{keyId}
前端入口位于登录后个人中心的 我的 → 开发者 API Key,用于查看当前 Key、创建新 Key、复制一次性明文和撤销已创建 Key。Key 卡片中的创建时间和最近使用时间必须格式化为 YYYY-MM-DD,不得直接展示后端时间戳。外部 OpenAPI 只描述 /api/external/v1 下可由 API Key 调用的接口,不混入登录态 API Key 管理接口。
版本与兼容策略
当前状态:v1 尚无外部存量调用方
截至 2026-08-08,已按当前线上 API Key 与调用方状态再次确认没有外部第三方存量调用方,v1 仍处于「已发布但无存量集成」阶段。本节记录的豁免只在该前提成立时有效;本次确认不自动延续到今后的 breaking change,每次仍需重新取得当日线上状态并形成明确决策。
已接受的未版本化 breaking change
2026-07-31「收紧编辑器内部处理元数据边界」从下列响应中移除了原本 required 的 provider,info.version 保持 1.0.0,路径前缀保持 /api/external/v1:
EditorImageGenerationResponse、EditorIconSpritesheetGenerationResponse、EditorVideoGenerationResponse、EditorAudioGenerationResponse:provider原为required且非空string,属性整体移除,JSON key 不再出现。EditorProjectResource、EditorAsset:provider原为可选 nullable,属性移除后同样不再出现在响应中。
受影响端点为 POST /api/external/v1/editor/images/generations、.../images/edits、.../icon-spritesheets/generations、.../ui-designs/assets/extractions、.../videos/generations、.../audios/sound-effects/generations、.../audios/background-music/generations,以及全部引用上述两个资源 schema 的读取端点。
这是 breaking change,不是文档同步:严格反序列化的调用方(OpenAPI Generator 生成的 Java / Kotlin / C#、pydantic、serde 非 Option 字段)在 required 字段缺失时直接失败,且失败发生在服务端上线瞬间,不需要调用方做任何动作。脱敏目标本身成立,接受不升版本、不设弃用期的唯一依据是当前无存量调用方。
2026-07-31 同一豁免还覆盖了「八类生成从同步成功响应切换为 202 + operationId,新增统一查询接口」这一 breaking change。旧调用方若仍把生成 POST 响应当作媒体结果会立即失败;接受原地修改 v1 的唯一依据同样是上线前已确认没有外部第三方存量调用方。托管 MCP、集成 manifest 与 Skill archive 均为新增入口,不产生既有客户端兼容债务。
2026-08-08「收紧图片编辑主来源契约」把 POST /api/external/v1/editor/images/edits 的既有必填 sourceImageSrc 替换为新的必填 sourceReferenceId,并移除可选 sourceResourceId / assetKind;info.version 继续为 1.0.0,路径继续为 /api/external/v1。严格客户端会因必填字段改名、旧字段被 additionalProperties: false 拒绝而立即失败,这属于本节定义的 breaking change。产品负责人已于 2026-08-08 根据当前线上 API Key 与调用方状态确认仍无外部调用方,因此明确接受本次不增加兼容字段、不新开 /v2、不设弃用期的原地变更。该豁免只覆盖本次字段替换,不得被后续 breaking change 自动引用。
豁免的失效条件
API Key 由用户在个人中心自助发放,因此「无外部调用方」不是受控状态,可能在无人决策的情况下变为假。本节豁免在下列任一条件出现后立即失效:
external_api_key出现属于非内部账号的活跃密钥;- 对外公布 v1 契约、接入文档或示例代码;
- 与外部团队开始基于 v1 的联调。
正式对外发放第一个外部密钥之前,必须先确认下节规则已生效且 v1 契约已冻结。
今后的变更规则
下列改动视为 breaking,不得在同一 info.version 与同一路径前缀下直接发布:
- 删除响应字段,或把响应字段移出
required; - 收窄字段类型、取值枚举或长度约束;
- 在不改字段名的前提下改变字段语义;
- 新增请求必填字段,或收紧既有请求字段的校验。
存量调用方出现后,上述改动按以下顺序择一处理:保留字段并返回兼容值(可为 null 或占位值);标注 deprecated 并公告弃用期后再移除;或开设 /api/external/v2 并冻结 v1。仅更新 docs/openapi/genarrative-external-v1.openapi.json 不构成合规的变更流程。
鉴权
外部调用使用 Bearer API Key:
Authorization: Bearer tnr_sk_xxx
规则:
- API Key 归属于
owner_user_id,外部接口只能访问该账号自己的项目、画布和生成素材。 - 明文 Key 只在创建接口返回一次,后端只保存
key_hash与key_prefix。 - API Key 被撤销后立即不可再用于外部接口。
- 外部 API 鉴权不复用登录态 JWT,不检查 refresh session;它是独立开发者凭据。
- OpenAPI JSON、Agent 集成 manifest、原始 Skill 入口和完整 Skill archive 公共可读,不需要鉴权;MCP 与全部业务操作需要鉴权。
数据模型
新增 SpacetimeDB private 表:
external_api_key
字段:
key_id:主键。owner_user_id:所属账号。name:用户可识别名称。key_prefix:前缀片段,用于列表展示和排障。key_hash:完整 Key 的 SHA-256 十六进制摘要,唯一。scopes_json:作用域 JSON,v1 固定包含editor:project、editor:canvas、editor:image-generate、editor:asset。其中editor:image-generate覆盖图片生成、重绘、去背景、规范图、宣发图、图标拆分、UI 素材拆分、角色动画、视频、音效和音乐生成。created_at/last_used_at/revoked_at/updated_at。
SpacetimeDB procedure:
create_external_api_key_and_returnlist_external_api_keys_and_returnrevoke_external_api_key_and_returnauthenticate_external_api_key_and_return
素材生成与落库
外部生成接口复用站内编辑器已有 DTO、入队器和 worker executor,不维护第二套生成语义:
- 图片生成 / 重绘 / 去背景 / 规范图 / 宣发图 / UI 设计图复用站内编辑器的校验、模型归一、计费和持久化规则,但 External handler 固定只入队。External v1 图片修改必须提交当前账号已登记的项目资源 ID 或素材 ID 作为
sourceReferenceId;上传对象必须先登记为项目资源或素材。objectKey、URL、Data URL、Blob URL 以及旧sourceImageSrc/sourceResourceId/assetKind字段均返回400。服务端分别按资源 ID 与素材 ID 主键窄查,双表冲突、未命中、越权或对象记录无效均失败关闭,快速编辑的完整有效类型白名单为null / spec / character / icon-spritesheet / icon-spec / publication-material / ui-design / scene,OpenAPI 的x-genarrative-allowed-effective-asset-kinds必须与后端白名单精确一致。请求带targetLayerId时必须同时带projectId;目标图层必须关联有效项目资源,来源与目标优先比较assetObjectId,缺失时比较 canonical(bucket, objectKey),来源默认类型还必须与目标资源默认类型一致。入队载荷保存版本化权威快照,worker 执行前再次定点解析并拒绝身份或类型漂移;仅以素材 ID 编辑时不伪造项目资源关系。主站和 External 的通用图片入口共用场景专用合同边界校验,禁止用kind = scene或assetKind = scene绕过后端场景 Prompt 组装;场景专用 handler 自己构造规范请求,不受该通用入口校验影响。External v1 去背景接受稳定 objectKey、项目资源 ID 或素材 ID,入队前按当前 owner 解析并规范化为权威 objectKey,同时从项目资源或素材库读取权威语义类型,并只把资产对象存储类型用于非静态媒体门禁;显式项目资源 ID / 素材 ID 优先于 objectKey 匹配,纯 objectKey 对应多条且权威元数据不一致时返回400并要求sourceResourceId或业务 ID 消歧,禁止依赖项目列表顺序。请求assetKind与权威语义类型冲突,或任一记录表示视频、音频、动画、图片序列时返回400,最终队列载荷只保存服务端解析出的静态语义类型。提供targetLayerId时始终必须同时提供projectId;存在canvasCompletion时按生成完成链路写入画布,targetLayerId不参与原位替换;没有canvasCompletion时,目标图层必须存在并关联当前项目静态图片资源,并与来源优先按assetObjectId、缺失时按 canonical(bucket, objectKey)证明为同一对象,默认权威类型也必须一致,否则在入队前返回400;纯 objectKey 省略sourceResourceId时自动绑定目标图层资源,并把绑定写入队列供 Worker 再验证。两种画布字段都未提供时只持久化请求指定的项目资源或素材记录,不自动写入画布。URL、未登记或越权引用、无效目标均在入队前失败。外部 DTO 不暴露内部taskId,也不接受 OpenAPI 未声明字段;任务 ID 只能由服务端队列生成。 - 图标 spritesheet 和 UI 设计图素材提取复用站内拆分逻辑,生成图集后按连通域切片,并把图集与切片都按请求写入项目资源和素材库。
- 角色动画、视频、音效和背景音乐复用站内编辑器生成链路;请求携带
assetFolderId时按站内规则写入素材库,音频类外部调用使用 API Key 所属账号作为 asset owner。 - API Key 管理接口仍只属于登录态个人中心,不进入外部 OpenAPI JSON。
素材外部生成由 worker 成功后:
- 通过 OSS / asset object adapter 持久化媒体文件。
- 写入
editor_asset,让生成素材进入账号级素材库。 - 如果请求带
projectId,写入editor_project_resource。 - 在
result_payload_json保存 compact 稳定引用,由查询接口返回素材 ID、资源 ID、objectKey、尺寸、媒体类型、model、taskId 和 warning;普通 External API 响应、项目资源与素材 read model 不返回生成 provider、原始 prompt 或内部抠图审计字段。同源画布前端自动提交默认segModel属于站内 BFF 请求契约,不因此向 External OpenAPI 开放该字段。
如果请求未带 projectId,只生成并写入素材库;调用方可随后创建项目或自行保存画板布局。
素材与项目资源操作
外部素材操作复用站内图片画布素材库和项目资源的后端事实源:
- 外部上传素材时先调用
POST /api/external/v1/assets/direct-upload-tickets获取 OSS 表单直传参数,上传完成后调用POST /api/external/v1/assets/objects/confirm写入asset_object,再用assetObjectId/objectKey创建账号级素材或项目资源记录。 - 外部读取私有 generated / uploaded 素材预览时调用
GET /api/external/v1/assets/read-url获取短期签名 URL;不开放浏览器 STS 写权限。 - 素材库读取、文件夹创建 / 更新 / 删除、素材创建 / 更新 / 删除、项目画布资源创建全部通过
api-server -> spacetime-client -> spacetime-module。 - 所有外部素材接口使用 API Key 所属的
owner_user_id,不能由请求体传入 owner。 - 素材库仍是账号级事实源,不归属于单个项目;项目画布内资源继续使用
editor_project_resource。 - 素材创建和项目资源创建接口只保存记录和元数据;图片二进制上传、签名读取和生成图持久化继续复用已有资产 / 生成链路。
OpenAPI 导出
OpenAPI 3.1 JSON 固定落在:
docs/openapi/genarrative-external-v1.openapi.json
服务端 GET /api/external/v1/openapi.json 和 MCP OpenAPI resource 使用同一份 JSON,通过 include_str! 导出,避免运行时生成结果与仓库文档漂移。MCP tool catalog 同样以这份 OpenAPI 的 path、method、operationId、参数和 request body 是否存在为来源;字段级精确约束继续以 OpenAPI resource 为准。
验收
- API Key 创建只返回一次明文,列表不返回明文。
- 撤销后的 API Key 调用外部接口返回
401。 - 九类外部生成 POST 缺少或携带非法
Idempotency-Key时返回400;同一 owner、请求和 key 重试只得到同一 operation。 - External 通用图片生成携带
kind = scene或assetKind = scene时均返回400,且不得产生入队尝试。 - 九类外部生成 POST 固定返回
202,查询能从queued/running收敛到completed/failed;调用方超时后使用原 operationId 继续查询。 - 外部图片生成、重绘、去背景、图标拆分、UI 素材拆分、角色动画、视频、音效和音乐 completed 后,生成结果按请求同时出现在画布资源和账号级素材库。
- 角色图、图标 spritesheet 和 UI 素材提取的 completed result 允许携带
EditorGenerationWarning;provider 原图保留降级与自动拆分降级必须保持成功状态,并分别使用通用warning与兼容sliceWarning表达。 - 外部视频、角色动画、音效和音乐接口使用站内编辑器相同的请求校验、模型限制和价格校验。
- OpenAPI JSON 能被
serde_json解析,且 security scheme 为 Bearer API Key。 - 项目列表 REST 默认
view=full并保持完整响应兼容;view=summary只返回项目选择元数据和可空封面稳定引用,MCPlist_editor_projects固定使用该摘要视图,不因完整项目数据量增长触发返回体上限。 - 摘要封面不内嵌图片或签名 URL;使用
cover.objectKey调/assets/read-url后才能临时展示。 - OpenAPI JSON 不包含
/api/profile/api-keys、UserAccessToken或 API Key 管理 schema。 agent-integration.json能发现 MCP、OpenAPI、Skill entry/archive;下载 archive 的 SHA-256 与 manifest 一致,ZIP 包含SKILL.md、四篇 references、Python helper 和agents/openai.yaml七个声明文件且不含凭据。- MCP 在无 Bearer、Bearer 格式错误或 Key 无效时返回相同的
401 + WWW-Authenticate + details.guide鉴权引导,且不暴露 tools/resources/owner;合法 Key 可完成 initialize、tools/list、resources/list/read 和生成提交/查询;resource catalog 必须包含 usage、OpenAPI、skill主入口和当前全部 Skill references,当前精确为skill/references/capability-routing.md、skill/references/api-operations.md、skill/references/authentication-and-safety.md与skill/references/requests-and-outputs.md,且不包含 CLI 脚本、测试或 workflow;多实例不依赖 sticky session,不暴露内部 SpacetimeDB MCP 或 worker 控制面。 - 外部素材库接口覆盖当前已有素材操作:直传凭证、素材对象确认、签名读取、读取素材库、创建 / 更新 / 删除文件夹、创建 / 更新 / 删除素材、创建项目画布资源。
- 外部项目接口覆盖当前已有项目管理操作:项目列表、最近项目、创建、读取、重命名、删除和默认画布保存。
- 外部素材生成接口覆盖当前已有编辑器素材操作:生图、重绘 / 调整、规范图生成、宣发素材生成、图标素材生成与拆分、UI 设计图生成与拆分、角色动画、视频、音效和背景音乐。
- 修改 SpacetimeDB schema 后运行
npm run spacetime:generate与npm run check:spacetime-schema。