@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
@@ -16,6 +16,9 @@
16
16
  * workspace request it is serving acts for; a `sandbox.state` claim's record becomes the
17
17
  * workspace's row in the `sandboxes` table.
18
18
  *
19
+ * Protocol 15: a harness reads and writes its run's session's artifacts over the artifact seam
20
+ * (`artifact.read`, `artifact.write`, `./artifacts.ts`); a run's open uploads end with it.
21
+ *
19
22
  * F7.2: a pod sandbox's engine connects as that sandbox's *host* (`HarnessPeer.host`, from its
20
23
  * host token): it leases only runs whose session is attached to its sandbox (`RunOffer.pod`),
21
24
  * serves only that sandbox's workspace (`workspace(..., { pod })`), and claims events only for
@@ -25,20 +28,24 @@
25
28
  * `connection.lost`.
26
29
  */
27
30
  import { randomUUID } from "node:crypto";
28
- import { DEFAULT_HARNESS, HARNESS_API_VERSION, HARNESS_CLAIMS, MAX_HARNESS_STATE_BYTES, isHarnessId, HarnessApiError, } from "@nylorun/core/harness-api";
29
- import { definitionFilesOf } from "@nylorun/core/contracts";
30
- import { TOOL_CALL_TOOL, TOOL_SEARCH_TOOL, delegatesOf, } from "@nylorun/core/define";
31
+ import { DEFAULT_HARNESS, HARNESS_API_VERSION, HARNESS_CLAIMS, isHarnessId, HarnessApiError, } from "@nylorun/core/harness-api";
32
+ import { definitionFilesOf, limitExceededMessage } from "@nylorun/core/contracts";
31
33
  import { isOwnershipLost } from "../store/ownership.js";
32
34
  import { harnessOf, ownedSession } from "../tenant/context.js";
33
- import { mcpDiscovered, pinDeferral, sessionToolsOf, } from "../mcp/snapshot.js";
34
- import { contextWindowOf } from "../model/catalog.js";
35
+ import { fitSnapshot, isSnapshot, mcpDiscovered, mcpFactsOf, } from "../mcp/snapshot.js";
35
36
  import { turnManifestOf } from "../tenant/session.js";
37
+ import { readRuntimeLimits } from "../tenant/runtime-limits.js";
36
38
  import { sandboxWorkspaceKey, workspacePrefix } from "../sandbox/records.js";
37
39
  import { abortKind } from "../tenant/worker.js";
38
- import { readDefinitionFile } from "../tenant/definition-files.js";
40
+ import { BlobRangeError } from "../blob/index.js";
41
+ import { openDefinitionFile, readDefinitionFile } from "../tenant/definition-files.js";
39
42
  import { recordIntent, recordOutcome } from "./record.js";
43
+ import { createArtifactSeam } from "./artifacts.js";
44
+ import { RecordEntryTooLargeError } from "../record/index.js";
40
45
  import { redactTokens } from "./redact.js";
41
46
  import { beat, renewEveryMs, tokenOf } from "./renew.js";
47
+ import { hostTuning } from "../tuning.js";
48
+ import { passStartCheck } from "../tenant/agent-versions.js";
42
49
  /** No attached harness serves workspaces (or, with `pod`, that pod sandbox's). */
