@nylorun/runtime 0.26.0-beta → 0.28.0-beta

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 (379) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +18 -14
  3. package/dist/adapters/execution/restate.d.ts +15 -18
  4. package/dist/adapters/execution/restate.js +31 -27
  5. package/dist/adapters/replication/pgoutput.d.ts +1 -1
  6. package/dist/adapters/replication/pgoutput.js +3 -2
  7. package/dist/adapters/sandbox/local.js +8 -5
  8. package/dist/adapters/sandbox/virtual.js +2 -2
  9. package/dist/adapters/streams/s2.d.ts +1 -1
  10. package/dist/adapters/streams/s2.js +18 -14
  11. package/dist/api/a2a/card.d.ts +4 -3
  12. package/dist/api/a2a/card.js +4 -4
  13. package/dist/api/a2a/endpoint.js +3 -4
  14. package/dist/api/a2a/protocol.js +4 -0
  15. package/dist/api/a2a/routes.d.ts +2 -6
  16. package/dist/api/a2a/routes.js +30 -25
  17. package/dist/api/ag-ui/endpoint.js +2 -3
  18. package/dist/api/ag-ui/routes.js +8 -11
  19. package/dist/api/components.d.ts +6789 -3405
  20. package/dist/api/components.js +43 -30
  21. package/dist/api/gate/keys.js +7 -4
  22. package/dist/api/gate/routes.d.ts +6 -2
  23. package/dist/api/gate/routes.js +15 -11
  24. package/dist/api/http/app.js +9 -4
  25. package/dist/api/http/body.d.ts +17 -3
  26. package/dist/api/http/body.js +35 -7
  27. package/dist/api/http/respond.js +6 -2
  28. package/dist/api/http/routes/access.js +5 -4
  29. package/dist/api/http/routes/agent-manifests.d.ts +10 -0
  30. package/dist/api/http/routes/agent-manifests.js +135 -0
  31. package/dist/api/http/routes/agents.d.ts +11 -0
  32. package/dist/api/http/routes/agents.js +418 -0
  33. package/dist/api/http/routes/artifacts.js +21 -9
  34. package/dist/api/http/routes/coverage.d.ts +4 -4
  35. package/dist/api/http/routes/coverage.js +13 -7
  36. package/dist/api/http/routes/files.d.ts +2 -1
  37. package/dist/api/http/routes/files.js +31 -5
  38. package/dist/api/http/routes/mcp.js +3 -3
  39. package/dist/api/http/routes/me.d.ts +1 -1
  40. package/dist/api/http/routes/me.js +1 -2
  41. package/dist/api/http/routes/memories.d.ts +9 -0
  42. package/dist/api/http/routes/memories.js +152 -0
  43. package/dist/api/http/routes/reads.d.ts +10 -111
  44. package/dist/api/http/routes/reads.js +51 -29
  45. package/dist/api/http/routes/sessions.js +26 -54
  46. package/dist/api/http/routes/tenant.d.ts +2 -2
  47. package/dist/api/http/routes/tenant.js +77 -24
  48. package/dist/api/http/routes/triggers.d.ts +10 -0
  49. package/dist/api/http/routes/triggers.js +180 -0
  50. package/dist/api/inbound-files.d.ts +3 -9
  51. package/dist/api/inbound-files.js +18 -24
  52. package/dist/api/openapi.js +73 -47
  53. package/dist/artifacts/disk.d.ts +10 -14
  54. package/dist/artifacts/disk.js +99 -95
  55. package/dist/artifacts/files.d.ts +13 -4
  56. package/dist/artifacts/files.js +27 -9
  57. package/dist/artifacts/folder-upload.d.ts +75 -0
  58. package/dist/artifacts/folder-upload.js +263 -0
  59. package/dist/artifacts/folders.d.ts +14 -8
  60. package/dist/artifacts/folders.js +19 -11
  61. package/dist/artifacts/links.js +7 -6
  62. package/dist/artifacts/parts.d.ts +9 -14
  63. package/dist/artifacts/parts.js +11 -9
  64. package/dist/artifacts/pipe.d.ts +15 -0
  65. package/dist/artifacts/pipe.js +71 -0
  66. package/dist/artifacts/quota.d.ts +36 -0
  67. package/dist/artifacts/quota.js +44 -0
  68. package/dist/artifacts/service.d.ts +25 -1
  69. package/dist/artifacts/service.js +72 -27
  70. package/dist/blob/fs.js +2 -1
  71. package/dist/blob/s3.d.ts +6 -2
  72. package/dist/blob/s3.js +9 -7
  73. package/dist/blob/types.d.ts +1 -1
  74. package/dist/blob/types.js +1 -1
  75. package/dist/core/flow-host.d.ts +0 -1
  76. package/dist/core/limits.d.ts +11 -35
  77. package/dist/core/limits.js +5 -73
  78. package/dist/core/sandbox-routes.js +0 -1
  79. package/dist/core/turn-manifest.d.ts +1 -2
  80. package/dist/core/turn-manifest.js +4 -28
  81. package/dist/execution/memory.d.ts +8 -5
  82. package/dist/execution/memory.js +8 -6
  83. package/dist/execution/types.d.ts +1 -6
  84. package/dist/execution/types.js +0 -5
  85. package/dist/gates/contract.d.ts +3 -2
  86. package/dist/gates/contract.js +1 -1
  87. package/dist/gates/egress-credentials.js +5 -4
  88. package/dist/gates/egress.d.ts +13 -13
  89. package/dist/gates/egress.js +19 -21
  90. package/dist/gates/fixture-model.js +13 -2
  91. package/dist/gates/handler.d.ts +1 -3
  92. package/dist/gates/handler.js +4 -3
  93. package/dist/gates/http-client.d.ts +4 -3
  94. package/dist/gates/http-client.js +5 -7
  95. package/dist/gates/http-tool.d.ts +24 -4
  96. package/dist/gates/http-tool.js +41 -13
  97. package/dist/gates/in-process.d.ts +2 -1
  98. package/dist/gates/in-process.js +17 -9
  99. package/dist/gates/inflight.d.ts +2 -2
  100. package/dist/gates/inflight.js +3 -2
  101. package/dist/gates/journal.js +5 -7
  102. package/dist/gates/mcp-handler.d.ts +4 -3
  103. package/dist/gates/mcp-handler.js +15 -5
  104. package/dist/gates/meter.js +6 -5
  105. package/dist/gates/model-gate.d.ts +11 -2
  106. package/dist/gates/policy.d.ts +34 -6
  107. package/dist/gates/policy.js +66 -18
  108. package/dist/gates/provider-gate.d.ts +22 -0
  109. package/dist/gates/provider-gate.js +30 -0
  110. package/dist/gates/tool-calls.d.ts +1 -3
  111. package/dist/gates/tool-calls.js +2 -3
  112. package/dist/gates/tool-client.d.ts +1 -1
  113. package/dist/gates/tool-client.js +5 -6
  114. package/dist/gates/tool-contract.d.ts +8 -5
  115. package/dist/gates/tool-contract.js +1 -1
  116. package/dist/gates/tool-gate.d.ts +18 -7
  117. package/dist/gates/tool-gate.js +49 -7
  118. package/dist/harness/calls.d.ts +27 -25
  119. package/dist/harness/calls.js +40 -46
  120. package/dist/harness/executors.d.ts +10 -3
  121. package/dist/harness/executors.js +53 -23
  122. package/dist/harness/main.js +2 -2
  123. package/dist/harness/pod.d.ts +2 -2
  124. package/dist/harness/pod.js +7 -6
  125. package/dist/harness/run-tokens.d.ts +4 -1
  126. package/dist/harness/run-tokens.js +6 -2
  127. package/dist/harness/service.d.ts +17 -14
  128. package/dist/harness/service.js +21 -35
  129. package/dist/harness/setup.d.ts +0 -2
  130. package/dist/harness/setup.js +21 -15
  131. package/dist/harness/ws-client.d.ts +2 -2
  132. package/dist/harness/ws-client.js +7 -5
  133. package/dist/harness/ws-port.d.ts +3 -4
  134. package/dist/harness/ws-port.js +3 -4
  135. package/dist/harness-api/artifacts.d.ts +20 -0
  136. package/dist/harness-api/artifacts.js +478 -0
  137. package/dist/harness-api/in-process.d.ts +2 -2
  138. package/dist/harness-api/in-process.js +18 -16
  139. package/dist/harness-api/record.d.ts +10 -9
  140. package/dist/harness-api/record.js +113 -157
  141. package/dist/harness-api/renew.d.ts +1 -1
  142. package/dist/harness-api/renew.js +2 -2
  143. package/dist/harness-api/server.d.ts +1 -16
  144. package/dist/harness-api/server.js +86 -73
  145. package/dist/harness-api/start.d.ts +27 -5
  146. package/dist/harness-api/start.js +102 -19
  147. package/dist/harness-api/tool-journal.d.ts +15 -10
  148. package/dist/harness-api/tool-journal.js +26 -24
  149. package/dist/harness-api/workspace.d.ts +0 -4
  150. package/dist/harness-api/workspace.js +4 -47
  151. package/dist/harness-api/ws-server.js +10 -10
  152. package/dist/host/create-host.js +2 -3
  153. package/dist/host/execution.js +2 -3
  154. package/dist/host/gates.d.ts +2 -9
  155. package/dist/host/gates.js +15 -12
  156. package/dist/host/http.d.ts +2 -4
  157. package/dist/host/http.js +5 -29
  158. package/dist/host/main.js +10 -3
  159. package/dist/host/operate.js +12 -3
  160. package/dist/host/stack-config.d.ts +11 -0
  161. package/dist/host/stack-config.js +21 -1
  162. package/dist/index.d.ts +0 -1
  163. package/dist/index.js +0 -1
  164. package/dist/infra/index.js +2 -1
  165. package/dist/infra/readiness.d.ts +0 -2
  166. package/dist/infra/readiness.js +4 -3
  167. package/dist/keys/client.d.ts +1 -0
  168. package/dist/keys/client.js +2 -3
  169. package/dist/keys/contract.d.ts +0 -2
  170. package/dist/keys/contract.js +0 -2
  171. package/dist/keys/egress-ca.d.ts +0 -2
  172. package/dist/keys/egress-ca.js +2 -3
  173. package/dist/keys/keys.d.ts +15 -4
  174. package/dist/keys/keys.js +22 -1
  175. package/dist/keys/webhooks.d.ts +25 -0
  176. package/dist/keys/webhooks.js +62 -0
  177. package/dist/keys/x509.d.ts +8 -4
  178. package/dist/keys/x509.js +14 -5
  179. package/dist/management-openapi.json +3043 -1954
  180. package/dist/mcp/connect.d.ts +35 -26
  181. package/dist/mcp/connect.js +112 -141
  182. package/dist/mcp/pool.d.ts +27 -22
  183. package/dist/mcp/pool.js +34 -48
  184. package/dist/mcp/preview.d.ts +12 -5
  185. package/dist/mcp/preview.js +43 -26
  186. package/dist/mcp/snapshot.d.ts +35 -86
  187. package/dist/mcp/snapshot.js +93 -135
  188. package/dist/memory/service.d.ts +97 -0
  189. package/dist/memory/service.js +335 -0
  190. package/dist/memory/tool.d.ts +36 -0
  191. package/dist/memory/tool.js +84 -0
  192. package/dist/model/auth-store.js +5 -3
  193. package/dist/model/capabilities.d.ts +1 -1
  194. package/dist/model/catalog.d.ts +9 -36
  195. package/dist/model/catalog.js +6 -33
  196. package/dist/model/descriptor.d.ts +51 -0
  197. package/dist/model/descriptor.js +83 -0
  198. package/dist/model/models.d.ts +0 -3
  199. package/dist/model/models.js +3 -5
  200. package/dist/model/native-blocks.js +1 -1
  201. package/dist/model/pi-model.d.ts +16 -5
  202. package/dist/model/pi-model.js +86 -105
  203. package/dist/openapi.json +13653 -9986
  204. package/dist/reads/cursor.js +3 -1
  205. package/dist/reads/types.d.ts +3 -3
  206. package/dist/record/agent.d.ts +27 -0
  207. package/dist/record/agent.js +46 -0
  208. package/dist/record/append.d.ts +34 -2
  209. package/dist/record/append.js +50 -1
  210. package/dist/record/index.d.ts +2 -2
  211. package/dist/record/index.js +2 -2
  212. package/dist/redact.d.ts +1 -1
  213. package/dist/redact.js +3 -2
  214. package/dist/sandbox/egress-token.d.ts +3 -3
  215. package/dist/sandbox/egress-token.js +3 -3
  216. package/dist/sandbox/join.js +8 -7
  217. package/dist/sandbox/manager.d.ts +41 -41
  218. package/dist/sandbox/manager.js +112 -44
  219. package/dist/sandbox/placement.d.ts +2 -2
  220. package/dist/sandbox/placement.js +7 -10
  221. package/dist/sandbox/pods/client.d.ts +1 -10
  222. package/dist/sandbox/pods/client.js +8 -4
  223. package/dist/sandbox/pods/lifecycle.d.ts +25 -17
  224. package/dist/sandbox/pods/lifecycle.js +51 -29
  225. package/dist/sandbox/pods/network-gate.d.ts +4 -5
  226. package/dist/sandbox/pods/network-gate.js +7 -7
  227. package/dist/sandbox/pods/reconcile.js +14 -3
  228. package/dist/sandbox/pods/spec.js +8 -5
  229. package/dist/sandbox/policy.d.ts +7 -1
  230. package/dist/sandbox/policy.js +10 -3
  231. package/dist/sandbox/resolve.d.ts +11 -6
  232. package/dist/sandbox/resolve.js +19 -9
  233. package/dist/sandbox/setup.d.ts +6 -2
  234. package/dist/sandbox/setup.js +47 -14
  235. package/dist/sandbox/share.d.ts +5 -14
  236. package/dist/sandbox/share.js +5 -34
  237. package/dist/sandbox/skills.d.ts +7 -13
  238. package/dist/sandbox/skills.js +16 -31
  239. package/dist/sandbox/tenant-config.d.ts +2 -2
  240. package/dist/sandbox/tenant-config.js +4 -3
  241. package/dist/sandbox/tools.d.ts +7 -1
  242. package/dist/sandbox/tools.js +26 -26
  243. package/dist/sandbox/types.d.ts +10 -3
  244. package/dist/sandbox/types.js +9 -0
  245. package/dist/store/postgres/connect.d.ts +6 -5
  246. package/dist/store/postgres/connect.js +14 -11
  247. package/dist/store/postgres/control.js +13 -13
  248. package/dist/store/postgres/drizzle/0028_artifact_write_keys.sql +2 -0
  249. package/dist/store/postgres/drizzle/0029_protocol_15.sql +11 -0
  250. package/dist/store/postgres/drizzle/0030_protocol_15_runtime_block.sql +11 -0
  251. package/dist/store/postgres/drizzle/0031_protocol_15_mcp_snapshot.sql +8 -0
  252. package/dist/store/postgres/drizzle/0032_agents.sql +54 -0
  253. package/dist/store/postgres/drizzle/0033_agent_versions.sql +7 -0
  254. package/dist/store/postgres/drizzle/0034_protocol_17_session_queue.sql +13 -0
  255. package/dist/store/postgres/drizzle/0035_t4_triggers.sql +41 -0
  256. package/dist/store/postgres/drizzle/0036_t5_memories.sql +30 -0
  257. package/dist/store/postgres/drizzle/meta/_journal.json +63 -0
  258. package/dist/store/postgres/reads.js +17 -82
  259. package/dist/store/postgres/record-writer.d.ts +4 -4
  260. package/dist/store/postgres/record-writer.js +9 -9
  261. package/dist/store/postgres/schema.d.ts +1382 -151
  262. package/dist/store/postgres/schema.js +191 -37
  263. package/dist/store/postgres/store.js +384 -105
  264. package/dist/store/postgres/tenant.js +1 -2
  265. package/dist/store/types.d.ts +172 -57
  266. package/dist/store/types.js +0 -1
  267. package/dist/streams/relay/core.d.ts +3 -3
  268. package/dist/streams/relay/core.js +9 -10
  269. package/dist/tenant/advance.js +41 -39
  270. package/dist/tenant/agent-manifests.d.ts +72 -0
  271. package/dist/tenant/agent-manifests.js +359 -0
  272. package/dist/tenant/agent-versions.d.ts +126 -0
  273. package/dist/tenant/agent-versions.js +389 -0
  274. package/dist/tenant/agents.d.ts +230 -0
  275. package/dist/tenant/{environments.js → agents.js} +493 -328
  276. package/dist/tenant/auth.d.ts +1 -1
  277. package/dist/tenant/auth.js +3 -3
  278. package/dist/tenant/commands.d.ts +63 -2
  279. package/dist/tenant/commands.js +240 -90
  280. package/dist/tenant/context.d.ts +57 -33
  281. package/dist/tenant/context.js +6 -2
  282. package/dist/tenant/definition-files.d.ts +25 -4
  283. package/dist/tenant/definition-files.js +85 -47
  284. package/dist/tenant/effects.js +15 -51
  285. package/dist/tenant/ephemeral.js +2 -1
  286. package/dist/tenant/history.d.ts +1 -1
  287. package/dist/tenant/history.js +1 -1
  288. package/dist/tenant/host-token.d.ts +3 -3
  289. package/dist/tenant/host-token.js +11 -10
  290. package/dist/tenant/http.d.ts +5 -8
  291. package/dist/tenant/http.js +9 -0
  292. package/dist/tenant/identity-file.d.ts +29 -6
  293. package/dist/tenant/identity-file.js +45 -15
  294. package/dist/tenant/issuers.d.ts +5 -5
  295. package/dist/tenant/issuers.js +34 -26
  296. package/dist/tenant/jwt.d.ts +8 -2
  297. package/dist/tenant/jwt.js +10 -2
  298. package/dist/tenant/limits.d.ts +87 -0
  299. package/dist/tenant/limits.js +172 -0
  300. package/dist/tenant/memories.d.ts +38 -0
  301. package/dist/tenant/memories.js +119 -0
  302. package/dist/tenant/module.d.ts +4 -1
  303. package/dist/tenant/module.js +9 -8
  304. package/dist/tenant/outbound.d.ts +11 -14
  305. package/dist/tenant/outbound.js +10 -15
  306. package/dist/tenant/reset.js +2 -2
  307. package/dist/tenant/run-grants.d.ts +6 -0
  308. package/dist/tenant/run-grants.js +7 -2
  309. package/dist/tenant/run-token.d.ts +0 -4
  310. package/dist/tenant/run-token.js +6 -11
  311. package/dist/tenant/runtime-limits.d.ts +24 -0
  312. package/dist/tenant/runtime-limits.js +27 -0
  313. package/dist/tenant/runtime.d.ts +1 -1
  314. package/dist/tenant/runtime.js +38 -43
  315. package/dist/tenant/session-streams.js +7 -6
  316. package/dist/tenant/session.d.ts +1 -1
  317. package/dist/tenant/session.js +1 -1
  318. package/dist/tenant/sessions.d.ts +28 -45
  319. package/dist/tenant/sessions.js +89 -209
  320. package/dist/tenant/signing-keys.d.ts +1 -1
  321. package/dist/tenant/signing-keys.js +5 -6
  322. package/dist/tenant/status.js +10 -10
  323. package/dist/tenant/streams.js +18 -20
  324. package/dist/tenant/sweep.d.ts +1 -21
  325. package/dist/tenant/sweep.js +51 -51
  326. package/dist/tenant/transcript.d.ts +70 -23
  327. package/dist/tenant/transcript.js +28 -22
  328. package/dist/tenant/triggers.d.ts +143 -0
  329. package/dist/tenant/triggers.js +715 -0
  330. package/dist/tenant/turn-timing.d.ts +11 -1
  331. package/dist/tenant/turn-timing.js +3 -1
  332. package/dist/tenant/types.d.ts +9 -14
  333. package/dist/tenant/worker.d.ts +4 -10
  334. package/dist/tenant/worker.js +10 -14
  335. package/dist/traces/ids.js +5 -1
  336. package/dist/traces/map.d.ts +10 -7
  337. package/dist/traces/map.js +16 -12
  338. package/dist/traces/otlp.d.ts +3 -3
  339. package/dist/traces/otlp.js +5 -3
  340. package/dist/traces/projector.d.ts +9 -4
  341. package/dist/traces/projector.js +13 -7
  342. package/dist/traces/read.js +6 -1
  343. package/dist/tuning.d.ts +390 -0
  344. package/dist/tuning.js +677 -0
  345. package/dist/vault/headers.js +4 -2
  346. package/dist/vault/service.d.ts +13 -8
  347. package/dist/vault/service.js +61 -17
  348. package/dist/version.d.ts +1 -1
  349. package/dist/version.js +1 -1
  350. package/package.json +13 -12
  351. package/dist/api/http/routes/environment-manifests.d.ts +0 -9
  352. package/dist/api/http/routes/environment-manifests.js +0 -118
  353. package/dist/api/http/routes/environments.d.ts +0 -11
  354. package/dist/api/http/routes/environments.js +0 -332
  355. package/dist/artifacts/export.d.ts +0 -8
  356. package/dist/artifacts/export.js +0 -204
  357. package/dist/artifacts/media-types.d.ts +0 -30
  358. package/dist/artifacts/media-types.js +0 -137
  359. package/dist/artifacts/workspace.d.ts +0 -60
  360. package/dist/artifacts/workspace.js +0 -45
  361. package/dist/media.d.ts +0 -10
  362. package/dist/media.js +0 -58
  363. package/dist/record/environment.d.ts +0 -25
  364. package/dist/record/environment.js +0 -44
  365. package/dist/sandbox/runtime-tools.d.ts +0 -9
  366. package/dist/sandbox/runtime-tools.js +0 -16
  367. package/dist/sandbox/session-sandbox.d.ts +0 -16
  368. package/dist/sandbox/session-sandbox.js +0 -77
  369. package/dist/tenant/artifact-tool.d.ts +0 -13
  370. package/dist/tenant/artifact-tool.js +0 -243
  371. package/dist/tenant/environment-manifests.d.ts +0 -57
  372. package/dist/tenant/environment-manifests.js +0 -200
  373. package/dist/tenant/environments.d.ts +0 -174
  374. package/dist/tenant/skill-tool.d.ts +0 -20
  375. package/dist/tenant/skill-tool.js +0 -67
  376. package/dist/tenant/tool-results.d.ts +0 -57
  377. package/dist/tenant/tool-results.js +0 -298
  378. package/dist/tenant/tool-search.d.ts +0 -39
  379. package/dist/tenant/tool-search.js +0 -103
