@sema-agent/server 7.141.0 → 7.143.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 (341) hide show
  1. package/MIGRATION.md +657 -0
  2. package/USAGE.md +102 -30
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +61 -43
  5. package/dist/approval-ask-audit-store.js +69 -44
  6. package/dist/approval-ask-machine.d.ts +15 -7
  7. package/dist/approval-ask-machine.js +10 -4
  8. package/dist/approval-card.d.ts +126 -27
  9. package/dist/approval-card.js +103 -23
  10. package/dist/approval-crash-convergence.d.ts +17 -7
  11. package/dist/approval-crash-convergence.js +94 -22
  12. package/dist/approval-deny-reasons.d.ts +34 -30
  13. package/dist/approval-deny-reasons.js +21 -6
  14. package/dist/approval-policy-settlement.d.ts +1 -1
  15. package/dist/approval-queue-kind.d.ts +27 -0
  16. package/dist/approval-queue-kind.js +6 -0
  17. package/dist/approval-reconciler.d.ts +41 -9
  18. package/dist/approval-reconciler.js +45 -42
  19. package/dist/audit.js +4 -2
  20. package/dist/auth-bridge.d.ts +9 -6
  21. package/dist/auth-bridge.js +9 -3
  22. package/dist/boot/adoption.js +2 -1
  23. package/dist/boot/budget-tracing.d.ts +17 -1
  24. package/dist/boot/budget-tracing.js +10 -6
  25. package/dist/boot/device-lane.d.ts +1 -1
  26. package/dist/boot/execution-env.d.ts +24 -4
  27. package/dist/boot/execution-env.js +26 -23
  28. package/dist/boot/execution-lane.js +2 -1
  29. package/dist/boot/exit-boundary.js +5 -4
  30. package/dist/boot/governance-seams.d.ts +26 -41
  31. package/dist/boot/governance-seams.js +61 -28
  32. package/dist/boot/late-binds.d.ts +7 -4
  33. package/dist/boot/late-binds.js +3 -1
  34. package/dist/boot/leader.js +2 -4
  35. package/dist/boot/memory-consolidation.d.ts +0 -8
  36. package/dist/boot/memory-consolidation.js +5 -4
  37. package/dist/boot/parked-revive-gate.js +2 -1
  38. package/dist/boot/permission-rules-audit.d.ts +0 -28
  39. package/dist/boot/permission-rules-audit.js +2 -1
  40. package/dist/boot/read-deny-anchor-audit.js +2 -1
  41. package/dist/boot/reapers.js +9 -7
  42. package/dist/boot/resolve-spec.d.ts +1 -1
  43. package/dist/boot/resolve-spec.js +19 -10
  44. package/dist/boot/retention-lane.js +5 -3
  45. package/dist/boot/runner-deps.d.ts +10 -7
  46. package/dist/boot/runner-deps.js +20 -29
  47. package/dist/boot/runtime-caps.js +3 -2
  48. package/dist/boot/session-faces.js +4 -3
  49. package/dist/boot/shutdown.d.ts +9 -0
  50. package/dist/boot/shutdown.js +19 -4
  51. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  52. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  53. package/dist/boot/stage-03-store-backend.js +1 -2
  54. package/dist/boot/stage-04-stores.d.ts +5 -2
  55. package/dist/boot/stage-04-stores.js +6 -7
  56. package/dist/boot/stage-05-execution-env.d.ts +6 -3
  57. package/dist/boot/stage-05-execution-env.js +8 -6
  58. package/dist/boot/stage-06-runners.d.ts +6 -3
  59. package/dist/boot/stage-06-runners.js +3 -4
  60. package/dist/boot/stage-07-capability-layer.d.ts +6 -3
  61. package/dist/boot/stage-07-capability-layer.js +7 -2
  62. package/dist/boot/stage-08-reapers.d.ts +6 -3
  63. package/dist/boot/stage-08-reapers.js +3 -2
  64. package/dist/boot/stage-09-leader.d.ts +6 -3
  65. package/dist/boot/stage-10-http-server.d.ts +6 -3
  66. package/dist/boot/stage-10-http-server.js +14 -5
  67. package/dist/boot/stores.d.ts +5 -2
  68. package/dist/boot/stores.js +10 -9
  69. package/dist/boot/web-admin.d.ts +5 -1
  70. package/dist/boot/web-admin.js +48 -36
  71. package/dist/boot/webfetch-summarize-lane.js +2 -1
  72. package/dist/boot/workflow-orchestration.js +3 -2
  73. package/dist/capabilities/builtin-tools.d.ts +2 -1
  74. package/dist/capabilities/builtin-tools.js +2 -4
  75. package/dist/capabilities/composite-members.d.ts +2 -1
  76. package/dist/capabilities/composite-members.js +2 -1
  77. package/dist/capabilities/hands-lane.d.ts +9 -39
  78. package/dist/capabilities/hands-lane.js +8 -13
  79. package/dist/capabilities/mcp-probe.d.ts +3 -2
  80. package/dist/capabilities/scenarios.d.ts +11 -1
  81. package/dist/capabilities/scenarios.js +1 -0
  82. package/dist/capabilities/skills.d.ts +1 -17
  83. package/dist/capabilities/skills.js +0 -8
  84. package/dist/capability-facts.d.ts +31 -7
  85. package/dist/capability-facts.js +27 -4
  86. package/dist/card-void.d.ts +6 -9
  87. package/dist/config-catalog.js +2 -1
  88. package/dist/config-dir-trust.js +58 -29
  89. package/dist/config-invariants.d.ts +7 -1
  90. package/dist/config-invariants.js +7 -0
  91. package/dist/config-provider.d.ts +10 -0
  92. package/dist/config-provider.js +15 -4
  93. package/dist/config-root-migration.d.ts +13 -0
  94. package/dist/config-root-migration.js +99 -0
  95. package/dist/config-types.d.ts +19 -8
  96. package/dist/config.d.ts +10 -3
  97. package/dist/config.js +18 -4
  98. package/dist/delegated-session-owner.d.ts +5 -3
  99. package/dist/delegated-session-owner.js +1 -1
  100. package/dist/device-ws-protocol.d.ts +1 -0
  101. package/dist/device-ws-protocol.js +2 -1
  102. package/dist/env-model-table-gate.d.ts +53 -0
  103. package/dist/env-model-table-gate.js +53 -0
  104. package/dist/execution-lane-caps.d.ts +2 -1
  105. package/dist/fleet/fleet-bus.d.ts +34 -55
  106. package/dist/fleet/fleet-bus.js +35 -100
  107. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  108. package/dist/fleet/fleet-reconciler.js +1 -1
  109. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  110. package/dist/fleet/subagent-tail-bus.js +15 -28
  111. package/dist/hooks/hook-runner.d.ts +6 -0
  112. package/dist/hooks/hook-runner.js +58 -8
  113. package/dist/host-decision.d.ts +54 -20
  114. package/dist/host-decision.js +42 -14
  115. package/dist/http/admission.d.ts +1 -1
  116. package/dist/http/admission.js +7 -3
  117. package/dist/http/approval-sweeps.js +11 -8
  118. package/dist/http/caller-trust.d.ts +1 -1
  119. package/dist/http/dispatch.js +4 -2
  120. package/dist/http/durable-run-leg.js +2 -2
  121. package/dist/http/engine-refusal.d.ts +16 -0
  122. package/dist/http/engine-refusal.js +17 -0
  123. package/dist/http/execution-context.d.ts +2 -2
  124. package/dist/http/idempotency.d.ts +1 -1
  125. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  126. package/dist/http/memory-compliance-failure-reply.js +4 -6
  127. package/dist/http/owner-access.d.ts +11 -0
  128. package/dist/http/owner-access.js +13 -0
  129. package/dist/http/principal-gate.d.ts +3 -1
  130. package/dist/http/principal-gate.js +17 -8
  131. package/dist/http/resume-legs.d.ts +21 -7
  132. package/dist/http/resume-legs.js +76 -58
  133. package/dist/http/resume-restatement.d.ts +39 -0
  134. package/dist/http/resume-restatement.js +25 -0
  135. package/dist/http/route-ctx.d.ts +35 -10
  136. package/dist/http/route-ctx.js +1 -1
  137. package/dist/http/route-table.js +2 -0
  138. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  139. package/dist/http/routes/approvals-assistant.js +142 -31
  140. package/dist/http/routes/attachments.js +18 -0
  141. package/dist/http/routes/capabilities.js +16 -4
  142. package/dist/http/routes/memory-policy.d.ts +2 -2
  143. package/dist/http/routes/memory-policy.js +27 -7
  144. package/dist/http/routes/notify-wake.js +23 -25
  145. package/dist/http/routes/rules.js +48 -13
  146. package/dist/http/routes/runs.js +12 -11
  147. package/dist/http/routes/session-memory-sync.d.ts +91 -0
  148. package/dist/http/routes/session-memory-sync.js +174 -0
  149. package/dist/http/routes/session-sync.js +13 -20
  150. package/dist/http/routes/sessions-list.d.ts +2 -1
  151. package/dist/http/routes/sessions.d.ts +2 -2
  152. package/dist/http/routes/sessions.js +22 -23
  153. package/dist/http/routes/tasks.js +34 -54
  154. package/dist/http/run-read-face.d.ts +7 -0
  155. package/dist/http/run-read-face.js +9 -3
  156. package/dist/http/send.d.ts +5 -0
  157. package/dist/http/send.js +9 -2
  158. package/dist/http/server.d.ts +27 -15
  159. package/dist/http/server.js +4 -6
  160. package/dist/http/stored-body-replay.js +15 -4
  161. package/dist/http/submit-replay.d.ts +4 -3
  162. package/dist/http/submit-replay.js +2 -2
  163. package/dist/http/sync-submit-body.d.ts +21 -4
  164. package/dist/http/sync-submit-body.js +13 -0
  165. package/dist/http/wire-types.d.ts +17 -7
  166. package/dist/identity-source.d.ts +21 -2
  167. package/dist/identity-source.js +6 -0
  168. package/dist/leader/leader.js +5 -2
  169. package/dist/leader/wire.d.ts +7 -1
  170. package/dist/leader/wire.js +6 -5
  171. package/dist/leg-facts.d.ts +37 -0
  172. package/dist/leg-facts.js +15 -0
  173. package/dist/memory-bundle-engine.d.ts +1 -4
  174. package/dist/memory-bundle-engine.js +2 -2
  175. package/dist/memory-incident-sink.d.ts +19 -6
  176. package/dist/memory-incident-sink.js +8 -4
  177. package/dist/memory-operator-faces.d.ts +30 -66
  178. package/dist/memory-operator-faces.js +17 -88
  179. package/dist/memory-scope-stores.d.ts +38 -40
  180. package/dist/memory-scope-stores.js +51 -36
  181. package/dist/memory-scope.d.ts +0 -9
  182. package/dist/memory-scope.js +0 -9
  183. package/dist/memory-sync-client.d.ts +21 -21
  184. package/dist/memory-sync-client.js +62 -43
  185. package/dist/memory-sync-identity.d.ts +24 -0
  186. package/dist/memory-sync-identity.js +57 -0
  187. package/dist/memory-sync.d.ts +27 -5
  188. package/dist/memory-sync.js +29 -7
  189. package/dist/model-plane-face.d.ts +13 -7
  190. package/dist/model-plane-face.js +2 -1
  191. package/dist/observability/fail-open.d.ts +47 -14
  192. package/dist/observability/fail-open.js +37 -11
  193. package/dist/observability/run-terminal.d.ts +92 -34
  194. package/dist/observability/run-terminal.js +171 -162
  195. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  196. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  197. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  198. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  199. package/dist/orchestration/workflow-park-decision.js +5 -3
  200. package/dist/org-delivery-gate.d.ts +11 -0
  201. package/dist/org-delivery-gate.js +19 -1
  202. package/dist/parked-decide.d.ts +13 -9
  203. package/dist/parked-decide.js +7 -7
  204. package/dist/parked-revive-surface.js +1 -1
  205. package/dist/peer-inbound-face.d.ts +127 -0
  206. package/dist/peer-inbound-face.js +158 -0
  207. package/dist/permission-rule-list.d.ts +13 -9
  208. package/dist/permission-rule-list.js +7 -3
  209. package/dist/plugins/approval-ask-store-file.d.ts +14 -4
  210. package/dist/plugins/approval-ask-store-file.js +64 -11
  211. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  212. package/dist/plugins/approval-ask-store-memory.js +17 -14
  213. package/dist/plugins/approval-ask-store-sql.d.ts +70 -23
  214. package/dist/plugins/approval-ask-store-sql.js +79 -30
  215. package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
  216. package/dist/plugins/checkpoint-store-sql.js +9 -7
  217. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  218. package/dist/plugins/file-history-store-sql.js +24 -19
  219. package/dist/plugins/file-run-store.d.ts +35 -1
  220. package/dist/plugins/file-run-store.js +108 -9
  221. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  222. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  223. package/dist/plugins/local-checkpoint-store.d.ts +1 -1
  224. package/dist/plugins/local-checkpoint-store.js +2 -2
  225. package/dist/plugins/local-session-store.d.ts +42 -9
  226. package/dist/plugins/local-session-store.js +83 -33
  227. package/dist/plugins/local-task-attachment-store.d.ts +12 -2
  228. package/dist/plugins/local-task-attachment-store.js +67 -43
  229. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  230. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  231. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  232. package/dist/plugins/mailbox-store-sql.js +76 -7
  233. package/dist/plugins/memory-key-guards.d.ts +3 -3
  234. package/dist/plugins/memory-run-store.d.ts +6 -1
  235. package/dist/plugins/memory-run-store.js +11 -1
  236. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  237. package/dist/plugins/memory-sync-store-pg.js +21 -0
  238. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  239. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  240. package/dist/plugins/one-time-migrations.d.ts +58 -2
  241. package/dist/plugins/one-time-migrations.js +161 -4
  242. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  243. package/dist/plugins/org-delivery-quota-store.js +2 -12
  244. package/dist/plugins/park-commit-watch.d.ts +1 -1
  245. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  246. package/dist/plugins/permission-rule-store-file.js +15 -2
  247. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  248. package/dist/plugins/permission-rule-store-sql.js +35 -2
  249. package/dist/plugins/remote-env-device.d.ts +8 -11
  250. package/dist/plugins/remote-env-device.js +6 -3
  251. package/dist/plugins/remote-env-e2b.d.ts +23 -4
  252. package/dist/plugins/remote-env-e2b.js +111 -28
  253. package/dist/plugins/remote-env-k8s.d.ts +61 -22
  254. package/dist/plugins/remote-env-k8s.js +133 -33
  255. package/dist/plugins/remote-env-local-docker.d.ts +15 -3
  256. package/dist/plugins/remote-env-local-docker.js +40 -12
  257. package/dist/plugins/retention-store-sql.d.ts +2 -2
  258. package/dist/plugins/run-store-sql.d.ts +9 -1
  259. package/dist/plugins/run-store-sql.js +9 -1
  260. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  261. package/dist/plugins/sandbox-read-floor.js +2 -7
  262. package/dist/plugins/sql-errors.d.ts +10 -1
  263. package/dist/plugins/sql-errors.js +13 -0
  264. package/dist/plugins/store-backend.d.ts +33 -35
  265. package/dist/plugins/store-backend.js +10 -1
  266. package/dist/plugins/store-contracts.d.ts +50 -1
  267. package/dist/plugins/store-contracts.js +6 -0
  268. package/dist/plugins/task-attachment-store.d.ts +112 -14
  269. package/dist/plugins/task-attachment-store.js +207 -29
  270. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  271. package/dist/plugins/tool-result-store-sql.js +23 -2
  272. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  273. package/dist/plugins/wiring-section-codec.js +55 -0
  274. package/dist/plugins/workspace-fill.d.ts +60 -0
  275. package/dist/plugins/workspace-fill.js +106 -0
  276. package/dist/project-bundle.d.ts +38 -0
  277. package/dist/project-bundle.js +609 -0
  278. package/dist/rule-entry-list.d.ts +3 -2
  279. package/dist/rule-entry-list.js +5 -1
  280. package/dist/rules-consent.d.ts +28 -5
  281. package/dist/rules-consent.js +40 -28
  282. package/dist/run-local.js +11 -13
  283. package/dist/runs.d.ts +12 -8
  284. package/dist/runs.js +6 -8
  285. package/dist/runtime-governance.d.ts +1 -1
  286. package/dist/sandbox-egress-policy.d.ts +4 -1
  287. package/dist/sandbox-egress-policy.js +3 -1
  288. package/dist/sandbox-git-plane.d.ts +31 -12
  289. package/dist/sandbox-git-plane.js +24 -4
  290. package/dist/security.d.ts +9 -0
  291. package/dist/security.js +8 -0
  292. package/dist/server-secret-env.d.ts +4 -0
  293. package/dist/session-error-wire.d.ts +36 -0
  294. package/dist/session-error-wire.js +13 -0
  295. package/dist/session-incarnation.d.ts +1 -1
  296. package/dist/session-notify-door.d.ts +106 -0
  297. package/dist/session-notify-door.js +93 -0
  298. package/dist/session-sync.d.ts +9 -14
  299. package/dist/session-sync.js +5 -5
  300. package/dist/session-workspace.d.ts +3 -13
  301. package/dist/session-workspace.js +0 -9
  302. package/dist/standing-answer-grant.d.ts +5 -0
  303. package/dist/standing-answer-grant.js +10 -0
  304. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  305. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  306. package/dist/task-mcp.d.ts +1 -1
  307. package/dist/task-settings.d.ts +21 -10
  308. package/dist/task-settings.js +46 -13
  309. package/dist/terminal.d.ts +39 -19
  310. package/dist/terminal.js +65 -22
  311. package/dist/tool-approval.d.ts +56 -37
  312. package/dist/tool-approval.js +78 -71
  313. package/dist/trace/core-keyset-guard.d.ts +134 -14
  314. package/dist/trace/engine-notice-wire.d.ts +9 -3
  315. package/dist/trace/engine-notice-wire.js +7 -3
  316. package/dist/trace/exit-seat.d.ts +9 -2
  317. package/dist/trace/exit-seat.js +1 -0
  318. package/dist/trace/ledger-sink.d.ts +10 -6
  319. package/dist/trace/ledger-sink.js +2 -2
  320. package/dist/trace/model-segment.d.ts +55 -25
  321. package/dist/trace/model-segment.js +101 -33
  322. package/dist/trace/project.d.ts +25 -5
  323. package/dist/trace/project.js +22 -0
  324. package/dist/trace/redact.d.ts +61 -9
  325. package/dist/trace/redact.js +1490 -468
  326. package/dist/trace/self-minted-wire.d.ts +745 -24
  327. package/dist/trace/self-minted-wire.js +239 -9
  328. package/dist/trace/wire-projection-faces.d.ts +2 -2
  329. package/dist/trace/wire-projection-faces.js +2 -2
  330. package/dist/verifier-pause-card.d.ts +33 -5
  331. package/dist/verifier-pause-card.js +15 -10
  332. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  333. package/dist/web-admin-client/apply-effective.js +109 -9
  334. package/dist/web-admin-client/effective-keys.js +2 -0
  335. package/dist/web-admin-client/types.d.ts +4 -0
  336. package/dist/workspace-space.d.ts +19 -3
  337. package/dist/workspace-space.js +8 -4
  338. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  339. package/package.json +3 -2
  340. package/wire-changes/server@7.142.0.json +639 -0
  341. package/wire-changes/server@7.143.0.json +1167 -0
