@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,17 +16,17 @@ export function mcpRoutes(api) {
16
16
  path: "/v1/tenant/mcp/preview",
17
17
  tags: ["MCP servers"],
18
18
  summary: "Preview an MCP server's tools",
19
- description: "Connects to the remote MCP server at `url` with the credential for that URL in the vault of `environmentId`, if given (its headers and `via`; never an identity header), under the Host's address policy, lists its tools within 15 s and closes the connection. It never calls a tool. Each tool comes with the name the model would call it (`modelName`, made with `name`), its annotations and its input schema's size. A server that answers `401` is `authRequired`, with its RFC 9728 protected-resource metadata when it publishes any: it needs a person's sign-in, so reach it through a gateway (`via`), or with a key. No credential value is in the answer.",
19
+ description: "Connects to the remote MCP server at `url` with the credential for that URL in the vault of the Agent `agentId`, if given (its headers and `via`; never an identity header), under the Host's address policy, lists its tools within 15 s and closes the connection. It never calls a tool. Each tool comes with the name the model would call it (`modelName`, made with `name`), its annotations and its input schema's size. A server that answers `401` is `authRequired`, with its RFC 9728 protected-resource metadata when it publishes any: it needs a person's sign-in, so reach it through a gateway (`via`), or with a key. No credential value is in the answer.",
20
20
  request: {
21
21
  body: { required: true, content: { "application/json": { schema: McpPreviewRequest } } },
22
22
  },
23
23
  responses: {
24
24
  200: json(McpPreview, "The server's tools, or that it needs a credential (`authRequired`)"),
25
- 409: json(Rejected, "The Environment's credential for the URL cannot be used"),
25
+ 409: json(Rejected, "The Agent's credential for the URL cannot be used"),
26
26
  502: json(Rejected, "The server could not be listed (`mcp_preview_failed`): `details.failure` is the code a tool call would have failed with, such as `mcp.unreachable` for an address the Host refuses"),
27
27
  },
28
28
  }, async (c) => {
29
- const request = McpPreviewRequestSchema.parse(await readJson(c.req.raw));
29
+ const request = McpPreviewRequestSchema.parse(await readJson(c));
30
30
  return jsonResponse(200, await c.env.tenant.keys.previewMcp(request));
31
31
  });
32
32
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `GET /v1/me` (Host feature `trusted-issuers`): who the Runtime takes the caller to be, for any
3
3
  * credential that acts on the Tenant. It shows what a trusted issuer's token renders to (its
4
- * subject, scopes, agents and sandbox grants), so an operator can check an identity file, and
4
+ * subject, scopes and Agent grants), so an operator can check an identity file, and
5
5
  * Studio can check a forwarded token for the `studio` scope.
6
6
  */
7
7
  import type { OpenAPIHono } from "@hono/zod-openapi";
@@ -19,7 +19,6 @@ export function describeCaller(scope) {
19
19
  subject: scope.subject,
20
20
  scopes: ordered(scope.scopes),
21
21
  agents: scope.agents === "*" ? "*" : [...scope.agents].sort(),
22
- environments: [...(scope.environments ?? [])],
23
22
  via: `issuer:${scope.issuer}`,
24
23
  };
25
24
  case "management":
