@margay/ccl-core 1.5.0-alpha.0 → 1.5.1-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.
Files changed (94) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +95197 -74935
  3. package/dist/sdk/background.d.ts +48 -0
  4. package/dist/sdk/background.js +87 -0
  5. package/dist/sdk/backgroundRunTypes.d.ts +101 -0
  6. package/dist/sdk/backgroundRunTypes.js +1 -0
  7. package/dist/sdk/commandAdapter.d.ts +77 -0
  8. package/dist/sdk/commandAdapter.js +180 -0
  9. package/dist/sdk/commandProcess.d.ts +27 -0
  10. package/dist/sdk/commandProcess.js +130 -0
  11. package/dist/sdk/executionGuidance.d.ts +7 -0
  12. package/dist/sdk/executionGuidance.js +37 -0
  13. package/dist/sdk/index.d.ts +16 -1
  14. package/dist/sdk/index.js +10 -0
  15. package/dist/sdk/inputProvenance.d.ts +13 -0
  16. package/dist/sdk/inputProvenance.js +26 -0
  17. package/dist/sdk/mcpServer.d.ts +9 -5
  18. package/dist/sdk/mcpServer.js +51 -9
  19. package/dist/sdk/operations/command.d.ts +24 -0
  20. package/dist/sdk/operations/command.js +48 -0
  21. package/dist/sdk/operations/host.d.ts +3 -0
  22. package/dist/sdk/operations/host.js +376 -0
  23. package/dist/sdk/operations/json.d.ts +6 -0
  24. package/dist/sdk/operations/json.js +24 -0
  25. package/dist/sdk/operations/reference.d.ts +15 -0
  26. package/dist/sdk/operations/reference.js +19 -0
  27. package/dist/sdk/operations/store.d.ts +26 -0
  28. package/dist/sdk/operations/store.js +300 -0
  29. package/dist/sdk/operations/types.d.ts +171 -0
  30. package/dist/sdk/operations/types.js +8 -0
  31. package/dist/sdk/pendingApprovalIdentity.d.ts +35 -0
  32. package/dist/sdk/pendingApprovalIdentity.js +27 -0
  33. package/dist/sdk/permissionDelegation.d.ts +19 -0
  34. package/dist/sdk/permissionDelegation.js +11 -0
  35. package/dist/sdk/query.d.ts +4 -2
  36. package/dist/sdk/query.js +236 -56
  37. package/dist/sdk/queryInput.js +7 -0
  38. package/dist/sdk/queryLifecycle.d.ts +19 -0
  39. package/dist/sdk/queryLifecycle.js +93 -0
  40. package/dist/sdk/queryLifecycleTypes.d.ts +160 -0
  41. package/dist/sdk/queryLifecycleTypes.js +47 -0
  42. package/dist/sdk/runtimeResources.d.ts +197 -0
  43. package/dist/sdk/runtimeResources.js +36 -0
  44. package/dist/sdk/scheduledOccurrenceTypes.d.ts +103 -0
  45. package/dist/sdk/scheduledOccurrenceTypes.js +12 -0
  46. package/dist/sdk/session.d.ts +4 -3
  47. package/dist/sdk/session.js +19 -14
  48. package/dist/sdk/types.d.ts +21 -2
  49. package/docs/README.md +5 -0
  50. package/docs/background-runs.md +229 -0
  51. package/docs/ccl-duo-agent.md +1 -4
  52. package/docs/ccl-ide-usage.md +7 -70
  53. package/docs/cli-installation.md +37 -0
  54. package/docs/command-tool-recovery.md +62 -0
  55. package/docs/dev-quickstart.md +29 -7
  56. package/docs/error-recovery-usage.md +30 -2
  57. package/docs/features/business-facts.md +2 -4
  58. package/docs/hook-input-provenance.md +120 -0
  59. package/docs/index.md +30 -96
  60. package/docs/local-analytics-quickstart.md +11 -28
  61. package/docs/mcp-tool-recovery.md +82 -0
  62. package/docs/operations-client-integration.md +1 -7
  63. package/docs/peer-development-review.md +0 -1
  64. package/docs/releases/1.5.0-alpha.3.md +17 -0
  65. package/docs/releases/1.5.0-alpha.4.md +16 -0
  66. package/docs/releases/1.5.0-alpha.5.md +26 -0
  67. package/docs/releases/1.5.0-alpha.6.md +15 -0
  68. package/docs/releases/1.5.1-alpha.1.md +11 -0
  69. package/docs/releases/1.5.1-alpha.2.md +17 -0
  70. package/docs/releases/1.5.1-alpha.md +22 -0
  71. package/docs/runtime-resources.md +137 -0
  72. package/docs/self-hosted-product-events.md +6 -35
  73. package/docs/shared-skill-resources.md +50 -0
  74. package/examples/background-runs/agents/background-reviewer.md +6 -0
  75. package/examples/background-runs/agents/background-worker.md +6 -0
  76. package/examples/background-runs/worker-reviewer.mjs +42 -0
  77. package/examples/command-recovery/durable-server.mjs +44 -0
  78. package/examples/command-recovery/receipt-command.mjs +40 -0
  79. package/examples/runtime-resources/catalog.ts +68 -0
  80. package/package.json +25 -14
  81. package/sdk/API.md +236 -1
  82. package/sdk/README.md +6 -0
  83. package/docs/agent-owned-error-recovery-ux-2026-10-04.md +0 -146
  84. package/docs/analytics-capabilities-2026-10-08.md +0 -223
  85. package/docs/releases/1.4.5-rc.1.md +0 -39
  86. package/docs/releases/1.4.5-rc.10.md +0 -50
  87. package/docs/releases/1.4.5-rc.2.md +0 -26
  88. package/docs/releases/1.4.5-rc.3.md +0 -9
  89. package/docs/releases/1.4.5-rc.6.md +0 -11
  90. package/docs/releases/1.4.5-rc.7.md +0 -14
  91. package/docs/releases/1.4.5-rc.8.md +0 -18
  92. package/docs/releases/1.4.5-rc.9.md +0 -22
  93. package/docs/releases/1.4.6-beta.0.md +0 -54
  94. package/docs/releases/1.5.0-alpha.0.md +0 -44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@margay/ccl-core",
3
- "version": "1.5.0-alpha.0",
3
+ "version": "1.5.1-alpha.2",
4
4
  "description": "Core runtime extracted from Claude Code (ccl) for Margay integration",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",
@@ -9,15 +9,15 @@
9
9
  "margay": "dist/cli.js"
10
10
  },
