# RP 模块业务审计：世界、剧情、记忆与专家

审计基线：`FlowGPT/roleplay-harness@80aef3fa5582d8508ecdd1afa206391940ce9502`。源码位于 `work/roleplay-harness-main`。已先读 `AGENTS.md`。这是源码和测试断言审读；未执行真实模型、未修改业务代码、图或 reader，也未把代码 fallback 当作线上配置。

本文的 `路径:行号` 均相对于上述仓库；可拼接固定版本 GitHub URL：`https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/<路径>#L<行号>`。

## 先把六种“记住”分开

| 名称 | PM 可以理解成什么 | 主要保存/处理什么 | 本轮是否直接给 Actor |
|---|---|---|---|
| Worldbook | 作者维护的世界设定资料库 | 条目原文、版本、适用条件与检索索引；不是每轮自动改写的聊天记忆 | 指定 `agentic-v2-worldbook` 场景在 Actor 准备时选条目，给当轮 Actor |
| Agentic RP State | RP 导演维护的当前局面便签 | 当前场景、事实、关系、未兑现事项等可持续状态；有验证与 CAS 提交 | Actor 准备阶段读取；后台更新提交后，后续读取才能看到 |
| Story World State | 有规则的世界模拟快照 | 前景事件、背景、暗流、时钟、可见性、待接受的当前行动等 | Story coordinator 将允许 Actor 使用的舞台投影注入 |
| Story Narrative State | 有状态的剧情编排器 | 主支线方向、待完成目标、回报债务、戏剧阶段、情绪、事件结算记录 | 给 Actor 当前方向/可处理的剧情任务；任务不是已发生事实 |
| 应用 Memory | 长期记忆读写系统的接线 | 日记/摘要、结构化记忆表，或外部 Hinos 服务记忆 | 召回结果通过 prompt 变量/消息进入准备阶段；成功回复后进入 ingest |
| Compact | 上下文窗口管理器 | 已发生对话的压缩摘要及覆盖范围/checkpoint | 把“较早历史摘要 + 保留的最近原文”放入当前模型上下文 |

还有一个最误导的目录：`packages/tools/src/modules/memory` 中的六个专家，**本质上是咨询模型，不是六个长期记忆数据库**。它们可以读当前状态，但只返回建议文字；并不自行写状态。

## 模块职责、输入输出与实际挂载矩阵

“写”分清两层：返回一个修改后的 snapshot，不等于已经写入数据库。工具层可返回候选，应用层才负责提交。

