@chanlerdev/scorel 0.0.1
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.md +110 -0
- package/dist/index.js +6675 -0
- package/dist/index.js.map +7 -0
- package/docs/CHANGELOG.md +12 -0
- package/docs/README.md +116 -0
- package/docs/ROADMAP.md +669 -0
- package/docs/SHIP.md +242 -0
- package/docs/spec/channels.md +156 -0
- package/docs/spec/client.md +326 -0
- package/docs/spec/daemon.md +408 -0
- package/docs/spec/events.md +423 -0
- package/docs/spec/extensions.md +255 -0
- package/docs/spec/relay.md +391 -0
- package/docs/spec/runtime.md +251 -0
- package/docs/spec/session.md +380 -0
- package/docs/spec/ship/S0001-docs-baseline.md +41 -0
- package/docs/spec/ship/S0002-package-skeleton.md +56 -0
- package/docs/spec/ship/S0003-protocol-contracts.md +49 -0
- package/docs/spec/ship/S0004-session-core.md +50 -0
- package/docs/spec/ship/S0005-runtime-loop.md +48 -0
- package/docs/spec/ship/S0006-embedded-daemon-client.md +51 -0
- package/docs/spec/ship/S0007-cli-alpha.md +49 -0
- package/docs/spec/ship/S0008-coding-tools.md +107 -0
- package/docs/spec/ship/S0009-code-discovery-tools.md +82 -0
- package/docs/spec/ship/S0010-todo-tool-and-cli.md +81 -0
- package/docs/spec/ship/S0011-coding-agent-alpha-smoke.md +110 -0
- package/docs/spec/ship/S0012-coding-tools-maturity.md +143 -0
- package/docs/spec/ship/S0013-local-daemon-protocol.md +57 -0
- package/docs/spec/ship/S0014-local-daemon-lifecycle.md +64 -0
- package/docs/spec/ship/S0015-local-attach-and-broadcast.md +58 -0
- package/docs/spec/ship/S0016-local-daemon-resync-smoke.md +60 -0
- package/docs/spec/ship/S0017-grep-files-output-mode.md +49 -0
- package/docs/spec/ship/S0018-daemon-entrypoint-smoke.md +48 -0
- package/docs/spec/ship/S0019-remote-transport-contract.md +59 -0
- package/docs/spec/ship/S0020-remote-websocket-server.md +56 -0
- package/docs/spec/ship/S0021-remote-websocket-client-transport.md +55 -0
- package/docs/spec/ship/S0022-remote-daemon-cli-lifecycle.md +60 -0
- package/docs/spec/ship/S0023-remote-control-e2e-validation.md +66 -0
- package/docs/spec/ship/S0024-remote-attach-interactive-stream.md +49 -0
- package/docs/spec/ship/S0025-remote-attach-session-event-view.md +57 -0
- package/docs/spec/ship/S0026-attach-project-cache-and-dual-seq-reconnect.md +87 -0
- package/docs/spec/ship/S0027-session-diagnostics-log.md +77 -0
- package/docs/spec/ship/S0028-client-attach-diagnostics-log.md +70 -0
- package/docs/spec/ship/S0029-project-index-for-session-lookup.md +119 -0
- package/docs/spec/ship/S0030-webui-product-intent.md +73 -0
- package/docs/spec/ship/S0031-daemon-projectslug-rule.md +72 -0
- package/docs/spec/ship/S0032-daemon-protocol-completion.md +123 -0
- package/docs/spec/ship/S0033-webui-skeleton-routing.md +92 -0
- package/docs/spec/ship/S0034-webui-device-settings.md +121 -0
- package/docs/spec/ship/S0035-webui-device-handshake.md +83 -0
- package/docs/spec/ship/S0036-webui-project-session-sync.md +70 -0
- package/docs/spec/ship/S0037-webui-chatbox-v1.md +97 -0
- package/docs/spec/ship/S0038-webui-cancel-multiclient.md +65 -0
- package/docs/spec/ship/S0039-webui-e2e-newchat.md +74 -0
- package/docs/spec/ship/S0040-webui-codex-visual-tokens.md +227 -0
- package/docs/spec/ship/S0041-webui-markdown-and-tool-block.md +248 -0
- package/docs/spec/ship/S0042-webui-streaming-ux-autoscroll.md +130 -0
- package/docs/spec/ship/S0043-startup-ergonomics.md +278 -0
- package/docs/spec/ship/S0044-webui-chatbox-rebuild.md +556 -0
- package/docs/spec/ship/S0045-webui-card-sidebar-and-session-fixes.md +469 -0
- package/docs/spec/ship/S0046-webui-empty-composer-and-lazy-session.md +428 -0
- package/docs/spec/ship/S0047-webui-project-hover-newchat-and-dynamic-greeting.md +176 -0
- package/docs/spec/ship/S0048-device-level-host-project-registry.md +253 -0
- package/docs/spec/ship/S0049-webui-add-project-directory-browser.md +217 -0
- package/docs/spec/ship/S0050-instruction-snapshot-and-agents-assembly.md +338 -0
- package/docs/spec/ship/S0051-harness-item-and-system-reminder.md +190 -0
- package/docs/spec/ship/S0052-follow-up-queue-and-dual-loop.md +195 -0
- package/docs/spec/ship/S0053-skill-index-and-skill-tool.md +252 -0
- package/docs/spec/ship/S0054-webui-running-message-behavior.md +72 -0
- package/docs/spec/ship/S0055-webui-composer-acceptance-and-queue-strip.md +68 -0
- package/docs/spec/ship/S0056-relay-and-hosted-webui-contract.md +106 -0
- package/docs/spec/ship/S0057-relay-service-protocol-skeleton.md +161 -0
- package/docs/spec/ship/S0058-host-outbound-relay-and-pair-command.md +138 -0
- package/docs/spec/ship/S0059-relay-transport-and-hosted-webui-connector.md +140 -0
- package/docs/spec/ship/S0060-relay-hosted-webui-e2e-validation.md +132 -0
- package/docs/spec/ship/S0060-relay-hosted-webui-e2e-validation.verification.md +90 -0
- package/docs/spec/ship/S0061-hosted-defaults-and-cli-command-surface.md +208 -0
- package/docs/spec/ship/S0062-npm-package-and-release-workflow.md +166 -0
- package/docs/spec/tools.md +173 -0
- package/package.json +51 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# S0050 — Instruction Snapshot And AGENTS.md Assembly
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
把 Scorel 当前 `systemPrompt = undefined` 的 runtime 路径升级为正式的 harness input assembly:
|
|
6
|
+
|
|
7
|
+
- session 初始化时发现并装配 `AGENTS.md`
|
|
8
|
+
- 生成一份冻结的 `instruction_snapshot`
|
|
9
|
+
- 将其作为一等 PersistentEvent 写入 session JSONL
|
|
10
|
+
- 后续 turn 从 snapshot 派生 provider-level `systemPrompt`
|
|
11
|
+
- 当前 session 内 system prompt 不因磁盘文件变动而漂移
|
|
12
|
+
|
|
13
|
+
本 spec 只定义 **instruction snapshot 与 runtime 接线**。不在本轮引入 GUI、HTTP API、自动刷新 snapshot 或 `<system-reminder>` 扩展语义。
|
|
14
|
+
|
|
15
|
+
## Why Now
|
|
16
|
+
|
|
17
|
+
当前 `M7` 已被定义为 Agent Runtime Quality。现状存在一个明确缺口:
|
|
18
|
+
|
|
19
|
+
- `packages/core/src/runtime/index.ts` 已支持 `executeTurn(context, systemPrompt, options)`
|
|
20
|
+
- `packages/core/src/provider/pi-ai.ts` 已支持把 `systemPrompt` 作为独立 provider 字段传给 pi-ai
|
|
21
|
+
- 但 `packages/daemon/src/index.ts` 仍以 `undefined` 调用 runtime
|
|
22
|
+
|
|
23
|
+
结果是:
|
|
24
|
+
|
|
25
|
+
- `AGENTS.md` 尚未进入真实产品主链路
|
|
26
|
+
- session 恢复、clone、branch、审计都无法回答“这个会话当时到底吃了哪份 instruction set”
|
|
27
|
+
- 未来 memory / workspace summary / runtime guidance 没有稳定挂点
|
|
28
|
+
|
|
29
|
+
在继续做 `<system-reminder>`、diagnostics、eval 之前,必须先把 session-scoped instruction snapshot 模型锁定。
|
|
30
|
+
|
|
31
|
+
## Scope
|
|
32
|
+
|
|
33
|
+
### 1. AGENTS.md Discovery
|
|
34
|
+
|
|
35
|
+
V1 discovery 规则固定如下:
|
|
36
|
+
|
|
37
|
+
- 发现基准是 session 初始化时的当前 `cwd`
|
|
38
|
+
- 从 `cwd` 逐级向上查找 project-scope `AGENTS.md`
|
|
39
|
+
- 如果 `cwd` 在 Git repository 内,project walk 在最近的 Git root 停止
|
|
40
|
+
- 如果 `cwd` 不在 Git repository 内,project walk 在用户 home `~` 前停止;不把 home 自身作为 project scope 读取
|
|
41
|
+
- 额外读取 `~/.scorel/AGENTS.md` 作为用户级全局源
|
|
42
|
+
- 所有命中的 `AGENTS.md` **全部加载**,不是只取最近一个
|
|
43
|
+
- discovery 结果在 session 初始化时冻结;当前 session 后续不动态重算
|
|
44
|
+
|
|
45
|
+
优先级模型:
|
|
46
|
+
|
|
47
|
+
- 高层目录先发现,低层目录后发现
|
|
48
|
+
- 更接近当前 `cwd` 的文件优先级更高
|
|
49
|
+
- 用户级全局源独立于 project walk;它不是 project-scope parent
|
|
50
|
+
- 当前 V1 只支持 `AGENTS.md`
|
|
51
|
+
- 不支持:
|
|
52
|
+
- `AGENTS.override.md`
|
|
53
|
+
- `SCOREL.md`
|
|
54
|
+
- `scrolls.md`
|
|
55
|
+
- fallback filenames
|
|
56
|
+
- include/import 展开
|
|
57
|
+
|
|
58
|
+
### 2. First-Class `instruction_snapshot` PersistentEvent
|
|
59
|
+
|
|
60
|
+
协议新增一等 PersistentEvent:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
interface InstructionSnapshotEvent extends PersistentEventBase {
|
|
64
|
+
type: "instruction_snapshot";
|
|
65
|
+
snapshot: InstructionSnapshot;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
它的语义是:
|
|
70
|
+
|
|
71
|
+
- 记录一个 session 初始化时冻结下来的 instruction assembly 结果
|
|
72
|
+
- 用于 resume、clone、branch、audit、diagnostics 和 runtime system prompt 派生
|
|
73
|
+
- 不直接作为普通 message 进入 LLM context
|
|
74
|
+
|
|
75
|
+
V1 规则:
|
|
76
|
+
|
|
77
|
+
- 一个 session 默认只追加一条 `instruction_snapshot`
|
|
78
|
+
- 追加时机是:
|
|
79
|
+
- 首次 user message 持久化前或紧邻其前
|
|
80
|
+
- 保证该 snapshot 在 JSONL 中先于首个 user turn 出现
|
|
81
|
+
- 不支持 session 中途自动刷新 snapshot
|
|
82
|
+
|
|
83
|
+
### 3. Structured Snapshot Schema
|
|
84
|
+
|
|
85
|
+
`instruction_snapshot` 不存一段无结构大字符串,而存结构化 section。
|
|
86
|
+
|
|
87
|
+
V1 section 顺序固定为:
|
|
88
|
+
|
|
89
|
+
1. `baseline`
|
|
90
|
+
2. `agents`
|
|
91
|
+
3. `memory`
|
|
92
|
+
4. `workspace`
|
|
93
|
+
5. `environment`
|
|
94
|
+
6. `time`
|
|
95
|
+
|
|
96
|
+
建议协议形态:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
type InstructionSectionKind =
|
|
100
|
+
| "baseline"
|
|
101
|
+
| "agents"
|
|
102
|
+
| "memory"
|
|
103
|
+
| "workspace"
|
|
104
|
+
| "environment"
|
|
105
|
+
| "time";
|
|
106
|
+
|
|
107
|
+
interface InstructionSource {
|
|
108
|
+
sourceType: "builtin" | "agents_md" | "memory";
|
|
109
|
+
path?: string;
|
|
110
|
+
scope?: "global_user" | "project";
|
|
111
|
+
priority?: number;
|
|
112
|
+
content?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface InstructionSection {
|
|
116
|
+
kind: InstructionSectionKind;
|
|
117
|
+
frozenAt: number;
|
|
118
|
+
sources?: InstructionSource[];
|
|
119
|
+
renderedBlock: string;
|
|
120
|
+
data?: Record<string, unknown>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface InstructionSnapshot {
|
|
124
|
+
version: 1;
|
|
125
|
+
cwd: string;
|
|
126
|
+
sections: InstructionSection[];
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
V1 约束:
|
|
131
|
+
|
|
132
|
+
- 所有 section 以固定顺序写入 snapshot
|
|
133
|
+
- 每个 section 至少保留 `kind`、`frozenAt`、`renderedBlock`
|
|
134
|
+
- `agents` section 必须保留来源块:
|
|
135
|
+
- `path`
|
|
136
|
+
- `scope`
|
|
137
|
+
- `priority`
|
|
138
|
+
- `content`
|
|
139
|
+
- `memory`、`workspace`、`environment`、`time` 即使当下内容很轻,也必须进入结构化 schema,而不是以后再另起另一套快照模型
|
|
140
|
+
|
|
141
|
+
### 4. Section Meaning
|
|
142
|
+
|
|
143
|
+
#### `baseline`
|
|
144
|
+
|
|
145
|
+
Scorel 自带的静态系统提示词,不来自用户文件。
|
|
146
|
+
|
|
147
|
+
包括但不限于:
|
|
148
|
+
|
|
149
|
+
- agent/product identity
|
|
150
|
+
- 输出与安全高层原则
|
|
151
|
+
- 工具使用的高层纪律
|
|
152
|
+
- `<system-reminder>` 解释性声明
|
|
153
|
+
|
|
154
|
+
这里冻结的是 **baseline prompt block**,不是未来所有实现细节的不可变版本数据库。
|
|
155
|
+
|
|
156
|
+
#### `agents`
|
|
157
|
+
|
|
158
|
+
`AGENTS.md` discovery 与装配结果。
|
|
159
|
+
|
|
160
|
+
要求:
|
|
161
|
+
|
|
162
|
+
- 以带来源分块的形式保存
|
|
163
|
+
- `renderedBlock` 是最终进入 provider-level system prompt 的 AGENTS block
|
|
164
|
+
- 当前 V1 不做 include/import 扩展
|
|
165
|
+
|
|
166
|
+
#### `memory`
|
|
167
|
+
|
|
168
|
+
进入 system prompt 的 memory block。
|
|
169
|
+
|
|
170
|
+
V1 可以先接入最小来源,甚至为空 block,但 schema 必须预留该 section。后续 memory specs 只能扩展其来源,不应再改变 snapshot 总模型。
|
|
171
|
+
|
|
172
|
+
#### `workspace`
|
|
173
|
+
|
|
174
|
+
工作区结构摘要,而不是全量目录树。
|
|
175
|
+
|
|
176
|
+
V1 建议只包含:
|
|
177
|
+
|
|
178
|
+
- `cwd`
|
|
179
|
+
- repo root / workspace root(如可得)
|
|
180
|
+
- monorepo/workspace 摘要
|
|
181
|
+
- 关键顶层模块/目录摘要
|
|
182
|
+
|
|
183
|
+
不要把 `find .` 或大体量树结构塞进该 section。
|
|
184
|
+
|
|
185
|
+
#### `environment`
|
|
186
|
+
|
|
187
|
+
运行环境摘要,例如:
|
|
188
|
+
|
|
189
|
+
- platform
|
|
190
|
+
- shell
|
|
191
|
+
- OS version
|
|
192
|
+
- git/worktree 约束
|
|
193
|
+
- 其他需要稳定告知 agent 的运行环境信息
|
|
194
|
+
|
|
195
|
+
#### `time`
|
|
196
|
+
|
|
197
|
+
时间快照,例如:
|
|
198
|
+
|
|
199
|
+
- session start timestamp
|
|
200
|
+
- local timezone
|
|
201
|
+
- human-readable date string
|
|
202
|
+
|
|
203
|
+
V1 明确接受它在长会话中会 stale,因为当前产品选择就是 session 初始化后冻结 prompt。
|
|
204
|
+
|
|
205
|
+
### 5. Runtime Integration
|
|
206
|
+
|
|
207
|
+
`instruction_snapshot` 的正确用途不是进入 `buildContext()` 普通消息流,而是:
|
|
208
|
+
|
|
209
|
+
1. session 初始化时生成并 append 到 JSONL
|
|
210
|
+
2. daemon/lane 在内存中持有这份 snapshot
|
|
211
|
+
3. 每次 `runtime.executeTurn()` 前,把 snapshot sections 渲染为 provider-level `systemPrompt`
|
|
212
|
+
4. 通过已有独立参数传给 runtime/provider
|
|
213
|
+
|
|
214
|
+
也就是:
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
instruction_snapshot -> renderSystemPrompt(snapshot) -> executeTurn(context, systemPrompt, ...)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
不允许:
|
|
221
|
+
|
|
222
|
+
- 把最终 provider-level system prompt 当普通 `message` / `custom_message` 塞进 `buildContext()`
|
|
223
|
+
- 依赖 `role = "system"` message 让 pi-ai 推导 system prompt
|
|
224
|
+
|
|
225
|
+
原因是当前 `packages/core/src/provider/pi-ai.ts` 会把 `role === "system"` 的 ScorelMessage 降成 provider `user` message,而不是 provider-level `systemPrompt`。
|
|
226
|
+
|
|
227
|
+
### 6. Session / Resume / Clone / Branch Semantics
|
|
228
|
+
|
|
229
|
+
V1 规则:
|
|
230
|
+
|
|
231
|
+
- loadSession 时必须能读出 `instruction_snapshot`
|
|
232
|
+
- 恢复当前 session 时继续使用这条 snapshot
|
|
233
|
+
- clone 成新 session 时:
|
|
234
|
+
- 默认复制源 session 的 snapshot 作为新 session 的初始 snapshot
|
|
235
|
+
- 不重新从磁盘发现 `AGENTS.md`
|
|
236
|
+
- 同一 session 内 branch 到旧 event 时:
|
|
237
|
+
- 继续使用本 session 既有 snapshot
|
|
238
|
+
- 不追加新的 `instruction_snapshot`
|
|
239
|
+
- branch 只改变 conversation tree 的 leaf,不改变 harness input world
|
|
240
|
+
|
|
241
|
+
理由:
|
|
242
|
+
|
|
243
|
+
- clone 是复制已有 session 状态到新 session,不是按当前磁盘环境重新初始化 prompt world
|
|
244
|
+
- branch 是同一 session 内的 conversation-tree 分叉,更不应该重新发现磁盘指令
|
|
245
|
+
|
|
246
|
+
## Explicitly Not In Scope
|
|
247
|
+
|
|
248
|
+
- `<system-reminder>` 新注入来源与 merge 语义扩展
|
|
249
|
+
- memory 检索/召回策略本身
|
|
250
|
+
- GUI 或 WebUI 对 snapshot 的可视化
|
|
251
|
+
- 自动刷新 snapshot、cache invalidation 后追加新 snapshot
|
|
252
|
+
- `AGENTS.override.md`
|
|
253
|
+
- `SCOREL.md` / `scrolls.md`
|
|
254
|
+
- fallback filenames
|
|
255
|
+
- include/import 语法
|
|
256
|
+
- 基于目标文件路径的动态重算
|
|
257
|
+
- 让 `instruction_snapshot` 进入普通 LLM context message history
|
|
258
|
+
- 重写当前完整 EventTypeHandler/convertToLlm 架构;本 spec 只要求新事件具备明确 skip/display 行为
|
|
259
|
+
|
|
260
|
+
## Required Tests
|
|
261
|
+
|
|
262
|
+
### Protocol
|
|
263
|
+
|
|
264
|
+
- 新增 `instruction_snapshot` 到 PersistentEvent union。
|
|
265
|
+
- `instruction_snapshot` round-trip 持久化与解析通过。
|
|
266
|
+
|
|
267
|
+
### Session Core
|
|
268
|
+
|
|
269
|
+
- session JSONL 可在 header 后追加 `instruction_snapshot` 再追加普通消息。
|
|
270
|
+
- `buildContext()` 不把 `instruction_snapshot` 当普通 message 带进消息历史。
|
|
271
|
+
- loadSession / append 对该事件类型通过校验。
|
|
272
|
+
|
|
273
|
+
### AGENTS.md Discovery
|
|
274
|
+
|
|
275
|
+
- project walk 从 `cwd` 到最近 Git root;无 Git root 时到 home 前停止。
|
|
276
|
+
- `~/.scorel/AGENTS.md` 作为用户级全局源进入 snapshot。
|
|
277
|
+
- 近处文件优先级高于远处文件。
|
|
278
|
+
- 当前 session 初始化后,即使磁盘上 `AGENTS.md` 改变,后续 turn 仍使用原 snapshot。
|
|
279
|
+
|
|
280
|
+
### Snapshot Shape
|
|
281
|
+
|
|
282
|
+
- snapshot 含固定 section 顺序:
|
|
283
|
+
- baseline
|
|
284
|
+
- agents
|
|
285
|
+
- memory
|
|
286
|
+
- workspace
|
|
287
|
+
- environment
|
|
288
|
+
- time
|
|
289
|
+
- `agents` section 保留带来源的 source blocks。
|
|
290
|
+
- `workspace` section 是摘要而不是全量树。
|
|
291
|
+
|
|
292
|
+
### Runtime Integration
|
|
293
|
+
|
|
294
|
+
- 首个 turn 之前若无 snapshot,daemon 会先生成并 append snapshot,再调用 runtime。
|
|
295
|
+
- 后续 turn 复用同一 snapshot 渲染的 system prompt。
|
|
296
|
+
- `packages/daemon/src/index.ts` 不再以 `undefined` 调用 runtime。
|
|
297
|
+
- pi-ai request payload 能看到 provider-level `systemPrompt`。
|
|
298
|
+
|
|
299
|
+
### Resume / Clone / Branch
|
|
300
|
+
|
|
301
|
+
- reload 现有 session 后仍能读取并使用相同 snapshot。
|
|
302
|
+
- clone 后新 session 继承源 session snapshot,而不是重新做磁盘 discovery。
|
|
303
|
+
- branch 到同一 session 的旧 event 时不生成新 snapshot。
|
|
304
|
+
|
|
305
|
+
## Likely Files
|
|
306
|
+
|
|
307
|
+
```text
|
|
308
|
+
packages/protocol/src/events.ts
|
|
309
|
+
packages/protocol/src/index.test.ts
|
|
310
|
+
packages/core/src/session/index.ts
|
|
311
|
+
packages/core/src/session/session.test.ts
|
|
312
|
+
packages/core/src/runtime/index.ts
|
|
313
|
+
packages/core/src/provider/pi-ai.ts
|
|
314
|
+
packages/core/src/provider/pi-ai.test.ts
|
|
315
|
+
packages/daemon/src/index.ts
|
|
316
|
+
packages/daemon/src/index.test.ts
|
|
317
|
+
packages/daemon/src/projects/sessions.ts
|
|
318
|
+
docs/spec/session.md
|
|
319
|
+
docs/spec/events.md
|
|
320
|
+
docs/spec/runtime.md
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Risks And Boundaries
|
|
324
|
+
|
|
325
|
+
- 如果把完整最终 provider prompt 冻结到 JSONL,会把 baseline wording、tool contract wording 和 runtime baseline 一起版本化,兼容边界过重;V1 只冻结结构化 snapshot 与其 rendered blocks。
|
|
326
|
+
- `time` section 会 stale,这是产品明确接受的冻结代价,不算 bug。
|
|
327
|
+
- `memory` section 当前即使实现很轻,也必须占住结构化位置,避免后续再改 snapshot 总模型。
|
|
328
|
+
- 现有 `buildContext()` 仍是 M1 风格“只收 message”的实现;本 spec 不强迫一次性重构为完整 EventTypeHandler 架构,但要求 `instruction_snapshot` 能在现有边界下被稳定跳过。
|
|
329
|
+
|
|
330
|
+
## Done When
|
|
331
|
+
|
|
332
|
+
- session 首次进入主链路时会 append 一条 `instruction_snapshot`
|
|
333
|
+
- snapshot 使用固定 section schema,包含 `baseline / agents / memory / workspace / environment / time`
|
|
334
|
+
- `AGENTS.md` project discovery 从 `cwd` 到最近 Git root 或 home 前停止,并包含 `~/.scorel/AGENTS.md`
|
|
335
|
+
- 当前 session 内 system prompt 由 snapshot 派生且保持冻结
|
|
336
|
+
- runtime 不再以 `undefined` 调用 provider-level `systemPrompt`
|
|
337
|
+
- 自动测试与 typecheck 通过
|
|
338
|
+
- 完成后 commit:`S0050: feat: add instruction snapshot and agents assembly`
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# S0051 — Harness Item And System Reminder Conversion
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
把 Scorel 的 runtime guidance 从 ad-hoc message 拼接升级为正式的 `harness_item` 事件模型:
|
|
6
|
+
|
|
7
|
+
- 用一等 PersistentEvent 表达 harness 注入项
|
|
8
|
+
- 用 `<system-reminder>` 作为进入 LLM message stream 的统一 envelope
|
|
9
|
+
- 区分 item 的真实来源和 LLM 传输形式
|
|
10
|
+
- 支持 steer 这类当前 turn 引导输入
|
|
11
|
+
- 为后续 follow-up queue、Skill listing/delta、memory、hook 等注入建立共用管道
|
|
12
|
+
|
|
13
|
+
本 spec 只做 `harness_item` 事件、LM/display conversion 和 system-reminder 格式。Queue 双 loop 与 Skill index 不在本轮实现。
|
|
14
|
+
|
|
15
|
+
## Why Now
|
|
16
|
+
|
|
17
|
+
S0050 只解决 provider-level `systemPrompt` 的冻结和装配。M7 还需要一条独立管道,把“不是普通用户消息、但模型必须看到”的 runtime guidance 放进 LLM context。
|
|
18
|
+
|
|
19
|
+
这些信息包括:
|
|
20
|
+
|
|
21
|
+
- 用户运行中 steer 的引导
|
|
22
|
+
- Skill listing / Skill delta
|
|
23
|
+
- memory 或 hook 产生的上下文
|
|
24
|
+
- runtime notice、date change、attachment metadata
|
|
25
|
+
|
|
26
|
+
如果这些内容直接伪装成普通 user message,UI、审计和 replay 都会混乱。如果把它们放进 provider system prompt,又会破坏 session-scoped snapshot 的冻结语义。因此需要 `harness_item`。
|
|
27
|
+
|
|
28
|
+
## Scope
|
|
29
|
+
|
|
30
|
+
### 1. Protocol Event
|
|
31
|
+
|
|
32
|
+
新增一等 PersistentEvent:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
type HarnessItemKind =
|
|
36
|
+
| "attachment"
|
|
37
|
+
| "skill_listing"
|
|
38
|
+
| "skill_delta"
|
|
39
|
+
| "memory"
|
|
40
|
+
| "date_change"
|
|
41
|
+
| "steer"
|
|
42
|
+
| "runtime_notice";
|
|
43
|
+
|
|
44
|
+
type HarnessItemOrigin = "user" | "system" | "tool" | "skill";
|
|
45
|
+
|
|
46
|
+
interface HarnessItem {
|
|
47
|
+
kind: HarnessItemKind;
|
|
48
|
+
origin: HarnessItemOrigin;
|
|
49
|
+
content: string;
|
|
50
|
+
visibility: "display" | "hidden" | "compact";
|
|
51
|
+
data?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface HarnessItemEvent extends PersistentEventBase {
|
|
55
|
+
type: "harness_item";
|
|
56
|
+
item: HarnessItem;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
语义:
|
|
61
|
+
|
|
62
|
+
- `kind` 描述产品语义。
|
|
63
|
+
- `origin` 描述真实来源,不等于 LLM role。
|
|
64
|
+
- `content` 是进入 `<system-reminder>` 的文本。
|
|
65
|
+
- `visibility` 决定 UI 是否展示。
|
|
66
|
+
|
|
67
|
+
### 2. System Reminder Envelope
|
|
68
|
+
|
|
69
|
+
`<system-reminder>` 是 LM transport envelope,不是事件类型名。
|
|
70
|
+
|
|
71
|
+
渲染格式固定为:
|
|
72
|
+
|
|
73
|
+
```xml
|
|
74
|
+
<system-reminder>
|
|
75
|
+
...
|
|
76
|
+
</system-reminder>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
baseline system prompt 必须解释:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
Tool results and user messages may include <system-reminder> tags. These tags contain information automatically added by Scorel's harness. They are not part of the specific tool result or user message in which they appear.
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 3. LM Conversion
|
|
86
|
+
|
|
87
|
+
`buildContext()` 必须开始支持事件级 conversion,而不是只过滤带 `message` 的事件。
|
|
88
|
+
|
|
89
|
+
V1 行为:
|
|
90
|
+
|
|
91
|
+
- 普通 `user_message` / `assistant_message` / `tool_result` 原样进入 context。
|
|
92
|
+
- `instruction_snapshot` 跳过。
|
|
93
|
+
- `harness_item`:
|
|
94
|
+
- 如果 context 中已有最近的 `tool_result`,把 `<system-reminder>` 文本合入该 tool result 的文本末尾。
|
|
95
|
+
- 如果没有可合入的 `tool_result`,作为 meta user message 进入 context。
|
|
96
|
+
|
|
97
|
+
合入规则:
|
|
98
|
+
|
|
99
|
+
- 只追加到最后一个 `tool_result` message。
|
|
100
|
+
- 保留原 tool result 内容,不覆盖。
|
|
101
|
+
- 合入后的内容必须与原内容用空行分隔。
|
|
102
|
+
- 如果 tool result content 无法安全合入,fallback 为独立 meta user message。
|
|
103
|
+
|
|
104
|
+
### 4. Display Conversion
|
|
105
|
+
|
|
106
|
+
UI 不应把所有 `harness_item` 展示成用户气泡。
|
|
107
|
+
|
|
108
|
+
V1 display:
|
|
109
|
+
|
|
110
|
+
- `kind = "steer"` 且 `origin = "user"`:展示为运行中引导。
|
|
111
|
+
- `skill_listing` / `skill_delta`:默认 hidden 或 compact。
|
|
112
|
+
- `memory` / `runtime_notice`:默认 compact。
|
|
113
|
+
- `visibility = "hidden"`:不展示,但仍可在 diagnostics/session detail 中审计。
|
|
114
|
+
|
|
115
|
+
### 5. Steer
|
|
116
|
+
|
|
117
|
+
`steer` 是当前 turn 的引导输入,不是 follow-up queue。
|
|
118
|
+
|
|
119
|
+
当用户在工具执行中插入 steer:
|
|
120
|
+
|
|
121
|
+
- append `harness_item { kind: "steer", origin: "user" }`
|
|
122
|
+
- `parentId` 挂到当前 active conversation leaf
|
|
123
|
+
- 下一次 inner tool loop 构建 context 时通过 `<system-reminder>` 注入
|
|
124
|
+
|
|
125
|
+
Steer 的来源仍是用户。`<system-reminder>` 只说明它由 harness 旁路注入,不说明它是 system-origin。
|
|
126
|
+
|
|
127
|
+
## Explicitly Not In Scope
|
|
128
|
+
|
|
129
|
+
- follow-up queue add/update/delete/consume
|
|
130
|
+
- Skill directory discovery、Skill index、Skill tool
|
|
131
|
+
- memory recall 策略
|
|
132
|
+
- hook 执行模型
|
|
133
|
+
- UI 完整设计
|
|
134
|
+
- compact / rewind / branch 完整 handler 架构重写
|
|
135
|
+
|
|
136
|
+
## Required Tests
|
|
137
|
+
|
|
138
|
+
### Protocol
|
|
139
|
+
|
|
140
|
+
- `harness_item` 加入 PersistentEvent union。
|
|
141
|
+
- round-trip parse / serialize 通过。
|
|
142
|
+
- `origin` 和 `kind` 非法值会失败。
|
|
143
|
+
|
|
144
|
+
### Session Core
|
|
145
|
+
|
|
146
|
+
- `buildContext()` 会跳过 `instruction_snapshot`。
|
|
147
|
+
- `harness_item` 在无 tool result 时变成 meta user message。
|
|
148
|
+
- `harness_item` 在已有 tool result 时合入最后一个 tool result。
|
|
149
|
+
- `steer` 的 `origin = "user"` 被保留到 event payload。
|
|
150
|
+
|
|
151
|
+
### Display
|
|
152
|
+
|
|
153
|
+
- `steer` 不渲染成普通用户气泡。
|
|
154
|
+
- hidden harness item 不进入普通 transcript。
|
|
155
|
+
|
|
156
|
+
### Runtime
|
|
157
|
+
|
|
158
|
+
- daemon 可以在当前 active leaf 后 append steer harness item。
|
|
159
|
+
- 下一次 runtime context 包含对应 `<system-reminder>`。
|
|
160
|
+
|
|
161
|
+
## Likely Files
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
packages/protocol/src/events.ts
|
|
165
|
+
packages/protocol/src/index.test.ts
|
|
166
|
+
packages/core/src/session/index.ts
|
|
167
|
+
packages/core/src/session/session.test.ts
|
|
168
|
+
packages/daemon/src/index.ts
|
|
169
|
+
packages/daemon/src/index.test.ts
|
|
170
|
+
apps/webui/lib/events/*
|
|
171
|
+
docs/spec/events.md
|
|
172
|
+
docs/spec/session.md
|
|
173
|
+
docs/spec/runtime.md
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Risks And Boundaries
|
|
177
|
+
|
|
178
|
+
- 事件名不能叫 `system_reminder`,否则会混淆来源;`steer` 是 user-origin。
|
|
179
|
+
- 不要把 harness item 放进 provider-level `systemPrompt`。
|
|
180
|
+
- 不要把 display 逻辑和 LM conversion 混在一起。
|
|
181
|
+
- V1 可以保留轻量 hardcoded conversion,但 public spec 必须按 handler/converter 语义描述,避免继续扩散 M1-only `buildContext()`。
|
|
182
|
+
|
|
183
|
+
## Done When
|
|
184
|
+
|
|
185
|
+
- `harness_item` 事件可以持久化、恢复、replay。
|
|
186
|
+
- `buildContext()` 能把 harness item 转成 `<system-reminder>` meta user message 或合入 tool result。
|
|
187
|
+
- steer 可以作为 user-origin harness item 注入当前 turn。
|
|
188
|
+
- UI/display 不把 harness item 误显示为普通用户输入。
|
|
189
|
+
- 自动测试与 typecheck 通过。
|
|
190
|
+
- 完成后 commit:`S0051: feat: add harness item system reminders`
|