两段式第一段的后端承接:用户原话进系统、判意图、返建议供前端确认(确认后才调 /modify 执行)。 契约先行: - studio.yaml 新增 POST /app-api/studio/modify/plan + StudioModifyPlanReqVO/RespVO studio(应用面): - AppStudioController.planModify;StudioServiceImpl.planModify = validateCreator 白名单门(与既有 createDraft/generate/modify 一致)+ 归属校验防越权 + 委托 aigc classifyModify + 异常/空兜底 unclear aigc(worker 对接): - AigcApi.classifyModify + AigcModifyProposalDTO - WorkerClassifyClient:据 baseVersionId 反查 base 源(同 injectBaseSourceProject seam) → NO_PROXY JDK HttpClient POST worker /classify → best-effort 兜底 unclear+needsConfirm - AigcApiImpl 软注入 ObjectProvider<WorkerClassifyClient>(executor 关闭时缺席→兜底, 绝不因 Bean 缺席启动失败,镜像 WorkerDispatchClient);worker URL 尾段 /generate→/classify 测试:StudioServiceImpl 31/31 + WorkerClassifyClient 10/10 + AigcApiImpl 2/2, 本地 maven 独立复跑 43/43 绿、BUILD SUCCESS,既有 modify/generate/SAA 回归零破坏。 真连 worker 的判意图 e2e 待 M5(mini-desktop)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
523 lines
34 KiB
YAML
523 lines
34 KiB
YAML
openapi: 3.0.3
|
||
# 契约 #1 API | 模块:studio(game-module-studio,Wave3 创作主链路最小版)| owner:studio 路
|
||
# 职责(架构 Doc B §71-76):有状态创作工作台后端。编排「建草稿(委托 project createProject)→一句话生成(委托 aigc)
|
||
# →进度轮询→重生成→模板应用」。不跑 LLM(委托 aigc)、不持久化项目版本(交 project)、不做锁风裁决(调 compliance)。
|
||
# 与 game-studio 前端仓区分:本契约是后端 studio 模块(错误码段 112),game-studio 是产品端前端仓名,二者不同。
|
||
# 端:/app-api(产品端 game-studio,用户 Token);前缀由 huijing 框架按 controller.app 包名自动添加。
|
||
# 错误码段:studio = 1-112-***-***(R4 治理新登记,本模块独占,禁与他模块重叠:
|
||
# 100 project/101 aigc/102 runtime/103 feed/104 telemetry/105 pay/106 trade/107 community/108 ip/109 compliance/110 biz/111 ad/112 studio)
|
||
# 响应统一 Huijing CommonResult 信封:{ code, data, msg };code=0 成功。
|
||
# 编排链路(MVP 轮询非 MQ,D4):
|
||
# /template/list (透传 aigc 模板注册表) → /draft (调 project ProjectApi.createProject 拿 gameId upsert 会话)
|
||
# → /generate (调 aigc AigcApi.submitGenerate 落任务链回填 aigc_task_id) → /task/{id} (透传 aigc 进度轮询)
|
||
# → /task/{id}/regenerate (调 aigc AigcApi.retryTask 新建 retry_of 任务链)
|
||
# x-feign-contracts(studio 是调用方,依赖以下对方 -api seam,本契约不对外暴露 Feign):
|
||
# - project-api ProjectApi.createProject(creatorUserId, title, templateId) → gameId(写类 RPC,显式 creatorUserId,归属校验在 project service)
|
||
# - aigc-api AigcApi.submitGenerate / getTask / retryTask / getTemplateList(Wave3 新增 seam,纯暴露层委托 AigcTaskService)
|
||
# attachments(R7):StudioGenerateReqVO.attachments 本波仅持久化(studio 侧落库),不透传 aigc(aigc reqDTO 无 attachments 字段);P1 再透传。
|
||
# 狠切留 seam 不实现(P1):rig/对白树/可视化批量;资产图仅槽位表(game_studio_asset)+ 单步调度,不六路并发。
|
||
# ---------------------------------------------------------------------------
|
||
# 生命周期编排扩展(契约 C3 | 2026-06-17 固定架构+SAA studio execution §5.6/§12-⑥):
|
||
# 范式:游戏 = 长生命周期源项目(LLM as 工作室)。新增 create/modify/extend 三生命周期操作(additive,不破现 draft/generate/regenerate 两步路)。
|
||
# - POST /create = draft+generate 一步式封装(templateId 缺省 generic,一句话直生免选模板,对齐 generic 桥接 7534bdf9)。
|
||
# - POST /modify = 改源不改打包产物:在 baseVersion 源项目上改一处(换美术/调参/改关卡=确定性免 LLM;改玩法=LLM 重生成单 behavior)→ 重构建出新预览版;
|
||
# 不动 currentVersion、不自动入 feed,仍走发布审核(B1 链);失败=不建新版、base 不动。
|
||
# - POST /extend = additive 内容扩展(加关卡/机制/内容,不重写既有部件)→ 新预览版。
|
||
# 三者均委托 aigc(job 模型 mode/baseVersionId/modifyPatch/idempotency)→ SAA 固定架构图产源项目 → 唯一确定性构建 → handleCallback 唯一写入路径落包;
|
||
# 产物均经 taskChain 轮询(复用 /task/{id}),完成后 versionId=新(预览)版。
|
||
# 关联冻结契约:contracts/agent-loop/source-project.schema.json(源项目工件)、modifyPatch(execution §5.6)、六类 assetContext(取代旧 attachments,additive)。
|
||
# x-feign-contracts(新增 seam,studio 为调用方,本契约不对外暴露 Feign):
|
||
# - aigc-api AigcApi.submitGenerate 扩 mode/baseVersionId/modifyPatch/idempotencyKey(生命周期编排参数,additive;后端线落地)。
|
||
# - project-api ProjectApi 取 baseVersion 源项目引用 + 新预览版落库(version 产物权威仍在 project;源项目独立 game_source_project 表存 V18)。
|
||
# idempotency 语义(create/modify/extend 共用):同 userId+operation+idempotencyKey 命中则返回既有 taskChain(不重复触发生成);缺省=不去重;建议 TTL 24h。
|
||
info:
|
||
title: 绘境AI studio 模块 API
|
||
version: 1.0.0
|
||
description: >-
|
||
创作主链路最小版("做得出"工作台)。创作者进工作坊建草稿(移交 project 建游戏拿 gameId)→ 一句话生成(委托 aigc)→
|
||
轮询进度直至终态(透传 aigc)→ 失败可重生成(委托 aigc retryTask)。MVP 轮询非 MQ;前端据此 vite-plugin-mock 自动生成 mock。
|
||
|
||
servers:
|
||
- url: http://localhost:48080
|
||
description: 本地(Swagger/Knife4j http://localhost:48080/doc.html)
|
||
|
||
paths:
|
||
# ===========================================================================
|
||
# 产品端 /app-api(创作工作台,用户 Token)
|
||
# ===========================================================================
|
||
/app-api/studio/template/list:
|
||
get:
|
||
tags: [app-studio]
|
||
summary: 玩法模板列表(模板浏览/应用 P-TPL-01/03,透传 aigc 模板注册表)
|
||
description: 透传 aigc 模板注册表(T-AGC-03);MVP 骨架返回空列表占位,待模板注册表接入。
|
||
responses:
|
||
'200':
|
||
description: 成功(玩法模板列表)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioTemplateList' }
|
||
|
||
/app-api/studio/draft:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 建草稿(进工作坊 P-CRT-10 + 草稿移交 project P-TPL-03)
|
||
description: >-
|
||
编排:服务端调 project ProjectApi.createProject(creatorUserId=当前登录用户, title, templateId) 建游戏拿 gameId
|
||
回写会话,再落会话(status=0 草稿)。attachments 仅持久化(R7)。createProject 是硬前置,返回空 gameId 视为移交失败。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioDraftCreateReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(新建会话,含回写的 gameId)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioSession' }
|
||
|
||
/app-api/studio/generate:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 一句话生成(P-CRT-01,委托 aigc 提交生成)
|
||
description: >-
|
||
编排:校验 session 归属 → 落任务链(status=1 生成中) → 委托 aigc AigcApi.submitGenerate(带 prompt/templateId/gameId/userId)
|
||
→ 回填 aigc_task_id → 立即返回任务链句柄,前端据 taskChainId 轮询。同步直写无 MQ(D4)。
|
||
attachments 仅持久化(R7),不入 aigc reqDTO。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioGenerateReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(任务链句柄,含 aigc_task_id)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioTaskChain' }
|
||
|
||
/app-api/studio/task/{id}:
|
||
get:
|
||
tags: [app-studio]
|
||
summary: 进度轮询(P-CRT-12,透传 aigc 进度/状态)
|
||
description: >-
|
||
编排:校验任务链归属 → 委托 aigc AigcApi.getTask 取进度/状态 → 映射链态
|
||
(aigc succeeded → 链完成回填 version_id + 会话完成;failed/timed_out → 链失败 + 会话失败;其余保持生成中仅回写 progress)。
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '创作任务链 ID(taskChainId)' }
|
||
responses:
|
||
'200':
|
||
description: 成功(任务链最新态,完成后 versionId 非空)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioTaskChain' }
|
||
|
||
/app-api/studio/task/{id}/regenerate:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 重生成迭代(P-CRT-09,委托 aigc retryTask)
|
||
description: 编排:校验原任务链归属 → 委托 aigc AigcApi.retryTask 重提生成 → 新建一条任务链(retry_of=原 id)回填新 aigc_task_id。
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '原创作任务链 ID' }
|
||
responses:
|
||
'200':
|
||
description: 成功(新建的重试任务链句柄)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioTaskChain' }
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 生命周期操作(契约 C3,execution §5.6/§12-⑥;additive,不破现两步路)
|
||
# ---------------------------------------------------------------------------
|
||
/app-api/studio/create:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 一步式创作(C3;draft+generate 封装,P-CRT-01/10)
|
||
description: >-
|
||
编排:建草稿(委托 project createProject,templateId 缺省 generic)→ 立即委托 aigc submitGenerate → 落任务链(status=1)
|
||
→ 返回任务链句柄供前端轮询(复用 /task/{id})。一步式封装,不破现 draft+generate 两步路(additive)。
|
||
六类 assetContext 透传生成上下文(取代旧 attachments)。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioCreateReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(任务链句柄,含 aigc_task_id)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioTaskChain' }
|
||
|
||
/app-api/studio/modify:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 修改(C3;改源不改产物,P-CRT-09 进阶)
|
||
description: >-
|
||
编排:取 baseVersion 源项目 → 应用 modifyPatch(mode=deterministic 确定性编辑免 LLM / regenerate-module LLM 只重生成单 behavior)
|
||
→ 唯一确定性构建出新预览版 → 落任务链供轮询。产物=新预览版(不动 currentVersion、不自动入 feed,仍走发布审核);
|
||
失败=不建新版、base 不动。modifyPatch 字段见 execution §5.6。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioModifyReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(新预览版任务链句柄,完成后 versionId=新预览版、baseVersionId=被改版本)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioTaskChain' }
|
||
|
||
/app-api/studio/modify/plan:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 判意图(A11 切片三 M2;两段式调整回路第一段)
|
||
description: >-
|
||
用户试玩后用自然语言提改("主角太暗""加快下落""做成赛车游戏")→ 本端点判意图:把原话 + base 源工程
|
||
喂便宜档 LLM(worker /classify),返回结构化建议改动 + 风险,供前端确认/编辑后再调已结构化的 /modify 执行(第二段)。
|
||
【判意图不执行、不建版本、不计费】——只判类别/落点/风险,不动 sourceProject、不落任务链。
|
||
编排:白名单可信边界 → base 版本归属校验(防越权判别人的游戏)→ 委托 aigc classifyModify(据 baseVersionId 反查 base 源 →
|
||
同步 POST worker /classify)→ 映射建议改动返回。
|
||
【best-effort 非阻断】base 源反查空 / worker 不可达 / 超时 / 非 200 → 返兜底 {category:unclear, needsConfirm:true},绝不 500、绝不静默判成可执行改动。
|
||
【确认门】needsConfirm=true(危险/大改/改玩法/意图不明/判意图不可用)时,前端必须让用户确认或编辑后才可调 /modify;
|
||
只有「低风险 + 确定性改(asset/config/level)」才 needsConfirm=false。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioModifyPlanReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(建议改动 + 风险 + 是否需确认;判意图不可用时返兜底 unclear)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioModifyPlan' }
|
||
|
||
/app-api/studio/extend:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 扩展(C3;additive 内容扩展)
|
||
description: >-
|
||
编排:在 baseVersion 源项目上做 additive 内容扩展(加关卡/机制/内容)→ 重构建出新预览版 → 落任务链供轮询。
|
||
语义=additive(不重写既有部件);产物处置同 modify(新预览版、不动 currentVersion、走发布审核)。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioExtendReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(新预览版任务链句柄)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioTaskChain' }
|
||
|
||
# ===========================================================================
|
||
# 素材库 R-MAT(U6 | 六类素材 浏览/选用/登记,additive)
|
||
# 上传归属裁定(plan-002):字节落共享文件服务(huijing-module-infra 的 POST /infra/file/upload,AppFileController),
|
||
# studio 不拥有/不代理字节上传端点——前端先调 /infra/file/upload 拿 ref/url/size/mime,再调本模块「按引用登记」端点。
|
||
# studio 仍拥有领域端点:浏览/选用/登记 + game_material 实体 + assetContext。
|
||
# 六类冻结:sprite/character/effect/scene/ui/music(与 StudioAssetContextItem + source-project.schema.json 同引同枚举)。
|
||
# 鉴权:均需用户 Token(不可 @PermitAll);归属隔离在 Service 强制(创作者只见/只用自己的素材,前端不是边界)。
|
||
# 登记自检:六类校验 + 声明 mimeType 与类目族 best-effort 一致性(image/* 给图类、audio/* 给 music);非法类目/MIME 错配前置拒(1-112-005-***)。
|
||
# 深度字节内容/magic-byte 校验已上移共享 infra 上传 + 合规「资产入库·文件安全」门(P2)——裁定后 studio 不持字节。
|
||
# ===========================================================================
|
||
/app-api/studio/asset:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 按引用登记素材(R-MAT;字节先经 /infra/file/upload 拿 ref)
|
||
description: >-
|
||
字节先经共享 huijing-module-infra 的 POST /infra/file/upload(前端直调拿 ref/url/size/mime),本端点据此登记一条素材行(供浏览/选用)。
|
||
编排:六类校验 → 声明 mimeType 与类目族 best-effort 一致性自检 → 落 game_material(归属本人) → 返回输入态六类引用项(直接喂 assetContext.ref)。
|
||
provider 落缺省 mmx-cli。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioMaterialRegisterReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(素材引用项,喂 assetContext)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioAssetContextItem' }
|
||
|
||
/app-api/studio/asset/browse:
|
||
get:
|
||
tags: [app-studio]
|
||
summary: 浏览素材(R-MAT;owner-isolated 分页)
|
||
description: 创作者只见自己的素材(服务端按当前登录用户强制过滤);可选按 category 过滤六类。按 id 倒序(新上传在前)。
|
||
parameters:
|
||
- { name: pageNo, in: query, required: true, schema: { type: integer, default: 1 }, description: '页码,从 1 开始' }
|
||
- { name: pageSize, in: query, required: true, schema: { type: integer, default: 10 }, description: '每页条数,最大 200' }
|
||
- { name: category, in: query, required: false, schema: { type: string, enum: [sprite, character, effect, scene, ui, music] }, description: '按类目过滤(可空=全部六类)' }
|
||
responses:
|
||
'200':
|
||
description: 成功(本人素材分页)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioMaterialPage' }
|
||
|
||
/app-api/studio/asset/select:
|
||
post:
|
||
tags: [app-studio]
|
||
summary: 选用素材入草稿(R-MAT;select-into-draft)
|
||
description: >-
|
||
把选中素材(按 materialIds,本人素材库)写入目标草稿会话的 assetContext(取代旧 attachments)。归属校验本人会话 + 本人素材;
|
||
与既有 assetContext 按 ref 去重合并。C3 create/modify/extend 已直接接受 assetContext 输入,本端点是「选好→落草稿」的便利产出。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StudioMaterialSelectReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 成功(写入后草稿的完整 assetContext)
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultStudioAssetContextItemList' }
|
||
|
||
components:
|
||
schemas:
|
||
# ========== 请求 VO ==========
|
||
StudioDraftCreateReqVO:
|
||
type: object
|
||
required: [title, templateId]
|
||
properties:
|
||
title: { type: string, maxLength: 128, description: '作品标题(透传 project createProject)', example: '我的放置小镇' }
|
||
templateId: { type: string, description: '玩法模板 ID(透传 project/aigc)', example: 'idle' }
|
||
prompt: { type: string, maxLength: 1000, description: '一句话 Prompt(建草稿可空,generate 必填)', example: '做一个躲避陨石的小游戏' }
|
||
attachments: { type: string, description: '附件上下文 JSON(P-CRT-04);本波仅持久化,P1 透传 aigc' }
|
||
|
||
StudioGenerateReqVO:
|
||
type: object
|
||
required: [sessionId, prompt]
|
||
properties:
|
||
sessionId: { type: integer, format: int64, description: '创作会话 ID(建草稿返回的 sessionId)', example: 1024 }
|
||
prompt: { type: string, maxLength: 1000, description: '一句话 Prompt(透传 aigc submitGenerate)', example: '做一个躲避陨石的小游戏' }
|
||
attachments: { type: string, description: '附件上下文 JSON(P-CRT-04);【本波仅持久化,P1 透传 aigc】——studio 侧落库持久化,本波不透传 aigc' }
|
||
|
||
# ---- 生命周期操作请求 VO(契约 C3,execution §5.6)----
|
||
StudioCreateReqVO:
|
||
type: object
|
||
required: [title, prompt]
|
||
description: 一步式创作(draft+generate 封装);templateId 缺省 generic,assetContext 取代旧 attachments
|
||
properties:
|
||
title: { type: string, maxLength: 128, description: '作品标题(透传 project createProject)', example: '我的放置小镇' }
|
||
prompt: { type: string, maxLength: 1000, description: '一句话 Prompt(一步式必填,透传 aigc)', example: '做一个躲避陨石的小游戏' }
|
||
templateId: { type: string, description: '玩法模板/品类引导 ID;缺省 generic(一句话直生免选模板,对齐 7534bdf9)', example: 'generic' }
|
||
assetContext: { type: array, items: { $ref: '#/components/schemas/StudioAssetContextItem' }, description: '六类素材引用(取代旧 attachments,additive);空=纯一句话生成' }
|
||
idempotencyKey: { type: string, maxLength: 64, description: '幂等键(C3;防重复提交触发重复生成,可空)' }
|
||
|
||
StudioModifyReqVO:
|
||
type: object
|
||
required: [baseVersionId, mode, target, payload]
|
||
description: >-
|
||
改源不改产物(execution §5.6 modifyPatch);产新预览版,不动 currentVersion,走发布审核。
|
||
【mode×target.kind 锁定映射——后端可信边界校验,违则 1-112-*** 拒(schema 不用 oneOf 编码以保 mock/codegen 简单)】:
|
||
mode=deterministic ⇔ target.kind∈{asset,config,level} ∧ payload.value 必填(确定性覆写免 LLM);
|
||
mode=regenerate-module ⇔ target.kind=behavior ∧ payload.intent 必填(LLM 只重生成那一个 behavior)。
|
||
properties:
|
||
baseVersionId: { type: integer, format: int64, description: '被改的 base 产物版本 ID(project.game_version.id)', example: 4096 }
|
||
mode: { type: string, enum: [deterministic, regenerate-module], description: 'deterministic=确定性编辑源文件免 LLM;regenerate-module=LLM 只重生成单 behavior 模块', example: 'deterministic' }
|
||
target: { $ref: '#/components/schemas/StudioModifyTarget' }
|
||
payload: { $ref: '#/components/schemas/StudioModifyPayload' }
|
||
idempotencyKey: { type: string, maxLength: 64, description: '幂等键(C3,可空)' }
|
||
|
||
StudioModifyTarget:
|
||
type: object
|
||
required: [kind]
|
||
anyOf:
|
||
- { required: [path] }
|
||
- { required: [id] }
|
||
description: 寻址源项目部件(path 与 id 至少其一:JSON 指针或部件 id)
|
||
properties:
|
||
kind: { type: string, enum: [asset, config, level, behavior], description: '换美术=asset / 调参=config / 改关卡=level(scene) / 改玩法=behavior' }
|
||
path: { type: string, description: '源项目内 JSON 指针(如 /config/speed、/assets/0、/files/src/game.js)', example: '/config/speed' }
|
||
id: { type: string, description: '或按部件 id 寻址(behaviors[].id / assets[].id)' }
|
||
|
||
StudioModifyPayload:
|
||
type: object
|
||
description: mode=deterministic 用 value(直接覆写免 LLM,必填);mode=regenerate-module 用 intent(喂 LLM 重生成意图,必填);后端按 mode 校验(见 StudioModifyReqVO 锁定映射)
|
||
properties:
|
||
value: { type: object, additionalProperties: true, description: 'deterministic 新值(确定性覆写)' }
|
||
intent: { type: string, maxLength: 1000, description: 'regenerate-module 改玩法逻辑的自然语言意图(只重生成那一个 behavior)', example: '把陨石下落改成会左右摇摆' }
|
||
|
||
# ---- 判意图请求 VO(A11 M2,两段式第一段)----
|
||
StudioModifyPlanReqVO:
|
||
type: object
|
||
required: [baseVersionId, instruction]
|
||
description: 判意图入参(用户试玩后的自然语言改话 + 被改 base 版本);判意图不执行、不建版本、不计费。
|
||
properties:
|
||
baseVersionId: { type: integer, format: int64, description: '被改的 base 产物版本 ID(project.game_version.id;判意图据此反查 base 源工程)', example: 4096 }
|
||
instruction: { type: string, maxLength: 1000, description: '用户原话(自然语言改话)', example: '把主角颜色调亮一点' }
|
||
|
||
StudioModifyPlanRespVO:
|
||
type: object
|
||
description: >-
|
||
判意图建议改动(对齐 worker /classify 响应)。前端据此预填一次 /modify:category/mode/target/payload 直接喂第二段;
|
||
needsConfirm=true 时必须先让用户确认/编辑。判意图不可用时返兜底 {category:unclear, mode:null, needsConfirm:true}。
|
||
properties:
|
||
category: { type: string, enum: [asset, config, level, behavior, big-change, unclear], description: '换美术=asset / 调数值=config / 改关卡=level / 改玩法=behavior / 换品类大改=big-change / 意图不明=unclear' }
|
||
mode: { type: string, nullable: true, enum: [deterministic, regenerate-module], description: 'asset/config/level→deterministic(免 LLM 确定性改);behavior→regenerate-module(重生成单模块);big-change/unclear→null(不可直接执行,须澄清/确认)' }
|
||
target: { $ref: '#/components/schemas/StudioModifyPlanTarget' }
|
||
payload: { type: object, additionalProperties: true, nullable: true, description: '确定性改用 {value:{…}};behavior 改用 {intent:"…"};big-change/unclear 为 null' }
|
||
riskLevel: { type: string, enum: [low, medium, high], description: '风险等级(big-change 强制 high)' }
|
||
needsConfirm: { type: boolean, description: '是否必须用户确认后才可调 /modify;只有「低风险 + 确定性改」为 false,其余(危险/大改/改玩法/意图不明/判意图不可用)一律 true' }
|
||
rationale: { type: string, description: '判断依据(中文,一句话)' }
|
||
clarify: { type: string, nullable: true, description: 'unclear/big-change 时回问用户的话;否则 null' }
|
||
|
||
StudioModifyPlanTarget:
|
||
type: object
|
||
nullable: true
|
||
description: 建议的寻址落点(big-change/unclear 为 null);前端预填 /modify 的 target。
|
||
properties:
|
||
kind: { type: string, enum: [asset, config, level, behavior], description: '落点类目' }
|
||
path: { type: string, description: '落点路径(assets.js 键名 / core.js 常量名 / 文件路径)', example: '/files/src/core.js#ROUND_MS' }
|
||
|
||
StudioExtendReqVO:
|
||
type: object
|
||
required: [baseVersionId, intent]
|
||
description: additive 内容扩展(加关卡/机制/内容),不重写既有部件
|
||
properties:
|
||
baseVersionId: { type: integer, format: int64, description: '在哪个产物版本上扩展', example: 4096 }
|
||
intent: { type: string, maxLength: 1000, description: '扩展意图(加关卡/机制/内容)', example: '再加一个 boss 关卡' }
|
||
assetContext: { type: array, items: { $ref: '#/components/schemas/StudioAssetContextItem' }, description: '扩展用的新增六类素材引用(可空)' }
|
||
idempotencyKey: { type: string, maxLength: 64, description: '幂等键(C3,可空)' }
|
||
|
||
StudioAssetContextItem:
|
||
type: object
|
||
required: [category, ref]
|
||
description: 六类素材引用(输入态,对齐 source-project.schema.json assetSpec.category;取代旧 attachments)。后端 asset 节点据此派生 sourceProject.assets[].id(项目内 id)、provider 默认 mmx-cli(§5.5)。
|
||
properties:
|
||
category: { type: string, enum: [sprite, character, effect, scene, ui, music], description: '六类:图元/角色/特效/场景/界面/音乐' }
|
||
ref: { type: string, description: '平台 assetId/ref(主)', example: 'asset_88231' }
|
||
url: { type: string, format: uri, description: '只读镜像 URL(可空)' }
|
||
provider: { type: string, description: '素材来源 provider(可空,默认 mmx-cli;切 provider 不动消费侧,§5.5)', example: 'mmx-cli' }
|
||
|
||
# ---- 素材库按引用登记 请求 VO(R-MAT,U6;上传归属裁定 plan-002)----
|
||
StudioMaterialRegisterReqVO:
|
||
type: object
|
||
required: [category, ref]
|
||
description: >-
|
||
按引用登记素材(字节先经 /infra/file/upload 拿 ref)。studio 不持字节:前端从 infra 上传响应透传 ref/url/size/mime 来此登记。
|
||
后端校验 category∈六类 + 声明 mimeType 与类目族 best-effort 一致(image/* 给图类、audio/* 给 music)。provider 落缺省 mmx-cli。
|
||
properties:
|
||
category: { type: string, enum: [sprite, character, effect, scene, ui, music], description: '六类素材类目' }
|
||
ref: { type: string, description: '平台素材引用 ref(主;来自 /infra/file/upload 返回的访问路径/资源标识)', example: '/infra/file/abc/陨石.png' }
|
||
url: { type: string, format: uri, description: '只读镜像 URL(可空;来自上传响应)' }
|
||
name: { type: string, description: '素材名称(可空,展示用;缺省取类目名)', example: '陨石.png' }
|
||
sizeBytes: { type: integer, format: int64, description: '文件大小(字节,可空;前端从上传响应透传,供配额/审计)', example: 20480 }
|
||
mimeType: { type: string, description: '文件 MIME 类型(可空;前端从上传响应透传,best-effort 校验与类目族一致)', example: 'image/png' }
|
||
|
||
# ---- 素材库选用入草稿 请求 VO(R-MAT,U6)----
|
||
StudioMaterialSelectReqVO:
|
||
type: object
|
||
required: [sessionId, materialIds]
|
||
description: 选用素材入草稿(把本人素材库选中项写入草稿会话 assetContext,取代旧 attachments)
|
||
properties:
|
||
sessionId: { type: integer, format: int64, description: '目标草稿会话 ID(写其 assetContext)', example: 512 }
|
||
materialIds: { type: array, items: { type: integer, format: int64 }, description: '选用的素材 ID 列表(本人素材库)', example: [88231, 88232] }
|
||
|
||
# ========== 响应 VO ==========
|
||
# ---- 素材库浏览项 响应 VO(R-MAT,U6;比输入态 StudioAssetContextItem 多 id + 展示元数据)----
|
||
StudioMaterialRespVO:
|
||
type: object
|
||
description: 素材浏览项(含 id 供选用 + 六类引用四元组 + 名称/大小/MIME/上传时间)
|
||
properties:
|
||
id: { type: integer, format: int64, description: '素材 ID(选用入参 materialIds)', example: 88231 }
|
||
category: { type: string, enum: [sprite, character, effect, scene, ui, music], description: '六类素材类目' }
|
||
ref: { type: string, description: '平台素材引用 ref(喂 assetContext.ref)', example: 'asset_88231' }
|
||
url: { type: string, format: uri, description: '素材访问 URL(只读镜像,可空)' }
|
||
provider: { type: string, description: '素材来源 provider(缺省 mmx-cli)', example: 'mmx-cli' }
|
||
name: { type: string, description: '素材名称(展示用)', example: '陨石.png' }
|
||
sizeBytes: { type: integer, format: int64, description: '文件大小(字节)', example: 20480 }
|
||
mimeType: { type: string, description: '文件 MIME 类型', example: 'image/png' }
|
||
createTime: { type: string, format: date-time, description: '上传时间' }
|
||
StudioTemplateRespVO:
|
||
type: object
|
||
description: 玩法模板(透传 aigc 模板注册表,对齐 aigc.yaml TemplateRespVO)
|
||
properties:
|
||
templateId: { type: string, description: '模板 ID', example: 'dodge' }
|
||
name: { type: string, description: '模板名称', example: '躲避' }
|
||
description: { type: string, description: '模板说明' }
|
||
coverUrl: { type: string, description: '模板封面/示意图 URL' }
|
||
examplePrompt: { type: string, description: '示例 Prompt(P-CRT-11)', example: '做一个躲避陨石的小游戏' }
|
||
|
||
StudioSessionRespVO:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, format: int64, description: '创作会话 ID(sessionId)', example: 1024 }
|
||
gameId: { type: integer, format: int64, description: '移交后的游戏 ID(project.game_project.id)', example: 2048 }
|
||
templateId: { type: string, description: '玩法模板 ID', example: 'idle' }
|
||
title: { type: string, description: '作品标题', example: '我的放置小镇' }
|
||
prompt: { type: string, description: '一句话 Prompt' }
|
||
status: { type: integer, description: '会话状态:0草稿 1生成中 2完成 3失败', example: 0 }
|
||
|
||
StudioTaskChainRespVO:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, format: int64, description: '创作任务链 ID(taskChainId,轮询用)', example: 1024 }
|
||
sessionId: { type: integer, format: int64, description: '所属创作会话 ID', example: 512 }
|
||
aigcTaskId: { type: integer, format: int64, description: '委托的 aigc 生成任务 ID', example: 8888 }
|
||
gameId: { type: integer, format: int64, description: '关联游戏 ID(project.game_project.id)', example: 2048 }
|
||
versionId: { type: integer, format: int64, description: '产物版本 ID(project.game_version.id);完成后非空', example: 4096 }
|
||
status: { type: integer, description: '任务链状态:0初始 1生成中 2完成 3失败', example: 1 }
|
||
progress: { type: integer, description: '进度百分比 0-100(透传 aigc)', example: 60 }
|
||
retryOf: { type: integer, format: int64, description: '若为重生成,指向原任务链 ID(P-CRT-09 血缘)', example: 1000 }
|
||
baseVersionId: { type: integer, format: int64, description: 'modify/extend 血缘:本预览版派生自的 base 版本(create/generate 为空,additive)', example: 4096 }
|
||
|
||
# ========== CommonResult 信封 ==========
|
||
CommonResultStudioTemplateList:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: array, items: { $ref: '#/components/schemas/StudioTemplateRespVO' } }
|
||
msg: { type: string }
|
||
CommonResultStudioSession:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/StudioSessionRespVO' }
|
||
msg: { type: string }
|
||
CommonResultStudioTaskChain:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/StudioTaskChainRespVO' }
|
||
msg: { type: string }
|
||
CommonResultStudioModifyPlan:
|
||
type: object
|
||
description: 判意图返回(A11 M2 建议改动 + 风险)
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/StudioModifyPlanRespVO' }
|
||
msg: { type: string }
|
||
# ---- 素材库 R-MAT 信封(U6)----
|
||
CommonResultStudioAssetContextItem:
|
||
type: object
|
||
description: 上传素材返回(单条六类引用项,喂 assetContext)
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/StudioAssetContextItem' }
|
||
msg: { type: string }
|
||
CommonResultStudioAssetContextItemList:
|
||
type: object
|
||
description: 选用入草稿返回(写入后草稿的完整 assetContext 列表)
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: array, items: { $ref: '#/components/schemas/StudioAssetContextItem' } }
|
||
msg: { type: string }
|
||
CommonResultStudioMaterialPage:
|
||
type: object
|
||
description: 素材浏览分页返回(owner-isolated)
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data:
|
||
type: object
|
||
properties:
|
||
list: { type: array, items: { $ref: '#/components/schemas/StudioMaterialRespVO' } }
|
||
total: { type: integer, format: int64, example: 42 }
|
||
msg: { type: string }
|