# Agent Module Rules

## 适用范围
适用于 `src/host/agent/`。本文件定义 agent 模块特有的稳定治理边界；通用规范遵循根 `AGENTS.md`，测试规范遵循 `tests/AGENTS.md`。

本文件描述治理原则，不是源码结构说明。文件移动、重命名或内部重构后，只要职责、状态所有权、生命周期与依赖边界未变，本文件不随之修改。

## 核心职责
治理「一个角色节点 ⇄ 一个可延续子代理」这一执行单元，并承担父代理会话能力的宿主适配：

- 把节点配置（角色 Prompt、provider/model/思考强度、工具白名单、两开关、协作 Prompt）确定性翻译为官方子代理运行时的创建参数；
- 创建/复用节点子代理，并把本轮任务块投递进去（创建即推理，不等待完成）；
- 在该子代理作用域内注入 Agent 语义（角色提示词段、工具可见性、模型选择、ReAct 软截停）；
- 为编排层与工具层提供父代理会话宿主能力（取根/子 Agent、followup、回合终态与会话事件读取、子代理存活判定）。

判断归属：该修改是否改变「节点 → 子代理」的创建/复用/投递/作用域装配语义，或改变本模块对官方 Agent / Subagent 能力的适配契约？若主要属于其他领域，应放到对应模块。

## 非职责
- 不拥有 Workflow Run 与节点状态：运行锁、快照、节点完成/失败/react-capped 判定、阻塞等待唤醒均属编排运行时；
- 不做 Agent 语义判断：是否重规划、是否汇报、是否改图、是否更换执行策略；
- 不实现 Tool 注册、Schema、工具可见性协议与调用方身份派生；
- 不直接读写工作流/运行持久化数据（可经注入的存储缝读取定义，写入归 storage）；
- 不管理官方 Agent / 子代理会话生命周期（创建与销毁由官方服务与宿主负责）。

## 依赖边界
允许：
- 官方能力仅经 `ctx.get()` / 注入缝**运行时解析**，并以本模块自带的最小结构守卫收窄；只允许 `import type` 官方纯类型（如 `Context`）；
- 编排模块仅允许**类型**导入其公共入口（`NodeRunner` / `AgentHost` / `NodeStartInput` 等契约缝）；本模块不得成为编排器的运行时依赖；
- 存储仅类型与读取缝；图模型仅纯函数事实推导；shared 仅共享类型与协议常量；Node 内置模块（fs / async_hooks）。

禁止：
- 依赖 tools / remote / service / scheduler / client（任何形式，含类型）；
- 新增 `@deepseek-ai/*` 运行时 import 或写入 `dependencies`；
- 新增跨模块能力时绕过宿主注入、直接 import 其他模块的实现类型；
- 让编排器或工具层直接持有本模块内部状态对象。

**官方适配必须可追溯**：改官方 seam 适配时，注释中必须写明包名与符号、取证结论（含版本差异）、失效或缺失时的降级路径与后果。不得凭记忆或推断编写官方契约。

## 状态所有权
本模块拥有的状态：
- 子代理复用表（复用键 → childId + 配置签名）与已创建 child 集合；
- 软截停护栏的按 child 迭代上限、回合计数与已触达标记。

不属于本模块：
- 子代理 Agent 与会话状态（官方）；运行与节点状态（编排器）；
- **每子代理作用域装配的生命周期（安装与撤销）归宿主层**：本模块只提供「贡献」，由宿主在子代理创建窗口内安装、在子代理处置或宿主卸载时撤销。本模块不得自建第二套作用域撤销表。

规则：
- 模块外只能经公开方法/事件请求变化，不得直接修改内部表；
- 新增按 child / 会话维度持有的状态必须定义释放条件；生命周期长于「单次子代理运行」的表必须有明确上界与回收路径，不允许只增不减；
- 同一事实只能有一个写入边界：子代理归属、迭代上限、软截停标记各自只有一处写入者。

## 生命周期
执行单元生命周期：创建 → 复用派发 → 进行中（不等待）→ 结束/失败/中断 → 清理（宿主统一）。

必须保证：
- **复用由配置签名决定**：签名必须覆盖一切影响子代理组成的输入（角色 Prompt 实际注入文本、provider/model/思考强度、工具清单、preset、两个提示词开关、协作 Prompt）。新增影响组成的配置而不纳入签名，等于旧子代理被静默复用。
- **首次创建必须注入完整任务块**作为首条 prompt，不得依赖后续消息补齐上下文。
- 创建/复用路径**不得等待子代理完成**；完成事实只经官方事件观察，由编排层回写。
- 任何影响「本回合第一个 pre-step」的登记（如迭代上限）必须在创建/派发**之前同步完成**，不得置于 `await` 之后。
- 中断是**尽力而为**：目标不存在或已停止视为成功；调用方不得依赖中断同步生效。
- **重建子代理时，旧子代理的处置语义必须明确**（保留/中断/归属回收），并在注释中说明其事件对节点结论的影响；不得让旧子代理的事件静默影响新子代理。
- 新增监听器、定时器、等待器、订阅必须有释放路径；清理必须幂等，且不得因单个取消失败而中断整体清理。

