# Emochi Actor / Agentic V2 上下文与时序核查

基线：roleplay-harness 80aef3fa5582d8508ecdd1afa206391940ce9502，本地源码归档。范围是当前 Emochi 普通 closed-loop + Agentic V2；StoryV1、Sumi 是单独分支，不能套用本页。已阅读根 AGENTS；只读业务源码，未调用真实模型，未修改业务或图。下列测试是逐项阅读断言，**本次没有运行测试**（归档无 node_modules/dist）。

## 1. 先纠正三个概念

- 当前业务接线不是“有 workflow 自动走 workflow，没 workflow 就单 LLM”。dispatch 明确构造空 executionGraph，然后普通 Actor 单次生成或按配置进入前台 function loop；通用 StaticPlanner 只校验/拓扑排序给定 DAG，不理解 query、不决定快慢。[dispatch:719–744](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L719)、[StaticPlanner:4–65](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/static-planner.ts#L4)
- 普通 Agentic V2 不是每累计 X 轮才启动。每个已完成准备、进入 generate 的逻辑轮，coordinator.schedule 一次；Actor 重试/同轮多个片段不会再次调度。它与当轮正文并行，先跑 Orchestrator，后者可决定不调用专家/Director。[runtime:558–621](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L558)、[generate:686–695](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L686)
- “前台 Planner”与“后台 Agentic Planner”不是同一个输入或循环。前者控制这次回复的 actor/image/dio/over；后者读开轮快照、更新将来可用的持续状态。前台工具调用不会自动转入 Agentic 的工具集合。

## 2. Actor 与后台 Planner 输入表

这里的 Planner 包含 Orchestrator、专家、Director；三者实际模型输入还有差异，见表。

| 输入 | 正文 Actor 实际拿到什么 | 后台 Agentic Planner 实际拿到什么 | 证据 |
|---|---|---|---|
| 角色定义 | Axon ModelConfig/PromptManager 宏渲染后的现有角色、人设、示例等；每轮补 characterName、language、角色指代约束 | 单独从 prompt.get + characterCard 取 name、description、definition；definition 优先 prompt.init_prompt，否则拼角色卡。不是整份 Actor prompt | [runtime:288–335](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L288)、[371–386](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L371) |
| 开场白 | 按 Actor 模板/历史是否渲染决定 | planningContext 有 openingMessage；专家与 Director 明确拼入；Orchestrator 的结构化输入未单独拼 openingMessage（它可能仍在历史） | [runtime:458–465](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L458)、[专家 sharedInput:213–236](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/memory/advisory.ts#L213)、[Director:363–393](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L363)、[Orchestrator:521–542](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L521) |
| 用户 Persona | userCustomPersona 进入 setvars；是否实际放进正文 prompt 取决于 Actor 模板；同时提取 axon.userPersona | 非空时传给各后台模型，最多4000字符，明确是用户而非角色，并要求不可未获剧情证明就写入持久状态 | [adapter:424–438](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L424)、[runtime:468](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L468)、[agentic:326–331](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L326) |
| 用户 query | 原输入/模板里的 question；可能与 history 宏配合避免重复最后一条 | inputQuestion ?? request.input 单列 LATEST USER QUERY；可能也出现在近期历史 | [adapter:374–386](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L374)、[render:705–711](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L705)、[runtime:467](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L467) |
| 原聊天历史 | 按 Actor PromptManager 渲染、模板窗口、消息合并、上下文限额裁剪；不是无限全史 | 默认/治理shadow：原 requestContext.messages；组装 transcript 只取非空 user/assistant 最后9条消息（不是9轮） | [adapter:700–784](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L700)、[runtime:402–404](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L402)、[transcript:303–315](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L303) |
| Compact | 若配置，Actor 使用 Compact 渲染后的摘要+保留历史，最终再计数 | 只有 contextGovernance=enforce 才使用 compactProjection.retainedHistory + summary；shadow 仍计划于原历史，投影仅对照观测 | [adapter:449–503](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L449)、[runtime:402–439](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L402)、[473–476](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L473) |
| persistent Agentic state | 读取开轮 snapshot，state+ledger 投影成 system 文本；缺失时 conservative fallback | 程序对象共享同一开轮 snapshot；模型拿6500字符投影，而非无损完整snapshot | [runtime:338–386](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L338)、[agentic:493–494](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L493)、[state编译:192–210](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/memory/advisory.ts#L192) |
| Director notes / context patch | 这条业务链没有独立 director_notes/contextPatch 字段。场景、软主线、镜头、agency等指导写在 state 文本各标题下 | Director 生成完整替换 state；后续轮 Actor 再读。未见“本轮先把新 Director notes patch 给正在生成的 Actor” | [state字段:37–61](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L37)、[Director输出:391–437](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L391)、[CAS:978–988](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L978) |
| 日记/表格等 memory | harness 先 recall；externalSetvars 进入 buildSetVars/模板，实际渲染取决于引用。items也被编译到通用compiledContext | planningContext 未接收 memory.items / externalSetvars；因此没有直接拿同一批日记/表格。可能通过已经形成的可见历史/state间接获知 | [harness:190–224](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L190)、[adapter:369–394](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L369)、[runtime:450–478](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L450) |
| 世界书 | 可选指定场景先 await select；选中 blocks 临时 decorate Actor 渲染消息；当轮生效 | 没有传入这些 blocks，规划历史取原始/Compact真实历史；不能说 audit_knowledge 已检查本轮入选世界书原文 | [worldbook:22–24](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/runtime.ts#L22)、[准备:351–355](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L351)、[Actor注入:618–621](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L618)、[planningHistory:402–404](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L402) |
| 可调用工具 | 普通正文 provider 请求没有 Agentic 专家工具；若启用前台loop，另一个控制LLM拿 actor/image/dio/over，Actor正文模型仍生成文字 | 第一次 Orchestrator 拿 enabledTools；专家无进一步工具选择；第二次 Orchestrator 只拿 update_director_state；Director无工具，输出候选文本 | [Actor请求:728–741](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L728)、[工具定义:86–124](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L86)、[agentic:803](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L803)、[873–895](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L873) |
| 本轮刚生成的回复 | 前台多次Actor会把已生成文字补到assistant历史继续；前台控制LLM收到Actor工具结果 | **没有**。schedule持有开轮历史；markActor只写观测节点，不重写 planningContext；当前回复只能待宿主保存并在未来请求历史中出现后可见 | [Actor续写:516–527](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L516)、[工具结果:666–678](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L666)、[schedule:563–605](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L563)、[markActor:275–285](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L275) |

附注：后台 PromptManager 宏渲染接口拿到 planningHistory，因此以上“9条”精确指内置 transcript 段。远端可配置 system 模板如主动引用历史宏可能包含更多内容；不能声称所有真实 provider prompt 总共绝不会超过9条历史的信息。[prompt-manager:163–183](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/prompt-manager.ts#L163)

## 3. 状态、所谓 patch、ledger 怎样进入下一轮

### 3.1 这条业务链实际没有“patch合并”协议

运行态保存 state 文本、revision/sourceTurn/sourceMessageId/historyRevision、toolsCalled、ledger。Director返回完整 candidateState；程序格式校验且内容有变化后，把完整 state + 新ledgerEntries 一起发CAS。原始专家建议不会直接改当前 Actor prompt。[snapshot类型](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/contracts.ts#L96)、[commit类型](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/contracts.ts#L107)、[提交](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L968)

如果图里要说“上下文更新”，可以写：**提交新状态 → 后续轮读取 → 编译为 Actor system 上下文**。不要借用其他SDK的 ContextPatch 机制来解释当前Emochi实现。

### 3.2 state 投影是文本裁剪，不是字段隔离

compileAgenticV2Context委托compileAgentCoreContext：

1. state先trim并截断到maxChars。
2. ledger只取status缺失或active的最近60条。
3. 接受event/knowledge/world/npc/callback/camera/agency七类，分组后每类最近6条。
4. 每条只取payload.analysis，或principle，或summary；每条最多900字符。
5. 拼在state后面，整体再次截断maxChars。state若已很长，会挤掉后面的ledger。
6. Actor调用上限是maxStateChars+2000（默认10000字符）；Orchestrator/专家/Director调用上限6500。程序对象虽有完整snapshot，后台模型不等于读到了完整无损state或所有ledger。
7. 没有按secret/hidden字段删除的步骤；普通Agentic state里的“知识边界/隐藏事实”仍可作为Actor控制文本。不能套用StoryV1的POV字段隔离描述。

证据：[state编译:192–210](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/memory/advisory.ts#L192)、[Actor:358–360](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L358)、[旧路径Actor:491–499](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L491)、[Planner:534](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L534)、[专家:224](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/memory/advisory.ts#L224)、[Director:377](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L377)。

### 3.3 ledger不是经机械证明的canon事实库

六类专家都标advisory only / never writes state。成功专家的result被存为analysis，带sourceTool/sourceTurn/userQuery；只有发生有效且有变化的Director提交时，才随CAS追加这些ledger；未选Director或unchanged时不追加。direct_scene还附一条固定agency原则。

它是“已持久化的专家分析/连续性记录”，可能含建议、推测、未来方向；不能逐条称为已在剧情发生的事实。Director提示要求只采纳可见历史或有效建议支持的变化，但代码校验主要是文本长度/标题顺序/内部标记/是否改变，不是对剧情真实性的证明，也未逐条核验ledger是否被Director采纳。[工具性质](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/modules/memory/advisory.ts#L31)、[ledger产生:741–772](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L741)、[校验:497–518](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L497)。

### 3.4 Actor投影的两个注入路径

- enforce治理或世界书存在：先读state、选世界书，state作为nonCompressibleSystemMessages交基础adapter；在Compact最终计数前插入，汇聚system后再decorate世界书。
- 默认/非enforce且未提前overlay：基础adapter先出Actor消息；coordinator插入state system，再把system合为一条首消息、保留最近连续对话窗口。
- shadow做观察性计数，不因此阻挡正文。enforce要求配置Compact，否则配置解析失败。

证据：[runtime:338–362](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L338)、[491–549](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L491)、[adapter:581–615](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L581)、[server:764–768](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/server.ts#L764)。

### 3.5 RPPromptCompiler不是当前Agentic状态注入点

它编译foundationBlocks + memory.items + 被projectTo的capability输出，按anchor/priority排序，得到foundation_context与turn_context。[compiler:33–80](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/prompt/compiler.ts#L33)

但当前ClosedLoopRoleplayRuntime实际provider消息来自options.axon.history。PreparedKaonRouter直接发送其构造参数里已准备好的request.messages，不自动把传来的compiledContext再拼一遍。记忆主要经externalSetvars/Actor模板注入，Agentic state经上述coordinator/adapter注入。不可因为compiler里有memoryBlocks就推断“所有memory.items一定自动出现在Actor prompt”。另一个ChatKernel adapter才显式把这些anchors映射为harnessFoundationContext/harnessTurnContext。
证据：[正文构造:728–741](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L728)、[实际请求body:416–423](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/llm/src/routers/kaon.ts#L416)、[ChatKernel映射:99–114](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/chat-kernel-runtime.ts#L99)。

## 4. 每一轮怎么执行，何时生效

上下文组装归属还要按入口分开：非closed-loop入口（根任务核查称v1）使用chat-service:precompiled；PreparedKaonRouter发送上游已经组好的request.messages，Harness里的ChatServiceOwnedMemoryRuntime为空操作，注释明确日记/表格前后hooks由chat-service负责。closed-loop入口（v2）才走本报告描述的Harness buildSetVars、PromptManager渲染、预算与Agentic叠加。不能把v1“上游workflow已做过什么”推测成v2每轮又完整重复做一遍。证据：[入口分支:1256–1291](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1256)、[memory归属:1244–1253](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1244)。

召回但模板未引用某记忆变量时，普通宏路径不会仅因memory.items中有它就强制追加该记忆；代码分别记录recalled和rendered，后者要求实际trackedMessages.sourceVariables出现对应变量。需注意hook可能再转换变量，因此这是当前模板直接渲染的追踪逻辑，不是对任意间接文本来源的完备证明。证据：[rendered追踪:527–533](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L527)。

1. 场景配置确定应用分支和组件；closed-loop memory.recall先执行。
2. 准备角色和Actor模板；加载开轮state/fallback；如世界书则先选择；基础adapter准备Actor消息；建立planningContext。
3. 准备期间还会加载/渲染后台Orchestrator、全部六专家、Director的配置模板。它们不是此时就都推理，但这些准备读取在正文开始前，因此配置读取/缺失失败可能阻止当轮，不能说所有慢系统问题都完全不影响首字。[prompt-manager:186–245](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/prompt-manager.ts#L186)、[runtime:442–478](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L442)
4. 进入AgenticV2RoleplayRuntime.generate：schedule一次后台任务，立即执行原Actor（可能是前台工具loop）。
5. 后台第一次Orchestrator总会尝试推理；常规续聊可以返回no tool，结束并保留旧state。不存在“先免费判断X轮，再决定是否调用Orchestrator”的代码。
6. 如果选了专家，执行受预算约束的一批并行专家；然后最多一轮第二阶段Orchestrator决定Director；Director也可在无专家时直接被第一阶段选择。
7. Director生成完整候选；校验、比较、CAS。有效且有变化才消费新revision；否则retained/unchanged/invalid/failed/stale_write_rejected。
8. 当轮Actor继续使用准备好的旧snapshot，不热更新。后台可能早于或晚于正文完成；不等待宿主存Actor回复。**“下轮生效”更准确是“后续轮准备时已读到该提交才生效”**，不保证紧接下一条用户消息必定赶上。
9. 正文完成后harness await memory.ingest；日记/表格是另一套后处理。Axon Go会安排日记，表格有background runner时安排后返回、无runner才同步await保存。因此不能把“memory.ingest被await”直接等同“必须等日记保存”或“所有记忆无条件后台”。[harness:332–361](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L332)、[Go memory:151–159](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/axon-memory-runtime.ts#L151)

sourceTurn计数取本地用户消息数，或与ceil(conversationLength/2)取较大值；用于开轮标记/首轮判断/CAS关联，不是“每X轮”的周期计数器。[runtime:197–209](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L197)

## 5. 工具选择、硬规则、Director、预算

- 可选专家：analyze_plot剧情、judge_npc人物连续性、audit_knowledge知识边界、simulate_world世界活动、manage_callbacks伏笔/承诺、direct_scene镜头/角色自主性。都是模型分析调用，不是天然数据库动作。
- 默认工具全部启用；maxToolCalls=7，maxParallelTools=6，maxStateChars=8000，modelCallTimeoutMs=180000；第一批执行上限min(7,6)=6，再可能Director。
- 首轮强制judge_npc + direct_scene（对应工具启用时）；近4条可见消息+query由多语正则识别到state未包含的新名字时，强制judge_npc。不是任意姓名理解的完备语义检测。
- 有required audit且state工具启用时，第二阶段会强制update_director_state；其他轮Director可不调用。即便调用也可能不提交。
- routingMode=manual并不表示人工审批，只是不自动升级到escalationModel；auto模式达到工具调用数阈值（默认3）时可用升级模型重做路由。不是快正文升级为慢任务。
- manual和auto都会让Orchestrator输出结构化tool_calls并由程序分发；它与选择scenario/入口版本是不同层次。auto第一阶段升级后，第二阶段先回到默认Orchestrator，若该阶段也达到阈值再升级；测试直接验证fast→quality→专家→fast→Director。[模型选择测试:724–769](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L724)
- 配置字段解析在server.ts:109–227；没有累计X轮/每N轮触发字段。Long-horizon outline (10–20 user turns)是状态内容的计划跨度，不是后台触发间隔；最近9条是上下文窗口，也不是触发间隔。

证据：[默认配置:208–235](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L208)、[规则:638–702](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L638)、[一阶段:803–869](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L803)、[二阶段:873–925](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L873)、[解析](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/server.ts#L109)。

## 6. CAS、失败、取消的业务后果

| 情况 | 当前实现 |
|---|---|
| 专家建议 | 不直接写state；结果交第二Orchestrator/Director |
| Director输出无效/未变化 | 不提交；保持原revision |
| CAS版本冲突 | 此次规划终止为stale_write_rejected，不读取新state重新规划，不覆盖别人较新写入 |
| 模型或保存瞬时失败 | 默认最多2次重试，即最多3次尝试；取消、特定恢复/治理错误会停止重试 |
| CAS响应不明确后重试遇冲突 | 读回核对revision=expected+1、sourceMessageId与state都相同，才认定前次其实已成功；竞争writer则仍拒绝 |
| 已调度后台规划失败 | planner返回failed report，Actor无需等待该结果；观测写失败也不阻塞正文 |
| Actor用户取消/断开/正文失败 | **不会自动取消已调度Agentic后台**：schedule没有传parentSignal；测试明确后台signal仍未abort。因此仍可能在之后产出有效候选并尝试CAS，最终成功取决于服务CAS约束 |
| 服务关闭 | BackgroundTaskRunner.abort会取消后台signal |
| 整个后台时限 | 这里schedule(timeoutMs=undefined)，没有900秒整条任务定时器；900是planning状态观测字段；单个模型调用配置默认180秒 |

证据：[重试与歧义确认:102–162](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L102)、[提交结果:968–1052](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L968)、[调度:571–621](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L571)、[BackgroundTaskRunner:23–74](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/tasks.ts#L23)、[shutdown:90–92](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/tasks.ts#L90)、[取消断言:1922–1940](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1922)。

这里描述的是Emochi业务包装器；不能把它写成通用SDK“用户取消后slow必定继续”的统一协议。仓库外Axon负责CAS最终语义，本报告不把本地客户端的注释当作服务端实现证明。

## 7. 前台 preActorDirector function loop 的真实接线

当前dispatch有preActorDirector配置就组装functionLoop并传ClosedLoopRoleplayRuntime；普通AgenticV2包装仍可同时装上，二者不是互斥。[dispatch:929–935](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L929)、[1110–1164](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1110)

- 前台控制LLM第一步只拿控制system说明+用户原输入；没有直接拿角色、全历史、state、memory、worldbook。后续拿本轮Actor返回的text和token用量、图片调度结果、DIO接收结果。它因此能根据本轮刚生成片段继续决策。
- actor调用复用已准备好的Actor消息；续段追加已生成assistant文字和续写指令。所有段共享同一整轮输出token预算。
- generate_image先放占位并调用独立图片任务调度。visual_beat成功且句子完整时，代码会在下一次Planner决策前自动调图，避免全靠模型记得调用。
- schedule_dio仅语义明确要求持久修改角色/世界/风格等时选择（工具描述引导）；Harness机械限制每轮成功接收一次。前台await接收，不await完成；独立background等待终态，结果只可能供后续轮加载。**这不是转交给AgenticV2的Director工具。**
- over前至少完成Actor一次。最多12步，有DIO能力时13步；若无有效Actor结果，回落普通generateOnce；若已有片段，部分后续错误可保留已完成片段。
- 文件tools/pre-actor-director.ts还保留“选择一个skill并返回Actor参数”的hook函数，但本次全仓引用仅函数自身及测试，当前dispatch实际使用的是上述functionLoop。不要把这个辅助API的测试误当当前业务调用链。

证据：[前台输入与限制:329–349](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L329)、[模型调用:401–411](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L401)、[DIO:458–480](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L458)、[续段:516–558](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L516)、[反馈:666–710](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L666)、[外部DIO调度:938–965](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L938)、[辅助hook](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/tools/pre-actor-director.ts#L123)。

## 8. 当前世界书场景实际配置，及能力边界

config/scenarios/agentic-v2-worldbook.json：memorySources=[]，worldbook hybrid / 2400 token，AgenticV2 manual，7工具预算/6并发/8000状态字符/180秒单调用；没有compact或contextGovernance。它不说明整个产品都关闭memory，也不证明线上当前启用该文件。[配置:1–36](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/config/scenarios/agentic-v2-worldbook.json#L1)

该文件确实写actorControlEnabled=true，但当前AgenticV2Config类型没有此字段，parseAgenticV2Config也没有读取，全仓TS无引用。因此它是本基线未消费的配置字段，不能当作有效功能开关证据。[类型:180–201](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L180)、[解析:214–227](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/server.ts#L214)

世界书场景限制agentic-v2-worldbook身份、必须AgenticV2、不能preActorDirector/Story/Sumi；这是世界书专用限制，不等于普通前台loop与AgenticV2互斥。[server:747–758](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/server.ts#L747)

业务后果：Actor本轮可引用所选世界书设定，但后台专家没有直接得到同一份原文来审查一致性；世界书内容若被Actor写入真实历史，下一轮后台才可能间接看到这些文字。不能把图画成“世界书→所有专家→验证后再让Actor说话”。

## 9. 阅读到的测试证据（本次未运行）

| 测试与断言 | 证明范围 |
|---|---|
| [agentic-v2.test:192–219](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L192) | 普通续聊仍调用1次Orchestrator；无工具、无提交、revision不变 |
| [246–270](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L246) | Orchestrator失败最多再试2次 |
| [338–407](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L338) | 新名字立即NPC审计；首轮专家拿到开场白 |
| [515–577](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L515) | 专家→第二Orchestrator→Director→CAS，不等Actor持久化；Director输入快照精确断言 |
| [580–679](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L580) | 保存失败重试、冲突不反复重试、歧义成功读回确认/竞争写拒绝 |
| [1699–1761](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1699) | 保留Actor原prompt控制；开轮state只读一次；后台并行；所有后台模型收到用户Persona；本轮新Actor文字不在Planner输入 |
| [1831–1835](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1831) | CAS冲突后不重跑/覆盖 |
| [1922–1940](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1922) | Actor取消不取消后台signal；此用例候选无效而未写，不证明所有取消案例都不写 |
| [1993–2122](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1993) | enforce把state纳入Compact且只注入一次；Planner使用摘要+保留history，不再使用raw旧史 |
| [2124](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L2124) | shadow保持Actor字节与观测计数行为 |
| [114–132](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L114) | ledger最新窗口与active过滤 |
| [roleplay-runtime.test:919](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/roleplay-runtime.test.ts#L919) | 前台Planner无工具时回落原Actor |
| [955–1064](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/roleplay-runtime.test.ts#L955) | DIO只接受一次，不改本轮Actor prompt；DIO提交失败正文仍成功 |
| [1068](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/roleplay-runtime.test.ts#L1068)、[1200](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/roleplay-runtime.test.ts#L1200) | 前台多Actor与图片交错、预算报告、visual_beat自动图片 |
| [worldbook.test:69–98](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/worldbook.test.ts#L69) | 当轮选择缓存；隐藏state不作为query；插入不改canonical历史 |
| [roleplay-runtime.test:2037–2063](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/roleplay-runtime.test.ts#L2037) | 重试复用世界书选择；必需prompt超预算在provider前拒绝 |

## 10. 给PM的说法

用户发一句话后，系统先把角色、历史和已保存的“剧情工作笔记”准备好。正文Actor拿这份材料开始写；配置了AgenticV2时，旁边也有一个规划员拿同一个时间点的材料检查：这句新输入是否需要查人物、知识、伏笔或推进计划。

规划员每轮会先看一次，但多数普通续聊可以什么专家都不叫。需要时叫几个专家并行提建议，再决定是否请Director改整份工作笔记。提交成功也不会插进已经开始生成的正文；后续回复准备时读到了，才生效。

如果启用了前台工具控制器，它是另一位“这次回复的编排员”：先写一段、安排插图、再写下一段，也能提交用户明确要求的长期设定修改。它能看到这次刚写出的段落；后台剧情规划员看的是开轮快照。世界书则是给当轮正文的外部设定材料，当前没有直接把同一批材料送给后台专家。


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