| 模块 / 工具 | 输入 → 输出；是否调用模型 | 读写边界 | 谁在什么时候实际调用 |
|---|---|---|---|
| 六专家 `createAgentCoreTool` | 角色卡、用户人设、当前 Agentic state、compact 摘要、最近可见对话、当前输入、`reason/focus` → 建议文本、usage；调用专家模型 | `advisory: true`；无持久化写入 | 普通 Agentic V2 注册六种能力，由启用工具配置及 Planner 决策选择；不代表每轮六个全跑。`agentic-v2.ts:339,447` |
| `context-compiler` | 当前状态及对话 → 有限预算的专家输入字符串；不调用模型 | 只做上下文投影，无数据库读写 | 公共工具能力；advisory 内也有输入组装。`packages/tools/src/context-compiler.ts:16,32,54` |
| `get_memory` / `update_memory` | get → JSON + revision；update 接收完整 JSON + expectedRevision → 新 revision；不调用模型 | 注入 store 的 get / CAS；update 是整对象替换，省略键会删除，不是深合并 | SDK 公开可复用工具。当前 `apps/`、`adapters/` 检索未发现 `createMemoryTools` 的挂载；不能说它就是服务现行 Planner 工具。`memory-tool.ts:14,20,36` |
| `ReadMemoryTool` / `WriteMemoryTool` | 通用 store 操作包装 → snapshot / revision；无模型 | 低层 get / CAS，Write 本身不重试 | Agentic state runtime 复用这个基础组件；实际导演工具名是 `update_director_state`。`planning/runtime.ts:341`；`planning/agentic-v2.ts:34,141` |
| `update_director_state` | 当前状态、上下文、专家结果等 → 完整候选 Agentic RP State | 服务验证候选并条件提交；不是专家自己写 | 普通 Agentic V2 registry 中与专家并列，但标记非 advisory。`planning/agentic-v2.ts:64,399,447` |
| `PovPrepareTurnTool` | World snapshot + 当前自由文本/choice intent → prepared snapshot、flags、stage、surfacing、dice、诊断 | 返回新候选；不写库。同一待处理 turn 可恢复，不重复消耗随机/时钟 | Story 的 Actor 准备阶段；自由文本可能先调 `pov_intent`，特殊情况可调 escort；明确传入 intent 可跳过 intent 模型。`modules/story/world.ts:86,97,109,128,144` |
| `PovAdvanceWorldTool` | 已准备的世界 + **权威保存的已接受完整 Actor 文本** → 已结算 snapshot，或 pending | 工具的 `committed` 是结算结果，不是数据库提交；宿主拥有并发与存储 | Story 在下次正常请求准备阶段，核对上轮保存结果后调用。`modules/story/world.ts:153,154,191`；`story/coordinator.ts:190,365` |
| `NarrativePlanCycleTool` | narrative snapshot + setting → 新一周期待办目标；调用模型 | 仅返回 snapshot；`needPlan` 才计划，同 turn 重放不重做 | Story 需要新周期且无阻塞待结算事件时调用。`modules/story/narrative.ts:47,48,70`；`story/coordinator.ts:253,255` |
| `NarrativeDealBeatTool` | narrative snapshot + phase/preferred kind → 当前剧情 packet + snapshot；**不调用模型** | 机械打分、依赖筛选、轮换；不写库，不把 pending 变成既成事实 | Story Actor 准备；只分派满足先决条件的目标。`modules/story/narrative.ts:100,101` |
| `NarrativeSettleEventTool` | eventId + 完整已接受事件文本 + 用户行动 → settled / unknown / duplicate + snapshot；调用模型 | unknown 不推进、不增加饥饿计数；eventId 去重；应用之后持久化 | Story 事件结束/待结算时；失败保留完整证据，有限重试。`modules/story/narrative.ts:183,190,197`；`story/coordinator.ts:286` |
| `NarrativeRebranchTool` | 请求的 main/sub scope + setting/direction → 新方向与 bridge；调用模型 | 只返回被要求范围的改写候选 | Story 的 nextActions 要求重分支时，coordinator 有限执行；不是每轮随意重写主线。`modules/story/narrative.ts:255`；`story/coordinator.ts:347` |
| `PersonalizationMemoryRuntime` | recall 调 before_chat hooks 返回 setvars；ingest 把输入上下文及 output/rawOutput/reasoning 给 after_chat hooks | 外部 hook 才拥有实际记忆行为；本地 `consolidate` 空实现 | 未选其他 runtime 时的默认应用路径；sources 决定实际 hook。`memory/personalization-memory-runtime.ts:35,79,104`；`dispatch.ts:797,871` |
| `AxonMemoryRuntime` | recall 取日记合并摘要/记忆表；ingest 日记调度和表编辑 | 日记写在后台编排；表经 Axon apply edits + version replace，有一次冲突重读重应用 | `memoryRuntime=axon_go` 且相应 sources 挂载。变量 `compassMemory` / `memoryTable`。`axon-memory-runtime.ts:41,98,151,162`；`dispatch.ts:805` |
| `DiaryIngestOrchestrator` | 完成事件、agent 配置、订阅/配额/计数 → 日记模型生成、解析、append、缓存等 | 真正长期记忆写入链路，经外部 Axon 操作；并非 Agentic Planner 工具 | 已完成回复后进入后台；是否生成还要通过 quota/cooldown/lock/summary enable/Axon plan。`diary-orchestrator.ts:179,197,269,297,332,354` |
| `ShadowMemoryRuntime` | 并行读 legacy 与 Go 并比对 → 仍返回 legacy 结果 | ingest 只写 legacy；不是双写双生效 | `memoryRuntime=axon_shadow`。`dispatch.ts:834,847`；`test/axon-memory-runtime.test.ts:256` |
| `HinosMemoryRuntime` | 外部 prepare 接收系统上下文与对话 → memory + claim；成功后 commit 同一 claim/user/assistant | 真正外部记忆服务边界；本仓库无法证明其内部召回/压缩算法 | `memoryRuntime=hinos`；先基础 Axon render，再 prepare，非空记忆再 render；独立于 Go 日记实现。`hinos-memory-runtime.ts:44,50,112,155` |
| `RoleplayCompactRuntime` | 源历史 + 角色语义 + 模型预算 + checkpoint → 摘要、保留历史、渲染结果 | 读取 checkpoint，必要时模型压缩；合格时 CAS checkpoint；本地采纳不等于持久化成功 | 显式 `compact` 配置下 Actor 准备阶段；Agentic 联用有 contextGovernance 要求。`compact-runtime.ts:859,934,985,1137`；`server.ts:763` |