@@ -34,7 +33,7 @@ export function meRoutes(api) {
34
33
  path: "/v1/me",
35
34
  tags: ["Access"],
36
35
  summary: "Get who the caller is",
37
- description: "The subject, scopes, agents and sandbox grants of the credential that sends it: an " +
36
+ description: "The subject, scopes and Agent grants of the credential that sends it: an " +
38
37
  "application key (alone or acting for a subject), a management key " +
39
38
  "(`via: management:<principalId>`, no scopes, no agents), or a trusted issuer's token " +
40
39
  "(`via: issuer:<name>`).",
@@ -0,0 +1,9 @@
1
+ /**
2
+ * An Agent's memories (track T5, D72), shaped like Anthropic's memory stores: list, read, write
3
+ * whole, delete, and the versions every change leaves. A memory's path is relative to
4
+ * `/memories`, with `/` percent-encoded (`conventions%2Frelease.md`), as an Agent id is. The
5
+ * caller reaches an Agent's memories as it reaches the Agent; writes are `agents:write`.
6
+ */
7
+ import type { OpenAPIHono } from "@hono/zod-openapi";
8
+ import type { TenantEnv } from "../app.js";
9
+ export declare function memoryRoutes(api: OpenAPIHono<TenantEnv>): void;
@@ -0,0 +1,152 @@
1
+ import { z } from "zod";
2
+ import { isAgentId, PutMemoryRequestSchema } from "@nylorun/core/contracts";
3
+ import { MemoryList, MemoryVersionDetail, MemoryVersionPage, MemoryView, PutMemoryRequest } from "../../components.js";
4
+ import { assertReaches } from "../../../tenant/agents.js";
5
+ import { fail } from "../../../tenant/http.js";
6
+ import { deleteMemoryPath, listMemories, listMemoryVersions, putMemoryContent, readMemory, readMemoryVersion, } from "../../../tenant/memories.js";
7
+ import { readJson } from "../body.js";
8
+ import { tenantRoute } from "../define.js";
9
+ import { pageQuery, pageSize, parseQuery } from "./reads.js";
10
+ import { jsonResponse } from "../respond.js";
11
+ const READ = {
12
+ credentials: ["application", "subject", "token"],
13
+ scopes: ["sessions:own", "agents:read", "agents:write"],
14
+ };
15
+ const WRITE = {
16
+ credentials: ["application", "subject", "token"],
17
+ scopes: ["agents:write"],
18
+ };
19
+ const json = (schema, description) => ({
20
+ description,
21
+ content: { "application/json": { schema } },
22
+ });
23
+ const agentId = z.object({
24
+ agentId: z.string().meta({ description: "The Agent id, percent-encoded" }),
25
+ });
26
+ const memoryPath = agentId.extend({
27
+ path: z.string().meta({
28
+ description: "The memory's path under `/memories`, percent-encoded: `conventions%2Frelease.md` is `/memories/conventions/release.md`",
29
+ }),
30
+ });
31
+ function idOf(value) {
32
+ if (!isAgentId(value))
33
+ return fail(400, "An Agent id is up to 200 characters: /-separated segments of letters, digits, '.', '_' and '-'");
34
+ return value;
35
+ }
36
+ export function memoryRoutes(api) {
37
+ tenantRoute(api, READ, {
38
+ method: "get",
39
+ path: "/v1/agents/{agentId}/memories",
40
+ tags: ["Memory"],
41
+ summary: "List an Agent's memories",
42
+ description: "Its memories by path, each with its size, `content_sha256`, frontmatter `description` and version. `pathPrefix` keeps one folder's (`conventions` for `/memories/conventions/…`).",
43
+ request: {
44
+ params: agentId,
45
+ query: pageQuery.extend({
46
+ pathPrefix: z.string().optional().meta({ description: "Only the memories in this folder, relative to `/memories`" }),
47
+ }),
48
+ },
49
+ responses: { 200: json(MemoryList, "A page of memories") },
50
+ }, async (c) => {
51
+ const id = idOf(c.req.param("agentId"));
52
+ assertReaches(c.get("scope"), id);
53
+ const pathPrefix = c.req.query("pathPrefix");
54
+ const { limit, cursor } = parseQuery(pageQuery, { limit: c.req.query("limit"), cursor: c.req.query("cursor") });
55
+ return jsonResponse(200, await listMemories(c.env.tenant, id, {
56
+ ...(pathPrefix ? { pathPrefix } : {}),
57
+ ...(cursor ? { cursor } : {}),
58
+ limit: await pageSize(c.env.tenant, limit, { fallback: 100 }),
59
+ }));
60
+ });
61
+ tenantRoute(api, READ, {
62
+ method: "get",
63
+ path: "/v1/agents/{agentId}/memories/{path}",
64
+ tags: ["Memory"],
65
+ summary: "Read a memory",
66
+ description: "The memory's content, with its size, `content_sha256`, description and version.",
67
+ request: { params: memoryPath },
68
+ responses: { 200: json(MemoryView, "The memory"), 404: { description: "No memory has this path" } },
69
+ }, async (c) => {
70
+ const id = idOf(c.req.param("agentId"));
71
+ assertReaches(c.get("scope"), id);
72
+ return jsonResponse(200, await readMemory(c.env.tenant, id, c.req.param("path") ?? ""));
73
+ });
74
+ tenantRoute(api, WRITE, {
75
+ method: "put",
76
+ path: "/v1/agents/{agentId}/memories/{path}",
77
+ tags: ["Memory"],
78
+ summary: "Write a memory",
79
+ description: "Creates the memory or replaces its content, as the `memory` tool's `create` does, and records a version with the caller as its actor. This is how an app seeds an Agent's memory. With `contentSha256` the write applies only while the memory still has that content (`\"\"`: only while no memory has the path); otherwise `409 memory_conflict` with the current memory. The path ends in `.md`; the Runtime limits `memoryBytes` (`413`) and `memoriesPerAgent` (`409 limit_exceeded`) hold.",
80
+ request: {
81
+ params: memoryPath,
82
+ body: { required: true, content: { "application/json": { schema: PutMemoryRequest } } },
83
+ },
84
+ responses: {
85
+ 200: json(MemoryView, "The memory as written"),
86
+ 409: { description: "The `contentSha256` precondition no longer holds, or a folder has this path (`memory_conflict`)" },
87
+ 413: { description: "Larger than the Runtime limit `memoryBytes`" },
88
+ },
89
+ }, async (c) => {
90
+ const id = idOf(c.req.param("agentId"));
91
+ const scope = c.get("scope");
92
+ assertReaches(scope, id);
93
+ const body = PutMemoryRequestSchema.safeParse(await readJson(c));
94
+ if (!body.success)
95
+ fail(400, "The body is { content, contentSha256? }", { code: "invalid_request" });
96
+ return jsonResponse(200, await putMemoryContent(c.env.tenant, id, c.req.param("path") ?? "", body.data, scope));
97
+ });
98
+ tenantRoute(api, WRITE, {
99
+ method: "delete",
100
+ path: "/v1/agents/{agentId}/memories/{path}",
101
+ tags: ["Memory"],
102
+ summary: "Delete a memory or a folder",
103
+ description: "Deletes the memory, or every memory in the folder the path names, each with a version that records the delete. Versions stay with the Agent.",
104
+ request: { params: memoryPath },
105
+ responses: {
106
+ 200: json(z.object({ path: z.string(), deleted: z.number().int().nonnegative() }).strict(), "What was deleted"),
107
+ 404: { description: "No memory or folder has this path" },
108
+ },
109
+ }, async (c) => {
110
+ const id = idOf(c.req.param("agentId"));
111
+ const scope = c.get("scope");
112
+ assertReaches(scope, id);
113
+ return jsonResponse(200, await deleteMemoryPath(c.env.tenant, id, c.req.param("path") ?? "", scope));
114
+ });
115
+ tenantRoute(api, READ, {
116
+ method: "get",
117
+ path: "/v1/agents/{agentId}/memory_versions",
118
+ tags: ["Memory"],
119
+ summary: "List an Agent's memory versions",
120
+ description: "Every change to its memories, newest first: the operation, the path (a rename's names its old one), and who made it: `agent:<manifest>@<version>` with the session, turn and trigger run of a turn's write, or the API caller. `path` keeps one memory's.",
121
+ request: {
122
+ params: agentId,
123
+ query: pageQuery.extend({
124
+ path: z.string().optional().meta({ description: "Only this memory's versions, relative to `/memories`" }),
125
+ }),
126
+ },
127
+ responses: { 200: json(MemoryVersionPage, "A page of versions") },
128
+ }, async (c) => {
129
+ const id = idOf(c.req.param("agentId"));
130
+ assertReaches(c.get("scope"), id);
131
+ const path = c.req.query("path");
132
+ const { limit, cursor } = parseQuery(pageQuery, { limit: c.req.query("limit"), cursor: c.req.query("cursor") });
133
+ return jsonResponse(200, await listMemoryVersions(c.env.tenant, id, {
134
+ ...(path ? { path } : {}),
135
+ ...(cursor ? { cursor } : {}),
136
+ limit: await pageSize(c.env.tenant, limit, { fallback: 50 }),
137
+ }));
138
+ });
139
+ tenantRoute(api, READ, {
140
+ method: "get",
141
+ path: "/v1/agents/{agentId}/memory_versions/{versionId}",
142
+ tags: ["Memory"],
143
+ summary: "Read a memory version",
144
+ description: "One version with the content it left (`null` for a delete). To roll a memory back, write this content again.",
145
+ request: { params: agentId.extend({ versionId: z.string().meta({ description: "The version's id (`mv_…`)" }) }) },
146
+ responses: { 200: json(MemoryVersionDetail, "The version"), 404: { description: "No such version" } },
147
+ }, async (c) => {
148
+ const id = idOf(c.req.param("agentId"));
149
+ assertReaches(c.get("scope"), id);
150
+ return jsonResponse(200, await readMemoryVersion(c.env.tenant, id, c.req.param("versionId") ?? ""));
151
+ });
152
+ }
@@ -6,6 +6,15 @@ export declare const pageQuery: z.ZodObject<{
6
6
  limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
7
7
  cursor: z.ZodOptional<z.ZodString>;
8
8
  }, z.core.$strip>;
9
+ /**
10
+ * The size of a page: `asked`, or, when the query names none, `fallback`, each within the Tenant's
11
+ * Runtime limit `name` (read for each request): a page asked larger holds that many, and its
12
+ * cursor reads on.
13
+ */
14
+ export declare function pageSize(ctx: TenantEnv["Bindings"]["tenant"], asked: number | undefined, options?: {
15
+ fallback?: number;
16
+ name?: "pageItems" | "exportPageItems";
17
+ }): Promise<number>;
9
18
  export declare const sessionPageQuery: z.ZodObject<{
10
19
  limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
11
20
  cursor: z.ZodOptional<z.ZodString>;
@@ -21,7 +30,7 @@ export declare const sessionPageQuery: z.ZodObject<{
21
30
  uncertain: "uncertain";
22
31
  waiting: "waiting";
23
32
  }>>;
24
- environmentId: z.ZodOptional<z.ZodString>;
33
+ manifest: z.ZodOptional<z.ZodString>;
25
34
  ownerUserId: z.ZodOptional<z.ZodString>;
26
35
  }, z.core.$strict>;
27
36
  export declare function parseQuery<T>(schema: z.ZodType<T>, query: unknown): T;
@@ -33,119 +42,9 @@ export declare function sessionPage(ctx: TenantEnv["Bindings"]["tenant"], scope:
33
42
  status: "cancelled" | "completed" | "failed" | "idle" | "paused" | "runnable" | "running" | "uncertain" | "waiting";
34
43
  activeTurnId: string | null;
35
44
  lastTurnId: string | null;
36
- environmentId: string | null;
37
45
  createdAt: string | null;
38
46
  lastEventAt: string | null;
39
47
  }[];
40
48
  nextCursor: string | null;
41
49
  }>;
