Preserve partial creation replies on stream failure
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
kdletters
2026-05-05 11:31:50 +08:00
parent 100fee7e7a
commit 995661e7cc
299 changed files with 13805 additions and 1429 deletions

View File

@@ -0,0 +1,278 @@
# AI 原生方洞挑战玩法创作工具与玩法系统 PRD
更新时间:`2026-05-04`
## 0. 文档目的
这份 PRD 用于在当前平台内新增一条“方洞挑战”玩法类型,并先冻结它从入口占位到完整可创建闭环的产品边界。
本玩法来自参考视频中的核心反差:玩家看到不同形状的积木与多个洞口,会本能判断“形状应放入对应洞口”,但演示不断把不同形状都放进同一个方洞,形成“规则预期被打破”的喜剧张力。
本次不是简单复制视频内容,也不是只新增一个前端小游戏。正式版本需要把这种反直觉机制抽象成平台内可创作、可试玩、可发布的玩法类型。
---
## 1. 一句话定义
“方洞挑战”是一个反直觉形状分拣玩法:百梦主通过 Agent 设定形状主题、洞口规则、误导节奏和反差演出,系统生成一个移动端优先的单局挑战;玩家在限时内把连续出现的形状投入正确洞口,后端根据当前关卡的真实兼容规则裁决成功、失败和连击。
---
## 2. 当前接入级别
根据 `genarrative-play-type-integration` 的接入分级,本次落地到 **完整玩法闭环**
1. 新增玩法 ID`square-hole`
2. 新增展示名称:`方洞挑战`
3. 新增子标题:`反直觉形状分拣`
4. 在新建作品入口、创作类型弹层、结果页、运行态和作品架展示。
5. 支持 Agent 创作、草稿生成、结果页编辑、试玩、发布和公开运行。
6. 后端以 `server-rs + Axum + SpacetimeDB` 为真相源,前端只渲染快照与交互。
不允许把运行规则临时写成前端本地真相,也不复用 `server-node`、Express 或 PostgreSQL。
---
## 3. 产品定位
## 3.1 模板名称
1. 对外模板名称:`方洞挑战`
2. 对外子标题:`反直觉形状分拣`
3. 开发代号:`SquareHole`
4. 工程玩法域:`square-hole`
5. 后端模块命名预期:`square_hole`
## 3.2 核心乐趣
1. 玩家先根据形状轮廓做直觉判断。
2. 关卡通过洞口、提示、视觉遮挡和演出制造误导。
3. 真实规则可以是“方洞万能”“指定洞口万能”“颜色优先于形状”“本轮只看尺寸”等反直觉规则。
4. 玩家通过连续试探和反馈理解规则,形成短局重复挑战。
## 3.3 与现有玩法的区别
1. 不等同于拼图:不切图、不交换、不合并拼块。
2. 不等同于抓大鹅:不做三消备选栏,不做堆叠遮挡点击。
3. 不等同于大鱼吃小鱼:不做摇杆移动、吞噬、成长等级。
4. 不复用 RPG 的世界、角色、章节或剧情推进结构。
5. 运行态只保留“当前形状 + 洞口选择 + 后端裁决”,不在前端写正式规则真相。
---
## 4. 完整闭环目标
本次完整闭环必须补齐:
1. 平台创作入口选择“方洞挑战”。
2. Agent 对话收集玩法锚点。
3. 生成方洞挑战草稿。
4. 进入结果页编辑作品名、标签、封面、形状数量、反差规则和视觉主题。
5. 支持发布前试玩。
6. 发布作品。
7. 玩家从作品详情或广场进入运行态。
8. 后端初始化单局形状队列、洞口兼容规则和计分状态。
9. 玩家拖拽或点击形状投入洞口。
10. 后端裁决投入结果、连击、扣时、失败、胜利和成绩。
11. 前端只渲染后端快照与即时反馈,不承接正式规则真相。
---
## 5. 创作锚点设计
Agent 型创作版本至少收集下面 5 个锚点:
| 锚点 | 字段建议 | 用途 |
| --- | --- | --- |
| 主题外观 | `themePrompt` | 决定玩具、洞板、背景、形状材质和色彩风格。 |
| 反差规则 | `twistRule` | 决定“为什么不是按形状匹配”的真实判定规则。 |
| 洞口组 | `holeSet` | 决定本局出现的洞口种类、数量、位置和视觉误导强度。 |
| 形状队列 | `shapeSequence` | 决定连续出现的形状、颜色、大小和难度递增。 |
| 反馈节奏 | `feedbackRhythm` | 决定成功、错误、连击、惊讶和结算演出风格。 |
Agent 需要把玩家一句灵感收束为上述锚点,不允许逐项盘问低价值字段。
## 5.1 Agent AI 生成契约
方洞挑战的创作对话必须接入 `api-server` 的现有 LLM 能力,不能把用户输入解析成固定模板后直接写回会话。工程实现以 `state.llm_client()` 为唯一模型入口,通过方洞专属 Agent turn 生成回复与下一轮配置。
单轮模型输出必须是严格 JSON
```json
{
"replyText": "",
"progressPercent": 0,
"nextConfig": {
"themeText": "",
"twistRule": "",
"shapeCount": 12,
"difficulty": 4
}
}
```
落地约束:
1. `replyText` 是直接展示给百梦主的中文回复,不得出现 JSON、字段名、内部结构等说明。
2. `nextConfig` 必须是完整配置,不允许只输出 patch缺失字段只能由后端用当前会话配置兜底。
3. `shapeCount` 由后端限制在 `6``24``difficulty` 限制在 `1``10`
4. `quickFillRequested=true` 时,模型应直接补齐剩余配置,后端把 `progressPercent` 固定为 `100`
5. 模型不可用或结果无法解析时,接口返回明确错误,不允许用确定性模板伪装成 AI 回复。
6. 非流式消息接口和 SSE 流式消息接口都必须走同一套方洞 Agent turnSSE 只额外负责把 `replyText` 增量回传。
---
## 6. 运行规则设计
## 6.1 单局结构
1. 单局默认 `60` 秒。
2. 每局默认 `12` 个形状。
3. 洞口数量默认 `4``6` 个。
4. 玩家每次只能操作当前形状。
5. 正确投入后进入下一个形状。
6. 错误投入扣除时间或清空连击。
7. 全部形状完成即胜利。
8. 时间归零即失败。
## 6.2 真实兼容规则
首版可支持下面几类规则:
1. `shape_match`:形状轮廓匹配。
2. `square_hole_priority`:方洞兼容所有形状,其他洞口只作为误导。
3. `color_match`:颜色优先于形状。
4. `size_match`:尺寸优先于形状。
5. `round_prompt`:本轮按后端给出的短提示规则判定。
其中 `square_hole_priority` 是参考视频核心反差的首选默认规则。
## 6.3 前端表现
1. 竖屏优先,桌面端居中显示游戏台。
2. 当前形状位于屏幕下半区域,洞板位于上半区域。
3. 只显示必要状态:剩余时间、连击、当前进度。
4. 不默认展示长篇规则说明。
5. 错误反馈用短促动画、颜色闪烁和轻量文字状态,不堆解释。
6. 点击按钮弹出的配置或结算必须使用独立面板,不在当前面板下方展开。
---
## 7. 后端分层边界
完整实现时必须遵循当前 `server-rs + Axum + SpacetimeDB` 路线:
1. `server-rs/crates/module-square-hole`
- 纯领域规则、形状队列生成、兼容性裁决、分数计算。
- 不依赖 Axum、SpacetimeDB、OSS 或 LLM。
2. `server-rs/crates/shared-contracts`
- 暴露 Agent、作品、运行态 DTO。
3. `server-rs/crates/spacetime-module`
- 存储 session、message、work profile、runtime run。
- 表结构变化必须同步 `migration.rs` 与表目录。
4. `server-rs/crates/spacetime-client`
- 提供 api-server 调用 SpacetimeDB 的 typed facade。
5. `server-rs/crates/api-server`
- 暴露 `/api/creation/square-hole/*``/api/runtime/square-hole/*`
- 处理鉴权、错误 envelope、LLM turn 和 HTTP facade。
---
## 8. 数据模型
## 8.1 创作 session
1. `sessionId`
2. `ownerUserId`
3. `currentTurn`
4. `progressPercent`
5. `stage`
6. `config`
7. `draft`
8. `messages`
9. `lastAssistantReply`
10. `publishedProfileId`
## 8.2 结果页 work profile
1. `workId`
2. `profileId`
3. `ownerUserId`
4. `sourceSessionId`
5. `gameName`
6. `themeText`
7. `twistRule`
8. `summary`
9. `tags`
10. `coverImageSrc`
11. `shapeCount`
12. `difficulty`
13. `publicationStatus`
14. `playCount`
15. `updatedAt`
16. `publishedAt`
## 8.3 运行态 run snapshot
1. `runId`
2. `profileId`
3. `ownerUserId`
4. `status`
5. `snapshotVersion`
6. `startedAtMs`
7. `durationLimitMs`
8. `remainingMs`
9. `totalShapeCount`
10. `completedShapeCount`
11. `combo`
12. `bestCombo`
13. `score`
14. `ruleLabel`
15. `currentShape`
16. `holes`
17. `lastFeedback`
---
## 9. API 设计
## 9.1 创作接口
1. `POST /api/creation/square-hole/sessions`
2. `GET /api/creation/square-hole/sessions/{sessionId}`
3. `POST /api/creation/square-hole/sessions/{sessionId}/messages`
4. `POST /api/creation/square-hole/sessions/{sessionId}/messages/stream`
5. `POST /api/creation/square-hole/sessions/{sessionId}/actions`
6. `POST /api/creation/square-hole/sessions/{sessionId}/compile`
7. `GET /api/creation/square-hole/works`
8. `GET /api/creation/square-hole/works/{profileId}`
9. `PUT /api/creation/square-hole/works/{profileId}`
10. `POST /api/creation/square-hole/works/{profileId}/publish`
11. `DELETE /api/creation/square-hole/works/{profileId}`
## 9.2 运行接口
1. `GET /api/runtime/square-hole/gallery`
2. `GET /api/runtime/square-hole/gallery/{profileId}`
3. `POST /api/runtime/square-hole/works/{profileId}/runs`
4. `GET /api/runtime/square-hole/runs/{runId}`
5. `POST /api/runtime/square-hole/runs/{runId}/drop`
6. `POST /api/runtime/square-hole/runs/{runId}/stop`
7. `POST /api/runtime/square-hole/runs/{runId}/restart`
8. `POST /api/runtime/square-hole/runs/{runId}/time-up`
---
## 10. 验收标准
1. `src/config/newWorkEntryConfig.ts` 中存在 `square-hole` 类型且开放创建。
2. 新建作品入口和创作类型弹层能展示“方洞挑战”。
3. 能进入 `square-hole` Agent 工作台。
4. 能生成草稿并进入结果页。
5. 能编辑结果页并保存、发布。
6. 能从作品详情或广场进入运行态。
7. 能点击或拖拽当前形状投入洞口。
8. 后端裁决命中规则、连击、失败和胜利。
9. 刷新后可恢复作品与运行态快照。
10. `docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md` 记录该入口开放状态。
11. 后端改动完成后必须执行 `npm run api-server:maincloud`,以 `GET /healthz` 返回 `200` 作为主云配置启动 smoke 通过标准,并在 smoke 后清理本次启动进程。