@@ -4,7 +4,7 @@
Agent 接口、注册表、进程本地发起方作用域,以及 `agent/*` 事件词汇。每个插件( UI、钩子、编排器) 都面向此处定义的 `Agent` handle 编程;它不依赖循环,因此循环可以替换。
可选配套包( package) `@deepseek-ai/dsh-agent/invariant` 会向 `ctx.invariants` 注册此包的 agent( 智能体) 状态转换检查。根 agent 服务不会隐式加载诊断。
可选配套包`@deepseek-ai/dsh-agent/invariant` 会向 `ctx.invariants` 注册此包的 agent( 智能体) 状态转换检查。根 agent 服务不会隐式加载诊断。
## 服务:`AgentRegistry`( ctx 键:`agents`)
@@ -14,7 +14,7 @@ Agent 接口、注册表、进程本地发起方作用域,以及 `agent/*` 事
带作用域的注册接口:`Agent.ctx` 是 agent 的作用域上下文(`dsh-scope` ,键 = 该 agent) 。通过它注册工具/ 段/ 变量/ 监听器, 只对该 agent 生效,并在 dispose( 资源释放) 时全部撤销。`agentEvents(ctx, agent)` 是普通 agent 主体操作的融合分发器(一次完成载体 + 注入主体);其通知 mode 会调用每个监听器,并同时收容同步抛出和返回 Promise 的拒绝。注册表生命周期对复用一个稳定路由载体。`assembleContextFor(agent)` 构建可用于检查的逐 agent 组装上下文(同时包含 `agent` + `scope` ),而 `assembleRequestContextFor(agent)` 还会将组装标记为其结果将由调用方物化为下一个模型请求。`installAgentLlmTarget(agentCtx, target)` 在提示词组装期间快照可变的提供方/ 模型/ 推理( reasoning) 强度选择, 将路由应用到提示词变量, 并将完整目标应用到一个步骤的请求路由; 如果没有选定推理强度, 则会清除继承的推理强度, 使该目标使用适配器/ 提供方默认值。`CreateAgentOptions.setup(agentCtx)` 和 `ResumeAgentOptions.setup(agentCtx)` 在新建或恢复的 agent 尚未发布时, 组合其带作用域的世界。Setup 可以返回一个 `AgentSetupCommit` ;所有 setup 的 await 均结算后,工厂会在进入注册表前立即调用其同步 `commit()` ,若其抛出异常,则回滚私有事务且不发布任何一个 id。Setup 仍是受信任、仅用于组合的同进程代码:只有创建完成后才能驱动 agent。
`AgentOptions` 提供初始的提供方/模型路由,以及可选的正数 `maxTokens` 输出上限。实 体循环会解析确切模型的适配器默认值,把生效上限记录到请求 header, 并应用到每次对话模型请求; 显式 Agent 选项优先,省略时由适配器或提供方路由默认值控制。
`AgentOptions` 提供初始的提供方/模型路由,以及可选的正数 `maxTokens` 输出上限。具 体循环会解析确切模型的适配器默认值,把生效上限记录到请求 header, 并应用到每次对话模型请求; 显式 Agent 选项优先,省略时由适配器或提供方路由默认值控制。
- `ctx.agents.register(agent: Agent): () => void` :记录一个 **已经构造完成 ** 的 agent。随调用 fiber dispose。
- 高级有序生命周期:`enter(agent, owner): () => void` 强制 `agent.id === agent.session.id` ,执行权威 ID 冲突检查,并在不通知的情况下插入;`owner` 显式记录实时创建方 agent 关系(根 agent 为 `undefined` ),与持久会话谱系无关。`announce(agent)` 恰好发出一次 `agent/created` 。创建监听器同步请求的 detach 会延后到该次分发结束;每次 detach 都会检查捕获的条目对象,因此陈旧能力无法删除后续使用同一 ID 的替代项。异步工厂使用这一拆分;普通插件使用 `register()` 。
@@ -36,7 +36,7 @@ Agent 接口、注册表、进程本地发起方作用域,以及 `agent/*` 事
#### 工厂 seam( 创建)
Agent * 创建 * 由实现 `AgentFactory` 的插件(`dsh-agent-loop` )提供,并通过 `setFactory` 注册。这样,创建功能留在 `dsh-agent` 接口上, 消费方( UI、ACP 桥接层)可以面向 `ctx.agents` 编程,而不依赖具体循环包。注册表会把已经 traced 的 Service 规范化为具体目标,并通过调用方上下文重新 trace 每次调用;这既避免嵌套 Cordis shadow, 也会把显式、绑定调用方的 `ownerCtx` 传给普通工厂。
Agent * 创建 * 由实现 `AgentFactory` 的插件(`dsh-agent-loop` )提供,并通过 `setFactory` 注册。这样,创建功能留在 `dsh-agent` 接口上, 消费方( UI、ACP( Agent Client Protocol) 桥接层)可以面向 `ctx.agents` 编程,而不依赖具体循环包。注册表会把已经 traced 的 Service 规范化为具体目标,并通过调用方上下文重新 trace 每次调用;这既避免嵌套 Cordis shadow, 也会把显式、绑定调用方的 `ownerCtx` 传给普通工厂。
- `ctx.agents.setFactory(factory: AgentFactory): () => void` : 注册创建工厂( 循环在构造时调用) 。第二个工厂会导致抛出; dispose 时清空槽位。
- `ctx.agents.create(options: CreateAgentOptions): Promise<AgentHandle>` :创建会话和 agent, 在不发布的情况下等待可选 setup, 调用其可选的同步提交, 然后通过最终的 `SessionStore.enter()` 与 `AgentRegistry.enter()` 检查发布。不支持并发创建同一 ID: 多个操作可以进行准备, 但只有一个能进入; 每个失败方都会回滚其私有作用域/ 会话/ 驱动器。可选且只用于创建的 `signal` 会取消未发布的 setup, 并在返回 handle 前分离;之后的取消使用 `handle.dispose()` 或 `agent.cancel()` 。发布包含在回滚范围内,回滚期间每条已交付创建边都会成对处理。未注册工厂时拒绝。
@@ -50,7 +50,7 @@ Agent *创建* 由实现 `AgentFactory` 的插件(`dsh-agent-loop`)提供,
生命周期边有两个重要的本地注意事项。`agent/created` 在作用域 setup 之后、会话与 agent 注册表条目都存在之后运行。Setup 是受信任、仅用于组合的代码;紧随其后且不可 veto 的 `agent/session-start` 通知是第一个受支持的启动注入点。`agent/disposed` 始终表示确切 agent 已离开注册表。AgentLoop 在其驱动器完全停稳后发出该事件,而有序 teardown 此时可能仍在分离会话并撤销作用域;直接注册的自定义 agent 自行拥有任何更强的驱动器顺序契约。
大多数拦截点都是协作式 waterfall( 瀑布式事件) 。轮次作用域的异步 seam 接收一个显式 `AbortSignal` ,其中 `signal` 紧邻 waterfall 最终的 `next` ;监听器可以配合,但不得将它保留为控制另一轮次的权限。`agent/step` 是派生请求前的串行检查点,而 `agent/request-error` 是失败模型请求的恢复 waterfall: 失败步骤关闭后, 它接收确切错误、规范化失败事实和信号。拥有恢复权的监听器返回 `{ kind: 'retry' }` 且不调用 `next()` ;循环会关闭失败轮次,并打开一个编号重试轮次。`agent/turn-stopping` 在本可完成的轮次关闭前运行。普通排队提示词保持原样。有效的广义取消会先发出只观测的 `agent/cancel-requested` 及其解析后的类型化原因,再清空队列并中止;通知失败会被收容,不能 veto 停止。信号生命周期由[显式取消决策 ](../../../.agents/notes/implemented/architecture/2026-07-16-explicit-turn-cancellation.md )拥有;作用域分发与终止结算由 [agent 作用域 runtime 设计 Agent Note( agent 决策记录) ](../../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way )拥有。
大多数拦截点都是协作式 waterfall( 瀑布式事件) 。轮次作用域的异步 seam 接收一个显式 `AbortSignal` ,其中 `signal` 紧接在 waterfall 最终的 `next` 之前 ;监听器可以配合,但不得将它保留为控制另一轮次的权限。`agent/step` 是派生请求前的串行检查点,而 `agent/request-error` 是失败模型请求的恢复 waterfall: 失败步骤关闭后, 它接收确切错误、规范化失败事实和信号。拥有恢复权的监听器返回 `{ kind: 'retry' }` 且不调用 `next()` ;循环会关闭失败轮次,并打开一个编号重试轮次。`agent/turn-stopping` 在本可完成的轮次关闭前运行。普通排队提示词保持原样。有效的广义取消会先发出只观测的 `agent/cancel-requested` 及其解析后的类型化原因,再清空队列并中止;通知失败会被收容,不能 veto 停止。信号生命周期由[显式取消决策 ](../../../.agents/notes/implemented/architecture/2026-07-16-explicit-turn-cancellation.md )拥有;作用域分发与终止结算由 [agent 作用域运行时 设计 Agent Note ](../../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#three-execution-boundaries-are-deliberately-one-way )拥有。
`PromptDecision.additionalContexts` 是由带标识且冻结的 `UserMessage` 值组成的数组,因此每个上下文都保留自己的标识和来源。获准的提示词与每个附加上下文都会在轮次运行前成为各自独立、面向模型的 `user/message` 事件。包装下游允许决策的监听器会保留其 `content` 与 `additionalContexts` ,除非有意替换任一字段;替换获准内容时仍会保留提示词的标识。
@@ -64,7 +64,7 @@ Agent *创建* 由实现 `AgentFactory` 的插件(`dsh-agent-loop`)提供,
- `agent.reserveTurnAdmission()` :在任何已排队唤醒提示词认领其轮次之前,同步预留空闲边界。已获接纳的提示词拥有优先权,包括同一 tick 内仍在等待唤醒的项,此时预留返回 `undefined` 。预留期间,之后发送的项保留其普通 ID、FIFO 位置与唤醒信息;`acceptsNextStep` 保持 false, `inject()` 不受阻塞,`whenIdle()` 将该预留计为活动, 返回的释放函数可幂等调用。这项范围有限的协调能力使手动压缩( compaction) 等独立持久操作能够在排队提示词从会话派生内容前完成并 flush。
- `agent.updateInbox(itemId, action)` :同步编辑、移除一个仍处于待处理状态的 queued 入队项,或对其执行严格 steering。编辑会替换已冻结的内容, 同时保留其 `MessageId` 、`InboxItemId` 、来源与 FIFO 位置;移除会发出该项的终态 discard。严格 steering 要求 `acceptsNextStep` 为 true; 它会结束 queued 单次入队项,并把同一条不可变消息接受为新的 steering 单次入队项,后者使用新的 `InboxItemId` 。窗口关闭时返回 `steer-unavailable` ,且不做任何变更。待处理 steering 和已被认领的项会返回 `not-found` 。
- `agent.followup(input)` : `send()` 的 `next-turn` / wakeup 预设:排队一个普通后续轮次并唤醒驱动器。
- `agent.steer(input)` : `next-step` / wakeup 预设:提交一条已有标识的消息,并取得其 `SteeringReceipt` 。提示词接纳期间或轮次打开时,消息会为下一个安全请求边界暂存,且不分发 `agent/prompt-submit` ;该接收窗口之外则成为会唤醒驱动器的排队提示词。只有循环记录消息、将其捕获到不可变请求历史并提交 `step/start` 后,`receipt.outcome` 才会解析为 `admitted` , 并附带轮次与步骤。结束轮次的工具结果、广义取消、dispose(资源释放) 或准入前故障会使其解析为 `rejected` ; `cancel(..., { keepInbox: true })` 和非终止型路由会保留待处理投递。需要可靠投递的调用方应等待回执;尽力执行的 UI steering 可以忽略它。
- `agent.steer(input)` : `next-step` / wakeup 预设:提交一条已有标识的消息,并取得其 `SteeringReceipt` 。提示词接纳期间或轮次打开时,消息会为下一个安全请求边界暂存,且不分发 `agent/prompt-submit` ;该接收窗口之外则成为会唤醒驱动器的排队提示词。只有循环记录消息、将其捕获到不可变请求历史并提交 `step/start` 后,`receipt.outcome` 才会解析为 `admitted` , 并附带轮次与步骤。结束轮次的工具结果、广义取消、dispose 或准入前故障会使其解析为 `rejected` ; `cancel(..., { keepInbox: true })` 和非终止型路由会保留待处理投递。需要可靠投递的调用方应等待回执;尽力执行的 UI steering 可以忽略它。
- `agent.inject(input)` : `next-step` /不唤醒预设:追加面向模型的上下文而不运行模型;下一次请求会看到一条逐字的 user role 消息,其来源由必填的 `input.source` 携带。提示词接纳期间或轮次打开时,注入会在 outbox 中等待下一个安全边界。该接收窗口之外,它会立即追加而不开启轮次;如果接纳结束却未开启轮次,仅含上下文的接纳批次会采用这一回退,而与 steering 一同暂存的上下文则会随其继续待处理。持久化独立地响应 `session/event` 。注入不发出 `agent/inbox/*` 事件。
- `agent.acceptsNextStep` :当前发送 `next-step` 时,是否会加入提示词接纳或已打开的轮次。当调用方必须在 steering 与新接纳的提示词之间选择时,应使用这一更窄的路由判定;`status === 'running'` 还涵盖接纳收尾与轮次结算阶段。
- `agent.cancel(cause, options?)` :取消活动轮次,并在未设置 `options.keepInbox` 时取消全部待处理工作。调用方必须显式选择 `user | parent` 原因;活动持有者会在中止前把其判别字段复制为已分离、冻结的信号原因。有效调用会在清除排队与 steering 工作前,随原因发出 `agent/cancel-requested` ;丢弃项在 `agent/inbox/discard` 上报告,观察方可以同步状态,但不能 veto 取消。`keepInbox: true` 会中止轮次,但保留排队与 steering 项(不丢弃,且不删除尚未开始的工作)。同进程类型化 seam 不会为无类型调用方添加运行时校验或兼容回退。重复取消活动轮次时, 首个信号生效; 空闲取消是安全空操作, 不发通知。ACP 映射到 `user` ,进程内父传播映射到 `parent` 。原因只存在于运行时;持久 `turn/end` 保持粗粒度的 `aborted` 。
@@ -77,7 +77,7 @@ Agent *创建* 由实现 `AgentFactory` 的插件(`dsh-agent-loop`)提供,
- Agent 创建:`AgentLoop.create()` 是具体配置路径实现(位于 `dsh-agent-loop` ),程序化消费方则通过 `ctx.agents.create()` /`ctx.agents.resume()` 创建或恢复有所有权的 agent。替换循环时, 应实现 `Agent` 并通过 `ctx.agents.register()` 注册。
- 事件监听器:全部 `agent/*` 事件都在此处声明,不需要依赖循环包。
- S ubagent 委派不是 `Agent` 方法;提供方通过工厂 seam 创建或驱动普通 handle, 因此委派传输留在核心 agent 接口之外。
- s ubagent 委派不是 `Agent` 方法;提供方通过工厂 seam 创建或驱动普通 handle, 因此委派传输留在核心 agent 接口之外。
## 模型体验
@@ -115,6 +115,6 @@ Agent *创建* 由实现 `AgentFactory` 的插件(`dsh-agent-loop`)提供,
- **环境身份可能比存活状态更久**:消费方在生命周期敏感工作前,仍要检查 `agent.status` 、取消状态和所属能力契约。
- **委派以外的 agent 间通道**:共享状态、流式子输出和后台/轮询语义仍在当前同步 `ctx.subagents` seam 之外。
- **`agent/session-start` 不能为启动设置门禁**:它仍是同步且不可 veto 的通知;必须在发布前完成的异步组合属于工厂的 `setup(agentCtx)` 事务。
- **`cancel()` 默认清空 inbox**:它会中止正在处理的轮次以及排队和 steering 工作;`cancel(cause, { keepInbox: true })` 只中止轮次并保留待处理项。仍不存在只中止步骤、同时让正在处理的轮次继续运行的操作([停止表层 Agent Note ](../../../.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.md ))。
- **`cancel()` 默认清空 inbox**:它会中止正在处理的轮次以及排队和 steering 工作;`cancel(cause, { keepInbox: true })` 只中止轮次并保留待处理项。仍不存在只中止步骤、同时让正在处理的轮次继续运行的操作([关于停止操作接口的 Agent Note ](../../../.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.md ))。
- **每条附加 `UserMessage` 恰好携带一个 `MessageSource` **:多个插件合并到一次工具调用上的贡献会归入一个来源;无法表示混合来源。
- **`SessionStartSource` 预留 `'clear'` /`'compact'` ,但还没有发出方**:在驱动子系统落地前,只会出现 `'startup'` /`'resume'` ( `TODO(compaction)` )。