42
- export declare function environmentPage(ctx: TenantEnv["Bindings"]["tenant"], scope: TenantEnv["Variables"]["scope"], query: Record<string, string>, labels: Record<string, string>): Promise<{
43
- environments: {
44
- id: string;
45
- kind: "none" | "pod" | "virtual";
46
- labels: Record<string, string>;
47
- manifest: {
48
- image?: string | undefined;
49
- resources?: {
50
- cpus: number;
51
- memory: string;
52
- } | undefined;
53
- storage?: string | undefined;
54
- network?: {
55
- allowedHosts: string[];
56
- } | undefined;
57
- harness: string;
58
- lifecycle: {
59
- idle?: string | undefined;
60
- deleteAfter?: string | undefined;
61
- };
62
- setup?: {
63
- command: string;
64
- cwd?: string | undefined;
65
- timeout?: string | undefined;
66
- }[] | undefined;
67
- files?: ({
68
- artifactId: string;
69
- version: number;
70
- path: string;
71
- } | {
72
- path: string;
73
- files: Record<string, string>;
74
- })[] | undefined;
75
- secrets?: Record<string, {
76
- required?: boolean | undefined;
77
- description?: string | undefined;
78
- type: "environment_secret";
79
- allowedHosts: string[];
80
- inject?: {
81
- header: string;
82
- format: string;
83
- } | undefined;
84
- } | {
85
- required?: boolean | undefined;
86
- description?: string | undefined;
87
- type: "environment_variable";
88
- } | {
89
- via?: string | undefined;
90
- identity?: {
91
- header: string;
92
- } | undefined;
93
- required?: boolean | undefined;
94
- description?: string | undefined;
95
- type: "bearer";
96
- url: string;
97
- } | {
98
- via?: string | undefined;
99
- identity?: {
100
- header: string;
101
- } | undefined;
102
- required?: boolean | undefined;
103
- description?: string | undefined;
104
- type: "headers";
105
- url: string;
106
- }> | undefined;
107
- };
108
- manifestName?: string | undefined;
109
- manifestVersion?: number | undefined;
110
- manifestHash?: string | undefined;
111
- forkedFrom?: {
112
- environment: string;
113
- disk: number | null;
114
- } | undefined;
115
- slots?: {
116
- name: string;
117
- type: string;
118
- required: boolean;
119
- set: boolean;
120
- }[] | undefined;
121
- version: number;
122
- appliedVersion: number;
123
- ownerUserId: string | null;
124
- state: string;
125
- pod?: {
126
- desired: "deleted" | "running" | "suspended";
127
- observed: "creating" | "deleting" | "failed" | "lost" | "running" | "suspended";
128
- volumeGeneration: number;
129
- hostEpoch: number;
130
- reason?: string | undefined;
131
- imageDigest?: string | undefined;
132
- } | undefined;
133
- lastUsedAt: string;
134
- disk?: {
135
- latestVersion: number | null;
136
- operation?: {
137
- kind: "restore" | "seed" | "snapshot";
138
- version?: number | undefined;
139
- startedAt: string;
140
- } | undefined;
141
- } | undefined;
142
- sessions: {
143
- id: string;
144
- activeTurnId: string | null;
145
- }[];
146
- createdAt: string;
147
- updatedAt: string;
148
- }[];
149
- nextCursor: string | null;
150
- }>;
151
50
  export declare function readRoutes(api: OpenAPIHono<TenantEnv>): void;
