1
This commit is contained in:
@@ -192,6 +192,7 @@ npm run dev:rust
|
||||
1. 资源 URL 不再是 `/generated-big-fish/...`
|
||||
2. 而是 `/generated-big-fish-assets/...`
|
||||
3. 结果页状态显示为 `已生成`,而不是 `占位已生成`
|
||||
4. `Lv.x 主图` 与 `idle_float / move_swim` 正式图若下载结果为 PNG,后端会在写 OSS 前复用 RPG 角色主图透明背景 alpha 后处理;`生成背景` 不走该处理
|
||||
|
||||
### 7.2 Custom World 场景图
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 大鱼吃小鱼草稿进度与会话超时兜底修复 2026-04-28
|
||||
|
||||
## 背景
|
||||
|
||||
大鱼吃小鱼在 `2026-04-28` 完成草稿结构化升级后,结果页草稿已经不再是单纯模板壳,而是会生成等级文本、形象描述、动作描述与运行参数。
|
||||
|
||||
但当前链路仍暴露出两个直接体验问题:
|
||||
|
||||
1. 前端草稿进度页仍把大鱼吃小鱼展示成单个 `compile` 步骤,用户会感觉“整个生成过程只有一步,而且一直卡在第一步”。
|
||||
2. 前端在打开大鱼草稿或结果页时,会通过 `GET /api/runtime/big-fish/agent/sessions/:sessionId` 拉取完整会话;当 Maincloud 上游偶发抖动时,Rust `spacetime-client` 统一 10 秒超时会直接映射成 `502`,用户会看到反复报错。
|
||||
|
||||
## 修复口径
|
||||
|
||||
### 1. 草稿进度页改为多阶段感知
|
||||
|
||||
大鱼吃小鱼的 `big_fish_compile_draft` 仍然保持为一次后端 compile action,不拆成多个新的后端接口。
|
||||
|
||||
但前端进度读模型不再把它渲染成单步,而是拆成下面三段:
|
||||
|
||||
1. `整理玩法骨架`
|
||||
- 收拢玩法承诺、成长阶梯与风险节奏。
|
||||
2. `编译等级蓝图`
|
||||
- 生成每级角色描述、形象描述与动作描述。
|
||||
3. `校准场地与参数`
|
||||
- 整理背景蓝图与运行参数,准备结果页。
|
||||
|
||||
这样做的边界是:
|
||||
|
||||
1. 不把动作正式出图重新塞回 compile action。
|
||||
2. 只增强生成中的阶段反馈,不改动现有结果页资产工坊分工。
|
||||
3. 进度阶段属于前端展示语义,不要求后端额外维护细粒度 procedure 状态。
|
||||
|
||||
### 2. 会话读取增加短重试与超时语义收口
|
||||
|
||||
大鱼会话读取现在补充两层守卫:
|
||||
|
||||
1. `api-server` 在读取大鱼 session 时,对 `SpacetimeClientError::Timeout` 和 `SpacetimeClientError::ConnectDropped` 做一次短重试。
|
||||
2. 若最终仍然超时,则错误状态码从泛化 `502` 收口为更准确的 `504 Gateway Timeout`。
|
||||
|
||||
这样可以覆盖两类常见情况:
|
||||
|
||||
1. Maincloud 连接偶发抖动,第一次 procedure 超时但第二次马上恢复。
|
||||
2. 用户打开草稿页时碰到短暂断链,不再被立即判定成稳定的坏网关故障。
|
||||
|
||||
## 落地范围
|
||||
|
||||
1. `src/services/miniGameDraftGenerationProgress.ts`
|
||||
2. `src/services/miniGameDraftGenerationProgress.test.ts`
|
||||
3. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
|
||||
4. `server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
## 验收口径
|
||||
|
||||
1. 用户点击大鱼吃小鱼“生成草稿”后,进度页至少能看到三个结构化阶段,而不是单个 compile 步骤。
|
||||
2. 这三个阶段都只描述草稿编译,不出现“生成动作素材”之类结果页资产动作。
|
||||
3. `GET /api/runtime/big-fish/agent/sessions/:sessionId` 遇到短暂 SpacetimeDB 抖动时,会先做一次短重试。
|
||||
4. 如果最终仍超时,接口返回语义应体现为超时,而不是继续统一落成泛化 `502`。
|
||||
@@ -0,0 +1,82 @@
|
||||
# 大鱼吃小鱼角色主图透明背景后处理对齐说明 2026-04-28
|
||||
|
||||
## 背景
|
||||
|
||||
当前大鱼吃小鱼的等级主图与动作关键帧 prompt 已经明确要求“按 RPG 角色资产口径生成透明背景”,但正式图片链实际仍主要依赖供应商出图结果本身。
|
||||
|
||||
这会带来一个问题:
|
||||
|
||||
1. prompt 约束只能提高透明背景命中率,不能保证每次都没有残留底色。
|
||||
2. RPG 角色主图链已经在 Rust 后端落了一层 PNG alpha 后处理,大鱼链没有对齐,导致两条“角色主图口径”资产在最终成品一致性上仍有差异。
|
||||
|
||||
## 本次目标
|
||||
|
||||
把“大鱼吃小鱼生成的角色主图后处理流程”对齐到 RPG 角色主图链:
|
||||
|
||||
1. 等级主图正式图生成后,若下载结果为 PNG,则复用 RPG 现有透明背景 alpha 后处理。
|
||||
2. `idle_float` / `move_swim` 动作关键帧静态图同样复用这套处理。
|
||||
3. 场地背景图不走这套处理,避免误把 9:16 场景背景做成透明底。
|
||||
|
||||
## 落地方案
|
||||
|
||||
### 1. 复用 RPG 透明背景后处理能力
|
||||
|
||||
`server-rs/crates/api-server/src/character_visual_assets.rs`
|
||||
|
||||
冻结现有 `try_apply_background_alpha_to_png(...)` 为 `pub(crate)` 复用入口,继续由 RPG 主图链维护这套“绿底/白底/软边缘”透明背景清理逻辑。
|
||||
|
||||
### 2. Big Fish 正式图链按资产类型决定是否启用后处理
|
||||
|
||||
`server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
在 `BigFishFormalAssetContext` 中新增:
|
||||
|
||||
1. `apply_transparent_background_post_process`
|
||||
|
||||
映射规则如下:
|
||||
|
||||
1. `level_main_image`:`true`
|
||||
2. `level_motion`:`true`
|
||||
3. `stage_background`:`false`
|
||||
|
||||
### 3. 下载完成后、写 OSS 前执行统一处理
|
||||
|
||||
`download_big_fish_remote_image(...)` 新增布尔开关参数。
|
||||
|
||||
当满足以下条件时执行后处理:
|
||||
|
||||
1. 当前资产槽位需要透明背景后处理
|
||||
2. 上游下载结果 `mime_type == image/png`
|
||||
|
||||
执行顺序冻结为:
|
||||
|
||||
1. DashScope 出图
|
||||
2. 下载远端 PNG
|
||||
3. 复用 RPG `try_apply_background_alpha_to_png(...)`
|
||||
4. 再写入 Big Fish 正式 OSS 对象
|
||||
5. 确认 `asset_object`
|
||||
6. 绑定到 Big Fish 槽位
|
||||
|
||||
## 为什么这样做
|
||||
|
||||
1. 这次需求说的是“生成后处理流程和 RPG 角色主图一致”,因此不能只继续加强 prompt,必须把后处理链对齐。
|
||||
2. 直接复用 RPG 已有实现,比在 Big Fish 再复制一份抠图算法更稳,也更符合仓库“默认复用现有系统”的约束。
|
||||
3. 背景图是环境资产,不属于“角色主图口径”,如果也启用透明背景后处理,会造成错误裁底风险。
|
||||
|
||||
## 验收口径
|
||||
|
||||
1. 在 Big Fish 结果页点击 `生成并应用正式图 -> Lv.x 主图` 后,若 DashScope 返回 PNG,正式落库前会执行和 RPG 主图相同的透明背景 alpha 处理。
|
||||
2. 在 Big Fish 动作工坊点击 `生成并应用正式图` 后,`idle_float` / `move_swim` 的静态关键帧图同样执行该处理。
|
||||
3. `生成背景` 仍保持完整场景图,不走透明背景后处理。
|
||||
4. 编码检查通过,Rust `api-server` 定向编译通过。
|
||||
|
||||
## 影响范围
|
||||
|
||||
1. `server-rs/crates/api-server/src/character_visual_assets.rs`
|
||||
2. `server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
## 风险与边界
|
||||
|
||||
1. 当前后处理只在下载结果本身是 PNG 时生效;若供应商返回 JPEG/WebP,则仍按原始格式入库。
|
||||
2. 本次不新增新的 Big Fish 专属抠图算法,不改变 DashScope prompt 和 OSS 绑定协议。
|
||||
3. 本次不修改 SpacetimeDB schema,也不涉及 `migration.rs` 变更。
|
||||
126
docs/technical/BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md
Normal file
126
docs/technical/BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 大鱼吃小鱼提示词脚本拆分 2026-04-28
|
||||
|
||||
## 背景
|
||||
|
||||
大鱼吃小鱼当前在 `server-rs/crates/api-server/src/big_fish.rs` 与 `server-rs/crates/api-server/src/big_fish_agent_turn.rs` 中同时承载了三类不同职责的提示词:
|
||||
|
||||
1. Agent 聊天阶段的草稿生成提示词。
|
||||
2. 结果页主图 / 生图提示词。
|
||||
3. 结果页动作关键帧提示词。
|
||||
|
||||
这会带来两个直接问题:
|
||||
|
||||
1. 聊天共创脚本和正式资产脚本混在路由业务文件中,后续继续调词时很容易顺手改到状态编排逻辑。
|
||||
2. 大鱼吃小鱼已经明确要求“草稿编译”和“结果页资产工坊”分离,如果提示词仍散落在业务实现里,后续很容易再次把动作资产逻辑误塞回 compile action。
|
||||
|
||||
## 本轮目标
|
||||
|
||||
把下面三类提示词显式拆到独立 prompt 脚本中:
|
||||
|
||||
1. 草稿生成提示词。
|
||||
2. 生图提示词。
|
||||
3. 动作提示词。
|
||||
|
||||
并保持以下边界不变:
|
||||
|
||||
1. 不改变 Big Fish 的会话表、草稿表、资产表结构。
|
||||
2. 不改变 compile action 只编译草稿、不串行生成资产的现有口径。
|
||||
3. 不改写当前中文提示词语义,只做脚本落位和调用收口。
|
||||
|
||||
## 落位方案
|
||||
|
||||
新增文件:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/prompt/big_fish.rs
|
||||
```
|
||||
|
||||
该文件统一收口:
|
||||
|
||||
1. `BIG_FISH_AGENT_SYSTEM_PROMPT`
|
||||
2. `build_big_fish_agent_prompt(...)`
|
||||
3. `build_big_fish_level_main_image_prompt(...)`
|
||||
4. `build_big_fish_level_motion_prompt(...)`
|
||||
5. `build_big_fish_stage_background_prompt(...)`
|
||||
6. `BIG_FISH_DEFAULT_NEGATIVE_PROMPT`
|
||||
7. `BIG_FISH_TRANSPARENT_ASSET_NEGATIVE_PROMPT`
|
||||
|
||||
同时把 `prompt/mod.rs` 补齐为正式导出入口,和现有:
|
||||
|
||||
1. `puzzle_image.rs`
|
||||
2. `character_visual.rs`
|
||||
3. `character_animation.rs`
|
||||
4. `scene_background.rs`
|
||||
|
||||
保持同一层级。
|
||||
|
||||
## 调用边界
|
||||
|
||||
### 1. 草稿生成
|
||||
|
||||
`server-rs/crates/api-server/src/big_fish_agent_turn.rs`
|
||||
|
||||
改为只负责:
|
||||
|
||||
1. 调用公共 LLM turn 执行器。
|
||||
2. 解析 `replyText / progressPercent / nextAnchorPack`。
|
||||
3. 组装 finalize input。
|
||||
|
||||
不再内联维护大段 system prompt / output contract / chat prompt 拼接逻辑。
|
||||
|
||||
### 2. 生图与动作
|
||||
|
||||
`server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
改为只负责:
|
||||
|
||||
1. 读取当前 session 与 draft。
|
||||
2. 根据 `asset_kind` 构造正式资产上下文。
|
||||
3. 调用 DashScope 出图。
|
||||
4. 下载、后处理、持久化并写入资产绑定。
|
||||
|
||||
主图、动作关键帧、背景图的正式提示词脚本都从 `crate::prompt::big_fish` 引入,不再内联在路由业务脚本中。
|
||||
|
||||
## 为什么三类脚本要继续分开
|
||||
|
||||
### 草稿生成提示词
|
||||
|
||||
它的职责是把玩法灵感收束成:
|
||||
|
||||
1. 玩法承诺
|
||||
2. 生态视觉主题
|
||||
3. 成长阶梯
|
||||
4. 风险节奏
|
||||
|
||||
它面向的是 LLM 的结构化共创,不面向图片模型。
|
||||
|
||||
### 生图提示词
|
||||
|
||||
它的职责是把已经落库的等级蓝图翻译成“单体鱼形主图”的正式图片提示词。
|
||||
|
||||
它面向的是透明背景主体资产,需要强调:
|
||||
|
||||
1. 单体主体
|
||||
2. 透明背景
|
||||
3. 中心构图
|
||||
4. 不出现 UI / 场景 / 多主体
|
||||
|
||||
### 动作提示词
|
||||
|
||||
它的职责是把等级蓝图和动作槽位翻译成“静态关键帧预览图”的正式图片提示词。
|
||||
|
||||
它和主图区别在于:
|
||||
|
||||
1. 需要显式带入 `motion_key`
|
||||
2. 需要区分 `idle_float / move_swim`
|
||||
3. 需要强调动作方向和关键帧姿态
|
||||
|
||||
因此不能继续复用同一段文本拼接后靠 if 分支临时改句子。
|
||||
|
||||
## 本轮验收
|
||||
|
||||
1. 大鱼吃小鱼草稿生成提示词已从 `big_fish_agent_turn.rs` 抽离。
|
||||
2. 大鱼吃小鱼主图、动作、背景提示词已从 `big_fish.rs` 抽离。
|
||||
3. 路由业务文件只保留编排、鉴权、调用与错误映射职责。
|
||||
4. 新增 prompt 文件具备最小测试覆盖。
|
||||
5. `npm run check:encoding` 通过,确保新增中文文档与 Rust 注释未被写坏。
|
||||
@@ -0,0 +1,63 @@
|
||||
# 创作页公开广场与 Agent 恢复指针兜底修复 2026-04-28
|
||||
|
||||
## 1. 问题现象
|
||||
|
||||
浏览器控制台同时出现两类请求错误:
|
||||
|
||||
1. `GET /api/runtime/custom-world/agent/sessions/:sessionId` 返回 `404`。
|
||||
2. `GET /api/runtime/big-fish/gallery` 返回 `400`。
|
||||
|
||||
第一类错误发生在平台页尝试恢复 RPG / Custom World Agent 旧工作区时。旧 URL 或旧 sessionStorage 指针里可能只有 `customWorldSessionId`,没有本机保存的 `ownerUserId`,登录后前端仍会直接读取受保护 session,后端按 `owner_user_id + session_id` 查不到后返回 `404`。
|
||||
|
||||
第二类错误发生在首页读取大鱼吃小鱼公开广场时。公开广场是平台首屏的可选展示数据,即使 SpacetimeDB procedure 暂未就绪、连接短暂断开或旧环境缺少对应 procedure,也不应该阻断平台主界面。
|
||||
|
||||
## 2. 落地原则
|
||||
|
||||
1. URL 中的 `customWorldSessionId` 只用于深链恢复,不作为鉴权凭据。
|
||||
2. 受保护 Agent session 恢复必须能确认本机 `ownerUserId` 与当前登录用户一致。
|
||||
3. 未登录状态仍保留登录弹窗流程,不提前丢弃深链;登录完成后若仍无法确认归属,再清空恢复指针。
|
||||
4. Big Fish 公开广场只展示 `published` 作品;读取失败时允许空态降级,不把错误写成 UI 主错误。
|
||||
5. 私有作品列表、会话详情、发布、删除仍保持严格错误,不复用公开广场的软降级策略。
|
||||
|
||||
## 3. 本次修改
|
||||
|
||||
### 3.1 RPG Agent 恢复指针
|
||||
|
||||
`src/services/customWorldAgentUiState.ts` 读取 URL query 时,会尝试从 sessionStorage 中匹配同一个 `activeSessionId` 的 `ownerUserId`。
|
||||
|
||||
如果 URL 指针和本机存储匹配:
|
||||
|
||||
1. 返回 `activeSessionId`。
|
||||
2. 同时带回本机 `ownerUserId`。
|
||||
|
||||
如果 URL 指针没有对应本机归属:
|
||||
|
||||
1. 只返回 session 指针。
|
||||
2. 登录后 `useRpgCreationSessionController` 会清空指针。
|
||||
3. 不调用 `getRpgCreationSession()`,避免向后端发起必然 404 的失效恢复请求。
|
||||
|
||||
### 3.2 Big Fish 公开广场
|
||||
|
||||
前端 `listBigFishGallery()` 对 `400 / 404` 返回 `{ items: [] }`,让平台首页可以继续渲染空广场。
|
||||
|
||||
Rust `api-server` 的 `list_big_fish_gallery()` 对以下 SpacetimeDB 读取问题做服务端空态降级:
|
||||
|
||||
1. `SpacetimeClientError::Runtime(_)`
|
||||
2. `SpacetimeClientError::ConnectDropped`
|
||||
3. 明确指向 `list_big_fish_works` procedure 缺失或不可用的 procedure 错误
|
||||
|
||||
服务端会保留 `warn` 日志,便于部署环境继续排查 schema / publish 状态。`Timeout` 不降级,仍按网关超时暴露,避免长时间卡死被误认为正常空广场。
|
||||
|
||||
## 4. 验收标准
|
||||
|
||||
1. 已登录用户打开只带旧 `customWorldSessionId`、但本机没有匹配 `ownerUserId` 的页面时,不再请求 `GET /api/runtime/custom-world/agent/sessions/:sessionId`。
|
||||
2. 未登录用户打开带 `customWorldSessionId` 的深链时,仍先打开登录弹窗。
|
||||
3. Big Fish 公开广场返回 `400 / 404` 时,前端展示空列表,不把“读取大鱼吃小鱼广场失败”写入主错误态。
|
||||
4. 服务端遇到 Big Fish gallery 可降级 SpacetimeDB 错误时返回成功 envelope,`items` 为空,并记录 warn 日志。
|
||||
|
||||
## 5. 回归范围
|
||||
|
||||
1. `src/services/customWorldAgentUiState.test.ts`
|
||||
2. `src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`
|
||||
3. `src/services/big-fish-gallery/bigFishGalleryClient.test.ts`
|
||||
4. `cargo test -p api-server big_fish_gallery`
|
||||
@@ -2,14 +2,27 @@
|
||||
|
||||
## 背景
|
||||
|
||||
RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进度页,并在该页展示生成链路的阶段、锚点与最终草稿内容。拼图与大鱼吃小鱼此前点击“生成结果页”后直接跳到结果页,正式图片、动作与背景仍分散在结果页工坊里逐个生成,导致用户无法看到“正在一次性准备完整草稿”的过程。
|
||||
RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进度页,并在该页展示生成链路的阶段、锚点与最终草稿内容。拼图与大鱼吃小鱼此前点击“生成结果页”后直接跳到结果页,缺少一个明确的“草稿编译中”过渡态。
|
||||
|
||||
但在 `2026-04-28` 的大鱼吃小鱼链路修正后,产品口径进一步收紧为:
|
||||
|
||||
1. 拼图仍然保留“生成草稿时一并补齐结果页主资产”的收口方式。
|
||||
2. 大鱼吃小鱼的“生成草稿”只负责把玩法锚点编译成结果页草稿。
|
||||
3. 大鱼吃小鱼的主图、动作、背景都留在结果页工坊按需生成,不再塞进草稿编译动作里串行执行。
|
||||
|
||||
这样做的原因是:
|
||||
|
||||
1. 大鱼吃小鱼草稿阶段的核心目标是先稳定产出等级蓝图、背景蓝图和运行参数,而不是在这一刻把整套资产都做完。
|
||||
2. 动作素材生成耗时最长,把它塞进草稿 action 会让用户长时间停留在首步等待态,形成“卡在第一步”的体感。
|
||||
3. 草稿阶段不需要配置动作,动作应当属于结果页资产精修阶段。
|
||||
|
||||
## 落地边界
|
||||
|
||||
- 前端只负责展示生成进度与触发已有后端动作,不新增 server-node 或 PostgreSQL 链路。
|
||||
- 后端继续沿用 `server-rs` + SpacetimeDB 的会话、草稿与资产写入能力;“一次性生成所有需要的东西”必须由 `server-rs` 的 compile action 承担,前端只发起一次 action 并展示进度页。
|
||||
- 拼图生成草稿链路必须包含:结果页草稿、候选图生成、正式图确认。
|
||||
- 大鱼吃小鱼生成草稿链路必须包含:玩法草稿、关卡主图、动作素材、场地背景。
|
||||
- 后端继续沿用 `server-rs` + `SpacetimeDB` 的会话、草稿与资产写入能力。
|
||||
- 拼图生成草稿链路仍包含:结果页草稿、候选图生成、正式图确认。
|
||||
- 大鱼吃小鱼生成草稿链路只包含:玩法草稿、等级蓝图、背景蓝图与运行参数编译。
|
||||
- 大鱼吃小鱼的主图、动作、背景都在结果页工坊单独触发,不再属于草稿编译阶段。
|
||||
- 生成过程中展示的“角色描述、角色图片、动作”等,统一映射为锚点、草稿蓝图与资产步骤,不把规则说明类文本写成默认 UI 文案。
|
||||
|
||||
## 交互设计
|
||||
@@ -17,8 +30,9 @@ RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进
|
||||
1. 用户在拼图或大鱼吃小鱼 Agent 工作区点击生成按钮。
|
||||
2. 页面立即切换到独立生成进度页,同时只向 `server-rs` 发起一次 compile action,返回按钮在生成中禁用,避免中途回退造成状态漂移。
|
||||
3. 进度页左侧展示阶段进度、步骤卡片与错误信息;右侧展示当前锚点与已成形的草稿结构。
|
||||
4. 全量生成成功后自动进入对应结果页,结果页直接展示已生成的资产。
|
||||
5. 生成失败时停留在进度页,用户可返回工作区补充设定,或点击重试重新执行完整草稿链路。
|
||||
4. 生成成功后自动进入对应结果页。
|
||||
5. 拼图结果页直接展示已生成的正式图;大鱼结果页则展示刚编译完成的玩法草稿,后续资产由结果页工坊继续生成。
|
||||
6. 生成失败时停留在进度页,用户可返回工作区补充设定,或点击重试重新执行完整草稿链路。
|
||||
|
||||
## 阶段映射
|
||||
|
||||
@@ -32,11 +46,14 @@ RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进
|
||||
### 大鱼吃小鱼
|
||||
|
||||
- `big_fish_compile_draft`:在 `server-rs` 内生成玩法草稿、关卡角色描述、背景蓝图与运行参数。
|
||||
- `big_fish_compile_draft`:同一次后端 action 内按每个关卡生成主角色/鱼群图片。
|
||||
- `big_fish_compile_draft`:同一次后端 action 内按每个关卡生成 `idle_float` 与 `move_swim` 动作素材。
|
||||
- `big_fish_compile_draft`:同一次后端 action 内生成玩法场地背景。
|
||||
- `ready`:进入大鱼吃小鱼结果页。
|
||||
|
||||
补充冻结:
|
||||
|
||||
- 大鱼吃小鱼草稿阶段不展示“生成动作素材”步骤。
|
||||
- `big_fish_generate_level_main_image`、`big_fish_generate_level_motion`、`big_fish_generate_stage_background` 继续保留为结果页中的独立资产动作。
|
||||
- 如果后续需要扩展大鱼草稿生成进度,也只能扩展“草稿结构编译”相关阶段,不能再把动作生成塞回 compile action。
|
||||
|
||||
## 前端流程收口
|
||||
|
||||
- 拼图与大鱼吃小鱼共用 `usePlatformCreationAgentFlowController` 管理会话、流式回复、忙碌态、错误态和草稿恢复,页面层不再重复手写两套 submit/action 流程。
|
||||
@@ -48,8 +65,10 @@ RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进
|
||||
## 验收点
|
||||
|
||||
- 拼图和大鱼吃小鱼点击生成草稿后不再直接停留在聊天工作区等待。
|
||||
- 生成中可看到独立进度页,且进度步骤随 action 完成逐步推进。
|
||||
- 拼图结果页打开时已有正式图;大鱼结果页打开时主图、动作和背景资产均已写入 `assetSlots`。
|
||||
- 前端点击生成草稿时不串行调用多个资产 action;多阶段业务编排收敛在 `server-rs`。
|
||||
- 生成中可看到独立进度页。
|
||||
- 拼图结果页打开时已有正式图。
|
||||
- 大鱼结果页打开时至少已有完整玩法草稿,不要求主图、动作和背景资产在草稿阶段写入 `assetSlots`。
|
||||
- 大鱼吃小鱼草稿生成进度中不再出现“生成动作素材”步骤。
|
||||
- 前端点击生成草稿时不串行调用多个大鱼资产 action;大鱼资产生成留在结果页独立触发。
|
||||
- 返回 Agent 工作区后,聊天区不出现“拼图结果页草稿已生成。”“本级主图已正式生成,可在结果页继续预览。”这类生成进度页状态消息。
|
||||
- 不新增 server-node 依赖,不复活 legacy public 静态资产路径。
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md](./RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md):冻结 RPG 提示词禁止存在前端的边界,明确前端只保留 API client,角色私聊/NPC 对话/剧情续写等 prompt 统一收口到 `server-rs`。
|
||||
- [RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md](./RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md):冻结 RPG 创作结果页保存、Agent session/result preview 真相优先级和结果页入口裁决迁移到后端 result-view 的落地边界。
|
||||
- [RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md](./RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md):记录 RPG 创作 profile 生成移除非浏览器 legacy AI 回退,统一通过 `server-rs` 的 `/api/runtime/custom-world/profile` 生成世界底稿。
|
||||
- [CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md](./CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md):记录 RPG Agent 旧 URL 恢复指针必须有本机用户归属才读取受保护 session,以及 Big Fish 公开广场读取失败按空广场降级的修复口径。
|
||||
- [BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md](./BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md):记录大鱼吃小鱼草稿进度页从单步 compile 改为多阶段感知展示,以及大鱼会话读取在 Maincloud 抖动时增加短重试与超时语义收口的修复口径。
|
||||
- [BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md](./BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md):记录大鱼吃小鱼草稿生成、生图、动作三类提示词从业务脚本中抽离到独立 `prompt/big_fish.rs` 模块的边界与职责划分。
|
||||
- [BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md](./BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md):记录大鱼吃小鱼等级主图与动作关键帧正式图在 Rust 后端复用 RPG 角色主图透明背景 alpha 后处理的对齐口径,并明确场地背景不走该处理。
|
||||
- [PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md](./PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md):记录拼图结果页名称与标签编辑自动保存、发布门槛统一到 `3~6` 标签,以及前端发布校验不再被旧 session blocker 卡死的修复口径。
|
||||
- [SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md](./SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md):记录发布包 `start.sh` 只输出“SpacetimeDB 进程在就绪前退出”时的诊断补强,启动失败或超时时自动回显 `logs/spacetimedb.log`、`server ping`、端口监听和 root-dir 相关进程。
|
||||
- [RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md](./RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md):记录 RPG 运行时 NPC 聊天、RPG/自定义世界 Agent 与大鱼 Agent 从“拼完整 SSE 字符串后一次性返回”改为 `mpsc + Sse<Event>` 真流式输出的后端落地口径。
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# RPG 创作 profile 生成后端迁移(2026-04-28)
|
||||
|
||||
## 1. 背景
|
||||
|
||||
`docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 的 5.3 指出,`src/services/rpg-creation/rpgCreationGenerationClient.ts` 在非浏览器环境仍会动态 `import('../ai')`,让 RPG 创作 profile 生成继续保留前端 legacy AI 后门。
|
||||
|
||||
这与当前边界冲突:
|
||||
|
||||
1. 前端只负责表现和 API client。
|
||||
2. RPG 创作 prompt 与 LLM 编排只能在 `server-rs/crates/api-server/src/prompt/rpg/` 与 `api-server` 侧出现。
|
||||
3. 外部 LLM 调用不能进入 SpacetimeDB reducer,必须由 Axum / `platform-llm` 完成后再把确定结果交给后续持久化链。
|
||||
|
||||
## 2. 本轮落地
|
||||
|
||||
### 2.1 前端
|
||||
|
||||
`src/services/rpg-creation/rpgCreationGenerationClient.ts` 现在不再判断 `typeof window`,也不再动态导入 `src/services/ai.ts`。
|
||||
|
||||
无论浏览器、SSR 还是 Vitest node 环境,`generateRpgWorldProfile(...)` 都只调用:
|
||||
|
||||
```text
|
||||
POST /api/runtime/custom-world/profile
|
||||
```
|
||||
|
||||
测试如需离线运行,应 mock `requestJson`,不能恢复本地 AI 生成链。
|
||||
|
||||
### 2.2 后端
|
||||
|
||||
`server-rs/crates/api-server/src/app.rs` 新增:
|
||||
|
||||
```text
|
||||
POST /api/runtime/custom-world/profile
|
||||
```
|
||||
|
||||
handler 落在 `server-rs/crates/api-server/src/custom_world.rs`:
|
||||
|
||||
1. 校验 `settingText`。
|
||||
2. 要求 Bearer 鉴权。
|
||||
3. 要求 `platform-llm` 可用。
|
||||
4. 复用 `generate_custom_world_foundation_draft(...)` 生成 profile 草稿。
|
||||
5. 补齐结果页需要的 `id / settingText / templateWorldType / compatibilityTemplateWorldType / items / generationMode / generationStatus / creatorIntent`。
|
||||
6. 直接返回 `CustomWorldProfile` JSON,保持前端旧 client contract 不变。
|
||||
|
||||
本轮不新增 SpacetimeDB 表,不修改 `migration.rs`。
|
||||
|
||||
## 3. 验收
|
||||
|
||||
1. `src/services/rpg-creation/**` 不再出现 `import('../ai')`、`LegacyAiModule`、`loadLegacyAiModule`。
|
||||
2. `src/services/rpg-creation/index.ts` 不再导出 `generateLegacyCustomWorldProfile`。
|
||||
3. node 环境测试确认 profile 生成只走 `requestJson` mock。
|
||||
4. Rust `api-server` 测试确认 `/api/runtime/custom-world/profile` 未登录返回 `401`。
|
||||
@@ -0,0 +1,82 @@
|
||||
# RPG 创作结果页后端真相视图迁移方案(2026-04-28)
|
||||
|
||||
## 1. 本次落地边界
|
||||
|
||||
本次只迁移 `RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 中 5.4 对应链路:
|
||||
|
||||
1. 创作结果页自动保存前的 profile normalize 与 session 同步顺序。
|
||||
2. Agent session / result preview / legacyResultProfile 的真相优先级。
|
||||
3. 作品草稿点击后应进入 Agent workspace、生成过程页还是结果页的裁决。
|
||||
|
||||
不在本轮处理运行时 GameState、战斗、NPC、背包和锻造规则。
|
||||
|
||||
## 2. 后端读模型
|
||||
|
||||
新增稳定读模型:
|
||||
|
||||
```text
|
||||
GET /api/runtime/custom-world/agent/sessions/:sessionId/result-view
|
||||
```
|
||||
|
||||
响应字段:
|
||||
|
||||
1. `session`:最新 Agent session snapshot。
|
||||
2. `profile`:服务端按优先级选出的结果页 profile。
|
||||
3. `profileSource`:`result_preview` / `draft_profile` / `none`。
|
||||
4. `targetStage`:前端应打开的 stage。
|
||||
5. `generationViewSource` / `resultViewSource`:前端视图来源。
|
||||
6. `canAutosaveLibrary`:作品库自动保存是否可执行。
|
||||
7. `canSyncResultProfile`:结果页编辑是否允许回写 session。
|
||||
8. `recoveryAction`:缺失或失败时的恢复指令。
|
||||
|
||||
## 3. 真相优先级
|
||||
|
||||
服务端统一执行以下优先级,前端不再自己解释:
|
||||
|
||||
1. 首选 `session.resultPreview.preview`。
|
||||
2. 若没有 result preview,但 `draftProfile` 是已可打开结果页的完整 profile,则使用 `draftProfile`。
|
||||
3. `draftProfile.legacyResultProfile` 只作为后端兼容恢复来源,不再由前端直接读取。
|
||||
4. 没有可用 profile 时,服务端返回 `targetStage` 指示前端回生成过程页或 Agent workspace。
|
||||
|
||||
## 4. 保存链路
|
||||
|
||||
结果页编辑仍允许前端持有临时表单态,但保存必须按顺序:
|
||||
|
||||
1. 前端调用 `sync_result_profile` action,把编辑后的 profile 写回 Agent session。
|
||||
2. 前端读取 `result-view`,以服务端返回的 `profile` 刷新界面。
|
||||
3. 自动保存作品库只保存 `result-view.profile`,不再自己决定 session/profile 优先级。
|
||||
4. Agent 结果页保存成功后,作品库响应只刷新列表、详情与自动保存签名;当前编辑界面仍以 `result-view.profile` 为准,避免兼容响应缺少角色、地标等完整字段时覆盖正在编辑的结果页。
|
||||
|
||||
### 4.1 保存前 profile canonicalize
|
||||
|
||||
`creatorIntent -> settingText` 的保存前归一必须在后端执行:
|
||||
|
||||
1. `sync_result_profile` action 入站时,后端基于 `payload.profile.creatorIntent` 生成 canonical `settingText` 后再写入 Agent session 与 `resultPreview`。
|
||||
2. `PUT /api/runtime/custom-world-library/:profileId` 入站时,后端对 `payload.profile` 执行同一规则后再抽取 metadata 与写入作品库。
|
||||
3. 前端结果页、作品详情页、平台壳层只能保存用户当前编辑草稿,不再调用 `normalizeRpgEntryAgentBackedProfile(...)` 改写正式字段。
|
||||
4. 前端自动保存去重签名使用草稿 JSON 本身;保存成功后以服务端返回的 canonical entry/result-view 刷新界面。
|
||||
|
||||
该规则的唯一语义是:当 `creatorIntent` 含有有效锚点时,按“世界一句话 / 玩家开局 / 主题气质 / 核心冲突 / 关键关系 / 标志元素”的固定顺序生成 foundation text,并覆盖保存入库或 session 的 `settingText`。没有有效锚点时不改写用户草稿。
|
||||
|
||||
## 5. 前端职责
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 页面切换。
|
||||
2. loading / error / autosave 状态。
|
||||
3. 用户正在编辑的临时 profile。
|
||||
4. 调用后端 action 和 result-view。
|
||||
|
||||
前端禁止继续:
|
||||
|
||||
1. 直接读取 `draftProfile.legacyResultProfile`。
|
||||
2. 自行判断草稿应打开 Agent workspace、生成过程页还是结果页。
|
||||
3. 自动保存前只刷新 session 后用 session 旧快照覆盖本地编辑。
|
||||
|
||||
## 6. 验收
|
||||
|
||||
1. `rpgCreationPreviewAdapter` 不再读取 `legacyResultProfile`。
|
||||
2. `useRpgCreationResultAutosave` 对 Agent 草稿结果页会先执行 `sync_result_profile`,再读取后端 result-view。
|
||||
3. `useRpgEntryLibraryDetail` 根据 result-view 的 `targetStage` 切页。
|
||||
4. 测试覆盖编辑后不会被旧 session 覆盖、无 result preview 时由后端决定恢复入口。
|
||||
5. 测试覆盖 `sync_result_profile` 与作品库 upsert 入站时由后端 canonicalize `settingText`,前端 autosave 不再保存前 normalize。
|
||||
@@ -0,0 +1,125 @@
|
||||
# RPG 选项函数与提示词编辑面整理方案(2026-04-28)
|
||||
|
||||
## 背景
|
||||
|
||||
当前 RPG 运行时已经把不少选项 function 的定义拆到了 `src/data/functionCatalog/`,但仍存在两个影响编辑效率的问题:
|
||||
|
||||
1. `src/data/stateFunctions.ts` 里还残留一批按 `functionId` 分支的运行时文案、优先级与细节逻辑,导致“定义在独立文件,行为还混在总文件里”。
|
||||
2. RPG 运行时提示词虽然已经有独立模块,但前端 `src/prompts/` 与 Rust `server-rs/crates/api-server/src/prompt/` 里仍然缺少按 `rpg` 维度统一收口的子目录,编辑提示词时仍要在多个平铺文件里来回找。
|
||||
|
||||
用户目标是:
|
||||
|
||||
1. RPG 中不同选项 function 拆成独立函数,并且能在同一个脚本中看到所有选项 function 的代码入口。
|
||||
2. RPG 中运行时提示词都整理进 `prompt` 文件夹,并把 RPG prompt 脚本整理到更适合专注编辑提示词的结构中。
|
||||
|
||||
## 本次落地边界
|
||||
|
||||
1. 只整理 RPG 相关的前端运行时 function 与 prompt 结构。
|
||||
2. Rust 侧只整理 `server-rs` 的 prompt 模块结构,不兼容 `server-node`。
|
||||
3. 不改玩法语义,不重写大段中文提示词正文;优先移动文件、补兼容导出、增加聚合入口。
|
||||
4. 不在 UI 里增加说明文案。
|
||||
|
||||
## 目标结构
|
||||
|
||||
### 前端 RPG prompt
|
||||
|
||||
整理为:
|
||||
|
||||
```text
|
||||
src/prompts/
|
||||
├─ customWorldEntityActionPrompts.ts
|
||||
├─ customWorldPrompts.ts
|
||||
└─ rpg/
|
||||
├─ index.ts
|
||||
├─ runtimeStoryPrompts.ts
|
||||
└─ characterChatPrompts.ts
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
1. `runtimeStoryPrompts.ts` 承载原 `storyPromptBuilders.ts` 的 RPG 运行时剧情导演、NPC 对话导演、招募对话等提示词。
|
||||
2. `characterChatPrompts.ts` 承载原角色面板私聊提示词。
|
||||
3. 旧入口 `src/services/prompt.ts` 与 `src/services/characterChatPrompt.ts` 保留兼容转发,避免一次性改调用方。
|
||||
4. 角色资产工坊默认 prompt 与缓存合并规则不再放在前端 prompt 目录,统一迁到 `server-rs/crates/api-server/src/prompt/rpg/role_asset_studio.rs`。
|
||||
|
||||
### Rust 侧 RPG prompt
|
||||
|
||||
整理为:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/prompt/
|
||||
├─ big_fish.rs
|
||||
├─ character_animation.rs
|
||||
├─ character_visual.rs
|
||||
├─ puzzle_image.rs
|
||||
├─ scene_background.rs
|
||||
├─ mod.rs
|
||||
└─ rpg/
|
||||
├─ mod.rs
|
||||
├─ agent_chat.rs
|
||||
├─ foundation_draft.rs
|
||||
├─ role_asset_studio.rs
|
||||
└─ runtime_chat.rs
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
1. `prompt/rpg/agent_chat.rs` 承载 RPG 共创聊天提示词。
|
||||
2. `prompt/rpg/foundation_draft.rs` 承载 RPG 草稿生成提示词。
|
||||
3. `prompt/rpg/role_asset_studio.rs` 承载角色资产工坊默认 prompt、legacy prompt 过滤与缓存合并 workflow view。
|
||||
4. `prompt/rpg/runtime_chat.rs` 承载 RPG 运行时剧情、NPC 对话、战斗结果叙事等提示词。
|
||||
5. 顶层 `prompt/mod.rs` 继续向外导出 RPG 子模块,保证原调用点只做最小修改。
|
||||
|
||||
### RPG function 总览
|
||||
|
||||
新增一个面向编辑者的聚合入口,用来同时暴露:
|
||||
|
||||
1. 所有 RPG function 文档项。
|
||||
2. 所有状态类 function source。
|
||||
3. 每个状态类 function 的运行时行为处理器入口。
|
||||
|
||||
目标是让后续查看时可以先打开一个总览文件,再跳到对应 function 文件,而不是先从 `stateFunctions.ts` 的大 `switch` 里反查。
|
||||
|
||||
## 代码落地策略
|
||||
|
||||
### 1. function 运行时逻辑继续拆分
|
||||
|
||||
把 `src/data/stateFunctions.ts` 中这些按 `functionId` 写死的逻辑继续拆出:
|
||||
|
||||
1. 建议 actionText 生成。
|
||||
2. detailText 生成。
|
||||
3. function priority 计算。
|
||||
4. 必要的运行时 definition 微调。
|
||||
|
||||
每个状态类 function 文件在保留 `definition + documentation + promptDescription` 的基础上,追加该 function 的运行时处理器。
|
||||
|
||||
### 2. 总览脚本
|
||||
|
||||
新增聚合入口文件,统一导出:
|
||||
|
||||
1. 各域 function 文档。
|
||||
2. 状态类 function runtime source。
|
||||
3. 便于编辑时查找的数组/映射。
|
||||
|
||||
这样“同一个脚本看到所有选项 function 的代码”具体落地为:
|
||||
|
||||
1. 先看总览脚本知道有哪些 function。
|
||||
2. 每个 function 仍在独立文件维护,避免再次回到一个巨型文件。
|
||||
3. 总览脚本只能依赖 `state / npc / treasure / flow / panel` 等分目录入口,不能从 `src/data/functionCatalog/index.ts` 反向导入聚合常量,避免浏览器 ESM 初始化时出现 `Cannot access before initialization`。
|
||||
|
||||
## 验证
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run test -- src/services/prompt.test.ts src/hooks/rpg-runtime-story/storyResponseOptions.test.ts`
|
||||
3. `npm run typecheck`
|
||||
4. 如涉及 Rust prompt 模块编译错误,再补 `cargo check -p api-server`
|
||||
|
||||
## 后续编辑约定
|
||||
|
||||
1. 想改 RPG 运行时提示词时,优先进入:
|
||||
- 前端:`src/prompts/rpg/`
|
||||
- Rust:`server-rs/crates/api-server/src/prompt/rpg/`
|
||||
2. 想改 RPG 选项 function 时,优先进入:
|
||||
- 总览:`src/data/functionCatalog/index.ts`
|
||||
- 状态类分项:`src/data/functionCatalog/state/*.ts`
|
||||
3. 后续不要再把 RPG prompt 正文重新塞回 `services`、路由或运行时编排文件。
|
||||
@@ -0,0 +1,99 @@
|
||||
# RPG 背包 / 装备 / 锻造视图后端迁移落地方案(2026-04-28)
|
||||
|
||||
## 0. 本次目标
|
||||
|
||||
依据 `docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 的 `5.2 P1` 项,本次只收口一类职责:
|
||||
|
||||
**背包、装备、锻造面板的可用性、禁用原因、配方视图由 `server-rs` 计算,前端只渲染后端 view,并提交用户选择。**
|
||||
|
||||
本次不顺手迁移以下 P0 链路:
|
||||
|
||||
1. runtime action 仍携带完整 `GameState` 快照。
|
||||
2. 战斗胜负后处理与旅行桥接仍在既有阶段迁移。
|
||||
3. `inventory_slot` 表真相与 compat `GameState` 快照仍按现状共存。
|
||||
|
||||
## 1. 后端落点
|
||||
|
||||
本阶段采用最小后端落点:
|
||||
|
||||
1. `server-rs/crates/shared-contracts/src/runtime_story.rs`
|
||||
- 扩展 `RuntimeStoryViewModel`,新增 `inventory` 字段。
|
||||
- 定义背包物品、装备槽、物品动作、锻造配方、配方材料需求的 view contract。
|
||||
2. `server-rs/crates/module-runtime-story-compat/src/forge.rs`
|
||||
- 公开确定性的配方定义与需求统计能力。
|
||||
- 配方定义补齐前端已有 `forgeSystem.ts` 的三条 forge 配方。
|
||||
3. `server-rs/crates/module-runtime-story-compat/src/view_model.rs`
|
||||
- 从 `GameState` 快照编译 `inventory` view model。
|
||||
- 输出每个动作的 `enabled / reason`,由后端统一说明为什么不可用。
|
||||
4. `server-rs/crates/api-server/src/runtime_story/compat/*`
|
||||
- 原 action resolver 复用同一套 forge 定义和可用性判断。
|
||||
|
||||
## 2. 前端落点
|
||||
|
||||
1. `packages/shared/src/contracts/rpgRuntimeStoryState.ts`
|
||||
- 与 Rust contract 对齐新增 `inventory` view 类型。
|
||||
2. `src/services/rpg-runtime/rpgRuntimeStoryClient.ts`
|
||||
- 提供 `loadRpgRuntimeInventoryView`,通过 runtime story session state 获取后端 view。
|
||||
- 当前 runtime story 主链已完成不上传完整 `GameState` 的迁移,因此该读取入口只按 `runtimeSessionId` 请求后端持久化状态。
|
||||
3. `src/hooks/rpg-runtime-story/inventoryActions.ts`
|
||||
- 删除 `getForgeRecipeViews(...)` 本地配方计算。
|
||||
- 不再通过本地 `playerInventory.find(...)` / `playerEquipment[...]` 作为正式动作门禁。
|
||||
- 使用后端 view 的 `actions` 与 `forgeRecipes` 判断按钮可用性和 action 文案。
|
||||
4. `src/components/InventoryPanel.tsx`
|
||||
- 继续只展示传入的 view。
|
||||
- 支持展示后端 `disabledReason`,不再自行解释配方规则。
|
||||
- 背包列表优先使用后端 `backpackItems`,货币文案优先使用后端 `currencyText`。
|
||||
|
||||
## 3. 可用性规则
|
||||
|
||||
后端 `inventory` view 应至少输出:
|
||||
|
||||
1. `backpackItems`
|
||||
- 背包里的物品快照。
|
||||
- `actions.use / equip / dismantle / reforge`。
|
||||
2. `equipmentSlots`
|
||||
- `weapon / armor / relic` 三槽。
|
||||
- 每槽当前装备与 `actions.unequip`。
|
||||
3. `forgeRecipes`
|
||||
- 配方 id、名称、类型、说明、产物、货币花费。
|
||||
- 每项需求的 `owned / quantity`。
|
||||
- `canCraft` 与 `disabledReason`。
|
||||
4. `currencyText`
|
||||
- 由后端按 `worldType` 格式化。
|
||||
|
||||
禁用规则:
|
||||
|
||||
1. 缺少玩家角色时,所有正式动作不可用。
|
||||
2. 战斗中,装备 / 卸装 / 锻造 / 拆解 / 重铸不可用;可用物品仍可由战斗动作链处理。
|
||||
3. 不可使用的物品返回 `use.enabled=false`。
|
||||
4. 非装备物品返回 `equip.enabled=false`。
|
||||
5. 无 buildProfile 且非装备的物品不可拆解。
|
||||
6. 非装备或材料不足 / 货币不足的物品不可重铸。
|
||||
7. 材料或货币不足的配方不可制作,并返回原因。
|
||||
|
||||
## 4. 验收
|
||||
|
||||
1. 前端 `inventoryActions.ts` 不再引用 `getForgeRecipeViews`。
|
||||
2. 前端配方按钮使用后端 `forgeRecipes`。
|
||||
3. 后端 `RuntimeStoryViewModel` JSON 中存在 `inventory`。
|
||||
4. Rust contract / compat view model 有单元测试覆盖:
|
||||
- 配方 `canCraft` 与需求数量。
|
||||
- 装备、卸装、拆解、重铸禁用原因。
|
||||
5. TypeScript client 测试覆盖后端 inventory view 获取与保留。
|
||||
6. 修改后执行:
|
||||
- Rust 相关测试。
|
||||
- TypeScript 相关测试。
|
||||
- `npm run api-server:maincloud`。
|
||||
|
||||
## 5. 本次实现结果
|
||||
|
||||
1. `server-rs` 已在 `RuntimeStoryViewModel.inventory` 输出背包、装备槽、锻造配方、动作 payload 与禁用原因。
|
||||
2. `module-runtime-story-compat` 的锻造配方定义已补齐 `forgeSystem.ts` 中仍留在前端的合成 / 锻造配方,并对 `mana / 法力` 标签做后端匹配兼容。
|
||||
3. `src/hooks/rpg-runtime-story/inventoryActions.ts` 已改为:
|
||||
- 读取 `loadRpgRuntimeInventoryView(...)`。
|
||||
- 用户动作只使用后端 action view 的 `functionId / actionText / payload`。
|
||||
- 缺失或禁用时展示后端 `reason / disabledReason`。
|
||||
4. `src/components/InventoryPanel.tsx` 已改为:
|
||||
- 背包格子优先渲染后端 `backpackItems`。
|
||||
- 工坊列表渲染后端 `forgeRecipes`。
|
||||
- 禁用配方展示后端原因。
|
||||
@@ -0,0 +1,102 @@
|
||||
# RPG 提示词前端禁存与 server-rs 收口方案(2026-04-28)
|
||||
|
||||
## 背景
|
||||
|
||||
当前 RPG 运行时虽然已经大面积切到 `server-rs` 的 `/api/runtime/**`,但前端仍残留以下错误边界:
|
||||
|
||||
1. `src/services/ai.ts` 仍保留 RPG 剧情、角色私聊、NPC 对话、招募对话的本地 prompt 生成与浏览器侧 LLM fallback。
|
||||
2. `src/prompts/rpg/`、`src/prompts/storyPromptBuilders.ts`、`src/prompts/characterChatPrompts.ts` 仍存放 RPG 提示词正文。
|
||||
3. `src/services/aiService.ts` 在非浏览器环境下仍会回退到 `./ai`,等价于保留“前端可持有 RPG prompt”的技术后门。
|
||||
|
||||
这与仓库约束“前端只负责表现,逻辑、数据放后端”直接冲突,也会让提示词编辑入口继续分裂。
|
||||
|
||||
## 本次强约束
|
||||
|
||||
1. RPG 提示词禁止存在前端工程。
|
||||
2. RPG 提示词唯一允许存在于 `server-rs/crates/api-server/src/prompt/rpg/`。
|
||||
3. 前端只允许保留:
|
||||
- 运行时请求 contract
|
||||
- API client
|
||||
- UI 展示与交互状态
|
||||
4. 旧 `src/services/ai.ts` 不再承担 RPG 剧情/聊天 prompt 生成职责。
|
||||
|
||||
## 收口目标
|
||||
|
||||
### 后端唯一 prompt 目录
|
||||
|
||||
RPG 运行时提示词统一收口到:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/prompt/rpg/
|
||||
├─ mod.rs
|
||||
├─ agent_chat.rs
|
||||
├─ foundation_draft.rs
|
||||
└─ runtime_chat.rs
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
1. `agent_chat.rs` 负责创作态 RPG Agent prompt。
|
||||
2. `foundation_draft.rs` 负责 RPG 草稿生成 prompt。
|
||||
3. `runtime_chat.rs` 负责运行时剧情、角色私聊、NPC 聊天、招募对话等 prompt。
|
||||
|
||||
### 前端职责缩减
|
||||
|
||||
前端保留:
|
||||
|
||||
1. `src/services/aiService.ts`
|
||||
- 只负责请求 `/api/runtime/**`
|
||||
- 不再回退到本地 RPG prompt 构造
|
||||
2. `src/services/rpg-runtime/*`
|
||||
- 只负责按运行时域转发 client
|
||||
3. `src/hooks/rpg-runtime-story/*`
|
||||
- 只消费 API 回包并驱动 UI
|
||||
|
||||
前端移除:
|
||||
|
||||
1. `src/prompts/rpg/*`
|
||||
2. `src/prompts/storyPromptBuilders.ts`
|
||||
3. `src/prompts/characterChatPrompts.ts`
|
||||
4. `src/services/prompt.ts`
|
||||
5. `src/services/characterChatPrompt.ts`
|
||||
6. `src/services/ai.ts` 中全部 RPG prompt / RPG 本地 LLM fallback 逻辑
|
||||
|
||||
## 运行时接口对齐
|
||||
|
||||
为彻底去掉前端 prompt,`server-rs` 必须承接以下接口:
|
||||
|
||||
1. `POST /api/runtime/story/initial`
|
||||
2. `POST /api/runtime/story/continue`
|
||||
3. `POST /api/runtime/chat/character/suggestions`
|
||||
4. `POST /api/runtime/chat/character/summary`
|
||||
5. `POST /api/runtime/chat/character/reply/stream`
|
||||
6. `POST /api/runtime/chat/npc/dialogue/stream`
|
||||
7. `POST /api/runtime/chat/npc/turn/stream`
|
||||
8. `POST /api/runtime/chat/npc/recruit/stream`
|
||||
|
||||
其中:
|
||||
|
||||
1. 非流式接口统一返回 `{ text: string }`
|
||||
2. 流式接口统一返回可被前端直接消费的纯文本 SSE 增量
|
||||
3. NPC turn 仍保留当前带 `suggestions / functionSuggestions / chatDirective` 的专用 SSE 结构
|
||||
|
||||
## 前端代码落地要求
|
||||
|
||||
1. `aiService.ts` 在 RPG 相关方法中禁止再动态 `import('./ai')`
|
||||
2. 若在非浏览器环境误调用 RPG 运行时能力,应直接报错,明确提示必须走 `api-server`
|
||||
3. 角色私聊目标状态类型等纯类型定义可以留在前端,但必须与 prompt 文件彻底解耦
|
||||
|
||||
## 验证
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run test -- src/services/ai.test.ts src/hooks/rpg-runtime-story/storyResponseOptions.test.ts`
|
||||
3. `cargo check -p api-server`
|
||||
4. `npm run api-server:maincloud`
|
||||
|
||||
## 后续编辑约定
|
||||
|
||||
之后如果要改 RPG 提示词:
|
||||
|
||||
1. 只进入 `server-rs/crates/api-server/src/prompt/rpg/`
|
||||
2. 不允许在 `src/` 下新增任何 RPG prompt、system prompt、prompt builder
|
||||
3. 前端若出现“为了临时 fallback 先放一个 prompt”的需求,视为越界,必须改为补后端接口
|
||||
@@ -0,0 +1,103 @@
|
||||
# RPG 角色资产工坊默认 Prompt 与缓存合并后端迁移(2026-04-28)
|
||||
|
||||
## 背景
|
||||
|
||||
`docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 已明确指出:角色资产工坊中用户正在编辑的 prompt 草稿可以留在前端表单,但默认 prompt 生成、legacy prompt 判断、缓存合并和工作流初始态不应继续散落在 `RpgCreationRoleAssetStudioModalImpl.tsx`。
|
||||
|
||||
本次迁移只处理这一项边界,不扩大到角色生图、动作生成的模型参数默认值重构。
|
||||
|
||||
## 落地边界
|
||||
|
||||
1. 后端新增角色资产工坊 workflow view,负责输出:
|
||||
- 从角色字段挑选出的默认视觉 / 动作 / 场景 prompt 种子。
|
||||
- 过滤 legacy 旧生成 prompt 后的视觉 prompt。
|
||||
- 按动作 key 合并后的动作 prompt map。
|
||||
- 从缓存回填的候选图、选中候选、选中动作、形象资产和动作 map。
|
||||
2. 前端只把当前正在编辑的角色快照传给后端解析 workflow view。
|
||||
3. 前端保存缓存时只保存用户当前表单草稿和资产结果,不再计算合并规则。
|
||||
4. 现有 OSS JSON 缓存继续复用,不新增 SpacetimeDB 表结构,因此本轮不修改 `migration.rs`。
|
||||
|
||||
## 接口设计
|
||||
|
||||
新增解析接口:
|
||||
|
||||
```text
|
||||
POST /api/runtime/custom-world/asset-studio/role/{character_id}/workflow
|
||||
```
|
||||
|
||||
请求体:
|
||||
|
||||
```json
|
||||
{
|
||||
"cacheScopeId": "world-id",
|
||||
"role": {
|
||||
"id": "role-id",
|
||||
"name": "角色名",
|
||||
"title": "头衔",
|
||||
"role": "世界身份",
|
||||
"visualDescription": "角色视觉描述",
|
||||
"actionDescription": "角色动作描述",
|
||||
"sceneVisualDescription": "场景描述",
|
||||
"description": "通用描述",
|
||||
"backstory": "背景",
|
||||
"combatStyle": "战斗风格"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
响应体:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"cache": {},
|
||||
"workflow": {
|
||||
"defaultPromptBundle": {
|
||||
"visualPromptText": "",
|
||||
"animationPromptText": "",
|
||||
"scenePromptText": ""
|
||||
},
|
||||
"visualPromptText": "",
|
||||
"animationPromptTextByKey": {
|
||||
"run": "",
|
||||
"attack": "",
|
||||
"idle": "",
|
||||
"die": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
新增保存接口:
|
||||
|
||||
```text
|
||||
PUT /api/runtime/custom-world/asset-studio/role/{character_id}/workflow
|
||||
```
|
||||
|
||||
它复用原 `POST /api/assets/character-workflow-cache` 的 OSS JSON 缓存保存逻辑,并补齐 `animationPromptTextByKey` 持久化。
|
||||
|
||||
## 合并规则主源
|
||||
|
||||
后端主源:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/prompt/rpg/role_asset_studio.rs
|
||||
```
|
||||
|
||||
规则保持现有语义:
|
||||
|
||||
1. `visualPromptText` 默认优先取 `visualDescription`,其次 `description`,长度上限 220。
|
||||
2. `animationPromptText` 默认优先取 `actionDescription`,其次 `combatStyle`,长度上限 180。
|
||||
3. `scenePromptText` 默认优先取 `sceneVisualDescription`,其次 `backstory`,长度上限 220。
|
||||
4. 角色存在新的 `visualDescription` 时,不使用缓存视觉 prompt 覆盖默认值。
|
||||
5. 角色存在新的 `actionDescription` 时,所有动作 prompt 使用新的默认动作 prompt。
|
||||
6. 角色没有新的动作描述时,逐动作优先使用 `animationPromptTextByKey`,再回退旧 `animationPromptText`,最后回退默认动作 prompt。
|
||||
7. 命中历史生成模板标记的视觉 / 动作 prompt 不再作为可继承缓存。
|
||||
|
||||
## 验收
|
||||
|
||||
1. `src/` 不再引用 `buildDefaultRolePromptBundle`。
|
||||
2. `RpgCreationRoleAssetStudioModalImpl.tsx` 不再包含 legacy prompt 判断与缓存合并函数。
|
||||
3. `CharacterWorkflowCachePayload` 能读写 `animationPromptTextByKey`。
|
||||
4. Rust 单测覆盖默认 prompt、legacy 过滤、逐动作缓存合并。
|
||||
5. 前端 client 单测覆盖 workflow 解析接口和 PUT 保存接口。
|
||||
@@ -0,0 +1,70 @@
|
||||
# RPG 运行时开局 GameState 后端迁移落地(2026-04-28)
|
||||
|
||||
## 目标
|
||||
|
||||
本次只收口 `RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 的 `4.1 P0 运行时开局 GameState 装配仍在前端`。
|
||||
|
||||
## 边界
|
||||
|
||||
前端保留:
|
||||
|
||||
1. 选择世界、选择角色、切换 tab、地图弹层等 UI 状态。
|
||||
2. 世界选择后的“尚未选角”中间态,用于展示角色选择页面。
|
||||
3. 调用后端开局接口并接收快照。
|
||||
|
||||
后端负责:
|
||||
|
||||
1. 生成 `runtimeSessionId` 与 `runtimeActionVersion`。
|
||||
2. 装配正式初始 `GameState`。
|
||||
3. 装配初始场景、opening act、首遇 NPC、NPC state。
|
||||
4. 装配初始背包、初始装备、血蓝、货币、技能冷却。
|
||||
5. 写入 runtime snapshot,成为后续 runtime story 的读取来源。
|
||||
|
||||
## 接口
|
||||
|
||||
新增:
|
||||
|
||||
```text
|
||||
POST /api/runtime/story/sessions
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"worldType": "CUSTOM",
|
||||
"customWorldProfile": {},
|
||||
"character": {},
|
||||
"runtimeMode": "play",
|
||||
"disablePersistence": false
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionId": "runtime-...",
|
||||
"serverVersion": 1,
|
||||
"snapshot": {
|
||||
"version": 2,
|
||||
"savedAt": "...",
|
||||
"bottomTab": "adventure",
|
||||
"gameState": {},
|
||||
"currentStory": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 验收
|
||||
|
||||
1. `useRpgSessionBootstrap.ts` 不再在 `handleCharacterSelect` 中本地构造完整初始 `GameState`。
|
||||
2. 开局后 `gameState.runtimeSessionId` 来自后端。
|
||||
3. 开局后 `gameState.currentScene === "Story"`。
|
||||
4. 自定义世界 opening act 能写入 `storyEngineMemory.currentSceneActState`。
|
||||
5. 自定义世界角色 `initialItems` 能进入背包并自动装配可推断槽位。
|
||||
6. 后端测试覆盖 opening act、首遇 NPC、初始物品、装备。
|
||||
|
||||
## 后续
|
||||
|
||||
本次仍沿用 runtime story compat 的 JSON `GameState` 桥接形态。后续阶段应继续把 `runtime_story` action 从“快照桥接”推进为 SpacetimeDB 表级状态读写。
|
||||
@@ -0,0 +1,63 @@
|
||||
# RPG 运行时战斗后处理后端迁移落地方案(2026-04-28)
|
||||
|
||||
## 目标
|
||||
|
||||
本方案承接 `docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 的 4.5 项,专门收口三类仍由前端补真相的逻辑:
|
||||
|
||||
1. 战斗胜利 / 切磋完成后的正式 `GameState` 清理。
|
||||
2. 玩家死亡后的复活场景、血蓝恢复与首场景 act 状态。
|
||||
3. 战斗结束后章节 act 推进与 `currentStory.deferredOptions` 编排。
|
||||
|
||||
## 边界
|
||||
|
||||
后端负责:
|
||||
|
||||
1. 根据 battle resolver 的 `outcome` 决定 `victory`、`spar_complete`、`defeat`、`escaped` 的最终状态。
|
||||
2. 写回 `inBattle`、`currentEncounter`、`sceneHostileNpcs`、`currentNpcBattleOutcome`、`playerHp`、`playerMana`、`storyEngineMemory.currentSceneActState`。
|
||||
3. 为死亡复活构造回到首场景的快照,并恢复 `playerHp = playerMaxHp`、`playerMana = playerMaxMana`。
|
||||
4. 为胜利 / 切磋完成构造只含 `story_continue_adventure` 的当前 story,并把真实后续 options 放入 `deferredOptions`。
|
||||
5. 在最后一幕或无需等待继续按钮时直接返回场景旅行 / 常规 fallback options。
|
||||
|
||||
前端只负责:
|
||||
|
||||
1. 播放 `presentation.battle` 对应动画。
|
||||
2. 使用 `response.snapshot.gameState` 与 `response.snapshot.currentStory` 渲染。
|
||||
3. 不再调用 `buildPostBattleVictoryState`、`buildPostBattleVictoryStory`、`buildRevivedFirstSceneState`、`buildDeathStory` 作为服务端动作后的正式状态。
|
||||
|
||||
## 后端落点
|
||||
|
||||
1. `server-rs/crates/module-runtime-story-compat/src/post_battle.rs`
|
||||
- 增加纯 JSON helper,迁移战斗后状态、复活和 scene act 推进。
|
||||
2. `server-rs/crates/api-server/src/runtime_story/compat.rs`
|
||||
- 在 `resolve_battle_action` 之后、生成 AI fallback 之前统一调用 post-battle finalizer。
|
||||
3. `server-rs/crates/api-server/src/runtime_story/compat/presentation.rs`
|
||||
- 复用现有 option / current story 构造函数。
|
||||
4. `packages/shared/src/contracts/rpgRuntimeStoryState.ts`
|
||||
- battle outcome 增加 `defeat`,避免前端类型层把失败误判成非战斗终局。
|
||||
|
||||
## 落地补充
|
||||
|
||||
1. 后端 post-battle finalizer 在 `resolve_battle_action` 之后、LLM fallback 之前执行,终局战斗不再生成额外 AI 文本。
|
||||
2. 胜利 / 切磋完成会清理战斗态并推进当前场景 act;非最后一幕只展示 `story_continue_adventure`,真实后续动作写入 `deferredOptions`。
|
||||
3. 败北复活会先写回首场景、回满血蓝、重置首场景 act,再基于复活后的场景重新生成 `deferredOptions`,避免沿用战斗前旧场景选项。
|
||||
4. story engine 投影额外接收 battle outcome;只有 `victory / spar_complete` 会记录胜利信号,`defeat` 不会被“战斗态从 true 变 false”误判成胜利。
|
||||
5. 前端 `runServerRuntimeChoiceAction` 的服务端路径不再调用 `postBattleFlow` 构造正式状态;死亡动画仍可短暂播放,但最终 `GameState/currentStory` 只采用后端 hydrated snapshot。
|
||||
|
||||
## 本轮收口记录
|
||||
|
||||
1. `choiceActions.ts` 删除 `shouldResolveCombatChoiceLocally(...)`,`battle_* / inventory_use` 不再因战斗可见态回落到本地 continuation。
|
||||
2. `storyChoiceContinuation.ts` 对 `battle_* / inventory_use` 以及被分类为 `battle / escape` 的动作加硬保护,误入时不会裁决掉落、复活、任务推进或战后 story。
|
||||
3. `storyChoiceRuntime.ts` 删除本地敌对 NPC 战斗奖励 helper,前端不再调用 `rollHostileNpcLoot(...)` 与 `addInventoryItems(...)` 生成正式战利品。
|
||||
4. 删除 `postBattleFlow.ts` 与其测试,前端不再保留死亡复活、胜利后 story、deferred options、章节推进的正式构造函数。
|
||||
5. `choiceActions.test.ts` 覆盖 `battle_use_skill`、stale `battle_attack_basic`、`inventory_use` 全部进入后端 resolver;`storyChoiceRuntime.test.ts` 继续覆盖服务端胜利 / 失败 snapshot 被直接采用。
|
||||
|
||||
## 验收
|
||||
|
||||
1. Rust 单测覆盖:
|
||||
- 服务端 battle victory 返回后,`currentEncounter = null`、`inBattle = false`、`currentStory.options = [story_continue_adventure]`、`deferredOptions` 存在。
|
||||
- 服务端 battle defeat 返回后,玩家复活到首场景,`playerHp/playerMana` 回满,`currentStory` 为死亡复活故事。
|
||||
2. 前端单测覆盖:
|
||||
- `runServerRuntimeChoiceAction` 对 `victory` 和 `defeat` 都直接采用服务端 snapshot/story,不再本地构造 post battle / revive 状态。
|
||||
3. 搜索确认 `src/hooks/rpg-runtime-story` 不再出现 `shouldResolveCombatChoiceLocally`、`buildPostBattleVictory*`、`buildRevivedFirstSceneState`、`buildDeathStory`、`buildHostileNpcBattleReward`。
|
||||
4. Rust 单测覆盖:
|
||||
- story engine 对 `defeat` outcome 不写入 `win_battle` 信号和敌压 mutation。
|
||||
@@ -0,0 +1,164 @@
|
||||
# RPG 运行时 Story Engine 后端迁移落地方案(2026-04-28)
|
||||
|
||||
## 0. 本轮目标
|
||||
|
||||
本轮只收口 `RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 中 `4.4 P0 story engine / chapter / world mutation` 这条。
|
||||
|
||||
目标不是新增一套前端规则,而是让运行时动作完成后由 `server-rs` 统一写回:
|
||||
|
||||
1. `storyHistory`
|
||||
2. `storyEngineMemory`
|
||||
3. `chapterState`
|
||||
4. `currentScenePreset.mutationStateText / currentPressureLevel / description`
|
||||
|
||||
前端只能展示这些后端字段,不能继续在 hook 中运行 `chapterDirector / threadSignalRouter / worldMutationRouter` 等正式状态机。
|
||||
|
||||
## 1. 后端落点
|
||||
|
||||
### 1.1 `module-runtime-story-compat`
|
||||
|
||||
新增 `story_engine.rs`,作为无 HTTP、无 `AppState` 的纯 JSON projector。
|
||||
|
||||
职责:
|
||||
|
||||
1. 确保 `storyEngineMemory` 最小结构存在。
|
||||
2. 按上一帧与下一帧快照生成 story signals。
|
||||
3. 基于信号推进 active thread、recent signal。
|
||||
4. 基于当前场景和任务生成 `ChapterState`。
|
||||
5. 基于章节和信号生成 `WorldMutation`。
|
||||
6. 把 mutation 投影到当前场景展示字段。
|
||||
7. 追加最小 chronicle、journey beat、continue digest。
|
||||
|
||||
### 1.2 `api-server runtime_story compat`
|
||||
|
||||
`resolve_runtime_story_action` 在动作确定性结算和 `storyHistory` 写入后,统一调用 projector,再持久化快照。
|
||||
|
||||
这样即使前端只提交 `functionId/payload`,正式叙事记忆也由后端结果生成。
|
||||
|
||||
## 2. 前端收口
|
||||
|
||||
### 2.1 `progressionActions.ts`
|
||||
|
||||
保留:
|
||||
|
||||
1. 展示层 loading/error。
|
||||
2. encounter 入场动画。
|
||||
3. 调用后端生成 story 或 fallback story。
|
||||
|
||||
移除:
|
||||
|
||||
1. `applyStoryEngineEchoes`
|
||||
2. 本地章节任务补发。
|
||||
3. 本地 thread signal、companion reaction、chapter、journey beat、world mutation、QA、release gate 等编排。
|
||||
|
||||
### 2.2 `storyContextBuilder.ts`
|
||||
|
||||
保留 prompt context 适配职责,但只能读取后端已存在的字段:
|
||||
|
||||
1. `state.chapterState`
|
||||
2. `state.storyEngineMemory.currentChapter`
|
||||
3. `state.storyEngineMemory.currentJourneyBeat`
|
||||
4. `state.storyEngineMemory.worldMutations`
|
||||
5. `state.currentScenePreset`
|
||||
|
||||
禁止继续导入并运行 story engine director。
|
||||
|
||||
## 3. 验收标准
|
||||
|
||||
1. `src/hooks/rpg-runtime-story/progressionActions.ts` 不再导入 `services/storyEngine/*`。
|
||||
2. `src/hooks/rpg-runtime-story/storyContextBuilder.ts` 不再导入 `services/storyEngine/*`。
|
||||
3. `resolve_runtime_story_action` 返回的 snapshot 中包含后端写入的 `storyEngineMemory.currentChapter`。
|
||||
4. 场景动作后 `currentScenePreset.mutationStateText` 由后端 projector 写入。
|
||||
5. `cargo test -p module-runtime-story-compat story_engine --manifest-path server-rs/Cargo.toml` 通过。
|
||||
6. `cargo test -p api-server runtime_story --manifest-path server-rs/Cargo.toml` 通过。
|
||||
7. 前端相关 vitest 与编码检查通过。
|
||||
|
||||
## 4. 本轮落地记录
|
||||
|
||||
### 4.1 后端已落地
|
||||
|
||||
1. `server-rs/crates/module-runtime-story-compat/src/story_engine.rs` 新增确定性 projector。
|
||||
2. `server-rs/crates/api-server/src/runtime_story/compat.rs` 在 action resolve 写入 `storyHistory` 后调用 projector,再保存 snapshot。
|
||||
3. `server-rs/crates/api-server/src/runtime_story/compat/tests.rs` 新增 route 边界测试,覆盖响应 snapshot 中的:
|
||||
- `chapterState.id`
|
||||
- `storyEngineMemory.currentChapter.id`
|
||||
- `quests[].chapterId`
|
||||
- `currentScenePreset.mutationStateText`
|
||||
- `storyEngineMemory.worldMutations`
|
||||
|
||||
### 4.2 前端已收口
|
||||
|
||||
1. `src/hooks/rpg-runtime-story/progressionActions.ts` 不再执行本地 story engine echo、chapter、journey beat、world mutation 编排。
|
||||
2. `src/hooks/rpg-runtime-story/storyContextBuilder.ts` 不再导入 `services/storyEngine/*`,只读取后端快照中已有的章节、旅程、mutation、chronicle、companion reaction 等字段。
|
||||
3. prompt context 中 `visibilitySlice / sceneNarrativeDirective / goalStack / activeScenarioPack / activeCampaignPack` 暂不在前端重建,等待后端后续模块正式写入后直接透传。
|
||||
|
||||
### 4.3 验证结果
|
||||
|
||||
已通过:
|
||||
|
||||
1. `cargo test -p module-runtime-story-compat story_engine --manifest-path server-rs\Cargo.toml`
|
||||
2. `cargo test -p api-server runtime_story --manifest-path server-rs\Cargo.toml`
|
||||
3. `cargo test -p api-server runtime_story_route_boundary_projects_story_engine_state --manifest-path server-rs\Cargo.toml`
|
||||
4. `npm run test -- src/hooks/rpg-runtime-story/storyRequestCoordinator.test.ts src/hooks/rpg-runtime-story/storyRequestRuntime.test.ts src/hooks/rpg-runtime-story/useRpgRuntimeStoryController.test.tsx src/hooks/rpg-runtime-story/choiceActions.test.ts src/hooks/rpg-runtime-story/storyInteractionCoordinator.test.ts`
|
||||
5. `npx eslint src/hooks/rpg-runtime-story/storyContextBuilder.ts src/hooks/rpg-runtime-story/progressionActions.ts --max-warnings 0`
|
||||
6. `cargo fmt --manifest-path server-rs\Cargo.toml --all --check`
|
||||
|
||||
已发现的非本轮阻塞:
|
||||
|
||||
1. `npm run typecheck` 当前被既有 NPC 交易、背包/锻造 UI、测试 fixture、`src/services/ai.ts` 缺 import 等错误拦截。
|
||||
2. `npm run test -- src/hooks/rpg-runtime-story` 当前有 1 个 `storyChoiceRuntime.test.ts` 战斗死亡/复活断言失败,属于审计后续 `4.5` post-battle 迁移范围。
|
||||
|
||||
### 4.4 NPC 聊天半量快照容错补丁
|
||||
|
||||
用户复测角色聊天时,点击 NPC 聊天选项后触发:
|
||||
|
||||
`Cannot read properties of undefined (reading 'length')`
|
||||
|
||||
复查调用链确认,后端 story engine projector 已经成为 `storyEngineMemory` 的主写入方,但部分快照或旧存档可能只携带 `currentChapter / worldMutations` 等增量字段,没有补齐 `activeThreadIds / recentCarrierIds / discoveredFactIds` 等数组字段。前端在 `syncNpcNarrativeState()` 中把半量对象当完整 `StoryEngineMemoryState` 消费,直接读取 `activeThreadIds.length`,导致 NPC 选项点击后的好感与叙事记忆同步中断。
|
||||
|
||||
本轮只做消费边界容错,不恢复前端 story engine 状态机:
|
||||
|
||||
1. `visibilityEngine.ts` 增加 `normalizeStoryEngineMemoryState()`,以 `createEmptyStoryEngineMemoryState()` 为基底补齐数组字段,同时保留后端快照已有字段。
|
||||
2. `syncNpcNarrativeState()` 与 `appendStoryEngineCarrierMemory()` 在读写叙事记忆前统一归一化,避免半量快照在 NPC 聊天、物品回声等路径里崩溃。
|
||||
3. `buildEncounterVisibilitySlice()` 与 `buildQuestVisibilitySlice()` 直接消费外部 memory 时也先归一化,保证 visibility 层独立调用时口径一致。
|
||||
4. 新增 `echoMemory.test.ts` 回归用例,覆盖只有 `currentChapter`、缺少 `activeThreadIds` 的后端投影快照。
|
||||
|
||||
验证:
|
||||
|
||||
1. `npm run test -- src/services/storyEngine/echoMemory.test.ts src/services/storyEngine/visibilityEngine.test.ts`
|
||||
2. `npm run check:encoding -- src/services/storyEngine/echoMemory.ts src/services/storyEngine/visibilityEngine.ts src/services/storyEngine/echoMemory.test.ts docs/technical/RPG_RUNTIME_STORY_ENGINE_BACKEND_MIGRATION_2026-04-28.md`
|
||||
|
||||
### 4.5 story prompt context 后端 projector 收口
|
||||
|
||||
本轮继续收口 `RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_COMPLETION_CHECK_2026-04-28.md` 中仍未完成的 `story engine / prompt context / AI story 请求编排`:
|
||||
|
||||
1. `server-rs/crates/module-runtime-story-compat/src/prompt_context.rs` 新增 `build_runtime_story_prompt_context(...)`,基于后端持久化 `gameState` 投影:
|
||||
- 场景描述、mutation、压力等级。
|
||||
- encounter / NPC 好感、披露阶段、可谈话题、首次接触姿态。
|
||||
- conversationSituation / conversationPressure / talkPriority。
|
||||
- chapter、journey beat、worldMutations、chronicle、party relationship notes。
|
||||
2. `POST /api/runtime/story/initial` 与 `POST /api/runtime/story/continue` 支持新主链 payload:
|
||||
- `sessionId`
|
||||
- `clientVersion`
|
||||
- `choice`
|
||||
- `lastFunctionId`
|
||||
- `observeSignsRequested`
|
||||
- `recentActionResult`
|
||||
- `requestOptions`
|
||||
3. 后端收到 `sessionId` 后只从服务端 runtime snapshot 读取 `worldType / playerCharacter / sceneHostileNpcs / storyHistory / prompt context`;旧 `worldType / character / history / context` 字段仅保留兼容,不作为正式主链来源。
|
||||
4. `runtime_chat_plain.rs` 与 `runtime_chat.rs` 同步支持 `sessionId`,角色私聊、NPC 对话、NPC 单轮聊天、招募对话的 prompt context 也由后端快照投影;前端只继续提交对话草稿、目标角色、玩家发言和必要 UI 临时项。
|
||||
5. `src/hooks/rpg-runtime-story/storyContextBuilder.ts` 缩减为 session 元信息适配器,不再推导 `conversationSituation / conversationPressure / NPC disclosure / partyRelationshipNotes / scene pressure` 等正式上下文。
|
||||
6. `src/services/aiService.ts` 在存在 `runtimeSessionId` 时,story initial/continue 只提交 session 轻量 payload;聊天接口只附带 `sessionId` 与对话输入,不再上传完整 `StoryGenerationContext`。
|
||||
7. `src/hooks/rpg-runtime-story/sessionActions.ts` 领取任务奖励时不再运行前端 `chapterDirector / echoMemory`,只保留旧 UI 层奖励展示所需的本地字段;章节和 `storyEngineMemory.currentChapter` 等正式叙事字段等待后端 action snapshot 刷新。
|
||||
8. `src/hooks/rpg-runtime-story/useRpgRuntimeNpcInteraction.ts` NPC 聊天闭合后不再调用前端 scene act runtime 推进 `storyEngineMemory.currentSceneActState`,也不再把 `deferredRuntimeState.storyEngineMemory` 写回正式 `GameState`。
|
||||
9. `src/hooks/rpg-runtime-story/choiceActions.ts` 兼容旧 `deferredRuntimeState` 时只允许采用场景字段,不再从 story moment 写入 `storyEngineMemory`。
|
||||
|
||||
新增验证:
|
||||
|
||||
1. `cargo test -p module-runtime-story-compat prompt_context --manifest-path server-rs\Cargo.toml`
|
||||
2. `cargo test -p shared-contracts runtime_story_ai_request --manifest-path server-rs\Cargo.toml`
|
||||
3. `cargo test -p api-server runtime_story_initial_uses_server_snapshot_prompt_context_when_session_id_present --manifest-path server-rs\Cargo.toml`
|
||||
4. `cargo check -p api-server --manifest-path server-rs\Cargo.toml --message-format short`
|
||||
5. `npm run test -- src/services/ai.test.ts src/hooks/rpg-runtime-story/storyRequestCoordinator.test.ts src/hooks/rpg-runtime-story/useRpgRuntimeStoryController.test.tsx`
|
||||
6. `npm run test -- src/hooks/rpg-runtime-story/sessionActions.test.ts src/hooks/rpg-runtime-story/choiceActions.test.ts src/hooks/rpg-runtime-story/npcEncounterActions.test.ts`
|
||||
7. `npx eslint src/hooks/rpg-runtime-story/sessionActions.ts src/hooks/rpg-runtime-story/sessionActions.test.ts src/hooks/rpg-runtime-story/useRpgRuntimeNpcInteraction.ts src/hooks/rpg-runtime-story/choiceActions.ts src/hooks/rpg-runtime-story/choiceActions.test.ts --max-warnings 0`
|
||||
@@ -112,6 +112,8 @@ src/services/creation-agent/
|
||||
1. 4 个玩法锚点映射。
|
||||
2. 输入框占位提示。
|
||||
3. 生成结果页 action:`big_fish_compile_draft`。
|
||||
4. `big_fish_compile_draft` 只负责编译玩法草稿并进入结果页,不在草稿阶段串行生成动作素材。
|
||||
5. 大鱼吃小鱼的主图、动作、背景都在结果页工坊独立触发;统一进度组件里不再为其草稿阶段展示“生成动作素材”步骤。
|
||||
|
||||
### 4.3 拼图
|
||||
|
||||
|
||||
Reference in New Issue
Block a user