上表路径省略前缀规则：`planning/`、`story/`、`memory/` 属于 `apps/emochi/`；`dispatch.ts` 属于 `adapters/agent-router/`；`modules/` 属于 `packages/tools/src/`。

### 六专家具体“分别执行什么”

全部共同机制：输入包含最近 **9 条 user/assistant 消息**，不是 9 轮；可以带 compact 摘要和当前状态。用户 persona 只是用户身份背景，不能自动记成目标角色事实。输出是建议；当前 Agentic state 的变更需要后续导演工具验证提交。

| API 名 | 业务工作 | 不应误读成 |
|---|---|---|
| `analyze_plot` | 看当前剧情节拍、主线、支线是否需要调整 | Story Narrative 持久状态机 |
| `judge_npc` | 检查 NPC 身份/人数/动机/位置/进退场与访问权 | 凭空加 NPC 或直接移动人物 |
| `audit_knowledge` | 区分事实、秘密、谎言、猜测和“谁知道什么” | 通用知识库检索器 |
| `simulate_world` | 判断时间变化、离场、日程、期限与幕后生活的合理推进 | `PovAdvanceWorldTool` 那种有状态结算器 |
| `manage_callbacks` | 识别承诺、伏笔、物件、伤势、义务、延迟后果 | 必须立刻兑现所有伏笔的队列 |
| `direct_scene` | 给视角、镜头、角色行动幅度建议，保留用户自主权 | 直接代替 Actor 写最终正文 |

证据：`packages/tools/src/modules/memory/advisory.ts:18,31,63,169,184,192,213,239,255,315`；`modules/memory/world.ts:5` 直接把 `WorldTool` 绑定为 `simulate_world`；`specialist-tools.ts:1` 是兼容导出入口。

## 八个必须向 PM 讲清的边界

### 1. 名字相似不代表同一套功能

`modules/memory` 的六专家、`memory-tool` 的任意 JSON CAS、Emochi 的日记/表/Hinos、Compact、Agentic state 是不同责任。`MemoryRuntime.consolidate()` 在 Personalization、Axon、Hinos 的当前实现为空，不能凭接口存在说“系统定期自我整理全部记忆”。

测试印证 JSON 工具是真正替换写：`test/json-memory-tools.test.ts:22` 断言省略字段被移除；`:51` 断言冲突、取消、网络失败不自动重试。注意 Agentic 应用在这个基础类外另有自己的有限故障重试/模糊写入确认策略，不能把“底层不重试”推广为整个应用都不重试。证据：`planning/agentic-v2.ts:133`。

### 2. 注册工具不等于全部调用，更不等于全部写入

Agentic 注册六专家和导演；专家结果供决策参考，导演生成候选状态。advisory 工具能并行，但导演不得与建议工具在同一步并行抢先决策；代码会要求等结果后再决定。工具自身可能产生模型调用，但不是每个请求固定跑全部专家。证据：`planning/agentic-v2.ts:447,607,840,846,873`。