@@ -5,18 +5,42 @@ import { turnTrace } from "../../../traces/read.js";
5
5
  import { readAccess, readStoreOf } from "../../../reads/access.js";
6
6
  import { requireApplication, requirePrincipal } from "../../../tenant/auth.js";
7
7
  import { fail } from "../../../tenant/http.js";
8
- import { environmentGrantsOf } from "../../../tenant/environments.js";
8
+ import { readRuntimeLimits } from "../../../tenant/runtime-limits.js";
9
9
  import { tenantRoute } from "../define.js";
10
10
  import { jsonResponse } from "../respond.js";
11
+ /** A page's `limit`, held to the Tenant's Runtime limit `pageItems` (`pageSize`). */
12
+ const limitParam = (fallback) => z.coerce
13
+ .number()
14
+ .int()
15
+ .min(1)
16
+ .optional()
17
+ .meta({
18
+ description: `A page holds at most the Tenant's Runtime limit \`pageItems\` (default 200); a larger limit gets that many${fallback === undefined ? "" : `. Default ${fallback}, or that limit when it is lower`}`,
19
+ });
11
20
  export const pageQuery = z.object({
12
- limit: z.coerce.number().int().min(1).max(200).optional(),
21
+ limit: limitParam(),
13
22
  cursor: z.string().optional(),
14
23
  });
