@sema-agent/server 7.146.0 → 7.147.0

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 (398) hide show
  1. package/MIGRATION.md +384 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +170 -66
  5. package/deploy/facts/lanes.json +7 -0
  6. package/deploy/sema-up/README.md +2 -2
  7. package/deploy/sema-up/chart/templates/_helpers.tpl +22 -0
  8. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
  9. package/deploy/sema-up/chart/templates/server.yaml +5 -4
  10. package/deploy/sema-up/chart/values.yaml +1 -1
  11. package/deploy/sema-up/cluster-up.sh +2 -1
  12. package/deploy/sema-up/lib/flagshape.sh +4 -0
  13. package/deploy/sema-up/lib/lanes.json +2 -5
  14. package/deploy/sema-up/sema-up.sh +12 -9
  15. package/deploy/sema-up/stack/compose.yaml +5 -4
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -3
  17. package/dist/approval-card.d.ts +4 -4
  18. package/dist/approval.d.ts +3 -3
  19. package/dist/audit.js +2 -2
  20. package/dist/bench/s1/live-deps.js +3 -1
  21. package/dist/boot/crash-last.js +2 -1
  22. package/dist/boot/device-lane.js +5 -5
  23. package/dist/boot/engine-lease.d.ts +12 -11
  24. package/dist/boot/execution-env.d.ts +2 -1
  25. package/dist/boot/execution-env.js +45 -33
  26. package/dist/boot/execution-lane.d.ts +37 -9
  27. package/dist/boot/execution-lane.js +74 -20
  28. package/dist/boot/exit-boundary.d.ts +1 -1
  29. package/dist/boot/exit-last.js +2 -1
  30. package/dist/boot/governance-seams.d.ts +2 -2
  31. package/dist/boot/leader.js +1 -1
  32. package/dist/boot/memory-boundary.d.ts +11 -11
  33. package/dist/boot/memory-boundary.js +3 -3
  34. package/dist/boot/memory-consolidation.d.ts +13 -24
  35. package/dist/boot/memory-consolidation.js +0 -13
  36. package/dist/boot/org-memory.js +3 -2
  37. package/dist/boot/parked-revive-gate.d.ts +1 -1
  38. package/dist/boot/parked-revive-gate.js +1 -1
  39. package/dist/boot/reapers.js +1 -1
  40. package/dist/boot/resolve-spec.js +91 -111
  41. package/dist/boot/retention-lane.d.ts +4 -42
  42. package/dist/boot/session-faces.d.ts +1 -0
  43. package/dist/boot/session-faces.js +8 -2
  44. package/dist/boot/stage-01-config.d.ts +1 -1
  45. package/dist/boot/stage-01-config.js +6 -2
  46. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
  47. package/dist/boot/stage-02-web-admin-pull.js +10 -8
  48. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  49. package/dist/boot/stage-04-stores.d.ts +1 -1
  50. package/dist/boot/stage-05-execution-env.d.ts +2 -2
  51. package/dist/boot/stage-05-execution-env.js +3 -3
  52. package/dist/boot/stage-06-runners.d.ts +3 -3
  53. package/dist/boot/stage-06-runners.js +1 -3
  54. package/dist/boot/stage-07-capability-layer.d.ts +3 -3
  55. package/dist/boot/stage-07-capability-layer.js +4 -9
  56. package/dist/boot/stage-08-reapers.d.ts +3 -3
  57. package/dist/boot/stage-09-leader.d.ts +4 -3
  58. package/dist/boot/stage-10-http-server.d.ts +4 -3
  59. package/dist/boot/stage-10-http-server.js +2 -1
  60. package/dist/boot/stores.d.ts +9 -0
  61. package/dist/boot/stores.js +18 -7
  62. package/dist/boot/web-admin.js +3 -3
  63. package/dist/capabilities/center-plugins.d.ts +2 -0
  64. package/dist/capabilities/center-plugins.js +6 -2
  65. package/dist/capabilities/composite-members.d.ts +1 -0
  66. package/dist/capabilities/composite-members.js +1 -0
  67. package/dist/capabilities/execution-lane.d.ts +7 -7
  68. package/dist/capabilities/execution-lane.js +2 -2
  69. package/dist/capabilities/hands-lane.d.ts +1 -1
  70. package/dist/capabilities/scenarios.d.ts +32 -18
  71. package/dist/capabilities/scenarios.js +13 -9
  72. package/dist/capabilities/settings-contract.d.ts +29 -0
  73. package/dist/capabilities/settings-contract.js +14 -0
  74. package/dist/capabilities/skills.d.ts +5 -5
  75. package/dist/capability-facts.d.ts +38 -0
  76. package/dist/capability-facts.js +34 -1
  77. package/dist/center-credential-renewer.js +3 -2
  78. package/dist/config-catalog.js +6 -5
  79. package/dist/config-invariants.d.ts +18 -3
  80. package/dist/config-invariants.js +36 -19
  81. package/dist/config-lkg.d.ts +1 -1
  82. package/dist/config-lkg.js +5 -6
  83. package/dist/config-provider.js +2 -0
  84. package/dist/config-types.d.ts +190 -186
  85. package/dist/config.d.ts +68 -5
  86. package/dist/config.js +80 -54
  87. package/dist/degenerate-instrument.js +1 -1
  88. package/dist/deploy-facts.js +3 -2
  89. package/dist/deployment-shape.d.ts +21 -12
  90. package/dist/deployment-shape.js +24 -6
  91. package/dist/env-facts.d.ts +7 -5
  92. package/dist/env-facts.js +10 -6
  93. package/dist/execution-config-root.d.ts +5 -5
  94. package/dist/execution-config-root.js +5 -5
  95. package/dist/execution-env-purpose.d.ts +14 -0
  96. package/dist/execution-env-purpose.js +29 -0
  97. package/dist/execution-lane-caps.d.ts +49 -86
  98. package/dist/execution-lane-caps.js +52 -62
  99. package/dist/execution-placement.d.ts +18 -2
  100. package/dist/execution-placement.js +19 -0
  101. package/dist/file-history-disclosure.d.ts +2 -2
  102. package/dist/fleet/drain-entry.d.ts +17 -10
  103. package/dist/fleet/drain-entry.js +1 -1
  104. package/dist/fleet/serving-lease.js +3 -4
  105. package/dist/history-anchor.d.ts +22 -0
  106. package/dist/history-anchor.js +14 -0
  107. package/dist/hooks/command-spawn.d.ts +1 -4
  108. package/dist/hooks/command-spawn.js +0 -11
  109. package/dist/hooks/hook-runner.d.ts +52 -8
  110. package/dist/hooks/hook-runner.js +160 -36
  111. package/dist/http/approval-sweeps.d.ts +2 -5
  112. package/dist/http/approval-sweeps.js +3 -2
  113. package/dist/http/checkpoint-ctx.d.ts +17 -0
  114. package/dist/http/checkpoint-ctx.js +6 -0
  115. package/dist/http/claim-latency.d.ts +10 -0
  116. package/dist/http/claim-latency.js +12 -0
  117. package/dist/http/dispatch.js +1 -1
  118. package/dist/http/durable-run-leg.js +2 -1
  119. package/dist/http/execution-context.d.ts +3 -1
  120. package/dist/http/execution-context.js +4 -0
  121. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  122. package/dist/http/memory-compliance-failure-reply.js +3 -0
  123. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  124. package/dist/http/memory-store-refusal-reply.js +3 -0
  125. package/dist/http/owner-access.d.ts +11 -0
  126. package/dist/http/owner-access.js +7 -4
  127. package/dist/http/principal-gate.d.ts +3 -14
  128. package/dist/http/principal-gate.js +0 -13
  129. package/dist/http/request-guards.d.ts +1 -1
  130. package/dist/http/resume-legs.d.ts +7 -10
  131. package/dist/http/resume-legs.js +79 -50
  132. package/dist/http/rewind-files-reply.d.ts +34 -0
  133. package/dist/http/rewind-files-reply.js +36 -0
  134. package/dist/http/route-ctx.d.ts +32 -16
  135. package/dist/http/route-table.js +2 -0
  136. package/dist/http/routes/approvals-assistant.js +5 -25
  137. package/dist/http/routes/capabilities.js +8 -2
  138. package/dist/http/routes/devices.js +1 -1
  139. package/dist/http/routes/memory-origin.d.ts +1 -1
  140. package/dist/http/routes/notify-wake.js +2 -1
  141. package/dist/http/routes/projects.d.ts +70 -0
  142. package/dist/http/routes/projects.js +86 -0
  143. package/dist/http/routes/rules.js +30 -2
  144. package/dist/http/routes/runs.js +8 -8
  145. package/dist/http/routes/session-sync.js +27 -10
  146. package/dist/http/routes/sessions.d.ts +7 -1
  147. package/dist/http/routes/sessions.js +104 -2
  148. package/dist/http/routes/tasks.js +9 -3
  149. package/dist/http/server.d.ts +24 -10
  150. package/dist/http/server.js +17 -6
  151. package/dist/http/stored-body-replay.d.ts +5 -3
  152. package/dist/http/stored-body-replay.js +10 -1
  153. package/dist/http/wire-types.d.ts +19 -10
  154. package/dist/index.d.ts +2 -2
  155. package/dist/index.js +1 -1
  156. package/dist/instruction-source-notice.d.ts +1 -1
  157. package/dist/memory-embedder-reembed.d.ts +38 -0
  158. package/dist/memory-embedder-reembed.js +20 -0
  159. package/dist/memory-incident-sink.d.ts +0 -28
  160. package/dist/memory-incident-sink.js +5 -0
  161. package/dist/memory-scope.d.ts +2 -2
  162. package/dist/memory-scope.js +1 -1
  163. package/dist/memory-store-refusal.d.ts +17 -4
  164. package/dist/memory-store-refusal.js +1 -1
  165. package/dist/memory-sync-client.d.ts +2 -0
  166. package/dist/memory-sync-client.js +13 -11
  167. package/dist/memory-sync.js +1 -1
  168. package/dist/model-compat.d.ts +35 -21
  169. package/dist/model-compat.js +49 -21
  170. package/dist/model-entry-refusal.d.ts +11 -1
  171. package/dist/model-entry-refusal.js +7 -0
  172. package/dist/namespaced-rule-name.d.ts +18 -1
  173. package/dist/namespaced-rule-name.js +12 -0
  174. package/dist/observability/fail-open.d.ts +17 -9
  175. package/dist/observability/fail-open.js +17 -9
  176. package/dist/observability/metrics.d.ts +2 -0
  177. package/dist/observability/metrics.js +2 -0
  178. package/dist/observability/secret-env-scrub.d.ts +30 -4
  179. package/dist/observability/secret-env-scrub.js +15 -3
  180. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  181. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  182. package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
  183. package/dist/orchestration/workflow-completion-inbox.js +63 -45
  184. package/dist/org-memory-admission.d.ts +5 -2
  185. package/dist/org-memory-admission.js +25 -10
  186. package/dist/parked-decide.d.ts +33 -26
  187. package/dist/parked-decide.js +36 -44
  188. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  189. package/dist/plugins/approval-ask-store-file.js +37 -4
  190. package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
  191. package/dist/plugins/approval-ask-store-memory.js +11 -2
  192. package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
  193. package/dist/plugins/approval-ask-store-sql.js +3 -1
  194. package/dist/plugins/blob-backend.d.ts +38 -195
  195. package/dist/plugins/blob-backend.js +33 -229
  196. package/dist/plugins/caching-session-store.d.ts +9 -4
  197. package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
  198. package/dist/plugins/checkpoint-index-columns.js +3 -2
  199. package/dist/plugins/checkpoint-store-face.d.ts +1 -1
  200. package/dist/plugins/device-store-sql.d.ts +2 -2
  201. package/dist/plugins/device-store-sql.js +5 -10
  202. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  203. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  204. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  205. package/dist/plugins/execution-placement-sql.js +94 -54
  206. package/dist/plugins/file-run-store.d.ts +26 -12
  207. package/dist/plugins/file-run-store.js +63 -63
  208. package/dist/plugins/imported-layer-root-retirement.d.ts +17 -8
  209. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  210. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  211. package/dist/plugins/inbox-payload-column.js +13 -0
  212. package/dist/plugins/local-checkpoint-store.d.ts +5 -0
  213. package/dist/plugins/local-checkpoint-store.js +11 -7
  214. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  215. package/dist/plugins/local-data-dir-modes-m39.js +182 -0
  216. package/dist/plugins/local-engine-high-water.d.ts +11 -0
  217. package/dist/plugins/local-engine-high-water.js +59 -0
  218. package/dist/plugins/local-session-store.d.ts +91 -25
  219. package/dist/plugins/local-session-store.js +124 -45
  220. package/dist/plugins/local-task-attachment-store.d.ts +2 -0
  221. package/dist/plugins/local-task-attachment-store.js +10 -11
  222. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  223. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  224. package/dist/plugins/memory-embedder.d.ts +1 -1
  225. package/dist/plugins/memory-embedder.js +2 -2
  226. package/dist/plugins/memory-engine-pg.d.ts +4 -3
  227. package/dist/plugins/memory-engine-pg.js +4 -4
  228. package/dist/plugins/memory-engine-sql-apply.d.ts +13 -4
  229. package/dist/plugins/memory-engine-sql-apply.js +1 -1
  230. package/dist/plugins/memory-engine-tidb.d.ts +8 -5
  231. package/dist/plugins/memory-engine-tidb.js +7 -8
  232. package/dist/plugins/one-time-migrations.d.ts +145 -35
  233. package/dist/plugins/one-time-migrations.js +272 -120
  234. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  235. package/dist/plugins/owner-only-file-mode.js +141 -0
  236. package/dist/plugins/permission-rule-store-file.d.ts +8 -8
  237. package/dist/plugins/permission-rule-store-file.js +14 -2
  238. package/dist/plugins/pg-pool.d.ts +2 -1
  239. package/dist/plugins/pg-pool.js +11 -4
  240. package/dist/plugins/release-version.d.ts +20 -0
  241. package/dist/plugins/release-version.js +28 -0
  242. package/dist/plugins/remote-env-adb.d.ts +20 -4
  243. package/dist/plugins/remote-env-adb.js +39 -11
  244. package/dist/plugins/remote-env-e2b.d.ts +12 -3
  245. package/dist/plugins/remote-env-e2b.js +6 -4
  246. package/dist/plugins/remote-env-host.d.ts +9 -1
  247. package/dist/plugins/remote-env-host.js +6 -5
  248. package/dist/plugins/remote-env-k8s.d.ts +5 -2
  249. package/dist/plugins/remote-env-k8s.js +15 -4
  250. package/dist/plugins/remote-env-local-docker.d.ts +4 -1
  251. package/dist/plugins/remote-env-local-docker.js +3 -3
  252. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  253. package/dist/plugins/remote-env-ssh.js +26 -24
  254. package/dist/plugins/remote-shell.d.ts +59 -30
  255. package/dist/plugins/remote-shell.js +175 -62
  256. package/dist/plugins/retention-declaration.d.ts +37 -0
  257. package/dist/plugins/retention-declaration.js +9 -0
  258. package/dist/plugins/retention-deployment.d.ts +126 -0
  259. package/dist/plugins/retention-deployment.js +88 -0
  260. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  261. package/dist/plugins/retention-lane-store-sql.js +103 -1
  262. package/dist/plugins/retention-sql.d.ts +29 -0
  263. package/dist/plugins/retention-sql.js +8 -0
  264. package/dist/plugins/schema-consistency.d.ts +0 -6
  265. package/dist/plugins/schema-consistency.js +1 -2
  266. package/dist/plugins/schema-ensure-legs.d.ts +1 -1
  267. package/dist/plugins/schema-ensure-legs.js +11 -1
  268. package/dist/plugins/session-ext-table.d.ts +74 -0
  269. package/dist/plugins/session-ext-table.js +121 -0
  270. package/dist/plugins/session-fork.d.ts +1 -1
  271. package/dist/plugins/session-row-sql.d.ts +8 -7
  272. package/dist/plugins/session-row-sql.js +15 -7
  273. package/dist/plugins/session-store-sql.d.ts +131 -0
  274. package/dist/plugins/session-store-sql.js +298 -0
  275. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  276. package/dist/plugins/session-workspace-cell.js +2 -2
  277. package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
  278. package/dist/plugins/shared-memory-store-sql.js +13 -13
  279. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  280. package/dist/plugins/sql-driver.d.ts +23 -7
  281. package/dist/plugins/sql-driver.js +41 -8
  282. package/dist/plugins/sql-errors.d.ts +5 -2
  283. package/dist/plugins/sql-errors.js +4 -0
  284. package/dist/plugins/store-backend.d.ts +35 -8
  285. package/dist/plugins/store-backend.js +184 -62
  286. package/dist/plugins/store-contracts.d.ts +9 -2
  287. package/dist/plugins/store-contracts.js +1 -0
  288. package/dist/plugins/task-attachment-store.d.ts +6 -8
  289. package/dist/plugins/task-attachment-store.js +15 -10
  290. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  291. package/dist/plugins/text-column-capacity.d.ts +21 -0
  292. package/dist/plugins/text-column-capacity.js +5 -0
  293. package/dist/plugins/tidb-pool.d.ts +3 -2
  294. package/dist/plugins/tidb-pool.js +19 -31
  295. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  296. package/dist/read-face-posture.d.ts +6 -6
  297. package/dist/read-face-posture.js +2 -2
  298. package/dist/request-value-closure.d.ts +5 -5
  299. package/dist/request-value-closure.js +1 -1
  300. package/dist/rules-consent.d.ts +41 -13
  301. package/dist/rules-consent.js +101 -53
  302. package/dist/run-local.js +17 -13
  303. package/dist/runs.d.ts +48 -30
  304. package/dist/runs.js +26 -16
  305. package/dist/runtime-caps-resolver.d.ts +15 -8
  306. package/dist/runtime-caps-resolver.js +14 -10
  307. package/dist/sealed-key-layout.d.ts +2 -3
  308. package/dist/sealed-key-layout.js +0 -1
  309. package/dist/sealed-key.js +7 -5
  310. package/dist/security.d.ts +5 -3
  311. package/dist/sema-config-dir.js +2 -2
  312. package/dist/server-secret-env.d.ts +2 -0
  313. package/dist/service-version.d.ts +2 -1
  314. package/dist/service-version.js +2 -2
  315. package/dist/session-error-wire.d.ts +1 -1
  316. package/dist/session-incarnation.d.ts +8 -5
  317. package/dist/session-resident-background.d.ts +85 -32
  318. package/dist/session-resident-background.js +75 -7
  319. package/dist/session-row.d.ts +1 -1
  320. package/dist/session-sync-kernel.d.ts +1 -1
  321. package/dist/session-workspace.d.ts +11 -2
  322. package/dist/session-workspace.js +5 -0
  323. package/dist/sighup-idle.d.ts +1 -1
  324. package/dist/store-posture.d.ts +2 -1
  325. package/dist/stored-request-hooks-m20.d.ts +3 -2
  326. package/dist/stored-request-hooks-m20.js +19 -14
  327. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  328. package/dist/stores-sql/blob-index-sql.js +154 -0
  329. package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
  330. package/dist/stores-sql/checkpoint-store-sql.js +11 -27
  331. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  332. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  333. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +23 -76
  334. package/dist/{plugins → stores-sql}/pg-session-storage.js +80 -209
  335. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
  336. package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
  337. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  338. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  339. package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
  340. package/dist/stores-sql/session-write-hooks.d.ts +59 -0
  341. package/dist/stores-sql/session-write-hooks.js +2 -0
  342. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
  343. package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
  344. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +32 -122
  345. package/dist/{plugins → stores-sql}/tidb-session-store.js +71 -171
  346. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  347. package/dist/stores-sql/tool-result-store-sql.js +1 -1
  348. package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
  349. package/dist/stores-sql/windowed-session-storage.js +61 -0
  350. package/dist/task-a2a.d.ts +7 -1
  351. package/dist/task-a2a.js +15 -14
  352. package/dist/task-cwd.d.ts +11 -3
  353. package/dist/task-cwd.js +17 -1
  354. package/dist/task-mcp.d.ts +10 -2
  355. package/dist/task-mcp.js +13 -16
  356. package/dist/task-settings.d.ts +9 -4
  357. package/dist/task-settings.js +17 -6
  358. package/dist/tool-approval.d.ts +21 -8
  359. package/dist/tool-approval.js +10 -6
  360. package/dist/trace/core-keyset-guard.d.ts +9 -3
  361. package/dist/trace/engine-notice-wire.d.ts +1 -1
  362. package/dist/trace/engine-notice-wire.js +2 -0
  363. package/dist/trace/exit-seat.d.ts +23 -1
  364. package/dist/trace/exit-seat.js +3 -0
  365. package/dist/trace/project.d.ts +33 -16
  366. package/dist/trace/project.js +12 -9
  367. package/dist/trace/redact.d.ts +1 -1
  368. package/dist/trace/redact.js +61 -73
  369. package/dist/trace/self-minted-wire.d.ts +263 -10
  370. package/dist/trace/self-minted-wire.js +90 -2
  371. package/dist/trace/sema-provenance.d.ts +45 -41
  372. package/dist/trace/sema-provenance.js +81 -10
  373. package/dist/trace/task-notification-facets.d.ts +70 -2
  374. package/dist/trace/task-notification-facets.js +71 -1
  375. package/dist/trace/wire-projection-faces.d.ts +38 -2
  376. package/dist/trace/wire-projection-faces.js +26 -1
  377. package/dist/unread-request-members.d.ts +66 -0
  378. package/dist/unread-request-members.js +41 -0
  379. package/dist/user-input-ledger.d.ts +2 -2
  380. package/dist/web-admin-client/apply-effective.js +22 -26
  381. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  382. package/dist/web-admin-client/candidate-gate.js +53 -5
  383. package/dist/web-admin-client/center-request.d.ts +4 -1
  384. package/dist/web-admin-client/center-request.js +2 -1
  385. package/dist/web-admin-client/effective-keys.js +0 -1
  386. package/dist/web-admin-client/facade.d.ts +1 -1
  387. package/dist/web-admin-client/http-client.d.ts +1 -0
  388. package/dist/web-admin-client/http-client.js +17 -9
  389. package/dist/web-admin-client/restart-signal.js +5 -2
  390. package/dist/web-admin-client/skills-mcp.d.ts +20 -6
  391. package/dist/web-admin-client/skills-mcp.js +26 -21
  392. package/dist/web-admin-client/types.d.ts +34 -49
  393. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
  394. package/package.json +13 -12
  395. package/scripts/drain-check-local.mjs +2 -28
  396. package/scripts/drain-check.mysql.sql +2 -18
  397. package/scripts/drain-check.pg.sql +2 -18
  398. package/wire-changes/server@7.147.0.json +813 -0