### 3. Story 不是普通 Agentic 后台 Planner 再叠一层

dispatch 是 `if (storyV1) ... else if (agenticV2)`：Story 创建自己的 `StoryScenarioAxonAdapter/StoryTurnCoordinator`；普通 Agentic 分支才创建 registry、Planner 和 TurnCoordinator。因此 Story 要求 Agentic Actor/recovery 配置，**不等于也运行普通 Agentic Planner**。证据：`dispatch.ts:1125,1141`。测试 `test/story-scenario.test.ts:131` 明确断言没有调用 `update_director_state`。

### 4. Story 当前输出是 pending；下轮才凭保存证据接受

以第 N 轮为例：

1. prepare 读取已持久 Story envelope。如果有 N−1 的 pendingActor，核对其 assistant ID、前一用户锚点、此前 accepted assistant 锚点，并读取权威已保存的消息内容。
2. 证据一致才用 **N−1 已保存的全文** 结算世界/剧情。第 N 轮用户的新请求被排除在上轮结算证据之外。
3. 为第 N 轮准备当前世界行动和剧情指导，Actor 生成正文。
4. Actor 成功后 `settle(prose)` CAS 保存本轮 prepared world + narrative + `pendingActor`，报告 `waiting_for_acceptance`。不是拿刚生成的 raw prose 当已接受事实。
5. 下次请求再走同样核对。更关键：步骤 2 的上轮结算在 prepare 中也只是**候选**；只有本轮 Actor 成功，才和本轮 pending 一起写回。如果本轮没成功，不提前提交这个新候选。

证据：`story/coordinator.ts:190,232,247,365,390,413`。测试：`test/story-scenario.test.ts:111` 检查当轮无 world advance、没有保存刚生成正文、仍 pending；`test/story-deferred-review.test.ts:68` 使用故意不同的 raw 与 saved 文本，`:85` 断言 prepare 后 durable state 不变，`:88` 断言实际结算用 saved，`:91–94` 断言排除下轮新输入与 raw。

最新 pending 回复仍为同一消息 ID、关联用户输入与更早 accepted 正文锚点匹配时，系统采用该 ID 下实际保存的正文，包括编辑版；关联用户输入或更早 accepted 正文变化导致锚点不一致，或 pending 消息缺失/换 ID，才会重建。regenerate/edit_regenerate 走既有 Actor，只读，不调用 Story 模型或写状态；回退到更旧 source position 也不覆写更高水位。证据：`story/coordinator.ts:190–225`；`story/axon-adapter.ts:35,53,81`；`test/story-scenario.test.ts:292`；`test/story-deferred-review.test.ts:68,112`。

### 5. 剧情“安排”与剧情“兑现”必须分开

NarrativePlanCycle 产生待办；DealBeat 按条件机械挑选，默认 policy 中 `dealEveryTurns=3` 是这个内部派发器的候选轮换配置，不是快慢系统通用“每 3 轮唤醒 Planner”。SettleEvent 才依据已接受事件判定任务完成、主支线是否推进；unknown 就保留原状态，不拿失败当作“这条线被冷落了一次”。

证据：`modules/story/narrative.ts:47,100,183,197`；`narrative-state.ts:93`。测试：`test/story-narrative.test.ts:34` 验证先满足 setup 再给 reward 且重放不修改调用方；`:77` 验证 unknown 完全保留快照与空 nextActions；`:91` 验证模型失败仍保留 needPlan，不会偷偷嵌套更多工具调用。

### 6. 日记的 20/10 是配置 fallback，不是已证实线上频率，更不是 Planner 触发器

这里至少有三组容易混淆的数字：

| 字段 | 代码缺省值 | 来源与含义 |
|---|---:|---|
| `min_rounds` | 20 | 从 diary agent 工作流的 `generate_and_save_diary` 节点 config 按订阅解析 |
| `free_rounds_per_diary` | 10 | 免费路径的配置 fallback，进入配额/计划参数；不能直接解释成每 10 轮必写日记 |
| Memory V2 `first-rounds` / `recurring-rounds` | 20 / 10 | 后端配置 fallback；V2 识别及付费分支另有条件 |

