refactor(goal): persist state with domain events

This commit is contained in:
_Kerman
2026-07-31 22:52:18 +08:00
parent b6cf9298e3
commit 1a09174987
48 changed files with 354 additions and 650 deletions
+2 -2
View File
@@ -2,5 +2,5 @@
# 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 packages/goal/command-goal/README.md
README.md: 47f81a5ae303d3587c0af1a26407f0f1f0ba0d88
README.zh.md: f5d22fa4889da8b7a1e2ac73e78ebe76714b8d42
README.md: 485a41abb22297f8018dceba258ec32692a28500
README.zh.md: 819f635b5c7c7f94109c1f076e7ed84b22ad96dc
+4 -4
View File
@@ -17,7 +17,7 @@ Human-facing `/goal` control over [`ctx.goals`](../goal/README.md). The plugin r
Control words are case-insensitive only when they occupy the complete input. Every other non-empty suffix is an objective, so `/goal pause after verification` creates that literal objective. The goal domain trims and validates objectives. Because the generic command plane has no modal editor or confirmation primitive, `edit` takes its replacement inline and an unfinished replacement returns a direct error instructing the user to edit or clear.
Expected domain rejections become stable direct command errors without exposing branded ids or revisions. Unexpected implementation failures still reject dispatch so adapters can report them as command failures. Generic command text and output remain live UI state; `dsh-goal` persists every accepted mutation through a durable inbox insertion and independently queues its model-facing context.
Expected domain rejections become stable direct command errors without exposing branded ids or revisions. Unexpected implementation failures still reject dispatch so adapters can report them as command failures. Generic command text and output remain live UI state; `dsh-goal` persists every accepted mutation through its own durable `goal/change` event.
## Composition
@@ -40,15 +40,15 @@ The TUI app enables the complete persisted-goal stack and this command by defaul
#### What the model sees
The slash input and direct status/error output are absent from model requests. An accepted mutation queues the goal domain's raw `<goal_state>` snapshot or clear tombstone; the model sees it only if a later pre-step admits that context. The mutation remains durable if the queued message is discarded, and presentation text is never logged.
The slash input, mutation, and direct status/error output are absent from model requests. The goal domain records the mutation as `goal/change`; an enabled same-session driver may expose the resulting state in a later continuation prompt. Presentation text is never logged.
#### Token effect
Reading status or receiving a direct command error adds no model tokens. An admitted mutation context adds the goal domain's retained full snapshot, while one discarded before admission adds none; an enabled same-session driver may add later goal-round prompts.
Reading status, mutating a goal, or receiving a direct command error adds no model tokens. An enabled same-session driver may add later goal-round prompts.
#### KV Cache effect
Command discovery and direct output do not affect the cache. An admitted mutation context appends after the reusable history prefix; later compaction may replace the derived-history suffix.
Command discovery, mutations, and direct output do not affect the cache. Later continuation prompts follow the driver's ordinary request history.
## Known Limitations and Deferred Work
+4 -4
View File
@@ -17,7 +17,7 @@
只有控制词占据完整输入时才不区分大小写。其他任何非空后缀都属于目标,因此 `/goal pause after verification` 会创建该字面目标。goal 领域会去除目标首尾空白并进行验证。由于通用命令平面没有模态编辑器或确认原语,`edit` 会内联接收替换内容;若试图替换未完成的 goal,则直接返回错误,提示用户执行 edit 或 clear。
可预期的领域拒绝会变成稳定的直接命令错误,不公开带品牌类型的 id 或 revision。意外实现失败仍会 reject 分发,使适配器能将其报告为命令失败。通用命令文本和输出仍属于实时 UI 状态;`dsh-goal` 通过持久 inbox 插入项持久化每项已接受变更,并单独将其面向模型的上下文排队。
可预期的领域拒绝会变成稳定的直接命令错误,不公开带品牌类型的 id 或 revision。意外实现失败仍会 reject 分发,使适配器能将其报告为命令失败。通用命令文本和输出仍属于实时 UI 状态;`dsh-goal` 通过自有的持久 `goal/change` 事件记录每项已接受变更。
## 组合
@@ -40,15 +40,15 @@ TUI 应用默认启用完整的持久 goal 栈和此命令。ACP(Agent Client
#### 模型看到的内容
斜杠输入与直接状态/错误输出不会进入模型请求。已接受的变更会将 goal 领域的原始 `<goal_state>` 快照或 clear tombstone 排队;只有后续 pre-step 准入该上下文时,模型才会看到它。如果已排队的消息被丢弃,变更仍然持久;呈现文本绝不会记录到日志中。
斜杠输入、变更以及直接状态/错误输出不会进入模型请求。Goal 领域把变更记录为 `goal/change`;已启用的同会话驱动器可以在后续继续执行提示词中暴露结果状态。呈现文本绝不会记录到日志中。
#### Token 影响
读取状态或收到直接命令错误不会增加模型 token。获准的变更上下文会增加 goal 领域保留的完整快照,准入前被丢弃的上下文则不会增加;已启用的同会话驱动器还可能增加后续 Goal Round 提示词。
读取状态、变更 goal 或收到直接命令错误不会增加模型 token。已启用的同会话驱动器可能增加后续 Goal Round 提示词。
#### KV Cache 影响
命令发现与直接输出不会影响缓存。获准的变更上下文会追加到可复用历史前缀之后;后续压缩可能替换派生历史后缀。
命令发现、变更与直接输出不会影响缓存。后续继续执行提示词遵循驱动器的普通请求历史。
## 已知限制与暂缓事项
@@ -126,7 +126,7 @@ describe('/goal human command', () => {
expect(created.text).toContain('Rounds: 0/256')
expect(created.text).toContain('Activation: armed')
expect(test.ctx.goals.get(test.agent)?.objective).toBe('finish the release')
expect(domainEvents(test.session).map(event => event.type)).toEqual(['agent/inbox/spliced'])
expect(domainEvents(test.session).map(event => event.type)).toEqual(['goal/change'])
const count = domainEvents(test.session).length
await expect(run(test, ' replacement')).resolves.toEqual({