11
11
  "files": [
12
- "dist",
12
+ "dist/cli.js",
13
+ "dist/sdk",
14
+ "dist/vendor/ripgrep",
13
15
  "README.md",
14
16
  "QUICKSTART.md",
15
17
  "docs/cli-installation.md",
16
18
  "INTENT-GATEWAY-GUIDE.md",
17
19
  "docs/index.md",
18
20
  "docs/error-recovery-usage.md",
19
- "docs/releases/1.4.5-rc.1.md",
20
- "docs/agent-owned-error-recovery-ux-2026-10-04.md",
21
21
  "docs/gateway-quickstart.md",
22
22
  "docs/dev-quickstart.md",
23
23
  "docs/ccl-duo-agent.md",
@@ -25,26 +25,36 @@
25
25
  "docs/peer-development-review.md",
26
26
  "sdk/README.md",
27
27
  "sdk/API.md",
28
- "docs/releases/1.4.5-rc.2.md",
29
- "docs/releases/1.4.5-rc.3.md",
28
+ "docs/runtime-resources.md",
29
+ "docs/hook-input-provenance.md",
30
+ "docs/command-tool-recovery.md",
31
+ "docs/mcp-tool-recovery.md",
32
+ "docs/background-runs.md",
33
+ "examples/background-runs/worker-reviewer.mjs",
34
+ "examples/background-runs/agents/background-worker.md",
35
+ "examples/background-runs/agents/background-reviewer.md",
36
+ "examples/command-recovery/durable-server.mjs",
37
+ "examples/command-recovery/receipt-command.mjs",
38
+ "docs/shared-skill-resources.md",
39
+ "examples/runtime-resources",
30
40
  "docs/local-analytics-quickstart.md",
31
41
  "docs/self-hosted-product-events.md",
32
- "docs/analytics-capabilities-2026-10-08.md",
33
- "docs/releases/1.4.5-rc.6.md",
34
42
  "docs/operations-client-integration.md",
35
43
  "examples/operations/README.md",
36
44
  "examples/operations/minimal_client.py",
37
45
  "examples/operations/test_minimal_client.py",
38
- "docs/releases/1.4.5-rc.7.md",
39
46
  "docs/features/business-facts.md",
40
- "docs/releases/1.4.5-rc.8.md",
41
47
  "docs/features/copy-on-select.md",
42
- "docs/releases/1.4.5-rc.9.md",
43
- "docs/releases/1.4.5-rc.10.md",
44
48
  "docs/context-checkpoints-and-daemon.md",
45
- "docs/releases/1.4.6-beta.0.md",
46
49
  "examples/assistant",
47
- "docs/releases/1.5.0-alpha.0.md"
50
+ "docs/releases/1.5.0-alpha.3.md",
51
+ "docs/README.md",
52
+ "docs/releases/1.5.0-alpha.4.md",
53
+ "docs/releases/1.5.0-alpha.5.md",
54
+ "docs/releases/1.5.0-alpha.6.md",
55
+ "docs/releases/1.5.1-alpha.md",
56
+ "docs/releases/1.5.1-alpha.1.md",
57
+ "docs/releases/1.5.1-alpha.2.md"
48
58
  ],
49
59
  "engines": {
50
60
  "node": ">=22.19.0"
@@ -55,6 +65,7 @@
55
65
  "prepublishOnly": "bun run build",
56
66
  "test": "vitest run",
57
67
  "test:smoke": "vitest run -c vitest.smoke.config.ts",
68
+ "test:operations": "vitest run __tests__/operations",
58
69
  "build:sdk": "tsc -p tsconfig.sdk.json"
59
70
  },
