@sema-agent/server 7.125.1 → 7.127.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 (275) hide show
  1. package/MIGRATION.md +229 -2
  2. package/README.md +2 -2
  3. package/README.zh-CN.md +2 -2
  4. package/USAGE.md +346 -145
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/chart/templates/networkpolicy-sandbox.yaml +57 -0
  7. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +32 -1
  8. package/deploy/sema-up/chart/templates/server-v4pro.yaml +3 -2
  9. package/deploy/sema-up/chart/templates/server.yaml +2 -1
  10. package/deploy/sema-up/chart/values.yaml +22 -0
  11. package/deploy/sema-up/cluster-up.sh +10 -10
  12. package/deploy/sema-up/kube-up.sh +20 -13
  13. package/deploy/sema-up/lib/dataroot.sh +1 -1
  14. package/deploy/sema-up/lib/envf.sh +5 -5
  15. package/deploy/sema-up/lib/flagshape.sh +5 -5
  16. package/deploy/sema-up/lib/lanes.py +1 -1
  17. package/deploy/sema-up/lib/node-addrs.sh +42 -0
  18. package/deploy/sema-up/lib/parse-machines.py +2 -2
  19. package/deploy/sema-up/lib/shell-access.sh +1 -1
  20. package/deploy/sema-up/preflight.sh +4 -4
  21. package/deploy/sema-up/sema-up.sh +33 -33
  22. package/deploy/sema-up/smoke.sh +3 -3
  23. package/deploy/sema-up/stack/compose.yaml +1 -1
  24. package/deploy/sema-up/stack/sema-stack-cluster.yaml +26 -3
  25. package/dist/approval-card.d.ts +20 -4
  26. package/dist/approval-content-kind.d.ts +38 -22
  27. package/dist/approval-content-kind.js +20 -4
  28. package/dist/audit.js +3 -0
  29. package/dist/bench/s1/arms.d.ts +9 -37
  30. package/dist/bench/s1/arms.js +4 -61
  31. package/dist/bench/s1/live-deps.d.ts +4 -10
  32. package/dist/bench/s1/live-deps.js +1 -222
  33. package/dist/bench/s1/oracle.d.ts +1 -1
  34. package/dist/bench/s1/reviewer.d.ts +1 -1
  35. package/dist/bench/s1/row.d.ts +5 -7
  36. package/dist/bench/s1/row.js +0 -2
  37. package/dist/bench/s1/run-firm.d.ts +2 -2
  38. package/dist/bench/s1/run-firm.js +1 -4
  39. package/dist/bench/s1/runner-ctx.d.ts +17 -29
  40. package/dist/bench/s1/runner-ctx.js +3 -7
  41. package/dist/bench/s1/tasks.d.ts +9 -46
  42. package/dist/bench/s1/tasks.js +4 -63
  43. package/dist/boot/execution-env.d.ts +38 -26
  44. package/dist/boot/execution-env.js +87 -41
  45. package/dist/boot/leader.d.ts +2 -1
  46. package/dist/boot/memory-boundary.d.ts +1 -1
  47. package/dist/boot/memory-consolidation.d.ts +37 -3
  48. package/dist/boot/memory-consolidation.js +18 -2
  49. package/dist/boot/parked-revive-gate.d.ts +0 -3
  50. package/dist/boot/parked-revive-gate.js +2 -2
  51. package/dist/boot/resolve-spec.d.ts +0 -2
  52. package/dist/boot/resolve-spec.js +12 -17
  53. package/dist/boot/retention-lane.d.ts +12 -1
  54. package/dist/boot/retention-lane.js +2 -0
  55. package/dist/boot/runner-deps.d.ts +7 -6
  56. package/dist/boot/runner-deps.js +5 -16
  57. package/dist/boot/session-faces.d.ts +7 -2
  58. package/dist/boot/session-faces.js +37 -1
  59. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  60. package/dist/boot/stage-03-store-backend.js +2 -2
  61. package/dist/boot/stage-04-stores.d.ts +1 -0
  62. package/dist/boot/stage-05-execution-env.d.ts +2 -2
  63. package/dist/boot/stage-05-execution-env.js +7 -4
  64. package/dist/boot/stage-06-runners.d.ts +2 -3
  65. package/dist/boot/stage-06-runners.js +13 -9
  66. package/dist/boot/stage-07-capability-layer.d.ts +2 -3
  67. package/dist/boot/stage-07-capability-layer.js +3 -4
  68. package/dist/boot/stage-08-reapers.d.ts +2 -3
  69. package/dist/boot/stage-08-reapers.js +2 -2
  70. package/dist/boot/stage-09-leader.d.ts +2 -3
  71. package/dist/boot/stage-09-leader.js +2 -1
  72. package/dist/boot/stage-10-http-server.d.ts +2 -3
  73. package/dist/boot/stage-10-http-server.js +2 -2
  74. package/dist/boot/stores.d.ts +1 -0
  75. package/dist/boot/stores.js +4 -3
  76. package/dist/boot/web-admin.d.ts +5 -0
  77. package/dist/boot/web-admin.js +28 -14
  78. package/dist/brain.d.ts +2 -2
  79. package/dist/brain.js +1 -1
  80. package/dist/capabilities/builtin-tools.d.ts +2 -1
  81. package/dist/capabilities/composite-members.d.ts +1 -1
  82. package/dist/capabilities/composite-members.js +1 -1
  83. package/dist/capabilities/hands-lane.d.ts +9 -6
  84. package/dist/capabilities/hands-lane.js +2 -2
  85. package/dist/capabilities/memory-notice.d.ts +27 -22
  86. package/dist/capabilities/memory-notice.js +15 -17
  87. package/dist/capabilities/scenarios.d.ts +9 -14
  88. package/dist/capabilities/scenarios.js +5 -50
  89. package/dist/capability-facts.d.ts +22 -11
  90. package/dist/capability-facts.js +13 -6
  91. package/dist/config-catalog.js +14 -5
  92. package/dist/config-provider.d.ts +5 -1
  93. package/dist/config-provider.js +23 -4
  94. package/dist/config-types.d.ts +19 -2
  95. package/dist/config.js +41 -6
  96. package/dist/deployment-governance.d.ts +19 -21
  97. package/dist/deployment-governance.js +7 -8
  98. package/dist/env-name-allowlist-knobs.d.ts +5 -5
  99. package/dist/env-name-allowlist-knobs.js +1 -0
  100. package/dist/execution-lane-caps.d.ts +12 -0
  101. package/dist/execution-lane-caps.js +18 -4
  102. package/dist/fleet/subagent-tail-bus.js +15 -5
  103. package/dist/hooks/hook-runner.d.ts +84 -30
  104. package/dist/hooks/hook-runner.js +74 -41
  105. package/dist/http/admission.js +17 -10
  106. package/dist/http/durable-run-leg.d.ts +5 -4
  107. package/dist/http/durable-run-leg.js +2 -4
  108. package/dist/http/idempotency.d.ts +28 -6
  109. package/dist/http/idempotency.js +10 -2
  110. package/dist/http/principal-gate.d.ts +14 -0
  111. package/dist/http/principal-gate.js +7 -0
  112. package/dist/http/request-guards.d.ts +2 -1
  113. package/dist/http/request-guards.js +14 -14
  114. package/dist/http/resume-legs.d.ts +2 -2
  115. package/dist/http/resume-legs.js +20 -10
  116. package/dist/http/route-ctx.d.ts +15 -7
  117. package/dist/http/routes/a2a-serve.js +11 -7
  118. package/dist/http/routes/approvals-assistant.js +18 -3
  119. package/dist/http/routes/background.d.ts +1 -1
  120. package/dist/http/routes/background.js +1 -1
  121. package/dist/http/routes/capabilities.js +10 -2
  122. package/dist/http/routes/mcp-reconnect.js +1 -1
  123. package/dist/http/routes/runs.d.ts +4 -3
  124. package/dist/http/routes/runs.js +35 -14
  125. package/dist/http/routes/session-sync.js +14 -11
  126. package/dist/http/routes/sessions.js +9 -9
  127. package/dist/http/routes/side-query.js +6 -19
  128. package/dist/http/routes/tasks.js +29 -19
  129. package/dist/http/routes/workflows.js +8 -0
  130. package/dist/http/server.d.ts +4 -0
  131. package/dist/http/server.js +3 -5
  132. package/dist/http/submit-replay.d.ts +15 -8
  133. package/dist/http/submit-replay.js +6 -0
  134. package/dist/http/wire-types.d.ts +7 -9
  135. package/dist/index.d.ts +1 -1
  136. package/dist/index.js +1 -1
  137. package/dist/internal-run-env.d.ts +30 -0
  138. package/dist/internal-run-env.js +11 -0
  139. package/dist/leader/wire.js +3 -2
  140. package/dist/lsp/manager.js +1 -1
  141. package/dist/memory-scope.d.ts +19 -7
  142. package/dist/memory-scope.js +25 -8
  143. package/dist/observability/fail-open.d.ts +31 -3
  144. package/dist/observability/fail-open.js +31 -3
  145. package/dist/observability/metrics.d.ts +0 -1
  146. package/dist/observability/metrics.js +1 -4
  147. package/dist/observability/run-terminal.js +72 -4
  148. package/dist/permission-rule-vocab.d.ts +3 -2
  149. package/dist/permission-rule-vocab.js +1 -1
  150. package/dist/plan-cache-probe.d.ts +3 -2
  151. package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
  152. package/dist/plugins/caching-session-store.d.ts +42 -22
  153. package/dist/plugins/caching-session-store.js +19 -9
  154. package/dist/plugins/checkpoint-store-sql.d.ts +42 -28
  155. package/dist/plugins/checkpoint-store-sql.js +57 -11
  156. package/dist/plugins/file-run-store.d.ts +25 -21
  157. package/dist/plugins/file-run-store.js +70 -34
  158. package/dist/plugins/k8s-exec-protocol.js +3 -0
  159. package/dist/plugins/local-checkpoint-store.d.ts +8 -5
  160. package/dist/plugins/local-checkpoint-store.js +5 -15
  161. package/dist/plugins/local-session-store.d.ts +66 -7
  162. package/dist/plugins/local-session-store.js +168 -101
  163. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +1 -1
  164. package/dist/plugins/memory-run-store.d.ts +19 -3
  165. package/dist/plugins/memory-run-store.js +38 -3
  166. package/dist/plugins/one-time-migrations.d.ts +165 -39
  167. package/dist/plugins/one-time-migrations.js +51 -144
  168. package/dist/plugins/pg-pool.js +11 -1
  169. package/dist/plugins/pg-session-storage.d.ts +2 -0
  170. package/dist/plugins/pg-session-storage.js +9 -5
  171. package/dist/plugins/remote-env-adb.d.ts +3 -0
  172. package/dist/plugins/remote-env-adb.js +1 -0
  173. package/dist/plugins/remote-env-device.d.ts +3 -0
  174. package/dist/plugins/remote-env-device.js +1 -0
  175. package/dist/plugins/remote-env-e2b.d.ts +4 -0
  176. package/dist/plugins/remote-env-e2b.js +2 -1
  177. package/dist/plugins/remote-env-host.d.ts +23 -1
  178. package/dist/plugins/remote-env-host.js +20 -2
  179. package/dist/plugins/remote-env-k8s.d.ts +264 -41
  180. package/dist/plugins/remote-env-k8s.js +551 -82
  181. package/dist/plugins/remote-env-local-docker.d.ts +4 -0
  182. package/dist/plugins/remote-env-local-docker.js +2 -1
  183. package/dist/plugins/remote-env-ssh.d.ts +3 -0
  184. package/dist/plugins/remote-env-ssh.js +1 -0
  185. package/dist/plugins/retention-store-sql.d.ts +4 -1
  186. package/dist/plugins/retention-store-sql.js +11 -9
  187. package/dist/plugins/run-store-sql.d.ts +44 -6
  188. package/dist/plugins/run-store-sql.js +92 -27
  189. package/dist/plugins/session-capture-record-store-sql.d.ts +2 -3
  190. package/dist/plugins/session-store.d.ts +4 -3
  191. package/dist/plugins/session-store.js +1 -1
  192. package/dist/plugins/sql-driver.d.ts +2 -1
  193. package/dist/plugins/store-backend.d.ts +12 -5
  194. package/dist/plugins/store-backend.js +13 -4
  195. package/dist/plugins/store-contracts.d.ts +20 -3
  196. package/dist/plugins/store-open-wait.js +3 -0
  197. package/dist/plugins/tidb-pool.js +15 -3
  198. package/dist/plugins/tidb-session-storage.js +3 -2
  199. package/dist/plugins/tidb-session-store.d.ts +2 -0
  200. package/dist/plugins/tidb-session-store.js +6 -2
  201. package/dist/request-key-closure.d.ts +32 -7
  202. package/dist/request-key-closure.js +25 -9
  203. package/dist/router/route-orchestration.d.ts +3 -11
  204. package/dist/router/route-orchestration.js +0 -4
  205. package/dist/rule-entry-list.js +0 -4
  206. package/dist/rules-consent.js +3 -0
  207. package/dist/run-acceptance.d.ts +51 -0
  208. package/dist/run-acceptance.js +27 -0
  209. package/dist/run-local.d.ts +5 -4
  210. package/dist/run-local.js +23 -17
  211. package/dist/runs.d.ts +7 -11
  212. package/dist/runs.js +6 -16
  213. package/dist/sandbox-egress-policy.d.ts +61 -0
  214. package/dist/sandbox-egress-policy.js +235 -0
  215. package/dist/security.d.ts +7 -0
  216. package/dist/security.js +5 -0
  217. package/dist/server-secret-env.d.ts +10 -4
  218. package/dist/server-secret-env.js +4 -1
  219. package/dist/session-error-wire.d.ts +2 -2
  220. package/dist/session-incarnation.d.ts +46 -2
  221. package/dist/session-incarnation.js +14 -3
  222. package/dist/session-sync-kernel.d.ts +10 -3
  223. package/dist/session-titler.d.ts +5 -3
  224. package/dist/spec-fields.d.ts +24 -8
  225. package/dist/spec-fields.js +21 -2
  226. package/dist/task-workflow.d.ts +6 -4
  227. package/dist/task-workflow.js +3 -2
  228. package/dist/tool-approval.d.ts +78 -6
  229. package/dist/tool-approval.js +7 -3
  230. package/dist/trace/core-keyset-guard.d.ts +6 -5
  231. package/dist/trace/engine-notice-wire.d.ts +26 -1
  232. package/dist/trace/engine-notice-wire.js +7 -2
  233. package/dist/trace/ledger-events.d.ts +9 -3
  234. package/dist/trace/ledger-sink.d.ts +7 -0
  235. package/dist/trace/ledger-sink.js +14 -4
  236. package/dist/trace/project.d.ts +57 -11
  237. package/dist/trace/project.js +54 -8
  238. package/dist/trace/self-minted-wire.d.ts +94 -2
  239. package/dist/trace/self-minted-wire.js +28 -0
  240. package/dist/trace/tool-output-media.d.ts +26 -0
  241. package/dist/trace/tool-output-media.js +57 -0
  242. package/dist/trace/wire-projection-faces.d.ts +7 -1
  243. package/dist/trace/wire-projection-faces.js +2 -1
  244. package/dist/web-admin-client/apply-effective.d.ts +13 -7
  245. package/dist/web-admin-client/apply-effective.js +11 -26
  246. package/dist/web-admin-client/apply-ledger.d.ts +2 -2
  247. package/dist/web-admin-client/candidate-gate.d.ts +39 -4
  248. package/dist/web-admin-client/candidate-gate.js +9 -2
  249. package/dist/web-admin-client/facade.d.ts +2 -2
  250. package/dist/web-admin-client/http-client.d.ts +3 -1
  251. package/dist/web-admin-client/http-client.js +4 -3
  252. package/dist/web-admin-client/read-warnings.d.ts +33 -5
  253. package/dist/web-admin-client/read-warnings.js +41 -6
  254. package/dist/web-admin-client/types.d.ts +11 -5
  255. package/dist/workspace-cache.d.ts +45 -0
  256. package/dist/workspace-cache.js +30 -0
  257. package/dist/workspace-space-commit.d.ts +116 -0
  258. package/dist/workspace-space-commit.js +117 -0
  259. package/dist/workspace-space.d.ts +75 -9
  260. package/dist/workspace-space.js +52 -1
  261. package/package.json +4 -4
  262. package/dist/boot/session-incarnation-seat.d.ts +0 -41
  263. package/dist/boot/session-incarnation-seat.js +0 -69
  264. package/dist/capabilities/code-review-council.d.ts +0 -49
  265. package/dist/capabilities/code-review-council.js +0 -111
  266. package/dist/capabilities/collab-wire.d.ts +0 -36
  267. package/dist/capabilities/collab-wire.js +0 -2
  268. package/dist/capabilities/collab-workflows.d.ts +0 -47
  269. package/dist/capabilities/collab-workflows.js +0 -90
  270. package/dist/capabilities/prompts/code-review.d.ts +0 -25
  271. package/dist/capabilities/prompts/code-review.js +0 -39
  272. package/dist/capabilities/prompts/team.d.ts +0 -10
  273. package/dist/capabilities/prompts/team.js +0 -6
  274. package/dist/capabilities/team.d.ts +0 -113
  275. package/dist/capabilities/team.js +0 -70