`diary-orchestrator.ts:91,112,118,123,139,145` 为解析证据。真正生成链是完成事件调度 → 拉 agent config → quota / cooldown / lock → diary state 与 rounds → `Axon.planDiary(...)` → 只有 `plan.should_generate` 才请求模型 → parse → 按 `plan.should_save_diary` 决定 append。证据：`:179,197,200,204,207,225,269,297,332,354`。

rounds 优先用 Axon diary state；缺少时才通过 conversation length / 2 回退。配置可能覆盖这些默认值，Axon 的计划结果才是最终裁决；本仓库没有给出当前线上 agent 配置及 Go 计划算法的完整证据。测试 `test/diary-orchestrator.test.ts:87` 明确设置 plus min_rounds=10，模拟 Axon 返回 should_generate=true，并验证生成/缓存写回流程；它证明的是该配置及 plan 下能工作，不证明全站默认每 10 轮运行。

### 7. 长期记忆与 Compact 的触发、存储、失败处理不同

Axon 日记是完成后的后台工作；表 ingest 解析 `rawOutput ?? output` 中的编辑，版本冲突后只重读并重应用一次。`axon-memory-runtime.ts:151,162`；`test/axon-memory-runtime.test.ts:70` 验证冲突后使用新版本 8 提交。

Compact 是 Actor 准备时的窗口管理：先读取/验证 checkpoint，即使当前短窗口本身很小也不能丢掉已压缩的历史；通常 `promptTokens > floor(promptBudget * triggerRatio)` 触发，还存在 checkpoint 边界即将滑出可见窗口而提前推进的情况。保留最近 canonical groups，再对更早可压缩历史做结构化总结。证据：`compact-runtime.ts:934,966,985,1001`。这是 token/覆盖连续性策略，不是固定 X 轮。

Compact 只有符合持久化条件才 CAS checkpoint；CAS 失败/冲突时仍可能本轮使用已验证摘要，但不谎报已持久化。证据：`compact-runtime.ts:1076,1137,1148`。测试定位：`test/compact-runtime.test.ts:301` checkpoint 重用；`:532` 分支不修改共享 checkpoint；`:767` 编辑源消息失效；`:1498` 持久化超时允许本地使用、不得声称 durable 或盲目重试。

Shadow 则是实验比较，读写仍以 legacy 为准，绝不是把 Go 作为第二份生产记忆同时写。`test/axon-memory-runtime.test.ts:256` 的断言为返回 version=legacy、legacy ingest=1、Go ingest=0。

### 8. 实際场景不能自由叠所有模块

| 组合 | 本快照的实际约束 |
|---|---|
| 普通 Agentic V2 + 六专家/导演 | 当前真实挂载；启用名单和 Planner 决策控制调用 |
| Story + Agentic Actor/recovery 配置 | 必须；Story 取代普通 Agentic coordinator，而非把两套 Planner 都运行 |
| Story + preActorDirector / Sumi | 配置拒绝 |
| Worldbook + 普通 Agentic V2 | 仅专门 `agentic-v2-worldbook` 场景；Actor 准备先读取状态，再 await Worldbook prepare；直接给 Actor |
| Worldbook + Story / Sumi / preActorDirector | 配置拒绝；不能画成所有业务默认都用世界书 |
| Agentic V2 + Compact | 可以，但要求 contextGovernance；enforce 模式反过来要求 Compact |
| Sumi + Agentic / Compact / preActorDirector / memorySources / before/after hooks | 当前场景配置拒绝；Sumi 是独立执行路径，不自动继承上述 Emochi 记忆链 |
| personalization / axon_go / axon_shadow / hinos | memoryRuntime 选择一条实现路径；shadow 是特定 legacy 对比模式，不是任意并联四套 |

证据：`apps/emochi/server.ts:715,720,724,728,749,763`；`adapters/agent-router/dispatch.ts:747,797,805,834,838,847,866,1125,1141`；Worldbook 准备次序 `apps/emochi/planning/runtime.ts:338`。具体生产 scenario 是否启用，仍需真实配置；这份审计只证明可用接线及拒绝规则。