@@ -114,8 +114,12 @@ function isCommandRuleMatch(match) {
114
114
  }
115
115
  }
116
116
  const unknownReasonLogger = createLogger();
117
- function confirmRefusalWord(reason) {
117
+ function confirmRefusalWord(confirmed) {
118
+ const { reason } = confirmed;
118
119
  switch (reason) {
120
+ case "store_read":
121
+ case "store_write":
122
+ throw new RuleStoreFaultError({ code: reason, reason: confirmed.detail?.message ?? reason });
119
123
  case "edit_disabled":
120
124
  case "edit_binding_mismatch":
121
125
  return "edit-unsupported";
@@ -137,7 +141,7 @@ function confirmRefusalWord(reason) {
137
141
  }
138
142
  }
139
143
  }
140
- function isRuleStoreFault(code) {
144
+ export function isRuleStoreFault(code) {
141
145
  switch (code) {
142
146
  case "store_read":
143
147
  case "store_write":
@@ -158,8 +162,11 @@ function isRuleStoreFault(code) {
158
162
  case "occ":
159
163
  case "dot_removed":
160
164
  return false;
161
- default:
162
- return code;
165
+ default: {
166
+ const unknown = code;
167
+ unknownReasonLogger.warn("isRuleStoreFault: unknown RuleRefusalCode from core (dist/core version skew?) — read as not a store failure", { code: String(unknown) });
168
+ return false;
169
+ }
163
170
  }
164
171
  }
165
172
  class RuleStoreFaultError extends Error {
@@ -170,17 +177,37 @@ class RuleStoreFaultError extends Error {
170
177
  this.code = refusal.code;
171
178
  }
172
179
  }
173
- function throwIfRuleStoreFault(refusal) {
174
- const { code } = refusal;
175
- if (!isRuleStoreFault(code))
180
+ const retriableSkewLogger = createLogger();
181
+ function throwIfRetriable(refusal) {
182
+ if (!refusal.retriable)
176
183
  return;
177
- switch (refusal.committed) {
178
- case "no":
179
- throw new RuleStoreFaultError({ code, reason: refusal.reason });
180
- case "unknown":
181
- return;
182
- default:
183
- return refusal.committed;
184
+ const { code } = refusal;
185
+ if (isRuleStoreFault(code))
186
+ throw new RuleStoreFaultError({ code, reason: refusal.reason });
187
+ retriableSkewLogger.warn("an engine refusal says retriable but its code is not a store failure (core/dist skew?) — not retried", { code });
188
+ }
189
+ export function confirmRefusalRetries(reason) {
190
+ switch (reason) {
191
+ case "conflict":
192
+ case "store_read":
193
+ case "store_write":
194
+ return true;
195
+ case "record_not_found":
196
+ case "record_schema_stale":
197
+ case "record_malformed":
198
+ case "selection_missing":
199
+ case "selection_invalid":
200
+ case "selection_mismatch":
201
+ case "not_pending":
202
+ case "edit_disabled":
203
+ case "edit_binding_mismatch":
204
+ case "edit_rejected":
205
+ return false;
206
+ default: {
207
+ const unknown = reason;
208
+ unknownReasonLogger.warn("confirmRefusalRetries: unknown ConfirmRefusalReason from core (dist/core version skew?) — read as not retriable", { reason: String(unknown) });
209
+ return false;
210
+ }
184
211
  }
185
212
  }
186
213
  function refusedMembersOf(members) {
@@ -287,39 +314,51 @@ function buildLocalImportLayers(candidates) {
287
314
  return root === "" ? { layer: "userSettings", path: LOCAL_IMPORT_LAYER_PATH, readFile } : { layer: "projectSettings", path: `${LOCAL_IMPORT_LAYER_PATH}:${root}`, root, readFile };
288
315
  });
289
316
  }
290
- function buildImportOutcomeMembers(members) {
291
- return members.map((m) => {
317
+ function settleImportWalk(members) {
318
+ const settled = [];
319
+ for (const m of members) {
292
320
  const key = { behavior: m.behavior, rule: m.rule, scope: serializeRuleScope(m.scope) };
293
321
  switch (m.status) {
294
322
  case "persisted":
295
- return { key, outcome: "persisted" };
323
+ settled.push({ key, outcome: "persisted" });
324
+ break;
296
325
  case "deduped":
297
- return { key, outcome: "no-op" };
298
- case "refused":
299
- return { key, outcome: refusedOutcomeOf(m.committed), reason: m.code, detail: m.reason };
326
+ settled.push({ key, outcome: "no-op" });
327
+ break;
328
+ case "refused": {
329
+ const open = openRefusalOf(m);
330
+ if (open !== undefined)
331
+ return { open: `the outcome of ${m.rule} is not settled (${m.code}, ${open}): ${m.reason}` };
332
+ settled.push({ key, outcome: "refused", reason: m.code, detail: m.reason });
333
+ break;
334
+ }
300
335
  default: {
301
336
  const unknown = m;
302
337
  throw new Error(`unknown redeemed-batch member status: ${JSON.stringify(unknown)}`);
303
338
  }
304
339
  }
305
- });
306
- }
307
- function unsettledDetailOf(members) {
308
- const open = members.find((m) => m.outcome === "indeterminate");
309
- return open === undefined ? undefined : `the outcome of ${open.key.rule} is not known (${open.reason ?? "unknown"}): ${open.detail ?? ""}`;
340
+ }
341
+ return { settled };
310
342
  }
311
- function refusedOutcomeOf(committed) {
312
- switch (committed) {
343
+ function openRefusalOf(refusal) {
344
+ if (refusal.retriable)
345
+ return "retriable";
346
+ switch (refusal.committed) {
313
347
  case "no":
314
- return "refused";
348
+ return undefined;
315
349
  case "unknown":
316
- return "indeterminate";
350
+ return "committed unknown";
317
351
  default: {
318
- const unknown = committed;
352
+ const unknown = refusal.committed;
319
353
  throw new Error(`unknown redeemed-batch member committed word: ${JSON.stringify(unknown)}`);
320
354
  }
321
355
  }
322
356
  }
357
+ function importRecordRefusal(refusal) {
358
+ if (!refusal.retriable)
359
+ throw new Error(`the engine refused to prepare this import and says repeating will not help (${refusal.code}): ${refusal.reason}`);
360
+ return { ok: false, reason: "record-store-refused", committed: refusal.committed, detail: refusal.reason };
361
+ }
323
362
  export function createRuleConsentLane(stores, opts) {
324
363
  const deps = { provider: stores.provider, approvals: stores.approvals, cardEdits: true };
325
364
  const ticketTtlMs = opts?.ticketTtlMs ?? RULE_IMPORT_TICKET_TTL_MS;
@@ -351,6 +390,10 @@ export function createRuleConsentLane(stores, opts) {
351
390
  if (prepared === undefined) {
352
391
  return { ok: false, reason: "no-candidates", detail: "the rule lane cannot speak for this command (compound / redirection / unsupported tool)" };
353
392
  }
393
+ if ("status" in prepared) {
394
+ throwIfRetriable(prepared);
395
+ return { ok: false, reason: "redeem-refused", detail: prepared.reason };
396
+ }
354
397
  const redemption = input.redemption;
355
398
  if (redemption.kind === "batch") {
356
399
  const wanted = new Set(redemption.offer.rules.map((r) => r.rule));
@@ -360,17 +403,17 @@ export function createRuleConsentLane(stores, opts) {
360
403
  }
361
404
  const confirmed = await confirmRuleApproval({ approvalId: prepared.approvalId, principal: input.principal, selectedOffer: offerIndex, deps });
362
405
  if (!confirmed.ok)
363
- return { ok: false, reason: "confirm-refused", detail: confirmed.reason };
406
+ return { ok: false, reason: confirmRefusalWord(confirmed), detail: confirmed.detail?.message ?? confirmed.reason };
364
407
  const result = await redeemRuleBatch({ approvalId: prepared.approvalId, principal: input.principal, deps });
365
408
  if ("status" in result) {
366
- throwIfRuleStoreFault(result);
409
+ throwIfRetriable(result);
367
410
  return { ok: false, reason: "redeem-refused", detail: result.reason };
368
411
  }
369
412
  const refused = refusedMembersOf(result.members);
370
413
  if (refused.length > 0) {
371
- if (refused.length === result.members.length && refused.every((m) => m.committed === "no"))
372
- for (const m of refused)
373
- throwIfRuleStoreFault(m);
414
+ const first = refused[0];
415
+ if (first !== undefined && refused.length === result.members.length && refused.every((m) => m.retriable))
416
+ throwIfRetriable(first);
374
417
  return { ok: false, reason: "redeem-refused", detail: `partial batch: ${refused.length} member(s) refused (${refused.map((x) => x.reason).join("; ")})` };
375
418
  }
376
419
  return { ok: true, ...anchorBatchMembers(result.members, redemption.offer), rev: result.rev };
@@ -385,7 +428,7 @@ export function createRuleConsentLane(stores, opts) {
385
428
  }
386
429
  const confirmed = await confirmRuleApproval({ approvalId: prepared.approvalId, principal: input.principal, selectedOffer: offerIndex, deps });
387
430
  if (!confirmed.ok)
388
- return { ok: false, reason: "confirm-refused", detail: confirmed.reason };
431
+ return { ok: false, reason: confirmRefusalWord(confirmed), detail: confirmed.detail?.message ?? confirmed.reason };
389
432
  ticket = offered;
390
433
  }
391
434
  else {
@@ -403,7 +446,7 @@ export function createRuleConsentLane(stores, opts) {
403
446
  deps,
404
447
  });
405
448
  if (!confirmed.ok)
406
- return { ok: false, reason: confirmRefusalWord(confirmed.reason), detail: confirmed.detail?.message ?? confirmed.reason };
449
+ return { ok: false, reason: confirmRefusalWord(confirmed), detail: confirmed.detail?.message ?? confirmed.reason };
407
450
  const minted = confirmed.mintedCandidate;
408
451
  if (minted === undefined) {
409
452
  return { ok: false, reason: "confirm-refused", detail: "the edited confirmation landed without a minted candidate — nothing to redeem" };
@@ -419,7 +462,7 @@ export function createRuleConsentLane(stores, opts) {
419
462
  }
420
463
  const redeemed = await redeemRuleTicket({ ticket, principal: input.principal, deps });
421
464
  if (redeemed.status !== "redeemed") {
422
- throwIfRuleStoreFault(redeemed);
465
+ throwIfRetriable(redeemed);
423
466
  return { ok: false, reason: "redeem-refused", detail: redeemed.reason };
424
467
  }
425
468
  return { ok: true, kind: "single", rule: redeemed.rule, rev: redeemed.rev, alreadyRedeemed: redeemed.alreadyRedeemed };
@@ -429,7 +472,10 @@ export function createRuleConsentLane(stores, opts) {
429
472
  const readFile = async () => l.content;
430
473
  return l.layer === "userSettings" ? { layer: l.layer, path: l.path, readFile } : { layer: l.layer, path: l.path, root: l.root, readFile };
431
474
  });
432
- const { preview, approvalId } = await prepareCcImport({ layers: ccLayers, principal, deps });
475
+ const prepared = await prepareCcImport({ layers: ccLayers, principal, deps });
476
+ if ("status" in prepared)
477
+ return importRecordRefusal(prepared);
478
+ const { preview, approvalId } = prepared;
433
479
  if (approvalId === undefined) {
434
480
  return { ok: true, preview };
435
481
  }
@@ -509,8 +555,8 @@ export function createRuleConsentLane(stores, opts) {
509
555
  if (record.state === "pending") {
510
556
  const confirmed = await confirmRuleApproval({ approvalId: consumed.approvalId, principal, deps });
511
557
  if (!confirmed.ok) {
512
- if (confirmed.reason === "conflict")
513
- return await indeterminate(confirmed.reason);
558
+ if (confirmRefusalRetries(confirmed.reason))
559
+ return await indeterminate(confirmed.detail?.message ?? confirmed.reason);
514
560
  return { ok: false, reason: "record-unusable", detail: confirmed.reason };
515
561
  }
516
562
  }
@@ -518,11 +564,10 @@ export function createRuleConsentLane(stores, opts) {
518
564
  if ("status" in result) {
519
565
  return await indeterminate(result.reason);
520
566
  }
521
- const members = buildImportOutcomeMembers(result.members);
522
- const open = unsettledDetailOf(members);
523
- if (open !== undefined)
524
- return await indeterminate(open);
525
- return { ok: true, outcome: { members, rev: result.rev } };
567
+ const walk = settleImportWalk(result.members);
568
+ if ("open" in walk)
569
+ return await indeterminate(walk.open);
570
+ return { ok: true, outcome: { members: walk.settled, rev: result.rev } };
526
571
  }
527
572
  catch (err) {
528
573
  return await indeterminate(err instanceof Error ? err.message : String(err));
@@ -580,7 +625,10 @@ export function createRuleConsentLane(stores, opts) {
580
625
  }
581
626
  if (allows.length === 0)
582
627
  return { ok: true, preview: { members } };
583
- const { preview, approvalId } = await prepareCcImport({ layers: buildLocalImportLayers(allows), principal, deps });
628
+ const prepared = await prepareCcImport({ layers: buildLocalImportLayers(allows), principal, deps });
629
+ if ("status" in prepared)
630
+ return importRecordRefusal(prepared);
631
+ const { preview, approvalId } = prepared;
584
632
  const engineKeys = new Set(preview.candidates.map((c) => `${c.behavior}${LOCAL_IMPORT_KEY_SEP}${serializeRuleScope(c.scope)}${LOCAL_IMPORT_KEY_SEP}${c.rule}`));
585
633
  for (let i = 0; i < members.length; i++) {
586
634
  const m = members[i];
@@ -669,8 +717,8 @@ export function createRuleConsentLane(stores, opts) {
669
717
  if (record.state === "pending") {
670
718
  const confirmed = await confirmRuleApproval({ approvalId, principal, deps });
671
719
  if (!confirmed.ok) {
672
- if (confirmed.reason === "conflict")
673
- return await transient(confirmed.reason);
720
+ if (confirmRefusalRetries(confirmed.reason))
721
+ return await transient(confirmed.detail?.message ?? confirmed.reason);
674
722
  return await verdict("record-unusable", confirmed.reason);
675
723
  }
676
724
  }
@@ -678,11 +726,11 @@ export function createRuleConsentLane(stores, opts) {
678
726
  if ("status" in result) {
679
727
  return await transient(result.reason);
680
728
  }
681
- members = buildImportOutcomeMembers(result.members);
729
+ const walk = settleImportWalk(result.members);
730
+ if ("open" in walk)
731
+ return await transient(walk.open);
732
+ members = walk.settled;
682
733
  rev = result.rev;
683
- const open = unsettledDetailOf(members);
684
- if (open !== undefined)
685
- return await transient(open);
686
734
  }
687
735
  catch (err) {
688
736
  return await transient(err instanceof Error ? err.message : String(err));
package/dist/run-local.js CHANGED
@@ -23,7 +23,7 @@ import { buildUnpricedCeilingNotice, isRosterGateArmed, loadConfig, logConfigDia
23
23
  import { buildStoreOpenRefusalTail } from "./plugins/store-open-refusal.js";
24
24
  import { acquireLocalBackendWithWait } from "./plugins/store-lock-wait.js";
25
25
  import { configLocalRoot, createConfigProvider } from "./config-provider.js";
26
- import { CONFIG_DOMAIN_INVALID_NOTE, buildCandidateRejectedFields, judgeConfigCandidate } from "./web-admin-client/candidate-gate.js";
26
+ import { CONFIG_DOMAIN_INVALID_NOTE, buildCandidateRejectedFields, buildCandidateRejectionNotes, judgeConfigCandidate } from "./web-admin-client/candidate-gate.js";
27
27
  import { buildUnreadConfigFileFields, buildUnreadConfigKeyFields } from "./web-admin-client/read-warnings.js";
28
28
  import { composeExecutionLane, settleHostLaneShell, warnReadDenyFloorUnkept } from "./boot/execution-lane.js";
29
29
  import { judgeConsolidationValve } from "./boot/memory-consolidation.js";
@@ -316,6 +316,7 @@ function buildUnfinishedStopFooter(stop, sessionId) {
316
316
  }
317
317
  }
318
318
  }
319
+ const RUN_LOCAL_LANE_ENTRY = { name: "run-local", runs: ["host", "none"], declares: "host" };
319
320
  export const RUN_LOCAL_CONFIG_SOURCE_REFUSAL = "CONFIG_PROVIDER=remote: run-local reads its configuration from the local config directory only — it does not pull a web-admin center " +
320
321
  "(center credential renewal, sealed model keys and the roster gate are assembled by the HTTP service). Unset CONFIG_PROVIDER or set " +
321
322
  "CONFIG_PROVIDER=local for this command, or run the HTTP service to use the center.";
@@ -345,30 +346,31 @@ export async function runLocal(argv, deps = {}) {
345
346
  if (args.root)
346
347
  process.env.CONFIG_LOCAL_DIR = args.root;
347
348
  declareServerWithheldEnv();
348
- const config = loadConfig();
349
- bindOwnCredentialsConfig(config);
350
- const root = configLocalRoot(config);
351
- const logger = deps.logger ?? createLogger(config.logLevel);
349
+ const loaded = loadConfig();
350
+ bindOwnCredentialsConfig(loaded);
351
+ const root = configLocalRoot(loaded);
352
+ const logger = deps.logger ?? createLogger(loaded.logLevel);
352
353
  const metrics = createMetrics();
353
354
  const memoryEngineIncident = createMemoryEngineIncidentSink({ logger, metrics });
354
355
  installSecretEnvScrubRecorder({ logger, metrics });
355
356
  installDefaultEngineNoticeSeat(logger, metrics);
356
357
  logConfigDiagnostics(logger);
357
- provisionSemaConfigDir(config, logger);
358
+ provisionSemaConfigDir(loaded, logger);
358
359
  installOutboundDispatcher(logger);
359
- const providerInput = { provider: "local", localDir: root, localOwnerUid: config.configLocalOwnerUid };
360
+ const providerInput = { provider: "local", localDir: root, localOwnerUid: loaded.configLocalOwnerUid };
360
361
  try {
361
- await assertLocalConfigDirTrusted({ root, declaredOwnerUid: config.configLocalOwnerUid });
362
+ await assertLocalConfigDirTrusted({ root, declaredOwnerUid: loaded.configLocalOwnerUid });
362
363
  }
363
364
  catch (err) {
364
365
  printErr(err instanceof Error ? err.message : String(err));
365
366
  return 2;
366
367
  }
367
- const envModelsMigration = { root, env: process.env, envTableIsPlaceholder: isRosterGateArmed(config.webAdmin) };
368
+ const envModelsMigration = { root, env: process.env, envTableIsPlaceholder: isRosterGateArmed(loaded.webAdmin) };
368
369
  logEnvModelsMigration(logger, envModelsMigration, await runEnvModelsMigration(envModelsMigration));
369
370
  logConfigDirMigration(logger, await migrateLocalConfigDirectory(root));
371
+ let config;
370
372
  try {
371
- await composeExecutionLane(config, { configSource: "local", localRoot: root, logger, drivesFromFile: ["host"] });
373
+ config = await composeExecutionLane(loaded, { configSource: "local", localRoot: root, logger, entry: RUN_LOCAL_LANE_ENTRY });
372
374
  }
373
375
  catch (err) {
374
376
  printErr(err instanceof Error ? err.message : String(err));
@@ -379,12 +381,14 @@ export async function runLocal(argv, deps = {}) {
379
381
  const rosterLease = peerDesk.lease("roster");
380
382
  let effective;
381
383
  let candidatePrompts;
384
+ let candidateRejectionNotes;
382
385
  let applying = false;
383
386
  try {
384
387
  const r = await configProvider.fetchEffective(undefined);
385
388
  if (r) {
386
389
  const verdict = judgeConfigCandidate(r);
387
390
  if (verdict.verdict === "rejected") {
391
+ candidateRejectionNotes = buildCandidateRejectionNotes({ errors: verdict.errors, ...(configProvider.kind === "local" ? { dir: root } : {}) });
388
392
  for (const de of r.domainErrors ?? [])
389
393
  logger.warn("config_domain_invalid", { domain: de.domain, error: de.error, note: CONFIG_DOMAIN_INVALID_NOTE });
390
394
  logger.warn("config_candidate_rejected", buildCandidateRejectedFields(r, verdict, "run-local", { lkgVersion: "(env)", ...(configProvider.kind === "local" ? { dir: root } : {}) }));
@@ -419,7 +423,7 @@ export async function runLocal(argv, deps = {}) {
419
423
  else
420
424
  logger.warn("config_source_unreachable_using_env", { source: configProvider.kind, err: String(err) });
421
425
  }
422
- const noDefaultModel = defaultModelRefusal(config, servedModelTableLeg(config));
426
+ const noDefaultModel = defaultModelRefusal({ models: config.models, modelRefusals: config.modelRefusals, candidateRejectionNotes }, servedModelTableLeg(config));
423
427
  if (noDefaultModel !== undefined)
424
428
  throw new Error(noDefaultModel);
425
429
  const routeVerdict = judgeServedModelRoute(config, { envTableIsPlaceholder: false });
@@ -474,7 +478,7 @@ export async function runLocal(argv, deps = {}) {
474
478
  }
475
479
  const sessionStore = fileBackend.sessionStore;
476
480
  const keyResolver = createKeyResolver(config.modelApiKeyEnv, process.env, config.modelApiKeys);
477
- const hostRx = config.remoteExec?.provider === "host" ? config.remoteExec : undefined;
481
+ const hostRx = config.remoteExec.provider === "host" ? config.remoteExec : undefined;
478
482
  const workspaceDir = args.workspace ?? hostRx?.workspaceBase ?? process.cwd();
479
483
  await settleHostLaneShell(config, logger);
480
484
  warnReadDenyFloorUnkept(config, logger);
@@ -720,7 +724,7 @@ export async function runLocal(argv, deps = {}) {
720
724
  ...(a2a ? { a2a } : {}),
721
725
  ...(Object.keys(limits).length > 0 ? { limits } : {}),
722
726
  }, config, workspaceDir), onAsk);
723
- logger.info("run_local_start", { scenario: scenarioName, model: spec.model, sessionId, exec: executionLaneOf(config.remoteExec?.provider) });
727
+ logger.info("run_local_start", { scenario: scenarioName, model: spec.model, sessionId, exec: config.remoteExec.provider });
724
728
  const settleSessionBackground = async () => {
725
729
  const reaped = defaultTaskRegistry.reapSessionBackground(sessionId, scope);
726
730
  if (reaped === 0)
package/dist/runs.d.ts CHANGED
@@ -151,33 +151,40 @@ export declare function releaseKeyIfZeroWorkRefusal(runStore: {
151
151
  * observable instead of a silent feature outage.
152
152
  */
153
153
  /**
154
- * 「这一次用户消息提交是不是一句**提问**」的唯一读法 —— 三处用户回退锚(后台腿与续跑腿的 {@link TurnAnchorCapture}、`/v1/tasks/stream`
155
- * 腿的 `userMsgEntryId`)同调这一只。
154
+ * 「这一次用户消息提交是不是这个 run 的**开场提示**」的唯一读法 —— 三处用户回退锚(后台腿与续跑腿的 {@link TurnAnchorCapture}、`/v1/tasks/stream`
155
+ * 腿的 `userMsgEntryId`)同调这一只;调用点零各自判、零按正文判,且都是「最后一次交出的赢」。
156
156
  *
157
- * 目标声明了附件时,引擎把每只附件铸成**一条自己的用户消息**,紧跟在目标后面提交(core `human_input.attachments` 顶注:
158
- * 「each attachment is delivered as its own message after the objective; its `message_committed` is the delivery」)。
159
- * 所以一次带 N 只附件的提交会出 1 + N 次 `message_committed{role:"user"}`,而「回到这条提问」的锚要的是**人的那条**
160
- * (core 的 `resumeAt` 认它:「a `resumeAt` that keeps the message keeps its group」;以附件帧作 `resumeAt` 引擎拒 `resume_at.not_a_message`),
161
- * 不是排在最后的附件帧。目标**之前**还可能有引擎排队的注入消息同批提交(亲读 core `engine/harness/agent-harness.js` 的 `takePrompts`:
162
- * 排队消息 ⇒ 目标 ⇒ 附件帧;真案 = 工作区是 git 仓且带图时,git 状态帧单独排在目标前面),所以「窗口里第一次用户提交」不是判据。
157
+ * **回退锚 = 该轮开场提示,一个 run 一个(开场窗 + 闩)**:run 一开始就开着一个**开场窗**,收集第一次模型输出之前的 user 提交;窗关上之后(闩上),同 run 的 user-role 提交 ——
158
+ * 用户打断时引擎收尾追加的「[Request interrupted by user]」、第一次模型调用前后排进来的 steer 正文、答完之后再来的 steer —— 一律不交。这是 CC「rewind to the message that started this turn」的
159
+ * 同义,与 core `resumeAt` 的 `before` 语义(叶 = 目标的 parent)配对:锚在开场提示上,切到它的 parent = 这一轮整个撤回;锚若漂到打断标记行上,
160
+ * parent 就是被撤回的那句提示本身,模型仍见它。同根:core 的文件历史边界按「本 run 第一条 user 提交」的 entry 键入(`rewindFilesTo` / `POST /v1/sessions/:id/rewind-files`
161
+ * 凭锚找边界),锚漂到没有自己边界的打断标记行上就解不到。打断标记行永远不是锚。
162
+ * 「一个 run」= 锚的键(`taskId`)的边界:读法实例每个 run 新建一只;续既有 run 的续跑腿不写用户锚(见 `resume-legs.ts`)。
163
163
  *
164
- * **为什么是「窗口 + 严格吻合」而不是读标记**:`message_committed` 上只有 `entryId / role / toolCallId?`,附件帧与用户真提交在事件上**不可辨认**;
165
- * 落盘的行上有标记(`attachment` 键;引擎收尾的中断标记带 `provenance: "engine-note"`),但事件到手的那一刻本仓读不到那一行
166
- * (会话店面没有按条目读的口,只有整日志导出),所以只能数。数的前提是「目标之后紧接恰好 N 只帧、其后才是别的」—— 前提成立才落锚,
167
- * **不成立就不猜**:猜错的锚会落在附件帧上(引擎拒)或引擎的中断标记上(回到的不是用户那句)。
164
+ * **窗里怎么认**。`message_committed` 上只有 `entryId / role / toolCallId?`:引擎排队在目标之前同批提交的消息(带图且工作区是 git 仓时单独排的 git 状态帧;会话空闲期间到的后台任务通知)、
165
+ * 目标、目标声明的附件帧、引擎收尾的中断标记,在事件上**不可辨认**(落盘的行上有标记 —— `attachment` 键、`provenance: "engine-note"` —— 但事件到手那一刻本仓读不到那一行:
166
+ * 会话店面没有按条目读的口,只有整日志导出),所以只能数。引擎的提交序(亲读 core `engine/harness/agent-harness.js` 的 `takePrompts`):排队消息 ⇒ 目标 ⇒ 附件帧;
167
+ * 中断标记只在打断收尾时追加(此时第一次模型输出没有出来,窗是被 `turn_end` 切断,不是被输出关上)。
168
+ * · **临时锚**:不带附件的提交,窗里**第一条** user 提交到手那一刻就交出 —— 打断 / 取消 / 断连常发生在第一次模型输出之前,那时窗还没关,锚必须已经在;
169
+ * 它也是 core 文件历史边界的键(本 run 第一条 user 提交)。
170
+ * · **校正**:窗被**非用户提交**(第一次助手消息 / 工具结果)关上 ⇒ 窗内共 k 条 user 提交、声明了 N 只附件帧:k ≥ N+1 时开场提示 = 倒数第 N+1 条(严格吻合)。
171
+ * 不带附件而 k > 1(目标之前有引擎排队的消息)⇒ 交出这一条,**盖过**临时锚(调用方「最后一次赢」,与修前同读:修前的读法就是『开场批里最后一条 user 提交』);k = 1 ⇒ 临时锚已是它,不再交。
172
+ * 带附件的提交没有临时锚(此刻还不知道哪几条是帧),只在关窗这一刻交一次;k < N+1(帧数不符)⇒ 不猜。
173
+ * · 窗被 `turn_end` 先切断 ⇒ 第一次模型调用没出任何输出就收了(halt / interrupt / cancel / 空失败):窗里可能夹着引擎收尾的中断标记,数 N 会落在帧或标记上 ⇒ **不校正**,
174
+ * 临时锚(不带附件)原样留着,带附件的提交不猜、不落锚。切断即闩上。
175
+ * · 带附件的提交,窗内又应用了一条别的输入(`human_input{applied}`,如第一次模型调用前排进来的 steer;事件先于它的正文提交到手)⇒ 窗里多了一条别人的消息,数 N 会落在帧后面的 steer 上 ⇒ 不猜。
176
+ * 不带附件的提交不看输入条数:多条 applied 输入可以合成一条提交(续跑把停驻的 steer 与 wake 文本并成一条续跑消息),按修前同读校正到窗内最后一条。排队未应用(`delivery: "queued"`)的输入不动窗。窗还开着时继续攒,直到被关上。
177
+ * · 「不猜」= 这个 run 不落(带附件)或不校正(不带附件),且窗关上之后闩上 —— 其后的 user 提交(steer 正文、打断标记)不是开场提示,不顶上来;拿这次 run 的 taskId 去 `resumeAt`
178
+ * 得 404 `resume_at.unknown_event`(文案点名带附件这一类成因)。
179
+ * 窗关上之前一个 user 提交都没有就关了(续跑腿里先到的是工具结果 / 助手消息)⇒ 窗照开着,不闩:那一条之后第一条 user 提交才是这个 run 里的第一条。
168
180
  *
169
- * 读法:
170
- * · `human_input{delivery:"applied"}` 带 N 只附件 ⇒ 开窗;窗内的用户提交只攒、不落锚(此刻还不知道它们是不是『目标 + N 只帧』)。
171
- * · 窗被**非用户提交**(第一次助手消息 / 工具结果)关上 ⇒ 窗内共 k 次用户提交,k ≥ N+1 时提问 = 倒数第 N+1 次(严格吻合);k < N+1(帧数不符)⇒ 不猜。
172
- * · 窗被 `turn_end` 先切断 ⇒ 第一次模型调用没出任何提交就收了(halt / interrupt / 空失败):窗里可能夹着引擎收尾的中断标记,数 N 会落在帧或标记上 ⇒ 不猜。
173
- * · 窗内又应用了一条别的输入(`human_input{applied}`,如第一次模型调用前排进来的 steer;事件先于它的正文提交到手)⇒ 窗里多了一条别人的消息,数 N 会落在帧上 ⇒ 窗作废、不猜,
174
- * 之后的用户提交(含那条 steer 正文)是窗口之外的提交,最后一次赢。排队未应用(`delivery: "queued"`)的输入不动窗。
175
- * · 「不猜」= 返回 `undefined`、这次提交不落锚;拿这次 run 的 taskId 去 `resumeAt` 得 404 `resume_at.unknown_event`(文案点名这一类成因)。
176
- * 窗口之外的用户提交(如 interrupt 带话的 steer 正文,在 `turn_end` 之后提交)照修前读法(是提问,最后一次赢)。
177
- * 返回这次提交之后的提问 `entryId`(调用方照旧「最后一次赢」地落锚),不是提问相关的提交返回 `undefined`。
181
+ * 已知边界(引擎在 `message_committed` 上带来源标 / 输入标之日见下):
182
+ * · 被 `turn_end` 切断(第一次模型输出之前打断 / 取消)、不带附件、且由引擎排队的消息领头的 run —— 窗来不及校正,锚落在领头的那一条上(修前:取消 = 目标,halt / interrupt = 打断标记)。
183
+ * 它与 core 文件历史边界的键是同一条消息,`resumeAtMode:"before"` 的叶仍是整轮之前;含目标的 `resumeAt` 只留下领头那条。
184
+ * · 不带附件、第一次模型输出之前就应用了一条 steer:校正到窗内最后一条 = steer 正文(与修前同读)。
178
185
  *
179
- * 退役条件:引擎在落盘的帧上(`message_committed`)带上附件标记之日,本读法整体换成「按标记判一次」(零计数、无窗口、无拒臂),
180
- * 窗口 / 严格吻合 / 不猜三臂与 `resume_at.unknown_event` 文案里对应的那一句一并删除。
186
+ * 退役条件:引擎在落盘的帧上(`message_committed`)带上来源标(附件标记 / 引擎消息标)之日,本读法整体换成「第一条非引擎消息」(零计数、无窗口、无校正、无拒臂),
187
+ * 窗口 / 严格吻合 / 不猜三臂与 `resume_at.unknown_event` 文案里对应的那一句一并删除,领头排队消息的边界随之消失。
181
188
  */
182
189
  export declare function createPromptCommitReader(): (ev: {
183
190
  readonly type: string;
@@ -206,12 +213,17 @@ export declare class TurnAnchorCapture {
206
213
  * assistant). This is the CC rewind target ("rewind to the prompt" = the code-restore parity path — a code
207
214
  * change happens in a tool turn WITHIN a prompt's run, so rewinding to the prompt + rewindFiles undoes it).
208
215
  * Keyed by the run's taskId (the handle the shell already holds from the POST response — no eventId→entryId
209
- * side map / no leaf-read inference needed). The assistant-turn capture above stays as an additive bonus. */
216
+ * side map / no leaf-read inference needed). The assistant-turn capture above stays as an additive bonus.
217
+ * The anchor is the run's OPENING prompt (the reader's opening window: provisional on the first user commit, corrected
218
+ * when the first model output closes the window, latched after); a later
219
+ * user-role commit in the same run — the interruption marker, a steer — never moves it. The capture instance is per
220
+ * run: a leg that CONTINUES an existing run (same taskId) wires no `captureUser` (its opening prompt was anchored
221
+ * by the first leg). */
210
222
  private readonly captureUser?;
211
223
  /** The turn's FIRST text_delta eventId = the message's stable resume handle (also stamped on the durable text event). */
212
224
  firstTextEventId: string | undefined;
213
225
  private turnHadTool;
214
- /** 用户提交是不是提问的唯一读法({@link createPromptCommitReader};附件帧不是提问)。 */
226
+ /** 用户提交是不是开场提示的唯一读法({@link createPromptCommitReader};开场窗 + 闩 —— 开场提示之后打断标记 / steer 不改锚;附件帧不是提问)。 */
215
227
  private readonly promptCommit;
216
228
  constructor(capture: ((eventId: string) => Promise<void>) | undefined,
217
229
  /** 这只捕获器在哪条腿上(写失败的 fail-open 探针行带它)。 */
@@ -222,16 +234,22 @@ export declare class TurnAnchorCapture {
222
234
  * assistant). This is the CC rewind target ("rewind to the prompt" = the code-restore parity path — a code
223
235
  * change happens in a tool turn WITHIN a prompt's run, so rewinding to the prompt + rewindFiles undoes it).
224
236
  * Keyed by the run's taskId (the handle the shell already holds from the POST response — no eventId→entryId
225
- * side map / no leaf-read inference needed). The assistant-turn capture above stays as an additive bonus. */
237
+ * side map / no leaf-read inference needed). The assistant-turn capture above stays as an additive bonus.
238
+ * The anchor is the run's OPENING prompt (the reader's opening window: provisional on the first user commit, corrected
239
+ * when the first model output closes the window, latched after); a later
240
+ * user-role commit in the same run — the interruption marker, a steer — never moves it. The capture instance is per
241
+ * run: a leg that CONTINUES an existing run (same taskId) wires no `captureUser` (its opening prompt was anchored
242
+ * by the first leg). */
226
243
  captureUser?: ((entryId: string) => Promise<void>) | undefined);
227
- /** A `human_input` arrived — the objective's declared attachments open the frame window of {@link createPromptCommitReader}. */
244
+ /** A `human_input` arrived — the objective's declared attachments open the frame window of {@link createPromptCommitReader} (another applied input inside the window voids it). */
228
245
  onHumanInput(ev: {
229
246
  readonly type: string;
230
247
  }): void;
231
248
  /** A `message_committed` arrived — capture a USER-message rewind anchor (CC parity). Best-effort (a failure only
232
- * makes that one prompt non-rewindable). Only a user commit that is a PROMPT (not an attachment frame trailing the
233
- * objective — {@link createPromptCommitReader}; an attachment window is decided when a non-user commit closes it, so
234
- * the anchor of an attachment-carrying prompt lands on THAT call); assistant/toolResult committed entries are handled by
249
+ * makes that one prompt non-rewindable). Only the run's OPENING prompt anchors (the opening window's user commit — not an
250
+ * attachment frame trailing the objective, not the interruption marker / a steer that follows it —
251
+ * {@link createPromptCommitReader}; an attachment window is decided when a non-user commit closes it, so the anchor of an
252
+ * attachment-carrying prompt lands on THAT call); assistant/toolResult committed entries are handled by
235
253
  * the turn-text path (assistant) or deliberately not anchored (toolResult — `resumeAt` rejects them). */
236
254
  onMessageCommitted(role: string | undefined, entryId: string | undefined): Promise<void>;
237
255
  /** A text_delta arrived — latch the first DEFINED eventId as the message handle (eventId is optional on the stream). */
package/dist/runs.js CHANGED
@@ -11,7 +11,7 @@ import { withPrincipal } from "./observability/principal-context.js";
11
11
  import { withModelReachScope } from "./model-reach-scope.js";
12
12
  import { createInstructionSelectionLeg } from "./instruction-selection.js";
13
13
  import { redactSecrets } from "./trace/redact.js";
14
- import { taskNotificationEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "./trace/project.js";
14
+ import { taskNotificationEventData, appendModelUsageDelta, attachModelUsage, createPromptManifestSeat } from "./trace/project.js";
15
15
  import { createLedgerSink } from "./trace/ledger-sink.js";
16
16
  import { registerEngineNoticeLeg } from "./trace/engine-notice-wire.js";
17
17
  import { recordTurnActivity } from "./turn-activity.js";
@@ -78,6 +78,8 @@ const PREPARE_REFUSAL_HTTP_STATUS = {
78
78
  "rewind.child_scope_unsupported": 422,
79
79
  "rewind.capture_disabled": 422,
80
80
  "rewind.store_unconfigured": 409,
81
+ "rewind.session_busy": 409,
82
+ "rewind.files_env_unsupported": 409,
81
83
  "memory.capture_optout_unpersisted": 503,
82
84
  "config.memory_capture_spelling": 400,
83
85
  "config.invalid_checkpoint_store": 400,
@@ -174,17 +176,25 @@ export async function releaseKeyIfZeroWorkRefusal(runStore, taskId, result) {
174
176
  await runStore.releaseIdemKey(taskId);
175
177
  }
176
178
  export function createPromptCommitReader() {
177
- let attachmentWindow;
179
+ const commits = [];
180
+ let frames = 0;
181
+ let appliedInputs = 0;
182
+ let settled = false;
178
183
  return (ev) => {
184
+ if (settled)
185
+ return undefined;
179
186
  if (ev.type === "human_input") {
180
187
  const h = ev;
181
188
  if (h.delivery !== "applied")
182
189
  return undefined;
183
- attachmentWindow = Array.isArray(h.attachments) && h.attachments.length > 0 ? { frames: h.attachments.length, commits: [] } : undefined;
190
+ appliedInputs += 1;
191
+ if (appliedInputs === 1)
192
+ frames = Array.isArray(h.attachments) ? h.attachments.length : 0;
184
193
  return undefined;
185
194
  }
186
195
  if (ev.type === "turn_end") {
187
- attachmentWindow = undefined;
196
+ if (commits.length > 0)
197
+ settled = true;
188
198
  return undefined;
189
199
  }
190
200
  if (ev.type !== "message_committed")
@@ -192,17 +202,17 @@ export function createPromptCommitReader() {
192
202
  const c = ev;
193
203
  const entryId = typeof c.entryId === "string" && c.entryId.length > 0 ? c.entryId : undefined;
194
204
  if (c.role === "user") {
195
- if (attachmentWindow !== undefined) {
196
- attachmentWindow.commits.push(entryId);
197
- return undefined;
198
- }
199
- return entryId;
205
+ commits.push(entryId);
206
+ return frames === 0 && commits.length === 1 ? entryId : undefined;
200
207
  }
201
- const closed = attachmentWindow;
202
- attachmentWindow = undefined;
203
- if (closed === undefined || closed.commits.length < closed.frames + 1)
208
+ if (commits.length === 0)
209
+ return undefined;
210
+ settled = true;
211
+ if (frames === 0)
212
+ return commits.length > 1 ? commits[commits.length - 1] : undefined;
213
+ if (appliedInputs > 1 || commits.length < frames + 1)
204
214
  return undefined;
205
- return closed.commits[closed.commits.length - 1 - closed.frames];
215
+ return commits[commits.length - 1 - frames];
206
216
  };
207
217
  }
208
218
  export async function settleResumeAnchor(write, where) {
@@ -385,8 +395,8 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
385
395
  const flushModelUsage = () => appendModelUsageDelta(append, modelUsage, taskId);
386
396
  const withModelUsage = (result) => attachModelUsage(result, { append, getEvents: (id, after) => runStore.getEvents(id, after), modelUsage, taskId });
387
397
  modelUsage?.register(taskId);
388
- const manifestLease = promptManifests?.register(taskId) ?? 0;
389
- const flushPromptManifest = () => appendPromptManifest(append, promptManifests, taskId);
398
+ const manifestSeat = createPromptManifestSeat(promptManifests, taskId);
399
+ const flushPromptManifest = () => manifestSeat.drain(append);
390
400
  const elicitEmit = (frame) => {
391
401
  const { type, ...rest } = frame;
392
402
  return append(type, rest);
@@ -652,7 +662,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
652
662
  for (const evict of subagentHandleEvictions)
653
663
  evict();
654
664
  modelUsage?.clear(taskId);
655
- promptManifests?.clear(taskId, manifestLease);
665
+ manifestSeat.release();
656
666
  clearInterval(heartbeat);
657
667
  }
658
668
  }