@@ -6,17 +6,20 @@
6
6
  *
7
7
  * Two implementations: `inProcessToolGate` (embedding, the ephemeral Runtime, tests), which
8
8
  * opens remote servers and calls HTTP tools in this process, and the HTTP client of the gates
9
- * service (`tool-client.ts`, the `gateway` container). The sandbox tools never cross it.
9
+ * service (`tool-client.ts`, the `gateway` container). The sandbox tools never cross it. A
10
+ * harness's MCP pool opens every server through a gate (`openMcp`), in process too (protocol
11
+ * 15): the vault authorizes a connection only here.
10
12
  */
11
- import type { LiveConnection } from "../mcp/connect.js";
12
- import type { McpServerRef } from "../mcp/pool.js";
13
+ import { openMcpServer, type LiveConnection } from "../mcp/connect.js";
14
+ import { type McpServerRef } from "../mcp/pool.js";
13
15
  import type { OutboundPolicy } from "../tenant/outbound.js";
14
16
  import type { Logger } from "../tenant/types.js";
15
17
  import { type HttpOutcome, type HttpToolCall, type HttpToolTenant } from "./http-tool.js";
16
18
  export interface ToolGate {
17
19
  /**
18
- * Opens a remote (`streamable-http` or `sse`) MCP server of a session. Absent: the loop's
19
- * pool opens it itself, with the Tenant vault.
20
+ * Opens a remote (`streamable-http` or `sse`) MCP server of a session: the one its pinned
21
+ * manifest declares, authorized with the Tenant vault. Absent: this Runtime opens no MCP
22
+ * server.
20
23
  */
21
24
  openMcp?(server: McpServerRef): Promise<LiveConnection>;
22
25
  /**
@@ -39,9 +42,17 @@ export interface ToolGate {
39
42
  }): Promise<void>;
40
43
  }
41
44
  /**
42
- * The Tool Gate in the caller's process: remote MCP through the pool, and HTTP tools with
43
- * `tenant`'s sessions and vault.
45
+ * The Tool Gate in the caller's process: remote MCP servers and HTTP tools with `tenant`'s
46
+ * sessions and vault. `openMcp` finds the server in the session's pinned manifest (as the gates
47
+ * service does), so a caller names a server, never a URL or a credential. `open` replaces how a
48
+ * server is opened (tests).
44
49
  */
45
50
  export declare function inProcessToolGate(policy?: OutboundPolicy, tenant?: HttpToolTenant & {
46
51
  readonly logger?: Logger;
52
+ readonly open?: typeof openMcpServer;
47
53
  }): ToolGate;
54
+ /**
55
+ * How a harness's MCP pool opens a server: through `gate`, or, for a Runtime whose gate opens
56
+ * none, never (the call fails to the model as `mcp.unreachable`).
57
+ */
58
+ export declare function openMcpThrough(gate: Pick<ToolGate, "openMcp">): (server: McpServerRef) => Promise<LiveConnection>;
@@ -1,14 +1,56 @@
1
+ /**
2
+ * The Tool Gate seam (blueprint §12, F4.1). Every tool call that leaves the loop crosses one
3
+ * `ToolGate`: a remote MCP server's connection and calls, and an HTTP tool's request (R2 M3).
4
+ * The gate owns what those need that the loop must not hold: the MCP and HTTP tool credentials,
5
+ * and the outbound route.
6
+ *
7
+ * Two implementations: `inProcessToolGate` (embedding, the ephemeral Runtime, tests), which
8
+ * opens remote servers and calls HTTP tools in this process, and the HTTP client of the gates
9
+ * service (`tool-client.ts`, the `gateway` container). The sandbox tools never cross it. A
10
+ * harness's MCP pool opens every server through a gate (`openMcp`), in process too (protocol
11
+ * 15): the vault authorizes a connection only here.
12
+ */
13
+ import { openMcpServer } from "../mcp/connect.js";
14
+ import { findServer } from "../mcp/pool.js";
1
15
  import { runHttpTool } from "./http-tool.js";
2
16
  /**
3
- * The Tool Gate in the caller's process: remote MCP through the pool, and HTTP tools with
4
- * `tenant`'s sessions and vault.
17
+ * The Tool Gate in the caller's process: remote MCP servers and HTTP tools with `tenant`'s
18
+ * sessions and vault. `openMcp` finds the server in the session's pinned manifest (as the gates
19
+ * service does), so a caller names a server, never a URL or a credential. `open` replaces how a
20
+ * server is opened (tests).
5
21
  */
6
22
  export function inProcessToolGate(policy = {}, tenant) {
23
+ if (!tenant)
24
+ return {};
25
+ const open = tenant.open ?? openMcpServer;
7
26
  return {
8
- ...(tenant
9
- ? {
10
- callHttp: (call, signal) => runHttpTool(tenant, call, { policy, signal, ...(tenant.logger ? { logger: tenant.logger } : {}) }),
11
- }
12
- : {}),
27
+ callHttp: (call, signal) => runHttpTool(tenant, call, { policy, signal, ...(tenant.logger ? { logger: tenant.logger } : {}) }),
28
+ async openMcp(server) {
29
+ const session = await tenant.session(server.sessionId);
30
+ if (!session)
31
+ throw new Error(`Session ${server.sessionId} not found`);
32
+ const declared = findServer(session.manifest, server.agentId, server.serverName);
33
+ if (!declared)
34
+ throw new Error(`MCP server '${server.serverName}' is not declared`);
35
+ return open({
36
+ server: declared.server,
37
+ policy,
38
+ errorExcerptChars: (await tenant.limits()).errorExcerptChars,
39
+ authorize: (url) => tenant.authorize(server.sessionId, {
40
+ url,
41
+ serverName: server.serverName,
42
+ ...(server.agentId === undefined ? {} : { agentId: server.agentId }),
43
+ }),
44
+ });
45
+ },
13
46
  };
14
47
  }
48
+ /**
49
+ * How a harness's MCP pool opens a server: through `gate`, or, for a Runtime whose gate opens
50
+ * none, never (the call fails to the model as `mcp.unreachable`).
51
+ */
52
+ export function openMcpThrough(gate) {
53
+ return (server) => gate.openMcp
54
+ ? gate.openMcp(server)
55
+ : Promise.reject(new Error("This Runtime opens MCP servers only through a Tool Gate, and has none"));
56
+ }
@@ -1,31 +1,30 @@
1
1
  /**
2
- * The calls a harness executes, as pure helpers over what routes them: the Model Gate (or the
3
- * Tenant's provider), the Tool Gate, the MCP pool, the SandboxManager. No store, no record: the
4
- * session's routing comes with the run (`TurnStart.routing`).
2
+ * The calls a harness executes, as pure helpers over what routes them: the Model Gate, the Tool
3
+ * Gate, the MCP pool, the SandboxManager. No store, no record: the session's routing comes with
4
+ * the run (`TurnStart.routing`). Every model call goes through the Model Gate, in a harness
5
+ * process and in core's alike (protocol 15): a Runtime with a scripted model serves it from a
6
+ * gate too (`providerModelGate`).
5
7
  */
6
- import { type AgentManifest } from "@nylorun/core/define";
8
+ import { type AgentManifest, type SandboxManifest } from "@nylorun/core/define";
7
9
  import type { HostEffect } from "@nylorun/harness/run";
10
+ import type { SandboxToolLimits } from "@nylorun/harness";
8
11
  import type { AbortReason } from "@nylorun/core/harness-api";
9
- import type { ModelProvider } from "../core/provider.js";
10
12
  import type { ModelGate } from "../gates/model-gate.js";
11
13
  import type { ToolGate } from "../gates/tool-gate.js";
12
14
  import { type McpPool } from "../mcp/pool.js";
13
- import { type McpSnapshot } from "../mcp/snapshot.js";
14
15
  import type { SandboxManager } from "../sandbox/manager.js";
15
- /** Where a Tenant's model calls go. */
16
+ /** Where a Tenant's model calls go: its Model Gate. */
16
17
  export interface ModelRoute {
17
18
  readonly tenantId: string;
18
19
  readonly modelGate: ModelGate;
19
- readonly modelProvider: ModelProvider;
20
- /** True when the model comes from the Tenant vault selection, served by `modelGate`. */
21
- readonly useVaultModel: boolean;
22
20
  }
23
21
  /** What a session's tool calls are routed by. */
24
22
  export interface ToolRouting {
25
23
  readonly rootManifest: AgentManifest;
26
- readonly mcpSnapshot?: McpSnapshot;
27
24
  /** The session that owns the tree's sandbox, and the sandbox resource it is attached to. */
28
25
  readonly sandboxOwnerId: string;
26
+ /** The sandbox spec the session pinned (`routing.sandbox.spec`); absent without a sandbox. */
27
+ readonly spec?: SandboxManifest;
29
28
  readonly environmentId?: string;
30
29
  /** Variables every sandbox command gets (R2c): secret names set to the sentinel, plain values. */
31
30
  readonly environment?: Readonly<Record<string, string>>;
@@ -34,14 +33,12 @@ export interface ToolRouting {
34
33
  readonly claim?: string;
35
34
  }
36
35
  /**
37
- * Call the model for one effect. A provider failure comes back as a failure outcome
38
- * (Model Calls §6), whichever provider serves the call; only an abort throws, and the
39
- * advance decides what the abort means. `atGate` sends the call to the Model Gate even when the
40
- * Tenant's model is not from the vault: the Tenant's fixture model is answered there (R4.3).
36
+ * Call the model for one effect, through the Model Gate. A provider failure comes back as a
37
+ * failure outcome (Model Calls §6), whichever provider serves the call; only an abort throws, and
38
+ * the advance decides what the abort means. The Tenant's fixture model is answered at the gate
39
+ * too (R4.3).
41
40
  */
42
- export declare function invokeModel(route: ModelRoute, request: HostEffect, signal: AbortSignal, options?: {
43
- readonly atGate?: boolean;
44
- }): Promise<unknown>;
41
+ export declare function invokeModel(route: ModelRoute, request: HostEffect, signal: AbortSignal): Promise<unknown>;
45
42
  /**
46
43
  * A signal that follows `signal` only for the abort kinds in `kinds`. An MCP call stops on a
47
44
  * cancel; at the Tool Gate it also stops waiting on a shutdown, since the gate keeps the call
@@ -49,13 +46,14 @@ export declare function invokeModel(route: ModelRoute, request: HostEffect, sign
49
46
  * so the next advance replays it.
50
47
  */
51
48
  export declare function abortOn(signal: AbortSignal, kinds: readonly AbortReason[]): AbortSignal;
52
- /** True when `request` calls `save_artifact`, which the Runtime pinned on `manifest`. */
53
- export declare function isSaveArtifactCall(manifest: AgentManifest | undefined, request: HostEffect): boolean;
54
- /** True when `request` calls `read_artifact` (R2b C11), which the Runtime pinned on `manifest`. */
55
- export declare function isReadArtifactCall(manifest: AgentManifest | undefined, request: HostEffect): boolean;
56
- /** True when `request` calls a tool of a declared MCP server (every one is remote). */
57
- export declare function isRemoteMcpCall(routing: Pick<ToolRouting, "rootManifest" | "mcpSnapshot">, request: HostEffect): boolean;
49
+ /**
50
+ * True when `request` calls a tool of an MCP server its agent declares (every one is remote): an
51
+ * `mcp` call, by its target's `server` (protocol 15).
52
+ */
53
+ export declare function isRemoteMcpCall(routing: Pick<ToolRouting, "rootManifest">, request: HostEffect): boolean;
58
54
  export declare function callMcpTool(mcp: McpPool, routing: ToolRouting, request: HostEffect, signal: AbortSignal,
55
+ /** The run's Runtime limit `toolAnswerBytes`: the largest answer kept where this process holds the connection. */
56
+ maxResultBytes: number,
59
57
  /** The call's span context (R7.4), sent as `traceparent` where this process holds the connection. */
60
58
  traceparent?: string): Promise<unknown>;
61
59
  /**
@@ -66,4 +64,8 @@ traceparent?: string): Promise<unknown>;
66
64
  export declare function callHttpTool(gate: Pick<ToolGate, "callHttp">, request: HostEffect, signal: AbortSignal,
67
65
  /** The call's span context (R7.4); the gates service reads its own from the journal. */
68
66
  traceparent?: string): Promise<unknown>;
69
- export declare function callSandboxTool(sandbox: SandboxManager, routing: ToolRouting, request: HostEffect, signal: AbortSignal): Promise<unknown>;
67
+ /**
68
+ * Runs a `sandbox` call: the operation it names, in the session's sandbox (the one its agents
69
+ * used as tools share), held to the harness's sandbox tool limits.
70
+ */
71
+ export declare function callSandboxTool(sandbox: SandboxManager, routing: ToolRouting, request: HostEffect, signal: AbortSignal, limits?: SandboxToolLimits): Promise<unknown>;
@@ -1,26 +1,23 @@
1
1
  /**
2
- * The calls a harness executes, as pure helpers over what routes them: the Model Gate (or the
3
- * Tenant's provider), the Tool Gate, the MCP pool, the SandboxManager. No store, no record: the
4
- * session's routing comes with the run (`TurnStart.routing`).
2
+ * The calls a harness executes, as pure helpers over what routes them: the Model Gate, the Tool
3
+ * Gate, the MCP pool, the SandboxManager. No store, no record: the session's routing comes with
4
+ * the run (`TurnStart.routing`). Every model call goes through the Model Gate, in a harness
5
+ * process and in core's alike (protocol 15): a Runtime with a scripted model serves it from a
6
+ * gate too (`providerModelGate`).
5
7
  */
6
- import { READ_ARTIFACT_TOOL, SAVE_ARTIFACT_TOOL, } from "@nylorun/core/define";
8
+ import { isSandboxToolName } from "@nylorun/core/define";
7
9
  import { runAbortKind } from "@nylorun/harness/api";
8
10
  import { httpToolRefOf } from "../gates/http-tool.js";
9
11
  import { classifyThrown } from "../model/classify.js";
10
12
  import { findServer } from "../mcp/pool.js";
11
- import { manifestFor, mcpToolOf } from "../mcp/snapshot.js";
12
- import { isPinnedRuntimeTool, sandboxToolSpec } from "../sandbox/runtime-tools.js";
13
13
  /**
14
- * Call the model for one effect. A provider failure comes back as a failure outcome
15
- * (Model Calls §6), whichever provider serves the call; only an abort throws, and the
16
- * advance decides what the abort means. `atGate` sends the call to the Model Gate even when the
17
- * Tenant's model is not from the vault: the Tenant's fixture model is answered there (R4.3).
14
+ * Call the model for one effect, through the Model Gate. A provider failure comes back as a
15
+ * failure outcome (Model Calls §6), whichever provider serves the call; only an abort throws, and
16
+ * the advance decides what the abort means. The Tenant's fixture model is answered at the gate
17
+ * too (R4.3).
18
18
  */
19
- export async function invokeModel(route, request, signal, options = {}) {
20
- const atGate = route.useVaultModel || options.atGate === true;
19
+ export async function invokeModel(route, request, signal) {
21
20
  try {
22
- if (!atGate)
23
- return await route.modelProvider(request, signal);
24
21
  return await route.modelGate.call({
25
22
  tenantId: route.tenantId,
26
23
  sessionId: request.sessionId,
@@ -28,6 +25,8 @@ export async function invokeModel(route, request, signal, options = {}) {
28
25
  agentId: request.agentId,
29
26
  effectId: request.effectId,
30
27
  invocationId: String(request.context.invocationId),
28
+ ...(request.agent === undefined ? {} : { agent: request.agent }),
29
+ ...(request.purpose === undefined ? {} : { purpose: request.purpose }),
31
30
  call: request.input,
32
31
  }, signal);
33
32
  }
@@ -35,7 +34,7 @@ export async function invokeModel(route, request, signal, options = {}) {
35
34
  if (signal.aborted) {
36
35
  // A call that outlives this process stops only when told to: on a user cancel. After a
37
36
  // shutdown or a lost lease the next owner re-sends it and picks up its outcome (P1.2).
38
- if (atGate && runAbortKind(signal) === "cancel" && route.modelGate.cancel)
37
+ if (runAbortKind(signal) === "cancel" && route.modelGate.cancel)
39
38
  await route.modelGate.cancel({
40
39
  tenantId: route.tenantId,
41
40
  sessionId: request.sessionId,
@@ -65,43 +64,34 @@ export function abortOn(signal, kinds) {
65
64
  signal.addEventListener("abort", follow, { once: true });
66
65
  return controller.signal;
67
66
  }
68
- /** True when `request` calls `save_artifact`, which the Runtime pinned on `manifest`. */
69
- export function isSaveArtifactCall(manifest, request) {
70
- return isArtifactsToolCall(manifest, request, SAVE_ARTIFACT_TOOL);
71
- }
72
- /** True when `request` calls `read_artifact` (R2b C11), which the Runtime pinned on `manifest`. */
73
- export function isReadArtifactCall(manifest, request) {
74
- return isArtifactsToolCall(manifest, request, READ_ARTIFACT_TOOL);
75
- }
76
- function isArtifactsToolCall(manifest, request, toolName) {
77
- return (request.kind === "tool" &&
78
- request.toolName === toolName &&
79
- isPinnedRuntimeTool(manifest, toolName));
80
- }
81
- /** True when `request` calls a tool of a declared MCP server (every one is remote). */
67
+ /**
68
+ * True when `request` calls a tool of an MCP server its agent declares (every one is remote): an
69
+ * `mcp` call, by its target's `server` (protocol 15).
70
+ */
82
71
  export function isRemoteMcpCall(routing, request) {
83
- if (request.kind !== "tool")
72
+ if (request.kind !== "tool" || request.target?.kind !== "mcp")
84
73
  return false;
85
- const tool = mcpToolOf(routing.mcpSnapshot, request);
86
- if (!tool)
87
- return false;
88
- return findServer(routing.rootManifest, tool.agentId, tool.serverName) !== undefined;
74
+ return findServer(routing.rootManifest, request.agent?.id, request.target.server) !== undefined;
89
75
  }
90
76
  export async function callMcpTool(mcp, routing, request, signal,
77
+ /** The run's Runtime limit `toolAnswerBytes`: the largest answer kept where this process holds the connection. */
78
+ maxResultBytes,
91
79
  /** The call's span context (R7.4), sent as `traceparent` where this process holds the connection. */
92
80
  traceparent) {
93
- const tool = mcpToolOf(routing.mcpSnapshot, request);
94
- if (!tool)
95
- throw new Error(`MCP tool '${request.toolName ?? ""}' is not in the session snapshot`);
81
+ // The call names its tool by its identity (protocol 15): the server, and its own name there.
82
+ const target = request.target;
83
+ if (target?.kind !== "mcp")
84
+ throw new Error(`'${request.toolName ?? ""}' is not an MCP tool call`);
96
85
  return mcp.call({
97
86
  sessionId: request.sessionId,
98
- ...(tool.agentId === undefined ? {} : { agentId: tool.agentId }),
99
- serverName: tool.serverName,
100
- serverToolName: tool.serverToolName,
87
+ ...(request.agent === undefined ? {} : { agentId: request.agent.id }),
88
+ serverName: target.server,
89
+ serverToolName: target.tool,
101
90
  args: request.input,
102
91
  manifest: routing.rootManifest,
103
92
  effectId: request.effectId,
104
93
  ...(traceparent ? { traceparent } : {}),
94
+ maxResultBytes,
105
95
  signal,
106
96
  });
107
97
  }
@@ -123,17 +113,21 @@ traceparent) {
123
113
  ...(traceparent ? { traceparent } : {}),
124
114
  }, signal);
125
115
  }
126
- export async function callSandboxTool(sandbox, routing, request, signal) {
127
- const spec = sandboxToolSpec(manifestFor(routing.rootManifest, request.agent), request.toolName);
116
+ /**
117
+ * Runs a `sandbox` call: the operation it names, in the session's sandbox (the one its agents
118
+ * used as tools share), held to the harness's sandbox tool limits.
119
+ */
120
+ export async function callSandboxTool(sandbox, routing, request, signal, limits) {
121
+ const { spec } = routing;
128
122
  if (!spec)
129
- throw new Error(`'${request.toolName ?? ""}' is not a sandbox tool`);
130
- // Agents used as tools share the session's sandbox; the tree declares one sandbox spec.
123
+ throw new Error(`This session has no sandbox to run '${request.toolName ?? ""}' in`);
124
+ if (request.toolName === undefined || !isSandboxToolName(request.toolName))
125
+ throw new Error(`'${request.toolName ?? ""}' is not a sandbox operation`);
131
126
  return sandbox.run({
132
127
  id: routing.sandboxOwnerId,
133
128
  activeTurnId: routing.activeTurnId,
134
- manifest: routing.rootManifest,
135
129
  ...(routing.environmentId === undefined ? {} : { environmentId: routing.environmentId }),
136
130
  ...(routing.environment === undefined ? {} : { environment: routing.environment }),
137
131
  ...(routing.claim === undefined ? {} : { claim: routing.claim }),
138
- }, spec, request.toolName, request.input, signal);
132
+ }, spec, request.toolName, request.input, signal, limits);
139
133
  }
@@ -1,3 +1,4 @@
1
+ import { type SandboxToolLimits } from "@nylorun/harness";
1
2
  import type { HarnessExecutors, HarnessRun, McpRecorder, PreparedRun } from "@nylorun/harness/api";
2
3
  import type { ToolGate } from "../gates/tool-gate.js";
3
4
  import { type McpPool } from "../mcp/pool.js";
@@ -10,12 +11,18 @@ export interface HarnessExecutorsOptions {
10
11
  readonly mcp: McpPool;
11
12
  /** The SandboxManager; a harness process creates it once `hello` names the Tenant. */
12
13
  readonly sandbox: () => SandboxManager;
14
+ /**
15
+ * The sandbox tools' limits the calls run with: the harness's configuration, the same it gives
16
+ * `createHarness({ sandboxTools })`. Each left out is its default.
17
+ */
18
+ readonly sandboxTools?: Partial<SandboxToolLimits>;
13
19
  }
14
20
  export declare function harnessExecutors(options: HarnessExecutorsOptions): HarnessExecutors;
15
21
  /**
16
- * Readies the run's MCP servers (§10.5 step 3): the first segment of a session discovers their
17
- * tools and records the snapshot (the first recorded wins); later ones reconnect them and record
18
- * what failed. Nothing for a session without MCP servers.
22
+ * Readies the run's MCP servers (§10.5 step 3): a run without MCP facts (`turn.start.mcp`, the
23
+ * session's first) discovers their tools and records the snapshot (the first recorded wins);
24
+ * later ones reconnect the snapshot's servers and record what failed. Answers the facts the run
25
+ * goes on with. Nothing for a session without MCP servers.
19
26
  */
20
27
  export declare function prepareMcp(pool: McpPool, run: HarnessRun, record: McpRecorder): Promise<PreparedRun | undefined>;
21
28
  /** A run's routing, as the call helpers take it. Its sandbox events are claimed for the run. */
@@ -8,36 +8,42 @@
8
8
  * (`--service harness`, `main.ts`) its own, whose sandbox events it claims from core.
9
9
  */
10
10
  import { hashManifest } from "@nylorun/core/define";
11
+ import { sandboxToolLimitsOf } from "@nylorun/harness";
11
12
  import { GateCallLost } from "../gates/tool-client.js";
12
13
  import { serversOf } from "../mcp/pool.js";
13
- import { mcpToolOf } from "../mcp/snapshot.js";
14
14
  import { isHttpToolCall } from "../gates/http-tool.js";
15
- import { abortOn, callHttpTool, callMcpTool, callSandboxTool, invokeModel, isRemoteMcpCall, isSaveArtifactCall, } from "./calls.js";
15
+ import { abortOn, callHttpTool, callMcpTool, callSandboxTool, invokeModel, isRemoteMcpCall, } from "./calls.js";
16
16
  export function harnessExecutors(options) {
17
17
  const recoversTools = options.toolGate.recovers === true;
18
+ const sandboxTools = sandboxToolLimitsOf(options.sandboxTools);
18
19
  const atGate = (effect, run) => {
19
20
  const routing = routingOf(run);
20
21
  return isRemoteMcpCall(routing, effect) || isHttpToolCall(routing.rootManifest, effect);
21
22
  };
22
23
  const recovered = (effect, run) => recoversTools && atGate(effect, run);
23
24
  return {
24
- // With the Tenant's fixture model on, the Model Gate answers it (R4.3), metered like any call.
25
- model: (effect, signal, run) => invokeModel(options.model, effect, signal, { atGate: run.start.options.fixtureModel }),
25
+ // Every call goes through the Model Gate (protocol 15); with the Tenant's fixture model on,
26
+ // the gate answers it (R4.3), metered like any call.
27
+ model: (effect, signal) => invokeModel(options.model, effect, signal),
26
28
  tool(effect, signal, run, call) {
27
29
  const routing = routingOf(run);
28
30
  const traceparent = call?.traceparent;
29
31
  // A call at the Tool Gate outlives a shutdown there; a local one finishes and is recorded.
30
32
  const kinds = recovered(effect, run) ? ["cancel", "shutdown"] : ["cancel"];
33
+ // A call is routed by what it names as its target (protocol 15); a flow's HTTP stage names
34
+ // its stage.
31
35
  if (isHttpToolCall(routing.rootManifest, effect))
32
36
  return callHttpTool(options.toolGate, effect, abortOn(signal, kinds), traceparent);
33
37
  // A sandbox command joins its call's span (R7.4): a CLI that reads TRACEPARENT traces under it.
34
- if (!mcpToolOf(routing.mcpSnapshot, effect))
35
- return callSandboxTool(options.sandbox(), traceparent ? { ...routing, environment: { ...routing.environment, TRACEPARENT: traceparent } } : routing, effect, signal);
36
- return callMcpTool(options.mcp, routing, effect, abortOn(signal, kinds), traceparent);
38
+ if (effect.target?.kind === "sandbox")
39
+ return callSandboxTool(options.sandbox(), traceparent ? { ...routing, environment: { ...routing.environment, TRACEPARENT: traceparent } } : routing, effect, signal, sandboxTools);
40
+ if (effect.target?.kind !== "mcp")
41
+ throw new Error(`This harness runs no ${effect.target?.kind ?? "untargeted"} call of '${effect.toolName ?? ""}'`);
42
+ return callMcpTool(options.mcp, routing, effect, abortOn(signal, kinds), run.start.limits.toolAnswerBytes, traceparent);
37
43
  },
38
44
  recovers: {
39
45
  get model() {
40
- return options.model.useVaultModel && options.model.modelGate.recovers === true;
46
+ return options.model.modelGate.recovers === true;
41
47
  },
42
48
  tool: recovered,
43
49
  },
@@ -51,12 +57,42 @@ export function harnessExecutors(options) {
51
57
  });
52
58
  },
53
59
  prepare: (run, record) => prepareMcp(options.mcp, run, record),
60
+ files: {
61
+ read: (run, path, maxBytes, signal) => withSandbox(run, (session, spec) => options.sandbox().readBytes(session, spec, path, maxBytes, signal)),
62
+ write: (run, path, body, signal) => withSandbox(run, (session, spec) => options.sandbox().writeBytes(session, spec, path, body, signal)),
63
+ list: (run, dir, maxEntries, signal) => withSandbox(run, async (session, spec) => {
64
+ const listed = await options.sandbox().listFiles(session, spec, dir, maxEntries, signal);
65
+ return listed.kind === "listed"
66
+ ? { kind: "listed", entries: listed.listing.entries, truncated: listed.listing.truncated }
67
+ : listed.kind === "missing"
68
+ ? { kind: "missing" }
69
+ : listed;
70
+ }),
71
+ mount: (run, folder, files, read, signal) => withSandbox(run, (session, spec) => options.sandbox().mountFolder(session, spec, folder, files, read, signal)),
72
+ },
54
73
  };
55
74
  }
56
75
  /**
57
- * Readies the run's MCP servers (§10.5 step 3): the first segment of a session discovers their
58
- * tools and records the snapshot (the first recorded wins); later ones reconnect them and record
59
- * what failed. Nothing for a session without MCP servers.
76
+ * Runs `use` on the run's sandbox (the session's, which its agents used as tools share), or
77
+ * answers `artifact.no_sandbox` for a session without one.
78
+ */
79
+ async function withSandbox(run, use) {
80
+ const routing = routingOf(run);
81
+ const { spec } = routing;
82
+ if (spec === undefined)
83
+ return { kind: "failed", code: "artifact.no_sandbox", message: "This session has no sandbox." };
84
+ return use({
85
+ id: routing.sandboxOwnerId,
86
+ activeTurnId: routing.activeTurnId,
87
+ ...(routing.environmentId === undefined ? {} : { environmentId: routing.environmentId }),
88
+ ...(routing.claim === undefined ? {} : { claim: routing.claim }),
89
+ }, spec);
90
+ }
91
+ /**
92
+ * Readies the run's MCP servers (§10.5 step 3): a run without MCP facts (`turn.start.mcp`, the
93
+ * session's first) discovers their tools and records the snapshot (the first recorded wins);
94
+ * later ones reconnect the snapshot's servers and record what failed. Answers the facts the run
95
+ * goes on with. Nothing for a session without MCP servers.
60
96
  */
61
97
  export async function prepareMcp(pool, run, record) {
62
98
  const routing = routingOf(run);
@@ -65,38 +101,32 @@ export async function prepareMcp(pool, run, record) {
65
101
  return undefined;
66
102
  const sessionId = run.grant.sessionId;
67
103
  let answer;
68
- if (!routing.mcpSnapshot) {
104
+ const facts = run.start.mcp;
105
+ if (!facts) {
69
106
  const found = await pool.discover({
70
107
  sessionId,
71
108
  manifest,
72
109
  manifestHash: hashManifest(manifest),
110
+ maxInstructionBytes: run.start.limits.recordEntryBytes,
73
111
  signal: run.signal,
74
112
  });
75
113
  answer = await record({ snapshot: found.snapshot, diagnostics: found.diagnostics });
76
114
  }
77
115
  else {
78
- const diagnostics = await pool.reconnect({
79
- sessionId,
80
- manifest,
81
- tools: routing.mcpSnapshot.mcpTools,
82
- signal: run.signal,
83
- });
116
+ const diagnostics = await pool.reconnect({ sessionId, manifest, servers: facts.servers, signal: run.signal });
84
117
  if (diagnostics.length === 0)
85
118
  return undefined;
86
119
  answer = await record({ diagnostics });
87
120
  }
88
- return {
89
- sessionTools: answer.sessionTools,
90
- ...(answer.snapshot === undefined ? {} : { mcpSnapshot: answer.snapshot }),
91
- };
121
+ return answer.mcp === undefined ? undefined : { mcp: answer.mcp };
92
122
  }
93
123
  /** A run's routing, as the call helpers take it. Its sandbox events are claimed for the run. */
94
124
  export function routingOf(run) {
95
125
  const { routing } = run.start;
96
126
  return {
97
127
  rootManifest: routing.rootManifest,
98
- ...(routing.mcpSnapshot ? { mcpSnapshot: routing.mcpSnapshot } : {}),
99
128
  sandboxOwnerId: routing.sandbox?.ownerId ?? run.grant.sessionId,
129
+ ...(routing.sandbox?.spec === undefined ? {} : { spec: routing.sandbox.spec }),
100
130
  ...(routing.sandbox?.environmentId === undefined ? {} : { environmentId: routing.sandbox.environmentId }),
101
131
  ...(routing.sandbox?.environment === undefined ? {} : { environment: routing.sandbox.environment }),
102
132
  activeTurnId: run.grant.turnId,
@@ -28,6 +28,7 @@ import { podHost } from "./pod.js";
28
28
  import { prepareDisk } from "./setup.js";
29
29
  import { harnessRunTokens } from "./run-tokens.js";
30
30
  import { startHarnessService } from "./service.js";
31
+ import { hostTuning } from "../tuning.js";
31
32
  /**
32
33
  * `baseline` is the allowlisted environment of a pod's sandbox tools (`baselineEnvironment`),
33
34
  * read by `host/main.ts`: nothing here reads the process environment.
@@ -77,7 +78,6 @@ export async function runHarness(stack, baseline) {
77
78
  : {}),
78
79
  paths,
79
80
  modelGate: httpModelGate({ url: config.gatesUrl, runTokens }),
80
- useVaultModel: true,
81
81
  toolGate: httpToolGate({ url: config.gatesUrl, runTokens }),
82
82
  logger,
83
83
  version: RUNTIME_VERSION,
@@ -107,7 +107,7 @@ export async function runHarness(stack, baseline) {
107
107
  // Runs are given back (core resumes them in its next advance), then MCP and sandboxes stop.
108
108
  pod?.stop();
109
109
  void service
110
- .stop(pod ? 7_000 : 10_000)
110
+ .stop(pod ? hostTuning().harness.podStopMs : hostTuning().harness.stopMs)
111
111
  .catch((error) => logger.warn("harness_stop_failed", { message: error instanceof Error ? error.message : String(error) }))
112
112
  .finally(() => {
113
113
  health.close();
@@ -1,9 +1,9 @@
1
1
  import type { PodHostConfig } from "../host/stack-config.js";
2
- /** How often the host and egress tokens are renewed. */
3
- export declare const RENEW_MS: number;
4
2
  /** What to run and copy on a new disk (`sandbox/setup.ts` in core), from the join answer. */
5
3
  export interface DiskSetup {
6
4
  readonly recipeVersion: number;
5
+ /** The sha256 of the commands and files (track T3): a marker with another runs the setup again. */
6
+ readonly setupHash?: string;
7
7
  readonly commands: readonly {
8
8
  readonly command: string;
9
9
  readonly cwd: string;
@@ -15,8 +15,7 @@ import { randomUUID } from "node:crypto";
15
15
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
16
16
  import { rootCertificates } from "node:tls";
17
17
  import { dirname } from "node:path";
18
- /** How often the host and egress tokens are renewed. */
19
- export const RENEW_MS = 5 * 60_000;
18
+ import { hostTuning } from "../tuning.js";
20
19
  /** The variables CLIs read their trust bundle from: OpenSSL, Node, Python, curl, git, AWS. */
21
20
  const TRUST_VARIABLES = [
22
21
  "SSL_CERT_FILE",
@@ -44,7 +43,7 @@ export function podHost(config, logger, options = {}) {
44
43
  ...(init.bearer ? { authorization: `Bearer ${init.bearer}` } : {}),
45
44
  },
46
45
  ...(init.body === undefined ? {} : { body: JSON.stringify(init.body) }),
47
- signal: AbortSignal.timeout(15_000),
46
+ signal: AbortSignal.timeout(hostTuning().harness.podJoinTimeoutMs),
48
47
  });
49
48
  const text = await response.text();
50
49
  if (response.status === 401 || response.status === 400)
@@ -109,11 +108,13 @@ export function podHost(config, logger, options = {}) {
109
108
  };
110
109
  /** A request with a current host token: the held one, renewed near expiry, or a new join. */
111
110
  const authorized = async (path, init) => {
112
- const current = held && held.expiresAt - Date.now() > 60_000 ? held : ((await renew()) ?? (await join()));
111
+ const current = held && held.expiresAt - Date.now() > hostTuning().harness.podRenewEarlyMs
112
+ ? held
113
+ : ((await renew()) ?? (await join()));
113
114
  return call(`${config.httpUrl}/nylorun/harness/v1/host/${path}`, {
114
115
  ...init,
115
116
  headers: { ...init.headers, authorization: `Bearer ${current.hostToken}` },
116
- signal: AbortSignal.timeout(5 * 60_000),
117
+ signal: AbortSignal.timeout(hostTuning().harness.podRequestTimeoutMs),
117
118
  });
118
119
  };
119
120
  const renew = async () => {
@@ -134,7 +135,7 @@ export function podHost(config, logger, options = {}) {
134
135
  };
135
136
  const timer = setInterval(() => {
136
137
  void renew().catch((error) => logger.warn("sandbox_host_renew_failed", { message: error instanceof Error ? error.message : String(error) }));
137
- }, options.renewMs ?? RENEW_MS);
138
+ }, options.renewMs ?? hostTuning().harness.podRenewMs);
138
139
  timer.unref();
139
140
  return {
140
141
  async token() {
@@ -14,5 +14,8 @@ export interface HarnessRunTokens {
14
14
  /** Keeps a run's grant: `createHarness({ onGrant })`. */
15
15
  grant(grant: RunGrant): void;
16
16
  }
17
- /** Remembers the last token of at most `limit` sessions (least recently granted dropped first). */
17
+ /**
18
+ * Remembers the last token of at most `limit` sessions (least recently granted dropped first).
19
+ * Default `harness.runTokensMax` (Host tuning, 10,000).
20
+ */
18
21
  export declare function harnessRunTokens(limit?: number): HarnessRunTokens;
@@ -1,5 +1,9 @@
1
- /** Remembers the last token of at most `limit` sessions (least recently granted dropped first). */
2
- export function harnessRunTokens(limit = 10_000) {
1
+ import { hostTuning } from "../tuning.js";
2
+ /**
3
+ * Remembers the last token of at most `limit` sessions (least recently granted dropped first).
4
+ * Default `harness.runTokensMax` (Host tuning, 10,000).
5
+ */
6
+ export function harnessRunTokens(limit = hostTuning().harness.runTokensMax) {
3
7
  const tokens = new Map();
4
8
  return {
5
9
  token: (sessionId) => tokens.get(sessionId),