@@ -10,8 +10,9 @@ import { adbExecutionEnvFactory } from "../plugins/remote-env-adb.js";
10
10
  import { deviceExecutionEnvFactory } from "../plugins/remote-env-device.js";
11
11
  import { e2bExecutionEnvFactory } from "../plugins/remote-env-e2b.js";
12
12
  import { hostExecutionEnvFactory, RemoteHostExecutionEnv } from "../plugins/remote-env-host.js";
13
- import { k8sExecutionEnvFactory } from "../plugins/remote-env-k8s.js";
13
+ import { checkSandboxEgressPolicy, createSpaceReclaimer, K8S_SANDBOX_NAMESPACE_DEFAULT, k8sExecutionEnvFactory } from "../plugins/remote-env-k8s.js";
14
14
  import { createRunWorkspaceSnapshotSeat } from "../fleet/workspace-snapshot-residual.js";
15
+ import { createSpaceCommitFence } from "../workspace-space-commit.js";
15
16
  import { localDockerExecutionEnvFactory } from "../plugins/remote-env-local-docker.js";
16
17
  import { sshExecutionEnvFactory } from "../plugins/remote-env-ssh.js";
17
18
  import { isRemoteScratchpadLane, withRemoteScratchpad } from "../plugins/remote-scratchpad.js";