43
50
  export class NoWorkspaceHarness extends Error {
44
51
  pod;
@@ -60,11 +67,12 @@ const OUTPUTS = [
60
67
  "checkpoint",
61
68
  ];
62
69
  export function createHarnessApiServer(ctx, options = {}) {
63
- const offerWaitMs = options.offerWaitMs ?? 10_000;
70
+ const offerWaitMs = options.offerWaitMs ?? hostTuning().harnessApi.offerWaitMs;
64
71
  const connections = new Set();
65
72
  const waiting = [];
66
73
  const queued = [];
67
74
  const runs = new Map();
75
+ const artifacts = createArtifactSeam(ctx);
68
76
  let closed = false;
69
77
  /**
70
78
  * A harness may take a run of its own harness id (R4.1): a pod sandbox's host its sandbox's
@@ -81,15 +89,6 @@ export function createHarnessApiServer(ctx, options = {}) {
81
89
  continue;
82
90
  }
83
91
  queued.splice(i, 1);
84
- const clash = nativeToolClashes(waiting[at].connection.tools, run.offer.start);
85
- if (clash.length > 0) {
86
- // The harness keeps waiting for a run its tools fit; this turn fails (Harness API 3).
87
- run.end({
88
- kind: "refused",
89
- message: `Harness '${waiting[at].connection.harness}' runs tools named like tools of this turn's agents: ${clash.join(", ")}. A tool the harness runs itself needs a name no other tool of the session has.`,
90
- });
91
- continue;
92
- }
93
92
  const lease = waiting.splice(at, 1)[0];
94
93
  run.connection = lease.connection;
95
94
  // The run token the advance holds now (F5): the gate calls of this run present it.
@@ -111,11 +110,18 @@ export function createHarnessApiServer(ctx, options = {}) {
111
110
  evidence: "claimed",
112
111
  ...(runId === undefined ? {} : { runId }),
113
112
  });
113
+ /** What the artifact seam serves a run: its session and turn, its limits, its signal. */
114
+ const artifactScope = (run) => ({
115
+ runId: run.grant.runId,
116
+ sessionId: run.grant.sessionId,
117
+ turnId: run.grant.turnId,
118
+ limits: run.offer.start.limits,
119
+ runSignal: run.offer.controller.signal,
120
+ });
114
121
  const scope = (run) => ({
115
122
  ctx,
116
123
  lease: run.offer.lease,
117
124
  signal: run.offer.controller.signal,
118
- ...(run.connection?.tools ? { nativeTools: run.connection.tools } : {}),
119
125
  ...(run.connection ? { writer: writerOf(run.connection, run.grant.runId) } : {}),
120
126
  });
121
127
  const serve = (connection) => async (method, params, signal) => {
@@ -127,8 +133,6 @@ export function createHarnessApiServer(ctx, options = {}) {
127
133
  throw new HarnessApiError("invalid", `unsupported Harness API version ${api}: this Runtime speaks ${HARNESS_API_VERSION}`);
128
134
  connection.harness = await harnessIdOf(connection, name);
129
135
  connection.workspace = features.workspace !== undefined;
130
- if (features.tools?.length)
131
- connection.tools = new Set(features.tools.map((tool) => tool.name));
132
136
  return {
133
137
  api: HARNESS_API_VERSION,
134
138
  tenantId: ctx.config.tenantId,
@@ -181,7 +185,11 @@ export function createHarnessApiServer(ctx, options = {}) {
181
185
  case "session.mcp":
182
186
  return recordMcp(run, p);
183
187
  case "definition.file":
184
- return definitionFile(run, p.sha256, signal);
188
+ return definitionFile(run, p, signal);
189
+ case "artifact.read":
190
+ return artifacts.read(artifactScope(run), p, signal);
191
+ case "artifact.write":
192
+ return artifacts.write(artifactScope(run), p, signal);
185
193
  default:
186
194
  throw new HarnessApiError("invalid", `Unknown request ${method}`);
187
195
  }
@@ -204,6 +212,9 @@ export function createHarnessApiServer(ctx, options = {}) {
204
212
  const expected = environment?.applied.harness ?? DEFAULT_HARNESS;
205
213
  if (expected !== name)
206
214
  throw new HarnessApiError("invalid", `Environment ${connection.host.sandboxId} runs the ${expected} harness, and this pod says ${name}`);
215
+ // Its pod started on the version it switched to, setup done (track T3): the start check passed.
216
+ if (environment?.startCheck)
217
+ await passStartCheck(ctx, connection.host.sandboxId, connection.host.epoch);
207
218
  }
208
219
  return name;
209
220
  };
@@ -211,7 +222,8 @@ export function createHarnessApiServer(ctx, options = {}) {
211
222
  * A `sandbox.*` event the harness claims: for a run it holds (the run's session, or the
212
223
  * session owning its sandbox), or a session one of its workspace requests acts for. A
213
224
  * `sandbox.state` record becomes the workspace's `sandboxes` row. Claims are best effort, as
214
- * the events of core's own SandboxManager are: a session gone since is skipped.
225
+ * the events of core's own SandboxManager are: a session gone since is skipped. One past the
226
+ * Tenant's `recordEntryBytes` is refused (`limit_exceeded`).
215
227
  */
216
228
  const claim = async (connection, event) => {
217
229
  if (!HARNESS_CLAIMS.includes(event.type))
@@ -240,6 +252,9 @@ export function createHarnessApiServer(ctx, options = {}) {
240
252
  });
241
253
  }
242
254
  catch (error) {
255
+ // Past the record entry limit is the harness's to hear (`limit_exceeded`), not a lost claim.
256
+ if (error instanceof RecordEntryTooLargeError)
257
+ throw error;
243
258
  ctx.config.logger.warn("harness event claim not recorded", {
244
259
  sessionId: event.sessionId,
245
260
  type: event.type,
@@ -250,22 +265,23 @@ export function createHarnessApiServer(ctx, options = {}) {
250
265
  };
251
266
  /**
252
267
  * What a harness found readying the run's MCP servers: the first snapshot recorded for the
253
- * session wins, with `mcp.discovered` in its log; diagnostics replace those of the same server.
254
- * Answers the session's snapshot and the tools the engine advertises.
268
+ * session wins, pinned as it is within the Tenant's Runtime limit `mcpSnapshotBytes` (a server
269
+ * past it is left out, with a diagnostic: `fitSnapshot`), with `mcp.discovered` in its log;
270
+ * diagnostics replace those of the same server. Answers the session's facts as the run's turn
271
+ * sees them (protocol 15).
255
272
  */
256
273
  const recordMcp = async (run, params) => {
257
274
  const snapshot = params.snapshot;
258
275
  if (snapshot !== undefined && !isSnapshot(snapshot))
259
276
  throw new HarnessApiError("invalid", "The MCP snapshot is malformed");
260
- // Which MCP tools the model reaches through tool_search, decided once for the session from
261
- // the Tenant's model's context window (R2b C10, Q21).
262
- const contextWindow = snapshot ? contextWindowOf(await ctx.vault.getHostModel()) : 0;
263
277
  return ctx.store.tx(async (t) => {
264
278
  const { lease } = run.offer;
265
279
  const current = await ownedSession(t, lease, lease.sessionId);
266
- const diagnostics = params.diagnostics;
280
+ let diagnostics = params.diagnostics;
267
281
  if (snapshot && !current.mcpSnapshot) {
268
- current.mcpSnapshot = pinDeferral(snapshot, current.manifest, contextWindow);
282
+ const fitted = fitSnapshot(snapshot, diagnostics, (await readRuntimeLimits(t)).mcpSnapshotBytes);
283
+ diagnostics = fitted.diagnostics;
284
+ current.mcpSnapshot = fitted.snapshot;
269
285
  current.mcpDiagnostics = diagnostics;
270
286
  await t.put("sessions", current.id, current);
271
287
  await t.event(current.id, run.grant.turnId, "mcp.discovered", mcpDiscovered(current.mcpSnapshot, diagnostics, current.manifest), run.connection ? writerOf(run.connection, run.grant.runId) : undefined);
@@ -282,27 +298,48 @@ export function createHarnessApiServer(ctx, options = {}) {
282
298
  current.mcpDiagnostics = prior;
283
299
  await t.put("sessions", current.id, current);
284
300
  }
285
- return {
286
- ...(current.mcpSnapshot ? { snapshot: current.mcpSnapshot } : {}),
287
- // The turn's manifest: a variant may have disabled tools or required their approval.
288
- sessionTools: [...(sessionToolsOf(current.mcpSnapshot, turnManifestOf(current)) ?? [])],
289
- };
301
+ // The turn's manifest: a variant may have disabled tools.
302
+ return current.mcpSnapshot ? { mcp: mcpFactsOf(current.mcpSnapshot, turnManifestOf(current)) } : {};
290
303
  });
291
304
  };
292
- /** A definition file the run's definition names (its skills', for its sandbox), base64. */
293
- const definitionFile = async (run, sha256, signal) => {
305
+ /**
306
+ * A definition file the run's definition names (its skills', for its sandbox), base64: whole,
307
+ * or the range `offset` and `length` name (none past the end), at most the run's
308
+ * `limits.chunkBytes`, which is also the length when the harness names none.
309
+ */
310
+ const definitionFile = async (run, { sha256, offset, length }, signal) => {
294
311
  if (!definitionFilesOf(run.offer.start.routing.rootManifest).has(sha256))
295
312
  throw new HarnessApiError("invalid", `The run's definition names no file ${sha256}`);
296
- const bytes = await readDefinitionFile(ctx.blobs, sha256, signal);
297
- if (!bytes)
298
- throw new HarnessApiError("unavailable", `The Object store has no bytes for ${sha256}`);
299
- return { base64: Buffer.from(bytes).toString("base64") };
313
+ const missing = () => new HarnessApiError("unavailable", `The Object store has no bytes for ${sha256}`);
314
+ if (offset === undefined && length === undefined) {
315
+ const bytes = await readDefinitionFile(ctx.blobs, sha256, signal);
316
+ if (!bytes)
317
+ throw missing();
318
+ return { base64: Buffer.from(bytes).toString("base64") };
319
+ }
320
+ const { chunkBytes } = run.offer.start.limits;
321
+ if (length !== undefined && length > chunkBytes)
322
+ throw new HarnessApiError("limit_exceeded", limitExceededMessage("The range asked for", length, "chunkBytes", chunkBytes));
323
+ const start = offset ?? 0;
324
+ const end = start + (length ?? chunkBytes) - 1;
325
+ let body;
326
+ try {
327
+ body = await openDefinitionFile(ctx.blobs, sha256, { range: { start, end }, signal });
328
+ }
329
+ catch (error) {
330
+ if (error instanceof BlobRangeError)
331
+ return { base64: "" };
332
+ throw error;
333
+ }
334
+ if (!body)
335
+ throw missing();
336
+ return { base64: Buffer.from(await new Response(body).arrayBuffer()).toString("base64") };
300
337
  };
301
338
  /**
302
339
  * A custom harness's output (R4.2): its state is its own, stored as sent and never read, so it
303
- * must be JSON and at most `MAX_HARNESS_STATE_BYTES`; a larger one fails the turn, as an engine
304
- * that threw would. It cannot pause for approvals in v2 (Q14): approvals read our engine's plan
305
- * until R5 makes them core holds.
340
+ * must be JSON and at most the run's `limits.harnessStateBytes`; a larger one fails the turn
341
+ * (`limit_exceeded`), as an engine that threw would. It cannot pause for approvals in v2 (Q14):
342
+ * approvals read our engine's plan until R5 makes them core holds.
306
343
  */
307
344
  const checkCustomOutput = (run, method, params) => {
308
345
  if (method === "turn.paused")
@@ -310,14 +347,16 @@ export function createHarnessApiServer(ctx, options = {}) {
310
347
  if (params.state === undefined || run.outputs.has(method))
311
348
  return;
312
349
  const bytes = Buffer.byteLength(JSON.stringify(params.state) ?? "");
313
- if (bytes <= MAX_HARNESS_STATE_BYTES)
350
+ const { harnessStateBytes } = run.offer.start.limits;
351
+ if (bytes <= harnessStateBytes)
314
352
  return;
353
+ const message = limitExceededMessage("The harness's state", bytes, "harnessStateBytes", harnessStateBytes);
315
354
  output(run, "turn.failed", {
316
355
  runId: run.grant.runId,
317
356
  status: "failed",
318
- thrown: { code: "invalid", message: `The harness's state is ${bytes} bytes, over ${MAX_HARNESS_STATE_BYTES}` },
357
+ thrown: { code: "limit_exceeded", message },
319
358
  }).catch(() => undefined);
320
- throw new HarnessApiError("invalid", `state over 256 KiB (${bytes} bytes): the turn failed`);
359
+ throw new HarnessApiError("limit_exceeded", `${message} The turn failed.`);
321
360
  };
322
361
  const output = (run, method, params) => {
323
362
  const known = run.outputs.get(method);
@@ -455,6 +494,8 @@ export function createHarnessApiServer(ctx, options = {}) {
455
494
  return;
456
495
  run.ended = true;
457
496
  clearTimeout(timer);
497
+ // An upload the run left open commits nothing.
498
+ artifacts.endRun(run.grant.runId);
458
499
  controller.signal.removeEventListener("abort", onAbort);
459
500
  // An output's run stays held until core answers it, so a repeat gets the same answer.
460
501
  if (end.kind === "output") {
@@ -501,31 +542,3 @@ export function createHarnessApiServer(ctx, options = {}) {
501
542
  },
502
543
  };
503
544
  }
504
- function isSnapshot(value) {
505
- const snapshot = value;
506
- return (typeof snapshot === "object" &&
507
- snapshot !== null &&
508
- snapshot.snapshotSchemaVersion === 1 &&
509
- typeof snapshot.manifestHash === "string" &&
510
- Array.isArray(snapshot.mcpTools));
511
- }
512
- /**
513
- * The tools a harness runs itself (`features.tools`) whose names the turn already uses: a tool of
514
- * the turn's agents (their own and the Runtime's `runtime` tools), a session tool, `tool_search` or
515
- * `tool_call` (session tools a later step may get). Tools are known by name alone, so a native
516
- * tool must not take one (Harness API 3); `hello` already refuses a name with `__`, which names an
517
- * MCP server's tools. A flow turn runs no native tools.
518
- */
519
- export function nativeToolClashes(tools, start) {
520
- if (!tools?.size || start.engine !== "agent")
521
- return [];
522
- const manifest = start.manifest;
523
- const taken = new Set([TOOL_SEARCH_TOOL, TOOL_CALL_TOOL]);
524
- for (const agent of [manifest, ...delegatesOf(manifest).map((delegate) => delegate.manifest)])
525
- for (const tool of [...(agent.tools ?? []), ...(agent.runtime?.tools ?? [])])
526
- taken.add(tool.name);
527
- for (const tool of (start.sessionTools ?? []))
528
- if (typeof tool?.name === "string")
529
- taken.add(tool.name);
530
- return [...tools].filter((name) => taken.has(name)).sort();
531
- }
@@ -1,4 +1,5 @@
1
- import type { RecordedOutcome, TurnStart } from "@nylorun/core/harness-api";
1
+ import type { ModelDescriptor, RecordedOutcome, RuntimeLimits, TurnAgent, TurnMemory, TurnStart } from "@nylorun/core/harness-api";
2
+ import { type SandboxManifest } from "@nylorun/core/define";
2
3
  import type { SandboxPodState } from "../store/types.js";
3
4
  import { type Lease, type Session, type TenantContext } from "../tenant/context.js";
4
5
  import { type TraceContext } from "../traces/ids.js";
@@ -6,29 +7,47 @@ import { type TraceContext } from "../traces/ids.js";
6
7
  export interface SegmentStart {
7
8
  readonly current: Session;
8
9
  readonly fixtureModel: boolean;
10
+ /** The Tenant's Runtime limits as the segment starts: what `turn.start.limits` hands the harness. */
11
+ readonly limits: RuntimeLimits;
9
12
  /** The transcript the engine resumes from (agents with state; empty otherwise). */
10
13
  readonly transcript: unknown[];
11
14
  /** The record position of `transcript` (`foldTranscriptWithCursor`). */
12
15
  readonly cursor: number;
13
16
  readonly outcomes: RecordedOutcome[];
14
- /** The session's sandbox workspace: the session, and the Environment whose workspace it is. */
17
+ /** The session's sandbox workspace: the session, and the Agent whose workspace it is. */
15
18
  readonly sandbox: {
16
19
  readonly ownerId: string;
17
20
  readonly environmentId?: string;
18
21
  /** Variables every sandbox command gets (R2c): secret names set to the sentinel, plain values. */
19
22
  readonly environment?: Readonly<Record<string, string>>;
23
+ /** The sandbox spec the session pinned when it opened; absent without a sandbox. */
24
+ readonly spec?: SandboxManifest;
20
25
  };
21
26
  /**
22
- * The Environment is a pod (F7.2): its engine runs the segment. Its lifecycle state, and
23
- * whether its new volume is still being seeded from a disk version (R2d step 3).
27
+ * The Agent the session runs on, as `TurnStart.agent` states it (Harness API 5): its id and
28
+ * kind, and its sandbox's workspace when the session has a sandbox.
29
+ */
30
+ readonly agent?: TurnAgent;
31
+ /**
32
+ * The Agent is a pod (F7.2): its engine runs the segment. Its lifecycle state, and whether its
33
+ * new volume is still being seeded from a disk version (R2d step 3).
24
34
  */
25
35
  readonly pod?: {
26
36
  readonly id: string;
27
37
  readonly pod: SandboxPodState;
28
38
  readonly seeding?: boolean;
39
+ /** It starts on a new version (track T3) and has not joined yet: a failed start goes back. */
40
+ readonly starting?: boolean;
29
41
  };
30
42
  /** The turn's span context (R7.4): what `TurnStart.trace` hands the harness. */
31
43
  readonly trace?: TraceContext;
44
+ /**
45
+ * The model the turn's calls use (protocol 15), as the segment starts: what `TurnStart.model`
46
+ * hands an agent's harness. Absent for a flow, and when the Tenant has no model.
47
+ */
48
+ readonly model?: ModelDescriptor;
49
+ /** The Agent's memory (track T5): its access, instructions and the index the harness pins. */
50
+ readonly memory?: TurnMemory;
32
51
  }
33
52
  /** The segment's starting transaction and fold. */
34
53
  export declare function startSegment(ctx: TenantContext, lease: Lease,
@@ -38,7 +57,10 @@ options?: {
38
57
  }): Promise<SegmentStart>;
39
58
  /** The run's `turn.start`. */
40
59
  export declare function buildTurnStart(ctx: TenantContext, segment: SegmentStart): TurnStart;
41
- /** The engine's yield budget for a segment. */
60
+ /**
61
+ * The engine's yield budget for a segment: the Tenant's `rollover`, else the Host tuning's
62
+ * (`harnessApi.rolloverSteps`, `rolloverMs`), well inside the advance deadline.
63
+ */
42
64
  export declare function yieldAfterOf(ctx: TenantContext): {
43
65
  steps: number;
44
66
  ms: number;
@@ -1,17 +1,31 @@
1
+ /**
2
+ * What a segment starts from (§10.5): in one transaction the session's state is rebased onto
3
+ * the turn's manifest, a transcript still on the row is recorded, and the segment's completed
4
+ * outcomes are read; then the transcript is folded from the record (P0.3). `buildTurnStart`
5
+ * turns that into the run's `turn.start`: the checkpoint goes without its transcript, which the
6
+ * harness holds at the fold's cursor or reads once.
7
+ */
8
+ import { harnessLimitsOf } from "@nylorun/core/contracts";
9
+ import { SANDBOX_WORKSPACE } from "@nylorun/core/define";
1
10
  import { isWorkflowManifest } from "../core/flow-host.js";
2
11
  import { sandboxWorkspaceOf } from "../sandbox/share.js";
3
12
  import { ownedTx } from "../store/ownership.js";
4
13
  import { harnessOf } from "../tenant/context.js";
14
+ import { repinTurn } from "../tenant/agent-versions.js";
5
15
  import { HARNESS_ID } from "../sandbox/placement.js";
6
16
  import { checkParity, foldTranscriptWithCursor, leanState, transcriptOf, transcriptUpdates, withTranscript, } from "../tenant/history.js";
7
17
  import { usesFixtureModel } from "../tenant/model-setting.js";
8
- import { sessionToolsOf, turnManifestOf } from "../tenant/session.js";
18
+ import { currentModelDescriptor } from "../model/descriptor.js";
19
+ import { readRuntimeLimits } from "../tenant/runtime-limits.js";
20
+ import { flowLimitsOf } from "../core/limits.js";
21
+ import { turnManifestOf } from "../tenant/session.js";
22
+ import { mcpFactsOf } from "../mcp/snapshot.js";
9
23
  import { bulkOutcomes } from "./record.js";
24
+ import { renderMemoryIndex } from "../memory/service.js";
25
+ import { memorySettingsOf } from "../memory/tool.js";
10
26
  import { traceKey } from "../traces/key.js";
27
+ import { hostTuning } from "../tuning.js";
11
28
  import { traceparentOf, turnSpanOf, turnTraceIdOf, } from "../traces/ids.js";
12
- /** Segment rollover defaults (Model Calls §10), well inside the advance deadline. */
13
- const ROLLOVER_STEPS = 50;
14
- const ROLLOVER_MS = 20 * 60_000;
15
29
  /** The segment's starting transaction and fold. */
16
30
  export async function startSegment(ctx, lease,
17
31
  /** For a harness: also the segment's outcomes and the sandbox's owner. */
@@ -19,34 +33,58 @@ options = {}) {
19
33
  const id = lease.sessionId;
20
34
  // Read before the transaction: the first read of the Tenant may create the key.
21
35
  const key = options.harness ? await traceKey(ctx.store) : undefined;
22
- const started = await ownedTx(ctx.store, id, lease.epoch, async (t, current) => {
36
+ const opened = await ownedTx(ctx.store, id, lease.epoch, async (t, current) => {
37
+ // A turn's first segment runs the version its Agent runs now (T3, D73).
38
+ if (options.harness && (await repinTurn(t, current)))
39
+ await t.put("sessions", id, current);
23
40
  // A transcript left on our engine's state by an older Runtime is recorded once; another
24
41
  // harness's state is its own (R4.2).
42
+ const limits = await readRuntimeLimits(t);
25
43
  if (!isWorkflowManifest(current.manifest) && current.checkpoint && harnessOf(current) === HARNESS_ID) {
26
- await adoptStoredTranscript(t, current);
44
+ await adoptStoredTranscript(t, current, limits.recordEntryBytes);
27
45
  const cp = current.checkpoint;
28
46
  current.checkpoint = { ...cp, state: current.state };
29
47
  await t.put("sessions", id, current);
30
48
  }
31
49
  const fixtureModel = await usesFixtureModel(t);
32
50
  if (!options.harness)
33
- return { current, fixtureModel, outcomes: [], sandbox: { ownerId: id } };
51
+ return { current, fixtureModel, limits, outcomes: [], sandbox: { ownerId: id } };
34
52
  const workspace = sandboxWorkspaceOf(current);
35
53
  const resource = workspace.environmentId === undefined ? undefined : await t.environment(workspace.environmentId);
36
54
  const environment = await ctx.vault.environmentVariables(t, current.environmentId);
37
- const sandbox = Object.keys(environment).length > 0 ? { ...workspace, environment } : workspace;
55
+ const sandbox = {
56
+ ...workspace,
57
+ ...(Object.keys(environment).length > 0 ? { environment } : {}),
58
+ ...(current.sandbox === undefined ? {} : { spec: current.sandbox }),
59
+ };
38
60
  const turnId = current.activeTurnId;
61
+ const memory = isWorkflowManifest(current.manifest) ? undefined : await turnMemoryOf(t, current, limits);
39
62
  return {
40
63
  current,
41
64
  fixtureModel,
65
+ limits,
66
+ ...(memory ? { memory } : {}),
42
67
  outcomes: current.checkpoint ? await bulkOutcomes(t, current, current.checkpoint) : [],
43
68
  sandbox,
69
+ ...(resource ? { agent: agentOf(resource, current.sandbox, await selfWakeOf(t, current)) } : {}),
44
70
  ...(key && turnId ? { trace: turnContextOf(key, ctx.store.tenantId, current, turnId) } : {}),
45
71
  ...(resource?.pod
46
- ? { pod: { id: resource.id, pod: resource.pod, ...(resource.diskSeed ? { seeding: true } : {}) } }
72
+ ? {
73
+ pod: {
74
+ id: resource.id,
75
+ pod: resource.pod,
76
+ ...(resource.diskSeed ? { seeding: true } : {}),
77
+ ...(resource.startCheck ? { starting: true } : {}),
78
+ },
79
+ }
47
80
  : {}),
48
81
  };
49
82
  });
83
+ // The model an agent's harness decides files by, read outside the session's transaction.
84
+ const model = options.harness && !isWorkflowManifest(opened.current.manifest)
85
+ ? await currentModelDescriptor(ctx)
86
+ : undefined;
87
+ const started = model ? { ...opened, model } : opened;
50
88
  // One history (P0.3): the engine resumes from the transcript folded from the record.
51
89
  const { current } = started;
52
90
  const cp = current.checkpoint;
@@ -76,24 +114,66 @@ export function buildTurnStart(ctx, segment) {
76
114
  checkpoint: !flow && cp.state && harnessOf(current) === HARNESS_ID
77
115
  ? { ...cp, state: withTranscript(cp.state, []) }
78
116
  : cp,
79
- // The turn's manifest: a variant may have disabled MCP tools or required their approval.
80
- ...(flow ? {} : { sessionTools: sessionToolsOf(current.mcpSnapshot, turnManifestOf(current)) ?? [] }),
117
+ // The session's MCP discovery as the turn's manifest sees it: a variant may disable tools.
118
+ ...(!flow && current.mcpSnapshot ? { mcp: mcpFactsOf(current.mcpSnapshot, turnManifestOf(current)) } : {}),
81
119
  outcomes: segment.outcomes,
82
120
  transcript: { cursor: segment.cursor },
83
121
  options: {
84
122
  ...(flow
85
- ? { flowLimits: ctx.flowLimits }
123
+ ? { flowLimits: flowLimitsOf(segment.limits) }
86
124
  : { yieldAfter: yieldAfterOf(ctx) }),
87
125
  fixtureModel: segment.fixtureModel,
88
126
  },
89
127
  routing: {
90
128
  rootManifest: current.manifest,
91
- ...(current.mcpSnapshot ? { mcpSnapshot: current.mcpSnapshot } : {}),
92
129
  sandbox: segment.sandbox,
93
130
  },
94
131
  ...(segment.trace ? { trace: segment.trace } : {}),
132
+ limits: harnessLimitsOf(segment.limits),
133
+ ...(segment.model && !flow ? { model: segment.model } : {}),
134
+ ...(segment.agent && !flow ? { agent: segment.agent } : {}),
135
+ // The agent manifest version the session pinned, and its harness's own settings (protocol 16).
136
+ ...(current.definition === undefined ? {} : { definition: current.definition }),
137
+ ...(current.loop === undefined || flow ? {} : { loop: current.loop }),
138
+ ...(segment.memory && !flow ? { memory: segment.memory } : {}),
139
+ };
140
+ }
141
+ /**
142
+ * The Agent's memory as the segment starts (track T5, D72), when the version the session runs sets
143
+ * `harness.memory`: its access (the same in every turn), the agent's instructions, and the index of
144
+ * its memories, newest first, within the Tenant's index limits.
145
+ */
146
+ async function turnMemoryOf(t, s, limits) {
147
+ const settings = await memorySettingsOf(t, s);
148
+ if (!settings)
149
+ return undefined;
150
+ const { index, truncated } = await renderMemoryIndex(t, s.agentId, limits);
151
+ return {
152
+ access: settings.access ?? "read_write",
153
+ ...(settings.instructions === undefined ? {} : { instructions: settings.instructions }),
154
+ index,
155
+ truncated,
95
156
  };
96
157
  }
158
+ /**
159
+ * The facts of the Agent a session runs on (Harness API 5): its id and kind, and, with the
160
+ * session's sandbox, the workspace its commands start in. The harness words them.
161
+ */
162
+ function agentOf(resource, spec, selfWake) {
163
+ return {
164
+ id: resource.id,
165
+ kind: resource.kind,
166
+ ...(spec === undefined ? {} : { sandbox: { workspace: SANDBOX_WORKSPACE } }),
167
+ ...(selfWake ? { selfWake: true } : {}),
168
+ };
169
+ }
170
+ /** Whether the manifest version the session runs sets `runtime.selfWake` (track T4, D77). */
171
+ async function selfWakeOf(t, s) {
172
+ if (!s.definition)
173
+ return false;
174
+ const version = await t.agentManifest(s.definition.name, s.definition.version);
175
+ return version?.body.runtime?.selfWake === true;
176
+ }
97
177
  /**
98
178
  * The context of turn `turnId`'s span (R7.4): its trace (the caller's when its message carried a
99
179
  * `traceparent`) and its span, as the trace projector derives them, with the caller's
@@ -106,18 +186,21 @@ function turnContextOf(key, tenantId, s, turnId) {
106
186
  ...(s.turnTrace?.tracestate ? { tracestate: s.turnTrace.tracestate } : {}),
107
187
  };
108
188
  }
109
- /** The engine's yield budget for a segment. */
189
+ /**
190
+ * The engine's yield budget for a segment: the Tenant's `rollover`, else the Host tuning's
191
+ * (`harnessApi.rolloverSteps`, `rolloverMs`), well inside the advance deadline.
192
+ */
110
193
  export function yieldAfterOf(ctx) {
111
194
  return {
112
- steps: ctx.config.rollover?.steps ?? ROLLOVER_STEPS,
113
- ms: ctx.config.rollover?.ms ?? ROLLOVER_MS,
195
+ steps: ctx.config.rollover?.steps ?? hostTuning().harnessApi.rolloverSteps,
196
+ ms: ctx.config.rollover?.ms ?? hostTuning().harnessApi.rolloverMs,
114
197
  };
115
198
  }
116
199
  /**
117
200
  * A session written before transcripts were recorded keeps its transcript on its row: record
118
201
  * it once (the turn's starting transcript, then the turn so far), and store the row lean.
119
202
  */
120
- async function adoptStoredTranscript(t, s) {
203
+ async function adoptStoredTranscript(t, s, recordEntryBytes) {
121
204
  if (s.history)
122
205
  return;
123
206
  const now = transcriptOf(s.state);
@@ -131,9 +214,9 @@ async function adoptStoredTranscript(t, s) {
131
214
  first ??= event.seq;
132
215
  }
133
216
  };
134
- await write(null, transcriptUpdates([], start));
217
+ await write(null, transcriptUpdates([], start, recordEntryBytes));
135
218
  if (s.activeTurnId)
136
- await write(s.activeTurnId, transcriptUpdates(start, now));
219
+ await write(s.activeTurnId, transcriptUpdates(start, now, recordEntryBytes));
137
220
  s.history = { from: first ?? 0, snapshot: first ?? 0 };
138
221
  s.state = leanState(s.state);
139
222
  s.turnStartState = leanState(s.turnStartState);
@@ -5,12 +5,13 @@
5
5
  * Delivery (R5.3, R5.4). A tool call is sent at least once, and every send carries its effect
6
6
  * id as the key. After a crash, a shutdown or a lost gate hop, a row still `invoking` is sent
7
7
  * again: an MCP or HTTP tool call (it crosses the Tool Gate, which hands the tool the key) up to
8
- * `MAX_TOOL_ATTEMPTS` sends, then it fails to the model as `tool.interrupted`. A sandbox or
8
+ * the Tenant's Runtime limit `toolAttempts` sends, then it fails to the model as
9
+ * `tool.interrupted`. A sandbox or
9
10
  * core-served call has no key to dedupe on, so a crash fails it to the model at once, and
10
11
  * nothing runs it again (Q2). No tool call leaves its session `uncertain`.
11
12
  *
12
- * The row body keeps the journal's facts: `toolKind`, `server`, `attempts`, `startedAt` and
13
- * `settledAt`. A row written before R5 has none of them.
13
+ * The row body keeps the journal's facts: `toolKind`, `server`, `tool` (the identity, protocol
14
+ * 15), `attempts`, `startedAt` and `settledAt`. A row written before R5 has none of them.
14
15
  *
15
16
  * Spans (R7.1). `tool.completed` also carries the call's effect id, the Tool Gate's own start
16
17
  * and end of its last send (`gate`, from its `tool_crossings` row: MCP and HTTP calls through
@@ -23,8 +24,6 @@ import type { HostEffect } from "@nylorun/harness/run";
23
24
  import type { Session } from "../tenant/context.js";
24
25
  import { type GateTimes, type ToolCallFacts, type ToolCallKind, type ToolCallStatus, type ToolPolicyFact } from "../tenant/transcript.js";
25
26
  import type { EffectDoc, Tx } from "../store/types.js";
26
- /** How many times a tool call is sent before it fails to the model as `tool.interrupted`. */
27
- export declare const MAX_TOOL_ATTEMPTS = 3;
28
27
  /** A tool row's journal facts (R5), kept in its body. */
29
28
  export interface ToolRowFacts {
30
29
  /** Why the Tool Gate held the call for approval, and since when (R5 step 2). */
@@ -40,6 +39,8 @@ export interface ToolRowFacts {
40
39
  };
41
40
  toolKind?: ToolCallKind;
42
41
  server?: string;
42
+ /** The tool's identity: an MCP tool's name on `server`, an HTTP tool's declared name. */
43
+ tool?: string;
43
44
  /** The skill the call ran, and the plugin that brought its skill or MCP server. */
44
45
  skill?: string;
45
46
  plugin?: PluginLabel;
@@ -62,18 +63,22 @@ export type ToolRow = EffectDoc & ToolRowFacts & {
62
63
  };
63
64
  /** Where a tool call runs, and what it traces to (Q7, Q11). */
64
65
  export interface ToolCallPlace {
65
- toolKind: ToolCallKind;
66
+ /** Its target's kind; absent for a call that names none (an author's code tool). */
67
+ toolKind?: ToolCallKind;
66
68
  /** Its MCP server or, for an agent's HTTP tool, its URL's host. */
67
69
  server?: string;
70
+ /** Its identity: an MCP tool's own name on the server, an HTTP tool's declared name. */
71
+ tool?: string;
68
72
  skill?: string;
69
73
  plugin?: PluginLabel;
70
74
  }
71
75
  /**
72
- * Where a tool call runs, and what it traces to: an MCP call names its server and the plugin
73
- * that brought it; a skill tool, or a sandbox tool whose input names `/skills/<name>@<hash>/`, names the
74
- * skill and its plugin. A tool the turn's harness declared (`nativeTools`) runs in the harness.
76
+ * Where a tool call runs, and what it traces to (protocol 15): its target's kind; an MCP call
77
+ * names its identity (server and tool) and the plugin that brought the server, an HTTP call its
78
+ * declared name and its URL's host. The skill the effect names (`skill`: a skill tool's, or a
79
+ * sandbox call in a skill's folder) is kept when the agent has it, with the plugin that brought it.
75
80
  */
76
- export declare function toolKindOf(s: Pick<Session, "manifest" | "mcpSnapshot">, agentManifest: AgentManifest | undefined, request: HostEffect, nativeTools?: ReadonlySet<string>): ToolCallPlace;
81
+ export declare function toolKindOf(s: Pick<Session, "manifest">, agentManifest: AgentManifest | undefined, request: HostEffect): ToolCallPlace;
77
82
  /** The facts a new tool row starts with: its first send, now. */
78
83
  export declare function firstSend(kind: ToolCallPlace, now?: Date): ToolRowFacts;
79
84
  /** A failed outcome the Runtime gives a call a crash interrupted: it may have run. */