24
+ /** The size of a page of a session's calls when the query names none (within `pageItems`). */
25
+ const CALLS_PAGE_DEFAULT = 50;
26
+ /** The size of a page of the model call export when the query names none (within `exportPageItems`). */
27
+ const EXPORT_PAGE_DEFAULT = 200;
28
+ /**
29
+ * The size of a page: `asked`, or, when the query names none, `fallback`, each within the Tenant's
30
+ * Runtime limit `name` (read for each request): a page asked larger holds that many, and its
31
+ * cursor reads on.
32
+ */
33
+ export async function pageSize(ctx, asked, options = {}) {
34
+ const name = options.name ?? "pageItems";
35
+ const limit = (await ctx.store.tx((t) => readRuntimeLimits(t)))[name];
36
+ return Math.min(asked ?? options.fallback ?? limit, limit);
37
+ }
15
38
  export const sessionPageQuery = pageQuery
16
39
  .extend({
17
40
  agentId: z.string().optional(),
18
41
  status: z.enum(SESSION_STATUSES).optional(),
19
- environmentId: z.string().optional(),
42
+ /** Sessions that pinned a version of this agent manifest. */
43
+ manifest: z.string().optional(),
20
44
  ownerUserId: z.string().optional(),
21
45
  })
22
46
  .strict();
@@ -30,13 +54,7 @@ export async function sessionPage(ctx, scope, query) {
30
54
  return fail(400, "Pagination requires limit");
31
55
  if (filters.ownerUserId !== undefined)
32
56
  requireApplication(scope);
33
- return readStoreOf(ctx).sessions(filters, { limit, cursor }, readAccess(scope));
34
- }
35
- export async function environmentPage(ctx, scope, query, labels) {
36
- const { limit, cursor } = parseQuery(pageQuery.extend({ label: z.string().optional() }).strict(), query);
37
- if (limit === undefined)
38
- return fail(400, "Pagination requires limit");
39
- return readStoreOf(ctx).environments(labels, { limit, cursor }, readAccess(scope), environmentGrantsOf(scope));
57
+ return readStoreOf(ctx).sessions(filters, { limit: await pageSize(ctx, limit), cursor }, readAccess(scope));
40
58
  }
41
59
  export function readRoutes(api) {
42
60
  const sessionId = z.object({ sessionId: z.string() });
@@ -57,15 +75,14 @@ export function readRoutes(api) {
57
75
  requirePrincipal(c.get("scope"));
58
76
  return jsonResponse(200, await readStoreOf(c.env.tenant).manifest(c.req.param("sessionId"), readAccess(c.get("scope"))));
59
77
  });
78
+ const callsQuery = turnQuery
79
+ .extend({
80
+ limit: limitParam(CALLS_PAGE_DEFAULT),
81
+ cursor: z.string().optional(),
82
+ })
83
+ .strict();
60
84
  for (const kind of ["usage", "calls/model"]) {
61
- const query = kind === "usage"
62
- ? turnQuery
63
- : turnQuery
64
- .extend({
65
- limit: z.coerce.number().int().min(1).max(200).default(50),
66
- cursor: z.string().optional(),
67
- })
68
- .strict();
85
+ const query = kind === "usage" ? turnQuery : callsQuery;
69
86
  // Spend is the application's to show: no subject scope reaches it (`tenant:settings`,
70
87
  // which used to, is retired in protocol 8).
71
88
  tenantRoute(api, { credentials: ["application"], scopes: "never" }, {
@@ -93,18 +110,14 @@ export function readRoutes(api) {
93
110
  const q = parseQuery(turnQuery, c.req.query());
94
111
  return jsonResponse(200, await store.usage(id, q.turnId, access));
95
112
  }
96
- const q = parseQuery(turnQuery
97
- .extend({
98
- limit: z.coerce.number().int().min(1).max(200).default(50),
99
- cursor: z.string().optional(),
100
- })
101
- .strict(), c.req.query());
102
- return jsonResponse(200, await store.modelCalls(id, q.turnId, q, access));
113
+ const q = parseQuery(callsQuery, c.req.query());
114
+ const limit = await pageSize(c.env.tenant, q.limit, { fallback: CALLS_PAGE_DEFAULT });
115
+ return jsonResponse(200, await store.modelCalls(id, q.turnId, { ...q, limit }, access));
103
116
  });
104
117
  }