@@ -22,8 +23,10 @@ import { reapOrphanWorktrees, withWorktreeIsolation } from "../plugins/worktree-
22
23
  import { customPkgSourceFromEnv, derivePkgSourceEnv } from "../sandbox-pkg-source.js";
23
24
  import { effectiveHostWorkspace } from "../task-cwd.js";
24
25
  import { taskInheritEnvRefusal } from "../hosted-posture.js";
26
+ import { workspaceSnapshotTimeoutOf } from "../workspace-space.js";
27
+ import { sayEgressPolicyReading } from "../sandbox-egress-policy.js";
25
28
  import { isSandboxPathAdjudicationLane, sandboxPathEnvSlots, withSandboxPathEnvSlot } from "./deferred-sandbox-path-env.js";
26
- import { REMOTE_EXEC_PROVIDER_WORDS, executionLaneHomeDir, executionLaneOf, isSingleMachineDefaultLane, laneIsolated } from "../execution-lane-caps.js";
29
+ import { REMOTE_EXEC_PROVIDER_WORDS, executionLaneHomeDir, executionLaneOf, isSingleMachineDefaultLane, laneBindsReads, laneIsolated } from "../execution-lane-caps.js";
27
30
  function boundedSessionSetter(map, maxEntries) {
28
31
  return (sid, value) => {
29
32
  map.delete(sid);
@@ -35,10 +38,10 @@ function boundedSessionSetter(map, maxEntries) {
35
38
  function forwardedSandboxEnvKeys(remoteExec) {
36
39
  switch (remoteExec.provider) {
37
40
  case "e2b":
41
+ case "k8s":
38
42
  return Object.keys(remoteExec.sandboxEnv ?? {}).sort();
39
43
  case "local-docker":
40
44
  return Object.keys(remoteExec.env ?? {}).sort();
41
- case "k8s":
42
45
  case "ssh":
43
46
  case "adb":
44
47
  case "host":
@@ -50,18 +53,20 @@ function forwardedSandboxEnvKeys(remoteExec) {
50
53
  }
51
54
  }
52
55
  }
56
+ function buildSandboxLaneEnv(config, explicit) {
57
+ const merged = { ...derivePkgSourceEnv(config.sandboxPkgSource, customPkgSourceFromEnv()), ...(explicit ?? {}) };
58
+ return Object.keys(merged).length > 0 ? merged : undefined;
59
+ }
53
60
  const MAX_CWD_SESSIONS = 4096;
54
61
  export function createSessionScopedRegistries(maxEntries = MAX_CWD_SESSIONS) {
55
62
  const perSessionCwd = new Map();
56
63
  const perSessionShellEnv = new Map();
57
64
  const perSessionInheritEnv = new Map();
58
- const perSessionIncarnation = new Map();
59
65
  const owners = new Map();
60
66
  const dropSession = (sid) => {
61
67
  perSessionCwd.delete(sid);
62
68
  perSessionShellEnv.delete(sid);
63
69
  perSessionInheritEnv.delete(sid);
64
- perSessionIncarnation.delete(sid);
65
70
  owners.delete(sid);
66
71
  };
67
72
  const touch = (sid, owner) => {
@@ -96,40 +101,71 @@ export function createSessionScopedRegistries(maxEntries = MAX_CWD_SESSIONS) {
96
101
  perSessionCwd.delete(sid);
97
102
  perSessionShellEnv.delete(sid);
98
103
  perSessionInheritEnv.delete(sid);
99
- perSessionIncarnation.delete(sid);
100
104
  }
101
105
  touch(sid, owner);
102
106
  },
103
107
  dropSession,
104
- noteSessionIncarnation: (sid, incarnation) => {
105
- if (incarnation === undefined) {
106
- perSessionIncarnation.delete(sid);
107
- return;
108
- }
109
- perSessionIncarnation.set(sid, incarnation);
110
- touch(sid, undefined);
111
- },
112
- sessionIncarnationOf: (sid) => perSessionIncarnation.get(sid),
113
108
  };
114
109
  }
115
110
  export function createK8sRunEnvFactory(k8sCfg, seats, deps) {
116
- return (ctx) => {
117
- const incarnation = seats.incarnationOf(ctx.sessionId);
111
+ return async (ctx) => {
112
+ const onWorkspaceSnapshot = createRunWorkspaceSnapshotSeat(ctx.sessionId);
113
+ const child = ctx.placementRootSessionId !== ctx.sessionId;
114
+ const s3Snapshot = child && k8sCfg.s3Snapshot !== undefined ? spaceOff(k8sCfg.s3Snapshot) : k8sCfg.s3Snapshot;
115
+ const spaceOccupant = child ? undefined : await occupantOf(seats, ctx.sessionId, ctx.taskId);
116
+ const { cache, ...deploymentCfg } = k8sCfg;
118
117
  return k8sExecutionEnvFactory({
119
- ...k8sCfg,
118
+ ...deploymentCfg,
119
+ ...(cache !== undefined && !child ? { cache } : {}),
120
+ ...(s3Snapshot !== undefined ? { s3Snapshot } : {}),
120
121
  image: seats.imageOf(ctx.sessionId) ?? k8sCfg.image,
121
- ...(incarnation !== undefined ? { spaceIncarnation: incarnation } : {}),
122
- onWorkspaceSnapshot: createRunWorkspaceSnapshotSeat(ctx.sessionId),
122
+ ...(spaceOccupant !== undefined ? { spaceOccupant } : {}),
123
+ onWorkspaceSnapshot,
123
124
  }, deps)(ctx);
124
125
  };
125
126
  }
126
- export function assertWorkspaceSpaceReadable(space, sessionFaceRead, sessionStoreLabel) {
127
- if (!space.available || !persistNeedsOccupant(space.policy.persist) || sessionFaceRead !== undefined)
127
+ const STORE_ERROR_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
128
+ async function occupantOf(seats, sessionId, taskId) {
129
+ let answer;
130
+ try {
131
+ answer = await seats.incarnationOf?.(sessionId);
132
+ }
133
+ catch (e) {
134
+ const code = e?.code;
135
+ return { fault: typeof code === "string" && STORE_ERROR_CODE.test(code) ? code : "incarnation_read_failed" };
136
+ }
137
+ if (answer === undefined)
138
+ return { unread: "incarnation_unknown" };
139
+ if (typeof answer !== "string" || answer === "")
140
+ return { fault: "incarnation_read_failed" };
141
+ const rows = seats.spaceCommits();
142
+ return rows !== undefined ? { incarnation: answer, fence: createSpaceCommitFence(rows, answer, taskId) } : { unread: "incarnation_unknown" };
143
+ }
144
+ function spaceOff(store) {
145
+ const { space: _off, ...parkOnly } = store;
146
+ return parkOnly;
147
+ }
148
+ export function assertWorkspaceSpaceReadable(space, seats, cache, sessionStoreLabel) {
149
+ if (space.available && persistNeedsOccupant(space.policy.persist)) {
150
+ const missing = seats.incarnationOf === undefined ? `the session store (${sessionStoreLabel}) has no by-id occupant read (incarnationOf)`
151
+ : seats.spaceCommits === undefined ? `this deployment has no store backend to hold the space's commit rows (the session store is ${sessionStoreLabel})`
152
+ : undefined;
153
+ if (missing === undefined)
154
+ return;
155
+ throw new Error(`WORKSPACE_PERSIST=space but ${missing} [workspace-space-unreadable]: ` +
156
+ "the k8s workspace space is partitioned by the session occupant and committed under a run-store row, so here no run would restore or save " +
157
+ '/workspace while GET /v1/capabilities.workspaceSync reports persist "space". Use a store backend (DB_BACKEND=local or DB_BACKEND=mysql|pg; ' +
158
+ "DB_BACKEND=memory has none), or set WORKSPACE_PERSIST=off (the default is space), and restart");
128
159
  return;
129
- throw new Error(`WORKSPACE_PERSIST=space but the session store is ${sessionStoreLabel}, which has no session occupant read (sessionFaceOf) [workspace-space-unreadable]: ` +
130
- "the k8s workspace space is partitioned by the session occupant, so on this store no run would restore or save /workspace while " +
131
- 'GET /v1/capabilities.workspaceSync reports persist "space". Use a session store with that read (DB_BACKEND=local, or DB_BACKEND=mysql|pg ' +
132
- "with SESSION_BACKEND not memory), or drop WORKSPACE_PERSIST=space (the default is off), and restart");
160
+ }
161
+ if (cache.available && (seats.incarnationOf === undefined || seats.spaceCommits === undefined)) {
162
+ const missing = seats.incarnationOf === undefined
163
+ ? `the session store (${sessionStoreLabel}) has no by-id occupant read (incarnationOf)`
164
+ : `this deployment has no store backend to hold the space durably (the session store is ${sessionStoreLabel})`;
165
+ throw new Error(`WORKSPACE_CACHE=volume but ${missing} [workspace-space-unreadable]: ` +
166
+ "the k8s build-cache volume belongs to the workspace space, which is keyed by the session occupant, so here no run would get its volume while " +
167
+ "GET /v1/capabilities.workspaceSync reports cache. Use a store backend (DB_BACKEND=local or DB_BACKEND=mysql|pg; DB_BACKEND=memory has none), or set WORKSPACE_CACHE=off, and restart");
168
+ }
133
169
  }
134
170
  function persistNeedsOccupant(persist) {
135
171
  switch (persist) {
@@ -158,6 +194,7 @@ export function createExecutionEnv(ctx) {
158
194
  const { perSessionShellEnv, setSessionShellEnv } = sessionScoped;
159
195
  const { perSessionInheritEnv, setSessionInheritEnv } = sessionScoped;
160
196
  let executionEnvFactory;
197
+ let spaceReclaimer;
161
198
  let worktreeReap;
162
199
  if (config.remoteExec?.provider === "e2b") {
163
200
  executionEnvFactory = e2bExecutionEnvFactory({
@@ -168,10 +205,7 @@ export function createExecutionEnv(ctx) {
168
205
  ...(config.remoteExec.livenessMs != null ? { livenessMs: config.remoteExec.livenessMs } : {}),
169
206
  ...(config.remoteExec.allowInternetAccess != null ? { allowInternetAccess: config.remoteExec.allowInternetAccess } : {}),
170
207
  ...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
171
- ...(() => {
172
- const merged = { ...derivePkgSourceEnv(config.sandboxPkgSource, customPkgSourceFromEnv()), ...(config.remoteExec.sandboxEnv ?? {}) };
173
- return Object.keys(merged).length > 0 ? { sandboxEnv: merged } : {};
174
- })(),
208
+ ...((env) => (env !== undefined ? { sandboxEnv: env } : {}))(buildSandboxLaneEnv(config, config.remoteExec.sandboxEnv)),
175
209
  logger,
176
210
  metrics,
177
211
  });
@@ -188,16 +222,22 @@ export function createExecutionEnv(ctx) {
188
222
  ...(config.remoteExec.runtimeClass != null ? { runtimeClass: config.remoteExec.runtimeClass } : {}),
189
223
  ...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
190
224
  ...(config.remoteExec.timeoutMs != null ? { timeoutMs: config.remoteExec.timeoutMs } : {}),
225
+ dataTimeoutMs: workspaceSnapshotTimeoutOf(config.remoteExec),
191
226
  ...(config.remoteExec.memory ? { memory: config.remoteExec.memory } : {}),
192
227
  ...(config.remoteExec.cpu ? { cpu: config.remoteExec.cpu } : {}),
193
- ...(config.remoteExec.s3Snapshot ? { s3Snapshot: { ...config.remoteExec.s3Snapshot, ...((f) => (f.available ? { space: f.policy } : {}))(facts.workspaceSpace(config)) } } : {}),
228
+ ...(config.remoteExec.sandboxIpv6 !== undefined ? { ipv6: config.remoteExec.sandboxIpv6 } : {}),
229
+ ...(config.remoteExec.s3Snapshot ? { s3Snapshot: { ...config.remoteExec.s3Snapshot, ...((f) => (f.available ? { space: { persist: f.policy.persist, keep: f.policy.keep } } : {}))(facts.workspaceSpace(config)) } } : {}),
230
+ ...((f) => (f.available ? { cache: f.cache } : {}))(facts.workspaceCache(config)),
231
+ ...(config.remoteExec.workspaceSnapshotExclude ? { snapshotExclude: config.remoteExec.workspaceSnapshotExclude } : {}),
194
232
  logger,
195
- ...(() => {
196
- const derived = derivePkgSourceEnv(config.sandboxPkgSource, customPkgSourceFromEnv());
197
- return Object.keys(derived).length > 0 ? { podEnv: derived } : {};
198
- })(),
233
+ ...((env) => (env !== undefined ? { podEnv: env } : {}))(buildSandboxLaneEnv(config, config.remoteExec.sandboxEnv)),
199
234
  };
200
- executionEnvFactory = createK8sRunEnvFactory(k8sCfg, { imageOf: (sid) => perTaskImage.get(sid), incarnationOf: sessionScoped.sessionIncarnationOf });
235
+ executionEnvFactory = createK8sRunEnvFactory(k8sCfg, { imageOf: (sid) => perTaskImage.get(sid), incarnationOf: ctx.incarnationOf, spaceCommits: ctx.spaceCommits ?? (() => undefined) });
236
+ if (k8sCfg.cache !== undefined || k8sCfg.s3Snapshot !== undefined)
237
+ spaceReclaimer = createSpaceReclaimer(k8sCfg);
238
+ void checkSandboxEgressPolicy(k8sCfg)
239
+ .then((gaps) => sayEgressPolicyReading(gaps, logger, k8sCfg.namespace ?? K8S_SANDBOX_NAMESPACE_DEFAULT))
240
+ .catch((e) => logger.error("sandbox_egress_policy_check_crashed", { error: e instanceof Error ? e.message : String(e), effect: "the sandbox egress self-check did not complete this boot — the lane runs; the egress policy was not read" }));
201
241
  }
202
242
  else if (config.remoteExec?.provider === "ssh") {
203
243
  executionEnvFactory = sshExecutionEnvFactory({
@@ -367,7 +407,15 @@ export function createExecutionEnv(ctx) {
367
407
  logger.info("task_inherit_env_honored", { honored: taskInheritEnvRefusal(config) === undefined });
368
408
  }
369
409
  const lspProvider = config.remoteExec?.provider;
370
- const lspManager = (lspProvider === "e2b" || lspProvider === "k8s") && config.lspEnabled
410
+ const lspLane = executionLaneOf(lspProvider);
411
+ const lspLaneBindsReads = lspLane !== undefined && laneBindsReads(lspLane);
412
+ if ((lspProvider === "e2b" || lspProvider === "k8s") && config.lspEnabled && !lspLaneBindsReads) {
413
+ logger.warn("lsp_not_mounted", {
414
+ provider: lspProvider,
415
+ reason: "LSP_ENABLED is set, but this lane's execution environment cannot bind a read to the file that was checked (openBound), so every language-server file sync would be refused; the LSP tool is not mounted on this lane in this version",
416
+ });
417
+ }
418
+ const lspManager = (lspProvider === "e2b" || lspProvider === "k8s") && config.lspEnabled && lspLaneBindsReads
371
419
  ? createE2bLspManager({
372
420
  log: (event, fields) => logger.info(event, fields),
373
421
  scheme: lspProvider === "k8s" ? "ws" : "wss",
@@ -375,7 +423,7 @@ export function createExecutionEnv(ctx) {
375
423
  metrics,
376
424
  })
377
425
  :
378
- lspProvider === "host" && config.lspHostEnabled && config.requirePrincipal !== true
426
+ lspProvider === "host" && config.lspHostEnabled && config.requirePrincipal !== true && lspLaneBindsReads
379
427
  ? createHostLspManager(config, (event, fields) => logger.info(event, fields))
380
428
  : undefined;
381
429
  if (lspManager)
@@ -384,9 +432,7 @@ export function createExecutionEnv(ctx) {
384
432
  perTaskImage, sessionEnvSelection, perSessionCwd, setSessionCwd, setSessionShellEnv, setSessionInheritEnv,
385
433
  fenceSessionOwner: sessionScoped.fenceSessionOwner,
386
434
  dropSessionScoped: sessionScoped.dropSession,
387
- noteSessionIncarnation: sessionScoped.noteSessionIncarnation,
388
- sessionIncarnationOf: sessionScoped.sessionIncarnationOf,
389
- executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager,
435
+ executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager, spaceReclaimer,
390
436
  };
391
437
  }
392
438
  //# sourceMappingURL=execution-env.js.map
@@ -12,6 +12,7 @@ import type { buildPricing } from "../budget.js";
12
12
  import { createLeaderEndpoint } from "../leader/endpoint.js";
13
13
  import type { Logger } from "../observability/logger.js";
14
14
  import type { CheckpointStoreFull, StoreBackend, ToolResultStoreFull } from "../plugins/store-backend.js";
15
+ import type { createSessionStore } from "../plugins/session-store.js";
15
16
  import type { RunnerDeps } from "@sema-agent/core";
16
17
  export interface LeaderCtx {
17
18
  config: ServiceConfig;
@@ -20,7 +21,7 @@ export interface LeaderCtx {
20
21
  pricing: ReturnType<typeof buildPricing>;
21
22
  executionEnvFactory: RunnerDeps["executionEnvFactory"];
22
23
  toolResultStore: ToolResultStoreFull | undefined;
23
- sessionStore: ReturnType<StoreBackend["session"]>;
24
+ sessionStore: ReturnType<typeof createSessionStore>;
24
25
  checkpointStore: CheckpointStoreFull | undefined;
25
26
  /** [ref] 件B/C/D([ref],codex R2-F1):部署治理三座席 —— leader 车道的每一只 Runner 都要带上它,
26
27
  * 否则开了 leader 端点的部署就有一条在部署治理**之外**的执行面(合规否决/锁都够不着)。 */
@@ -75,7 +75,7 @@ import type { MemoryEngineBackend } from "@sema-agent/settings-schema/execution-
75
75
  * 而且它断言的是 per-task 事实,不是本键的车道级语义。
76
76
  *
77
77
  * ## 位置与纪律
78
- * 单源:resolve-spec 的 spec 直通、`shouldDiscloseNoPersistentMemory` 判别式、boot 审计的 declared 位
78
+ * 单源:resolve-spec 的 spec 直通、`noPersistentMemoryNotice` 判别式、boot 审计的 declared 位
79
79
  * 三处都必须读本函数,禁各自重算(operator-knob 律:显式 env 的优先权在这一个函数里执法一次)。
80
80
  * 自动补位在 boot 日志上必须可见(stores.ts 的 info 行),部署方随时可用显式 env 覆盖。
81
81
  */
@@ -1,6 +1,11 @@
1
1
  import type { RestartSliceCtx } from "../web-admin-client/restart-signal.js";
2
2
  import type { MemoryConsolidationDriverConfig, ServiceConfig } from "../config-types.js";
3
- import { type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type MemoryBackend, type MemoryConsolidationDriverDeps, type RunMemoryConsolidationOptions, type SessionCaptureRecordStore } from "@sema-agent/core";
3
+ import { resolveMemoryConsolidationDriver, type ConsolidationWriteJudge, type EngineNotice, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type MemoryBackend, type MemoryConsolidationDriverDeps, type SessionCaptureRecordStore } from "@sema-agent/core";
4
+ /**
5
+ * 座解析的 options 形 = core 解析器交回的那只(core 7.50.0 起它**不含** `writeJudge`:判官不是模型席的一部分,由调用方在动词上带)。
6
+ * 取解析器的返回型而不是自己写 `Omit<…>`:形的属主是 core 的解析器,本仓不持第二份。
7
+ */
8
+ type ConsolidationSeatOptions = ReturnType<typeof resolveMemoryConsolidationDriver>;
4
9
  /** D3 投影的座标签闭集。`role:<name>` 里的 name 只可能是 core 的 role 链两跳之一。 */
5
10
  export type ConsolidationSeatLabel = "explicit" | "role:consolidate" | "role:summarize";
6
11
  /** {@link buildConsolidationValveAudit} 的告警名闭集(事件名进日志 ⇒ 运维可按名过滤/告警)。 */
@@ -48,8 +53,8 @@ export type ConsolidationSeatBilling = {
48
53
  };
49
54
  /** 座解析的产物:core 的 options 原样 + 给投影用的两位自证。 */
50
55
  export interface ConsolidationDriverSeat {
51
- /** `runMemoryConsolidationDriver` 的第三参,core 的 `resolveMemoryConsolidationDriver` 原样产出。 */
52
- readonly options: RunMemoryConsolidationOptions;
56
+ /** `runMemoryConsolidationDriver` 第三参的**模型席那一半**,core 的 `resolveMemoryConsolidationDriver` 原样产出(写判官另由操作面的座给)。 */
57
+ readonly options: ConsolidationSeatOptions;
53
58
  /** D3 的 `seat` 位。 */
54
59
  readonly seat: ConsolidationSeatLabel;
55
60
  /** 真正会被记进 run 行与 mint 归档的模型 id(= `options.model`,单独拎出来是投影面的便利)。 */
@@ -390,6 +395,27 @@ export declare function assertAutoConsolidationWirable(input: {
390
395
  /** 铸好的 `RunnerDeps` 上**真的**有整理席吗(`deps.memoryConsolidation !== undefined`)。 */
391
396
  memoryConsolidationWired: boolean;
392
397
  }): void;
398
+ /**
399
+ * 运维阀门腿的写判官座(core 7.50.0 起驱动动词必带)。
400
+ *
401
+ * ## 判官只有一只,这条腿拿不到它
402
+ *
403
+ * 「这条路径能不能写」在引擎里只有**一只**判官(合成写判官:技能拒行 / 收窄折叠 / 调用方与继承策略 / 人的持久规则车道 /
404
+ * 组织车道,一条走法一个优先序);引擎的自动整理腿把**腿自己的**那只交给驱动。本腿(运维手动阀门)没有腿:没有名册上的
405
+ * `Write` 脸、没有引擎盖的豁免根与工作目录、没有持久规则车道 —— 而引擎包今天不导出那只判官的构造器。在本仓手搭一只
406
+ * 「对部署策略问一次合成 `Write`」的判官 = 把引擎判官的层走法、脸、豁免根、已中止信号的约定与判词读法**再写一份**
407
+ * (第二个读者,与引擎那只迟早分歧,而且分歧是静默的)。所以本腿不造第二只。
408
+ *
409
+ * ## 于是它是一只**响亮的放行座**,登记为保护型欠账
410
+ *
411
+ * 答 `no_objection` —— 与 v7.49.x 本腿的行为逐字同(那时驱动根本不问),不回退任何现网能力;每被问一次记一次
412
+ * `server.memory-consolidation.operator-valve-unjudged`(P-DEBT:计数 + 探针行 + 一次性告警),债在遥测里显形。
413
+ * 自动整理腿不受影响:它走引擎腿自己的判官,人的持久规则与部署策略照判。
414
+ * 退役条件:引擎导出宿主可用的写判官构造器(收部署策略 + 一只规则店主体)那一版,本函数换成它、本 tag 删。
415
+ * scope 与人:本仓的文件后端不按请求主体铸 scope(单用户形是部署声明的全局层 `MEMORY_SCOPE` 与按任务根派生的项目层),
416
+ * 所以从 scope 读不出「这是谁的库」;匿名 run 读不读本地属主那只规则桶另候裁定 —— 两件都不在本座里猜。
417
+ */
418
+ export declare function createOperatorValveWriteJudge(): ConsolidationWriteJudge;
393
419
  /** 两个 admin 口消费的窄能力面(`ServiceDeps.memoryConsolidation` 的实参来源)。 */
394
420
  export interface MemoryConsolidationFaces {
395
421
  /** D3 的座位自证(投影用;boot 期解析一次,restart-to-apply)。 */
@@ -446,5 +472,13 @@ export declare function createMemoryConsolidationFaces(store: {
446
472
  * 机器钉 capture-optout-lane ②)。S-215 起 local 车道在引擎接线时也供(core 文件三腿,同一只控制面);
447
473
  * 缺席 ⇒ 记忆面暗(引擎未接线),与 Runner 同本。 */
448
474
  captureRecordStore?: SessionCaptureRecordStore;
475
+ /** core 7.50.0:整理跑的**写判官座**(必填 —— 缺席不是「没有规则」,core 也拒)。操作面不判任何东西,只把它原样递给驱动动词:
476
+ * 早问库目录一次、应用时问每个产物文件,答 `no_objection` 以外一律拒写。装配层给哪一只见 {@link createOperatorValveWriteJudge}。 */
477
+ writeJudge: ConsolidationWriteJudge;
478
+ /** 引擎通告的**运维行**座(与 Runner 的 `onNotice` 同一只转发器)。缺席 ⇒ 通告只在回执上。判官拒的两种时机都经它走一次:
479
+ * 应用时拒 = 引擎在驱动里铸的 `memory.consolidation_incomplete`;早问拒 = 驱动抛出的拒绝经引擎导出的构造器转成的
480
+ * `memory.consolidation_refused`(本仓不读通告名、不自铸通告形)。 */
481
+ onNotice?: (notice: EngineNotice) => void;
449
482
  }): MemoryConsolidationFaces;
483
+ export {};
450
484
  //# sourceMappingURL=memory-consolidation.d.ts.map
@@ -1,8 +1,9 @@
1
1
  import { redactSecrets } from "../trace/redact.js";
2
+ import { recordFailOpen } from "../observability/fail-open.js";
2
3
  import { memoryMountRootOf } from "../memory-scope.js";
3
4
  import { DEFAULT_MODEL_REF, resolveMainModel } from "../model-select.js";
4
5
  import { backendOwnsControlPlane } from "../memory-operator-faces.js";
5
- import { expandTiers, MemoryEngine, readConsolidationDriverRun, resolveMemoryConsolidationDriver, runMemoryConsolidationDriver, } from "@sema-agent/core";
6
+ import { CONSOLIDATION_WRITE_REFUSED_CODE, ConsolidationRefusedError, expandTiers, MemoryEngine, memoryConsolidationRefusedNotice, readConsolidationDriverRun, resolveMemoryConsolidationDriver, runMemoryConsolidationDriver, } from "@sema-agent/core";
6
7
  export function resolveConsolidationDriverSeat(deps) {
7
8
  let options;
8
9
  try {
@@ -316,6 +317,12 @@ export function assertAutoConsolidationWirable(input) {
316
317
  `unset, or set MEMORY_AUTO_CONSOLIDATION=off (unsetting it is NOT the same: the engine's named default is ON as of ` +
317
318
  `core 7.21.1).`);
318
319
  }
320
+ export function createOperatorValveWriteJudge() {
321
+ return () => {
322
+ recordFailOpen("server.memory-consolidation.operator-valve-unjudged");
323
+ return { verdict: "no_objection" };
324
+ };
325
+ }
319
326
  export function createMemoryConsolidationFaces(store, input) {
320
327
  const engine = new MemoryEngine({
321
328
  backend: store.backend,
@@ -331,7 +338,16 @@ export function createMemoryConsolidationFaces(store, input) {
331
338
  model: input.seat.model,
332
339
  scopes: input.scopes,
333
340
  run: (scope) => flight(scope, async () => {
334
- const receipt = await runMemoryConsolidationDriver(engine, scope, input.seat.options);
341
+ const receipt = await runMemoryConsolidationDriver(engine, scope, {
342
+ ...input.seat.options,
343
+ writeJudge: input.writeJudge,
344
+ ...(input.onNotice !== undefined ? { onNotice: input.onNotice } : {}),
345
+ }).catch((err) => {
346
+ if (input.onNotice !== undefined && err instanceof ConsolidationRefusedError && err.code === CONSOLIDATION_WRITE_REFUSED_CODE) {
347
+ input.onNotice(memoryConsolidationRefusedNotice({ code: err.code, scope, reason: err.message, ...(err.occurrenceId !== undefined ? { occurrenceId: err.occurrenceId } : {}) }));
348
+ }
349
+ throw err;
350
+ });
335
351
  if (receipt.stopDetail !== undefined) {
336
352
  input.onStopDetail?.(buildStopDetailAudit({ scope, runId: receipt.runId, outcome: receipt.outcome, stopDetail: receipt.stopDetail }));
337
353
  }
@@ -72,9 +72,6 @@ export interface ParkedReviveGateDeps {
72
72
  };
73
73
  /** host 腿 cwd 占位的落地根(main.ts 的 `localRoot`;`config.localDataRoot` 优先)。 */
74
74
  readonly localRoot: string;
75
- /** S-133:守卫集 `dataRoot` = boot 已铸的引擎记忆根(`memoryEngine.root`,boot/stores.ts 单一写者),不在本腿重推导
76
- * (重推导 = 第二个写者,7.59.0 重扫 codex 轮抓到 HTTP 腿 fallback 与 stores 不同源正是这一形)。`undefined` = 引擎未接。 */
77
- readonly memoryEngineRoot: string | undefined;
78
75
  /** 沙箱 lane 的真 env 登记簿。缺省 = 进程内唯一那只(工厂装饰器写的同一个);测试注入自建实例。 */
79
76
  readonly slots?: SandboxPathEnvSlots;
80
77
  }
@@ -11,7 +11,7 @@ function hostGateCwd(config, localRoot) {
11
11
  return join(config.localDataRoot ?? localRoot, "parked-revive-unrooted");
12
12
  }
13
13
  export function createParkedReviveInheritedGate(deps) {
14
- const { config, question, approvalExemptionStore, logger, localRoot, approverSeat, memoryEngineRoot } = deps;
14
+ const { config, question, approvalExemptionStore, logger, localRoot, approverSeat } = deps;
15
15
  const slots = deps.slots ?? sandboxPathEnvSlots;
16
16
  return async (row, identity) => {
17
17
  const metadata = await chainMetadataOf(deps, row, identity);
@@ -33,7 +33,7 @@ export function createParkedReviveInheritedGate(deps) {
33
33
  question,
34
34
  ...(approvalExemptionStore !== undefined && rootSessionId ? { exemption: createDeploymentListExemption(approvalExemptionStore, rootSessionId, logger, "parked_revive") } : {}),
35
35
  });
36
- const governed = applyRuntimeGovernance({ objective: "", toolPolicy: baseline }, createDeploymentGovernanceInputs(config, pathAdjudication, { engineDataRoot: memoryEngineRoot }));
36
+ const governed = applyRuntimeGovernance({ objective: "", toolPolicy: baseline }, createDeploymentGovernanceInputs(config, pathAdjudication));
37
37
  return {
38
38
  parentConstraints: [
39
39
  {
@@ -39,8 +39,6 @@ export interface ResolveSpecCtx {
39
39
  /** 两张 per-session 登记簿的**租户围栏**(codex R1-F1):每次提交对拍本会话的主人,换主即清。
40
40
  * 论证(为什么 device lane 把这条从「不需要」变成「必需」)逐字见 `createSessionScopedRegistries` 头注。 */
41
41
  fenceSessionOwner: (sid: string, owner: string | null) => void;
42
- /** S-506([ref] §5):装配期化身读数的写腿(per-session 登记簿,与围栏同一只;记忆座同步从那里读)。 */
43
- noteSessionIncarnation: (sid: string, incarnation: string | undefined) => void;
44
42
  hookLlm: ReturnType<typeof createHookLlm>["hookLlm"];
45
43
  hookAgent: HookLlmCall;
46
44
  fleetBus: FleetEventBus;
@@ -7,7 +7,7 @@ import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilit
7
7
  import { sendUserFileTool } from "../capabilities/send-user-file-tool.js";
8
8
  import { gateScenarioRequest, mergeUserSkills, selectScenario } from "../capabilities/scenarios.js";
9
9
  import { stampHandsLane, toolPolicyForHands } from "../capabilities/hands-lane.js";
10
- import { buildNoticeLaneFacts, shouldDiscloseNoPersistentMemory, withNoPersistentMemoryNotice } from "../capabilities/memory-notice.js";
10
+ import { buildNoticeLaneFacts, noPersistentMemoryNotice, withNoPersistentMemoryNotice } from "../capabilities/memory-notice.js";
11
11
  import { applyLongtailDefer } from "../capabilities/tool-defer.js";
12
12
  import { assertGuardPatternsUsable, buildApprovalGrantNotice, buildOnlySensitiveBaselineWarning, createApprovalBaselinePolicy, createDeploymentGovernanceInputs } from "../deployment-governance.js";
13
13
  import { createDeploymentListExemption, gateIntentUnserviceableReason, singleUserAutoAcceptBaselineApplies } from "../approval.js";
@@ -31,25 +31,23 @@ import { HttpError, createCodedHttpError, encodeCheckpointScope } from "../secur
31
31
  import { memoryProjectKeyFor, memorySpecForRequest } from "../memory-scope.js";
32
32
  import { inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
33
33
  import { a2aForScenario, mcpForScenario } from "../web-admin-client/facade.js";
34
- import { normalizeAttachments, normalizeResilience, normalizeResumeAtMode, normalizeSuggestNextPrompts, promptProfileFromBody, resolveTaskLimits, retainBackgroundProcessesFromBody, taskAgentsSpecFragment, toolMaterializeStrategyFromBody, toolNameListFromBody } from "../spec-fields.js";
34
+ import { normalizeAttachments, normalizeResilience, normalizeResumeAtMode, normalizeSuggestNextPrompts, promptProfileFromBody, resolveTaskLimits, retainBackgroundProcessesFromBody, taskAgentsSpecFragment, toolMaterializeStrategyFromBody, allowToolsSpecFragment, toolNameListFromBody } from "../spec-fields.js";
35
35
  import { isAbsoluteHostPath } from "@sema-agent/settings-schema";
36
36
  import { cwdHonored, deviceCwdHonored, effectiveHostWorkspace, inProcessSingleUserLane, parseAdditionalDirectories, satisfiedByProcessCwd, shellEnvMismatchCount } from "../task-cwd.js";
37
37
  import { assertRequestA2aUnlocked, resolveRequestA2a } from "../task-a2a.js";
38
38
  import { assertRequestMcpContentOrigin, assertRequestMcpUnlocked, resolveRequestMcp } from "../task-mcp.js";
39
39
  import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, acceptAppendSystemPrompt, applyTaskSettings, effectivePermissionMode, effectiveThinking, hasConstitutionAnchors, parseTaskSettings, taskHooksHonored, providerDropsAppend, settingsPermissionBucketIssue, withPermissionMode } from "../task-settings.js";
40
40
  import { skillDenyInertEntryOf } from "../rule-entry-list.js";
41
- import { enableForkFromBody, normalizeRetainSubagentSessions, selfOrchestrationFromBody } from "../task-workflow.js";
41
+ import { TENANCY_WALL_CLOCK_BASE_SEC, enableForkFromBody, normalizeRetainSubagentSessions, selfOrchestrationFromBody } from "../task-workflow.js";
42
42
  import { redactSecrets } from "../trace/redact.js";
43
43
  import { DeferredSandboxPathEnv, isSandboxPathAdjudicationLane, sandboxPathEnvSlots } from "./deferred-sandbox-path-env.js";
44
44
  import { executionLaneCaps, executionLaneHomeDir, executionLaneOf } from "../execution-lane-caps.js";
45
45
  import { effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
46
46
  import { withUnattendedLeg } from "../unattended-permission-mode.js";
47
47
  import { memoryFaceMounted } from "../memory-scope.js";
48
- import { createAssemblyIncarnationRead, sessionFaceReaderOf } from "./session-incarnation-seat.js";
49
48
  export function createResolveSpec(ctx) {
50
- const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, noteSessionIncarnation, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, approverSeat, lockedKeys, } = ctx;
49
+ const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, approverSeat, lockedKeys, } = ctx;
51
50
  assertGuardPatternsUsable(config);
52
- const assemblyIncarnationRead = createAssemblyIncarnationRead(sessionFaceReaderOf(ownerAware), (e, f) => logger.warn(e, f));
53
51
  const onlySensitiveBaseline = buildOnlySensitiveBaselineWarning(config, {
54
52
  approvalSeat: durableEnabled ? "durable" : "absent",
55
53
  singleUserAutoAcceptBaseline: singleUserAutoAcceptBaselineApplies(config),
@@ -124,8 +122,6 @@ export function createResolveSpec(ctx) {
124
122
  throw new HttpError(422, why, { code: HOST_POSTURE_REFUSED_CODE });
125
123
  }
126
124
  const lane = bindSettingsCwdEnvAndModel(body, auth, gated, opts);
127
- if (auth?.sessionId && assemblyIncarnationRead)
128
- noteSessionIncarnation(auth.sessionId, await assemblyIncarnationRead(auth.sessionId));
129
125
  const anchors = await resolveHistoryAnchors(body, auth);
130
126
  const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors }, effMode);
131
127
  const folded = await foldGovernanceAndSettings(body, auth, spec, gated, effMode);
@@ -368,6 +364,7 @@ export function createResolveSpec(ctx) {
368
364
  : {}),
369
365
  ...(body.excludeAllTools === true ? { excludeAllTools: true } : {}),
370
366
  ...(() => { const v = toolNameListFromBody(body.excludeTools); return v ? { excludeTools: v } : {}; })(),
367
+ ...allowToolsSpecFragment(body.allowTools),
371
368
  ...(() => { const v = toolNameListFromBody(body.deferTools); return v ? { deferTools: v } : {}; })(),
372
369
  ...(() => { const v = promptProfileFromBody(body.promptProfile); return v ? { promptProfile: v } : {}; })(),
373
370
  ...(() => { const v = toolMaterializeStrategyFromBody(body.toolMaterializeStrategy); return v ? { toolMaterializeStrategy: v } : {}; })(),
@@ -409,7 +406,7 @@ export function createResolveSpec(ctx) {
409
406
  thinking: effectiveThinking(body.reasoningEffort, parsedSettings.settings?.ultracode === true),
410
407
  getApiKeyAndHeaders: getKeyResolver(),
411
408
  ...(() => {
412
- const limits = resolveTaskLimits(body.limits, taskLimitCaps, taskTimeoutSec, config.requirePrincipal, body.council === true || body.debate === true || scenarioName === "discuss", (event, fields) => logger.warn(event, { ...fields, sessionId: auth?.sessionId ?? null }));
409
+ const limits = resolveTaskLimits(body.limits, taskLimitCaps, taskTimeoutSec, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: auth?.sessionId ?? null }));
413
410
  const declarations = [];
414
411
  if (taskLimitCaps.timeoutSec !== undefined)
415
412
  declarations.push({ key: "server.limits.timeoutSecCap", value: String(taskLimitCaps.timeoutSec), reason: "env TASK_TIMEOUT_MAX_SEC (seconds; operator ceiling applied to caller limits.maxWalltimeMs as cap×1000)" });
@@ -422,7 +419,7 @@ export function createResolveSpec(ctx) {
422
419
  if (config.maxTaskTokens > 0)
423
420
  declarations.push({ key: "server.budget.maxTokensCap", value: String(config.maxTaskTokens), reason: "env MAX_TASK_TOKENS_MAX (operator ceiling; becomes the effective value when the caller sends none)" });
424
421
  if (config.requirePrincipal === true)
425
- declarations.push({ key: "server.limits.wallClockBaseSec", value: "2400/3600", reason: "tenancy wall-clock base (multi-tenant; big tasks 3600) — TASK_TIMEOUT_SEC raises, never shrinks" });
422
+ declarations.push({ key: "server.limits.wallClockBaseSec", value: String(TENANCY_WALL_CLOCK_BASE_SEC), reason: "tenancy wall-clock base (multi-tenant) — TASK_TIMEOUT_SEC raises, never shrinks" });
426
423
  const maxCostUsd = cappedCeiling(body.maxCostUsd, config.maxTaskCostUsd);
427
424
  const maxTokens = cappedCeiling(body.maxTokens, config.maxTaskTokens);
428
425
  const degrade = (() => {
@@ -518,7 +515,7 @@ export function createResolveSpec(ctx) {
518
515
  }),
519
516
  ...laneHomeBase(),
520
517
  };
521
- const governedBase = applyRuntimeGovernance(spec, createDeploymentGovernanceInputs(config, pathAdjudication, { engineDataRoot: memoryEngine?.root }));
518
+ const governedBase = applyRuntimeGovernance(spec, createDeploymentGovernanceInputs(config, pathAdjudication));
522
519
  let governed = governedBase;
523
520
  let effectiveSettings = effMode ? withPermissionMode(parsedSettings.settings, effMode) : parsedSettings.settings;
524
521
  if (appendLessPack && effectiveSettings?.outputStyle) {
@@ -600,16 +597,15 @@ export function createResolveSpec(ctx) {
600
597
  throw new HttpError(422, `request settings cannot be applied as written: ${e.message}`);
601
598
  }
602
599
  }
603
- if (shouldDiscloseNoPersistentMemory({
600
+ const notice = noPersistentMemoryNotice({
604
601
  memoryFaceMounted: memoryFaceMounted(governed.memory),
605
602
  declaredCapable: effectiveMemoryPersistenceCapable(config),
606
603
  hands: gated.hands,
607
604
  handsReadOnly: governed.handsReadOnly === true,
608
- excludeAllTools: governed.excludeAllTools === true,
609
- excludeTools: governed.excludeTools,
610
605
  ...buildNoticeLaneFacts(executionLaneOf(config.remoteExec?.provider)),
611
- })) {
612
- governed = { ...governed, promptProvider: withNoPersistentMemoryNotice(governed.promptProvider) };
606
+ });
607
+ if (notice !== "silent") {
608
+ governed = { ...governed, promptProvider: withNoPersistentMemoryNotice(governed.promptProvider, notice) };
613
609
  }
614
610
  return { governed, scratchpadDir, hostSemanticsLane };
615
611
  };
@@ -667,7 +663,6 @@ export function createResolveSpec(ctx) {
667
663
  isolatedExecEnv,
668
664
  hasExecutionEnv: executionLaneCaps(executionLaneOf(config.remoteExec?.provider)).coreRemoteExecutionEnv === "supported",
669
665
  ...(config.autonomy ? { autonomy: config.autonomy } : {}),
670
- explicitTeam: body.council === true || body.debate === true || scenarioName === "discuss",
671
666
  });
672
667
  logger.info("orchestration_routed", { mode: decision.mode, reason: decision.reason, sessionId: auth?.sessionId ?? null });
673
668
  if (decision.mode === "supervisor") {
@@ -31,6 +31,7 @@
31
31
  */
32
32
  import type { RetentionPolicy, RetentionReceipt } from "@sema-agent/core";
33
33
  import type { RetentionMode } from "../config-types.js";
34
+ import type { EndedSpace, SpaceReclaimer } from "../workspace-space.js";
34
35
  /** 同 domain 连续失败多少次算「卡住了」(fail-loud 的阈值)。`5` 与 reaper 家族的
35
36
  * `REAPER_FAILURE_WARN_THRESHOLD` 同值同理由:一次抖动(一次重连、一次超时)正是容错要吸收的,
36
37
  * 只有**连败**才越过「可诊断」这条线。 */
@@ -56,7 +57,7 @@ export interface RetentionExecutor {
56
57
  toolResults: number;
57
58
  }>;
58
59
  expireCheckpoints(input: RetentionDestructiveInput): Promise<RetentionReceipt>;
59
- deleteExpiredSessions(input: RetentionDestructiveInput): Promise<RetentionReceipt>;
60
+ deleteExpiredSessions(input: RetentionDestructiveInput): Promise<RetentionSessionsReceipt>;
60
61
  deleteOrphanToolResults(input: RetentionDestructiveInput): Promise<RetentionReceipt>;
61
62
  }
62
63
  /** 破坏性调用的入参(判定时点的三格随行 —— 理由逐字见车1 `RetentionAuditContext` 的头注)。 */
@@ -127,7 +128,17 @@ export interface RetentionSweepCtx {
127
128
  * `createThrottledReaperCatch` 必须建在 `setInterval` 之外是同一条理由。
128
129
  */
129
130
  streaks?: Map<string, number>;
131
+ /** 结束的空间的回收座(k8s 车道 ∧ 配了缓存卷或快照存储时在场;与会话删除协调器同一只):enforce 删掉会话树之后,把回执里结束了的空间交给它
132
+ * (缓存卷、`space/` 快照、该会话停驻车道的快照一并回收)。它从不抛(失败 = 一行 + fail-open 计数);缺席 = 本部署没有可回收的东西。 */
133
+ spaceReclaimer?: SpaceReclaimer;
130
134
  }
135
+ /**
136
+ * 会话树 sweep 的回执 = core 契约的 `RetentionReceipt` + 本仓一位:`endedSpaces` = 本次删掉的会话树里**结束了的空间**(会话 id + 住客空间键 = 会话化身;
137
+ * 读不出住客的空化身不算),present-iff 非空。lane 把它交给空间的回收座(与会话删除协调器同一只),缓存卷与快照随空间的终结回收。
138
+ */
139
+ export type RetentionSessionsReceipt = RetentionReceipt & {
140
+ readonly endedSpaces?: readonly EndedSpace[];
141
+ };
131
142
  /** 一轮的读数(给日志与判据用;lane 自己不做任何决策依赖它)。 */
132
143
  export interface RetentionSweepOutcome {
133
144
  /** 本轮真正处理完的 domain 数(丢租中止时 = 中止之前那些)。 */
@@ -99,6 +99,8 @@ async function sweepDomainEnforce(ctx, d) {
99
99
  };
100
100
  const checkpoints = await ctx.executor.expireCheckpoints(input);
101
101
  const sessions = await ctx.executor.deleteExpiredSessions(input);
102
+ if (sessions.endedSpaces !== undefined && ctx.spaceReclaimer !== undefined)
103
+ await ctx.spaceReclaimer.reclaim(sessions.endedSpaces);
102
104
  const toolResults = await ctx.executor.deleteOrphanToolResults(input);
103
105
  const touched = checkpoints.deleted + sessions.deleted + toolResults.deleted;
104
106
  if (touched > 0) {