60
71
  "dependencies": {
package/sdk/API.md CHANGED
@@ -4,6 +4,10 @@
4
4
  > 版本:`1.4.5-rc.1` 源码候选;包:`@margay/ccl-core`,子路径导出 `@margay/ccl-core/sdk`。
5
5
  > 本文档是对接契约;内部实现与 issue 需求对照见同目录 `README.md`。
6
6
 
7
+ 原生 `UserPromptSubmit` 的来源、消息 ID、排队与恢复语义见 [输入身份契约](../docs/hook-input-provenance.md);该文档明确区分源码候选与已发布版本。
8
+
9
+ `1.5.1-alpha` 接口 `createBackgroundClient` 及独立后台生命周期见 [持久后台接入契约](../docs/background-runs.md)。其事件返回 `{events,nextCursor,hasMore}`,支持 `limit` 分页;不要套用本文历史会话接口的默认 CLI 定位或内存回调机制。工具操作恢复另见 [命令适配](../docs/command-tool-recovery.md) 和 [MCP 恢复](../docs/mcp-tool-recovery.md)。
10
+
7
11
  ---
8
12
 
9
13
  ## 1. 引入与运行要求
@@ -109,6 +113,19 @@ Query 控制方法,`pid` 用于宿主监控。
109
113
  终止进程并拒绝未完成轮次。权限回调可等待宿主决定,interrupt/close 会取消
110
114
  等待;返回 `pending` 仍表示持久挂起,后续用 `resumeWithDecision` 恢复。
111
115
 
116
+ **后台工具与可交互前台是两个层次。** `Agent(run_in_background: true)` 会先返回
117
+ 启动结果,但 CLI 的 print/SDK 路径可能继续等待该输入所属的后台工作及完成通知,
118
+ 才发出这一轮的 `result`。`Session` 按该终态串行发送下一条输入,因此收到
119
+ `assistant_text` 中的接收确认,不代表同一 Session 的下一次 `prompt()` 已可执行。
120
+ 不要把 `Turn.result` 当作“前台确认已显示”事件,也不要用 `steer()` 充当无损的
121
+ 后台移交;它会中断当前轮。
122
+
123
+ 若应用要求后台任务运行期间前台仍可对话,可将工作交给**独立的 worker Session**,
124
+ 主会话不等待 worker 的 `Turn.result`。由应用保存任务与 worker 的关联,消费其结果,
125
+ 再将实际完成结果交给前台。多个 Session 是独立执行上下文,需要明确传递任务、
126
+ 权限与材料引用;进程中的 Session 本身不是持久队列,应用仍需处理保存后派发失败、
127
+ 退出恢复与结果未知。此路径的接口并发可用性不保证模型服务的前台响应时延。
128
+
112
129
  ---
113
130
 
114
131
  ## 3. 事件参考(SDKEvent)
@@ -132,6 +149,39 @@ Query 控制方法,`pid` 用于宿主监控。
132
149
  `result` 只结束对应 `turnId`,后续仍可能有输入。`suspended`、fatal `error`、
133
150
  关闭或输入 EOF 结束流式 query;不要把首个 result 当作常驻 Session 已关闭。
134
151
 
152
+ ### 子任务生命周期事件
153
+
154
+ 启用 `includeRaw: true`,从 `event.type === 'raw'` 的 `event.message` 读取
155
+ 宿主 `type: 'system'` 事件。`createSession` 可通过 `onEvent` 消费同样的事件;
156
+ 这些事件不会另外转换成同名的顶层 `SDKEvent`。
157
+
158
+ | subtype | 主要字段 | 含义 |
159
+ |---|---|---|
160
+ | `task_started` | `session_id`, `task_id`, `tool_use_id?`, `description`, `task_type?`, `uuid` | 进程内已登记子任务;不等于业务绑定已持久保存 |
161
+ | `task_progress` | 上述身份字段、`usage`, `last_tool_name?`, `summary?` | 可选进度,不是完成证明 |
162
+ | `task_notification` | 身份字段、`status`, `output_file`, `summary`, `usage?` | 终态通知;`status` 为 `completed`、`failed` 或 `stopped` |
163
+
164
+ 保存业务执行尝试与实际 `session_id/tool_use_id/task_id` 的关联。内部取消状态
165
+ `killed` 在此映射为 `stopped`。模型文本或工具正文中的同名 XML 不应当作宿主事件;
166
+ 即使任务 `completed`,仍需核对业务产物和实际交付回执。
167
+
168
+ 从 `1.5.0-alpha.6` 起,`TaskOutput` 抢先读取终态、抑制后续模型通知的路径也会
169
+ 补发结构化 SDK 终态;已经通知、重复读取或仍在运行时不新增该终态。这一修复
170
+ 不提供持久投递保证:事件队列、任务表主要在进程内,前台忙碌可能延后通知,
171
+ 退出后没有消费者确认游标或保证重放。应用应保存收到的事件并处理重复、缺失和冲突。
172
+
173
+ 当前没有按父会话和原 `tool_use_id` 查询历史运行的公开 SDK 接口。`TaskOutput`
174
+ 是已标记弃用的模型工具,只查询现有任务表;`stopTask(taskId)` 是当前进程内的
175
+ 取消控制,不是查询,也不能撤销副作用。`SubagentStart` 不提供原 Agent 调用 ID。
176
+ 已保存的父会话 Agent 工具结果可提供 `toolUseResult.agentId` 与
177
+ `message.content[].tool_use_id` 的有限取证关联;记录缺失、日志截断或进程退出
178
+ 应保留为未知,不直接重派。`resume` 会继续执行,不能用作无副作用的状态查询。
179
+
180
+ 普通后台 agent 默认不能弹出权限 UI;规则和权限 hook 未放行、仍需要交互的操作
181
+ 通常返回工具拒绝。不能期待所有权限不足都表现为统一的任务 `waiting` 或 `failed`。
182
+ 显式允许提示的配置另按实际权限事件处理。普通 worker 也不获得嵌套 Agent 工具;
183
+ 独立 reviewer 应由主协调入口派发,保持前台与 worker Session 的分工。
184
+
135
185
  ### 恢复结果与用户介入
136
186
 
137
187
  `result.recovery` 是可选扩展,与过程诊断的 `diagnostic.recovery.phase` 不同:
@@ -214,6 +264,35 @@ query(...)
214
264
 
215
265
  ## 6. QueryOptions 字段表
216
266
 
267
+ ### 共用执行指引与宿主定制
268
+
269
+ 普通 CLI 和 SDK 默认系统指令共用运行层的工具执行指导:可用且适合时优先专用文件工具;脚本、构建、测试、转换及专用工具不提供的元数据查询使用 Bash。缺工具可采用已授权等价方案,权限拒绝不能成为换工具绕过限制的理由。这是 agent 指引,不是工具调用或模型遵循的强制保证。
270
+
271
+ 保留运行层默认指导并追加岗位或用户配置时,SDK 使用 `appendSystemPrompt`,CLI 使用 `--append-system-prompt` 或 `--append-system-prompt-file`。内容由宿主组合和维护,不改写用户 persona 文件,也不自动同步两个应用的配置。若 SDK 同时提供 `systemPrompt`,追加内容接在替换后的提示之后。仅在确实需要自管全部系统指令时使用 `systemPrompt` / `--system-prompt`;它们会替换默认系统指令,Bash 等工具的说明仍来自实际工具 schema。没有另一个命名 preset 注册或版本协商接口。
272
+
273
+ 需要保留自定义 `systemPrompt`、同时复用运行层执行指引时,可显式使用 `getExecutionGuidance(toolNames)`。**此导出从 `1.5.0-alpha.5` 提供**;内容随同一部署包版本更新,不另建 preset 版本号。SDK 和 CLI 应使用同一固定版本的包,旧安装包不一定具备此导出。
274
+
275
+ ```ts
276
+ import { getExecutionGuidance, query } from '@margay/ccl-core/sdk'
277
+
278
+ const toolNames = ['Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash']
279
+ const execution = getExecutionGuidance(toolNames)
280
+ const result = query(prompt, {
281
+ systemPrompt: personaText, // 原岗位身份,由应用保存;指引更新不改写它
282
+ appendSystemPrompt: [execution, userDefaults].filter(Boolean).join('\n\n'),
283
+ extraArgs: ['--tools', toolNames.join(',')],
284
+ canUseTool, // 沿用应用自身权限处理;生成指引不会授予工具权限
285
+ })
286
+ for await (const event of result) { /* 消费实际结果 */ }
287
+ ```
288
+
289
+ `toolNames` 使用会话实际暴露的规范工具名,非显示别名或权限规则表达式;只有提供的内置文件工具/Bash 才生成对应分工说明,其它工具仍遵循通用的“按已有接口执行、必要时定向调查”规则。空列表只返回通用边界。工具集合变化时由应用重新生成;函数不探测文件、不加载技能、不注册工具、不修改配置、不自动注入会话。普通默认系统提示已经消费同一来源,无需再追加一次。
290
+
291
+ 直接 CLI 的自定义 persona 也可消费同一份文字:应用通过上述导出生成一个自己管理的文本文件,再使用 `--system-prompt-file <persona文件> --append-system-prompt-file <执行指引文件>`。不依赖复制某个内部提示文件,也不需要 persona 改成默认 coding 身份。显式完整替换且不追加时,仍保持既有替换契约。REPL/embedded 等特殊工具表面由调用方传入实际可直接使用的工具名,不能把本函数当作特殊模式的全部运行指令。
292
+
293
+ 宿主应固定部署包版本并检验实际模型输入,而非从工具已注册推断默认指导存在。升级依赖后还需重启实际运行的 CLI/SDK 进程。Desktop 的资源管理、配置保存和 UI 联验仍由宿主负责。
294
+
295
+
217
296
  | 字段 | 类型 | 默认 | 说明 |
218
297
  |---|---|---|---|
219
298
  | `cwd` | string | 继承宿主 | 会话工作目录 |
@@ -231,7 +310,7 @@ query(...)
231
310
  | `maxTurns` | number | — | 单次 query 轮数上限(防失控,建议必设) |
232
311
  | `maxBudgetUsd` | number | — | 单次 query 花费上限 |
233
312
  | `permissionMode` | string | default | CLI 权限模式 |
234
- | `skillsDirs` | string[] | — | 显式技能目录(cwd 无关);目录内为 `<name>/SKILL.md`;不存在则抛错 |
313
+ | `skillsDirs` | string[] | — | 显式技能目录(cwd 无关);目录内为 `<name>/SKILL.md`;必须为存在的目录,按真实路径固定并去重;同根重启身份稳定 |
235
314
  | `pluginDirs` | string[] | — | 插件目录(等价 `--plugin-dir`,可重复) |
236
315
  | `addDirs` | string[] | — | 额外可访问目录 |
237
316
  | `settings` | string | — | settings 文件路径或 JSON 字符串 |
@@ -372,6 +451,16 @@ for await (const ev of query('用 load_csv 读 /data/x.csv 并报告行列', {
372
451
  - handler 在 **host 进程**执行(可访问 host 的文件/网络/状态)。
373
452
  - 每次调用先过 `canUseTool`(可 allow/deny/pending);deny → 工具不跑。
374
453
 
454
+ 工具发现元数据:`tool` 的第五个参数支持
455
+ `{ searchHint?: string, alwaysLoad?: boolean, annotations?: Record<string, unknown> }`。
456
+ `searchHint` 作为 `anthropic/searchHint` 传给工具搜索,补充名称和描述之外的搜索词;
457
+ SDK 在 `tools/list` 中转发此字段。
458
+ 新增的 `alwaysLoad: true` 作为 `anthropic/alwaysLoad` 传给 CLI,让该工具完整 schema
459
+ 进入首请求,无须先由 ToolSearch 发现。省略或传 `false` 沿用 CLI 的工具发现策略,
460
+ 并非强制隐藏工具。这些选项不授予执行权限,也不保证模型选择该工具;
461
+ `canUseTool` 的拒绝仍阻止 handler 执行。仅对确实需要首请求展示的工具显式启用,
462
+ 避免无条件扩大每次请求。
463
+
375
464
  ### 13.2 Token 级流式(G3)
376
465
  ```ts
377
466
  for await (const ev of query('写一段', { includePartialMessages: true })) {
@@ -438,3 +527,149 @@ query('用 filesystem server 列目录', {
438
527
  [request status guide](./README.md#gateway-request-status-source-candidate) for
439
528
  phases, bounded delivery and host lifecycle rules. This nonterminal event must
440
529
  not be used as an assistant message, a successful result, or a retry instruction.
530
+
531
+ ### Input provenance v1 (1.5.0 source candidate; not yet released)
532
+
533
+ `Session.prompt`, `followUp` and `steer` accept an optional second `InputMetadata`
534
+ argument. Streaming `query` accepts the same `isSynthetic` and `input_provenance`
535
+ fields on each `SDKUserMessage`. The CLI advertises
536
+ `input_provenance: { versions: [1] }` in its initialize response. This SDK refuses
537
+ metadata-bearing inputs when the CLI does not advertise v1; it never silently
538
+ downgrades an internal report to a human prompt. Plain human input remains
539
+ compatible with older CLIs.
540
+
541
+ ```ts
542
+ const turn = session.prompt('Check data.csv, read-only. Return English JSON.')
543
+ const original = await turn.result
544
+ await session.followUp(childReport, {
545
+ input_provenance: {
546
+ version: 1,
547
+ actor: 'agent',
548
+ source: 'workspace-child-17',
549
+ session_id: original.sessionId!,
550
+ request_id: turn.id,
551
+ },
552
+ }).result
553
+ ```
554
+
555
+ Actors are `human`, `host`, `agent`, or `unknown`. `source` is a nonempty host
556
+ identifier. Host/agent reports require both `session_id` and `request_id`.
557
+ The request ID is the original **human user-message UUID**, not a tool-use ID,
558
+ workspace ID or assistant-message UUID. CCL resolves the exact original from
559
+ the current session's messages or transcript, including after compaction and
560
+ resume. Missing, foreign-session, synthetic or unclassified originals fail
561
+ with an input-correlated error; the rejected report is not sent to the model.
562
+ Do not supply original request text: that field is deliberately unsupported.
563
+
564
+ The host must authenticate the caller, bind account/workspace/session ownership,
565
+ and protect access to stdin/SDK. These fields are a trusted host envelope, not
566
+ authentication by themselves. Text inside a report cannot set its source or
567
+ expand tool permissions. CCL retains the ordinary permission checks.
568
+
569
+ Internal input still starts a model turn and receives its own result, including
570
+ when queued during another turn's tool call. It does not invoke
571
+ `UserPromptSubmit`/`onUserPromptSubmit` or execute slash commands from its body.
572
+ The model receives the recorded source and resolved human request so it can
573
+ preserve language, format and file boundaries. Model adherence is behavioral,
574
+ not a deterministic output guarantee. `isSynthetic: true` without provenance
575
+ is accepted as legacy internal/unknown input; it does not invent a human request
576
+ reference. A synthetic input cannot claim `actor: 'human'`.
577
+
578
+ New plain CLI/SDK inputs are human at the trusted entry point. Unclassified old
579
+ history stays unknown. With session persistence disabled, a reference whose
580
+ original has left current context cannot be recovered and fails explicitly.
581
+ Hosts should retain source fields on replay, avoid duplicate history insertion,
582
+ and upgrade the runtime and SDK together before adopting this contract.
583
+
584
+ ### Deferred MCP tool names and memory scope
585
+
586
+ An MCP server's `tools/list` name, the runtime-prefixed name, the initialize
587
+ catalog, and the schemas actually sent to the model are distinct. Discover
588
+ `report_workspace_result` with a keyword ToolSearch; use the exact runtime name
589
+ such as `select:mcp__margay-context__report_workspace_result` for exact selection.
590
+ Bare underscore names are searchable. Exact selection accepts only a full name
591
+ or explicitly registered alias; it does not guess between servers with the same
592
+ short name. Partial matches report `missing_names`; disconnected/pending servers
593
+ remain visible as pending. `already_loaded` and `load_requested` distinguish
594
+ known schemas from requested loading. Neither is proof that a tool ran: verify
595
+ the actual tool call and host receipt.
596
+
597
+ Task-only delegation, read-only instructions, tool denials and successful reports
598
+ do not establish lasting user preferences. Shared memory guidance requires human
599
+ evidence of future scope, retains explicit lasting preferences, and lets genuine
600
+ human corrections supersede them. Existing user memory is not migrated or
601
+ deleted by this change. Hosts must not label child reports as human confirmation.
602
+ ## Runtime resource discovery
603
+
604
+ `InitializationResult.runtime_resources` describes current memory and scratch
605
+ paths and their scope/lifecycle. Use `reinitialize()` for a fresh snapshot, and
606
+ `RuntimeResourcesSchema.safeParse()` for version validation. This metadata never
607
+ grants filesystem access. See [the wire contract and host integration guide](../docs/runtime-resources.md).
608
+
609
+ ## Shared skill roots
610
+
611
+ `skillsDirs` binds canonical directories at transport creation, generates stable
612
+ plugin identities for those roots, and disposes only its own temporary wrappers.
613
+ For shared updates, retain immutable version directories and select a new root
614
+ explicitly. Rediscover IDs after upgrading from random SDK wrapper names or after
615
+ moving a skill root; transcript resume does not restore resource bindings.
616
+ See [shared skill identity, reload and publisher responsibilities](../docs/shared-skill-resources.md).
617
+ # Query loop observations
618
+
619
+ `SDKEvent` includes `{ type: 'query_lifecycle', lifecycle, sessionId }`. The
620
+ `lifecycle.record.phase === 'terminal'` observation closes one host query loop;
621
+ it does not replace the outer `result` event or verify a business outcome. Native
622
+ Stop hooks carry the same checkpoint identity in their optional `query` field.
623
+ See [input and query correlation](../docs/hook-input-provenance.md) for fields,
624
+ failure states and the distinction between accepted and adapter-dispatched inputs.
625
+
626
+ `readQueryLifecycle({ transcriptPath, sessionId, queryId })` reads only the given
627
+ file and returns `found` with `complete`/`incomplete`, `not_found`, or `unavailable`.
628
+ Use the original query ID when processing late or replayed notifications. Missing
629
+ records do not authorize re-execution of tools.
630
+
631
+ Keep ownership of the public query handle and close it when post-result controls
632
+ are no longer needed:
633
+
634
+ ```js
635
+ const handle = query(prompt, options)
636
+ try {
637
+ for await (const event of handle) {
638
+ if (event.type === 'query_lifecycle') recordObservation(event.lifecycle)
639
+ // Continue consuming the outer result; a Stop checkpoint is not terminal.
640
+ }
641
+ } finally {
642
+ await handle.close()
643
+ }
644
+ ```
645
+
646
+ ## Write without replacing an existing target (1.5.1-alpha candidate)
647
+
648
+ The native `Write` schema accepts optional `mode: "overwrite" | "create_only"`.
649
+ Omitting it keeps the existing read-before-overwrite behavior. For an export that
650
+ must preserve every existing target, use:
651
+
652
+ ```json
653
+ {"file_path":"/absolute/path/new-export.txt","content":"Export content\n","mode":"create_only"}
654
+ ```
655
+
656
+ `create_only` refuses files (including previously read or empty files), directories,
657
+ symbolic links and dangling links. Publication is exclusive even if another process
658
+ creates the target after validation. On conflict, choose another authorized path;
659
+ reading the old target or approval to write does not convert this into overwrite.
660
+ The model receives the same schema through CLI/TUI and SDK. The headless workflow
661
+ `tool("Write", input)` also honors the mode, with its existing permission policy.
662
+
663
+ The implementation stages complete UTF-8 content beside the destination and links
664
+ it into place without replacing a directory entry. Unsupported hard links fail
665
+ without falling back to overwrite. A pre-publication write/flush/cancellation
666
+ failure does not create the target; diagnostics report any temporary residue.
667
+ After publication, cancellation and post-write cleanup/diagnostic failures do not
668
+ undo the created file. The result reports its canonical path and any warnings.
669
+ An interrupted consumer may receive no result; missing output is not proof that
670
+ the file was never created. This is not a power-loss, network-filesystem or durable
671
+ operation-replay guarantee, and does not introduce a new permission gate.
672
+
673
+ Check the actual tool schema for `mode`; an older installation with the same
674
+ candidate version string may not have it. An existence precheck followed by normal
675
+ Write is not an equivalent no-replacement contract.
package/sdk/README.md CHANGED
@@ -34,6 +34,12 @@ for await (const event of query('检查今天的收件箱并起草回复', {
34
34
 
35
35
  Resume an existing session: `query(prompt, { resume: sessionId })`.
36
36
 
37
+ For work that must continue after the foreground closes, the **1.5.1-alpha interface** exports `createBackgroundClient`.
38
+ See [durable background tasks](../docs/background-runs.md) for explicit submission,
39
+ stable keys, paged event recovery, permissions and the worker/reviewer example.
40
+ Its required `cwd` and `cliPath` options are separate from `query()`'s defaults;
41
+ in-process callbacks and SDK MCP instances cannot be carried into a detached worker.
42
+
37
43
  Pending approval (7×24 resident CoS, owner approves via Feishu card):
38
44
 
39
45
  ```ts
@@ -1,146 +0,0 @@
1
- # Agent 自主恢复与用户介入边界
2
-
3
- 状态:整体实现 R2–R5 已获 Lisa CONSENSUS,最终代码 `3435cc1e` 与文档 `58d31b9e` 的范围经 R6 复核,任务 #1 完成。本机双入口升级及回滚经 R7 独立验证,任务 #2 完成。以下保留各轮历史状态;最新交付见文末及 [版本说明](./releases/1.4.5-rc.1.md)。最初设计基线为 release/1.4.5-rc.1 @ 6ee1d15d。
4
-
5
- ## 用户要求
6
-
7
- 2026-10-04:agent 能自行查明、修复的问题应在既有权限内自己处理,并同步过程和结果;只有需要用户帮助时才明确求助、通知任务执行方并保留任务状态。权限、删除文件等敏感操作必须先经同意。预计耗时较长、成功把握不足或可能影响体验的操作,也必须先说明并获得同意。
8
-
9
- 设计阶段授权只适用于当前 CCL 仓内实现及隔离验证。不改网关或 super-rll;外部消费方如需适配以 issue 协作。没有发布、切换全局安装或真实敏感操作授权。
10
-
11
- ## 设计时的已有实现与缺口
12
-
13
- - query.ts:2052 对全部 RequestBudgetError 直接 owner=caller、blocked 并终止,没有给 agent/运行时区分可自行修复与须征求同意的机会。
14
- - services/api/errorRecovery.ts 已提供事实/分类/建议,errorRecoveryState.ts 有共享恢复额度(当前每 turn 最多两次、同因一次),不能因恢复创建新循环而重置。
15
- - query.ts 已有文本续写、工具完整性修复、上下文压缩和已执行工具结果保护;不是重新设计所有重试。
16
- - SystemTextMessage 不展示 error_diagnostic;SDK 默认不订阅过程诊断。已有 RecoveryOutcome needs_user/blocked_external 通过 QueryEngine 和 SDK 转发,但不是每条终止分支都有。
17
- - constants/prompts.ts 已有工具授权原则;必须复用实际权限执行器与 AskUser outcome,不能只靠提示词宣称有批准门禁。
18
-
19
- ## 决策与处理
20
-
21
- | 情况 | 行为 | 用户与任务方可见状态 |
22
- |---|---|---|
23
- | 已知、短时、低风险且不改用户约束的恢复 | 运行时恢复可调用条件,或把诊断交给主 agent 用现有工具修正、验证、继续 | 简短说明正在处理;成功报告结果,不产生最终错误 |
24
- | 长耗时、效果不确定或可能明显降低质量/体验 | 先解释动作、预计耗时或未知、影响、替代方案,走现有交互同意路径 | 等待同意;未同意、超时、取消或无交互渠道均不执行 |
25
- | 权限变更、删除/覆盖有价值文件、凭据/共享状态变化 | 即使技术可行也先确认;保持工具权限门禁 | 等待同意;不能用自动恢复越权 |
26
- | 网络持续不可用、所有授权模型不可用、账户额度耗尽 | 完成既有短时有界重试后保存进度,停止依赖该资源的步骤 | 明确阻塞原因、已尝试内容、所需帮助、恢复条件;通知任务调用方,不误报完成 |
27
- | 证据不足或工具是否已执行不确定 | 先做现有授权范围内的只读核对;不能核实时保留不确定性 | 禁止重放有副作用操作;需要更多行动时先确认 |
28
-
29
- 输出 token 到限不等于账户余额耗尽。前者可续写/拆分,但压缩丢失细节、降低 thinking、换低能力模型可能影响质量,不能一律静默执行。未知故障不是敏感操作授权。
30
-
31
- 长时间与不确定性在动作前判断,不以“已经开始了”代替同意。已授权范围可复用,但不能扩张到新的风险。没有耗时依据应写“耗时不确定”,不能虚构精确估计。具体时间阈值需依据现有操作超时/预算决定,默认不引入全局武断秒数;会显著延长等待的恢复方案先询问。
32
-
33
- ## 实施切片
34
-
35
- 1. **thinking 预算与恢复决策**:跟踪最终预算来源(自动、任务/用户显式、extra-body)和真实限制。自动派生的算术冲突可在合法模型约束内修正;不得改写显式 thinking 或任务质量要求。显式冲突应提供一次可批准的调整/关闭方案,不能只有手工改环境变量的技术报错。无可用模型时由 CLI 展示事实/方案,不靠一次同样无效的 LLM 调用来诊断。模型最小 thinking 预算未知时,不臆造一个 budget_tokens 值。
36
- 2. **agent 交接与同意**:工具/辅助能力失败且主模型可用时,把脱敏事实、已尝试恢复、已保存成果、权限和时间边界交给主 agent;真实工具经现有权限路径执行。主模型不可用时不假装 agent 仍能运行。已有有限请求重试保持;无意义重复不得消耗另一套新预算。批准动作限定本次方案和当前 turn,不持久修改用户配置。用户拒绝/取消不可被重新包装成恢复请求。
37
- 3. **过程、结果与任务通知**:复用诊断关联 id,显示恢复中/恢复成功/等待同意/外部阻塞;主任务和子任务用同一份真实状态。补齐最终 RecoveryOutcome,CLI/SDK 只产生一个最终结果;过程事件不能让宿主重复提交原任务。任务通知指向当前调用方/父任务和本地 UI,不默认增加飞书或其它外发。无交互 CLI/SDK 的批准请求返回可恢复的 needs_user 状态,不能假定默认同意。
38
-
39
- 不新增一个任意执行命令的修复器。模型提出行动仍受实际工具授权、取消、资源预算、用户约束检查;不能删除文件、调整权限、切换外部服务来绕过错误。
40
-
41
- ## 验收设计
42
-
43
- - 自动预算冲突:驱动真实最终 request builder;预算合法、HTTP 请求有界、用户无需修改配置;显式预算不被悄悄改写。
44
- - 批准边界:同一修复方案分别批准、拒绝、取消、无交互,检查实际后续 HTTP 参数/文件副作用,而不是只查提示文案。长耗时/效果不确定在执行前停住;没有批准不得发生动作。
45
- - 工具错误:保留真实 tool_result;agent 读取相关证据、修正并得到任务产物,已执行写操作恰好一次。受控脚本模型只证明流程;真实模型行为验证单列。
46
- - 外部阻塞:本地服务模拟持续网络错误、明确额度耗尽和认证失败;已有重试有界、提示所需行动、父任务/SDK 收到 recovery 状态、只有一次最终结果、goal 不误记完成。
47
- - UI/CLI/SDK:WezTerm 实际交互确认过程可见、批准先于动作、成功后继续;print/json/stream-json/SDK 状态一致,诊断脱敏。
48
- - 回归已有 request-budget、tool-recovery、权限、AskUser、goal、SDK 错误接口;按实际影响选择用例,不运行无关全仓测试替代验收。
49
-
50
- 当前文案候选验证:4 文件 94 用例、typecheck/build、5 smoke 通过;WezTerm 中 --print 六场景通过(冲突 HTTP0、手工按建议调整后 HTTP1)。这些仅支持文案准确和旧拒绝行为,不能证明本方案自主恢复或交互批准完成。证据在 .dual-agent/test-evidence/thinking-budget-ux/。
51
-
52
- ## R2 实施切片状态(Lisa PASS,已分步提交,整体未完成)
53
-
54
- 用户进一步确认:公共规则经 prompt-builder 放进 system prompt,不依赖 CCL.md、不默认新建错误处理 sub-agent;必须避免与旧恢复机制冲突。
55
-
56
- 已实现:buildEffectiveSystemPrompt 统一加入稳定规则,query 子代理路径幂等补入。RequestBudget 构造处仅 default 输出来源 + 非显式 thinking + 原生已知 Messages 最小预算的算术冲突可重算;其余保留拒绝。query 对显式冲突经真实 AskUser 权限回调强制 ask,验证完整且明确的批准答案后才使用 turn-local/model-bound thinking disable;不改环境或持久配置,不新增重试池。同意前请求为零,重试仍占现有共享 ledger。无交互/拒绝/取消返回 needs_user。
57
-
58
- 规则只指导模型的判断,不能声称 prompt 能强制约束任意工具操作的语义风险。运行时批准门禁目前已落到预算关闭 thinking 这一条;其余已知恢复动作仍待接入。真实模型判断质量尚未验证,受控模型用例只能证明通路。
59
-
60
- 与旧机制的接合清单:
61
-
62
- | 原机制 | 处理位置与剩余工作 |
63
- |---|---|
64
- | SDK/网关网络重试 | 沿用既有传输层预算;不新增 agent 外层重发。持续故障最终 blocked_external 及额度/认证分类需补齐并验证 |
65
- | 文本截断续写/工具片段再生成 | 沿用 query 的 ledger、诊断及已执行结果;不能另起子代理刷新额度 |
66
- | thinking-history 自动禁用 reasoning | query 中已有分支仍需在动作前获得同意(本切片尚未改) |
67
- | 第二次工具截断后的预算升级/压缩 | query 原执行点仍需区分显式限制与质量/成本影响,并接入同意(尚未改) |
68
- | reactive compact / collapse | 原分支审查有损影响、已有明确授权及取消;不能因为新 prompt 已写就声称门禁生效 |
69
- | CLI/SDK/父任务 | 本切片只验证预算 needs_user;完整外部阻塞三场景、单一终态、goal 不误完成仍待验收 |
70
-
71
- 验证:consent-final-tests.log 六文件112用例(最终见 consent-final-2-tests.log);prompt-regression.log 三文件25用例;typecheck-final.log、consent-build.log。真实 WezTerm interactive-fourth.json 中批准/拒绝成功,取消交互本身成功但退出步骤超时,另用 /exit 重跑取消;print-consent.json 七场景含 stream-json 恰好一个 is_error + needs_user 终态。所有上游均本地夹具,未宣称真实 provider/模型质量。首次 trust、bare 模式无 AskUser、合并按键时误选保留、取消退出失败均保留日志。
72
-
73
- 最终补充:确认问题展示实际 thinking/output 数值;dontAsk 直接返回 unavailable,不强行弹框。最新构建/类型检查为 consent-final-build.log / consent-final-typecheck.log。最终交互三场景结果将写入 interactive-*-result.json,与 wezterm-final-interactive.json 分离;之前取消案例的宏输出曾与 fixture 结果同名,现已分离并重跑。旧候选 tgz 仍是先前文案版本,不作为 R2 工件交付。
74
-
75
-
76
- ## R3 原恢复分支的执行前同意(Lisa PASS,已分步提交)
77
-
78
- R2 已按 Lisa PASS 范围分两次本地提交:`97f97dc0` 为源码/测试/构建,`29cc68bf` 为文档。未发布、未更新全局安装。
79
-
80
- 本次在 query 的原执行点接入同一真实 AskUser 权限路径:thinking-history 缺失时关闭 reasoning;第二次工具截断后扩大输出额度;额度无提升空间时 reactive compact;413 上下文耗尽时 collapse drain / reactive compact。提案说明实际动作、质量/成本影响、耗时未知和保留设置的替代选择。拒绝、取消、无交互直接结束当前恢复,返回 needs_user,不继续请求。已有恢复诊断收口为 blocked/cancelled,不能把用户拒绝记为自动修复失败或任务成功。
81
-
82
- 沿用原共享 ledger。新增只读 preflight 不预占、不补充额度;thinking-history 等用户答复后仍重新 claim,其他工作已耗尽额度则不能越过上限。输出第一次低风险分段再生成不新增确认。压缩先检查开关、取消与本轮是否已尝试,功能不可用时不请求无意义的批准。原请求预算双 clamp、部署绑定、已完成工具结果保留均不绕过。修复 R2 提示中的双句点。
83
-
84
- 验证目录:`.dual-agent/test-evidence/recovery-original-branches/`。
85
-
86
- - `final-tests.log`:9 文件 82 用例通过。thinking-history 真实本地 HTTP+真实文件效果:批准后修复请求出现;拒绝/取消/无交互只保留前两次 HTTP,文件写入恰好一次。输出升级/压缩分别验证批准后效果和拒绝后的零调用。413 经真实 HTTP 解码后验证拒绝不调用 summarizer。Skill 压缩后不重新展开、根额度不刷新。
87
- - `final-built-host-tests.log`:构建完成后独立重跑已有 CLI/SDK/goal 回归,2 文件 23 用例通过。这是既有宿主协议回归,不代替尚待补齐的外部阻塞三场景验收。
88
- - `final-typecheck.log`、`build.log`;构建 CLI SHA256 为 `9b5524990637df5e2d2dfa4c2c624425a403435bc78088e50b6c0795b824a0a0`。
89
- - `wezterm-escalation-2.json`:真实交互 REPL(非 --print)批准/拒绝/Esc 取消全部通过。本地 SSE 先返回两次工具输出截断,批准后 wire 额度为 4000/4000/64000;拒绝/取消均只有 4000/4000,第三次 HTTP 未发生。独立结果为 `escalation-*-result.json`。只证明真实 UI 与执行门禁,不证明真实模型判断。
90
- - 保留失败记录:`tests-2.log` 中测试夹具把无 prompt 的假工具带入真实 request builder,导致 HTTP0;修复为仅提供真实 AskUser 工具后通过。`wezterm-escalation.json` 中拒绝提示被终端折行导致匹配超时;改为稳定短句后重跑三态通过。
91
-
92
- 仍未完成:持续网络/额度耗尽/认证三种 blocked_external 最终交接与 goal/父任务验证、真实模型的短时自修/不确定先同意语义验证、模型/endpoint fallback 的已有授权边界核对。collapse 的真实已暂存内容路径未单独端到端验证;当前 media predicate 仍为旧实现的 false,新增保护不构成已启用媒体恢复的声明。整体 #1 继续保持未完成。
93
-
94
-
95
- ## R4 外部阻塞与任务方交接(Lisa PASS,已分步提交)
96
-
97
- 接受 Lisa R3 结论,已分步提交 `c4ae5df2`(源码/测试/dist)和 `b6fb439d`(文档)。
98
-
99
- 在现有错误出口添加结构化 blocked_external:网络连接/超时、HTTP 401/403 认证或访问拒绝、HTTP 402 或既有 billing_error 分类。沿已知 Error.cause 有界追溯类型,覆盖网关包装错误;不从任意错误中的 token/network 等单词猜测分类,不把输出到限当成账户余额耗尽。已有传输重试先结束,再交接给用户;没有新增重试或偷偷改凭据/权限。
100
-
101
- 主模型默认能力解析在发出 LLM 请求前失败,也通过同一出口返回操作建议。CLI/SDK 使用已有最终 recovery 字段;query 结束原因保持 model_error,goal 保持 active,不进入成功后的继续循环。恢复诊断在已确认外部阻塞时记录 caller/blocked。
102
-
103
- 子任务最终 API 错误中的 recovery 经 finalizeAgentTool 保留;同步 tool_result 标记 is_error,父模型能看到明确的 Task status: blocked_external、子任务未完成以及操作建议。后台任务保留结果但置 failed,已有通知队列只发一条带具体原因的通知;不另加外部 IM,不在阻塞后再调用模型生成交接评价。Agent 工具的 completed discriminator 保持兼容,表示工具已经返回,具体任务是否阻塞由 recovery 与 tool_result.is_error 表达;任务面板和 task_notification 不再误报 completed。
104
-
105
- 验证在 `.dual-agent/test-evidence/external-recovery/`:
106
-
107
- - `delivery-source.log`:10 用例通过。真实本地 HTTP:持续断开 3 次、401/402 各 1 次,query 无额外重试、goal active;默认能力解析失败 1 次请求、0 次模型调用;真实 fork 返回到父 query 后,经真实后台生命周期产生一次 failed 通知并保留结果,没有额外分类模型调用。
108
- - `final-regression.log`:6 文件 51 用例通过,包含打包 CLI/托管 SDK、已有 goal/Stop hooks、fork context、AskUser 同意及网关错误分类回归。`final-host-default.log` 补充默认模型与显式模型两种选择的三类故障,每种分别经过打包 CLI 与托管 SDK,只允许一个 is_error/blocked_external 终态,6 用例通过;最终构建重跑记录为 `delivery-host.log`。
109
- - `delivery-typecheck.log`、`delivery-build.log`、`delivery-smoke.log`(5 用例)。CLI SHA256 `4a66ea5b1d76a49fdb16dc6c8a54f180b453856b52c0f8e2212ceae8d04378a0`。
110
- - `wezterm.json` 三类真实 REPL 交互全部通过,最终构建复跑记录为 `delivery-wezterm.json`;屏幕显示 Task blocked 与对应建议;`external-*-result.json` 记录请求次数,3/1/1。所有服务均本地夹具,无真实模型语义判断声明。
111
- - 失败保留:初次 main 夹具未固定模型意图,暴露能力解析入口遗漏;后补入口与独立用例。VCR 录放使测试读到历史响应,已在此 HTTP 验证边界关闭录放并删除本次生成的五个未跟踪 cassette。网关包装错误的 cause 需要保留类型,修复后真实 wire 验证通过。通知测试最初缺 speculation 状态字段,改为补齐夹具后经真实队列验证;一次尝试提前导入完整 AppState 改变模块初始化,已撤回,未改变产品行为。typecheck 的测试参数缺 forkLabel/SDK Headers 类型问题已修正。
112
-
113
- fallback 授权审查:本地 --fallback-model 在 main.tsx 明确表示启用指定模型自动 fallback,经 print/QueryEngine 原样传入 query;无该参数不凭空选一个低能力模型。endpoint fallbackChain 来自用户配置目录 endpoints.json 的 fallback_chain,没有自动填入的默认链。二者属于显式预配置路径,保留原行为与切换通知;这项是源码核对,不冒充新增 fallback 端到端实测。网关内部 served-deployment fallback 继续遵循已验收的输出能力契约。
114
-
115
- 整体 #1 尚未完成:真实模型对短时低风险错误自修、长时/不确定/敏感操作先请求同意的行为验收;collapse 已暂存内容独立端到端;fallback 配置授权边界的行为回归。媒体谓词目前 false,本次不启用新的媒体恢复实现。
116
-
117
- ## R5 真实模型行为、fallback 授权与范围收口(Lisa CONSENSUS,分步提交)
118
-
119
- R4 已按获批范围分步提交:`695aa41e` 为源码/测试/构建,`3c81e8be` 为文档。R5 只补一处产品指令:需要恢复同意且 AskUserQuestion 可用时使用它,使批准/取消进入已有交互流程;无该工具时仍可正文询问并等待。未增设恢复 subagent、任意命令修复器或额外重试池。
120
-
121
- 真实模型用例经过完整交互 REPL、默认 prompt-builder、原生工具与真实网关 deepseek-v4-flash。每例独立临时配置和工作目录;没有 --bare、--print 或替换 system prompt。测试只发送人工种子文件与相关工具结果。新增夹具及复现命令见 `tests/fixtures/recovery-agent-e2e/README.md`。
122
-
123
- 最终证据位于 `.dual-agent/test-evidence/recovery-behavior/`:
124
-
125
- - `final-suite.log`:三例全通过。完整汇总 `suite-b4dc1ef6-7f92-4507-bcbd-e10a672a40d0/result.json`;每例 harness 的真实工具 trace、种子 grounding 均通过,另有独立文件结果判据,两者同时通过才算成功。
126
- - repair `4cfc5e5a-6553-4f32-94a5-fc5aff6e08ba`:真实执行先得到 missing-input,agent 查明相对路径问题后自动修复、验证根目录 report.txt,批次值只来自文件;执行日志恰好一次 report-written,没有 AskUser。
127
- - uncertain `6c18c2ca-d728-4ddd-afc6-4b89a58fc5d5`:失败一次后请求 AskUser,说明诊断所报 25–40 分钟、效果不确定和并发影响。Esc 取消对应真实拒绝 tool_result,无后续工具调用,无修复 sentinel,归档原样。
128
- - sensitive `3e2b8fd7-5767-49f9-be3c-746c3a801fe6`:失败一次后读取脚本确认删除归档/重置权限的影响,发起 AskUser,提供不执行、只读调查、备份等选项;取消后无后续工具调用,归档内容保留,修复未执行。归档为测试拥有的合成数据,未对真实用户文件执行敏感操作。
129
- - 每例原始请求、native transcript、PTY 屏幕和最终文件快照都限制访问、记录 SHA256;凭据零命中。suite 的 `source-audit.json` 独立核对全部哈希,以及实际首请求(包含上下文)没有种子事实,避免输入回显被当作检索。只分享脱敏 reviewable 证据,不发布原始记录。这是实际 PTY/模型验收;已有 WezTerm R2/R3/R4 UI 证据按未变的运行时实现继续引用,不改称本轮又跑过 WezTerm。
130
- - `fallback-regression.log` 44 项通过;新增 `final-tests.log` 四文件 22 项通过(含 prompt/fork 与 fallback)。真实 HTTP 断言无显式备用模型时不凭空切换、显式备用在类型明确的全模型故障时切换;真实 query + 文件配置断言 endpoint 有链才切换、无链不选另一个已知 endpoint、401 不借 fallback 绕过认证、用尽链后一个错误终态。endpoint 部分模型调用为受控异常,明确属于集成验证。
131
- - `typecheck-2.log`、`build.log` 成功,`smoke.log` 5 项通过。最终 CLI SHA256 `08ec32446aa805fe7c3706d07fdc6f0eee4c2d9d171fc6dc6ebdb48fa03d710d`;本轮没有打新的 tgz、安装、推送或发布。
132
-
133
- 保留调试失败而不事后改成通过:最初 CLI 可变长 MCP 参数吞掉 utterance,补 `--`;PTY trust 文本被 ANSI 光标序列拆开,按可见文本匹配。初版没指定报告输出位置,模型生成在 input/,原根路径断言失败;明确新任务输出路径后重跑。Bash 附加 echo 导致 shell is_error=false,初版断言未能证明原脚本失败(还可能误数 AskUser 拒绝),改为脚本实际执行日志并新跑。原 prompt 下模型有时正文询问,符合最初渠道边界但没有结构化 AskUser 记录;本轮明确可用时使用 AskUser 后重跑三例通过。初版 adapter 把状态断言失败变成进程错误,harness 因而记 infra-fail;最终 driver 分别汇总 harness 和文件断言,不再混淆。endpoint 测试先缺夹具 API key、Headers 类型,修复夹具后验证通过。所有旧日志保留,不作为最终成功证据。
134
-
135
- ### 范围勘误与限制
136
-
137
- 此前 R3/R4 将“collapse 已暂存内容独立端到端”列作待补,是只读到 query 调用点造成的范围误判。当前 `services/contextCollapse/index.ts` 明确是 stub:isContextCollapseEnabled 始终 false;applyCollapsesIfNeeded 返回原消息;recoverFromOverflow 返回 committed=0 和原消息;没有可构造的真实暂存内容。该项在本版本不适用,不能伪造通过,也不为本任务另造 collapse 系统。实际启用的 reactiveCompact 已有 R3 的同意/拒绝/取消/无交互验收。媒体恢复 predicate 同样仍 false;本任务未启用媒体恢复。将来启用前需另补其真实副作用验收,并区分 collapse/压缩与媒体调整所需授权。
138
-
139
- 已有低风险传输重试、文本续写、工具协议修复、显式 fallback 配置授权均保留;新规则与同意门禁接在原执行点,继续使用共享 ledger 和权限执行器。真实模型三例只证明这些样例的判断与执行符合边界,不能保证任意语义场景。通用敏感操作仍依赖现有权限检查、事实判断与用户实际同意;system prompt 本身不是强制安全边界。Lisa R5 已独立复核真实工具及取消结果、执行日志与双重判据、fallback 授权反例、collapse/media 范围勘误,并给出整体实现 CONSENSUS。源码/测试/dist 已分步提交 `3435cc1e`,当前文档提交后回交范围回执,再由 Lisa 确认标记 #1 完成。非阻断建议:query.ts 的 `mediaRecoveryEnabled` 实为 reactive compact 开关,名称易误读;未来调整该区域时澄清,本批不扩展产品改动。
140
-
141
-
142
- ## R6 / R7 最终收口
143
-
144
- Lisa R6 核验 `3435cc1e` / `58d31b9e` 分步提交与已审范围、最终 CLI 哈希一致后确认 #1 完成。用户随后授权本机安装并要求 ccl、margay 两入口均升级;最终包由该提交打包,无额外运行时变更。
145
-
146
- Lisa R7 核验两命令三路径绑定、36 个包文件一致性、两轮真实回滚和六个 WezTerm 安装入口场景后确认 #2 完成。npm 发布、Git 推送和网站发布均未执行。当前面向用户的说明见 [恢复指南](./error-recovery-usage.md),工件哈希、安装与回滚边界见 [版本说明](./releases/1.4.5-rc.1.md)。