105
118
  const toolCallsQuery = turnQuery
106
119
  .extend({
107
- limit: z.coerce.number().int().min(1).max(200).default(50),
120
+ limit: limitParam(CALLS_PAGE_DEFAULT),
108
121
  cursor: z.string().optional(),
109
122
  })
110
123
  .strict();
@@ -125,7 +138,8 @@ export function readRoutes(api) {
125
138
  }, async (c) => {
126
139
  requirePrincipal(c.get("scope"));
127
140
  const q = parseQuery(toolCallsQuery, c.req.query());
128
- return jsonResponse(200, await readStoreOf(c.env.tenant).toolCalls(c.req.param("sessionId"), q.turnId, q, readAccess(c.get("scope"))));
141
+ const limit = await pageSize(c.env.tenant, q.limit, { fallback: CALLS_PAGE_DEFAULT });
142
+ return jsonResponse(200, await readStoreOf(c.env.tenant).toolCalls(c.req.param("sessionId"), q.turnId, { ...q, limit }, readAccess(c.get("scope"))));
129
143
  });
130
144
  // A turn's spans (R7.5): the same mapping the trace projector posts, from the turn's log rows,
131
145
  // with the installation's content opt-ins. Spans carry cost: the application's, as /calls are.
@@ -153,7 +167,14 @@ export function readRoutes(api) {
153
167
  const exportQuery = z
154
168
  .object({
155
169
  after: z.string().optional(),
156
- limit: z.coerce.number().int().min(1).max(1000).default(200),
170
+ limit: z.coerce
171
+ .number()
172
+ .int()
173
+ .min(1)
174
+ .optional()
175
+ .meta({
176
+ description: `A page holds at most the Tenant's Runtime limit \`exportPageItems\` (default 1000); a larger limit gets that many. Default ${EXPORT_PAGE_DEFAULT}, or that limit when it is lower`,
177
+ }),
157
178
  })
158
179
  .strict();
159
180
  // The whole Tenant's ledger is the Management API's (protocol 8): a management key, as itself.
@@ -171,6 +192,7 @@ export function readRoutes(api) {
171
192
  },
172
193
  }, async (c) => {
173
194
  const q = parseQuery(exportQuery, c.req.query());
174
- return jsonResponse(200, await readStoreOf(c.env.tenant).exportModel(q.after, q.limit));
195
+ const limit = await pageSize(c.env.tenant, q.limit, { fallback: EXPORT_PAGE_DEFAULT, name: "exportPageItems" });
196
+ return jsonResponse(200, await readStoreOf(c.env.tenant).exportModel(q.after, limit));
175
197
  });
176
198
  }
@@ -1,19 +1,20 @@
1
1
  import { RESPONSE_ALREADY_SENT } from "@hono/node-server/utils/response";
2
2
  import { z } from "zod";
3
- import { PutAgentRequestSchema, PutSessionRequestSchema, SessionCommandSchema, } from "@nylorun/core/contracts";
3
+ import { PROTOCOL_HEADER } from "@nylorun/core/compatibility";
4
+ import { PutSessionRequestSchema, SessionCommandSchema, } from "@nylorun/core/contracts";
4
5
  import { handleSessionSandboxTool, SandboxRouteError } from "../../../core/sandbox-routes.js";
5
6
  import { traceContextOf } from "../../../traces/ids.js";
6
- import { AcceptedResponse, ListAgentsResponse, ListPublicAgentsResponse, ListSessionsResponse, SessionPage, HistoryPage, SessionEvent, PutAgentRequest, PutAgentResponse, PutSessionRequest, SandboxToolOutcome, SessionCommand, SessionItemsResponse, SessionView, StreamClosedFrame, } from "../../components.js";
7
+ import { AcceptedResponse, QueuedResponse, ListSessionsResponse, SessionPage, HistoryPage, SessionEvent, PutSessionRequest, SandboxToolOutcome, SessionCommand, SessionItemsResponse, SessionView, StreamClosedFrame, } from "../../components.js";
7
8
  import { accessOf, requireApplication } from "../../../tenant/auth.js";
8
9
  import { command } from "../../../tenant/commands.js";
9
10
  import { loadSession, sessionOf } from "../../../tenant/context.js";
10
11
  import { fail } from "../../../tenant/http.js";
11
- import { environmentGrantsOf, sandboxRouteDeps } from "../../../tenant/environments.js";
12
+ import { agentGrantsOf, sandboxRouteDeps } from "../../../tenant/agents.js";
12
13
  import { readHistory, requestCursor, streamHolderOf, streamSessionEvents } from "../../../tenant/session-streams.js";
