This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
# Runtime Story 后端边界迁移记录(2026-04-19)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 1. 本轮目标
|
||||
|
||||
本轮只处理 `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md` 中已经明确、且可以无需求漂移落地的两类问题:
|
||||
|
||||
1. `RuntimeStoryOptionView` 的 `interaction` 语义不能再由前端根据 `functionId + currentEncounter` 本地重建。
|
||||
2. `src/hooks/story/npcEncounterActions.ts` 中 `help / leave / fight / spar / quest_turn_in` 等运行时动作不能继续在浏览器里保留旧本地结算分支。
|
||||
|
||||
本轮**没有**做以下事情:
|
||||
|
||||
1. 没有修改任何功能需求。
|
||||
2. 没有修改任何业务提示词。
|
||||
3. 没有扩展新的动作能力面。
|
||||
4. 没有处理 custom-world 领域规则从 `server-node -> src/services/**` 反向 import 的剩余问题。
|
||||
|
||||
## 2. 已落地收口
|
||||
|
||||
### 2.1 runtime option interaction 改为后端唯一构建
|
||||
|
||||
已完成:
|
||||
|
||||
1. `server-node/src/modules/story/runtimeSession.ts`
|
||||
- `buildOptionView(...)` 直接输出 `interaction`
|
||||
- `buildAvailableOptions(...)` 直接返回带 `interaction` 的 runtime option
|
||||
- 删除前一版补丁式附加逻辑,避免后续再出现“双份映射”
|
||||
2. `server-node/src/modules/story/storyActionService.ts`
|
||||
- story option view model 直接透传 `option.interaction`
|
||||
3. `src/services/runtimeStoryService.ts`
|
||||
- 前端不再根据 `currentEncounter` 重建一份 `interaction`
|
||||
- 只消费服务端返回的 `option.interaction`
|
||||
|
||||
这意味着:
|
||||
|
||||
1. `npc_chat / npc_help / npc_fight / npc_leave / npc_trade / npc_gift / npc_quest_*`
|
||||
2. `treasure_secure / treasure_inspect / treasure_leave`
|
||||
|
||||
这些交互语义以后都以后端 runtime session 为准。
|
||||
|
||||
### 2.2 npcEncounterActions 收缩为前端壳层
|
||||
|
||||
已完成:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts`
|
||||
- `help`
|
||||
- `leave`
|
||||
- `fight`
|
||||
- `spar`
|
||||
- `quest_accept`
|
||||
- `quest_turn_in`
|
||||
|
||||
以上动作已统一改为走 `resolveServerRuntimeChoice(...)`
|
||||
2. 删除本轮迁移后已无消费方的本地 helper / import / 常量残留,避免误以为本地仍承担这部分结算职责。
|
||||
|
||||
当前前端在这条链路上只保留:
|
||||
|
||||
1. 选项点击分发
|
||||
2. trade / gift / recruit 的 UI modal 打开
|
||||
3. NPC 对话壳层与流式展示
|
||||
4. 服务端返回结果的状态落地与 story 刷新
|
||||
|
||||
### 2.3 待接委托正式接取改为后端收口
|
||||
|
||||
已完成:
|
||||
|
||||
1. `server-node/src/modules/quest/questStoryActionService.ts`
|
||||
- `npc_quest_accept` 会优先读取服务端快照里 `currentStory.npcChatState.pendingQuestOffer.quest`
|
||||
- 如果当前聊天态里已经存在待接委托,就按这份已展示给玩家的委托正式接取,不再在后端临时重建另一份任务
|
||||
2. `server-node/src/modules/story/storyActionService.ts`
|
||||
- `npc_quest_accept` 在存在待接委托聊天态时,会继续输出 `displayMode: 'dialogue'` 的 current story
|
||||
- 会清空 `pendingQuestOffer`
|
||||
- 会恢复既有的三条自由追问建议,避免接任务后 UI 退回普通 story 文本态
|
||||
3. `src/hooks/story/npcEncounterActions.ts`
|
||||
- `acceptPendingNpcQuestOffer()` 不再本地直接修改 `quests / runtimeStats / storyHistory`
|
||||
- 现在只负责触发 `resolveServerRuntimeChoice(...)`,由后端统一落地正式接取结果
|
||||
|
||||
这意味着:
|
||||
|
||||
1. “NPC 聊天里弹出的待接委托”不再是一份只存在于前端内存里的临时结果
|
||||
2. 前端不会再一边展示待接委托、一边本地把正式 quest log 写出来
|
||||
3. 正式接取后的 quest 真相源、聊天态投影与快照持久化统一以后端为准
|
||||
|
||||
### 2.4 NPC 聊天待接委托生成与浏览器 LLM fallback 继续后移
|
||||
|
||||
已完成:
|
||||
|
||||
1. `server-node/src/modules/ai/chatOrchestrator.ts`
|
||||
- `streamNpcChatTurnFromOrchestrator(...)` 现在会基于前端提交的 `questOfferContext`
|
||||
- 由后端判断是否应该生成 `pendingQuestOffer`
|
||||
- quest draft 与引导文案 `introText` 由服务端一并回填到 `complete` 事件
|
||||
2. `src/services/aiService.ts`
|
||||
- `streamNpcChatTurn(...)` 已支持把 `questOfferContext` 送入后端
|
||||
3. `src/hooks/story/npcEncounterActions.ts`
|
||||
- NPC 单轮聊天结束后不再本地调用 `generateQuestForNpcEncounter(...)`
|
||||
- 前端改为只消费服务端回填的 `pendingQuestOffer + introText`
|
||||
4. `src/services/questDirector.ts`
|
||||
- 浏览器端 quest draft 失败时,不再退回本地 LLM 调用
|
||||
- 当前改为直接走 deterministic fallback quest compile
|
||||
5. `src/services/runtimeItemAiDirector.ts`
|
||||
- 浏览器端 runtime item intent 失败时,不再退回本地 LLM 调用
|
||||
- 当前改为直接返回 deterministic fallback intents
|
||||
|
||||
这意味着:
|
||||
|
||||
1. NPC 聊天里“是否触发待接委托”的判定不再由前端依据 `turnCount / affinity / quests` 本地重跑
|
||||
2. 浏览器不再保留 quest draft 与 runtime item intent 的正式 LLM fallback orchestration
|
||||
3. 前端在这两条链路上继续退化为服务端结果消费层
|
||||
|
||||
## 3. 本轮涉及文件
|
||||
|
||||
代码:
|
||||
|
||||
1. `server-node/src/modules/story/runtimeSession.ts`
|
||||
2. `server-node/src/modules/story/storyActionService.ts`
|
||||
3. `server-node/src/modules/story/storyActionRoutes.test.ts`
|
||||
4. `src/services/runtimeStoryService.ts`
|
||||
5. `src/services/runtimeStoryService.test.ts`
|
||||
6. `src/hooks/story/npcEncounterActions.ts`
|
||||
7. `src/hooks/story/npcEncounterActions.test.ts`
|
||||
8. `server-node/src/modules/quest/questStoryActionService.ts`
|
||||
9. `server-node/src/modules/ai/chatOrchestrator.ts`
|
||||
10. `server-node/src/modules/ai/orchestrator.test.ts`
|
||||
11. `src/services/aiService.ts`
|
||||
12. `src/services/questDirector.ts`
|
||||
13. `src/services/runtimeItemAiDirector.ts`
|
||||
|
||||
说明:
|
||||
|
||||
1. 本轮没有改 prompt 文本。
|
||||
2. 本轮没有新增或删减 runtime functionId。
|
||||
3. 本轮只是把既有交互语义和动作结算职责收回到后端。
|
||||
|
||||
## 4. 验证结果
|
||||
|
||||
已执行并通过:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npx vitest run src/services/runtimeStoryService.test.ts src/hooks/story/npcEncounterActions.test.ts`
|
||||
3. `npx tsx --test server-node/src/modules/story/runtimeSession.test.ts`
|
||||
|
||||
新增的防回退验证包括:
|
||||
|
||||
1. 前端 `runtimeStoryService` 会保留并消费服务端返回的 `interaction`
|
||||
2. `npcEncounterActions` 的 `help / leave / fight / spar` 明确走服务端 resolver
|
||||
3. `npc_quest_turn_in` 会把 `questId` 原样透传到后端
|
||||
4. 后端 `runtimeSession` 明确直接构建并透传 NPC option interaction
|
||||
5. 待接委托正式接取会复用快照中的 pending quest,而不是在接取瞬间重新造一份 quest
|
||||
6. 待接委托接取后仍保持 NPC 聊天展示态,并清空 `pendingQuestOffer`
|
||||
7. NPC chat turn 的 pending quest offer 现在由后端直接产出,前端不再本地二次决定
|
||||
8. 浏览器端 quest / runtime item 已不再保留直接调用本地 LLM 的 fallback orchestration
|
||||
|
||||
补充说明:
|
||||
|
||||
1. `server-node/src/modules/story/storyActionRoutes.test.ts` 已补充路由级 interaction 断言。
|
||||
2. `2026-04-20` 的补充收口改为以 `storyActionRoutes.test.ts` 直接覆盖待接委托正式接取链路,验证快照输入与快照输出是否都以后端为准。
|
||||
3. 本轮没有改 prompt 文本,也没有新增函数能力面,只是继续把现有 runtime story 结算权后移。
|
||||
|
||||
## 5. 暂未处理的后续边界项
|
||||
|
||||
这轮故意没有继续扩大的点:
|
||||
|
||||
1. `server-node/src/modules/ai/customWorldOrchestrator.ts` 仍直接依赖 `src/services/customWorld*.ts`
|
||||
2. `server-node/src/services/customWorldAgentFoundationDraftService.ts` 仍直接依赖 `src/services/customWorld*.ts` 与 `src/types.ts`
|
||||
3. `pending quest offer` 的 replace / abandon 仍由前端 UI 壳层协调
|
||||
4. 浏览历史、本地快照真相源、custom-world 领域规则共享化仍需后续阶段继续推进
|
||||
|
||||
原因:
|
||||
|
||||
1. 这些点会牵涉 shared contract 抽取与较大范围重组
|
||||
2. 若与本轮 runtime story 收口混做,容易把“边界迁移”误做成“需求改造”
|
||||
|
||||
因此本轮把范围锁在 runtime story 主链,优先交付一条可验证、可继续扩展的后端边界基线。
|
||||
Reference in New Issue
Block a user