## 并发与异步
- 子代理**创建/复用是跨 `await` 的 check-then-act**：当前正确性依赖调用方串行化（官方工具调度默认 exclusive + 运行锁）。一旦出现并发启动路径（并行工具调用、并发 API 请求、多宿主装配），必须在此处补进行中去重，并在成功/失败/取消路径清理登记。
- 去重、waiter 注册时机、事件先后假设都属隐含契约：新增必须在注释中写明「谁先谁后、失败怎么处理」。
- 不得依赖 `sleep` 或宏任务顺序保证正确性；若确实依赖官方事件顺序，必须写明取证结论。
- 取消信号必须沿创建/派发/中断传播；吞掉取消不得伪装成成功。
- 面向官方事件的守卫必须按结构判定并容忍未知形状（形状漂移时降级而非抛错），但**降级方向必须与业务语义一致**（例如存活判定失败保守视为仍在运行）。

## 公共接口
- 对外契约有两类：节点执行能力（`NodeRunner`）与父代理会话宿主能力（`AgentHost`）；实现由宿主装配，接口归编排模块。
- 修改公共契约必须同步检查：宿主装配点、测试夹具、编排模块的依赖缝。
- **面向模型的文本是对外契约**：软截停指令、工具拒绝原因、兜底任务 prompt、提示词段名与顺序都属契约文本，改动必须说明理由，不得出于措辞偏好调整。
- 注入官方消息流的任何内容必须满足官方消息契约（role / content / source 全字段合法），来源归属必须写真实插件名，不得缺字段。
- 工具白名单是对外安全边界：父代理专属工具的隐藏必须是「白名单永不包含 + 作用域显式拒绝」双线。

## 副作用边界
允许的副作用：创建/派发/中断子代理、注册与撤销官方作用域贡献、读取角色 Prompt 文件、读取工作流定义（db-in 连线判定）、向官方消息流注入内容。

- IO 必须 best-effort 且有明确降级：角色 Prompt 文件不可读 → 回退内联文本；连线读取失败 → 按无连线处理；护栏工具拒绝线注册失败 → 保留消息替换线。
- 降级只能降在辅助路径上：环境缺失（服务不可用、父代理未激活、provider 缺失）必须抛可行动错误，不得静默变成「不带工具/不带护栏」的错误行为。
- 副作用不得隐藏在看似纯的函数中：复用键与签名构造、provider 选择、段过滤判定必须保持纯函数。

## 纯函数边界
复用键、配置签名、provider 首选序、提示词段保留判定、软截停计步判定等确定性逻辑必须为纯函数：相同输入相同输出、不修改输入、不读全局可变状态与时间/文件/网络。

经注入的 view/store/service 求值逻辑（白名单解析、连线判定、事件流读取）不属于纯函数：它们不得直接 import 具体服务实现，只能消费注入的最小结构缝。

## 错误处理
- 错误信息必须可行动：说明缺什么、当前状态、如何恢复（例如「请先在对话区发送一条消息后重试」）。
- 区分「运行语义失败」与「best-effort 辅助失败」：前者不得吞掉或伪装成功，后者必须有注释标注降级链。
- 护栏类失败不得静默失效：单线失效时另一线必须在（消息替换线失败仍保留工具拒绝线，反之亦然）。
- 官方 payload 形状漂移（版本升级）按运行时守卫收窄并降级，不因未知字段抛错；但**降级后仍必须保持业务语义**，且必须在注释中写下取证结论。

## 模块内部组织
- 文件结构不是架构契约。禁止因文件长、函数多、import 多而拆分。
- 拆分依据只能是：职责、变化原因、依赖边界、测试边界（例如：官方服务契约适配 / 子代理执行与复用 / 声明式作用域注入 / 会话事件读取）。
- 不得创建 `utils.ts`、`helpers.ts`、`common.ts`、`shared.ts`、`misc.ts` 等无明确职责的聚合文件；跨职责共享的常量放 `shared/` 的协议契约。
- 不得通过继承层扩展职责；新增能力优先组合与最小接口注入。

## 修改前检查清单
1. 改动属于「节点 → 子代理执行/官方适配」还是其他模块？
2. 是否改变复用签名的组成？签名与测试是否同步？
3. 是否改变作用域装配的安装/撤销或子代理归属？宿主层是否需要同步？
4. 是否改变面向模型的文本、工具白名单或官方消息 payload？
5. 是否新增按 child/会话维度的状态、监听器、定时器？释放路径在哪、上界是什么？
6. 是否引入新的官方能力依赖或版本分支？取证与降级是否写明？
7. 是否引入跨 `await` 的 check-then-act 或并发路径？去重策略是什么？

## 验证
至少执行：

```text
pnpm typecheck
pnpm test          # 至少覆盖 tests/host/agent/ 与 tests/integration/
pnpm build         # 涉及官方适配、宿主装配或产物契约时必需
```

同时确认：无旧路径残留、无新增反向/循环依赖、复用签名与作用域装配测试同步、无未声明行为变化、面向模型文本与白名单未意外改变。

## 核心原则
1. 节点配置确定性映射为官方子代理调用。
2. 复用由签名决定，签名必须完整。
3. 作用域装配的生命周期归宿主，模块不私建撤销表。
4. 创建即推理、不等待完成，完成只经事件观察。
5. 官方能力零运行时类型依赖，适配必须取证可追溯。
6. 每子代理状态必须有释放条件与上界。
7. 重要副作用显式声明，best-effort 必须写明降级链。
8. 面向模型的文本、工具白名单与官方消息 payload 是对外契约。
9. 文件结构可重构，治理边界不可突破。