## 用一个 PM 业务例子把分工串起来

以下是虚构示意，不是测试输出或模型必然反应。用户说：“我拿着昨天借来的钥匙，推开北塔的大门。”

### 路径 A：专门的 Agentic + Worldbook 场景

- **世界书**负责找作者写好的北塔设定，例如“午夜封门”“禁术要付代价”。它回答“这个世界原本怎么规定”，不会自行把本次开门写入静态书。
- **Agentic state**可能已有“钥匙借自莉娅、承诺天亮归还、守卫还不知道钥匙在用户手里”。它回答“这段 RP 到目前为止是什么局面”。
- **长期记忆召回（若此场景配置）**可带回更早的相处记录或记忆表；**Compact（若配置）**保住窗口装不下的早期聊天事实。两者目的相似但数据与触发不同。
- **Actor**在本轮准备好的角色卡、历史、状态与世界书条目等上下文下回复；它可能描写门锁、守卫和代价，不能说世界书强制保证某句话一定出现。
- **普通 Agentic Planner 需要时**可以问 `audit_knowledge`：“守卫是否有理由知道钥匙？”问 `manage_callbacks`：“借钥匙的约定是否值得继续保留？”专家只给建议；导演工具才产生待验证的完整新状态。写成功后的后续读取才能使用。
- **回复完成后的记忆 ingest**另走所选 MemoryRuntime。若为 Go diary，不代表当前立刻产生日记；需要配额、锁和 Axon plan 许可才生成并写入。

### 路径 B：独立 Story 场景（不能同时假设世界书已挂载）

- **World**解析本轮“开北塔门”的意图，准备门外/门内、背景与暗流中哪些信息可被看见，并可能处理时钟/掷骰等规则。
- **Narrative**机械挑一个条件已满足的当前任务，例如“让借钥匙的承诺形成一个可选择的冲突”；它不会把任务写成已经发生。
- **Actor**依据舞台与方向写出具体回复，成功后保存 prepared snapshot + pendingActor。
- **下次请求到来**，系统从权威存储取到用户实际保留的上轮回复，例如“守卫拦住了你”。只有这个已保存版本才作为世界/剧情结算证据；若原始流式草稿曾写“守卫被打倒”但最终保存版没有，就不应把“守卫被打倒”登记成事实。
- 复盘结果仍在本轮候选里；本轮 Actor 成功后再一起 CAS。若上轮没有充分事件证据，Narrative 可以保持 unknown/pending，不能为了推动进度假装目标已完成。

PM 的模块边界是：**资料库给规则，状态记录当下，专家给建议，Story 控制可结算的世界与剧情，长期记忆跨更长时间召回，Compact 让上下文装得下，Actor 负责对用户说话。** 真实请求根据场景走其中一套有效组合，并不会将所有名称都遍历一遍。

## 本轮检查范围

- 已读实际实现及上面列出的测试断言；主要核查 Story deferred acceptance、JSON CAS、Narrative unknown/replay、日记计划、表冲突重应用、shadow 读写归属。
- 未执行测试、真实模型或外部写请求；Compact 个别测试引用是定位后的覆盖索引，核心行为已按实现核对，未声称本轮运行通过。
- 未确认线上场景配置、在线模型内容、Axon Go 计划算法或 Hinos 内部实现。因此数字默认和服务边界按证据范围明确标注。


[返回 PM 导读](rp-business-guide.html) · [导读文本版](rp-business-guide.md)

## 可点击源码索引

