Merge remote-tracking branch 'origin/master' into xtr/react-loop-simplification
# Conflicts: # .agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.i18n.yaml # .agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.md # .agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.zh.md # .agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.i18n.yaml # .agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.md # .agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.zh.md # .agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.i18n.yaml # .agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.md # .agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.zh.md # docs/architecture.i18n.yaml # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.i18n.yaml # docs/core-data-structures/core.md # docs/core-data-structures/core.zh.md # docs/defensive-patterns.i18n.yaml # packages/client/runtime/src/client/sessions/session.ts # packages/client/runtime/tests/queue-store.spec.ts # packages/context/time-context/tests/time-context.spec.ts # packages/context/workspace-context/tests/workspace-context.spec.ts # packages/cordis/tool-cordis/src/api-catalog.ts # packages/core/agent-loop/README.i18n.yaml # packages/core/agent-loop/README.md # packages/core/agent-loop/README.zh.md # packages/core/agent-loop/src/agent.ts # packages/core/agent/README.i18n.yaml # packages/core/agent/README.md # packages/core/agent/README.zh.md # packages/core/agent/src/types.ts # packages/core/agent/tests/agent.spec.ts # packages/core/scope/src/scoped-events.generated.ts # packages/goal/command-goal/tests/command-goal.spec.ts # packages/goal/goal-session/src/index.ts # packages/goal/goal-session/tests/goal-session.spec.ts # packages/goal/goal/tests/goal.spec.ts # packages/goal/goal/tests/projection.spec.ts # packages/goal/tool-goal/tests/tool-goal.spec.ts # packages/host/apiproxy/src/api-proxy.ts # packages/host/apiproxy/src/api/events.schema.ts # packages/host/apiproxy/src/api/events.ts # packages/host/apiproxy/tests/api-proxy-workspace.spec.ts # packages/llm/llm/README.i18n.yaml # packages/llm/llm/README.zh.md # packages/llm/llm/src/index.ts # packages/pty/pty-local/tests/index.spec.ts # packages/pty/pty-local/tests/local.spec.ts # packages/pty/pty/tests/service.spec.ts # packages/pty/tool-pty/tests/loader-composition.spec.ts # packages/pty/tool-pty/tests/tools.spec.ts # packages/skill/tool-skill/tests/tool-skill.spec.ts # packages/tasks/tasks-local/tests/tasks.spec.ts # packages/ui/tui/src/index.ts # packages/ui/tui/tests/harness.ts # packages/ui/tui/tests/tui.spec.ts # scripts/gen-cordis-catalog.ts # scripts/type-equiv.manifest.json
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write packages/goal/README.md
|
||||
README.md: f43dfd8258eabe8342207c0b1b9d6acc9e215e9f
|
||||
README.zh.md: f663939bb19d8bc295a96fc0a673c56251e9a2a9
|
||||
README.zh.md: 70b38caac723d757f44109e4ec75e3c31e7c34b8
|
||||
|
||||
@@ -7,8 +7,8 @@ goal 家族负责持久目标状态,与消费该状态的面向模型工具和
|
||||
| 包 | 职责 | ctx 键 |
|
||||
|---|---|---|
|
||||
| `goal/` | 事件溯源的目标生命周期、回放折叠、比较并设置变更,以及进程本地激活 | `ctx.goals` |
|
||||
| `goal-session/` | 同会话 goal round 的准入、结果映射与生命周期竞态隔离 | 无 |
|
||||
| `goal-session/` | 同会话 Goal Round 的准入、结果映射与生命周期竞态隔离 | 无 |
|
||||
| `tool-goal/` | 面向模型的读取/创建/更新工具,并在执行时检查权限 | 无 |
|
||||
| `command-goal/` | 面向用户的 `/goal` 状态,以及通过命令平面执行的生命周期控制 | 无 |
|
||||
|
||||
目标状态属于所属会话日志。消费方依赖 `dsh-goal`,而不是具体的 agent loop;续行行为由基于公开 agent seam 的独立插件负责。
|
||||
目标状态是其所属会话日志的一部分。消费方依赖 `dsh-goal`,而不是具体的 agent loop(智能体循环);续行行为由基于公开 agent seam 的独立插件负责。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write packages/goal/command-goal/README.md
|
||||
README.md: 8e1a5b417467c8701ea935e25acfece11c5a70d4
|
||||
README.zh.md: fc7229e1fa14160b8247ae0c33a5fbc3cb062254
|
||||
README.zh.md: 66f237ac7ea8ef5d158917998b0dfd49189289f1
|
||||
|
||||
@@ -2,22 +2,22 @@
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
面向用户的 `/goal` 控制,基于 [`ctx.goals`](../goal/README.md) 实现。该插件通过 [`ctx.commands`](../../ui/commands/README.md) 注册一个全局命令,因此每个已组合的命令适配器都能发现它;随附 TUI 无需模型轮次即可执行。[用户 goal 命令 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-human-goal-command.md)负责用户体验与组合决策。
|
||||
面向用户的 `/goal` 控制,基于 [`ctx.goals`](../goal/README.md) 实现。该插件通过 [`ctx.commands`](../../ui/commands/README.md) 注册一个全局命令,因此每个已组合的命令适配器都能发现它;随附 TUI 无需模型轮次即可执行。[用户 goal 命令 Agent Note(agent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-19-human-goal-command.md) 负责用户体验与组合决策。
|
||||
|
||||
## 命令契约
|
||||
|
||||
| 输入 | 结果 |
|
||||
|---|---|
|
||||
| `/goal` | 显示当前目标、持久 phase、round 计数/上限、进程本地激活状态与有效的下一步命令;被阻塞的 goal 还会显示策略代码和说明,没有 goal 时则显示用法。 |
|
||||
| `/goal <objective>` | 创建并激活 goal,或用全新身份替换已完成 goal。未完成 goal 绝不会在没有显式 clear 的情况下被替换。 |
|
||||
| `/goal edit <objective>` | 编辑当前目标,不改变其 phase 或激活状态。编辑已完成 goal 会创建新的 active goal。 |
|
||||
| `/goal pause` | 暂停 active goal,并撤销续行激活。 |
|
||||
| `/goal resume` | 恢复已停止 goal,或在会话 resume/fork 后重新激活 active goal;仍受剩余 round 上限约束。 |
|
||||
| `/goal` | 显示当前目标、持久 phase、Round 计数/上限、进程本地续行启用状态与有效的下一步命令;被阻塞的 goal 还会显示策略代码和说明,没有 goal 时则显示用法。 |
|
||||
| `/goal <objective>` | 创建 goal 并启用续行,或用全新身份替换已完成 goal。未完成 goal 绝不会在没有显式 clear 的情况下被替换。 |
|
||||
| `/goal edit <objective>` | 编辑当前目标,不改变其 phase 或续行启用状态。编辑已完成 goal 会创建新的 active goal。 |
|
||||
| `/goal pause` | 暂停 active goal,并停用续行。 |
|
||||
| `/goal resume` | 恢复已停止 goal,或在会话 resume/fork 后为 active goal 重新启用续行;仍受剩余 Round 上限约束。 |
|
||||
| `/goal clear` | 清除当前指针,同时保留其持久历史和 tombstone。 |
|
||||
|
||||
只有控制词占据完整输入时才不区分大小写。其他任何非空后缀都属于目标,因此 `/goal pause after verification` 会创建该字面目标。goal 领域会修剪并验证目标。由于通用命令平面没有模态编辑器或确认原语,`edit` 会内联接收替换内容;若替换内容不完整,则直接返回错误,提示用户执行 edit 或 clear。
|
||||
只有控制词占据完整输入时才不区分大小写。其他任何非空后缀都属于目标,因此 `/goal pause after verification` 会创建该字面目标。goal 领域会去除目标首尾空白并进行验证。由于通用命令平面没有模态编辑器或确认原语,`edit` 会内联接收替换内容;若试图替换未完成的 goal,则直接返回错误,提示用户执行 edit 或 clear。
|
||||
|
||||
可预期的领域拒绝会变成稳定的直接命令错误,不公开品牌化 id 或 revision。意外实现失败仍会 reject 分发,使适配器能将其报告为命令失败。通用命令文本和输出只属于活跃 UI 状态;每项已接受变更都由 `dsh-goal` 持久化并提供给模型,而不是由此插件完成。
|
||||
可预期的领域拒绝会变成稳定的直接命令错误,不公开带品牌类型的 id 或 revision。意外实现失败仍会 reject 分发,使适配器能将其报告为命令失败。通用命令文本和输出仍属于实时 UI 状态;每项已接受变更都由 `dsh-goal` 持久化并提供给模型,而不是由此插件完成。
|
||||
|
||||
## 组合
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
name: '@deepseek-ai/dsh-command-goal'
|
||||
```
|
||||
|
||||
TUI 应用默认启用完整的持久 goal 栈和此命令。ACP 自动化应用会启用领域与模型工具,但不挂载命令注册表;`goals: false` 会移除该栈。无 UI 的 `agent-spine-demo` 必须显式配置 `goals: {}`,避免无头单次调用方在不知情时从一个物理轮次变为多 round 操作。
|
||||
TUI 应用默认启用完整的持久 goal 栈和此命令。ACP(Agent Client Protocol)自动化应用会启用领域与模型工具,但不挂载命令注册表;`goals: false` 会移除该栈。无 UI 的 `agent-spine-demo` 必须显式配置 `goals: {}`,避免无头单次调用方在不知情时从一个物理轮次变为包含多个 Round 的操作。
|
||||
|
||||
## 模型体验
|
||||
|
||||
@@ -44,15 +44,15 @@ TUI 应用默认启用完整的持久 goal 栈和此命令。ACP 自动化应用
|
||||
|
||||
#### Token 影响
|
||||
|
||||
读取状态或收到直接命令错误不会增加模型 token。每项已接受变更都会增加 goal 领域保留的完整快照;已启用的同会话驱动器还可能增加后续 goal-round 提示词。
|
||||
读取状态或收到直接命令错误不会增加模型 token。每项已接受变更都会增加 goal 领域保留的完整快照;已启用的同会话驱动器还可能增加后续 Goal Round 提示词。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
命令发现与直接输出不会影响缓存。变更会追加到可复用历史前缀之后;后续压缩可能替换派生历史后缀。
|
||||
|
||||
## 已知限制与暂缓工作
|
||||
## 已知限制与暂缓事项
|
||||
|
||||
- **仅纯文本交互**:通用命令注册表没有模态编辑表单或替换确认回调;内联 edit 与显式 clear 能在不同适配器中保持确定的破坏性意图。
|
||||
- **没有逐命令 round 上限参数**:`defaultMaxGoalRounds` 仍是部署配置;用户直接请求时,可以要求模型通过另行授权的 goal 工具编辑 `max_goal_rounds`。
|
||||
- **没有持续状态组件**:裸 `/goal` 是可移植的观察接口;适配器专用徽标和可重新连接的命令输出仍属于未来 UI 工作。
|
||||
- **随附应用中只有 TUI 使用此命令**:无头 CLI、ACP 自动化和 JSON-RPC 适配器不消费 `ctx.commands`。如果组合中包含面向模型的 goal 工具,普通提示词仍能授权它们。
|
||||
- **仅纯文本交互**:通用命令注册表没有模态编辑表单或替换确认回调;内联 edit 与显式 clear 能在不同适配器中保持明确且一致的破坏性意图。
|
||||
- **没有逐命令 Round 上限参数**:`defaultMaxGoalRounds` 仍是部署配置;用户直接请求时,可以要求模型通过另行授权的 goal 工具编辑 `max_goal_rounds`。
|
||||
- **没有持续状态组件**:裸 `/goal` 是可移植的观察接口;适配器专用徽标和重连后可恢复的命令输出仍属于未来 UI 工作。
|
||||
- **随附应用中只有 TUI 使用此命令**:无头 CLI(命令行界面)、ACP 自动化和 JSON-RPC 适配器不消费 `ctx.commands`。如果组合中包含面向模型的 goal 工具,普通提示词仍能授权它们。
|
||||
|
||||
@@ -37,6 +37,8 @@ function stubAgent(ctx: Context, id: string): { agent: Agent; session: Session }
|
||||
ctx: new Context(),
|
||||
get status() { return status },
|
||||
get acceptsNextStep() { return status === 'running' },
|
||||
send: () => {},
|
||||
updateInbox: () => 'not-found',
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input) { appendInjection(session, input) },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write packages/goal/goal-session/README.md
|
||||
README.md: 6a1c3b9455c93762c2458109c753588ce9a08d9a
|
||||
README.zh.md: d06d2d96deb845f72c5c88bc47a04a1af621c078
|
||||
README.zh.md: 4162411bf2dbeebbec8da6433c71e176057c4277
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
[`ctx.goals`](../goal/README.md) 的同会话续行驱动器。它通过公开 `Agent` 与会话 seam,把活跃且已激活的目标转换为连续的 [goal round](../../../docs/glossary.md#goal-round);[同会话驱动器 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-same-session-goal-round-driver.md)负责竞态和生命周期理由。
|
||||
[`ctx.goals`](../goal/README.md) 的同会话续行驱动器。它通过公开 `Agent` 与会话 seam,把 phase 为 active 且已启用续行的目标转换为连续的 [Goal Round](../../../docs/glossary.md#goal-round);[同会话驱动器 Agent Note(agent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-19-same-session-goal-round-driver.md) 记载竞态与生命周期方面的设计理由。
|
||||
|
||||
## 组合
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
|
||||
## Round 契约
|
||||
|
||||
当完全相同的活跃 agent 处于 idle 状态,且目标 active、已经激活并有剩余容量时,驱动器先为待处理 goal 变更创建检查点,再预留 `roundsStarted + 1`,对应当前 `{ goalId, revision }`。它会排入一条 `<goal_round>` 提示词,并携带 `GoalMessageSource`。通过 `agent/prompt-submit` 准入时,会在下游提示词 hook 前后同时验证完整的排队记录与当前 goal;只有被接受的 `user/message` 才会增加 `roundsStarted`。因陈旧而被拒绝的预留不会消耗 round 编号。
|
||||
当对应的活跃 agent 实例处于 idle 状态,且目标 phase 为 active、已启用续行并有剩余容量时,驱动器先为待处理 goal 变更创建检查点,再预留 `roundsStarted + 1`,对应当前 `{ goalId, revision }`。它会排入一条 `<goal_round>` 提示词,并携带 `GoalMessageSource`。通过 `agent/prompt-submit` 准入时,会在下游提示词钩子前后验证完整的排队记录与当前 goal;只有被接受的 `user/message` 才会增加 `roundsStarted`。因陈旧而被拒绝的预留不会消耗 Round 编号。
|
||||
|
||||
一个 goal round 拥有一个普通会话轮次,该轮次可以包含多个模型/工具步骤。驱动器只会把预留与 `message` 轮次配对,且该轮次必须携带完全相同的 `GoalMessageSource`;可通过声明合并扩展的插件轮次触发器不会准入或替换该预留。用户消息仍是普通轮次,不消耗 goal 上限。如果用户工作在预留前进入 inbox,或加入预留的待处理批次,自动工作会让行,直到用户工作结算;混合批次中的待处理自动提示词会被拒绝,只有 agent 再次 idle 后才重新预留。
|
||||
一个 Goal Round 对应一个普通会话轮次,该轮次可以包含多个模型/工具步骤。驱动器只会把预留与 `message` 轮次配对,且该轮次必须携带完全相同的 `GoalMessageSource`;可通过声明合并扩展的插件轮次触发器不会准入或替换该预留。用户消息仍是普通轮次,不消耗 goal 上限。如果用户工作在预留前进入 inbox,或加入预留的待处理批次,自动工作会让行,直到用户工作结算;混合批次中的待处理自动提示词会被拒绝,只有 agent 再次 idle 后才重新预留。
|
||||
|
||||
保留的提示词会点明经过 JSON 引用的目标与 `round/maxGoalRounds`,将当前工作区、工具结果和持久会话状态视为权威信息,要求在完成前提供证据,并要求在工作仍未完成时保持目标 active。引用可将多行或形似标签的目标文本保留为数据。goal 生命周期变更仍必须通过 `dsh-tool-goal` 的独立权限检查。
|
||||
|
||||
@@ -31,43 +31,43 @@
|
||||
|
||||
| 持久轮次结果 | Goal 操作 | 自动重试 |
|
||||
|---|---|---|
|
||||
| goal 仍 active 且已激活时的 `completed` | 准入下一 round;达到上限时以代码 `round-limit` 阻塞 | 是 |
|
||||
| 已预留/准入 goal round 的取消,或其 `aborted` 结果 | `paused` | 否 |
|
||||
| 未尝试 goal round 时取消 | 保留持久 phase;撤销激活 | 否 |
|
||||
| goal phase 仍为 active 且已启用续行时的 `completed` | 准入下一 Round;达到上限时以代码 `round-limit` 阻塞 | 是 |
|
||||
| 已预留/准入 Goal Round 的取消,或其 `aborted` 结果 | `paused` | 否 |
|
||||
| 未尝试 Goal Round 时取消 | 保留持久 phase;撤销激活 | 否 |
|
||||
| `error` 且带 `RATE_LIMIT` 或 `QUOTA` | 设为 `blocked`,代码为 `usage-limited` | 否 |
|
||||
| 其他 `error`、`max-tokens` 或非陈旧提示词拒绝 | 以诊断代码和消息设为 `blocked` | 否 |
|
||||
| 持久性失败、资源释放、中断或未知未来结果 | 撤销激活或阻塞,以便检查 | 否 |
|
||||
| 持久性失败、dispose(资源释放)、中断或未知未来结果 | 撤销激活或阻塞,以便检查 | 否 |
|
||||
|
||||
某个 goal 在自身 round 中发生的变更,会取代旧 revision 的结算。因此,即使物理轮次随后关闭,完成、暂停、阻塞和编辑仍具有最终决定权。任何异常结果都不会自动重试。
|
||||
某个 goal 在自身 Round 中发生的变更,会取代旧 revision 的结算。因此,即使物理轮次随后关闭,完成、暂停、阻塞和编辑仍具有最终决定权。任何异常结果都不会自动重试。
|
||||
|
||||
## 生命周期与持久性
|
||||
|
||||
`goal/changed` 会产生持久性义务。排队工作前,驱动器会等待 `ctx.sessions.flush()`,并在等待后重新检查 goal revision 与竞争输入。关闭时的 flush 失败通过 `agent/error` 到达;即使后续一次性注入已经追加另一轮次,驱动器仍会把失败关联到完全相同的已关闭轮次,然后撤销激活,避免另一 round 启动。
|
||||
`goal/changed` 会产生持久性义务。排队工作前,驱动器会等待 `ctx.sessions.flush()`,并在等待后重新检查 goal revision 与竞争输入。关闭时的 flush 失败通过 `agent/error` 到达;即使后续一次性注入已经追加另一轮次,驱动器仍会把失败关联到完全相同的已关闭轮次,然后停用续行,避免另一 Round 启动。
|
||||
|
||||
此插件加载到现有 agent 上时绝不会继承激活状态。`GoalService.disarm()` 会移除进程本地权限,而不改变持久 phase、revision 或历史;之后由用户明确授权的 resume 会记录重新激活。会话 resume 和 fork 后,goal 领域通过 `agent/session-start` 处理应用相同规则。
|
||||
此插件加载到现有 agent 上时绝不会继承续行启用状态。`GoalService.disarm()` 会移除进程本地权限,而不改变持久 phase、revision 或历史;之后由用户明确授权的 resume 会记录重新启用续行。会话 resume 和 fork 后,goal 领域通过 `agent/session-start` 处理应用相同规则。
|
||||
|
||||
取消采用先观察、后行动的顺序:具体循环会在清空队列或中止轮次前,发送带类型 cause 的 `agent/cancel-requested`。只有取消操作拥有已预留或已准入的 goal 尝试时,插件才会持久暂停 active goal;取消无关用户工作只会撤销进程本地续行权限。如果 pause 变更失败,驱动器会回退到撤销激活。插件 teardown 会关闭准入,撤销所有活跃 goal 的激活,以 `parent` cause 取消已经准入的 round,并在事件隔离仍安装的情况下等待驱动器和 agent 完全停稳。
|
||||
取消采用先观察、后行动的顺序:具体循环会在清空队列或中止轮次前,发送带类型 cause 的 `agent/cancel-requested`。仅当取消操作所针对的是已预留或已准入的 Goal Round 尝试时,插件才会持久暂停 active goal;取消无关用户工作只会撤销进程本地续行权限。如果 pause 变更失败,驱动器会回退到停用续行。插件 teardown 会关闭准入,停用所有活跃 goal 的续行,以 `parent` cause 取消已经准入的 Round,并在事件隔离仍安装的情况下等待驱动器和 agent 完全停稳。
|
||||
|
||||
## 模型体验
|
||||
|
||||
### Goal-round 提示词
|
||||
### Goal Round 提示词
|
||||
|
||||
#### 模型看到的内容
|
||||
|
||||
每个已准入 round 都是一段保留的用户角色 `<goal_round>` 块,其中点明完整目标与正 round 编号。更早的用户消息、goal 状态快照、assistant 输出与工具记录仍保留在同一会话历史中。
|
||||
每个已准入 Round 都是一段保留的用户角色 `<goal_round>` 块,其中点明完整目标与正数 Round 编号。更早的用户消息、goal 状态快照、assistant 输出与工具记录仍保留在同一会话历史中。
|
||||
|
||||
#### Token 影响
|
||||
|
||||
每个已准入 round 会增加一个固定指令块和目标。后续请求会重新发送保留的 round,直到压缩将其遮蔽;不会创建新 agent,也不会复制对话前缀。
|
||||
每个已准入 Round 会增加一个固定指令块和目标。后续请求会重新发送保留的 Round,直到压缩(compaction)将其遮蔽;不会创建新 agent,也不会复制对话前缀。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
在一个 epoch 内仅追加:每个已准入 round 都会在可复用前缀后扩展现有对话。压缩可能替换派生历史后缀,并移动可复用边界。
|
||||
在一个 epoch 内仅追加:每个已准入 Round 都会在可复用前缀后扩展现有对话。压缩可能替换派生历史后缀,并移动可复用边界。
|
||||
|
||||
## 已知限制与暂缓工作
|
||||
## 已知限制与暂缓事项
|
||||
|
||||
- **没有独立评估器**:面向模型的 goal 策略会判断证据是否足以完成,以及 blocker 在语义上是否未变;评估器支持的认证仍保持暂缓。
|
||||
- **只在同一会话执行**:此包有意不 spawn 新 agent、不 fork 会话前缀,也不实现 Ralph 风格的独立尝试;该工作流属于自己的插件层。
|
||||
- **已接受队列的卸载竞态**:Cordis 插件卸载是异步的。已经被 agent inbox 接受的 goal 提示词可以在卸载开始前启动并消耗其 round;teardown 随后会取消请求、撤销 goal 激活并等待完全停稳。不会再启动后续 round。
|
||||
- **只有 round 上限,不是资源预算**:token、货币、时间与提供方配额策略保持独立;观察到 `RATE_LIMIT` 和 `QUOTA` 时,只会映射为阻塞原因代码 `usage-limited`。
|
||||
- **异常情况不自动重试**:短暂的提供方与持久化失败需要之后由用户授权 resume,而不是隐式重试策略。
|
||||
- **只在同一会话执行**:此包(package)有意不 spawn 新 agent、不 fork 会话前缀,也不实现 Ralph 风格的独立尝试;该工作流属于单独的插件层。
|
||||
- **已接受队列的卸载竞态**:Cordis 插件卸载是异步的。已经被 agent inbox 接受的 goal 提示词可以在卸载开始前启动并消耗其 Round;teardown 随后会取消请求、撤销 goal 激活并等待完全停稳。不会再启动后续 Round。
|
||||
- **只有 Round 上限,不是资源预算**:token、货币、时间与提供方配额策略保持独立;观察到 `RATE_LIMIT` 和 `QUOTA` 时,只会映射为阻塞原因代码 `usage-limited`。
|
||||
- **异常情况不自动重试**:暂时性的提供方与持久化失败需要之后由用户授权 resume,而不会采用隐式重试策略。
|
||||
|
||||
@@ -324,6 +324,37 @@ export function apply(ctx: Context): void {
|
||||
requestDrive(state)
|
||||
}
|
||||
})
|
||||
ctx.on('agent/inbox/enqueue', (agent, item) => {
|
||||
const state = stateFor(agent)
|
||||
const attempt = state.attempt
|
||||
if (attempt !== undefined && sameQueued(item.message.content, item.message.source, attempt)) return
|
||||
state.competingQueued = true
|
||||
if (attempt?.phase === 'queued') attempt.stale = true
|
||||
})
|
||||
ctx.on('agent/cancel-requested', (agent, cause) => {
|
||||
const state = stateFor(agent)
|
||||
const attempt = state.attempt
|
||||
state.competingQueued = false
|
||||
const goal = currentGoal(state)
|
||||
if (goal?.phase === 'active' && goal.activation === 'armed') {
|
||||
if (attempt === undefined) {
|
||||
disarm(state)
|
||||
return
|
||||
}
|
||||
// An admitted round closes durably as aborted; retain it so the normal
|
||||
// turn outcome path appends pause after cancellation reaches idle.
|
||||
// Pausing here would stage context into the active outbox only for this
|
||||
// same cancel() call to discard it.
|
||||
if (attempt.turn !== undefined || attempt.phase === 'admitted') return
|
||||
state.attempt = undefined
|
||||
try {
|
||||
applyOutcome(state, goal, { kind: 'pause', reason: cause.kind })
|
||||
} catch (error: unknown) {
|
||||
ctx.logger.warn(`goal-session: could not pause cancelled goal for agent "${agent.id}": ${renderThrown(error)}`)
|
||||
disarm(state)
|
||||
}
|
||||
}
|
||||
})
|
||||
ctx.on('goal/changed', (agent) => {
|
||||
const state = stateFor(agent)
|
||||
state.needsCheckpoint = true
|
||||
|
||||
@@ -280,7 +280,7 @@ describe('same-session goal driving', () => {
|
||||
it('pauses and drops a reserved round when cancellation lands before admission', async () => {
|
||||
const test = await harness([])
|
||||
const cancel = test.ctx.on('agent/inbox/enqueue', (agent, info) => {
|
||||
if (agent === test.agent && info.source.kind === 'goal') {
|
||||
if (agent === test.agent && info.message.source.kind === 'goal') {
|
||||
cancel()
|
||||
agent.cancel({ kind: 'user' })
|
||||
}
|
||||
@@ -331,7 +331,7 @@ describe('same-session goal driving', () => {
|
||||
const test = await harness([textResponse('human batch'), textResponse('later goal')])
|
||||
let inserted = false
|
||||
test.ctx.on('agent/inbox/enqueue', (agent, info) => {
|
||||
if (agent !== test.agent || info.source.kind !== 'goal' || inserted) return
|
||||
if (agent !== test.agent || info.message.source.kind !== 'goal' || inserted) return
|
||||
inserted = true
|
||||
agent.followup(createUserMessage({ content: [{ type: 'text', text: 'human joined the pending batch' }], source: { kind: 'user' } }))
|
||||
})
|
||||
@@ -349,7 +349,7 @@ describe('same-session goal driving', () => {
|
||||
const test = await harness([textResponse('new revision')])
|
||||
let edited = false
|
||||
test.ctx.on('agent/inbox/enqueue', (agent, info) => {
|
||||
if (agent !== test.agent || info.source.kind !== 'goal' || edited) return
|
||||
if (agent !== test.agent || info.message.source.kind !== 'goal' || edited) return
|
||||
edited = true
|
||||
const current = test.ctx.goals.get(agent)
|
||||
if (current === undefined) throw new Error('missing goal during queued edit')
|
||||
@@ -629,7 +629,7 @@ describe('same-session goal driving', () => {
|
||||
const test = await harness([textResponse('retry after containment')])
|
||||
let armed = true
|
||||
test.ctx.on('agent/inbox/enqueue', (agent, info) => {
|
||||
if (agent !== test.agent || info.source.kind !== 'goal' || !armed) return
|
||||
if (agent !== test.agent || info.message.source.kind !== 'goal' || !armed) return
|
||||
armed = false
|
||||
vi.spyOn(test.ctx.goals, 'get').mockImplementationOnce(() => {
|
||||
throw new Error('admission projection failed')
|
||||
@@ -705,7 +705,7 @@ describe('same-session goal driving', () => {
|
||||
it('falls back to disarming when a cancelled reservation cannot be paused', async () => {
|
||||
const test = await harness([])
|
||||
const cancel = test.ctx.on('agent/inbox/enqueue', (agent, info) => {
|
||||
if (agent !== test.agent || info.source.kind !== 'goal') return
|
||||
if (agent !== test.agent || info.message.source.kind !== 'goal') return
|
||||
cancel()
|
||||
vi.spyOn(test.ctx.goals, 'pause').mockImplementationOnce(() => {
|
||||
throw new Error('pause failed')
|
||||
@@ -759,7 +759,7 @@ describe('same-session goal driving', () => {
|
||||
const test = await harness([])
|
||||
let unloading: Promise<void> | undefined
|
||||
test.ctx.on('agent/inbox/enqueue', (agent, info) => {
|
||||
if (agent === test.agent && info.source.kind === 'goal' && unloading === undefined) {
|
||||
if (agent === test.agent && info.message.source.kind === 'goal' && unloading === undefined) {
|
||||
unloading = Promise.resolve(test.driver.dispose())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write packages/goal/goal/README.md
|
||||
README.md: 45d7ac2e1c8fbd60ab2bc8b917b326d20da02ec1
|
||||
README.zh.md: 9936b8af1a5f5b49486eeda6bf137ee534377f06
|
||||
README.zh.md: b657d1d52f75657ba44b99306e4621aa82688e96
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
事件溯源的同会话目标状态。该服务在 agent(智能体)的现有会话中保留一个当前完成目标,同时将继续执行的权限作为进程本地激活状态。[goal 领域 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md)负责设计理由;[goal 类型目录](../../../docs/core-data-structures/goal.md)记录字面数据形状。
|
||||
事件溯源的同会话目标状态。该服务在 agent(智能体)的现有会话中保留一个当前完成目标,同时将继续执行的权限作为进程本地续行启用状态。[goal 领域 Agent Note(agent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md) 负责设计理由;[goal 类型目录](../../../docs/core-data-structures/goal.md)记录具体的数据形状。
|
||||
|
||||
## 配置
|
||||
|
||||
@@ -13,25 +13,25 @@
|
||||
defaultMaxGoalRounds: 256
|
||||
```
|
||||
|
||||
`defaultMaxGoalRounds` 必须是正安全整数。`create()` 会在提交目标前于内部物化这项部署默认值;请求级取值可以覆盖它。
|
||||
`defaultMaxGoalRounds` 必须是正的安全整数。`create()` 会在提交目标前于内部物化这项部署默认值;请求级取值可以覆盖它。
|
||||
|
||||
## 服务契约
|
||||
|
||||
`ctx.goals` 只接受以对应 id 注册的完全相同的活跃 `Agent` 实例。`get()` 返回分离的 `GoalView`;变更通过 `GoalRef { id, revision }` 比较并设置限制,并拒绝陈旧引用。服务通过生成的[服务目录](../../../docs/cordis-catalog/services.md)公开 create、edit、pause、resume、complete、block 和 clear 动词。创建默认值在内部解析。`disarm()` 是仅供生命周期使用的例外:它移除进程本地续行权限,不写入新 revision,也不发送变更事件。
|
||||
`ctx.goals` 只接受以对应 id 注册的完全相同的活跃 `Agent` 实例。`get()` 返回与内部状态脱离的 `GoalView`;变更通过 `GoalRef { id, revision }` 比较并设置屏障,并拒绝陈旧引用。服务通过生成的[服务目录](../../../docs/cordis-catalog/services.md)公开 create、edit、pause、resume、complete、block 和 clear 动词。创建默认值在内部解析。`disarm()` 是仅供生命周期使用的例外:它移除进程本地续行权限,不写入新 revision,也不发出变更。
|
||||
|
||||
最多只有一个当前目标。创建操作会生成 revision 为 1 的活跃目标并将其激活。未完成的目标必须编辑、转换或清除;已完成目标可以由拥有全局新 id 的目标替换。编辑会保留 phase、blocker reason 与 activation。暂停、完成、阻塞和清除都会撤销激活。阻塞会记录策略自有的 lower-kebab-case 代码和规范化的自由文本说明;提供方限制、配置预算、执行错误与请求用户输入都使用这一种持久 phase,不会扩增生命周期状态。只有配置的 round 上限仍有剩余容量时,resume 才接受已停止 phase 或撤销激活的 active 目标;它会清除原 blocker reason。活跃且已激活的目标会拒绝冗余操作。
|
||||
最多只有一个当前目标。创建操作会生成 revision 为 1、phase 为 active 的目标并启用续行。未完成的目标必须编辑、转换或清除;已完成目标可以由拥有全局未使用过的 id 的目标替换。编辑会保留 phase、blocker reason 与 activation。暂停、完成、阻塞和清除都会停用续行。阻塞会记录策略自有的 lower-kebab-case 代码和规范化的自由文本说明;提供方限制、配置预算、执行错误与请求人工输入都使用这一种持久 phase,不会扩增生命周期状态。只有配置的 Round 上限仍有剩余容量时,resume 才接受已停止 phase 或 phase 为 active 但已停用续行的目标;它会清除原 blocker reason。phase 为 active 且已启用续行的目标会拒绝冗余操作。
|
||||
|
||||
每次非 clear 变更都会通过 `agent.inject()` 追加完整的版本化快照;clear 则追加带 revision 的 tombstone。模型可见的 `user/message` 内容与其带类型的 `{ kind: 'goal', change }` 来源必须完全一致。回放会拒绝形状错误、来源/内容漂移、不连续 revision、非法生命周期转换、每目标时间戳非单调,以及不连续的 goal round。墙上时间倒退时,变更时间戳会限制在不早于上一次目标更新的值。
|
||||
每次非 clear 变更都会通过 `agent.inject()` 追加完整的版本化快照;clear 则追加带 revision 的 tombstone。模型可见的 `user/message` 内容与其带类型的 `{ kind: 'goal', change }` 来源必须完全一致。回放会拒绝形状错误、来源/内容漂移、不连续 revision、非法生命周期转换、每目标时间戳非单调,以及不连续的 Goal Round。挂钟时间倒退时,变更时间戳会限制在不早于上一次目标更新的值。
|
||||
|
||||
注入可以立即追加,也可能在活跃工具批次 FIFO 中等待。服务会在内存中覆盖已经接受但尚待写入的变更,并在每个确切载荷进入日志时执行协调,因此连续的模型工具变更可以看到自身最新 revision,而不会把尚未记录的缓存当作持久状态。可重入追加观察者会且只会看到每项已接受变更一次;增量回放会把游标保留在第一个损坏事件处。追加或入队成功后才触发 `goal/changed`;监听器失败会受到隔离。
|
||||
注入可以立即追加,也可能在活跃工具批次 FIFO 中等待。服务会在内存中叠加已接受的待处理变更,并在每个完全一致的载荷进入日志时逐一完成对账,因此连续的模型工具变更可以看到自身最新 revision,而不会把尚未记录的缓存当作持久状态。可重入追加观察者会且只会看到每项已接受变更一次;增量回放会把游标保留在第一个损坏事件处。追加或入队成功后才触发 `goal/changed`;监听器失败会被隔离处理。
|
||||
|
||||
激活状态绝不持久化。新缓存与每条 `agent/session-start` 边都会撤销激活,即使回放找到了持久 phase 为 active 的目标。续行驱动器在卸载前或持久性不确定后也会调用 `disarm()`。因此,会话恢复、fork 与驱动器替换会保留目标、phase、revision 和已准入 round 数量,却不会启动工作;之后必须通过显式 resume 变更重新激活续行。
|
||||
续行启用状态绝不持久化。新缓存与每次触发 `agent/session-start` 时都会停用续行,即使回放找到了持久 phase 为 active 的目标。续行驱动器在卸载前或持久性不确定后也会调用 `disarm()`。因此,会话恢复、fork 与驱动器替换会保留目标、phase、revision 和已准入 Round 数量,却不会启动工作;之后必须通过显式 resume 变更重新启用续行。
|
||||
|
||||
单独发布的 `./invariant` 配套模块会为每个已挂接会话维护独立折叠。它会在候选事件进入持久日志前拒绝错误的 goal 来源变更、模型可见内容漂移、不连续 revision、非法生命周期转换、时间戳回退,以及不连续的已准入 round。
|
||||
单独发布的 `./invariant` 配套模块会为每个已挂接会话维护独立折叠。它会在候选事件进入持久日志前拒绝格式错误的 goal 来源变更、模型可见内容漂移、不连续 revision、非法生命周期转换、时间戳回退,以及不连续的已准入 round。
|
||||
|
||||
## 扩展点
|
||||
|
||||
策略插件调用服务动词,并响应限定范围的 `goal/changed` 事件。续行消费方将 round 准入为 `user/message` 事件,并携带 `GoalMessageSource`;普通用户轮次绝不会增加 `roundsStarted`。消费方使用 `Agent` 接口和事件,不导入 `dsh-agent-loop`。
|
||||
策略插件调用服务动词,并响应限定范围的 `goal/changed` 事件。续行消费方将 Round 准入为 `user/message` 事件,并携带 `GoalMessageSource`;普通的人类轮次绝不会增加 `roundsStarted`。消费方使用 `Agent` 接口和事件,不导入 `dsh-agent-loop`。
|
||||
|
||||
## 模型体验
|
||||
|
||||
@@ -43,16 +43,16 @@
|
||||
|
||||
#### Token 影响
|
||||
|
||||
每项保留的变更都会向派生历史增加一份完整快照,直到压缩将其遮蔽。完整快照让每条记录都能独立检查,但会重复目标和生命周期字段。
|
||||
每项保留的变更都会向派生历史增加一份完整快照,直到压缩(compaction)将其遮蔽。完整快照让每条记录都能独立检查,但会重复目标和生命周期字段。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
在一个 epoch 内仅追加:每项变更都位于可复用请求前缀和既有历史之后。压缩可能替换派生历史后缀,并移动可复用边界。
|
||||
|
||||
## 已知限制与暂缓工作
|
||||
## 已知限制与暂缓事项
|
||||
|
||||
- **只负责状态,不负责任务调度**:此包不决定已激活目标何时继续,不重试异常失败,也不取消活跃轮次;这些策略属于 agent seam 消费方。
|
||||
- **只有 round 数量预算**:`maxGoalRounds` 不计量 token、货币、墙上时间或提供方配额。
|
||||
- **只负责状态,不负责任务调度**:此包(package)不决定已启用续行的目标何时继续,不重试异常失败,也不取消活跃轮次;这些策略属于 agent seam 消费方。
|
||||
- **只有 Round 数量预算**:`maxGoalRounds` 不计量 token、货币、挂钟时间或提供方配额。
|
||||
- **没有独立评估器**:记录完成或阻塞的调用方拥有最终决定权;由评估器支持的认证暂缓到独立策略层。
|
||||
- **只有一个当前目标**:系统有意不支持并行目标或独立目标数据库;替换或清除后,历史仍可在会话日志中读取。
|
||||
- **信任进程内生产方**:能直接访问 `Session` 的插件可以追加伪造的 goal 来源数据。严格回放会检测错误或不一致的记录,并使 goal 访问从该记录起失败,直到日志修复;这是完整性检测,不是插件隔离。
|
||||
- **信任进程内生产方**:能直接访问 `Session` 的插件可以追加伪造的 goal 来源数据。严格回放会检测格式错误或不一致的记录,并使 goal 访问从该记录起失败,直到日志修复;这是完整性检测,不是插件隔离。
|
||||
|
||||
@@ -103,7 +103,7 @@ export function applyGoalProjection(state: GoalProjection | null, event: Session
|
||||
// Session-log data is a durable boundary: the static type promises the kind,
|
||||
// but a foreign or corrupted change record must degrade to same-reference,
|
||||
// never feed the zod parse in the registry drive.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- durable-boundary guard
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-condition -- durable-boundary guard
|
||||
if (change === undefined || change.kind !== 'goal/change') return state
|
||||
if (change.operation === 'clear') return null
|
||||
return {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class GoalError extends HarnessError {
|
||||
* @param code - stable machine-routable classification.
|
||||
*/
|
||||
// Keep the constructor to narrow HarnessError's string code at this boundary.
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor -- type-only narrowing
|
||||
// oxlint-disable-next-line typescript/no-useless-constructor -- type-only narrowing
|
||||
constructor(message: string, code: GoalErrorCode) {
|
||||
super(message, code)
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ function stubAgentForSession(session: Session): StubAgent {
|
||||
ctx: new Context(),
|
||||
get status() { return status },
|
||||
get acceptsNextStep() { return status === 'running' },
|
||||
send: () => {},
|
||||
updateInbox: () => 'not-found',
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input) {
|
||||
|
||||
@@ -38,6 +38,8 @@ function liveAgent(ctx: Context, session: Session): Agent {
|
||||
ctx,
|
||||
get status() { return status },
|
||||
get acceptsNextStep() { return false },
|
||||
send: () => {},
|
||||
updateInbox: () => 'not-found',
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input: UserMessage) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
# pnpm run verify-translation-pairing --write packages/goal/tool-goal/README.md
|
||||
README.md: aaed61dd517aeb2f94efa22c34c64d1068155d46
|
||||
README.zh.md: ca41900f1b157e51fec6804db6dc79e699bd1db9
|
||||
README.zh.md: 5365b64ef65fb3d3f00e19357327479ebd8285a8
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
[`ctx.goals`](../goal/README.md) 的面向模型控制接口:`get_goal`、`create_goal` 和 `update_goal`。[goal 工具 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-model-facing-goal-tools.md)负责权限拆分与 Codex 风格用户体验。
|
||||
[`ctx.goals`](../goal/README.md) 的面向模型控制接口:`get_goal`、`create_goal` 和 `update_goal`。[goal 工具 Agent Note(agent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-19-model-facing-goal-tools.md) 负责权限拆分与 Codex 风格用户体验。
|
||||
|
||||
## 工具
|
||||
|
||||
- `get_goal()` 返回当前 goal 或 `null`,包括比较并设置 id/revision、持久 phase、已经准入/受限的 goal round、任何 blocker reason,以及当前进程本地激活状态。
|
||||
- `create_goal(objective, max_goal_rounds?)` 从顶层用户直接轮次创建一个 goal。模型可以从长期 goal 意图中推断,而无需精确命令短语;非用户轮次和 subagent 会在执行时被拒绝。
|
||||
- `get_goal()` 返回当前 goal 或 `null`,包括比较并设置 id/revision、持久 phase、Goal Round 的已准入数/上限、任何 blocker reason,以及当前进程本地续行启用状态。
|
||||
- `create_goal(objective, max_goal_rounds?)` 根据顶层人类直接发起的轮次创建一个 goal。模型可以推断长期运行的 goal 意图,而无需精确命令短语;非人类轮次和 subagent 会在执行时被拒绝。
|
||||
- `update_goal(goal_id, revision, action, objective?, max_goal_rounds?, blocked_reason?)` 支持 `edit`、`pause`、`resume`、`complete` 和 `blocked`。替换值只属于 `edit`;`blocked_reason` 只有在 action 为 `blocked` 时才必填,并以稳定代码 `model-reported` 持久化。严格 schema 下的空字符串和零填充值视为省略,而有意义的值仍限定到各自 action。
|
||||
|
||||
所有调用都互斥,因此模型排序的批次能观察到更早变更及其新 revision。UI 客户端会收到纯通用卡片:`get_goal` 使用 read,变更使用 other。变更卡片选择第一个有意义的 action 值,否则显示 goal id,因此已接受的填充值绝不会产生空输入。
|
||||
|
||||
3 个规范值都与已经渲染给 Native 调用方的紧凑 JSON 一致:`{ goal: null }` 或 `{ goal: { id, revision, objective, phase, roundsStarted, maxGoalRounds, blockedReason? }, activation }`。因此,编程消费方无需解析渲染后的 JSON,即可收到相同领域结构。
|
||||
|
||||
自主 goal round 成功报告 `complete` 或 `blocked` 时,会用 `concludeTurn()` 标记该次工具执行,使物理轮次在该步骤后停止。用户直接变更绝不会贡献该停止决策:assistant 可以确认变更,并发的用户 steering 仍可进入循环。
|
||||
自主 Goal Round 成功报告 `complete` 或 `blocked` 时,会用 `concludeTurn()` 标记该次工具执行,使物理轮次在该步骤后停止。人类直接变更绝不会导致这种停止:assistant 可以确认变更,循环仍可接收并发的人类 steering(中途引导)。
|
||||
|
||||
## 权限
|
||||
|
||||
执行要求完全相同的活跃 `exec.agent`、其继承的 `AgentRegistry` initiator、running 状态与开放轮次。create、edit、pause 和 resume 还要求运行时根 agent 的当前轮次中存在已接受的 `{ kind: 'user' }` 消息或 steering 事件。持久 fork 谱系不会降低已恢复根 agent 的等级;活跃 subagent 所有权会降低。
|
||||
|
||||
`{ kind: 'user' }` 是宿主证明。`Agent.followup()` 与 `steer()` 会在调用方省略 source 时分配该值,因此插件、调度器与其他非用户生产方必须传入自己的 source,不能继承用户权限。
|
||||
`{ kind: 'user' }` 是宿主证明。`Agent.followup()` 与 `steer()` 会在调用方省略 source 时分配该值,因此插件、调度器与其他非人类生产方必须传入自己的 source,不能继承用户权限。
|
||||
|
||||
complete 与 blocked 还接受完全相同的当前 goal round:来源为 goal 的 `user/message`,其 id、revision 和 round 与折叠后的当前 goal 相等。在达到 `blockedAfterConsecutiveRounds` 前,goal-round 的 blocked 调用会被机械拒绝;模型判断同一条件是否确实持续,并必须在 `blocked_reason` 中说明。用户直接权限可以立即停止 goal。
|
||||
complete 与 blocked 还接受完全一致的当前 Goal Round:来源为 goal 的 `user/message`,其 id、revision 和 Round 编号与折叠后的当前 goal 相等。在达到 `blockedAfterConsecutiveRounds` 前,Goal Round 的 blocked 调用会被机械拒绝;模型判断同一条件是否确实持续,并必须在 `blocked_reason` 中说明。人类直接授权可以立即停止 goal。
|
||||
|
||||
## 配置
|
||||
|
||||
@@ -33,7 +33,7 @@ complete 与 blocked 还接受完全相同的当前 goal round:来源为 goal
|
||||
blockedAfterConsecutiveRounds: 3
|
||||
```
|
||||
|
||||
该值必须是正安全整数。它既提供模型自行阻塞的硬下限,也决定模型指引中点名的数量。
|
||||
该值必须是正的安全整数。它既提供模型自行报告阻塞的硬下限,也决定模型指引中指明的数值。
|
||||
|
||||
## 模型体验
|
||||
|
||||
@@ -41,7 +41,7 @@ complete 与 blocked 还接受完全相同的当前 goal round:来源为 goal
|
||||
|
||||
#### 模型看到的内容
|
||||
|
||||
固定 goal 策略说明何种用户语义意图值得创建 goal,要求更新前先精确读取 ref,解释会话 resume/fork 后如何重新激活,并限制完成/阻塞声明。配置的阈值会插入该指引。
|
||||
固定 goal 策略说明何种用户语义意图值得创建 goal,要求更新前先精确读取 ref,解释会话 resume/fork 后如何重新启用续行,并限制完成/阻塞声明。配置的阈值会插入该指引。
|
||||
|
||||
##### Goal 策略
|
||||
|
||||
@@ -55,26 +55,26 @@ Use goal tools for one long-running completion objective in the current session.
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
插件范围、配置阈值和指引文本不变时,前缀保持稳定。激活、资源释放或配置变更可能使此提示词章节的复用失效。
|
||||
插件范围、配置阈值和指引文本不变时,前缀保持稳定。启用、dispose(资源释放)或配置变更可能使此提示词章节的复用失效。
|
||||
|
||||
### 工具 schema 与结果
|
||||
|
||||
#### 模型看到的内容
|
||||
|
||||
生成的 [`get_goal`、`create_goal` 和 `update_goal` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-goal)。成功结果是紧凑 JSON。变更结果之后是工具批次结束后由 goal 领域产生的原始 `<goal_state>` 快照。结果中的 `activation` 是活跃观察值,绝不会成为回放权限依据。
|
||||
生成的 [`get_goal`、`create_goal` 和 `update_goal` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-goal)。成功结果是紧凑 JSON。变更结果之后是工具批次结束后由 goal 领域产生的原始 `<goal_state>` 快照。结果中的 `activation` 是实时观察值,绝不会成为回放权限依据。
|
||||
|
||||
#### Token 影响
|
||||
|
||||
固定 schema 成本,加上每次调用的一条紧凑结果。变更还会保留领域快照,直到压缩。
|
||||
固定 schema 成本,加上每次调用的一条紧凑结果。变更还会保留领域快照,直到压缩(compaction)。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
Schema 的定义与可见性不变时,前缀保持稳定。调用、结果和生成的 goal 快照会追加到可复用请求前缀之后,不会使更早条目失效。
|
||||
schema 的定义与可见性不变时,前缀保持稳定。调用、结果和生成的 goal 快照会追加到可复用请求前缀之后,不会使更早条目失效。
|
||||
|
||||
## 已知限制与暂缓工作
|
||||
## 已知限制与暂缓事项
|
||||
|
||||
- **语义意图仍由模型判断**:执行只能证明直接用户来源,无法证明请求是否足够重大而值得创建 goal。
|
||||
- **阻塞条件是否相同仍由模型判断**:运行时强制执行不同的已准入 round 计数,而不是障碍的语义等价性;独立评估器保持暂缓。
|
||||
- **不负责调度或直接用户呈现**:这些工具只变更状态;同会话驱动器与 [`dsh-command-goal`](../command-goal/README.md) 是同一领域的独立消费方。
|
||||
- **Goal-round 权限需要驱动器**:除非续行驱动器准入 goal 来源的用户轮次,否则自主 `complete`/`blocked` 路径不会启用;只挂载此工具包不会创建这些轮次。
|
||||
- **语义意图仍由模型判断**:执行只能证明人类直接来源,无法证明请求是否足够重大而值得创建 goal。
|
||||
- **阻塞条件是否相同仍由模型判断**:运行时强制统计互不重复的已准入 Goal Round,而不判断障碍在语义上是否等价;独立评估器的实现暂缓。
|
||||
- **不负责调度或直接面向人类呈现**:这些工具只变更状态;同会话驱动器与 [`dsh-command-goal`](../command-goal/README.md) 是同一领域的独立消费方。
|
||||
- **Goal Round 权限需要驱动器**:除非续行驱动器准入 goal 来源的用户轮次,否则自主 `complete`/`blocked` 路径不会启用;只挂载这个包(package)不会创建这些轮次。
|
||||
- **提示词注册与过滤相互独立**:某个范围可能隐藏工具,却保留指引,除非部署将两项注册限定在同一范围。
|
||||
|
||||
@@ -32,6 +32,8 @@ function stubAgent(rawId: string, supplied?: Session): StubAgent {
|
||||
get status() { return status },
|
||||
get acceptsNextStep() { return status === 'running' },
|
||||
ctx: new Context(),
|
||||
send: () => {},
|
||||
updateInbox: () => 'not-found',
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject(input) {
|
||||
|
||||
Reference in New Issue
Block a user