13
- import { listAgentsPublic, listDefinitions, listSessions, putDefinition, putSession, sessionView, } from "../../../tenant/sessions.js";
14
+ import { listSessions, putSession, sessionView } from "../../../tenant/sessions.js";
14
15
  import { readJson } from "../body.js";
15
16
  import { TraceHeaders, tenantRoute } from "../define.js";
16
- import { pageQuery, sessionPage, sessionPageQuery, parseQuery } from "./reads.js";
17
+ import { pageQuery, pageSize, sessionPage, sessionPageQuery, parseQuery } from "./reads.js";
17
18
  import { jsonResponse } from "../respond.js";
18
19
  const OWN_SESSIONS = {
19
20
  credentials: ["application", "subject", "token"],
@@ -46,61 +47,31 @@ async function sessionBelow(ctx, incoming, id, access) {
46
47
  await loadSession(ctx, id, access);
47
48
  return requestCursor(incoming, urlOf(incoming));
48
49
  }
50
+ /**
51
+ * What a message to a busy session does when it says nothing (D76): a protocol 17 client's waits
52
+ * in the queue; a protocol 16 client's is refused, as before.
53
+ */
54
+ function deliveryFor(headers) {
55
+ const protocol = Number(headers.get(PROTOCOL_HEADER)?.trim());
56
+ return Number.isInteger(protocol) && protocol >= 17 ? "queue" : "reject";
57
+ }
49
58
  export function sessionRoutes(api) {
50
59
  tenantRoute(api, OWN_SESSIONS, {
51
60
  method: "post",
52
61
  path: "/v1/sessions/{sessionId}/commands",
53
62
  tags: ["Sessions"],
54
63
  summary: "Send a command to a session",
55
- description: "A message starts a turn; the others answer what the session waits on, or cancel. Idempotent on the command's `idempotencyKey`.",
64
+ description: "A message starts a turn, or waits in the session's queue while a turn runs or waits (protocol 17; `delivery: \"reject\"` is refused with `409 session_busy` instead); the others answer what the session waits on, or cancel. Idempotent on the command's `idempotencyKey`.",
56
65
  request: { params: sessionId, body: body(SessionCommand), headers: TraceHeaders },
57
66
  responses: {
58
- 200: json(AcceptedResponse, "The command, accepted"),
59
- 409: { description: "A turn is running, or the session does not wait on this" },
60
- 422: {
61
- description: "A message names a file the Tenant's model does not read (`attachment_unsupported`; `details.parts` lists each with its reason). No turn starts.",
62
- },
67
+ 200: json(z.union([AcceptedResponse, QueuedResponse]), "The command, accepted; a message may be queued"),
68
+ 409: { description: "A turn is running (`session_busy`), or the session does not wait on this" },
69
+ 429: { description: "The session's queue is full (`queue_full`)" },
63
70
  },
64
71
  }, async (c) => {
65
72
  // A `traceparent` joins the turn to the caller's trace (R7.4); a malformed one is ignored.
66
73
  const trace = traceContextOf(c.req.raw.headers);
67
- return jsonResponse(200, await command(c.env.tenant, c.req.param("sessionId"), SessionCommandSchema.parse(await readJson(c.req.raw)), c.get("scope"), trace ? { trace } : {}));
68
- });
69
- tenantRoute(api, {
70
- credentials: ["application", "subject", "token"],
71
- scopes: ["agents:read", "agents:write"],
72
- }, {
73
- method: "get",
74
- path: "/v1/agents",
75
- tags: ["Agents"],
76
- summary: "List agents",
77
- description: "With an application key, every definition, manifest included. With a trusted issuer's token, only the agents it may use, by name.",
78
- responses: {
79
- 200: json(z.union([ListAgentsResponse, ListPublicAgentsResponse]), "The agents"),
80
- },
81
- }, async (c) => {
82
- const scope = c.get("scope");
83
- const ctx = c.env.tenant;
84
- return jsonResponse(200, scope.kind === "token"
85
- ? await listAgentsPublic(ctx, scope.agents)
86
- : await listDefinitions(ctx));
87
- });
88
- tenantRoute(api, { credentials: ["application", "subject"], scopes: ["agents:write"] }, {
89
- method: "put",
90
- path: "/v1/agents/{agentId}",
91
- tags: ["Agents"],
92
- summary: "Put an agent's definition",
93
- description: "Saves the agent's definition. With `?dryRun=true` (protocol 14) every check runs and nothing is saved: the answer says what a save would record.",
94
- request: {
95
- params: z.object({ agentId: z.string() }),
96
- query: z.object({
97
- dryRun: z.enum(["true", "false"]).optional().meta({ description: "`true`: check and save nothing" }),
98
- }),
99
- body: body(PutAgentRequest),
100
- },
101
- responses: { 200: json(PutAgentResponse, "The definition, stored (or checked, with dryRun)") },
102
- }, async (c) => {
103
- return jsonResponse(200, await putDefinition(c.env.tenant, c.req.param("agentId"), PutAgentRequestSchema.parse(await readJson(c.req.raw)), { dryRun: c.req.query("dryRun") === "true" }));
74
+ return jsonResponse(200, await command(c.env.tenant, c.req.param("sessionId"), SessionCommandSchema.parse(await readJson(c)), c.get("scope"), { ...(trace ? { trace } : {}), delivery: deliveryFor(c.req.raw.headers) }));
104
75
  });
105
76
  tenantRoute(api, OWN_SESSIONS, {
106
77
  method: "get",
@@ -121,7 +92,7 @@ export function sessionRoutes(api) {
121
92
  path: "/v1/sessions/{sessionId}",
122
93
  tags: ["Sessions"],
123
94
  summary: "Open a session",
124
- description: "Creates the session, or answers the one already opened with the same agent, owner, info and Environment. Its Environment (its sandbox and vault) is chosen now and fixed for its life.",
95
+ description: "Creates the session on an Agent, or answers the one already opened with the same Agent, owner and info. Its Agent (its sandbox and vault) is fixed for its life, and it pins the manifest version the Agent runs. No session is special: an app that keeps one conversation going reuses its id.",
125
96
  request: { params: sessionId, body: body(PutSessionRequest) },
126
97
  responses: {
127
98
  200: json(SessionView, "The session"),
@@ -130,12 +101,12 @@ export function sessionRoutes(api) {
130
101
  }, async (c) => {
131
102
  const scope = c.get("scope");
132
103
  const ctx = c.env.tenant;
133
- const request = PutSessionRequestSchema.parse(await readJson(c.req.raw));
104
+ const request = PutSessionRequestSchema.parse(await readJson(c));
134
105
  // Agent code may trust `info`: only an app server sets it.
135
106
  if (scope.kind === "token" && request.info !== undefined)
136
107
  fail(403, "A token caller cannot set session info", { code: "scope_required" });
137
- const grants = environmentGrantsOf(scope);
138
- const session = await putSession(ctx, c.req.param("sessionId"), request, accessOf(scope), grants === undefined ? {} : { environmentGrants: grants });
108
+ const grants = agentGrantsOf(scope);
109
+ const session = await putSession(ctx, c.req.param("sessionId"), request, accessOf(scope), grants === undefined ? {} : { agentGrants: grants });
139
110
  return jsonResponse(200, await ctx.store.tx((t) => sessionView(t, session)));
140
111
  });
141
112
  tenantRoute(api, OWN_SESSIONS, {
@@ -172,7 +143,8 @@ export function sessionRoutes(api) {
172
143
  const ctx = c.env.tenant;
173
144
  const id = c.req.param("sessionId");
174
145
  const cursor = await sessionBelow(ctx, c.env.incoming, id, accessOf(scope));
175
- const { limit } = parseQuery(pageQuery.pick({ limit: true }), { limit: c.req.query("limit") });
146
+ const { limit: asked } = parseQuery(pageQuery.pick({ limit: true }), { limit: c.req.query("limit") });
147
+ const limit = asked === undefined ? undefined : await pageSize(ctx, asked);
176
148
  return jsonResponse(200, await readHistory(ctx, id, cursor, c.req.query("agent"), limit));
177
149
  });
178
150
  tenantRoute(api, OWN_SESSIONS, {
@@ -222,7 +194,7 @@ export function sessionRoutes(api) {
222
194
  await sessionBelow(ctx, c.env.incoming, id, accessOf(scope));
223
195
  requireApplication(scope);
224
196
  try {
225
- return jsonResponse(200, await handleSessionSandboxTool(sandboxRouteDeps(ctx), id, c.req.param("tool"), await readJson(c.req.raw), c.req.raw.signal));
197
+ return jsonResponse(200, await handleSessionSandboxTool(sandboxRouteDeps(ctx), id, c.req.param("tool"), await readJson(c), c.req.raw.signal));
226
198
  }
227
199
  catch (error) {
228
200
  if (error instanceof SandboxRouteError)
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The Tenant's own settings (`/v1/tenant/**`): its status, reset, a first configuration, the
3
- * model it calls, what its model calls cost and may cost (budgets), and the sandboxes its
4
- * sessions get.
3
+ * model it calls, what its model calls cost and may cost (budgets), the sandboxes its
4
+ * sessions get, and its Runtime limits.
5
5
  *
6
6
  * A reset that deletes sessions moves the Tenant to a new basin generation, so a session
7
7
  * created again starts in an empty basin; the old basin is deleted after a grace period.