- [apps/emochi/planning/agentic-v2.ts:339](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L339)
- [packages/tools/src/context-compiler.ts:16](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/context-compiler.ts#L16)
- [packages/tools/src/memory-tool.ts:14](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/memory-tool.ts#L14)
- [apps/emochi/planning/runtime.ts:341](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L341)
- [apps/emochi/planning/agentic-v2.ts:34](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L34)
- [apps/emochi/planning/agentic-v2.ts:64](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L64)
- [packages/tools/src/modules/story/world.ts:86](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/story/world.ts#L86)
- [packages/tools/src/modules/story/world.ts:153](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/story/world.ts#L153)
- [apps/emochi/story/coordinator.ts:190](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L190)
- [packages/tools/src/modules/story/narrative.ts:47](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/story/narrative.ts#L47)
- [apps/emochi/story/coordinator.ts:253](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L253)
- [packages/tools/src/modules/story/narrative.ts:100](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/story/narrative.ts#L100)
- [packages/tools/src/modules/story/narrative.ts:183](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/story/narrative.ts#L183)
- [apps/emochi/story/coordinator.ts:286](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L286)
- [packages/tools/src/modules/story/narrative.ts:255](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/story/narrative.ts#L255)
- [apps/emochi/story/coordinator.ts:347](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L347)
- [apps/emochi/memory/personalization-memory-runtime.ts:35](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/personalization-memory-runtime.ts#L35)
- [adapters/agent-router/dispatch.ts:797](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L797)
- [apps/emochi/memory/axon-memory-runtime.ts:41](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/axon-memory-runtime.ts#L41)
- [adapters/agent-router/dispatch.ts:805](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L805)
- [apps/emochi/memory/diary-orchestrator.ts:179](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/diary-orchestrator.ts#L179)
- [adapters/agent-router/dispatch.ts:834](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L834)
- [test/axon-memory-runtime.test.ts:256](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/axon-memory-runtime.test.ts#L256)
- [apps/emochi/memory/hinos-memory-runtime.ts:44](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/hinos-memory-runtime.ts#L44)
- [apps/emochi/memory/compact-runtime.ts:859](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/compact-runtime.ts#L859)
- [packages/tools/src/modules/memory/advisory.ts:18](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/memory/advisory.ts#L18)
- [packages/tools/src/modules/memory/world.ts:5](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/memory/world.ts#L5)
- [packages/tools/src/specialist-tools.ts:1](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/specialist-tools.ts#L1)
- [test/json-memory-tools.test.ts:22](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/json-memory-tools.test.ts#L22)
- [apps/emochi/planning/agentic-v2.ts:133](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L133)
- [apps/emochi/planning/agentic-v2.ts:447](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L447)
- [adapters/agent-router/dispatch.ts:1125](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1125)
- [test/story-scenario.test.ts:131](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/story-scenario.test.ts#L131)
- [test/story-scenario.test.ts:111](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/story-scenario.test.ts#L111)
- [test/story-deferred-review.test.ts:68](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/story-deferred-review.test.ts#L68)
- [apps/emochi/story/axon-adapter.ts:35](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/axon-adapter.ts#L35)
- [test/story-scenario.test.ts:292](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/story-scenario.test.ts#L292)
- [test/story-deferred-review.test.ts:112](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/story-deferred-review.test.ts#L112)
- [packages/tools/src/modules/story/narrative-state.ts:93](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/story/narrative-state.ts#L93)
- [test/story-narrative.test.ts:34](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/story-narrative.test.ts#L34)
- [apps/emochi/memory/diary-orchestrator.ts:91](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/diary-orchestrator.ts#L91)
- [test/diary-orchestrator.test.ts:87](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/diary-orchestrator.test.ts#L87)
- [apps/emochi/memory/axon-memory-runtime.ts:151](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/axon-memory-runtime.ts#L151)
- [test/axon-memory-runtime.test.ts:70](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/axon-memory-runtime.test.ts#L70)
- [apps/emochi/memory/compact-runtime.ts:934](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/compact-runtime.ts#L934)
- [apps/emochi/memory/compact-runtime.ts:1076](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/compact-runtime.ts#L1076)
- [test/compact-runtime.test.ts:301](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/compact-runtime.test.ts#L301)
- [apps/emochi/server.ts:715](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/server.ts#L715)
- [adapters/agent-router/dispatch.ts:747](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L747)
- [apps/emochi/planning/runtime.ts:338](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L338)
