@@ -124,7 +124,7 @@
|
||||
|
||||
工具链:
|
||||
|
||||
- `scripts/dev-server/localApiPlugins.ts`:`1504` 行
|
||||
- `scripts/dev-server/*.ts`:已于 `2026-04-19` 删除,旧 Vite 本地 API 链路不再保留实现代码
|
||||
|
||||
#### 影响
|
||||
|
||||
@@ -145,27 +145,27 @@
|
||||
|
||||
---
|
||||
|
||||
### P1-2:继续收口 editor / assets 工具链边界
|
||||
### P1-2:继续收口 editor / assets 工具链边界(旧链路已删除)
|
||||
|
||||
这项的重要性正在上升。
|
||||
|
||||
#### 证据
|
||||
|
||||
- `docs/technical/EDITOR_ASSET_API_MIGRATION_2026-04-08.md` 已说明 editor/assets API 已经迁到 `server-node`,方向是对的。
|
||||
- 但当前仓库里仍保留一个 `1504` 行的 `scripts/dev-server/localApiPlugins.ts`。
|
||||
- `scripts/dev-server/*.ts` 旧 Vite 本地 API 实现代码已于 `2026-04-19` 删除,仓库里不再保留并行实现。
|
||||
- 目录 `temp-build-goal-check/` 当前包含 `15099` 个文件,已经开始干扰 lint 和本地开发信号。
|
||||
- 相关日志里还出现了大量指向 `temp-build-goal-check` 的页面 reload 与 `ENOENT` 噪音。
|
||||
|
||||
#### 影响
|
||||
|
||||
- 旧工具链虽然“不再是主入口”,但它们还在继续占据认知空间和仓库噪音预算。
|
||||
- 新旧 editor/assets 路径长期并存,会导致维护者很难快速判断哪条链才是正式路径。
|
||||
- editor/assets 正式入口已经收口到 `server-node`,这部分双链路问题已解除。
|
||||
- 当前更大的噪音来源已经转移到临时构建目录、检查目录和历史日志残留。
|
||||
|
||||
#### 当前建议
|
||||
|
||||
1. 明确把旧 Vite 插件链标记为迁移参考,避免继续被误用。
|
||||
1. 保持 `scripts/dev-server/README.md` 作为迁移结果标记,不要恢复旧 Vite `/api/*` 本地插件链。
|
||||
2. 将临时构建目录、检查目录、导出目录统一移出主工程扫描面。
|
||||
3. 对 editor/assets 正式入口补一份“唯一推荐入口”文档或 README 更新,减少后续回流。
|
||||
3. 继续以 `server-node/src/modules/editor/**`、`server-node/src/modules/assets/**` 与 `src/editor/shared/editorApiClient.ts` 作为唯一推荐入口,减少后续回流。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,91 @@
|
||||
# 工程清理与后端边界审计(2026-04-19)
|
||||
|
||||
更新时间:`2026-04-19`
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0.1 执行回填(2026-04-19)
|
||||
|
||||
本文审计项 `3.2` 与 `4.4` 已于 `2026-04-19` 当日完成首轮处置:
|
||||
|
||||
1. 已删除 `scripts/dev-server/localApiPlugins.ts`
|
||||
2. 已删除 `scripts/dev-server/characterAssetStudioPlugins.ts`
|
||||
3. 已删除 `scripts/dev-server/qwenSpriteSheetToolPlugins.ts`
|
||||
4. `scripts/dev-server/` 目录仅保留迁移说明,不再保留旧 Vite 本地 API 实现代码
|
||||
5. 当前正式入口统一为 `scripts/dev-node.mjs + vite proxy + server-node/src/modules/**`
|
||||
|
||||
本文其余段落保留为本次审计时的原始问题快照,用于解释为什么要做这轮删除。
|
||||
|
||||
## 0.2 执行回填(2026-04-19,仓库噪音产物)
|
||||
|
||||
本文审计项 `3.1` 已于 `2026-04-19` 当日完成首轮处置:
|
||||
|
||||
1. 已从版本库删除以下根目录历史扫描/截图产物:
|
||||
- `npc-editor-dom.html`
|
||||
- `npc-editor-shot.png`
|
||||
- `temp-write-check.txt`
|
||||
- `tmp_character_presets_scan.txt`
|
||||
- `tmp_jsx_text_scan.txt`
|
||||
- `tmp_runtime_text_scan.txt`
|
||||
- `tmp_text_candidates.txt`
|
||||
- `tmp_text_candidates_refined.txt`
|
||||
- `tmp_visible_props_scan.txt`
|
||||
- `tmp_volc_seedance_doc.html`
|
||||
2. 已从版本库删除 `scripts/__pycache__/generate-build-tag-similarity.cpython-313.pyc`。
|
||||
3. 已清理本地工作区中的 `.codex-*.log`、`.preview.*`、`npc-editor-console.log` 与 `temp-build-goal-check/`,清理前对应体量约为:
|
||||
- 根目录噪音文件 `60` 个,约 `49.94 MB`
|
||||
- `temp-build-goal-check/` 共 `15620` 个条目,约 `158.85 MB`
|
||||
4. 已补齐 `.gitignore`、`.prettierignore` 与 `.eslintrc.cjs` 的忽略口径,显式覆盖 `tmp_*`、`tmp/`、`npc-editor-*`、`temp-write-check.txt`、`temp-build-goal-check/`、`__pycache__/`。
|
||||
5. `scripts/dev-server/localApiPlugins.ts` 之外的后端边界收口项不在本轮噪音清理范围内,后续继续按本文第二至第四阶段推进。
|
||||
|
||||
## 0.3 执行回填(2026-04-19,运行时边界第一轮收口)
|
||||
|
||||
本文审计项 `4.1` 与 `5.1` 已于 `2026-04-19` 当日完成一轮工程收口:
|
||||
|
||||
1. `RuntimeStoryOptionView` 现在由后端直接附带 `interaction` 元数据。
|
||||
2. `server-node/src/modules/story/runtimeSession.ts` 已成为 runtime option interaction 的唯一构建位置。
|
||||
3. `src/services/runtimeStoryService.ts` 不再根据 `currentEncounter + functionId` 在前端本地重建一份 interaction 映射。
|
||||
4. `/api/custom-world/scene-image` 已补齐服务端 prompt 兜底组装能力,允许前端只提交 `profile + landmark + userPrompt` 上下文。
|
||||
5. `src/services/aiService.ts` 的场景图 SDK 已改为直接调用后端接口,不再为了该链路动态加载 `src/services/ai.ts`。
|
||||
|
||||
## 0.4 执行回填(2026-04-19,自定义世界后端边界第二轮收口)
|
||||
|
||||
本文审计项 `5.2` 与“第三阶段第 4 条:清理 `server-node -> src/**` 的反向依赖”已于 `2026-04-19` 当日完成第二轮工程收口:
|
||||
|
||||
1. `server-node/src/modules/custom-world/` 已新增服务端自持 runtime 模块,承接:
|
||||
- `creator intent` 归一化
|
||||
- `anchorPack / lockState` 推导
|
||||
- custom world framework/profile compile 与 normalize
|
||||
2. `server-node/src/modules/ai/customWorldOrchestrator.ts` 与 `server-node/src/services/customWorldAgentFoundationDraftService.ts` 已不再运行时依赖:
|
||||
- `src/services/customWorld.js`
|
||||
- `src/services/customWorldBuilder.js`
|
||||
- `src/services/customWorldCreatorIntent.js`
|
||||
- `src/types.js`
|
||||
3. `server-node/src/prompts/customWorldPrompts.ts` 已成为后端自持的 custom world prompt source,`scene image` 与 `foundation draft` 相关 builder 不再从前端 `src/prompts/customWorldPrompts.ts` 反向 import。
|
||||
4. 本轮只迁移 prompt source 位置,没有改动任何 custom world 提示词正文,也没有改动功能需求。
|
||||
|
||||
## 0.5 执行回填(2026-04-20,NPC 待接委托正式接取收口)
|
||||
|
||||
本文审计项 `5.3` 已于 `2026-04-20` 完成一轮补充收口:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts` 中“聊天里的待接委托正式接取”已不再由前端本地直接写入:
|
||||
- `quests`
|
||||
- `runtimeStats.questsAccepted`
|
||||
- `npcChatState.pendingQuestOffer`
|
||||
2. `server-node/src/modules/quest/questStoryActionService.ts` 现在会优先读取服务端快照里已保存的 `pendingQuestOffer.quest`,按当前聊天态中已经展示给玩家的那份委托完成正式接取。
|
||||
3. `server-node/src/modules/story/storyActionService.ts` 已补齐待接委托接取后的聊天态投影:
|
||||
- 保留 NPC 对话展示模式
|
||||
- 清空 `pendingQuestOffer`
|
||||
- 回到既有的三条自由追问建议
|
||||
4. 本轮没有新增任何 runtime functionId,也没有改动任务生成提示词或任务需求,只是把既有“接任务”正式结算权收回到后端。
|
||||
|
||||
## 0.6 执行回填(2026-04-20,NPC 聊天任务草案与浏览器 LLM fallback 收口)
|
||||
|
||||
本文审计项 `5.1` 与 `5.3` 已于 `2026-04-20` 完成一轮补充收口:
|
||||
|
||||
1. `server-node/src/modules/ai/chatOrchestrator.ts` 现在会基于 `NPC chat turn` 的运行时上下文,在后端判断是否触发 `pendingQuestOffer`,并把 quest draft 与引导文案一并回填给前端。
|
||||
2. `src/hooks/story/npcEncounterActions.ts` 不再在 NPC 单轮聊天完成后本地调用 `generateQuestForNpcEncounter(...)` 再决定是否挂出待接委托。
|
||||
3. `src/services/questDirector.ts` 浏览器端在后端失败时不再退回本地 LLM 生成 quest draft,而是直接走 deterministic fallback compile。
|
||||
4. `src/services/runtimeItemAiDirector.ts` 浏览器端在后端失败时不再退回本地 LLM 生成 runtime item intent,而是直接返回 deterministic fallback intents。
|
||||
5. 本轮仍未改动任何业务提示词正文,也没有改动 quest / runtime item 的需求能力面,只是继续清理浏览器里的正式 AI orchestration 残留。
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
@@ -71,11 +156,11 @@
|
||||
|
||||
### 证据
|
||||
|
||||
| 项目 | 当前证据 | 判断 |
|
||||
| --- | --- | --- |
|
||||
| 根目录日志/临时文件 | 根目录命中 `60` 个 `.codex-*.log`、`.preview.*`、`tmp_*`、`npc-editor-*`、`temp-write-check.txt`,合计约 `52.36 MB` | 已经不是偶发临时文件,而是长期堆积的开发残留 |
|
||||
| `temp-build-goal-check/` | 当前包含 `15099` 个文件,合计约 `166.56 MB` | 大体量检查产物,应该移出主工程视野 |
|
||||
| Python 缓存 | 当前存在 `scripts/__pycache__/` | 纯缓存产物,不应长期留在仓库工作区中 |
|
||||
| 项目 | 当前证据 | 判断 |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
||||
| 根目录日志/临时文件 | 根目录命中 `60` 个 `.codex-*.log`、`.preview.*`、`tmp_*`、`npc-editor-*`、`temp-write-check.txt`,合计约 `52.36 MB` | 已经不是偶发临时文件,而是长期堆积的开发残留 |
|
||||
| `temp-build-goal-check/` | 当前包含 `15099` 个文件,合计约 `166.56 MB` | 大体量检查产物,应该移出主工程视野 |
|
||||
| Python 缓存 | 当前存在 `scripts/__pycache__/` | 纯缓存产物,不应长期留在仓库工作区中 |
|
||||
|
||||
### 影响
|
||||
|
||||
@@ -123,20 +208,20 @@
|
||||
|
||||
### 高置信度无入口/仅测试引用清单
|
||||
|
||||
| 模块 | 证据 | 判断 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/GameShell.tsx` | 文件体量 `761` 行;当前 `src/App.tsx` 只接入 `components/game-shell/GameShellRuntime.tsx`;仓库内无其它 import | 旧版壳层残留 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationHub.tsx` | 仅被 `CustomWorldCreationHub.test.tsx` 和 `CustomWorldCreationHub.interaction.test.tsx` 引用;`src/routing/appRoutes.tsx` 只有 `game` 和 `qwen-sprite-tool` 两条路由 | 已做出 UI,但未进入正式入口 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | 当前无运行时引用 | 同属未接线入口壳层 |
|
||||
| `src/components/custom-world-agent/*` 中 `9` 个子模块 | 当前合计约 `826` 行;典型文件包括 `CustomWorldAgentLauncherModal.tsx`、`CustomWorldAgentDraftDrawer.tsx`、`CustomWorldAgentLockBar.tsx`、`CustomWorldAgentQuickActions.tsx`、`CustomWorldAgentSummaryPanel.tsx`;部分文件完全无引用,部分仅被测试引用 | 处于“做了一部分 UI,但未进入主链”的孤岛状态 |
|
||||
| `src/hooks/story/storyBootstrap.ts` | `250` 行,仓库内只定义不消费 | 已被新流程替代的可能性高 |
|
||||
| `src/hooks/useEquipmentFlow.ts` / `useForgeFlow.ts` / `useInventoryFlow.ts` | 合计约 `393` 行,当前无运行时引用 | 旧流转层残留 |
|
||||
| `src/editor/shared/cloneValue.ts` / `EditorEmptyState.tsx` / `EditorSelectionCard.tsx` / `useJsonSave.ts` | 当前无运行时引用 | editor 旧共享层碎片 |
|
||||
| `src/services/customWorldPresentation.stub.ts` | 当前无引用,且文件本身就是 stub | 高置信度占位残留 |
|
||||
| `src/services/typewriter.ts` | 当前无引用,仅提供一个 `getTypewriterDelay` | 已被其它链路内联实现替代 |
|
||||
| `src/data/buildTagSimilarity.generated.ts` | 当前 `823` 行,仅能被生成脚本自身检索到,没有消费方 | 生成产物未接入任何业务链路 |
|
||||
| `src/data/customWorldCharacterLoadout.stub.ts` | 当前无引用,且实现只返回空数组 | 占位残留 |
|
||||
| `src/components/DeveloperTeamModal.tsx` / `src/components/LazySkillEffectPreview.tsx` | 当前无运行时引用 | 小体量零散孤岛 |
|
||||
| 模块 | 证据 | 判断 |
|
||||
| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
||||
| `src/components/GameShell.tsx` | 文件体量 `761` 行;当前 `src/App.tsx` 只接入 `components/game-shell/GameShellRuntime.tsx`;仓库内无其它 import | 旧版壳层残留 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationHub.tsx` | 仅被 `CustomWorldCreationHub.test.tsx` 和 `CustomWorldCreationHub.interaction.test.tsx` 引用;`src/routing/appRoutes.tsx` 只有 `game` 和 `qwen-sprite-tool` 两条路由 | 已做出 UI,但未进入正式入口 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | 当前无运行时引用 | 同属未接线入口壳层 |
|
||||
| `src/components/custom-world-agent/*` 中 `9` 个子模块 | 当前合计约 `826` 行;典型文件包括 `CustomWorldAgentLauncherModal.tsx`、`CustomWorldAgentDraftDrawer.tsx`、`CustomWorldAgentLockBar.tsx`、`CustomWorldAgentQuickActions.tsx`、`CustomWorldAgentSummaryPanel.tsx`;部分文件完全无引用,部分仅被测试引用 | 处于“做了一部分 UI,但未进入主链”的孤岛状态 |
|
||||
| `src/hooks/story/storyBootstrap.ts` | `250` 行,仓库内只定义不消费 | 已被新流程替代的可能性高 |
|
||||
| `src/hooks/useEquipmentFlow.ts` / `useForgeFlow.ts` / `useInventoryFlow.ts` | 合计约 `393` 行,当前无运行时引用 | 旧流转层残留 |
|
||||
| `src/editor/shared/cloneValue.ts` / `EditorEmptyState.tsx` / `EditorSelectionCard.tsx` / `useJsonSave.ts` | 当前无运行时引用 | editor 旧共享层碎片 |
|
||||
| `src/services/customWorldPresentation.stub.ts` | 当前无引用,且文件本身就是 stub | 高置信度占位残留 |
|
||||
| `src/services/typewriter.ts` | 当前无引用,仅提供一个 `getTypewriterDelay` | 已被其它链路内联实现替代 |
|
||||
| `src/data/buildTagSimilarity.generated.ts` | 当前 `823` 行,仅能被生成脚本自身检索到,没有消费方 | 生成产物未接入任何业务链路 |
|
||||
| `src/data/customWorldCharacterLoadout.stub.ts` | 当前无引用,且实现只返回空数组 | 占位残留 |
|
||||
| `src/components/DeveloperTeamModal.tsx` / `src/components/LazySkillEffectPreview.tsx` | 当前无运行时引用 | 小体量零散孤岛 |
|
||||
|
||||
### 判断
|
||||
|
||||
@@ -521,4 +606,3 @@
|
||||
6. `vite.config.ts`
|
||||
7. `.eslintrc.cjs`
|
||||
8. `git grep` 对关键模块引用、后端跨层 import、localStorage、旧 dev 插件入口的扫描结果
|
||||
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
# 高好感角色聊天内委托触发与领取流程设计
|
||||
|
||||
更新时间:`2026-04-19`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这次迭代解决的是一个很具体的体验断层:
|
||||
|
||||
1. 当前角色委托主要还是从 NPC 互动菜单里直接出现,缺少“先聊上 1-2 轮,再顺着上下文自然托付任务”的过渡。
|
||||
2. 聊天态虽然已经有多轮对话、自定义输入和选项建议,但没有“临时任务 offer”这一层中间状态。
|
||||
3. 现有任务详情面板已经能看任务、领奖励,但还不能承接“任务尚未正式入日志,只是对方刚提出委托”的场景。
|
||||
|
||||
目标不是新造一套聊天任务系统,而是把现有:
|
||||
|
||||
- `npc_chat` 多轮聊天流
|
||||
- `generateQuestForNpcEncounter(...)` 任务生成链
|
||||
- `QuestLogEntry` 任务日志结构
|
||||
- `AdventurePanelOverlays` 任务详情面板
|
||||
|
||||
串成一条更自然的“聊天内委托”链路。
|
||||
|
||||
一句话目标:
|
||||
|
||||
**当玩家与好感度大于 0 的角色聊天时,先寒暄 1-2 轮,再由角色顺着上下文提出委托;玩家可查看、换任务、放弃任务,确认领取后任务才正式进入日志,并恢复自由聊天。**
|
||||
|
||||
## 1. 这次不做什么
|
||||
|
||||
为了避免系统边界漂移,这次明确不做下面这些事:
|
||||
|
||||
1. 不重写任务生成器。
|
||||
- “任务”和“更换任务”都必须复用现有 `generateQuestForNpcEncounter(...)` 链路。
|
||||
- 也就是说,仍然走现在的 `evaluateQuestOpportunity -> AI / fallback quest intent -> compileQuestIntentToQuest`。
|
||||
|
||||
2. 不把聊天态任务 offer 直接视为已接任务。
|
||||
- 对方刚把委托提出来时,它还只是 `pending offer`,不应立即写进 `gameState.quests`。
|
||||
- 只有玩家点击“领取任务”后,才正式调用现有任务接取写入逻辑。
|
||||
|
||||
3. 不在 UI 默认堆说明文字。
|
||||
- 聊天态只切换三项操作:
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
- 不额外在主界面堆功能说明。
|
||||
|
||||
4. 不改成必须走服务端聊天。
|
||||
- 当前多轮 NPC 聊天仍沿用前端本地的 `handleNpcChatTurn(...)` 流程。
|
||||
- 这次只是在聊天流程里插入任务 offer 状态。
|
||||
|
||||
## 2. 核心流程
|
||||
|
||||
## 2.1 触发条件
|
||||
|
||||
只有同时满足下面条件时,聊天中才允许提出委托:
|
||||
|
||||
1. 当前遭遇是角色型 NPC。
|
||||
- `encounter.characterId` 存在。
|
||||
|
||||
2. 当前好感度大于 `0`。
|
||||
|
||||
3. 当前角色没有未结清任务。
|
||||
- 复用 `getQuestForIssuer(...)` 判断。
|
||||
|
||||
4. 当前聊天里还没有待处理的任务 offer。
|
||||
|
||||
5. 已经完成前置寒暄轮次。
|
||||
- 默认要求先完成 `1-2` 轮自然聊天。
|
||||
- 建议规则:
|
||||
- `affinity >= 30` 时,完成 `1` 轮后即可进入委托时机。
|
||||
- `0 < affinity < 30` 时,完成 `2` 轮后再进入委托时机。
|
||||
|
||||
## 2.2 聊天轮次切换
|
||||
|
||||
正常聊天时:
|
||||
|
||||
- 保持现有三条 `npc_chat` 建议选项
|
||||
- 保持自定义输入可用
|
||||
|
||||
当触发委托时:
|
||||
|
||||
1. 先正常生成本轮 NPC 回复。
|
||||
2. 随后调用现有 `generateQuestForNpcEncounter(...)` 生成一份 `pending quest offer`。
|
||||
3. 在当前轮次追加一段 NPC 委托台词。
|
||||
4. 把当前轮次选项替换成:
|
||||
- 第一项:`查看任务`
|
||||
- 第二项:`更换任务`
|
||||
- 第三项:`放弃任务`
|
||||
5. 临时隐藏自定义输入。
|
||||
|
||||
这意味着聊天态此时进入一个短暂的“任务处理态”,直到玩家:
|
||||
|
||||
- 查看并领取
|
||||
- 更换
|
||||
- 放弃
|
||||
|
||||
其中任一分支结算完成后,再恢复自由聊天。
|
||||
|
||||
## 2.3 查看任务
|
||||
|
||||
点击 `查看任务` 时:
|
||||
|
||||
1. 不立即写入任务日志。
|
||||
2. 直接复用现有任务详情弹层展示 `pending quest offer` 的详情。
|
||||
3. 任务详情面板在这类任务上新增主按钮:
|
||||
- `领取任务`
|
||||
|
||||
这一步的关键是:
|
||||
|
||||
**查看任务只是看,不等于接。**
|
||||
|
||||
## 2.4 领取任务
|
||||
|
||||
点击 `领取任务` 时:
|
||||
|
||||
1. 使用当前 `pending quest offer` 的 `QuestLogEntry`,调用现有任务接取写入逻辑,把任务正式写入 `gameState.quests`。
|
||||
2. 同时把这轮动作写回聊天:
|
||||
- 追加玩家一句明确接受委托的话。
|
||||
- 可追加一条简短 NPC 确认回应,或直接用现有结果文案转成对话语义。
|
||||
3. 更新 `storyHistory`,确保后续聊天上下文知道“这份委托已经接下”。
|
||||
4. 清空 `pending quest offer`。
|
||||
5. 恢复正常 `npc_chat` 建议选项与自定义输入。
|
||||
|
||||
## 2.5 更换任务
|
||||
|
||||
点击 `更换任务` 时:
|
||||
|
||||
1. 必须再次调用现有 `generateQuestForNpcEncounter(...)`。
|
||||
2. 旧的 `pending quest offer` 被新的覆盖。
|
||||
3. 当前聊天追加一条“对方换了个委托”的回应。
|
||||
4. 仍然维持任务处理态:
|
||||
- 继续显示
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
- 自定义输入仍隐藏
|
||||
|
||||
这里的关键约束是:
|
||||
|
||||
**更换任务不是本地改标题或改描述,而是重新走现有任务生成链。**
|
||||
|
||||
## 2.6 放弃任务
|
||||
|
||||
点击 `放弃任务` 时:
|
||||
|
||||
1. 直接丢弃当前 `pending quest offer`。
|
||||
2. 在对话里补一条“玩家暂时不接”的回应。
|
||||
3. 恢复自由聊天:
|
||||
- 再次显示正常 `npc_chat` 建议
|
||||
- 恢复自定义输入
|
||||
|
||||
放弃这里只作用于“待领取委托”,不会影响已经入日志的正式任务。
|
||||
|
||||
## 3. 数据与状态设计
|
||||
|
||||
## 3.1 聊天态新增待领取任务状态
|
||||
|
||||
建议把这次临时状态挂在 `StoryNpcChatState` 上,而不是直接写入 `GameState.quests`。
|
||||
|
||||
```ts
|
||||
interface StoryNpcQuestOfferState {
|
||||
quest: QuestLogEntry;
|
||||
}
|
||||
|
||||
interface StoryNpcChatState {
|
||||
npcId: string;
|
||||
npcName: string;
|
||||
turnCount: number;
|
||||
customInputPlaceholder?: string;
|
||||
pendingQuestOffer?: StoryNpcQuestOfferState | null;
|
||||
}
|
||||
```
|
||||
|
||||
这样有 3 个好处:
|
||||
|
||||
1. 任务 offer 只属于当前聊天上下文,不污染正式任务日志。
|
||||
2. AdventurePanel 可以直接从 `currentStory.npcChatState` 判断是否进入任务处理态。
|
||||
3. 任务详情面板可以直接读取这份 `QuestLogEntry` 展示,而不用再造一套展示结构。
|
||||
|
||||
## 3.2 任务处理态的选项表达
|
||||
|
||||
建议不要把“查看 / 更换 / 放弃”接进服务端 runtime action。
|
||||
|
||||
原因是:
|
||||
|
||||
1. `查看任务` 只是 UI 行为,不需要服务端结算。
|
||||
2. `更换任务` 和 `放弃任务` 都是当前聊天态内部状态流转。
|
||||
3. 这三项更适合作为本地聊天态专用选项,由 `AdventurePanel + npcEncounterActions` 协同处理。
|
||||
|
||||
建议做成 3 个本地专用 `StoryOption`:
|
||||
|
||||
```ts
|
||||
{
|
||||
functionId: 'npc_chat_quest_offer_view',
|
||||
actionText: '查看任务',
|
||||
runtimePayload: { npcChatQuestOfferAction: 'view' }
|
||||
}
|
||||
```
|
||||
|
||||
其余两个同理:
|
||||
|
||||
- `replace`
|
||||
- `abandon`
|
||||
|
||||
## 3.3 接取后的正式写入
|
||||
|
||||
正式领取后才进入任务日志:
|
||||
|
||||
```ts
|
||||
nextState = {
|
||||
...state,
|
||||
quests: acceptQuest(state.quests, pendingQuest.quest),
|
||||
runtimeStats: incrementGameRuntimeStats(state.runtimeStats, {
|
||||
questsAccepted: 1,
|
||||
}),
|
||||
}
|
||||
```
|
||||
|
||||
也就是说:
|
||||
|
||||
- `pending offer` 不计入 `questsAccepted`
|
||||
- 真正点击 `领取任务` 才计数
|
||||
|
||||
## 4. UI 落点
|
||||
|
||||
## 4.1 聊天面板
|
||||
|
||||
`AdventurePanel` 中增加一个判断:
|
||||
|
||||
1. `currentStory.npcChatState?.pendingQuestOffer` 存在时:
|
||||
- 只显示三项任务处理选项
|
||||
- 隐藏自定义输入
|
||||
|
||||
2. 不存在时:
|
||||
- 保持现有聊天输入与 `npc_chat` 建议
|
||||
|
||||
## 4.2 任务详情弹层
|
||||
|
||||
`AdventurePanelOverlays` 里的任务详情弹层继续复用,但要区分两种任务来源:
|
||||
|
||||
1. 已在任务日志中的正式任务
|
||||
- 保持现有逻辑
|
||||
- 完成后仍显示 `领取奖励`
|
||||
|
||||
2. 聊天里的 `pending quest offer`
|
||||
- 底部显示 `领取任务`
|
||||
- 不显示 `领取奖励`
|
||||
|
||||
点击 `领取任务` 后:
|
||||
|
||||
- 关闭详情弹层
|
||||
- 回到聊天界面
|
||||
- 当前聊天追加“我愿意接下”这一步
|
||||
|
||||
## 5. 代码改动建议
|
||||
|
||||
建议落地在这些文件:
|
||||
|
||||
1. `src/types/story.ts`
|
||||
- 扩展 `StoryNpcChatState`
|
||||
|
||||
2. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 增加聊天内任务 offer 触发判断
|
||||
- 接入 `generateQuestForNpcEncounter(...)`
|
||||
- 增加
|
||||
- 更换任务
|
||||
- 放弃任务
|
||||
- 领取任务
|
||||
对应的本地状态流转
|
||||
|
||||
3. `src/hooks/story/useStoryInteractionCoordinator.ts`
|
||||
- 向上暴露聊天内任务 offer 的操作方法
|
||||
|
||||
4. `src/hooks/useStoryGeneration.ts`
|
||||
- 把聊天内任务 offer UI 能力透传给面板
|
||||
|
||||
5. `src/components/AdventurePanel.tsx`
|
||||
- 聊天态隐藏 / 恢复输入
|
||||
- 拦截 `查看任务 / 更换任务 / 放弃任务`
|
||||
- 让 pending quest 也能进入任务详情弹层
|
||||
|
||||
6. `src/components/adventure-panel/AdventurePanelOverlays.tsx`
|
||||
- 为 pending quest 增加 `领取任务` 按钮
|
||||
|
||||
7. `src/components/AdventurePanel.test.tsx`
|
||||
- 补聊天态输入隐藏测试
|
||||
|
||||
8. `src/hooks/story/npcEncounterActions.test.ts`
|
||||
- 补任务 offer 触发 / 更换 / 接取测试
|
||||
|
||||
## 6. 验收标准
|
||||
|
||||
做到以下几点,才算这次需求成立:
|
||||
|
||||
1. 与好感度大于 `0` 的角色聊天时,不会一上来立刻塞任务,前 `1-2` 轮先正常寒暄。
|
||||
2. 达到委托时机后,系统会调用现有 `generateQuestForNpcEncounter(...)` 生成一份待领取任务。
|
||||
3. 当前聊天轮次会出现一段明确的委托台词。
|
||||
4. 这一轮聊天选项会切成:
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
5. 任务处理态下,自定义输入会被临时隐藏。
|
||||
6. 点击 `查看任务` 会弹出现有任务详情面板。
|
||||
7. 点击 `领取任务` 后,任务才正式进入任务日志,并在对话里体现“玩家愿意接下”。
|
||||
8. 领取完成后,聊天会恢复正常输入与自由继续对话。
|
||||
9. 点击 `更换任务` 时,必须重新调用现有任务生成链,而不是本地改文案。
|
||||
|
||||
## 7. 一句话收束
|
||||
|
||||
这次要做的,不是“让聊天里多一个任务按钮”,而是把:
|
||||
|
||||
- 高好感聊天
|
||||
- 上下文化任务生成
|
||||
- 临时任务 offer
|
||||
- 任务详情查看
|
||||
- 正式领取后回流聊天
|
||||
|
||||
整合成一个更自然的叙事交接过程。
|
||||
@@ -134,6 +134,17 @@
|
||||
- 公开作品广场
|
||||
- 本地浏览历史
|
||||
|
||||
公开作品广场前端请求约束:
|
||||
|
||||
- `listCustomWorldGallery`
|
||||
- `getCustomWorldGalleryDetail`
|
||||
|
||||
这两类公开请求必须走“公开只读请求”通道:
|
||||
|
||||
- 不主动附带 `Authorization`
|
||||
- 不因本地 access token 失效去触发 `/api/auth/refresh`
|
||||
- refresh cookie 缺失、refresh 失败、账号状态过期时,不能把首页公开作品广场一起拖成错误态
|
||||
|
||||
未登录时不读取:
|
||||
|
||||
- 自定义世界库
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
- 大圆角卡片
|
||||
- 半透明玻璃质感
|
||||
- 平台正文与功能信息统一使用 `Inter + Noto Serif SC`
|
||||
- 左上角品牌区允许使用专用像素字标组件或直接使用 `Fusion Pixel` 文本,但仅限品牌 logo,不向正文、按钮、标签扩散
|
||||
- 品牌 logo 只能复用游戏现有 `Fusion Pixel`,不允许再引入第二套像素字体文件
|
||||
|
||||
主题基准:
|
||||
|
||||
@@ -57,6 +59,10 @@
|
||||
### 3.2 排版
|
||||
|
||||
- 平台层正文、按钮、说明、功能标签统一使用非像素字体
|
||||
- 左上角 `叙世 / GENARRATIVE` 品牌字标允许单独做成像素化 logo
|
||||
- `GENARRATIVE` 与 `叙世` 都优先直接使用游戏内同款 `Fusion Pixel`
|
||||
- 品牌字标默认保持正常像素字观感,禁止再叠双层粗阴影或手动加粗到影响识别
|
||||
- 品牌字标直接使用字体文件内原字形,不额外做运行时描字、轮廓拼字或伪粗体处理
|
||||
- 主标题保留明显层级,但不再做像素描边效果
|
||||
- 微型标签维持高字距英文/中文短标签,用来保留产品感和秩序感
|
||||
|
||||
@@ -69,8 +75,12 @@
|
||||
- 弹窗:沿用登录页的圆角浮层和半透明遮罩,不再使用像素弹窗边框
|
||||
- 桌面壳层:首页允许增加顶部工具栏、左侧导航轨、中央内容舞台与右侧趋势面板的组合
|
||||
- 登录页、绑定手机号、账户弹窗、平台详情、创作生成页、结果页、编辑弹窗都必须共享同一套平台主题 token,禁止再各自写一套独立旧色板
|
||||
- 创作中心、Agent 工作台、草稿详情抽屉、资产工坊、启动弹窗、生成弹窗这类二三级平台面板必须显式挂载平台主题壳层或平台 remap 容器,禁止直接在局部面板里写死旧深色 modal 底和旧输入框底色
|
||||
- 平台“我的”页中的“设置”入口必须打开真正的设置面板;账号信息、设备管理、安全状态属于设置面板中的分区,不允许再把账号信息弹层直接充当设置页
|
||||
- 设置面板必须支持平台亮色 / 暗色主题切换,并复用同一套平台 token 驱动登录页、首页、详情页与二三级面板
|
||||
- 首页移动端底部 Tab 与桌面侧边导航的图标底座、图标颜色、文字状态必须全部由平台 token 驱动;暗色主题下不得出现过浅底座和错误文字色,亮色主题下不得残留旧灰蓝 inactive 状态
|
||||
- 首页、存档页、作品详情这类平台主导航与局部 Tab 的 active fill、active shadow、icon shell fill 必须全部来自主题 token;暗色主题禁止继续复用亮色主题的粉橘高光、白色 active 底座
|
||||
- “我的”页账号主卡必须跟随平台亮 / 暗主题联动,不允许继续写死浅色渐变卡面与 `slate` 系按钮
|
||||
|
||||
## 4. 交互与布局约束
|
||||
|
||||
@@ -84,17 +94,19 @@
|
||||
## 5. 实现约束
|
||||
|
||||
- 平台态从 `fusion-pixel-app` 中隔离,避免被全局像素字体覆盖
|
||||
- 品牌区禁止新增额外像素字体包;平台层只允许保留现有 `public/fusion-pixel.ttf` 这一份像素字体资源
|
||||
- 平台态背景不再使用 `/UI/Background_fill.png`
|
||||
- 新样式优先沉淀为平台专用 class / theme token,避免把游戏内像素 class 改坏
|
||||
- 平台默认挂载亮色主题 class,旧紫蓝方案保留为暗色主题 class
|
||||
- 亮色主题需要补齐统一的 overlay、progress track、status pill token,登录弹层与二三级功能面板禁止继续沿用旧深色遮罩与紫蓝强调残留
|
||||
- 平台态中仍保留旧 Tailwind 深色类的历史组件,必须通过平台 remap 容器或平台专用 class 统一收口,不能放任 `bg-[#111318]`、`bg-black/*`、`bg-white/*` 这类旧类在亮色主题下直接裸露
|
||||
- 编辑弹窗保留业务结构与表单逻辑,只替换壳层样式
|
||||
|
||||
## 6. 验收标准
|
||||
|
||||
达到以下结果才算完成:
|
||||
|
||||
1. 平台首页、详情、登录、绑定手机号、账户弹窗、创作入口、创作结果页不再出现像素字体
|
||||
1. 除左上角品牌像素字标外,平台首页、详情、登录、绑定手机号、账户弹窗、创作入口、创作结果页不再出现像素字体
|
||||
2. 平台层按钮、面板、关闭按钮、底部 tab 不再依赖像素 UI 素材
|
||||
3. 平台默认展示亮色主题,暗色主题保留为独立主题方案
|
||||
4. 平台层二三级面板、表单、状态卡、弹窗与登录体系不再残留旧金橙 / 青蓝 / 深黑混搭方案
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
- [RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md](./RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md):专业剧情策划构建 RPG 游戏全剧情的工作流程与交付模板。
|
||||
- [EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md](./EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md):配装构筑与合成/锻造闭环设计。
|
||||
- [COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md](./COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md):角色首遇感、关系分层解锁、私聊系统设计。
|
||||
- [NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md](./NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md):高好感角色在聊天内自然提出委托,并支持查看、更换、放弃、领取的流程设计。
|
||||
- [SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md](./SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md):把每个场景收束成章节单元,并在首进场景时开启章节任务的设计稿。
|
||||
- [SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md](./SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md):对标仙剑、博德之门、黑神话,分析单场景章节的体验缺口,并给出 AI 原生补强方案。
|
||||
- [npc-conversation-situation-draft.md](./npc-conversation-situation-draft.md):NPC 对话阶段和情景注入草案。
|
||||
@@ -27,6 +28,7 @@
|
||||
- 做自定义世界去模板依赖、跨题材泛化、兼容迁移设计时,优先看新增的去模板化优化设计稿。
|
||||
- 做“模板依赖如何真正变成自定义世界自有设定层”的具体迁移方案时,优先看新增的自有设定层优化方案。
|
||||
- 做角色关系、同伴互动、对话表现时,先看后两份。
|
||||
- 做“高好感聊天里如何顺着上下文自然抛出委托、并让任务在聊天内领取”的需求时,优先看新增的聊天委托流程设计稿。
|
||||
- 做剧情引擎章节化、场景闭环、章节任务接入时,优先看新增的场景章节设计稿。
|
||||
- 做“单章节体验还缺什么、该补哪种情感 / 抉择 / 试炼模块”时,优先看新增的章节对标补强设计稿。
|
||||
- 如果要判断是否符合目标,再和 `docs/prd/` 中对应 PRD 对照阅读。
|
||||
|
||||
@@ -498,7 +498,7 @@ type GeneratedCharacterAnimationAsset = {
|
||||
- `src/components/CharacterAnimator.tsx`
|
||||
- `src/types/characters.ts`
|
||||
- `src/data/characterOverrides.json`
|
||||
- `scripts/dev-server/localApiPlugins.ts`
|
||||
- `server-node/src/modules/assets/**`
|
||||
|
||||
建议新增:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AI 原生自定义世界创作页面 PRD
|
||||
|
||||
更新时间:`2026-04-13`
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 文档目的
|
||||
|
||||
@@ -314,9 +314,11 @@ UI 主标题建议:
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. `draftProfile.camp.imageSrc`
|
||||
2. `draftProfile` 中可解析的营地图
|
||||
3. 角色主图或默认创作占位图
|
||||
1. `draftProfile.cover.imageSrc`,当 `sourceType` 为 `uploaded / generated`
|
||||
2. `draftProfile.camp.imageSrc` 作为默认封面底图
|
||||
3. 默认封面底图上叠加 `draftProfile.cover.characterRoleIds` 对应的角色主形象
|
||||
4. 若未显式指定角色,则按 `playableNpcs` 顺序取前 `3` 个有主图的角色
|
||||
5. 若开局场景图为空,则回退到第一张场景图;再不行才回退到首个角色主图或默认占位图
|
||||
|
||||
### 草稿卡片主操作
|
||||
|
||||
@@ -358,9 +360,78 @@ UI 主标题建议:
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. 营地图
|
||||
2. 第一可扮演角色立绘
|
||||
3. 默认已发布作品占位图
|
||||
1. `CustomWorldProfile.cover.imageSrc`,当 `sourceType` 为 `uploaded / generated`
|
||||
2. 开局场景图作为默认封面底图
|
||||
3. 默认封面底图上叠加 `cover.characterRoleIds` 指定的角色主形象
|
||||
4. 若未显式指定角色,则按 `playableNpcs` 顺序取前 `3` 个有主图的角色
|
||||
5. 若默认底图不可用,再回退到第一可扮演角色立绘或默认占位图
|
||||
|
||||
## 7.3 作品封面属性
|
||||
|
||||
作品必须新增显式封面属性,作为作者可编辑的作品资产,而不再只靠“卡片展示时临时猜一张图”。
|
||||
|
||||
建议字段:
|
||||
|
||||
```ts
|
||||
type CustomWorldCoverSourceType = 'default' | 'uploaded' | 'generated';
|
||||
|
||||
interface CustomWorldCoverProfile {
|
||||
sourceType: CustomWorldCoverSourceType;
|
||||
imageSrc?: string | null;
|
||||
characterRoleIds?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
字段含义:
|
||||
|
||||
1. `sourceType = default`
|
||||
- 表示继续使用系统默认封面布局
|
||||
- `imageSrc` 不作为最终封面图使用
|
||||
- 底图固定取“开局场景图”
|
||||
- 前景角色取 `characterRoleIds`
|
||||
|
||||
2. `sourceType = uploaded`
|
||||
- 表示作者直接上传了一张最终封面
|
||||
- 卡片与详情页直接显示 `imageSrc`
|
||||
- 不再叠加默认角色前景
|
||||
|
||||
3. `sourceType = generated`
|
||||
- 表示作者通过 AI 生成了一张最终封面
|
||||
- 卡片与详情页直接显示 `imageSrc`
|
||||
- 不再叠加默认角色前景
|
||||
|
||||
## 7.4 默认封面布局
|
||||
|
||||
默认封面布局不是单纯“取开局场景图”,而是:
|
||||
|
||||
```text
|
||||
开局场景图
|
||||
+ 前景主角色主形象 2~3 个
|
||||
+ 用于列表卡片和作品详情的统一封面预览
|
||||
```
|
||||
|
||||
明确规则:
|
||||
|
||||
1. 默认封面底图固定优先取 `camp.imageSrc`
|
||||
2. 默认前景角色固定从 `playableNpcs` 中取前 `3` 个有主图的角色
|
||||
3. 若作者在 `cover.characterRoleIds` 中显式指定角色,则优先按指定顺序展示
|
||||
4. 前端只负责把后端给出的“底图 + 角色主图列表”渲染成封面,不在前端做封面规则推理
|
||||
5. 已上传或已生成的最终封面,直接作为成品图显示,不再做默认布局叠加
|
||||
|
||||
## 7.5 作者操作
|
||||
|
||||
作者在作品编辑态至少支持 4 个动作:
|
||||
|
||||
1. `使用默认封面`
|
||||
2. `上传封面`
|
||||
3. `AI 生成封面`
|
||||
4. `重置为默认`
|
||||
|
||||
约束:
|
||||
|
||||
1. 上传和 AI 生成都必须把最终图片落到后端资产目录,前端不能长期持有 Data URL 作为作品封面
|
||||
2. 重置为默认后,`sourceType` 回到 `default`
|
||||
3. 草稿与已发布作品都读取同一份封面属性,不允许出现“草稿页是一个封面、发布后又自动换另一张”的漂移
|
||||
|
||||
### 已发布卡片主操作
|
||||
|
||||
@@ -395,6 +466,8 @@ interface CustomWorldWorkSummary {
|
||||
subtitle: string;
|
||||
summary: string;
|
||||
coverImageSrc?: string | null;
|
||||
coverRenderMode?: 'image' | 'scene_with_roles';
|
||||
coverCharacterImageSrcs?: string[];
|
||||
updatedAt: string;
|
||||
publishedAt?: string | null;
|
||||
stage?: string | null;
|
||||
@@ -447,6 +520,25 @@ interface CustomWorldWorkSummary {
|
||||
|
||||
仅已发布作品为 `true`
|
||||
|
||||
### `coverRenderMode / coverCharacterImageSrcs`
|
||||
|
||||
用于支撑默认封面布局。
|
||||
|
||||
规则:
|
||||
|
||||
1. 当作品封面为上传或 AI 生成成图时:
|
||||
- `coverRenderMode = image`
|
||||
- `coverCharacterImageSrcs = []`
|
||||
|
||||
2. 当作品封面为默认布局时:
|
||||
- `coverRenderMode = scene_with_roles`
|
||||
- `coverImageSrc = 开局场景图`
|
||||
- `coverCharacterImageSrcs = 需要叠加的角色主图列表`
|
||||
|
||||
一句话:
|
||||
|
||||
**后端负责告诉前端“这张封面该怎么画”,前端只负责把它画出来。**
|
||||
|
||||
---
|
||||
|
||||
## 9. 后端接口设计
|
||||
@@ -700,8 +792,9 @@ type SelectionStage =
|
||||
|
||||
1. 新建作品区位于首屏
|
||||
2. tabs 横向可滚
|
||||
3. 作品卡优先单列
|
||||
3. 平台“创作”页中的“我的创作”列表在移动端至少双列展示,不能继续沿用横向滚动卡片的固定宽度
|
||||
4. 不使用桌面化大表格
|
||||
5. 双列卡片必须采用紧凑栅格布局,标题、状态、时间允许换行或截断,但不能横向溢出或出现参差错位
|
||||
|
||||
## 12.2 页面保持清爽
|
||||
|
||||
|
||||
@@ -0,0 +1,728 @@
|
||||
# AI 原生场景多幕配置与 NPC 相遇聊天流程 PRD
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 文档目的
|
||||
|
||||
这份 PRD 用于把下面几条已经存在但还没真正接成一条产品主链的设计,收束成一次可直接编码的迭代:
|
||||
|
||||
- `docs/prd/AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md`
|
||||
- `docs/prd/AI_NATIVE_SCENE_CHAPTER_GAMEPLAY_PRD_AND_EXECUTION_PLAN_2026-04-08.md`
|
||||
- `docs/prd/AI_NATIVE_NPC_CHAT_SINGLE_TURN_SESSION_PRD_2026-04-18.md`
|
||||
- `docs/design/NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md`
|
||||
- `docs/design/SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md`
|
||||
|
||||
本次要解决的不是再新建一套场景系统或聊天系统,而是把现有:
|
||||
|
||||
1. 创作工作区
|
||||
2. 场景章节闭环
|
||||
3. NPC 多轮聊天
|
||||
4. 场景背景资产
|
||||
5. 好感度关系流
|
||||
|
||||
接成一条新的稳定流程:
|
||||
|
||||
**每个场景由创作者在工具中配置为 `2~5` 幕;每一幕都绑定独立背景图和相遇 NPC 顺序;每一幕的第一个 NPC 视为主角色;运行时按幕切换背景和可遇对象,并根据主角色当前好感度裁决聊天轮数与第 5 轮收束方式。**
|
||||
|
||||
这份文档必须能直接指导后续创作工具和游戏流程改造,避免需求落地漂移。
|
||||
|
||||
---
|
||||
|
||||
## 1. 一句话定义
|
||||
|
||||
把当前“一个场景只有一层平铺内容”的创作与运行方式,升级成“一个场景内有多幕推进、每幕有独立视觉和主角色相遇规则”的章节内流程。
|
||||
|
||||
---
|
||||
|
||||
## 2. 本次目标
|
||||
|
||||
本次迭代必须同时满足以下目标:
|
||||
|
||||
1. 创作者可以在现有创作页面中为每个场景章节配置多幕内容。
|
||||
2. 每一幕都必须绑定一张正式背景图。
|
||||
3. 每一幕都可以配置玩家会遇到哪些 NPC,并且保留顺序。
|
||||
4. 每一幕配置的第一个 NPC 必须被系统认定为该幕主角色。
|
||||
5. 运行时进入某一幕时,背景图和可遇 NPC 必须随幕切换。
|
||||
6. 当前幕主角色的聊天轮数必须按好感度裁决,而不是继续完全沿用统一规则。
|
||||
7. 好感度大于 `0` 的主角色,在相遇后进入无限轮聊天态,直到玩家主动退出。
|
||||
8. 好感度小于 `0` 的主角色,在相遇后最多只允许聊天 `5` 轮,第 `5` 轮必须输出一段为后续剧情开展铺垫的收束回应。
|
||||
9. 前端继续只负责展示,幕切换、聊天限制、幕进度与数据裁决全部由 Express 后端负责。
|
||||
10. 默认复用现有创作页面、草稿抽屉、详情弹层、场景章节和聊天流程,不新开独立系统或新页面。
|
||||
|
||||
---
|
||||
|
||||
## 3. 明确不做
|
||||
|
||||
本次明确不做下面这些事:
|
||||
|
||||
1. 不新建独立的“场景编辑器”页面。
|
||||
2. 不把幕推进逻辑放到前端本地计算。
|
||||
3. 不让创作者直接编辑底层运行时 `ChapterState` 或聊天状态对象。
|
||||
4. 不做多 NPC 并行聊天。
|
||||
5. 不做每一幕的复杂分支树可视化编辑器。
|
||||
6. 不把“规则说明文案”默认堆到创作页或游戏 UI 面板里。
|
||||
7. 不把“点击配置”实现成在当前卡片下面继续展开大段内容。
|
||||
8. 不重写现有高好感委托链路,只在本次规则下明确它什么时候还能触发。
|
||||
|
||||
---
|
||||
|
||||
## 4. 现状判断
|
||||
|
||||
## 4.1 创作工具侧现状
|
||||
|
||||
当前仓库已经具备下面这些基础:
|
||||
|
||||
1. `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- 已存在 `scene_chapter` 草稿卡 kind。
|
||||
|
||||
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
- 已经能编译世界、第一幕、线程、势力、角色、地点等草稿卡。
|
||||
|
||||
3. `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
|
||||
- 已有草稿抽屉,但还没有把 `scene_chapter` 正式纳入抽屉分组。
|
||||
|
||||
4. 现有场景背景图生成与发布链已存在。
|
||||
|
||||
但当前仍有 4 个缺口:
|
||||
|
||||
1. 场景章节没有“幕”这一层结构化对象。
|
||||
2. 背景图是场景级资产,不是幕级资产。
|
||||
3. NPC 与场景的关系主要还是地点级归属,不是幕级相遇编排。
|
||||
4. 创作者无法在创作页里明确控制“这一幕谁先出场、谁是主角色”。
|
||||
|
||||
## 4.2 游戏运行侧现状
|
||||
|
||||
当前运行时已经具备下面这些基础:
|
||||
|
||||
1. `src/data/questFlow.ts`
|
||||
- 已有 `scene chapter quest` 与 `buildSceneChapterId(...)`。
|
||||
|
||||
2. `src/services/storyEngine/chapterDirector.ts`
|
||||
- 已能按场景章节输出 `ChapterState`。
|
||||
|
||||
3. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 已有 `npc_chat` 多轮聊天、`turnCount`、`pendingQuestOffer` 等状态。
|
||||
|
||||
4. `packages/shared/src/contracts/story.ts`
|
||||
- 已有 `NpcChatTurnRequest` / `NpcChatTurnResult` 契约。
|
||||
|
||||
但当前仍有 5 个问题:
|
||||
|
||||
1. 场景内部仍偏单层推进,缺少“第几幕”的明确状态。
|
||||
2. 场景背景不会随幕切换。
|
||||
3. 场景可遇 NPC 不会随幕切换。
|
||||
4. 主角色没有从配置顺序直接编译成运行时规则。
|
||||
5. 负好感主角色聊天仍没有“最多 5 轮且第 5 轮收束铺垫”的规则。
|
||||
|
||||
一句话总结:
|
||||
|
||||
**现在我们有场景章节,也有聊天系统,但还没有“场景多幕蓝图”这一层把创作配置、背景资产、NPC 相遇顺序和聊天规则真正串起来。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 核心决策
|
||||
|
||||
## 5.1 场景章节与场景幕的关系
|
||||
|
||||
本次新增一个明确约束:
|
||||
|
||||
- `场景章节` 仍然是场景级闭环容器
|
||||
- `场景幕` 是场景章节内部的有序分段
|
||||
|
||||
关系定义如下:
|
||||
|
||||
| 层级 | 作用 |
|
||||
| --- | --- |
|
||||
| `scene chapter` | 表示这一整个场景在剧情上的一章 |
|
||||
| `scene act` | 表示这章内部的第几幕、当前视觉和当前相遇主体 |
|
||||
|
||||
每个场景章节必须至少有 `2` 幕,最多 `5` 幕。
|
||||
|
||||
## 5.2 多幕数量与章节阶段映射
|
||||
|
||||
为了不引入第二套完全独立的运行时章节体系,本次规定场景幕按数量映射到现有 `ChapterState.stage`:
|
||||
|
||||
| 幕数 | 编译规则 |
|
||||
| --- | --- |
|
||||
| `2` 幕 | 幕 1=`opening + expansion`,幕 2=`turning_point + climax + aftermath` |
|
||||
| `3` 幕 | 幕 1=`opening`,幕 2=`expansion + turning_point`,幕 3=`climax + aftermath` |
|
||||
| `4` 幕 | 幕 1=`opening`,幕 2=`expansion`,幕 3=`turning_point`,幕 4=`climax + aftermath` |
|
||||
| `5` 幕 | 与 `opening / expansion / turning_point / climax / aftermath` 一一对应 |
|
||||
|
||||
这意味着:
|
||||
|
||||
1. 创作者在工具里编辑的是“第几幕”。
|
||||
2. 运行时仍然只认现有章节阶段枚举。
|
||||
3. `chapterDirector` 可以继续复用,只是数据来源从“纯 quest 推导”升级成“quest + 幕蓝图联合推导”。
|
||||
|
||||
## 5.3 主角色定义
|
||||
|
||||
每一幕配置的 `encounterNpcIds` 必须是有序数组。
|
||||
|
||||
规则固定为:
|
||||
|
||||
1. `encounterNpcIds[0]` 就是当前幕主角色。
|
||||
2. 运行时会把它编译成 `primaryNpcId`。
|
||||
3. 主角色承担该幕默认的首次相遇、聊天轮数裁决和幕推进优先级。
|
||||
4. 其余 NPC 视为辅助相遇角色,不直接承担本次“好感度聊天轮数规则”。
|
||||
|
||||
---
|
||||
|
||||
## 6. 数据结构要求
|
||||
|
||||
## 6.1 创作草稿层新增结构
|
||||
|
||||
建议在现有 `CustomWorldFoundationDraftProfile` 之上新增下面两层:
|
||||
|
||||
```ts
|
||||
type SceneActAdvanceRule =
|
||||
| 'after_primary_contact'
|
||||
| 'after_active_step_complete'
|
||||
| 'after_chapter_resolution';
|
||||
|
||||
interface CustomWorldFoundationDraftSceneAct {
|
||||
id: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
stageCoverage: Array<
|
||||
| 'opening'
|
||||
| 'expansion'
|
||||
| 'turning_point'
|
||||
| 'climax'
|
||||
| 'aftermath'
|
||||
>;
|
||||
backgroundImageSrc?: string | null;
|
||||
backgroundAssetId?: string | null;
|
||||
encounterNpcIds: string[];
|
||||
primaryNpcId: string;
|
||||
linkedThreadIds: string[];
|
||||
actGoal: string;
|
||||
transitionHook: string;
|
||||
advanceRule: SceneActAdvanceRule;
|
||||
}
|
||||
|
||||
interface CustomWorldFoundationDraftSceneChapter {
|
||||
id: string;
|
||||
sceneId: string;
|
||||
sceneName: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
linkedThreadIds: string[];
|
||||
linkedLandmarkIds: string[];
|
||||
acts: CustomWorldFoundationDraftSceneAct[];
|
||||
}
|
||||
```
|
||||
|
||||
硬要求:
|
||||
|
||||
1. `primaryNpcId` 必须等于 `encounterNpcIds[0]`,不允许单独填写成别的角色。
|
||||
2. 每幕必须至少有 `1` 个 NPC。
|
||||
3. 每幕必须有 `backgroundImageSrc` 或 `backgroundAssetId`。
|
||||
4. `advanceRule` 由系统按幕位置默认编译,第一版不要求创作者手改。
|
||||
|
||||
## 6.2 发布到运行时的蓝图结构
|
||||
|
||||
创作草稿在发布时必须进一步编译成运行时蓝图:
|
||||
|
||||
```ts
|
||||
interface SceneActBlueprint {
|
||||
id: string;
|
||||
sceneId: string;
|
||||
title: string;
|
||||
stageCoverage: Array<
|
||||
| 'opening'
|
||||
| 'expansion'
|
||||
| 'turning_point'
|
||||
| 'climax'
|
||||
| 'aftermath'
|
||||
>;
|
||||
backgroundImageSrc?: string | null;
|
||||
encounterNpcIds: string[];
|
||||
primaryNpcId: string;
|
||||
advanceRule:
|
||||
| 'after_primary_contact'
|
||||
| 'after_active_step_complete'
|
||||
| 'after_chapter_resolution';
|
||||
actGoal: string;
|
||||
transitionHook: string;
|
||||
}
|
||||
|
||||
interface SceneChapterBlueprint {
|
||||
id: string;
|
||||
sceneId: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
acts: SceneActBlueprint[];
|
||||
}
|
||||
```
|
||||
|
||||
建议把它挂入 `CustomWorldProfile` 的新字段中:
|
||||
|
||||
```ts
|
||||
sceneChapterBlueprints?: SceneChapterBlueprint[] | null;
|
||||
```
|
||||
|
||||
原因:
|
||||
|
||||
1. 现有 `landmarks` 只足够表达地点,不足够表达幕顺序。
|
||||
2. 现有 `ChapterState` 是运行时状态,不适合直接兼做创作者蓝图。
|
||||
3. 独立蓝图层更适合后端编译和发布校验。
|
||||
|
||||
## 6.3 聊天状态扩展
|
||||
|
||||
建议在现有 `StoryNpcChatState` 上新增有限聊天需要的状态:
|
||||
|
||||
```ts
|
||||
interface StoryNpcChatState {
|
||||
npcId: string;
|
||||
npcName: string;
|
||||
turnCount: number;
|
||||
customInputPlaceholder?: string;
|
||||
pendingQuestOffer?: {
|
||||
quest: QuestLogEntry;
|
||||
} | null;
|
||||
sceneActId?: string | null;
|
||||
turnLimit?: number | null;
|
||||
remainingTurns?: number | null;
|
||||
limitReason?: 'negative_affinity' | null;
|
||||
forceExitAfterTurn?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
1. 正常无限聊天时,`turnLimit` 和 `remainingTurns` 为 `null`。
|
||||
2. 负好感主角色聊天时,`turnLimit=5`。
|
||||
3. 第 `5` 轮结束后,`forceExitAfterTurn=true`,由后端明确告知前端结束当前聊天态。
|
||||
|
||||
## 6.4 NPC 聊天返回契约扩展
|
||||
|
||||
建议扩展 `NpcChatTurnResult`:
|
||||
|
||||
```ts
|
||||
type NpcChatTurnResult = {
|
||||
npcReply: string;
|
||||
affinityDelta: number;
|
||||
affinityText: string;
|
||||
suggestions: string[];
|
||||
chatDirective?: {
|
||||
turnLimit?: number | null;
|
||||
remainingTurns?: number | null;
|
||||
forceExit?: boolean;
|
||||
closingMode?: 'free' | 'foreshadow_close';
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
这部分必须由后端给出,不允许前端自己猜。
|
||||
|
||||
---
|
||||
|
||||
## 7. 创作工具需求
|
||||
|
||||
## 7.1 入口与承载方式
|
||||
|
||||
本次必须继续复用现有:
|
||||
|
||||
1. `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
|
||||
2. `src/components/custom-world-agent/CustomWorldDraftCardDetailModal.tsx`
|
||||
3. `src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx`
|
||||
|
||||
不新建独立页面。
|
||||
|
||||
新增规则:
|
||||
|
||||
1. 草稿抽屉必须正式支持 `scene_chapter` 分组。
|
||||
2. `scene_chapter` 分组应位于 `chapter` 后、`thread` 前。
|
||||
3. 点开 `scene_chapter` 草稿卡后,进入现有详情弹层和编辑面板体系。
|
||||
4. 创作页面卡片摘要后续可增加 `sceneChapterCount`,但第一版不是阻塞项。
|
||||
|
||||
## 7.2 场景章节卡展示要求
|
||||
|
||||
每张 `scene_chapter` 草稿卡至少展示:
|
||||
|
||||
1. 场景名称
|
||||
2. 章节标题
|
||||
3. 幕数量
|
||||
4. 已就绪背景图数量
|
||||
5. 关联 NPC 数量
|
||||
6. 关联线程数量
|
||||
7. 当前风险数
|
||||
|
||||
详情页必须至少展示:
|
||||
|
||||
1. 场景摘要
|
||||
2. 幕结构总览
|
||||
3. 每幕的背景缩略图
|
||||
4. 每幕的主角色
|
||||
5. 每幕的辅助 NPC
|
||||
6. 每幕目标
|
||||
7. 每幕过渡钩子
|
||||
|
||||
## 7.3 幕编辑交互
|
||||
|
||||
每个场景章节卡的编辑区必须支持下面这些操作:
|
||||
|
||||
1. 新增幕
|
||||
2. 删除幕
|
||||
3. 调整幕顺序
|
||||
4. 编辑幕标题
|
||||
5. 编辑幕摘要
|
||||
6. 绑定幕背景图
|
||||
7. 配置幕相遇 NPC 顺序
|
||||
8. 编辑幕目标
|
||||
9. 编辑幕过渡钩子
|
||||
|
||||
交互要求:
|
||||
|
||||
1. 幕列表在桌面端纵向堆叠,在移动端同样保持纵向,不做复杂双列。
|
||||
2. 每幕是独立卡片,不把所有字段一次性铺满。
|
||||
3. 点击“配置背景图”时必须打开独立面板或独立弹层,不允许在当前卡片下方内联展开。
|
||||
4. 点击“配置相遇 NPC”时必须打开独立面板或独立弹层,不允许在当前卡片下方内联展开。
|
||||
5. 默认不展示大段规则说明文字。
|
||||
|
||||
## 7.4 幕背景图配置
|
||||
|
||||
背景图配置必须复用现有场景图资产链,而不是另造上传体系。
|
||||
|
||||
要求如下:
|
||||
|
||||
1. 一幕只绑定一张正式背景图。
|
||||
2. 可从已生成场景图中选择,也可调用现有场景图生成链生成。
|
||||
3. 幕背景图和场景总背景图不是同一个概念,允许不同幕使用不同图。
|
||||
4. 发布前如果存在未绑定背景图的幕,必须阻止发布。
|
||||
5. 幕切换时运行时优先使用幕背景图,而不是地点默认图。
|
||||
|
||||
## 7.5 幕相遇 NPC 配置
|
||||
|
||||
NPC 配置面板必须支持:
|
||||
|
||||
1. 从当前世界的 `playableNpcs + storyNpcs` 中选择角色
|
||||
2. 只展示与当前场景相关的优先推荐角色
|
||||
3. 支持排序
|
||||
4. 第一位角色明确标记为“主角色”
|
||||
5. 允许同一角色出现在多个不同幕
|
||||
|
||||
硬约束:
|
||||
|
||||
1. 每幕至少 `1` 名 NPC。
|
||||
2. 第一位 NPC 不能为空。
|
||||
3. 不允许把不存在于当前世界角色池中的 id 写入幕配置。
|
||||
4. 若主角色未与当前场景或线程建立任何关联,给出发布警告。
|
||||
|
||||
## 7.6 创作校验
|
||||
|
||||
`CustomWorldQualityFinding` 至少新增下面这些检查项:
|
||||
|
||||
1. `scene_chapter_missing_act`
|
||||
2. `scene_act_missing_background`
|
||||
3. `scene_act_missing_primary_npc`
|
||||
4. `scene_act_missing_encounter_npc`
|
||||
5. `scene_act_primary_npc_not_first`
|
||||
6. `scene_act_unlinked_thread`
|
||||
7. `scene_act_unpublished_background`
|
||||
|
||||
发布阻断项:
|
||||
|
||||
1. 幕数小于 `2`
|
||||
2. 任意一幕没有背景图
|
||||
3. 任意一幕没有 NPC
|
||||
4. 任意一幕的第一 NPC 为空
|
||||
|
||||
---
|
||||
|
||||
## 8. 游戏流程需求
|
||||
|
||||
## 8.1 幕运行时状态
|
||||
|
||||
运行时必须为每个场景章节维护独立幕进度:
|
||||
|
||||
```ts
|
||||
interface SceneActRuntimeState {
|
||||
sceneId: string;
|
||||
chapterId: string;
|
||||
currentActId: string;
|
||||
currentActIndex: number;
|
||||
completedActIds: string[];
|
||||
visitedActIds: string[];
|
||||
}
|
||||
```
|
||||
|
||||
建议挂入当前 story engine memory 中,和现有 `openedSceneChapterIds` 并存。
|
||||
|
||||
## 8.2 进入场景时的流程
|
||||
|
||||
当玩家进入一个有 `SceneChapterBlueprint` 的场景时:
|
||||
|
||||
1. 后端定位当前场景对应的 `scene chapter blueprint`
|
||||
2. 如果该场景首次进入,则激活第 `1` 幕
|
||||
3. 如果该场景未完成且已有幕进度,则恢复到当前未完成幕
|
||||
4. 把当前幕的背景图写入前端展示模型
|
||||
5. 把当前幕的 `encounterNpcIds` 作为本幕优先相遇池
|
||||
6. 把当前幕的 `stageCoverage` 交给 `chapterDirector` 参与裁决,并结合 quest 进度输出单一 `ChapterState.stage`
|
||||
|
||||
## 8.3 幕推进规则
|
||||
|
||||
第一版不要求创作者手填推进条件,而是由系统按幕位置默认编译:
|
||||
|
||||
1. 第 `1` 幕默认 `after_primary_contact`
|
||||
- 玩家与主角色发生首次有效接触后可进入下一幕判定
|
||||
|
||||
2. 中间幕默认 `after_active_step_complete`
|
||||
- 当前场景章节任务 active step 完成后进入下一幕判定
|
||||
|
||||
3. 最后一幕默认 `after_chapter_resolution`
|
||||
- 当前场景章节任务完成或进入可收束状态后结束本场景章节
|
||||
|
||||
要求:
|
||||
|
||||
1. 幕推进由后端统一裁决。
|
||||
2. 前端只接收“幕已切换”的结果,不自行判断。
|
||||
3. 幕切换后必须触发背景切换与相遇池更新。
|
||||
|
||||
## 8.4 幕切换表现
|
||||
|
||||
游戏前台在幕切换时必须至少做到:
|
||||
|
||||
1. 显示当前幕标题
|
||||
2. 更新背景图
|
||||
3. 更新当前可遇 NPC
|
||||
4. 给出一条轻量系统提示,说明进入了新一幕
|
||||
|
||||
注意:
|
||||
|
||||
1. 不新建独立页面。
|
||||
2. 不弹全屏说明面板。
|
||||
3. 移动端优先保证幕标题与背景切换不遮挡底部操作区。
|
||||
|
||||
---
|
||||
|
||||
## 9. NPC 相遇与聊天规则
|
||||
|
||||
## 9.1 规则适用范围
|
||||
|
||||
本次新增的“按好感度控制聊天轮数”规则,只对**当前幕主角色**生效。
|
||||
|
||||
也就是说:
|
||||
|
||||
1. 当前幕 `primaryNpcId` 命中的角色,使用本次新规则。
|
||||
2. 当前幕其他辅助 NPC,第一版继续沿用现有 `npc_chat` 通用流程。
|
||||
3. 辅助 NPC 的聊天不直接推进幕进度,除非后端另有章节 step 裁决。
|
||||
|
||||
## 9.2 主角色好感度大于 0
|
||||
|
||||
当当前幕主角色对玩家的当前好感度 `> 0` 时:
|
||||
|
||||
1. 玩家与其相遇后可以进入聊天态。
|
||||
2. 聊天轮数无限制。
|
||||
3. 继续沿用现有:
|
||||
- `3` 个续聊建议项
|
||||
- `1` 个自定义输入框
|
||||
- 主动退出聊天
|
||||
4. 只要满足 `docs/design/NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md` 中的条件,仍然允许在聊天内抛出委托。
|
||||
|
||||
## 9.3 主角色好感度等于 0
|
||||
|
||||
为了避免编码边界歧义,本 PRD 先明确:
|
||||
|
||||
1. `affinity = 0` 视为中立档,不归入负好感限制分支。
|
||||
2. 中立档允许进入正常多轮聊天。
|
||||
3. 中立档不自动享受“高好感委托时机”。
|
||||
|
||||
这意味着:
|
||||
|
||||
- `> 0`:无限聊,且可进入高好感委托逻辑
|
||||
- `= 0`:无限聊,但不进入高好感委托逻辑
|
||||
- `< 0`:最多 `5` 轮
|
||||
|
||||
## 9.4 主角色好感度小于 0
|
||||
|
||||
当当前幕主角色对玩家的当前好感度 `< 0` 时,必须进入 `limited hostile chat mode`:
|
||||
|
||||
1. 允许进入聊天,但最多 `5` 轮。
|
||||
2. 聊天状态中必须显示剩余轮数。
|
||||
3. 第 `1~4` 轮仍然走正常“玩家一句 -> NPC 一句 -> 建议项刷新”的基本结构。
|
||||
4. 第 `5` 轮不是普通续聊,而是强制收束轮。
|
||||
5. 第 `5` 轮必须输出一段带方向的收束回应,为后续剧情开展铺垫。
|
||||
6. 第 `5` 轮结束后:
|
||||
- 自定义输入框隐藏
|
||||
- 当前聊天态结束
|
||||
- 恢复普通冒险态或进入后续 action 选择
|
||||
|
||||
## 9.5 第 5 轮的“铺垫”定义
|
||||
|
||||
“为开展铺垫”在本次 PRD 中必须被明确解释为:
|
||||
|
||||
**NPC 在第 5 轮必须抛出一个明确的后续方向,不能只用一句敌意台词把对话硬截断。**
|
||||
|
||||
可接受的铺垫结果包括:
|
||||
|
||||
1. 抛出新的威胁或最后通牒
|
||||
2. 指向某个地点、人物或线索
|
||||
3. 把矛盾推向对峙、交易、追踪或战斗
|
||||
4. 暗示自己下一步行动去向
|
||||
5. 给玩家一个必须接住的悬念或条件
|
||||
|
||||
不可接受的结果:
|
||||
|
||||
1. 纯重复敌意表达
|
||||
2. 没有任何新方向的信息
|
||||
3. 第 5 轮结束后界面直接空掉,没有后续承接
|
||||
|
||||
## 9.6 对当前负好感拦截逻辑的调整
|
||||
|
||||
当前若主角色属于本幕 `primaryNpcId`,则需要覆盖现有“负好感直接不给持续聊天”的逻辑。
|
||||
|
||||
新规则如下:
|
||||
|
||||
1. 如果它是当前幕主角色,即使当前好感度 `< 0`,也允许进入有限聊天态。
|
||||
2. 只有在完成第 `5` 轮铺垫收束后,才切回普通探索/对峙流程。
|
||||
3. 如果该 NPC 不是当前幕主角色,仍可沿用现有负好感拦截逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 10. 前端表现要求
|
||||
|
||||
## 10.1 创作页
|
||||
|
||||
创作页必须保持清爽,不默认塞规则说明。
|
||||
|
||||
必须做到:
|
||||
|
||||
1. `scene_chapter` 卡片可见
|
||||
2. 幕列表可编辑
|
||||
3. 背景图选择和 NPC 选择都走独立面板
|
||||
4. 移动端仍能完成幕排序、背景选择、NPC 排序
|
||||
|
||||
## 10.2 游戏主面板
|
||||
|
||||
Adventure 主面板在本次迭代中至少增加下面这些表现:
|
||||
|
||||
1. 当前幕标题或幕序号标签
|
||||
2. 当前幕背景图切换
|
||||
3. 主角色负好感聊天时的“剩余轮数”轻量提示
|
||||
4. 第 5 轮结束后的过渡系统消息
|
||||
|
||||
禁止:
|
||||
|
||||
1. 默认展示大段规则介绍
|
||||
2. 把幕配置说明直接写进玩家面板
|
||||
3. 为了展示幕切换而新建独立剧情页面
|
||||
|
||||
---
|
||||
|
||||
## 11. 前后端职责边界
|
||||
|
||||
## 11.1 前端职责
|
||||
|
||||
前端只负责:
|
||||
|
||||
1. 渲染 `scene_chapter` 草稿卡与幕编辑 UI
|
||||
2. 发起背景图配置和 NPC 配置请求
|
||||
3. 渲染当前幕背景和幕标题
|
||||
4. 渲染负好感聊天剩余轮数
|
||||
5. 根据后端返回切换幕、退出聊天、展示后续 options
|
||||
|
||||
前端不负责:
|
||||
|
||||
1. 计算主角色是谁
|
||||
2. 计算好感度轮数限制
|
||||
3. 判定什么时候切幕
|
||||
4. 决定第 5 轮要输出什么铺垫
|
||||
5. 本地拼接下一幕 encounter 池
|
||||
|
||||
## 11.2 后端职责
|
||||
|
||||
后端必须负责:
|
||||
|
||||
1. 把创作页幕配置编译成运行时蓝图
|
||||
2. 校验每幕背景与 NPC 配置完整性
|
||||
3. 维护 `SceneActRuntimeState`
|
||||
4. 进入场景时确定当前幕
|
||||
5. 输出当前幕背景与 encounter 池
|
||||
6. 裁决主角色聊天轮数限制
|
||||
7. 在第 `5` 轮生成铺垫式收束回应
|
||||
8. 在满足条件时推进到下一幕
|
||||
|
||||
---
|
||||
|
||||
## 12. 影响模块
|
||||
|
||||
本 PRD 落地时,至少会影响下面这些模块:
|
||||
|
||||
1. `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- 新增场景多幕草稿结构
|
||||
|
||||
2. `src/types/customWorld.ts`
|
||||
- 新增发布态 `sceneChapterBlueprints`
|
||||
|
||||
3. `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
- 编译 `scene_chapter` 草稿卡
|
||||
|
||||
4. `server-node/src/services/customWorldAgentDraftEditService.ts`
|
||||
- 支持场景幕的增删改排序
|
||||
|
||||
5. `server-node/src/services/customWorldAgentQualityService.ts`
|
||||
- 增加幕背景和幕 NPC 校验
|
||||
|
||||
6. `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
|
||||
- 展示 `scene_chapter` 分组
|
||||
|
||||
7. `src/components/custom-world-agent/CustomWorldDraftCardDetailModal.tsx`
|
||||
- 展示幕详情
|
||||
|
||||
8. `src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx`
|
||||
- 新增幕编辑 UI
|
||||
|
||||
9. `src/data/questFlow.ts`
|
||||
- 让 scene chapter quest 感知当前幕
|
||||
|
||||
10. `src/services/storyEngine/chapterDirector.ts`
|
||||
- 用当前幕映射章节阶段和摘要
|
||||
|
||||
11. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 新增主角色有限聊天与第 5 轮收束逻辑
|
||||
|
||||
12. `packages/shared/src/contracts/story.ts`
|
||||
- 扩展 `NpcChatTurnResult`
|
||||
|
||||
13. `src/services/aiService.ts`
|
||||
- 透传有限聊天新字段
|
||||
|
||||
14. `server-node/src/modules/ai/chatOrchestrator.ts`
|
||||
- 生成第 `5` 轮铺垫式收束结果
|
||||
|
||||
---
|
||||
|
||||
## 13. 验收标准
|
||||
|
||||
当下面这些结果都成立时,视为本次 PRD 已被正确落地:
|
||||
|
||||
1. 创作者可以在现有创作工作区中创建并编辑 `scene_chapter`。
|
||||
2. 每个场景章节都可以配置 `2~5` 幕。
|
||||
3. 每一幕都可以绑定独立背景图。
|
||||
4. 每一幕都可以配置有序 NPC 列表,第一位自动成为主角色。
|
||||
5. 发布时缺少幕背景或幕 NPC 会被明确拦截。
|
||||
6. 玩家进入场景后,当前幕背景图能正确显示。
|
||||
7. 当前幕可遇 NPC 会按幕配置切换。
|
||||
8. 当前幕主角色好感度 `> 0` 时可以无限续聊。
|
||||
9. 当前幕主角色好感度 `< 0` 时最多只聊 `5` 轮。
|
||||
10. 第 `5` 轮结束后一定会出现为后续剧情开展铺垫的收束结果,而不是直接硬断。
|
||||
11. 高好感委托链仍只在正好感聊天中触发。
|
||||
12. 桌面端和移动端都能完成幕配置与幕切换使用。
|
||||
|
||||
---
|
||||
|
||||
## 14. 本稿默认假定
|
||||
|
||||
为了避免下一步编码时再出现语义歧义,这份 PRD 先明确采用下面两条默认假定:
|
||||
|
||||
1. `affinity = 0` 先按中立档处理:允许无限聊,但不进入高好感委托分支。
|
||||
2. “第 5 轮为开展铺垫”先解释为“为后续剧情推进、对峙、追踪、交易或战斗制造明确下一跳”,而不是限定为必须开战。
|
||||
|
||||
如果后续你希望把:
|
||||
|
||||
- `affinity = 0` 改成也只聊 `5` 轮
|
||||
- 第 `5` 轮明确收束到“开战前摇”
|
||||
|
||||
可以在下一版实现文档中单独收紧,不影响本稿主结构。
|
||||
@@ -1,6 +1,6 @@
|
||||
# “我的”Tab 设置与账号安全 PRD
|
||||
|
||||
更新时间:`2026-04-16`
|
||||
更新时间:`2026-04-19`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
@@ -64,6 +64,13 @@
|
||||
4. 更换手机号
|
||||
5. 账号操作记录
|
||||
|
||||
交互层级要求补充为:
|
||||
|
||||
1. 设置首页只展示分区入口与危险操作,不在首页内联展开具体详情
|
||||
2. 点击任一分区入口后,必须进入独立二级面板
|
||||
3. 二级面板负责单一任务,不允许把详情继续堆在入口列表下面
|
||||
4. 更换手机号属于独立操作面板,不允许在账号概况面板内直接展开表单
|
||||
|
||||
底部保留两个危险操作按钮:
|
||||
|
||||
1. 退出登录
|
||||
@@ -84,6 +91,12 @@
|
||||
|
||||
这里只看信息,不做大编辑动作。
|
||||
|
||||
标题约束:
|
||||
|
||||
- 设置首页标题固定表达“设置”或“设置与账号安全”
|
||||
- 设置首页标题区域不展示手机号,也不允许把手机号当作主标题替代昵称
|
||||
- 手机号只允许出现在账号概况信息项中,以脱敏值展示
|
||||
|
||||
## 4.2 当前安全状态
|
||||
|
||||
展示当前账号命中的风控保护:
|
||||
@@ -188,8 +201,11 @@
|
||||
|
||||
1. 设置继续采用当前账号弹窗基础形态即可
|
||||
2. 移动端优先底部弹层,桌面端可居中弹窗
|
||||
3. 更换手机号区域默认折叠
|
||||
4. 危险操作按钮与普通按钮必须明显区分
|
||||
3. 设置首页只保留分区入口,不直接承载分区详情内容
|
||||
4. 分区详情必须通过独立子面板承载,移动端优先使用全宽底部子弹层,桌面端使用覆盖在设置首页之上的居中子面板
|
||||
5. 更换手机号必须通过独立操作面板完成,不再使用当前面板内联展开表单
|
||||
6. 危险操作按钮与普通按钮必须明显区分
|
||||
7. 设置首页标题处禁止展示手机号、脱敏手机号或手机号形态的 displayName
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -110,6 +110,14 @@
|
||||
- 最后游玩时间
|
||||
- 游戏信息
|
||||
|
||||
### 3.3.1 移动端卡片布局约束
|
||||
|
||||
- 移动端列表卡片中的封面只能作为独立缩略图或弱化背景层使用,不能直接占满整张卡片并压在正文信息下方。
|
||||
- 标题、时间、摘要所在的信息区必须保持 `min-width: 0` 的可收缩布局,长标题不能把正文挤出屏幕外。
|
||||
- 世界名称最多展示 2 行,游戏信息最多展示 3 行,超出后截断,不允许横向溢出。
|
||||
- 时间标签、状态标签在窄屏下必须允许换行或独立成行,不能为了保持单行导致卡片内容错位。
|
||||
- 列表卡片缩略图区域比例固定,文本区与缩略图区在移动端需要保持稳定对齐,避免出现上下参差和视觉歪斜。
|
||||
|
||||
其中“游戏信息”优先级如下:
|
||||
|
||||
1. `continueGameDigest`
|
||||
|
||||
185
docs/reference/BUSINESS_PROMPT_INVENTORY_2026-04-19.md
Normal file
185
docs/reference/BUSINESS_PROMPT_INVENTORY_2026-04-19.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# 业务提示词清单(2026-04-19)
|
||||
|
||||
## 1. 目标
|
||||
|
||||
这份清单用于回答两个问题:
|
||||
|
||||
- 目前业务里到底有哪些提示词还在被使用。
|
||||
- 哪些提示词已经收口到独立目录,哪些仍散落在前后端与工具链里。
|
||||
|
||||
本次统计范围:
|
||||
|
||||
- `server-node/src/**`
|
||||
- `src/**`
|
||||
- `packages/shared/src/**`
|
||||
|
||||
本次“提示词”统计口径包含:
|
||||
|
||||
- system prompt
|
||||
- user prompt builder
|
||||
- repair prompt
|
||||
- negative prompt
|
||||
- 图像 / 动画生成 prompt
|
||||
- 编辑器里会直接喂给模型的默认 prompt 种子
|
||||
|
||||
本次不计入:
|
||||
|
||||
- 单纯转发 prompt 的接口入参校验
|
||||
- 普通剧情文案、UI 文案、剧情预设文本
|
||||
- 纯测试断言文件
|
||||
|
||||
## 2. 当前结论
|
||||
|
||||
截至 2026-04-19 本轮收口完成后,业务 prompt 主源已经集中到 3 个目录:
|
||||
|
||||
1. `server-node/src/prompts/`
|
||||
2. `src/prompts/`
|
||||
3. `packages/shared/src/prompts/`
|
||||
|
||||
当前业务模块、路由、服务层里的旧 prompt 文件大多已经退化成两类:
|
||||
|
||||
- prompt 调用方
|
||||
- 薄 re-export 兼容层
|
||||
|
||||
目前没有再发现“正式业务 prompt 正文仍长期内联在主流程文件里”的大块散点;剩余位于非 prompt 目录的相关文件,主要是兼容层、测试文件或普通调用方。
|
||||
|
||||
## 3. 当前 Prompt 目录清单
|
||||
|
||||
### 3.1 后端
|
||||
|
||||
| 文件 | 业务域 | 关键导出 |
|
||||
| --- | --- | --- |
|
||||
| `server-node/src/prompts/storyPromptBuilders.ts` | 主剧情推进 | `SYSTEM_PROMPT`、`buildUserPrompt` |
|
||||
| `server-node/src/prompts/storyOrchestratorPrompts.ts` | 剧情语言修复 | `STORY_LANGUAGE_REPAIR_SYSTEM_PROMPT`、`buildStoryLanguageRepairPrompt` |
|
||||
| `server-node/src/prompts/chatPromptBuilders.ts` | 角色私聊 / NPC 对话 / 招募 | `CHARACTER_PANEL_CHAT_*`、`NPC_CHAT_*`、多个 `build*Prompt` |
|
||||
| `server-node/src/prompts/questPrompts.ts` | 任务意图 | `QUEST_INTENT_SYSTEM_PROMPT`、`buildQuestIntentPrompt` |
|
||||
| `server-node/src/prompts/runtimeItemPrompts.ts` | 运行时物品意图 | `RUNTIME_ITEM_INTENT_SYSTEM_PROMPT`、`buildRuntimeItemIntentPromptText` |
|
||||
| `server-node/src/prompts/customWorldOrchestratorPrompts.ts` | 自定义世界主编排 | `CUSTOM_WORLD_GENERATION_JSON_ONLY_SYSTEM_PROMPT`、`CUSTOM_WORLD_JSON_REPAIR_SYSTEM_PROMPT`、`buildCustomWorldProfilePrompt`、`buildCustomWorldProfileRepairPrompt` |
|
||||
| `server-node/src/prompts/customWorldAgentPrompts.ts` | 世界草稿增补 | `FOUNDATION_JSON_ONLY_SYSTEM_PROMPT`、`FOUNDATION_JSON_REPAIR_SYSTEM_PROMPT`、多个扩展 prompt |
|
||||
| `server-node/src/prompts/customWorldEntityPrompts.ts` | 世界编辑器实体生成 | `CUSTOM_WORLD_ENTITY_GENERATOR_SYSTEM_PROMPT`、`buildPlayablePrompt`、`buildStoryPrompt`、`buildLandmarkPrompt` |
|
||||
| `server-node/src/prompts/customWorldSceneNpcPrompts.ts` | 世界编辑器场景 NPC | `CUSTOM_WORLD_SCENE_NPC_SYSTEM_PROMPT`、`buildCustomWorldSceneNpcPrompt` |
|
||||
| `server-node/src/prompts/eightAnchorPrompts.ts` | 八锚点共创 | `BASE_SYSTEM_PROMPT`、`GLOBAL_HARD_RULES`、`MODE_RULES`、`USER_SIGNAL_RULES`、`buildPromptDynamicStateInferencePrompt`、`buildEightAnchorSingleTurnPrompt` |
|
||||
| `server-node/src/prompts/characterAssetPrompts.ts` | 角色形象 / 动作资产生成 | `CHARACTER_PROMPT_BUNDLE_SYSTEM_PROMPT`、`buildFallbackCharacterPromptBundle`、`buildCharacterPromptBundleUserPrompt`、`buildNpcVisualPrompt`、`buildNpcAnimationPrompt`、`buildArkCharacterAnimationPrompt` |
|
||||
|
||||
### 3.2 前端
|
||||
|
||||
| 文件 | 业务域 | 关键导出 |
|
||||
| --- | --- | --- |
|
||||
| `src/prompts/storyPromptBuilders.ts` | 剧情推进 | `SYSTEM_PROMPT`、`buildUserPrompt` |
|
||||
| `src/prompts/characterChatPrompts.ts` | 角色面板私聊 | `CHARACTER_PANEL_CHAT_*`、多个 `build*Prompt` |
|
||||
| `src/prompts/questPrompts.ts` | 前端任务意图兜底 | `QUEST_INTENT_SYSTEM_PROMPT`、`buildQuestIntentPrompt` |
|
||||
| `src/prompts/runtimeItemPrompts.ts` | 前端物品意图兜底 | `RUNTIME_ITEM_INTENT_SYSTEM_PROMPT`、`buildRuntimeItemIntentPrompt` |
|
||||
| `src/prompts/customWorldPrompts.ts` | 自定义世界分阶段生成 + 场景背景图 | 多个 `buildCustomWorld*Prompt`、`DEFAULT_CUSTOM_WORLD_SCENE_IMAGE_NEGATIVE_PROMPT` |
|
||||
| `src/prompts/customWorldOrchestratorPrompts.ts` | 世界 JSON 修复 / JSON only | `CUSTOM_WORLD_JSON_REPAIR_SYSTEM_PROMPT`、`CUSTOM_WORLD_GENERATION_JSON_ONLY_SYSTEM_PROMPT` |
|
||||
| `src/prompts/storyOrchestratorPrompts.ts` | 剧情中文修复 | `STORY_LANGUAGE_REPAIR_SYSTEM_PROMPT` |
|
||||
| `src/prompts/customWorldRolePromptDefaults.ts` | 角色资产工作台默认词 | `buildDefaultRolePromptBundle` |
|
||||
| `src/prompts/customWorldEntityActionPrompts.ts` | 编辑器技能动作词 | `buildSkillActionPrompt` |
|
||||
| `src/prompts/qwenSpriteSheetToolPrompts.ts` | Qwen 精灵图工具 prompt 模型 | 主 prompt / sheet prompt / repair prompt / negative prompt 系列 |
|
||||
|
||||
### 3.3 共享层
|
||||
|
||||
| 文件 | 业务域 | 关键导出 |
|
||||
| --- | --- | --- |
|
||||
| `packages/shared/src/prompts/qwenSprite.ts` | 共享像素角色主 prompt 模板 | `QWEN_SPRITE_ACTION_TEMPLATES`、`buildMasterPrompt`、`buildVideoActionPrompt`、`getActionTemplateById` |
|
||||
|
||||
## 4. 兼容层与调用层
|
||||
|
||||
为了避免一次性打断旧引用,当前保留了若干兼容层:
|
||||
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/characterChatPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
- `server-node/src/services/eightAnchorPromptBuilder.ts`
|
||||
- `src/tools/qwenSpriteSheetToolModel.ts`
|
||||
- `src/components/asset-studio/customWorldRolePromptDefaults.ts`
|
||||
- `packages/shared/src/assets/qwenSprite.ts`
|
||||
|
||||
这些文件当前职责是:
|
||||
|
||||
- 维持旧路径可用
|
||||
- re-export 到新的 prompt 目录
|
||||
|
||||
它们不再是 prompt 正文主源。
|
||||
|
||||
## 5. AI 角色形象生成当前来源
|
||||
|
||||
这部分是你点名要求补齐的重点,现在已经收口为:
|
||||
|
||||
| 文件 | 角色 | 当前定位 |
|
||||
| --- | --- | --- |
|
||||
| `server-node/src/prompts/characterAssetPrompts.ts` | 正式角色资产生成 prompt | 后端角色主图、动作试片、角色场景词主源 |
|
||||
| `packages/shared/src/prompts/qwenSprite.ts` | 共享角色主 prompt 模板 | 共享给后端资产链使用的基础模板 |
|
||||
| `src/prompts/qwenSpriteSheetToolPrompts.ts` | 工具链 prompt 模型 | Qwen 精灵图工具主词、分镜词、修帧词、负面词 |
|
||||
| `src/prompts/customWorldRolePromptDefaults.ts` | 工作台默认词种子 | 角色视觉词、动画词、场景词默认值 |
|
||||
| `src/prompts/customWorldEntityActionPrompts.ts` | 编辑器动作词 | 技能动作描述 prompt builder |
|
||||
|
||||
当前调用关系:
|
||||
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts` 调用 `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `src/tools/QwenSpriteSheetTool.tsx` 通过兼容层消费 `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
- `src/components/CustomWorldRoleAssetStudioModal.tsx` 通过兼容层消费 `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
- `src/components/CustomWorldEntityEditorModal.tsx` 直接调用 `src/prompts/customWorldEntityActionPrompts.ts`
|
||||
|
||||
## 6. AI 场景背景生成当前来源
|
||||
|
||||
场景背景图 prompt 现在已经从业务流程文件里抽出,统一主源是:
|
||||
|
||||
| 文件 | 角色 | 当前定位 |
|
||||
| --- | --- | --- |
|
||||
| `src/prompts/customWorldPrompts.ts` | 场景背景图 prompt 主源 | `buildCustomWorldSceneImagePrompt`、`DEFAULT_CUSTOM_WORLD_SCENE_IMAGE_NEGATIVE_PROMPT` |
|
||||
| `src/services/ai.ts` | 前端编排调用方 | 组装请求并调用同一份 prompt builder |
|
||||
| `server-node/src/services/sceneImageService.ts` | 后端执行器调用方 | 在服务端用同一份 prompt builder 生成 prompt,再请求上游模型 |
|
||||
|
||||
这条链的关键变化是:
|
||||
|
||||
- 不再让 `src/services/customWorld.ts` 承担场景图 prompt 正文主源
|
||||
- 前后端场景图生成改为共用 `src/prompts/customWorldPrompts.ts`
|
||||
|
||||
## 7. 本轮完成的原散点收口
|
||||
|
||||
本轮已经完成的原散点包括:
|
||||
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts` 中的角色资产 prompt
|
||||
- `server-node/src/services/eightAnchorPromptBuilder.ts` 中的八锚点 prompt
|
||||
- `src/services/customWorld.ts` 中的自定义世界分阶段 prompt 与场景背景图 prompt
|
||||
- `src/services/ai.ts` 中的世界修复 / 语言修复 / JSON only system prompt
|
||||
- `src/services/prompt.ts`、`characterChatPrompt.ts`、`questPrompt.ts`、`runtimeItemAiPrompt.ts` 这批前端 prompt 脚本
|
||||
- `src/tools/qwenSpriteSheetToolModel.ts`、`src/components/asset-studio/customWorldRolePromptDefaults.ts`、`src/components/CustomWorldEntityEditorModal.tsx` 里的工具 / 编辑器 prompt 散点
|
||||
|
||||
## 8. 当前仍在非 Prompt 目录中的相关文件
|
||||
|
||||
仍在非 prompt 目录中的相关文件,当前主要是:
|
||||
|
||||
- 调用方
|
||||
- 兼容层
|
||||
- 测试
|
||||
|
||||
因此现在的工程状态已经从“散点查找”变成“目录集中 + 兼容过渡”。
|
||||
|
||||
## 9. 验证结果
|
||||
|
||||
本轮收口后已验证:
|
||||
|
||||
- `npm run check:encoding`
|
||||
- `npm --prefix server-node run build`
|
||||
- `npm run build`
|
||||
- `npm run server-node:test`
|
||||
|
||||
结果:
|
||||
|
||||
- 编码检查通过
|
||||
- 前端构建通过
|
||||
- 后端构建通过
|
||||
- `server-node` 测试 143 项全部通过
|
||||
|
||||
## 10. 本次盘点后的判断
|
||||
|
||||
截至 2026-04-19,本仓库的业务 prompt 已经基本完成目录化管理。
|
||||
|
||||
当前更准确的结论是:
|
||||
|
||||
- 后端正式业务 prompt 主源集中在 `server-node/src/prompts/`
|
||||
- 前端与编辑器 prompt 主源集中在 `src/prompts/`
|
||||
- 共享资产 prompt 主源集中在 `packages/shared/src/prompts/`
|
||||
- 旧服务路径、旧工具路径仍保留为兼容层,但不再承担 prompt 正文维护职责
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
## 当前入口
|
||||
|
||||
- [BUSINESS_PROMPT_INVENTORY_2026-04-19.md](./BUSINESS_PROMPT_INVENTORY_2026-04-19.md):业务中现存提示词的总清单,覆盖后端主链、前端遗留、自定义世界、角色形象生成、场景背景生成与工具链 prompt。
|
||||
- [FUNCTION_SCRIPT_CATALOG_2026-04-04.md](./FUNCTION_SCRIPT_CATALOG_2026-04-04.md):Function 独立脚本目录与分类速查。
|
||||
- [TASK_GENERATION_TRACE_2026-04-08.md](./TASK_GENERATION_TRACE_2026-04-08.md):任务描述、达成条件与奖励生成链路梳理。
|
||||
- [CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md](./CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md):自定义世界当前仍依赖哪些模板世界设定的清单。
|
||||
|
||||
@@ -854,7 +854,8 @@ generatedAnimationOverrides?: Partial<Record<AnimationState, string>>;
|
||||
|
||||
## 10.3 本地 API 层
|
||||
|
||||
当前项目已经有 `scripts/dev-server/localApiPlugins.ts` 这种本地 API 插件机制,应该复用。
|
||||
自 `2026-04-19` 起,旧 `scripts/dev-server/localApiPlugins.ts` 已从仓库删除。
|
||||
当前角色视觉与动画相关 `/api/*` 能力应统一落到 `server-node/src/modules/assets/**` 与 `server-node/src/modules/ai/**`,不再复用旧 Vite 本地插件链路。
|
||||
|
||||
建议新增:
|
||||
|
||||
|
||||
@@ -82,7 +82,8 @@
|
||||
|
||||
### 2.3 本地 API 插件里已经有 DashScope 接入样板
|
||||
|
||||
`scripts/dev-server/localApiPlugins.ts` 里已经接了自定义世界场景图:
|
||||
本文撰写时,旧 `scripts/dev-server/localApiPlugins.ts` 里已经接了自定义世界场景图。
|
||||
截至 `2026-04-19`,该文件已从仓库删除,对应样板能力应改为参考 `server-node/src/modules/assets/**` 与 `server-node/src/modules/ai/**`:
|
||||
|
||||
- 默认 DashScope base URL 已经存在
|
||||
- 已经有异步任务创建、轮询、下载、落盘、写 manifest 的完整样板
|
||||
@@ -480,7 +481,7 @@
|
||||
|
||||
- 最少改 UI
|
||||
- 最快复用当前 `CharacterAssetPanel`
|
||||
- 最容易复用 `localApiPlugins.ts` 里现有 DashScope 异步任务模式
|
||||
- 最容易复用现已迁入 `server-node` 的 DashScope 异步任务模式
|
||||
|
||||
## 9.2 第二轮
|
||||
|
||||
@@ -641,5 +642,6 @@
|
||||
- `src/components/preset-editor/characterAssetStudioPersistence.ts`
|
||||
- `src/routing/appRoutes.tsx`
|
||||
- `src/services/ai.ts`
|
||||
- `scripts/dev-server/localApiPlugins.ts`
|
||||
- `server-node/src/modules/assets/**`
|
||||
- `server-node/src/modules/ai/**`
|
||||
- `docs/technical/AI_CHARACTER_ANIMATION_TECHNICAL_SOLUTION_2026-04-04.md`
|
||||
|
||||
@@ -73,12 +73,12 @@
|
||||
|
||||
## 5. 旧工具链隔离状态
|
||||
|
||||
`scripts/dev-server/**` 中的旧 Vite 本地插件已经不再由 `vite.config.ts` 注入,也不再作为当前开发入口使用。
|
||||
自 `2026-04-19` 起,`scripts/dev-server/**` 中的旧 Vite 本地插件实现代码已经从仓库删除,也不再作为当前开发入口使用。
|
||||
|
||||
旧文件保留用途:
|
||||
当前保留状态:
|
||||
|
||||
- 作为历史迁移参考。
|
||||
- 对照旧 DashScope 调用与文件写入逻辑。
|
||||
- `scripts/dev-server/` 目录只保留迁移说明 README。
|
||||
- 旧链路的历史背景由 `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md` 等审计文档承接。
|
||||
|
||||
新增编辑器或资产能力时,应优先写入:
|
||||
|
||||
@@ -103,4 +103,4 @@
|
||||
- 前端编辑器组件已通过统一 SDK 或资源 ID 访问编辑器 API。
|
||||
- Vite 已代理 `/api/editor` 与 `/api/assets` 到 Node 后端。
|
||||
- 写接口已经有环境门禁。
|
||||
- 旧 Vite 本地插件不再是当前工具链入口。
|
||||
- 旧 Vite 本地插件代码已删除,不再保留并行实现。
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
当前不再使用:
|
||||
|
||||
- Vite 本地 API 插件 `scripts/dev-server/` 作为当前接口入口
|
||||
- 已删除的旧 Vite 本地 API 插件链路 `scripts/dev-server/*.ts`
|
||||
|
||||
## 2. 技术栈
|
||||
|
||||
@@ -162,6 +162,11 @@ JWT 现状:
|
||||
- `POST /api/runtime/items/runtime-intent`
|
||||
- `POST /api/runtime/quests/generate`
|
||||
|
||||
补充说明(`2026-04-19`):
|
||||
|
||||
- `POST /api/custom-world/scene-image` 现在支持前端仅提交 `profile + landmark + userPrompt` 上下文,由后端统一补齐场景图 prompt 与默认 negative prompt。
|
||||
- runtime story option 的 `interaction` 元数据现在由后端随 option 一并返回,前端不再本地按 `functionId` 重建 NPC / treasure 交互语义。
|
||||
|
||||
编辑器工具:
|
||||
|
||||
- `GET /api/editor/catalog/items`
|
||||
@@ -198,7 +203,11 @@ Story:
|
||||
|
||||
Custom World:
|
||||
|
||||
- Node 后端直接复用前端现有多阶段生成编排
|
||||
- Node 后端当前已自持 `server-node/src/modules/custom-world/**` 运行时模块
|
||||
- 已承接 `creator intent` 归一化、`anchorPack / lockState` 推导、framework normalize、runtime profile compile
|
||||
- `customWorldOrchestrator` 与 `customWorldAgentFoundationDraftService` 已不再运行时 import 前端 `src/services/customWorld*.ts` 与 `src/types.js`
|
||||
- `server-node/src/prompts/customWorldPrompts.ts` 已承接 foundation draft 与 scene image 使用的 custom world prompt source
|
||||
- 上述 prompt 迁移只改变源码归属位置,没有改动提示词正文
|
||||
- 当前保留 `session + answers + SSE progress/result/error` 协议
|
||||
- 前端已支持接收真实阶段进度对象
|
||||
|
||||
@@ -238,4 +247,4 @@ Vite 当前只负责代理,不再提供本地 API 插件。
|
||||
|
||||
全部转发到 Node 后端。
|
||||
|
||||
旧 `scripts/dev-server/**` 文件仅保留为迁移参考,不再由 `vite.config.ts` 注入。
|
||||
`scripts/dev-server/` 目录现仅保留 README 作为迁移说明,旧本地 API 实现代码已于 `2026-04-19` 删除。
|
||||
|
||||
@@ -2,12 +2,17 @@
|
||||
|
||||
## 1. 这次调整解决什么问题
|
||||
|
||||
此前后端提示词分散在多个业务模块里:
|
||||
此前提示词分散在多个后端、前端和工具文件里:
|
||||
|
||||
- `server-node/src/modules/ai/**`
|
||||
- `server-node/src/modules/quest/**`
|
||||
- `server-node/src/modules/runtime-item/**`
|
||||
- `server-node/src/services/customWorld*.ts`
|
||||
- `server-node/src/services/eightAnchorPromptBuilder.ts`
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
- `src/services/**`
|
||||
- `src/tools/qwenSpriteSheetToolModel.ts`
|
||||
- `src/components/**`
|
||||
|
||||
问题主要有三类:
|
||||
|
||||
@@ -15,23 +20,40 @@
|
||||
2. 同一类 prompt 缺少集中入口,排查系统 prompt / user prompt / repair prompt 成本高。
|
||||
3. 老桥接层、测试和新业务链路同时依赖时,迁移成本高,容易出现导出断裂。
|
||||
|
||||
这次收口目标不是“重写全部 AI 链路”,而是先把当前后端主链 prompt 收到单独目录,业务模块退化成“准备上下文 + 调用 prompt 脚本”。
|
||||
这次收口目标不是“重写全部 AI 链路”,而是把当前正式业务 prompt 主源收到独立目录,业务模块退化成“准备上下文 + 调用 prompt 脚本”。
|
||||
|
||||
## 2. 新目录
|
||||
|
||||
本轮新增目录:
|
||||
本轮落地后的目录:
|
||||
|
||||
```text
|
||||
packages/shared/src/prompts/
|
||||
└─ qwenSprite.ts
|
||||
|
||||
server-node/src/prompts/
|
||||
├─ characterAssetPrompts.ts
|
||||
├─ chatPromptBuilders.ts
|
||||
├─ customWorldAgentPrompts.ts
|
||||
├─ customWorldEntityPrompts.ts
|
||||
├─ customWorldOrchestratorPrompts.ts
|
||||
├─ customWorldSceneNpcPrompts.ts
|
||||
├─ eightAnchorPrompts.ts
|
||||
├─ questPrompts.ts
|
||||
├─ runtimeItemPrompts.ts
|
||||
├─ storyOrchestratorPrompts.ts
|
||||
└─ storyPromptBuilders.ts
|
||||
|
||||
src/prompts/
|
||||
├─ characterChatPrompts.ts
|
||||
├─ customWorldEntityActionPrompts.ts
|
||||
├─ customWorldOrchestratorPrompts.ts
|
||||
├─ customWorldPrompts.ts
|
||||
├─ customWorldRolePromptDefaults.ts
|
||||
├─ questPrompts.ts
|
||||
├─ qwenSpriteSheetToolPrompts.ts
|
||||
├─ runtimeItemPrompts.ts
|
||||
├─ storyOrchestratorPrompts.ts
|
||||
└─ storyPromptBuilders.ts
|
||||
```
|
||||
|
||||
当前职责划分:
|
||||
@@ -54,6 +76,20 @@ server-node/src/prompts/
|
||||
- 世界编辑器角色 / 场景实体生成 prompt
|
||||
- `customWorldSceneNpcPrompts.ts`
|
||||
- 世界编辑器场景 NPC 生成 prompt
|
||||
- `characterAssetPrompts.ts`
|
||||
- 角色主图 / 动作试片 / 角色关联场景 prompt
|
||||
- `eightAnchorPrompts.ts`
|
||||
- 八锚点状态推断、模式规则与正式单轮共创 prompt
|
||||
- `src/prompts/customWorldPrompts.ts`
|
||||
- 自定义世界分阶段生成 prompt 与场景背景图 prompt
|
||||
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
- 精灵图工具主词 / 分镜词 / 修帧词 / 负面词
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
- 角色资产工作台默认 prompt 种子
|
||||
- `src/prompts/customWorldEntityActionPrompts.ts`
|
||||
- 编辑器技能动作 prompt
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- 共享资产层的基础角色 prompt 模板
|
||||
|
||||
## 3. 落地规则
|
||||
|
||||
@@ -82,12 +118,18 @@ server-node/src/prompts/
|
||||
|
||||
### 3.3 兼容层保留旧导出
|
||||
|
||||
本轮对已有纯 prompt builder 文件采取了兼容迁移:
|
||||
本轮对已有纯 prompt builder 文件采取了兼容迁移,旧路径保留为薄 re-export:
|
||||
|
||||
- `server-node/src/modules/ai/chatPromptBuilders.ts`
|
||||
- `server-node/src/modules/ai/storyPromptBuilders.ts`
|
||||
|
||||
旧路径现在作为薄 re-export 保留,避免测试、桥接层和旧引用一次性全部断掉。
|
||||
- `server-node/src/services/eightAnchorPromptBuilder.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/characterChatPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
- `src/tools/qwenSpriteSheetToolModel.ts`
|
||||
- `src/components/asset-studio/customWorldRolePromptDefaults.ts`
|
||||
- `packages/shared/src/assets/qwenSprite.ts`
|
||||
|
||||
对于 `runtimeQuestModule.ts`、`runtimeItemModule.ts` 这类被桥接层直接引用的模块,本轮保留原导出名,通过 re-export 指向新 prompt 文件,保证兼容性。
|
||||
|
||||
@@ -95,11 +137,12 @@ server-node/src/prompts/
|
||||
|
||||
新增提示词时按下面顺序处理:
|
||||
|
||||
1. 先判断是否属于已有领域。
|
||||
2. 如果属于已有领域,优先补到对应 `server-node/src/prompts/*.ts`。
|
||||
3. 如果是新领域,再新增一个独立 prompt 脚本文件。
|
||||
4. 业务模块只传入已经整理好的上下文字段,不在模块内部继续拼长文本。
|
||||
5. 至少补一条该 prompt 的调用链测试或现有测试断言。
|
||||
1. 先判断属于后端、前端/编辑器还是共享工具层。
|
||||
2. 后端正式业务优先补到 `server-node/src/prompts/*.ts`。
|
||||
3. 前端/编辑器 prompt 优先补到 `src/prompts/*.ts`。
|
||||
4. 可复用的共享资产 prompt 优先补到 `packages/shared/src/prompts/*.ts`。
|
||||
5. 业务模块只传入已经整理好的上下文字段,不在模块内部继续拼长文本。
|
||||
6. 至少补一条该 prompt 的调用链测试或现有测试断言。
|
||||
|
||||
建议命名:
|
||||
|
||||
@@ -108,7 +151,7 @@ server-node/src/prompts/
|
||||
- user prompt:`buildXXXPrompt`
|
||||
- 纯文本装配:`buildXXXPromptText`
|
||||
|
||||
## 5. 本轮范围与剩余事项
|
||||
## 5. 本轮范围与当前状态
|
||||
|
||||
本轮已经收口:
|
||||
|
||||
@@ -119,16 +162,17 @@ server-node/src/prompts/
|
||||
- Custom World 主编排
|
||||
- Custom World Agent 草稿增补
|
||||
- Custom World 编辑器角色 / 场景 / 场景 NPC 生成
|
||||
- Character Asset
|
||||
- Eight Anchor
|
||||
- Scene Image
|
||||
- 前端剧情 / 私聊 / 任务 / 物品 prompt 兼容层
|
||||
- 编辑器与工具链 prompt 种子
|
||||
|
||||
本轮尚未完全收口的内联 prompt 聚集区:
|
||||
当前状态:
|
||||
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
- `server-node/src/services/eightAnchorPromptBuilder.ts`
|
||||
|
||||
这两块后续继续沿用同一规则:
|
||||
|
||||
- 先抽出 prompt 文本与 builder
|
||||
- 再让业务文件只保留参数整理与调用
|
||||
- 正式业务 prompt 主源已经集中到 prompt 目录。
|
||||
- 旧 `services/`、`tools/`、`components/` 下保留的相关文件主要是兼容层或调用方。
|
||||
- 当前没有再发现需要优先继续抽离的大块业务 prompt 正文。
|
||||
|
||||
## 6. 验证方式
|
||||
|
||||
@@ -138,6 +182,9 @@ server-node/src/prompts/
|
||||
- `npm run server-node:test`
|
||||
- `npm --prefix server-node run build`
|
||||
|
||||
说明:
|
||||
本轮实测结果:
|
||||
|
||||
- 当前仓库里 `server-node/src/db.test.ts` 仍有一条与新增迁移版本号相关的既有失败,不属于本次 prompt 目录改造引入的问题。
|
||||
- `npm run check:encoding` 通过
|
||||
- `npm --prefix server-node run build` 通过
|
||||
- `npm run build` 通过
|
||||
- `npm run server-node:test` 143 项全部通过
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md](./REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md):落实工程清理审计第一阶段后的仓库噪音清理范围、忽略规则闭合点与后续约束。
|
||||
- [PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md](./PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md):后端提示词收口到 `server-node/src/prompts/` 的目录方案、兼容策略与后续新增规则。
|
||||
- [NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md](./NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md):当前 Node 运行时后端的技术栈、入口、鉴权、存储与接口知识图谱。
|
||||
- [EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md](./EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md):Express 后端当前 contract 冻结版本、热点文件编辑规则与集成窗口清单。
|
||||
|
||||
53
docs/technical/REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md
Normal file
53
docs/technical/REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# 仓库噪音清理基线(2026-04-19)
|
||||
|
||||
更新时间:`2026-04-19`
|
||||
|
||||
## 1. 背景
|
||||
|
||||
本次清理落实以下审计结论:
|
||||
|
||||
- `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md`
|
||||
|
||||
目标只覆盖审计文档推荐执行顺序中的第一阶段,也就是先把仓库噪音产物和本地检查残留从主工程面清掉,不在这一轮同时推进前后端边界迁移或无入口模块归档。
|
||||
|
||||
## 2. 本次已执行的清理
|
||||
|
||||
本轮已从仓库中移除以下高置信度噪音产物:
|
||||
|
||||
- 根目录的 `.codex-*` 日志、`.preview.*` 输出、`tmp_*` 扫描文本与 HTML、`npc-editor-*` 截图和调试文件、`temp-write-check.txt`
|
||||
- 根目录 `temp-build-goal-check/` 大体量检查产物目录
|
||||
- `scripts/__pycache__/` Python 缓存目录与 `.pyc` 文件
|
||||
- `.codex-logs/` 中遗留的旧日志与 restore backup 文件
|
||||
|
||||
这些文件都不属于正式运行时代码、PRD、设计稿或生产资源,继续保留只会污染根目录视野、拖慢扫描和 review,并增加误判成本。
|
||||
|
||||
## 3. 规则闭合
|
||||
|
||||
为避免相同问题反复回流,本次同步补齐了两层规则:
|
||||
|
||||
1. `.gitignore`
|
||||
- 新增 `/.codex-logs/`
|
||||
- 新增 `*.py[cod]`
|
||||
- 保持 `.preview.*`、`tmp_*`、`tmp/`、`npc-editor-*`、`temp-write-check.txt`、`temp-build-goal-check/`、`**/__pycache__/` 为忽略项
|
||||
2. `.eslintrc.cjs`
|
||||
- 保持 `temp-build-goal-check/**`
|
||||
- 保持 `.preview.*`、`tmp_*`、`tmp/**`、`npc-editor-*`、`temp-write-check.txt`
|
||||
- 保持 `**/__pycache__/**`
|
||||
|
||||
这样 Git 与 ESLint 对临时产物的忽略口径保持一致,不会再出现某个目录虽然被 Git 忽略,但仍被 lint 扫进去的情况。
|
||||
|
||||
## 4. 后续约束
|
||||
|
||||
- 以后所有临时扫描结果、调试截图、HTML 导出、一次性日志,不要直接落在仓库根目录。
|
||||
- 如需保留本地临时产物,统一放到本地忽略目录,例如 `tmp/` 或 `.codex-logs/`。
|
||||
- `temp-build-goal-check/` 仍视为本地检查产物,不作为主工程目录的一部分长期保留。
|
||||
- Python 脚本执行后产生的 `__pycache__` 不应进入仓库。
|
||||
|
||||
## 5. 本轮未处理范围
|
||||
|
||||
以下内容仍按审计原计划留待后续阶段处理:
|
||||
|
||||
- `scripts/dev-server/localApiPlugins.ts` 及旧 Vite 本地 API 链路的归档
|
||||
- 无运行时入口或仅测试引用的孤岛模块处置
|
||||
- 前后端双份真相收口与 `server-node -> src/**` 反向依赖治理
|
||||
- 巨型热点文件拆分
|
||||
@@ -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 主链,优先交付一条可验证、可继续扩展的后端边界基线。
|
||||
@@ -42,7 +42,8 @@
|
||||
|
||||
### 2.2 当前 API 层还只是开发期能力
|
||||
|
||||
这些接口现在主要由 [scripts/dev-server/localApiPlugins.ts](/E:/Repos/Genarrative/scripts/dev-server/localApiPlugins.ts) 挂在 Vite dev/preview 服务器里。
|
||||
本文撰写时,这些接口主要由旧 `scripts/dev-server/localApiPlugins.ts` 挂在 Vite dev/preview 服务器里。
|
||||
截至 `2026-04-19`,这条旧链路已经从仓库删除,当前统一由 `server-node` 承接。
|
||||
|
||||
这在本地开发阶段很方便,但生产环境存在几个明显问题:
|
||||
|
||||
@@ -500,7 +501,14 @@ flowchart LR
|
||||
|
||||
## 11.1 第一优先级:把 Vite 里的 API 能力抽出来
|
||||
|
||||
当前 [scripts/dev-server/localApiPlugins.ts](/E:/Repos/Genarrative/scripts/dev-server/localApiPlugins.ts) 里的能力,建议分三类迁移:
|
||||
该迁移建议已完成,原 `scripts/dev-server/localApiPlugins.ts` 已于 `2026-04-19` 删除。
|
||||
对应能力现统一收口到以下正式模块:
|
||||
|
||||
- `server-node/src/modules/editor/**`
|
||||
- `server-node/src/modules/assets/**`
|
||||
- `server-node/src/modules/ai/**`
|
||||
|
||||
原旧链路中的能力,可按以下三类理解其迁移归属:
|
||||
|
||||
### A. 运行时代理接口
|
||||
|
||||
|
||||
Reference in New Issue
Block a user