@deepseek-ai/dsh-goal 0.1.1-rc.2 → 0.1.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +131 -17
- package/README.zh.md +137 -23
- package/lib/index.js +170 -128
- package/lib/typert.host.js +111 -27
- package/lib/typert.remote-client.js +6 -6
- package/lib/types/index.d.ts +27 -18
- package/lib/types/index.js +169 -142
- package/lib/types/types.d.ts +14 -5
- package/package.json +26 -21
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/goal/goal/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 119c5e246494c7cb14c84b18e03ca04155f2158c
|
|
6
|
+
README.zh.md: f17d9fa6b84fff50c3c7263c92725959bde99775
|
package/README.md
CHANGED
|
@@ -1,45 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "The persisted same-session goal service for users and maintainers choosing, configuring, or debugging one durable completion objective per session."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-goal
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-goal` keeps one durable completion objective per agent session: the goal's text, phase, round count, and revision history live in the session log, so they survive session resume, fork, and process restarts. You can create, edit, pause, resume, complete, block, and clear a goal, and every mutation is compare-and-set, so a stale view cannot clobber newer state. A goal carries a round cap (default 256) that bounds automatic continuation, and a blocked goal keeps a stable policy code plus a human explanation. It is state, not a scheduler: the service decides nothing about when work continues, and continuation permission is process-local and never persisted. Choose it when one long-running objective should span many turns; skip it for routine single-turn work.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Mount `dsh-goal` whenever a session should remember one long-running completion objective across many turns and restarts. The package is a service: the model tools, the `/goal` command, and the continuation driver are separate packages that consume the same goal state, so mounting only this package stores and serves the goal without starting any work.
|
|
29
|
+
|
|
30
|
+
### When to use it
|
|
31
|
+
|
|
32
|
+
A goal suits one long-running completion objective that should continue across autonomous goal rounds — for example shipping a migration or fixing every failing documentation gate. Routine single-turn work should not create a goal. The service keeps at most one current goal per session: an unfinished goal must be edited, paused, resumed, blocked, or cleared before another takes its place, while a completed goal can be replaced directly.
|
|
33
|
+
|
|
34
|
+
### Set up the service
|
|
6
35
|
|
|
7
|
-
|
|
36
|
+
Load the package with a composition entry; the only deployment choice is the default round cap applied to creates that do not name their own.
|
|
8
37
|
|
|
9
38
|
```yaml
|
|
10
|
-
-
|
|
11
|
-
name: '@deepseek-ai/dsh-goal'
|
|
39
|
+
- name: '@deepseek-ai/dsh-goal'
|
|
12
40
|
config:
|
|
13
41
|
defaultMaxGoalRounds: 256
|
|
14
42
|
```
|
|
15
43
|
|
|
16
|
-
|
|
44
|
+
| Field | Default | Meaning |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `defaultMaxGoalRounds` | `256` | Round cap applied when a create request omits its own |
|
|
17
47
|
|
|
18
|
-
|
|
48
|
+
`defaultMaxGoalRounds` must be a positive safe integer; a create request that names its own cap overrides it. The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-goal) is the exhaustive source for every accepted field.
|
|
19
49
|
|
|
20
|
-
|
|
50
|
+
### Session projection
|
|
21
51
|
|
|
22
|
-
|
|
52
|
+
`GoalService` requires `ctx.sessionProjections` ([`@deepseek-ai/dsh-session-projection`](../../session/session-projection/README.md)) and registers the `goal` projection unit at startup; a composition that omits the projection registry cannot activate `ctx.goals`. The unit's version 6 host state retains the latest valid current goal, every previously used goal id, and the first strict replay failure. Its client view exposes the current goal or `null` before the first create and after a clear tombstone. The key merges into both `SessionProjectionStateMap` and `SessionProjectionMap`; carriers serve the client value on the history tail page and the `session/projection` push frame.
|
|
23
53
|
|
|
24
|
-
|
|
54
|
+
### Drive the lifecycle
|
|
55
|
+
|
|
56
|
+
A goal moves through four durable phases — `active`, `paused`, `blocked`, `complete` — plus a process-local flag that says whether automatic continuation is armed. The verbs:
|
|
57
|
+
|
|
58
|
+
| Operation | What it does |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `create` | Starts an active goal with an objective and round cap |
|
|
61
|
+
| `edit` | Changes the objective and/or round cap without changing the phase |
|
|
62
|
+
| `pause` | Stops automatic continuation and keeps the state |
|
|
63
|
+
| `resume` | Restarts continuation; also rearms an active goal after session resume or fork |
|
|
64
|
+
| `complete` | Marks the goal achieved and stops continuation |
|
|
65
|
+
| `block` | Records a stable blocker code and explanation |
|
|
66
|
+
| `clear` | Removes the current goal; its history stays in the session log |
|
|
67
|
+
|
|
68
|
+
Pause, completion, blocking, and clear all disarm continuation. Blocking is the one phase that keeps a policy-owned lower-kebab-case code and a free-form explanation, so provider limits, exhausted budgets, execution errors, and requests for human input share a single durable phase instead of multiplying lifecycle states. Resume accepts a stopped goal, or an active but disarmed one, only while the round cap has remaining capacity, and it clears any former blocker reason.
|
|
69
|
+
|
|
70
|
+
### What survives and what does not
|
|
71
|
+
|
|
72
|
+
Every accepted change is recorded durably in the session log — the only store of goal state — so goal state never depends on transient message delivery. After session resume or fork, the goal, its phase, its revisions, and its admitted-round count are all still there. Automatic continuation is the exception: an active goal is disarmed after any session-start edge, so the agent does not continue on its own until someone explicitly resumes it.
|
|
73
|
+
|
|
74
|
+
### Observing a goal
|
|
75
|
+
|
|
76
|
+
Consumers read the current goal with `ctx.goals.get(agent)` and receive a detached view: objective, phase, rounds started versus the cap, blocker reason when blocked, and whether continuation is armed. Mutations must carry the exact `{ id, revision }` from that view, so a consumer holding older state receives a clear stale-revision error instead of silently overwriting newer state:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
const view = ctx.goals.get(agent) // undefined when no goal is current
|
|
80
|
+
view.phase // 'active' | 'paused' | 'blocked' | 'complete'
|
|
81
|
+
view.roundsStarted, view.maxGoalRounds // continuation progress
|
|
82
|
+
view.activation // 'armed' | 'disarmed' — not persisted
|
|
83
|
+
```
|
|
25
84
|
|
|
26
|
-
|
|
85
|
+
-----
|
|
27
86
|
|
|
28
|
-
|
|
87
|
+
<a id="understand-the-implementation"></a>
|
|
88
|
+
## Understand the implementation
|
|
29
89
|
|
|
30
|
-
|
|
90
|
+
<details>
|
|
91
|
+
<summary>Implementation internals — click to expand</summary>
|
|
31
92
|
|
|
32
|
-
|
|
93
|
+
This section explains how the service realizes the behavior above; the observable contract is covered in [Use this package](#use-this-package).
|
|
33
94
|
|
|
34
|
-
|
|
95
|
+
### Design
|
|
35
96
|
|
|
97
|
+
- **Event-sourced state.** Every mutation appends a durable `goal/change` event (version 1) carrying the complete post-mutation snapshot; `clear` writes a revisioned tombstone. The session log is the only durable authority.
|
|
98
|
+
- **Compare-and-set mutations.** `ctx.goals` accepts only the exact live `Agent` registered under its id. `get()` returns a detached `GoalView`; mutations take a `GoalRef { id, revision }` and reject stale refs. Creation resolves the deployment default internally before committing.
|
|
99
|
+
- **Activation is process-local.** `armed` and `disarmed` live in a per-session cache and are never persisted. A fresh cache and every `agent/session-start` edge disarm continuation even when replay finds an active durable phase; `disarm()` removes authority without writing a revision or emitting a mutation.
|
|
100
|
+
- **Strict replay.** The fold derives lifecycle mutations only from `goal/change` and rejects malformed shapes, discontinuous revisions, illegal phase transitions, non-monotonic per-goal timestamps, and non-sequential admitted rounds. Positive rounds advance only on admitted goal-sourced `user/message` events, and mutation timestamps clamp against the preceding update when wall time moves backward.
|
|
101
|
+
- **Projection unit.** The package requires the projection registry and registers a strict `goal` unit. Its host state retains replay validation data and the first failure, while its client view exposes the latest valid whole goal or `null`; `GoalService` rejects access after a retained replay failure.
|
|
102
|
+
|
|
103
|
+
### Source map
|
|
104
|
+
|
|
105
|
+
| File | Role |
|
|
106
|
+
|---|---|
|
|
107
|
+
| [`src/index.ts`](src/index.ts) | Plugin entry: `GoalService`, config schema, mutations, activation cache, projection unit |
|
|
108
|
+
| [`src/domain.ts`](src/domain.ts) | Durable change payloads, `goal/changed` event, goal message-source attribution |
|
|
109
|
+
| [`src/types.ts`](src/types.ts) | Pure client-safe types: `GoalView`, `GoalSnapshot`, projection-key declaration |
|
|
110
|
+
| [`src/fold.ts`](src/fold.ts) | Strict replay fold and decoder for durable goal changes |
|
|
111
|
+
| [`src/runtime.ts`](src/runtime.ts) | `GoalId` brand, `GoalError` codes, change-version constant |
|
|
112
|
+
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion: independent incremental fold over every attached session |
|
|
113
|
+
|
|
114
|
+
### Events and attribution
|
|
115
|
+
|
|
116
|
+
`goal/changed` fires after the durable event commits, with listener failures contained; the payload carries the operation, the exact ref, and the fresh view (absent for a clear tombstone). Admitted continuation rounds are attributed through `GoalMessageSource { goalId, revision, round }` on the `user/message` event, which the strict fold validates as the next admitted round of the current goal.
|
|
117
|
+
|
|
118
|
+
</details>
|
|
119
|
+
|
|
120
|
+
-----
|
|
121
|
+
|
|
122
|
+
<a id="further-exploration"></a>
|
|
123
|
+
## Further Exploration
|
|
124
|
+
|
|
125
|
+
The package-level contract is enough for most consumers; read these when you need the surrounding domain and the design rationale.
|
|
126
|
+
|
|
127
|
+
- [Goal subsystem](../../../docs/subsystems/goal.md) — the goal types, durable change payloads, and generated service API.
|
|
128
|
+
- [Goal group map](../README.md) — the goal packages and how they compose.
|
|
129
|
+
- [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-goal) — every accepted config field and its source declaration.
|
|
130
|
+
- [Goal domain Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md) — the domain design, alternatives, and decisions.
|
|
131
|
+
|
|
132
|
+
-----
|
|
133
|
+
|
|
134
|
+
<a id="model-experience"></a>
|
|
36
135
|
## Model Experience
|
|
37
136
|
|
|
38
|
-
### Goal-state
|
|
137
|
+
### Goal-state mutations
|
|
39
138
|
|
|
40
139
|
#### What the model sees
|
|
41
140
|
|
|
42
|
-
Goal mutations do not inject model context. Tools such as `get_goal` return the current state, and a continuation consumer may render the objective and round state when it schedules model work.
|
|
141
|
+
Goal mutations do not inject model context. Tools such as `get_goal` return the current state, and a continuation consumer may render the objective and round state when it schedules model work.
|
|
43
142
|
|
|
44
143
|
#### Token effect
|
|
45
144
|
|
|
@@ -51,8 +150,23 @@ There is no KV-cache effect until another component exposes goal state in model-
|
|
|
51
150
|
|
|
52
151
|
## Known Limitations and Deferred Work
|
|
53
152
|
|
|
54
|
-
|
|
153
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
These limits define when the goal service is a poor fit or needs special care. They are current package constraints, not a task backlog.
|
|
157
|
+
|
|
158
|
+
- **State, not scheduling** — this package does not decide when an armed goal continues, retry abnormal failures, or cancel an active turn; those policies belong to consumer packages such as `dsh-goal-round-driver`.
|
|
55
159
|
- **Round-count budget only** — `maxGoalRounds` does not meter tokens, currency, wall time, or provider quotas.
|
|
56
160
|
- **No independent evaluator** — the caller that records completion or blocking is authoritative; evaluator-backed certification is deferred to a separate policy layer.
|
|
57
161
|
- **One current goal** — parallel objectives and a separate goal database are intentionally absent; history remains available in the session log after replacement or clear.
|
|
58
162
|
- **Trusted in-process producers** — a plugin with direct `Session` access can append counterfeit `goal/change` data. Strict replay detects malformed or inconsistent records and leaves goal access failed at that record until the log is repaired; this is integrity detection, not plugin isolation.
|
|
163
|
+
|
|
164
|
+
<a id="dev-note"></a>
|
|
165
|
+
### Dev Note
|
|
166
|
+
|
|
167
|
+
<details>
|
|
168
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
169
|
+
|
|
170
|
+
This Dev Note is working context for maintainers; it is explicitly non-authoritative. Open, undecided directions: an always-visible goal context plugin for deployments that want the objective in every model request, and evaluator-backed certification of completion and blocking claims.
|
|
171
|
+
|
|
172
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,58 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "面向选择、配置或排查同会话持久 goal 服务的用户与维护者:每会话一个持久的完成目标。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-goal
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-goal` 为每个 agent 会话保留一个持久的完成目标:目标的文本、phase、Round 数量与 revision 历史都保存在会话日志中,因此会话 resume(恢复)、fork 与进程重启后依然存在。你可以 create、edit、pause、resume、complete、block 和 clear 一个 goal,且每次变更都是比较并设置,陈旧的视图不会覆盖更新的状态。goal 带有 Round 上限(默认 256)以约束自动续行,被阻塞的 goal 会保留稳定的策略代码和面向人的说明。它是状态而非调度器:服务不决定工作何时继续,续行权限是进程本地的且绝不持久化。当单个长期目标需要横跨多轮时选择它;常规单轮工作不要使用。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
当会话需要在多轮与多次重启之间记住一个长期完成目标时,挂载 `dsh-goal`。本包是服务:模型工具、`/goal` 命令与续行驱动器都是消费同一 goal 状态的独立包,因此只挂载本包只会存储和提供 goal,不会启动任何工作。
|
|
29
|
+
|
|
30
|
+
### 何时使用
|
|
31
|
+
|
|
32
|
+
goal 适合一个需要跨自动 Goal Round 持续的长期完成目标——例如完成一次迁移,或修复所有失败的文档门禁。常规单轮工作不应创建 goal。服务每会话至多保留一个当前 goal:未完成的 goal 必须先 edit、pause、resume、block 或 clear,才能被另一个替代;已完成的 goal 可以直接被替换。
|
|
33
|
+
|
|
34
|
+
### 配置服务
|
|
6
35
|
|
|
7
|
-
|
|
36
|
+
通过组合配置项加载本包;唯一的部署选择是默认 Round 上限,应用于未自行指定上限的 create。
|
|
8
37
|
|
|
9
38
|
```yaml
|
|
10
|
-
-
|
|
11
|
-
name: '@deepseek-ai/dsh-goal'
|
|
39
|
+
- name: '@deepseek-ai/dsh-goal'
|
|
12
40
|
config:
|
|
13
41
|
defaultMaxGoalRounds: 256
|
|
14
42
|
```
|
|
15
43
|
|
|
16
|
-
|
|
44
|
+
| 字段 | 默认值 | 含义 |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `defaultMaxGoalRounds` | `256` | 当 create 请求省略上限时应用的 Round 上限 |
|
|
17
47
|
|
|
18
|
-
|
|
48
|
+
`defaultMaxGoalRounds` 必须是正的安全整数;指定了自身上限的 create 请求会覆盖它。生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-goal)是每个受支持字段的穷尽式真源。
|
|
19
49
|
|
|
20
|
-
|
|
50
|
+
### 会话投影
|
|
21
51
|
|
|
22
|
-
|
|
52
|
+
`GoalService` 要求组合提供 `ctx.sessionProjections`([`@deepseek-ai/dsh-session-projection`](../../session/session-projection/README.zh.md)),并在启动时注册 `goal` 投影单元;未组合投影注册表的组合无法激活 `ctx.goals`。该单元版本为 6,其宿主状态保留最新的有效当前 goal、所有曾使用的 goal id,以及第一次严格回放失败。客户端 view 提供当前 goal;首次 create 前与 clear tombstone 后为 `null`。该 key 同时合并到 `SessionProjectionStateMap` 与 `SessionProjectionMap`;载体通过历史尾页和 `session/projection` 推送帧提供客户端值。
|
|
23
53
|
|
|
24
|
-
|
|
54
|
+
### 驱动生命周期
|
|
55
|
+
|
|
56
|
+
goal 经历四种持久 phase——`active`、`paused`、`blocked`、`complete`——外加一个进程本地标志,表示自动续行是否已启用。动词如下:
|
|
57
|
+
|
|
58
|
+
| 操作 | 作用 |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `create` | 以目标和 Round 上限启动一个 active goal |
|
|
61
|
+
| `edit` | 修改目标和/或 Round 上限,不改变 phase |
|
|
62
|
+
| `pause` | 停止自动续行并保留状态 |
|
|
63
|
+
| `resume` | 重新开始续行;也用于会话 resume 或 fork 后重新启用 active goal |
|
|
64
|
+
| `complete` | 标记 goal 已完成并停止续行 |
|
|
65
|
+
| `block` | 记录稳定的 blocker 代码与说明 |
|
|
66
|
+
| `clear` | 移除当前 goal;其历史保留在会话日志中 |
|
|
67
|
+
|
|
68
|
+
pause、complete、block 和 clear 都会停用续行。block 是唯一保留策略自有 lower-kebab-case 代码与自由文本说明的 phase,因此提供方限制、预算耗尽、执行错误与请求人工输入共用一种持久 phase,而不是扩增生命周期状态。resume 只在 Round 上限仍有剩余容量时接受已停止的 goal,或 active 但已停用续行的 goal,并清除任何先前的 blocker reason。
|
|
69
|
+
|
|
70
|
+
### 什么会保留,什么不会
|
|
71
|
+
|
|
72
|
+
每项被接受的变更都会持久记录到会话日志——goal 状态的唯一存储——因此 goal 状态绝不依赖临时消息投递。会话 resume 或 fork 后,goal、其 phase、其 revision 与已准入 Round 数量都仍然存在。自动续行是例外:任何会话开始边界之后,`active` 的 goal 都会被停用续行——在有人显式 resume 之前,agent 不会自行继续。
|
|
73
|
+
|
|
74
|
+
### 观察 goal
|
|
75
|
+
|
|
76
|
+
消费方用 `ctx.goals.get(agent)` 读取当前 goal,获得脱离内部状态的视图:目标、phase、已开始与上限 Round 数量、被阻塞时的 blocker reason,以及续行是否已启用。变更必须携带该视图中的精确 `{ id, revision }`,因此持有旧状态的消费方会收到清晰的陈旧 revision 错误,而不是静默覆盖更新的状态:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
const view = ctx.goals.get(agent) // undefined when no goal is current
|
|
80
|
+
view.phase // 'active' | 'paused' | 'blocked' | 'complete'
|
|
81
|
+
view.roundsStarted, view.maxGoalRounds // continuation progress
|
|
82
|
+
view.activation // 'armed' | 'disarmed' — not persisted
|
|
83
|
+
```
|
|
25
84
|
|
|
26
|
-
|
|
85
|
+
-----
|
|
27
86
|
|
|
28
|
-
|
|
87
|
+
<a id="understand-the-implementation"></a>
|
|
88
|
+
## 理解实现
|
|
29
89
|
|
|
30
|
-
|
|
90
|
+
<details>
|
|
91
|
+
<summary>实现细节——点击展开</summary>
|
|
31
92
|
|
|
32
|
-
|
|
93
|
+
本节解释服务如何实现上述行为;可观察约定已在[使用本包](#use-this-package)中说明。
|
|
33
94
|
|
|
34
|
-
|
|
95
|
+
### 设计
|
|
35
96
|
|
|
97
|
+
- **事件溯源状态。** 每次变更都追加持久的 `goal/change` 事件(版本 1),携带变更后的完整快照;clear 写入带 revision 的 tombstone。会话日志是唯一的持久权威。
|
|
98
|
+
- **比较并设置的变更。** `ctx.goals` 只接受以对应 id 注册的完全相同的活跃 `Agent` 实例。`get()` 返回脱离状态的 `GoalView`;变更携带 `GoalRef { id, revision }` 并拒绝陈旧引用。创建在提交前于内部解析部署默认值。
|
|
99
|
+
- **续行启用状态是进程本地的。** `armed` 与 `disarmed` 保存在每会话缓存中,绝不持久化。新缓存与每次 `agent/session-start` 边界都会停用续行,即使回放发现持久 phase 为 active;`disarm()` 移除续行权限,不写入 revision 也不发出变更事件。
|
|
100
|
+
- **严格回放。** 折叠只从 `goal/change` 派生生命周期变更,并拒绝形状错误、不连续 revision、非法 phase 转换、每目标时间戳非单调,以及不连续的已准入 Round。只有已准入的来源为 goal 的 `user/message` 事件会推进正数 Round;挂钟时间倒退时,变更时间戳会限制在不早于上一次更新的值。
|
|
101
|
+
- **投影单元。** 本包要求提供投影注册表,并注册一个严格的 `goal` 单元。其宿主状态保留回放校验数据与第一次失败,客户端 view 提供最新有效的完整 goal 或 `null`;保留回放失败后,`GoalService` 会拒绝访问。
|
|
102
|
+
|
|
103
|
+
### 源码地图
|
|
104
|
+
|
|
105
|
+
| 文件 | 职责 |
|
|
106
|
+
|---|---|
|
|
107
|
+
| [`src/index.ts`](src/index.ts) | 插件入口:`GoalService`、config schema、变更、续行启用缓存、投影单元 |
|
|
108
|
+
| [`src/domain.ts`](src/domain.ts) | 持久变更载荷、`goal/changed` 事件、goal 消息来源归属 |
|
|
109
|
+
| [`src/types.ts`](src/types.ts) | 纯客户端安全类型:`GoalView`、`GoalSnapshot`、投影键声明 |
|
|
110
|
+
| [`src/fold.ts`](src/fold.ts) | 持久 goal 变更的严格回放折叠与解码器 |
|
|
111
|
+
| [`src/runtime.ts`](src/runtime.ts) | `GoalId` 品牌、`GoalError` 代码、变更版本常量 |
|
|
112
|
+
| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生:对每个已挂接会话的独立增量折叠 |
|
|
113
|
+
|
|
114
|
+
### 事件与归属
|
|
115
|
+
|
|
116
|
+
`goal/changed` 在持久事件提交后触发,监听器失败会被隔离;载荷携带操作、精确 ref 与最新视图(clear tombstone 时省略)。已准入的续行 Round 通过 `user/message` 事件上的 `GoalMessageSource { goalId, revision, round }` 归属,严格折叠会将其验证为当前 goal 的下一个已准入 Round。
|
|
117
|
+
|
|
118
|
+
</details>
|
|
119
|
+
|
|
120
|
+
-----
|
|
121
|
+
|
|
122
|
+
<a id="further-exploration"></a>
|
|
123
|
+
## 进一步探索
|
|
124
|
+
|
|
125
|
+
包级约定对大多数消费方已经足够;需要了解周边领域与设计理由时阅读以下页面。
|
|
126
|
+
|
|
127
|
+
- [goal 子系统](../../../docs/subsystems/goal.zh.md)——goal 类型、持久的变更载荷与生成的服务 API。
|
|
128
|
+
- [goal 组地图](../README.zh.md)——goal 各包及其组合方式。
|
|
129
|
+
- [生成的配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-goal)——每个受支持配置字段及其源声明。
|
|
130
|
+
- [goal 领域 Agent Note](../../../.agents/notes/implemented/feature/2026-07-19-persisted-same-session-goal-domain.zh.md)——领域设计、备选方案与决策。
|
|
131
|
+
|
|
132
|
+
-----
|
|
133
|
+
|
|
134
|
+
<a id="model-experience"></a>
|
|
36
135
|
## 模型体验
|
|
37
136
|
|
|
38
137
|
### 目标状态变更
|
|
39
138
|
|
|
40
|
-
####
|
|
139
|
+
#### 模型看到什么
|
|
41
140
|
|
|
42
|
-
Goal 变更不会注入模型上下文。`get_goal`
|
|
141
|
+
Goal 变更不会注入模型上下文。`get_goal` 等工具返回当前状态;续行消费方可以在调度模型工作时渲染目标与 Round 状态。
|
|
43
142
|
|
|
44
143
|
#### Token 影响
|
|
45
144
|
|
|
46
|
-
Goal 变更事件本身不增加模型 token
|
|
145
|
+
Goal 变更事件本身不增加模型 token。工具结果与续行调度提示词各自暴露的状态会分别计入 token 用量。
|
|
47
146
|
|
|
48
147
|
#### KV Cache 影响
|
|
49
148
|
|
|
50
149
|
在其他组件把 goal 状态暴露为模型可见输入之前,不会影响 KV Cache。
|
|
51
150
|
|
|
52
|
-
##
|
|
151
|
+
## 已知限制与延期工作
|
|
152
|
+
|
|
153
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
这些限制说明 goal 服务何时不合适或需要特别注意。它们是当前包约束,不是任务积压。
|
|
157
|
+
|
|
158
|
+
- **只负责状态,不负责任务调度**——本包不决定已启用续行的 goal 何时继续,不重试异常失败,也不取消活跃轮次;这些策略属于 `dsh-goal-round-driver` 等消费方包。
|
|
159
|
+
- **只有 Round 数量预算**——`maxGoalRounds` 不计量 token、货币、挂钟时间或提供方配额。
|
|
160
|
+
- **没有独立评估器**——记录完成或阻塞的调用方拥有最终决定权;由评估器支持的认证暂缓到独立策略层。
|
|
161
|
+
- **只有一个当前 goal**——系统有意不支持并行目标或独立 goal 数据库;替换或清除后,历史仍可在会话日志中读取。
|
|
162
|
+
- **信任进程内生产方**——能直接访问 `Session` 的插件可以追加伪造的 `goal/change` 数据。严格回放会检测格式错误或不一致的记录,并使 goal 访问从该记录起失败,直到日志修复;这是完整性检测,不是插件隔离。
|
|
163
|
+
|
|
164
|
+
<a id="dev-note"></a>
|
|
165
|
+
### 开发备注
|
|
166
|
+
|
|
167
|
+
<details>
|
|
168
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
169
|
+
|
|
170
|
+
本开发备注是维护者的工作上下文,明确不具权威性。开放且未决的方向:为需要在每个模型请求中看到目标的部署提供始终可见的 goal 上下文插件,以及由评估器支持的完成与阻塞认证。
|
|
53
171
|
|
|
54
|
-
|
|
55
|
-
- **只有 Round 数量预算**:`maxGoalRounds` 不计量 token、货币、挂钟时间或提供方配额。
|
|
56
|
-
- **没有独立评估器**:记录完成或阻塞的调用方拥有最终决定权;由评估器支持的认证暂缓到独立策略层。
|
|
57
|
-
- **只有一个当前目标**:系统有意不支持并行目标或独立目标数据库;替换或清除后,历史仍可在会话日志中读取。
|
|
58
|
-
- **信任进程内生产方**:能直接访问 `Session` 的插件可以追加伪造的 `goal/change` 数据。严格回放会检测格式错误或不一致的记录,并使 goal 访问从该记录起失败,直到日志修复;这是完整性检测,不是插件隔离。
|
|
172
|
+
</details>
|