@@ -1,18 +1,5 @@
1
- import type { TaskNotificationPayload, TerminalCause, WorkflowRun } from "@sema-agent/core";
1
+ import type { TerminalCause, WorkflowRun } from "@sema-agent/core";
2
2
  import type { RunRecord } from "../plugins/store-contracts.js";
3
- /** [ref] 幽灵行案的单源判别:一条 `task_notification` 只有在 **agent 族 × 终态** 时才允许打
4
- * `onChildTerminal`(fleet「subagent 树」只渲 agent 子代)。`background_bash`/`monitor`/`external`
5
- * 不属 agent fleet 树——它们此前每条都打,fleet-bus 的「无 tick 无 claim」臂给 b\* 与 m\* handle 合成
6
- * agent 形瞬态终帧,壳终态留存池把这帧渲 60s = footer 幽灵子行;monitor 的 `status:"event"` 还被
7
- * 终态映射折成 `failed`。
8
- *
9
- * 🔴 [ref]([ref]):判别**本体已换 core 的 {@link isDelegatedAgentTerminal}**。此前这里是一份手写语义
10
- * 孪生(自己枚举 `completed|failed|killed|cancelled`),头注自陈「与 core 语义同源——core 根导出后换装
11
- * import 删本镜像」。core 现已从包根导出(`index.d.ts`),且它的终态集与 pending 店的驱逐偏好共用
12
- * 同一份 `TERMINAL_STATUSES`(core 原话:「so "terminal" can never mean two things in this module」)——
13
- * 孪生留在这里等于让 fleet 面板对「终态」的理解可以和引擎分家。本函数保留为**具名的 fleet 语义位**
14
- * (调用点读的是「这条通知该不该打 fleet 的 onChildTerminal」,不是「core 怎么判终态」)。 */
15
- export declare function isFleetAgentTerminalNotification(n: Pick<TaskNotificationPayload, "task_type" | "status">): boolean;
16
3
  /** The fleet vocabulary the shell renders (MF-Fleet `FleetTask.status`). The service maps its run/workflow status
17
4
  * onto this neutral set; `awaiting approval` = a needs-review/plan-approval park, `waiting` = a durable suspend.
18
5
  *
@@ -144,8 +131,8 @@ export interface FleetTaskRow {
144
131
  * - 缺席 = BCE 车道(`fleetBackgroundChildPublisher`)的 a\* 与 wa\* 真行,或顶层 run 行 —— 单源,常态。
145
132
  * - `"run-leg"` = 由每腿的 `fleetRunPublisher` 从 `task_progress` tick 铸的**复合 id 行**
146
133
  * (`${runId} ${childTaskId}`)。此形只在**没有 BCE 真行**的前台 delegation 上保留(同步腿委派的
147
- * 子代不过 background-child registry ⇒ 不让位就没有行);同 (scope, progressTaskId) 一旦有 BCE 真行,
148
- * 本车道**让位不铸**(双生行退役)。
134
+ * 子代不过 background-child registry ⇒ 不让位就没有行);tick 点名的是 BCE 真行(后台子代的 tick 带它的行 id;workflow agent 的
135
+ * tick 带会话 id、经让位登记簿换成行 id),本车道**让位不铸**(双生行退役)。
149
136
  * 消费端读法:带 `sourceLane:"run-leg"` 的行是过渡形,与 a\* 行**不会**同时描述同一个 agent;不需要再
150
137
  * 自己发明「复合 id 首段==parentId 且撞 (parentId,name)」那类集合级判据(cli 侧的防御税)。
151
138
  * ADDITIVE / tolerate-absent。 */
@@ -247,15 +234,14 @@ export type FleetFrame = {
247
234
  * 车HW 逐条亲读本文件的七处 `removeTask` 铸点后改成真话,消费方面的成文版 =
248
235
  * `docs/ASSISTANT-WIRE-CONTRACT.md` 附录 H)。缺席形其实是**两族**:
249
236
  * (**按臂名找,不给行号** —— 本注与铸点同住一个文件,写死数字会被下一次改注自己顶歪。)
250
- * · **结算级** —— 这一行**自己的**终态 `task` 帧刚发过,remove 只是成对的后半。四处:
251
- * `fleetRunPublisher.onChildTerminal` 的「bash 无 tick 形」合成瞬态帧(publish → remove 同一个
252
- * `for` 体)、`fleetRunPublisher.onTerminal` 的顶层行(`publishTask(run.runId, fleetStatus)` →
237
+ * · **结算级** —— 这一行**自己的**终态 `task` 帧刚发过,remove 只是成对的后半。三处:
238
+ * `fleetRunPublisher.onTerminal` 的顶层行(`publishTask(run.runId, fleetStatus)` →
253
239
  * `if (terminal) removeTask(run.runId)`)、`fleetBackgroundChildPublisher` 的子代终局
254
240
  * (带残局键的行帧 → `removeTask(e.taskId)`)、以及对账腿 `fleet-reconciler.ts` 的 `retire` 与
255
241
  * 候补窗 `upgradeWatched`(两者都先帧后撤)。
256
- * · **投影级 —— 没有自己的终态帧,但也不是「这个任务结束了」**:① **双生让位 / 双生抑制**
257
- * (`yieldToBackgroundChildLane` 把 run-leg 行让给 BCE 权威行;tick 期与子代终局期两处按
258
- * ` ${uuid}` 后缀扫掉 run-leg 复合键双生)—— 同一个实体改由**另一行**渲染,终局会落在**那一行**上;
242
+ * · **投影级 —— 没有自己的终态帧,但也不是「这个任务结束了」**:① **双生让位**
243
+ * (`yieldToBackgroundChildLane` 把本车道先前铸的 run-leg 行让给 BCE 权威行,由 run-leg 车道自己收)
244
+ * —— 同一个实体改由**另一行**渲染,终局会落在**那一行**上;
259
245
  * ② **父 leg settle 时把子代行收走**(`onTerminal` 里的 `for (const cid of children) removeTask(cid)`),
260
246
  * **含父 parked 的形**(理由逐字在该处:子代在父 park 期间并不在跑,resume 后新的 `task_progress`
261
247
  * 会重新建行;而子代本来就从不发终态 tick)。
@@ -369,8 +355,10 @@ export interface HookNonBlockingFailure {
369
355
  * · `matcher_over_budget` —— 这条 hook 所在组的 `matcher`(或条目自己的 `if` 条件)在这次事件的这个名字上求值没在预算内结束(灾难回溯;[ref])。
370
356
  * **不是 hook 脚本坏了,是它的选中条件不可求值**:server 按「选中」处理(守卫不被跳过,条目照跑),此帧说的是「这只 matcher 在这个名字上跑不完」。
371
357
  * **一组一帧**(`if` 一条目一帧),`hookName` / `entryType` 指认组的第一个条目,`detail` 点名 matcher、名字、额度与组里的条目数;无 `exitCode` / `stderr`。
358
+ * · `url_not_allowed` —— http 条目被 http hook 名单拦下(`settings.allowedHttpHookUrls`,契约包判官答拦:没命中 / 空名单 / 名单坏形),**一个字节都没发**(7.142.0 起)。
359
+ * 不是端点坏了,是配置不许它出门;`detail` 点名 `settings.hooks.<event>`、名单键与规则词(`url` / `empty` / `malformed`)和出路;无 `exitCode` / `stderr`。
372
360
  */
373
- reason: "exit_nonzero" | "timeout" | "spawn_failed" | "bad_json" | "matcher_over_budget";
361
+ reason: "exit_nonzero" | "timeout" | "spawn_failed" | "bad_json" | "matcher_over_budget" | "url_not_allowed";
374
362
  /** hook 身份(CC `OG`/`AEe` 锚:`statusMessage` 优先,否则 command / url / prompt),已脱敏+有界。
375
363
  * ⚠️ http 条目取 URL 时**剥掉 query 与 fragment**([ref] codex R1-F1:端点凭据最常见的挂法是
376
364
  * `?token=…`,而通用脱敏器只认 `user:pass@` 形)。要更友好的名字,作者有 `statusMessage`。 */
@@ -411,9 +399,10 @@ export interface HookManagedUnrun {
411
399
  * · `spawn_failed` / `timeout` —— 起不来 / 超时被收;
412
400
  * · `exit_nonzero` —— 退出码非 0 非 2;`bad_json` —— 看着是 JSON 却读不成(含 http 条目 2xx 回了非 JSON 体、Stop × prompt 的判词读不出);`decision_out_of_set` —— `permissionDecision` 不在 allow / deny / ask 里;
413
401
  * · `evidence_unavailable` —— Stop × prompt 条目因会话证据面不足(或运维关了 transcript)被滤掉没跑;
414
- * · `rewrite_unsettled` —— 一个托管相(插件相 / 策略相)改写了输入、按新输入把那一相重判一遍后仍交回不同的值(不收敛;「改写」按值判,恒等回显不算)。
402
+ * · `rewrite_unsettled` —— 一个托管相(插件相 / 策略相)改写了输入、按新输入把那一相重判一遍后仍交回不同的值(不收敛;「改写」按值判,恒等回显不算);
403
+ * · `url_not_allowed` —— http 条目被 http hook 名单拦下、没发出(7.142.0 起;同一次的 `hook_non_blocking_failure{url_not_allowed}` 照发)。
415
404
  */
416
- reason: "matcher_invalid" | "llm_carrier_unavailable" | "llm_cap" | "powershell_unsupported" | "if_unevaluable" | "budget_exhausted" | "spawn_failed" | "timeout" | "exit_nonzero" | "bad_json" | "decision_out_of_set" | "evidence_unavailable" | "rewrite_unsettled";
405
+ reason: "matcher_invalid" | "llm_carrier_unavailable" | "llm_cap" | "powershell_unsupported" | "if_unevaluable" | "budget_exhausted" | "spawn_failed" | "timeout" | "exit_nonzero" | "bad_json" | "decision_out_of_set" | "evidence_unavailable" | "rewrite_unsettled" | "url_not_allowed";
417
406
  /** 那一组的来源词(`managedPolicy` 或 `managedPlugin:<name>`;名只留痕)。 */
418
407
  source: string;
419
408
  /** hook 身份(同 `hook_non_blocking_failure`:`statusMessage` 优先,否则 command / url〔剥 query〕/ prompt),已脱敏 + 有界。 */
@@ -582,7 +571,7 @@ export declare class FleetEventBus {
582
571
  *
583
572
  * `opts`([ref],两键均 ADDITIVE):`removeReason:"orphaned"` = **陈述级退场**(没有结算语义,见
584
573
  * {@link FleetFrame} 的 `task_remove` 臂;[ref] 起**不封被退那一代**,同代帧 = 复活);`cycleSeq` = 被退那一代的代际号。发布方的常规清场
585
- * (`onTerminal`/`onChildTerminal`)不传 opts ⇒ 帧逐字节与本改动之前相同。 */
574
+ * (`onTerminal`、BCE 车道的子代终局)不传 opts ⇒ 帧逐字节与本改动之前相同。 */
586
575
  removeTask(id: string, opts?: {
587
576
  removeReason?: "orphaned";
588
577
  cycleSeq?: number;
@@ -590,30 +579,28 @@ export declare class FleetEventBus {
590
579
  private readonly bceClaims;
591
580
  private static readonly BCE_CLAIM_MAX;
592
581
  private static bceKey;
593
- /** BCE 车道:本车道已为该子代 uuid 建了真行 —— run-leg 车道自此让位。幂等。 */
594
- claimBackgroundChildLane(scope: string | undefined, childUuid: string, rowId: string): void;
595
- /** BCE 车道:该子代已终态离场 —— 让位解除(后续同 uuid 的迟到 tick 回到旧行为)。幂等。 */
596
- releaseBackgroundChildLane(scope: string | undefined, childUuid: string): void;
597
- /** run-leg 车道:该子代是否已有 BCE 真行(有 ⇒ 让位,不铸复合 id 行)。 */
598
- backgroundChildLaneRow(scope: string | undefined, childUuid: string): string | undefined;
582
+ /** BCE 车道:腿的这个名字(会话 id 或腿 task id)点名的是本车道的这一行 —— run-leg 车道自此让位。幂等。 */
583
+ claimBackgroundChildLane(scope: string | undefined, legName: string, rowId: string): void;
584
+ /** BCE 车道:该行已终态离场 —— 撤它名下的**每一个**名字(重试换过会话的,几只都撤;后续同名的迟到 tick 回到旧行为)。幂等。 */
585
+ releaseBackgroundChildLane(scope: string | undefined, rowId: string): void;
586
+ /** 腿的这个名字点名的 BCE 行(有 ⇒ run-leg 让位、孙代挂它下面、审批归它)。 */
587
+ backgroundChildLaneRow(scope: string | undefined, legName: string): string | undefined;
599
588
  /** [ref] 让位迁移料的读面:迁移「只补缺席位」需要看得见存活行现有什么(BCE 是权威车道,不覆盖)。 */
600
589
  taskRow(id: string): Readonly<FleetTaskRow> | undefined;
601
590
  /**
602
- * [ref]:一条子代行在它两只**属主账**上的键。三个 id 域互不相同,换算只有本类做得了(两种行 id 都是本文件
603
- * 铸的,两域之间唯一的 join —— 让位登记簿 —— 也住在这里),所以换算只写这一处:
604
- * · 行 id —— BCE 车道 = registry handle 本身(`e.taskId`);run-leg 车道 = `${runId} ${子代 task_progress taskId}`
605
- * (`fleetRunPublisher` 的 `childId`);
606
- * · `handle` —— core bg registry / `BackgroundAgentStore` 的行键,**只认** `DURABLE_AGENT_HANDLE_RE` 形
607
- * (`wa*` 不在 bg 账上);
608
- * · `sessionIds` —— 子代自己的 core session id(uuid 域)= 待决审批 `originTaskId` 的值域
609
- * (core `AskRequest.sourceTaskId`:「the issuing task's session id」),**不是** handle。是**集合**:同一行名下
610
- * 可以先后挂过几个子代 session(`wa*` 重试换 session、复活换 session),让位登记簿对每一个都留着 claim ——
611
- * 只取其一(此前取最早那个)会漏掉当前这一次的卡(codex r1 F3)。
612
- * 换不出的键就缺席 / 空(不猜):父链接行 / 顶层 run 行两者皆无;BCE 行在本车道学到子代 uuid 之前 `sessionIds` 为空。
591
+ * [ref]:一条子代行在它两只**属主账**上的键。行 → 键的换算只写这一处(两种行 id 都是本文件铸的,会话 id 那张 join 表也住在这里):
592
+ * · `handle` —— core bg registry / `BackgroundAgentStore` 的行键:行 id 本身是引擎的句柄形(`DURABLE_AGENT_HANDLE_RE`)才有
593
+ * (`wa*` 与 run-leg 复合行不在 bg 账上);
594
+ * · `names` —— 这一行那条腿的名字,待决审批按它们认发起者(问上带它那条腿的名字:`agentId` = 腿 task id,委派子代的问另带
595
+ * 发起会话 `sourceSessionId`;任一个是这一行的名字 ⇒ 这一问是这一行的)。同一条读法点名 tick 的行,所以三形各取各的:句柄形的行 ⇒
596
+ * 行 id 本身(后台子代的会话 id 不是它的名字,本表不登);run-leg 复合行 `${runId} ${前台子代的腿 id}` ⇒ 尾段(前台子代的腿 id
597
+ * 就是它的会话 id);其余 BCE 行(`wa*`)⇒ 登记在它名下的**每一个**名字(会话 id,重试换了会话两次都在 —— 只取其一会漏掉当前这一次的卡,
598
+ * codex r1 F3;脚本声明的腿 task id,首拍起)。
599
+ * 换不出的键就缺席 / 空(不猜):顶层 run 行两者皆无。
613
600
  */
614
601
  childOwnerKeys(row: Pick<FleetTaskRow, "id" | "scope">): {
615
602
  handle?: string;
616
- sessionIds: readonly string[];
603
+ names: readonly string[];
617
604
  };
618
605
  /**
619
606
  * Publish a workflow row + fan out. **The row is the whole row and REPLACES the previous one** (by `id`). A workflow row has exactly one producer,
@@ -688,14 +675,6 @@ export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
688
675
  status?: string;
689
676
  seq?: number;
690
677
  }) => void;
691
- /** Flip + remove one subagent CHILD row when its background completion notification arrives
692
- * (task_progress never emits a terminal tick — without this a bg child sat "running" until parent settle).
693
- * FLIP-THROUGH: publishes the terminal frame even when the row no longer exists — the parent leg's
694
- * settle removes ALL child rows (it cannot tell a settled sync child from a still-running bg child), so a bg
695
- * child that completes after parent settle otherwise had NO row to flip and the shell (auto-exit's fourth
696
- * release condition watches the viewed cid's terminal) never saw a terminal transition. Returns whether the
697
- * row EXISTED (hadRow — the observer logs it; false = the frame was synthesized flip-through). */
698
- onChildTerminal: (taskId: string, status: string, altId?: string, toolUseId?: string) => boolean;
699
678
  /** [ref]①/(a) 案:`residuals` = 顶层 run 的终局残局键(有源才传,见 FleetTaskRow 上的键注)。
700
679
  * 只有**真终态**(completed/failed/killed)帧带残局——parked(suspended/needs_review)的行还活着,
701
680
  * 没有「终局」可言,误传也不上帧。 */
@@ -736,9 +715,9 @@ export declare function fleetRunResiduals(result: {
736
715
  * child frames), this observer lives as long as the process and covers the child's WHOLE lifecycle:
737
716
  * spawn → row appears the moment the child registers (launch→turn-tail 零帧 fixed: no more waiting for a
738
717
  * first tick that a slow child never emits inside the turn);
739
- * tick → token rollup onto the row; ALSO best-effort removes the per-leg uuid-keyed TWIN row the leg's
740
- * onForwardEvent built for the same child (`${parentTaskId} ${progressTaskId}` composite — the
741
- * per-leg childId shape), so the child shows ONCE, keyed by its stable a* handle;
718
+ * tick → token rollup onto the row. The child shows ONCE, keyed by its row id: a background agent's
719
+ * ticks carry that id (core 7.61.0), a workflow agent's carry its session id, registered here from
720
+ * the frame's `sessionId` — either way the per-leg lane yields; this lane writes only its own rows;
742
721
  * terminal → terminal frame under the a* row id, row leaves the fleet, and the contract
743
722
  * `bg_notification` frame rides the always-open stream (缺口②'s immediate idle delivery).
744
723
  * Rows are tagged `scope` (tenant filter) from the registry scope and `sessionId` (the `?session=` filter)
@@ -1,13 +1,10 @@
1
1
  import { EventEmitter } from "node:events";
2
- import { DURABLE_AGENT_HANDLE_RE, deriveAgentDisplayStatus, isDelegatedAgentTerminal, runParkedOf } from "@sema-agent/core";
2
+ import { DURABLE_AGENT_HANDLE_RE, deriveAgentDisplayStatus, runParkedOf } from "@sema-agent/core";
3
3
  import { persistedPlaneOf } from "../terminal.js";
4
4
  import { takeWorkspaceSnapshotFailure } from "./workspace-snapshot-residual.js";
5
5
  import { recordFailOpen } from "../observability/fail-open.js";
6
6
  import { redactSecrets } from "../trace/redact.js";
7
7
  import { buildRunObjectivePreview } from "../user-authored-text.js";
8
- export function isFleetAgentTerminalNotification(n) {
9
- return isDelegatedAgentTerminal(n);
10
- }
11
8
  export function buildFleetWorkflowRow(id, run) {
12
9
  const agents = run.agents ?? [];
13
10
  const done = agents.filter((a) => a.status === "completed").length;
@@ -156,9 +153,9 @@ export class FleetEventBus {
156
153
  }
157
154
  bceClaims = new Map();
158
155
  static BCE_CLAIM_MAX = 4096;
159
- static bceKey(scope, childUuid) { return `${scope ?? "default"}\u0000${childUuid}`; }
160
- claimBackgroundChildLane(scope, childUuid, rowId) {
161
- const k = FleetEventBus.bceKey(scope, childUuid);
156
+ static bceKey(scope, legName) { return `${scope ?? "default"}\u0000${legName}`; }
157
+ claimBackgroundChildLane(scope, legName, rowId) {
158
+ const k = FleetEventBus.bceKey(scope, legName);
162
159
  this.bceClaims.delete(k);
163
160
  this.bceClaims.set(k, rowId);
164
161
  if (this.bceClaims.size > FleetEventBus.BCE_CLAIM_MAX) {
@@ -167,28 +164,30 @@ export class FleetEventBus {
167
164
  this.bceClaims.delete(oldest.value);
168
165
  }
169
166
  }
170
- releaseBackgroundChildLane(scope, childUuid) {
171
- this.bceClaims.delete(FleetEventBus.bceKey(scope, childUuid));
167
+ releaseBackgroundChildLane(scope, rowId) {
168
+ const prefix = FleetEventBus.bceKey(scope, "");
169
+ for (const [k, v] of this.bceClaims)
170
+ if (v === rowId && k.startsWith(prefix))
171
+ this.bceClaims.delete(k);
172
172
  }
173
- backgroundChildLaneRow(scope, childUuid) {
174
- return this.bceClaims.get(FleetEventBus.bceKey(scope, childUuid));
173
+ backgroundChildLaneRow(scope, legName) {
174
+ return this.bceClaims.get(FleetEventBus.bceKey(scope, legName));
175
175
  }
176
176
  taskRow(id) {
177
177
  return this.tasks.get(id);
178
178
  }
179
179
  childOwnerKeys(row) {
180
+ if (DURABLE_AGENT_HANDLE_RE.test(row.id))
181
+ return { handle: row.id, names: [row.id] };
180
182
  const sp = row.id.lastIndexOf(" ");
181
- if (sp > 0) {
182
- const sessionId = row.id.slice(sp + 1);
183
- const claimed = this.bceClaims.get(FleetEventBus.bceKey(row.scope, sessionId));
184
- return { sessionIds: [sessionId], ...(claimed !== undefined && DURABLE_AGENT_HANDLE_RE.test(claimed) ? { handle: claimed } : {}) };
185
- }
183
+ if (sp > 0)
184
+ return { names: [row.id.slice(sp + 1)] };
186
185
  const prefix = FleetEventBus.bceKey(row.scope, "");
187
- const sessionIds = [];
186
+ const names = [];
188
187
  for (const [k, rowId] of this.bceClaims)
189
188
  if (rowId === row.id && k.startsWith(prefix))
190
- sessionIds.push(k.slice(prefix.length));
191
- return { sessionIds, ...(DURABLE_AGENT_HANDLE_RE.test(row.id) ? { handle: row.id } : {}) };
189
+ names.push(k.slice(prefix.length));
190
+ return { names };
192
191
  }
193
192
  publishWorkflow(row) {
194
193
  this.workflows.set(row.id, row);
@@ -231,15 +230,15 @@ export class FleetEventBus {
231
230
  }
232
231
  export function fleetRunPublisher(bus, run) {
233
232
  if (!bus)
234
- return { onStart: () => undefined, onEvent: () => undefined, onForwardEvent: () => undefined, onChildTerminal: () => false, onTerminal: () => undefined };
233
+ return { onStart: () => undefined, onEvent: () => undefined, onForwardEvent: () => undefined, onTerminal: () => undefined };
235
234
  let tokens = 0;
236
235
  const startedAt = Date.now();
237
236
  const sessionField = run.sessionId ? { sessionId: run.sessionId } : {};
238
237
  const children = new Set();
239
238
  const childStartedAt = new Map();
240
- const childByToolCall = new Map();
241
239
  let settledLeg = false;
242
240
  const childId = (taskId) => `${run.runId} ${taskId}`;
241
+ const backgroundRowOf = (taskId) => (DURABLE_AGENT_HANDLE_RE.test(taskId) ? taskId : bus.backgroundChildLaneRow(run.scope, taskId));
243
242
  const tickStatus = (st) => (st === "completed" ? "completed" : st === "failed" ? "failed" : "running");
244
243
  const workflowRunIdField = (ev) => (ev.workflowRunId ? { workflowRunId: ev.workflowRunId } : {});
245
244
  const toolUsesOf = (usage) => {
@@ -247,15 +246,12 @@ export function fleetRunPublisher(bus, run) {
247
246
  return typeof t === "number" ? t : undefined;
248
247
  };
249
248
  const yieldToBackgroundChildLane = (childTaskId, cid, tickName) => {
250
- const bceRowId = bus.backgroundChildLaneRow(run.scope, childTaskId);
249
+ const bceRowId = backgroundRowOf(childTaskId);
251
250
  if (bceRowId === undefined)
252
251
  return false;
253
252
  if (children.has(cid)) {
254
253
  bus.removeTask(cid);
255
254
  children.delete(cid);
256
- for (const [k, v] of childByToolCall)
257
- if (v === cid)
258
- childByToolCall.delete(k);
259
255
  }
260
256
  const row = bus.taskRow(bceRowId);
261
257
  if (row) {
@@ -303,8 +299,6 @@ export function fleetRunPublisher(bus, run) {
303
299
  const childName = ev.name !== undefined ? redactSecrets(ev.name) : undefined;
304
300
  if (!childStartedAt.has(cid))
305
301
  childStartedAt.set(cid, Date.now());
306
- if (ev.parentToolCallId)
307
- childByToolCall.set(ev.parentToolCallId, cid);
308
302
  bus.publishTask({ id: cid, sourceLane: "run-leg", ...(childName !== undefined ? { name: childName, agentType: childName } : {}), parentId: run.runId, scope: run.scope, ...sessionField, ...workflowRunIdField(ev), status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
309
303
  }
310
304
  else if (ev.type === "tool_start" && ev.toolName) {
@@ -320,43 +314,12 @@ export function fleetRunPublisher(bus, run) {
320
314
  if (yieldToBackgroundChildLane(ev.taskId, cid, ev.name))
321
315
  return;
322
316
  children.add(cid);
323
- const parentId = ev.parentTaskId && ev.parentTaskId !== run.rootTaskId ? childId(ev.parentTaskId) : run.runId;
317
+ const parentId = ev.parentTaskId && ev.parentTaskId !== run.rootTaskId ? (backgroundRowOf(ev.parentTaskId) ?? childId(ev.parentTaskId)) : run.runId;
324
318
  const fwdName = ev.name !== undefined ? redactSecrets(ev.name) : undefined;
325
319
  if (!childStartedAt.has(cid))
326
320
  childStartedAt.set(cid, Date.now());
327
- if (ev.parentToolCallId)
328
- childByToolCall.set(ev.parentToolCallId, cid);
329
321
  bus.publishTask({ id: cid, sourceLane: "run-leg", ...(fwdName !== undefined ? { name: fwdName, agentType: fwdName } : {}), parentId, scope: run.scope, ...sessionField, ...workflowRunIdField(ev), status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
330
322
  },
331
- onChildTerminal(taskId, status, altId, toolUseId) {
332
- if (settledLeg)
333
- return false;
334
- const fleetStatus = status === "completed" ? "completed" : status === "killed" || status === "cancelled" ? "killed" : "failed";
335
- const candidateCids = [childId(taskId)];
336
- if (altId !== undefined && altId !== taskId)
337
- candidateCids.push(childId(altId));
338
- const viaToolCall = toolUseId !== undefined ? childByToolCall.get(toolUseId) : undefined;
339
- if (viaToolCall !== undefined && !candidateCids.includes(viaToolCall))
340
- candidateCids.push(viaToolCall);
341
- const liveCids = candidateCids.filter((c) => children.has(c));
342
- const hadRow = liveCids.length > 0;
343
- if (!hadRow) {
344
- const claimed = [taskId, altId].some((t) => t !== undefined && bus.backgroundChildLaneRow(run.scope, t) !== undefined);
345
- if (claimed)
346
- return true;
347
- }
348
- for (const cid of hadRow ? liveCids : [childId(taskId)]) {
349
- const startedAtChild = childStartedAt.get(cid);
350
- bus.publishTask({ id: cid, ...(children.has(cid) ? {} : { parentId: run.runId, scope: run.scope, ...sessionField }), status: fleetStatus, ...(startedAtChild !== undefined ? { elapsedMs: Date.now() - startedAtChild } : {}) });
351
- bus.removeTask(cid);
352
- children.delete(cid);
353
- childStartedAt.delete(cid);
354
- for (const [k, v] of childByToolCall)
355
- if (v === cid)
356
- childByToolCall.delete(k);
357
- }
358
- return hadRow;
359
- },
360
323
  onTerminal(status, residuals) {
361
324
  settledLeg = true;
362
325
  const fleetStatus = runStatusToFleet(status);
@@ -374,7 +337,6 @@ export function fleetRunPublisher(bus, run) {
374
337
  bus.removeTask(cid);
375
338
  children.clear();
376
339
  childStartedAt.clear();
377
- childByToolCall.clear();
378
340
  if (terminal) {
379
341
  bus.removeTask(run.runId);
380
342
  }
@@ -433,11 +395,13 @@ export function fleetBackgroundChildPublisher(bus, log) {
433
395
  }
434
396
  }
435
397
  };
436
- const claimIfKnown = (e, m) => {
437
- const own = !e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink);
438
- const uuid = e.sessionId ?? (own ? e.progressTaskId : undefined);
439
- if (uuid)
440
- bus.claimBackgroundChildLane(m.tenantScope, uuid, e.taskId);
398
+ const joinWorkflowAgentNames = (e, m) => {
399
+ if (DURABLE_AGENT_HANDLE_RE.test(e.taskId))
400
+ return;
401
+ if (e.sessionId)
402
+ bus.claimBackgroundChildLane(m.tenantScope, e.sessionId, e.taskId);
403
+ if (e.kind === "tick" && e.progressTaskId && e.progressParentTaskId === m.parentTaskId)
404
+ bus.claimBackgroundChildLane(m.tenantScope, e.progressTaskId, e.taskId);
441
405
  };
442
406
  const resolveParentId = (parentInput, domain, childScope) => {
443
407
  const rows = bus.snapshot().tasks;
@@ -445,12 +409,9 @@ export function fleetBackgroundChildPublisher(bus, log) {
445
409
  if (rows.some((r) => r.id === parentInput && r.scope === childScope))
446
410
  return { id: parentInput, resolved: true };
447
411
  }
448
- for (const [aStar, pm] of meta) {
449
- if (pm.aliasUuid === parentInput && pm.tenantScope === childScope) {
450
- if (rows.some((r) => r.id === aStar && r.scope === childScope))
451
- return { id: aStar, resolved: true };
452
- }
453
- }
412
+ const joined = bus.backgroundChildLaneRow(childScope, parentInput);
413
+ if (joined !== undefined && rows.some((r) => r.id === joined && r.scope === childScope))
414
+ return { id: joined, resolved: true };
454
415
  let match;
455
416
  for (const r of rows) {
456
417
  if (r.sessionId === parentInput && r.parentId === undefined && r.scope === childScope && !meta.has(r.id))
@@ -506,7 +467,6 @@ export function fleetBackgroundChildPublisher(bus, log) {
506
467
  ...(e.startedAt !== undefined ? { spawnedAt: e.startedAt } : {}),
507
468
  ...(e.rootSessionId ? { rootSessionId: e.rootSessionId } : {}),
508
469
  ...(e.parentToolCallId ? { parentToolCallId: e.parentToolCallId } : {}),
509
- ...(e.sessionId ? { aliasUuid: e.sessionId } : {}),
510
470
  ...(e.workflowRunId ? { workflowRunId: e.workflowRunId } : {}),
511
471
  ...(e.workflowRunId && !(e.sessionScoped && e.owner)
512
472
  ? (e.rootSessionId ? { hostSessionId: e.rootSessionId } : {})
@@ -516,29 +476,13 @@ export function fleetBackgroundChildPublisher(bus, log) {
516
476
  : {}),
517
477
  };
518
478
  remember(e.taskId, m);
519
- claimIfKnown(e, m);
479
+ joinWorkflowAgentNames(e, m);
520
480
  const displayName = e.description ?? e.name;
521
481
  bus.publishTask({ id: e.taskId, ...(displayName !== undefined ? { name: redactSecrets(displayName) } : {}), ...(e.agentType ? { agentType: redactSecrets(e.agentType) } : {}), ...(e.spawnName ? { agentName: e.spawnName } : {}), ...rowTags(m), status: "running", tokens: 0, ...(typeof e.seq === "number" ? { cycleSeq: e.seq } : {}), ...(e.transcriptId ? { transcriptId: e.transcriptId } : {}) });
522
482
  dlog("bg_child_event", { kind: "spawn", taskId: e.taskId, sessionScoped: e.sessionScoped, scope: m.tenantScope, hostSessionId: m.hostSessionId ?? null, parentTaskId: m.parentTaskId ?? null });
523
483
  };
524
484
  const handleTick = (e, m) => {
525
- claimIfKnown(e, m);
526
- if (!m.suppressedTwin && e.progressTaskId && (!e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink))) {
527
- const tail = ` ${e.progressTaskId}`;
528
- for (const row of bus.snapshot().tasks) {
529
- if (row.id.endsWith(tail))
530
- bus.removeTask(row.id);
531
- }
532
- m.suppressedTwin = true;
533
- }
534
- if (m.aliasUuid === undefined && e.progressTaskId && (!e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink))) {
535
- m.aliasUuid = e.progressTaskId;
536
- for (const [cid, cm] of meta) {
537
- if ((cm.parentTaskId ?? cm.parentSessionLink) === m.aliasUuid && cm.resolvedParentId === undefined && !cm.done) {
538
- bus.publishTask({ id: cid, ...rowTags(cm) });
539
- }
540
- }
541
- }
485
+ joinWorkflowAgentNames(e, m);
542
486
  const tokens = sumUsage(e.usage);
543
487
  const name = e.name ? redactSecrets(e.name) : undefined;
544
488
  const agentType = e.agentType ? redactSecrets(e.agentType) : undefined;
@@ -573,15 +517,7 @@ export function fleetBackgroundChildPublisher(bus, log) {
573
517
  : {}),
574
518
  });
575
519
  bus.removeTask(e.taskId);
576
- if (m.aliasUuid)
577
- bus.releaseBackgroundChildLane(m.tenantScope, m.aliasUuid);
578
- if (m.aliasUuid) {
579
- const tail = ` ${m.aliasUuid}`;
580
- for (const row of bus.snapshot().tasks) {
581
- if (row.id.endsWith(tail))
582
- bus.removeTask(row.id);
583
- }
584
- }
520
+ bus.releaseBackgroundChildLane(m.tenantScope, e.taskId);
585
521
  if (m.workflowRunId !== undefined) {
586
522
  m.done = true;
587
523
  dlog("bg_child_event", { kind: "terminal-wa-no-notification", taskId: e.taskId, workflowRunId: m.workflowRunId });
@@ -623,7 +559,6 @@ export function fleetBackgroundChildPublisher(bus, log) {
623
559
  });
624
560
  dlog("bg_child_event", { kind: "terminal", taskId: e.taskId, status, scope: m.tenantScope ?? null, hostSessionId: m.hostSessionId ?? null, childSessionId: e.sessionId ?? null, bgNotificationPublished: true });
625
561
  m.done = true;
626
- m.suppressedTwin = true;
627
562
  };
628
563
  return (e) => {
629
564
  if (e.kind === "spawn") {
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * ## 它修什么(§0 病灶机制链)
5
5
  * fleet 总线是进程内纯内存聚合(`fleet-bus.ts` 头注自陈 NOT durable / NOT cross-replica),行的**唯一**
6
- * 离场路径是发布方主动打 `onTerminal`/`onChildTerminal`。发布方没走到终态臂(run 事件环异常中断、引擎
6
+ * 离场路径是发布方主动打终态臂(run-leg 的 `onTerminal`、BCE 车道的子代终局)。发布方没走到终态臂(run 事件环异常中断、引擎
7
7
  * 被壳 reuse 而旧 run 对象已死、BCE 终态通知丢失),行就**永久僵在** `tasks` Map 里 —— 此后每个订阅方
8
8
  * (含 snapshot 新连接)看到一条永远 "running" 的幽灵行。壳侧只能靠 overlay 防御(cli 1.0.74 过渡件)。
9
9
  *
@@ -147,10 +147,10 @@ export interface FleetReconcilerDeps {
147
147
  agents?: FleetReconcileAgentPort;
148
148
  /**
149
149
  * [ref]:子代活性的属主②:这只子代此刻有没有**待决**审批卡。只问是非(与 {@link isLiveOnThisReplica} 同姿势,
150
- * 不搬 Map)。入参是 ask 发起者域(子代自己的 core session id,= 卡上的 `originTaskId`),**不是**行 id ——
151
- * 行 id → 该域的换算只在 `FleetEventBus.childOwnerKeys`。生产 = `ToolApprovalCoordinator.hasLivePendingFrom`。
150
+ * 不搬 Map)。入参是这一行那条腿的名字,**不总是**行 id(前台子代 = 会话 id;`wa*` = 会话 id 与脚本声明的腿 task id)——
151
+ * 行 id → 名字的换算只在 `FleetEventBus.childOwnerKeys`。生产 = `ToolApprovalCoordinator.hasLivePendingFromLeg`。
152
152
  */
153
- hasPendingAsk?: (originTaskId: string) => boolean;
153
+ hasPendingAsk?: (names: readonly string[]) => boolean;
154
154
  /** 本副本 id(与 `RunRecord.instanceId` 同域)。只进日志/读数 —— 两条 `running` 臂的**处置相同**
155
155
  * (都是陈述级退场),分不分得出 claim 属谁不改变行为,故它不是判据。 */
156
156
  instanceId?: string;
@@ -146,7 +146,7 @@ export function createFleetReconciler(deps) {
146
146
  }
147
147
  }
148
148
  const hasPendingAsk = deps.hasPendingAsk;
149
- if (hasPendingAsk !== undefined && deps.bus.childOwnerKeys(row).sessionIds.some((id) => hasPendingAsk(id))) {
149
+ if (hasPendingAsk !== undefined && hasPendingAsk(deps.bus.childOwnerKeys(row).names)) {
150
150
  keptAlive(row, "pending_ask");
151
151
  return "settled";
152
152
  }
@@ -6,10 +6,9 @@
6
6
  export type SubagentTailFrame = Record<string, unknown> & {
7
7
  type: string;
8
8
  };
9
- /** core forward 事件 → wire 投影(sync 主流五分支同源;不认识的帧类型=null 不发——tail 面只承诺
10
- * content 六类,新 core 帧类型先经这里显式收编再出 wire)。
11
- * ⚠️ **本函数是无状态逐帧投影**:`reasoning_end`([ref] 的推理权威段)不在这里 —— 它要按句柄攒段,
12
- * 住在 {@link SubagentTailBus.onForwardFrame}(publish 侧是唯一知道句柄的地方)。 */
9
+ /** core forward 事件 → wire 投影(sync 主流同源;不认识的帧类型=null 不发——新 core 帧类型先经这里显式收编再出 wire)。
10
+ * ⚠️ **本函数是无状态逐帧投影**:模型文本(`text_delta` / `reasoning_delta` / `text_end` 与段界上的 `reasoning_end`)不在这里 ——
11
+ * 它们要按句柄攒段、经同一只脱敏器放行,住在 {@link SubagentTailBus.onForwardFrame} 的登记册里(publish 侧是唯一知道句柄的地方);本函数对它们答 null。 */
13
12
  export declare function projectTailFrame(e: Record<string, unknown> & {
14
13
  type?: string;
15
14
  }): SubagentTailFrame | null;
@@ -53,16 +52,20 @@ export declare class SubagentTailBus {
53
52
  */
54
53
  private readonly modeByHandle;
55
54
  /**
56
- * 句柄 → 该句柄这条 tail 流上**在攒的推理段**([ref])。
55
+ * 句柄 → 该句柄这条 tail 流的**模型文本登记册**(`trace/model-segment.ts` 的 `createLiveModelText`:按流身份分账攒段、经同一只脱敏器放行)。
57
56
  *
58
- * 键必须是句柄,理由与 {@link modeByHandle} 同源再加一条硬的:两个并发子代的 `reasoning_delta` 在
59
- * **同一个** forward sink 上交错到达,一只累积器会把两份思考拼成一段、再盖上其中一个的身份键。
57
+ * 键必须是句柄,理由与 {@link modeByHandle} 同源再加一条硬的:两个并发子代的逐块帧在**同一个** forward sink 上交错到达,
58
+ * 一只累积器会把两份文字拼成一段、再盖上其中一个的身份键(登记册内部再按流身份分账)。
60
59
  *
61
- * 生命期 = **有人在听的那段时间**:攒段住在 `hasSubscribers` 快门之内(tail 是 live-only 面,没人听
62
- * 就不投影也不攒),最后一个订阅者走掉或句柄终态({@link forgetHandle})时整条删掉 ⇒ 本表恒被
63
- * 订阅者数量所界,不需要第二道容量闸。
60
+ * 🔴 **生命期 = 句柄活着的那段时间,不是有人在听的那段时间**:没人听时登记册照样攒原文、照样按段界收段(只是不扫描、不出帧 —— 免投影快门仍在),
61
+ * 订阅者半路进来,放行位从**此刻**起,而判定仍按**整段**的上下文:否则一个在 `password=` 之后才开始听的订阅者拿到的是一段没有锚的值,认不出、原样出门
62
+ * (同一段在 `done` / 账本上早已遮掉)。
63
+ * 🔴 **条目只活在开着的段上,没有容量逐出**:一条段的上下文只被**它自己的**段界 / 终态收走(登记册分账律的同一句,`trace/model-segment.ts`)——
64
+ * 按容量逐出一只开着的登记册 = 别的句柄替它收了段,它的下一块从一段没有锚的新文本算起、值原样出门(对抗复审 r1 high:4096 只只报进度的句柄就够)。
65
+ * 所以:段全收了(登记册空着,与新建的一只等价)就删条目;只报进度、从没开过段的句柄不留条目。条目数 = 此刻有开着的模型文本段的句柄数,
66
+ * 每条的量 = 那几段到此刻的原文 —— 在途的模型输出本身;句柄终态({@link forgetHandle})收段并删。
64
67
  */
65
- private readonly segByHandle;
68
+ private readonly textByHandle;
66
69
  /** 三条 run 腿的 forward 回调里逐帧调(在 `hasSubscribers` 快门**之前**——没人在听时也要学,
67
70
  * 否则晚开的 tail 永远读不到供给形)。同值重复写是 no-op(热路径只付一次 Map.get)。 */
68
71
  noteHandleContentMode(bgAgentId: string, mode: TailContentMode): void;
@@ -1,7 +1,6 @@
1
- import { redactSecrets } from "../trace/redact.js";
2
- import { taskProgressEventData, taskStartedEventData, toolStartEventData, toolEndEventData, textEndEventData } from "../trace/project.js";
1
+ import { taskProgressEventData, taskStartedEventData, toolStartEventData, toolEndEventData } from "../trace/project.js";
3
2
  import { liveMediaBytesOf, liveToolEndForBacklog } from "../trace/tool-output-media.js";
4
- import { createReasoningSegments } from "../trace/model-segment.js";
3
+ import { createLiveModelText } from "../trace/model-segment.js";
5
4
  const TAIL_QUEUE_CAP = 512;
6
5
  export function projectTailFrame(e) {
7
6
  const t = e.type;
@@ -19,18 +18,6 @@ export function projectTailFrame(e) {
19
18
  const te = e;
20
19
  return { type: "tool_end", ...toolEndEventData(te) };
21
20
  }
22
- if (t === "text_delta") {
23
- const td = e;
24
- return { type: "text_delta", delta: td.delta, ...(td.eventId ? { eventId: td.eventId } : {}), ...(td.parentToolCallId ? { parentToolCallId: td.parentToolCallId } : {}) };
25
- }
26
- if (t === "text_end") {
27
- const f = textEndEventData(e);
28
- return f === null ? null : { type: "text_end", ...f };
29
- }
30
- if (t === "reasoning_delta") {
31
- const rd = e;
32
- return { type: "reasoning_delta", delta: redactSecrets(rd.delta), ...(rd.eventId ? { eventId: rd.eventId } : {}), ...(rd.parentToolCallId ? { parentToolCallId: rd.parentToolCallId } : {}) };
33
- }
34
21
  return null;
35
22
  }
36
23
  function putBounded(map, key, value) {
@@ -46,7 +33,7 @@ const HOST_MODE_CAP = 4096;
46
33
  export class SubagentTailBus {
47
34
  subs = new Map();
48
35
  modeByHandle = new Map();
49
- segByHandle = new Map();
36
+ textByHandle = new Map();
50
37
  noteHandleContentMode(bgAgentId, mode) {
51
38
  if (this.modeByHandle.get(bgAgentId) === mode)
52
39
  return;
@@ -54,23 +41,24 @@ export class SubagentTailBus {
54
41
  }
55
42
  onForwardFrame(bgAgentId, mode, e) {
56
43
  this.noteHandleContentMode(bgAgentId, mode);
57
- if (!this.hasSubscribers(bgAgentId))
44
+ const deliver = this.hasSubscribers(bgAgentId);
45
+ const text = this.textByHandle.get(bgAgentId) ?? createLiveModelText();
46
+ for (const f of text.onEvent(e, deliver))
47
+ this.publish(bgAgentId, f);
48
+ if (text.isIdle())
49
+ this.textByHandle.delete(bgAgentId);
50
+ else
51
+ this.textByHandle.set(bgAgentId, text);
52
+ if (!deliver)
58
53
  return;
59
- let segs = this.segByHandle.get(bgAgentId);
60
- if (segs === undefined) {
61
- segs = createReasoningSegments();
62
- this.segByHandle.set(bgAgentId, segs);
63
- }
64
- for (const end of segs.onEvent(e))
65
- this.publish(bgAgentId, end);
66
54
  const f = projectTailFrame(e);
67
55
  if (f)
68
56
  this.publish(bgAgentId, f);
69
57
  }
70
58
  forgetHandle(bgAgentId) {
71
- for (const end of this.segByHandle.get(bgAgentId)?.cut() ?? [])
72
- this.publish(bgAgentId, end);
73
- this.segByHandle.delete(bgAgentId);
59
+ for (const f of this.textByHandle.get(bgAgentId)?.cut(undefined, this.hasSubscribers(bgAgentId)) ?? [])
60
+ this.publish(bgAgentId, f);
61
+ this.textByHandle.delete(bgAgentId);
74
62
  this.modeByHandle.delete(bgAgentId);
75
63
  }
76
64
  handleContentMode(bgAgentId) {
@@ -114,7 +102,6 @@ export class SubagentTailBus {
114
102
  set.delete(sub);
115
103
  if (set.size === 0 && this.subs.get(bgAgentId) === set) {
116
104
  this.subs.delete(bgAgentId);
117
- this.segByHandle.delete(bgAgentId);
118
105
  }
119
106
  };
120
107
  const it = {
@@ -1,5 +1,6 @@
1
1
  import { type HookEntry, type HookEntryType, type HookEventName, type HooksDroppedPiece, type HooksDroppedPieceCode, type HooksRejection, type HooksRejectionCode } from "@sema-agent/settings-schema/hooks";
2
2
  import { type ConfigPath, type UrlCredential } from "@sema-agent/settings-schema";
3
+ import { type HttpHookAllowlistLayer } from "@sema-agent/settings-schema";
3
4
  import { ENGINE_OWNED_HOOK_EVENTS } from "@sema-agent/settings-schema/hooks";
4
5
  import type { EngineDollar, ModRegistration } from "@sema-agent/core";
5
6
  import type { Logger } from "../observability/logger.js";
@@ -514,6 +515,11 @@ export interface HookRunnerContext {
514
515
  * 的 TaskStream.steer(下个 turn 边界注入);返回 false=没有活流可投(任务已结束/挂起/别副本)——
515
516
  * 调用方记账不重试(挂起腿的 pending-steer park 是后续切片)。缺席 ⇒ asyncRewake 降级纯 async(记账)。 */
516
517
  wake?: (text: string) => Promise<boolean>;
518
+ /**
519
+ * http hook 两张名单(`allowedHttpHookUrls` / `httpHookAllowedEnvVars`)的**设置层**,交契约包判官原样读(见 {@link runHttpHook})。必填:每个装配点都要说这条 run 有哪些层 ——
520
+ * `[]` = 没有层写名单(不限,与引擎外的参照实现「名单未设 ⇒ 不限」同读)。今天唯一的层来源是请求的 `settings`(`task-settings.ts` 的 `httpHookAllowlist`,源 `flagSettings`)。
521
+ */
522
+ httpHookAllowlistLayers: readonly HttpHookAllowlistLayer[];
517
523
  }
518
524
  /** 阶段三b 模型调用载体契约(prompt=直连一次 completion;agent=runTask 收敛后的 final text)。
519
525
  * 返回 ok/text 或 ok:false/error——载体自己兜超时(timeoutMs 是硬顶,载体可更严),绝不 throw。 */