@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
@@ -1,8 +1,9 @@
1
1
  import { z } from "zod";
2
- import { ModelUsageQuerySchema, PutModelBudgetsRequestSchema, PutToolPolicyRequestSchema, PutModelInputsRequestSchema, PutHostModelRequestSchema, PutTenantEnvironmentsRequestSchema, ResetTenantRequestSchema, SeedTenantConfigRequestSchema, SelectHostModelRequestSchema, } from "@nylorun/core/contracts";
3
- import { HostModelCatalog, HostModelView, ListProvidersResponse, ModelBudgets, ModelInputsView, ModelUsageTotals, PutModelBudgetsRequest, PutToolPolicyRequest, PutModelInputsRequest, ToolPolicy, PutHostModelRequest, PutTenantEnvironmentsRequest, ResetTenantRequest, ResetTenantResponse, SeedTenantConfigRequest, SeedTenantConfigResponse, SelectHostModelRequest, TenantSandboxView, TenantStatus, } from "../../components.js";
2
+ import { ModelUsageQuerySchema, PutModelBudgetsRequestSchema, PutToolPolicyRequestSchema, PutModelInputsRequestSchema, PutHostModelRequestSchema, PutTenantEnvironmentsRequestSchema, PutTenantLimitsRequestSchema, RUNTIME_LIMIT_CEILINGS, RUNTIME_LIMIT_DEFAULTS, ResetTenantRequestSchema, runtimeLimitIssues, runtimeLimitsOf, SeedTenantConfigRequestSchema, SelectHostModelRequestSchema, } from "@nylorun/core/contracts";
3
+ import { HostModelCatalog, HostModelView, ListProvidersResponse, ModelBudgets, ModelInputsView, ModelUsageTotals, PutModelBudgetsRequest, PutToolPolicyRequest, PutModelInputsRequest, ToolPolicy, PutHostModelRequest, PutTenantEnvironmentsRequest, PutTenantLimitsRequest, ResetTenantRequest, ResetTenantResponse, SeedTenantConfigRequest, SeedTenantConfigResponse, SelectHostModelRequest, TenantLimitsView, TenantSandboxView, TenantStatus, } from "../../components.js";
4
+ import { readRuntimeLimits, writeLimitsConfig } from "../../../tenant/runtime-limits.js";
4
5
  import { periodStart } from "../../../gates/meter.js";
5
- import { readToolPolicy, TOOL_POLICY_SETTING } from "../../../gates/policy.js";
6
+ import { readToolPolicy, TOOL_POLICY_SETTING, ToolPolicyUnreadable } from "../../../gates/policy.js";
6
7
  import { addableInputs, capabilitiesOf, inputsError } from "../../../model/capabilities.js";
7
8
  import { catalogModel, hostModelCatalog } from "../../../model/catalog.js";
8
9
  import { sandboxConfigErrors } from "../../../sandbox/resolve.js";
@@ -17,9 +18,15 @@ import { tenantReset, streamsStatus, } from "../../../tenant/streams.js";
17
18
  import { readJson } from "../body.js";
18
19
  import { pathSegments, tenantRoute } from "../define.js";
19
20
  import { jsonResponse } from "../respond.js";
20
- import { rearmPodTimers } from "../../../tenant/environments.js";
21
+ import { rearmPodTimers } from "../../../tenant/agents.js";
22
+ import { hostTuning } from "../../../tuning.js";
23
+ import { budgetIssues, toolPolicyIssues } from "../../../tenant/limits.js";
21
24
  /** Every Management API route (`/v1/tenant/*`): a management key, acting as itself (protocol 8). */
22
25
  const MANAGEMENT = { credentials: ["management"], scopes: "never" };
26
+ /** Each Runtime limit's default and ceiling, for the limits routes' descriptions. */
27
+ const LIMITS_TABLE = `Defaults and ceilings: ${Object.entries(RUNTIME_LIMIT_CEILINGS)
28
+ .map(([name, ceiling]) => `\`${name}\` ${RUNTIME_LIMIT_DEFAULTS[name]} ${ceiling.unit}, at most ${ceiling.value} (${ceiling.why})`)
29
+ .join("; ")}.`;
23
30
  const json = (schema, description) => ({
24
31
  description,
25
32
  content: { "application/json": { schema } },
@@ -30,7 +37,7 @@ const body = (schema) => ({
30
37
  });
31
38
  const budgetRow = (budget, updatedAt) => ({
32
39
  scope: budget.scope,
33
- scopeId: budget.scope === "agent" ? budget.id : "*",
40
+ scopeId: budget.scope === "manifest" ? budget.id : "*",
34
41
  period: budget.period ?? null,
35
42
  limitUsd: budget.limitUsd ?? null,
36
43
  limitTokens: budget.limitTokens ?? null,
@@ -38,7 +45,7 @@ const budgetRow = (budget, updatedAt) => ({
38
45
  });
39
46
  const budgetView = (row) => ({
40
47
  scope: row.scope,
41
- ...(row.scope === "agent" ? { id: row.scopeId } : {}),
48
+ ...(row.scope === "manifest" ? { id: row.scopeId } : {}),
42
49
  ...(row.period ? { period: row.period } : {}),
43
50
  ...(row.limitUsd !== null ? { limitUsd: row.limitUsd } : {}),
44
51
  ...(row.limitTokens !== null ? { limitTokens: row.limitTokens } : {}),
@@ -94,7 +101,7 @@ export function tenantRoutes(api) {
94
101
  vault,
95
102
  sandbox: ctx.sandbox,
96
103
  closing: ctx.closing || ctx.closed,
97
- modelConfigured: !ctx.useVaultModel ||
104
+ modelConfigured: ctx.scriptedModel ||
98
105
  (await ctx.store.tx((t) => usesFixtureModel(t))) ||
99
106
  (await vault.getHostModel()).configured,
100
107
  ...(ctx.stuckInvocations ? { stuckInvocations: ctx.stuckInvocations } : {}),
@@ -107,16 +114,16 @@ export function tenantRoutes(api) {
107
114
  path: "/v1/tenant/reset",
108
115
  tags: ["Tenant"],
109
116
  summary: "Reset the Tenant",
110
- description: "Deletes its sessions, its Environments (with their vaults), or both, after draining or cancelling the turns in progress. The Tenant stays open.",
117
+ description: "Deletes its sessions, its Agents (with their vaults), or both, after draining or cancelling the turns in progress. The Tenant stays open.",
111
118
  request: { body: body(ResetTenantRequest) },
112
119
  responses: { 200: json(ResetTenantResponse, "Reset") },
113
120
  }, async (c) => {
114
121
  const ctx = c.env.tenant;
115
- const request = ResetTenantRequestSchema.parse(await readJson(c.req.raw));
116
- await drain(ctx, request.activeWork, 30_000);
122
+ const request = ResetTenantRequestSchema.parse(await readJson(c));
123
+ await drain(ctx, request.activeWork, hostTuning().tenant.drainTimeoutMs);
117
124
  // A sessions reset moves the Tenant to a new basin generation, so a session created
118
125
  // again with the same id, during or after the reset, starts in an empty basin at 0.
119
- const sessionsReset = request.scope !== "environments";
126
+ const sessionsReset = request.scope !== "agents";
120
127
  await resetTenant({
121
128
  store: ctx.store,
122
129
  sandbox: ctx.sandbox,
@@ -143,7 +150,7 @@ export function tenantRoutes(api) {
143
150
  responses: { 200: json(SeedTenantConfigResponse, "What was set, and what was kept") },
144
151
  }, async (c) => {
145
152
  const ctx = c.env.tenant;
146
- const request = SeedTenantConfigRequestSchema.parse(await readJson(c.req.raw));
153
+ const request = SeedTenantConfigRequestSchema.parse(await readJson(c));
147
154
  return jsonResponse(200, await seedTenantConfig({ store: ctx.store, vault: ctx.vault, keys: ctx.keys }, request));
148
155
  });
149
156
  tenantRoute(api, MANAGEMENT, {
@@ -162,11 +169,11 @@ export function tenantRoutes(api) {
162
169
  path: "/v1/tenant/models/inputs",
163
170
  tags: ["Tenant"],
164
171
  summary: "Set what a catalog model reads",
165
- description: "Replaces the inputs the operator added to one catalog model (Tenant setting `model.inputs`): only those in its `addableInputs`, which its provider API carries. Its catalog's own inputs always stay; an empty list removes the additions. A message naming a file the Tenant's model does not read is refused with `422 attachment_unsupported`. A custom endpoint sets `settings.inputs` on `PUT /v1/tenant/model` instead.",
172
+ description: "Replaces the inputs the operator added to one catalog model (Tenant setting `model.inputs`): only those in its `addableInputs`, which its provider API carries. Its catalog's own inputs always stay; an empty list removes the additions. The agent's harness learns them in `turn.start.model` and decides how each file reaches the model. A custom endpoint sets `settings.inputs` on `PUT /v1/tenant/model` instead.",
166
173
  request: { body: body(PutModelInputsRequest) },
167
174
  responses: { 200: json(ModelInputsView, "What the model reads now") },
168
175
  }, async (c) => {
169
- const { provider, model, inputs } = PutModelInputsRequestSchema.parse(await readJson(c.req.raw));
176
+ const { provider, model, inputs } = PutModelInputsRequestSchema.parse(await readJson(c));
170
177
  if (provider === "custom")
171
178
  fail(400, "A custom endpoint's inputs are its settings: set settings.inputs on PUT /v1/tenant/model.");
172
179
  const found = catalogModel(provider, model);
@@ -183,24 +190,51 @@ export function tenantRoutes(api) {
183
190
  inputs: capabilitiesOf(found, added).inputs,
184
191
  });
185
192
  });
193
+ tenantRoute(api, MANAGEMENT, {
194
+ method: "get",
195
+ path: "/v1/tenant/limits",
196
+ tags: ["Tenant"],
197
+ summary: "Get the Tenant's Runtime limits",
198
+ description: `The sizes, counts and deadlines the Runtime holds what crosses it to: the Tenant's (Tenant setting \`limits.config\`), with the default for each it leaves out. Harnesses get the ones they must respect in \`turn.start.limits\` (record entry, model call, model file, tool answer, custom harness state, Harness API chunk, folder entries). ${LIMITS_TABLE}`,
199
+ responses: { 200: json(TenantLimitsView, "The limits in force") },
200
+ }, async (c) => jsonResponse(200, { limits: await c.env.tenant.store.tx((t) => readRuntimeLimits(t)) }));
201
+ tenantRoute(api, MANAGEMENT, {
202
+ method: "put",
203
+ path: "/v1/tenant/limits",
204
+ tags: ["Tenant"],
205
+ summary: "Set the Tenant's Runtime limits",
206
+ description: `Replaces the Tenant's Runtime limits: a limit left out takes its default. A limit above its ceiling, which a dependency sets, is \`400\` naming the ceiling, and nothing is written. Each is read where it is checked, so a new value holds for the next request, write, call or segment. ${LIMITS_TABLE}`,
207
+ request: { body: body(PutTenantLimitsRequest) },
208
+ responses: {
209
+ 200: json(TenantLimitsView, "The limits now in force"),
210
+ 400: { description: "A limit above its ceiling" },
211
+ },
212
+ }, async (c) => {
213
+ const { requestId: _requestId, ...config } = PutTenantLimitsRequestSchema.parse(await readJson(c));
214
+ const issues = runtimeLimitIssues(config.limits);
215
+ if (issues.length > 0)
216
+ fail(400, issues.join(" "));
217
+ await c.env.tenant.store.tx((t) => writeLimitsConfig(t, config));
218
+ return jsonResponse(200, { limits: runtimeLimitsOf(config.limits) });
219
+ });
186
220
  tenantRoute(api, MANAGEMENT, {
187
221
  method: "get",
188
222
  path: "/v1/tenant/sandbox",
189
223
  tags: ["Tenant"],
190
- summary: "Get the Tenant's sandbox backend and Environment settings",
224
+ summary: "Get the Tenant's sandbox backend and Agent compute settings",
191
225
  responses: { 200: json(TenantSandboxView, "The backend in use and the configuration in force") },
192
226
  }, async (c) => jsonResponse(200, await sandboxView(c.env.tenant)));
193
227
  tenantRoute(api, MANAGEMENT, {
194
228
  method: "put",
195
229
  path: "/v1/tenant/sandbox",
196
230
  tags: ["Tenant"],
197
- summary: "Set the Tenant's Environment settings",
198
- description: "The limits every Environment's recipe must fit, the pods' stop grace and where harnesses may run (Tenant setting `environments.config`).",
231
+ summary: "Set the Tenant's Agent compute settings",
232
+ description: "The limits every Agent's runtime must fit, the pods' stop grace and where harnesses may run (Tenant setting `environments.config`).",
199
233
  request: { body: body(PutTenantEnvironmentsRequest) },
200
234
  responses: { 200: json(TenantSandboxView, "The configuration now in force") },
201
235
  }, async (c) => {
202
236
  const ctx = c.env.tenant;
203
- const { requestId: _requestId, ...config } = PutTenantEnvironmentsRequestSchema.parse(await readJson(c.req.raw));
237
+ const { requestId: _requestId, ...config } = PutTenantEnvironmentsRequestSchema.parse(await readJson(c));
204
238
  const errors = sandboxConfigErrors(effectiveSandboxConfig(config));
205
239
  if (errors.length > 0)
206
240
  fail(400, errors.join(" "));
@@ -257,9 +291,12 @@ export function tenantRoutes(api) {
257
291
  request: { body: body(PutModelBudgetsRequest) },
258
292
  responses: { 200: json(ModelBudgets, "The budgets now in force") },
259
293
  }, async (c) => {
260
- const { budgets } = PutModelBudgetsRequestSchema.parse(await readJson(c.req.raw));
294
+ const { budgets } = PutModelBudgetsRequestSchema.parse(await readJson(c));
261
295
  const updatedAt = new Date().toISOString();
262
296
  const rows = await c.env.tenant.store.tx(async (t) => {
297
+ const issues = budgetIssues(budgets, await readRuntimeLimits(t));
298
+ if (issues.length > 0)
299
+ fail(400, issues.join(" "));
263
300
  await t.putModelBudgets(budgets.map((budget) => budgetRow(budget, updatedAt)));
264
301
  return t.listModelBudgets();
265
302
  });
@@ -271,7 +308,18 @@ export function tenantRoutes(api) {
271
308
  tags: ["Tenant"],
272
309
  summary: "Get the Tenant's tool policy",
273
310
  responses: { 200: json(ToolPolicy, "The rules the Tool Gate applies to every MCP and HTTP tool call") },
274
- }, async (c) => jsonResponse(200, await c.env.tenant.store.tx((t) => readToolPolicy(t))));
311
+ }, async (c) => {
312
+ try {
313
+ return jsonResponse(200, await c.env.tenant.store.tx((t) => readToolPolicy(t)));
314
+ }
315
+ catch (error) {
316
+ // A stored rule this Runtime refuses (an MCP tool named `server__tool`, protocol 15):
317
+ // every call is denied until the policy is set again.
318
+ if (error instanceof ToolPolicyUnreadable)
319
+ return fail(409, error.message, { code: "request_rejected" });
320
+ throw error;
321
+ }
322
+ });
275
323
  tenantRoute(api, MANAGEMENT, {
276
324
  method: "put",
277
325
  path: "/v1/tenant/tool-policy",
@@ -281,9 +329,14 @@ export function tenantRoutes(api) {
281
329
  request: { body: body(PutToolPolicyRequest) },
282
330
  responses: { 200: json(ToolPolicy, "The policy now in force") },
283
331
  }, async (c) => {
284
- const { rules } = PutToolPolicyRequestSchema.parse(await readJson(c.req.raw));
332
+ const { rules } = PutToolPolicyRequestSchema.parse(await readJson(c));
285
333
  const policy = { rules, updatedAt: new Date().toISOString() };
286
- await c.env.tenant.store.tx((t) => t.putSetting(TOOL_POLICY_SETTING, JSON.stringify(policy)));
334
+ await c.env.tenant.store.tx(async (t) => {
335
+ const issues = toolPolicyIssues(rules, await readRuntimeLimits(t));
336
+ if (issues.length > 0)
337
+ fail(400, issues.join(" "));
338
+ await t.putSetting(TOOL_POLICY_SETTING, JSON.stringify(policy));
339
+ });
287
340
  return jsonResponse(200, policy);
288
341
  });
289
342
  tenantRoute(api, MANAGEMENT, {
@@ -309,7 +362,7 @@ export function tenantRoutes(api) {
309
362
  responses: { 200: json(HostModelView, "The model now in force") },
310
363
  }, async (c) => {
311
364
  const ctx = c.env.tenant;
312
- return jsonResponse(200, await ctx.keys.putHostModel(PutHostModelRequestSchema.parse(await readJson(c.req.raw))));
365
+ return jsonResponse(200, await ctx.keys.putHostModel(PutHostModelRequestSchema.parse(await readJson(c))));
313
366
  });
314
367
  tenantRoute(api, MANAGEMENT, {
315
368
  method: "put",
@@ -320,6 +373,6 @@ export function tenantRoutes(api) {
320
373
  responses: { 200: json(HostModelView, "The model now in force") },
321
374
  }, async (c) => {
322
375
  const ctx = c.env.tenant;
323
- return jsonResponse(200, await ctx.keys.selectHostModel(SelectHostModelRequestSchema.parse(await readJson(c.req.raw))));
376
+ return jsonResponse(200, await ctx.keys.selectHostModel(SelectHostModelRequestSchema.parse(await readJson(c))));
324
377
  });
325
378
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * An Agent's triggers and their runs (track T4, D74): read them, pause and resume one, run one now
3
+ * (keyed by `Idempotency-Key`), and page the runs; make a webhook trigger's signing secret, and
4
+ * take a sender's delivery at its endpoint (D75), an anonymous, unversioned route. What a trigger is lives in the Agent's manifest
5
+ * (`runtime.triggers`); these routes change only what the Agent owns, its status.
6
+ */
7
+ import type { OpenAPIHono } from "@hono/zod-openapi";
8
+ import type { TenantEnv } from "../app.js";
9
+ export declare function triggerRoutes(api: OpenAPIHono<TenantEnv>): void;
10
+ export declare function webhookRoutes(api: OpenAPIHono<TenantEnv>): void;
@@ -0,0 +1,180 @@
1
+ import { z } from "zod";
2
+ import { isAgentId } from "@nylorun/core/contracts";
3
+ import { RunTriggerResponse, TriggerList, TriggerRunPage, WebhookAcceptedResponse, WebhookSecretResponse, } from "../../components.js";
4
+ import { assertReaches } from "../../../tenant/agents.js";
5
+ import { fail } from "../../../tenant/http.js";
6
+ import { listRuns, listTriggers, receiveWebhook, rotateWebhookSecret, runTriggerNow, setTriggerStatus, } from "../../../tenant/triggers.js";
7
+ import { readRuntimeLimits } from "../../../tenant/runtime-limits.js";
8
+ import { readBytes } from "../body.js";
9
+ import { tenantRoute } from "../define.js";
10
+ import { pageQuery, pageSize, parseQuery } from "./reads.js";
11
+ import { jsonResponse } from "../respond.js";
12
+ const READ = {
13
+ credentials: ["application", "subject", "token"],
14
+ scopes: ["sessions:own", "agents:read", "agents:write"],
15
+ };
16
+ const WRITE = {
17
+ credentials: ["application", "subject", "token"],
18
+ scopes: ["agents:write"],
19
+ };
20
+ const json = (schema, description) => ({
21
+ description,
22
+ content: { "application/json": { schema } },
23
+ });
24
+ const agentId = z.object({
25
+ agentId: z.string().meta({ description: "The Agent id, percent-encoded" }),
26
+ });
27
+ const triggerPath = agentId.extend({
28
+ triggerId: z.string().meta({ description: "The trigger's id in the manifest's `runtime.triggers`" }),
29
+ });
30
+ function idOf(value) {
31
+ if (!isAgentId(value))
32
+ return fail(400, "An Agent id is up to 200 characters: /-separated segments of letters, digits, '.', '_' and '-'");
33
+ return value;
34
+ }
35
+ export function triggerRoutes(api) {
36
+ tenantRoute(api, READ, {
37
+ method: "get",
38
+ path: "/v1/agents/{agentId}/triggers",
39
+ tags: ["Triggers"],
40
+ summary: "List an Agent's triggers",
41
+ description: "Each trigger its manifest declares, with what the Agent holds of it: its status (`active`, `paused` with a reason, `completed` for an `at` that ran), when it runs next and last ran.",
42
+ request: { params: agentId },
43
+ responses: { 200: json(TriggerList, "The triggers") },
44
+ }, async (c) => {
45
+ const id = idOf(c.req.param("agentId"));
46
+ assertReaches(c.get("scope"), id);
47
+ return jsonResponse(200, await listTriggers(c.env.tenant, id, originOf(c.req.url)));
48
+ });
49
+ for (const action of ["pause", "resume"])
50
+ tenantRoute(api, WRITE, {
51
+ method: "post",
52
+ path: `/v1/agents/{agentId}/triggers/{triggerId}/${action}`,
53
+ tags: ["Triggers"],
54
+ summary: action === "pause" ? "Pause a trigger" : "Resume a trigger",
55
+ description: action === "pause"
56
+ ? "It stops firing until it is resumed; a run already started or queued goes on."
57
+ : "It fires again from its next time after now; missed times are not run. An `at` whose time has passed is refused (`trigger_expired`).",
58
+ request: { params: triggerPath },
59
+ responses: {
60
+ 200: json(TriggerList, "The Agent's triggers"),
61
+ 409: { description: "An `at` whose time has passed (`trigger_expired`)" },
62
+ },
63
+ }, async (c) => {
64
+ const id = idOf(c.req.param("agentId"));
65
+ assertReaches(c.get("scope"), id);
66
+ return jsonResponse(200, await setTriggerStatus(c.env.tenant, id, c.req.param("triggerId"), action, originOf(c.req.url)));
67
+ });
68
+ tenantRoute(api, WRITE, {
69
+ method: "post",
70
+ path: "/v1/agents/{agentId}/triggers/{triggerId}/run",
71
+ tags: ["Triggers"],
72
+ summary: "Run a trigger now",
73
+ description: "Runs it once now, paused or not, as if it had fired: a turn on its session, or a queued message when a turn runs there. A retried request with the same `Idempotency-Key` answers the same run.",
74
+ request: {
75
+ params: triggerPath,
76
+ headers: z.object({ "Idempotency-Key": z.string().min(1).max(200) }),
77
+ },
78
+ responses: { 200: json(RunTriggerResponse, "The run") },
79
+ }, async (c) => {
80
+ const id = idOf(c.req.param("agentId"));
81
+ assertReaches(c.get("scope"), id);
82
+ const key = c.req.header("idempotency-key")?.trim();
83
+ if (!key || key.length > 200)
84
+ fail(400, "Idempotency-Key is required: 1-200 characters");
85
+ return jsonResponse(200, { run: await runTriggerNow(c.env.tenant, id, c.req.param("triggerId"), key) });
86
+ });
87
+ tenantRoute(api, READ, {
88
+ method: "get",
89
+ path: "/v1/agents/{agentId}/runs",
90
+ tags: ["Triggers"],
91
+ summary: "List an Agent's runs",
92
+ description: "Each time one of its triggers fired or was run by hand, newest first: when it was due, whether it was late, and what came of it (`started`, `queued`, `skipped` or `failed`, with a reason), with the session and turn.",
93
+ request: {
94
+ params: agentId,
95
+ query: pageQuery.extend({
96
+ triggerId: z.string().optional().meta({ description: "Only this trigger's runs" }),
97
+ }),
98
+ },
99
+ responses: { 200: json(TriggerRunPage, "A page of runs") },
100
+ }, async (c) => {
101
+ const id = idOf(c.req.param("agentId"));
102
+ assertReaches(c.get("scope"), id);
103
+ const triggerId = c.req.query("triggerId");
104
+ const { limit, cursor } = parseQuery(pageQuery, { limit: c.req.query("limit"), cursor: c.req.query("cursor") });
105
+ return jsonResponse(200, await listRuns(c.env.tenant, id, {
106
+ ...(triggerId ? { triggerId } : {}),
107
+ ...(cursor ? { cursor } : {}),
108
+ limit: await pageSize(c.env.tenant, limit, { fallback: 50 }),
109
+ }));
110
+ });
111
+ }
112
+ /** A delivery: no credential, no protocol header, any body; the endpoint id and the signature are the grant. */
113
+ const DELIVERY = {
114
+ credentials: ["application", "subject", "token"],
115
+ scopes: "any",
116
+ anonymous: true,
117
+ unversioned: true,
118
+ bytes: true,
119
+ };
120
+ export function webhookRoutes(api) {
121
+ tenantRoute(api, WRITE, {
122
+ method: "post",
123
+ path: "/v1/agents/{agentId}/triggers/{triggerId}/secret",
124
+ tags: ["Triggers"],
125
+ summary: "Make a webhook trigger's signing secret",
126
+ description: "A new Standard Webhooks secret (`whsec_…`) for a webhook trigger, shown this once; the one before stops working at once. Give it to the sender with the trigger's `webhookUrl`.",
127
+ request: { params: triggerPath },
128
+ responses: {
129
+ 200: json(WebhookSecretResponse, "The secret, this once"),
130
+ 400: { description: "Not a webhook trigger" },
131
+ },
132
+ }, async (c) => {
133
+ const id = idOf(c.req.param("agentId"));
134
+ assertReaches(c.get("scope"), id);
135
+ return jsonResponse(200, await rotateWebhookSecret(c.env.tenant, id, c.req.param("triggerId"), originOf(c.req.url)));
136
+ });
137
+ tenantRoute(api, DELIVERY, {
138
+ method: "post",
139
+ path: "/v1/webhooks/{endpointId}",
140
+ tags: ["Triggers"],
141
+ summary: "Deliver to a webhook trigger",
142
+ description: "A sender's delivery, signed with Standard Webhooks (`webhook-id`, `webhook-timestamp` within 5 minutes by default, `webhook-signature`): no credential and no `Nylorun-Protocol`. The body, any media type, at most the Runtime limit `webhookBodyBytes`, is read as bytes and verified before anything else. It runs the trigger once per `webhook-id`: a retry answers the first run. The body reaches the model as data under the trigger's prompt. Other senders (GitHub, Stripe, Slack) are relayed by an app.",
143
+ request: {
144
+ params: z.object({ endpointId: z.string().meta({ description: "The trigger's endpoint id, `wh_…`" }) }),
145
+ headers: z.object({
146
+ "webhook-id": z.string().optional().meta({ description: "The delivery's id; a retry sends the same" }),
147
+ "webhook-timestamp": z.string().optional().meta({ description: "Seconds since the epoch" }),
148
+ "webhook-signature": z.string().optional().meta({ description: "`v1,<base64>`, space-separated" }),
149
+ }),
150
+ body: {
151
+ required: true,
152
+ description: "The payload, of any media type",
153
+ content: { "*/*": { schema: z.string().meta({ format: "binary" }) } },
154
+ },
155
+ },
156
+ responses: {
157
+ 202: json(WebhookAcceptedResponse, "The run it made: started, queued, skipped or failed"),
158
+ 401: { description: "Not signed with the endpoint's secret, or a timestamp out of tolerance" },
159
+ 404: { description: "No endpoint has this id" },
160
+ 409: { description: "The trigger is paused (`trigger_paused`)" },
161
+ 413: { description: "Over `webhookBodyBytes`" },
162
+ },
163
+ }, async (c) => {
164
+ const tenant = c.env.tenant;
165
+ const { webhookBodyBytes } = await tenant.store.tx((t) => readRuntimeLimits(t));
166
+ const body = await readBytes(c.req.raw, webhookBodyBytes, "webhookBodyBytes");
167
+ const header = (name) => c.req.header(name)?.trim() || undefined;
168
+ return jsonResponse(202, await receiveWebhook(tenant, c.req.param("endpointId"), {
169
+ id: header("webhook-id"),
170
+ timestamp: header("webhook-timestamp"),
171
+ signature: header("webhook-signature"),
172
+ contentType: header("content-type"),
173
+ body,
174
+ }));
175
+ });
176
+ }
177
+ /** The origin a request reached: where its webhook URLs live. */
178
+ function originOf(url) {
179
+ return new URL(url).origin;
180
+ }
@@ -11,13 +11,6 @@
11
11
  import type { MessagePart } from "@nylorun/core/contracts";
12
12
  import { type ArtifactAccess } from "../artifacts/service.js";
13
13
  import type { TenantContext } from "../tenant/context.js";
14
- /** The largest file a message may carry inline, decoded. */
15
- export declare const INLINE_FILE_MAX_BYTES: number;
16
- /**
17
- * The request body of an endpoint that takes inline files: one file at the cap, base64-encoded
18
- * (a third larger), and the rest of the request.
19
- */
20
- export declare const INLINE_BODY_MAX_BYTES: number;
21
14
  /** A file sent inline: its name, declared media type and base64 bytes. */
22
15
  export interface InlineFile {
23
16
  readonly name: string;
@@ -40,8 +33,9 @@ export declare function refuseUrl(): never;
40
33
  /** A name for a file its client did not name: its place in the message and its type's extension. */
41
34
  export declare function inlineFileName(mediaType: string, index: number): string;
42
35
  /**
43
- * Stores `file` as a new artifact of `sessionId`, within the inline cap and the Tenant's
44
- * artifact limits: `400` for bad base64 or a bad media type, `413 limit_exceeded` past a limit.
36
+ * Stores `file` as a new artifact of `sessionId`, within the Tenant's Runtime limit
37
+ * `inlineFileBytes` (read for the file) and its artifact limits: `400` for bad base64 or a bad
38
+ * media type, `413 limit_exceeded` past a limit.
45
39
  */
46
40
  export declare function storeInlineFile(ctx: TenantContext, sessionId: string, file: InlineFile, access: ArtifactAccess): Promise<{
47
41
  artifactId: string;
@@ -1,15 +1,8 @@
1
- import { MAX_MESSAGE_PARTS } from "@nylorun/core/contracts";
2
1
  import { commandKey } from "../core/flow-host.js";
3
- import { extensionFor, normalizeContentType } from "../artifacts/media-types.js";
2
+ import { extensionFor, normalizeContentType } from "@nylorun/core/contracts";
4
3
  import { deleteArtifact, uploadArtifact } from "../artifacts/service.js";
5
4
  import { fail } from "../tenant/http.js";
6
- /** The largest file a message may carry inline, decoded. */
7
- export const INLINE_FILE_MAX_BYTES = 20 * 1024 * 1024;
8
- /**
9
- * The request body of an endpoint that takes inline files: one file at the cap, base64-encoded
10
- * (a third larger), and the rest of the request.
11
- */
12
- export const INLINE_BODY_MAX_BYTES = 28 * 1024 * 1024;
5
+ import { readRuntimeLimits } from "../tenant/runtime-limits.js";
13
6
  const BASE64 = /^[A-Za-z0-9+/_-]*={0,2}$/;
14
7
  /** The 400 for a file sent by URL. */
15
8
  export function refuseUrl() {
@@ -23,26 +16,26 @@ export function inlineFileName(mediaType, index) {
23
16
  return `file-${index + 1}${extension ? `.${extension}` : ""}`;
24
17
  }
25
18
  /**
26
- * Stores `file` as a new artifact of `sessionId`, within the inline cap and the Tenant's
27
- * artifact limits: `400` for bad base64 or a bad media type, `413 limit_exceeded` past a limit.
19
+ * Stores `file` as a new artifact of `sessionId`, within the Tenant's Runtime limit
20
+ * `inlineFileBytes` (read for the file) and its artifact limits: `400` for bad base64 or a bad
21
+ * media type, `413 limit_exceeded` past a limit.
28
22
  */
29
23
  export async function storeInlineFile(ctx, sessionId, file, access) {
30
24
  const data = file.data.replace(/\s+/gu, "");
31
25
  if (!BASE64.test(data) || data.length % 4 === 1)
32
26
  fail(400, `File "${file.name}" is not valid base64`, { code: "invalid_request" });
33
- // Three bytes per four characters, before decoding a byte.
34
- if (Math.floor((data.length * 3) / 4) > INLINE_FILE_MAX_BYTES + 2)
35
- fail(413, `A file sent inline may hold at most ${INLINE_FILE_MAX_BYTES} bytes`, {
36
- code: "limit_exceeded",
37
- details: { limitBytes: INLINE_FILE_MAX_BYTES },
38
- });
27
+ const { inlineFileBytes } = await ctx.store.tx((t) => readRuntimeLimits(t));
28
+ const tooLarge = () => fail(413, `A file sent inline may hold at most ${inlineFileBytes} bytes (the Runtime limit inlineFileBytes)`, {
29
+ code: "limit_exceeded",
30
+ details: { limitBytes: inlineFileBytes },
31
+ });
32
+ // Three bytes per four characters, before decoding a byte; padding may take up to two.
33
+ if (Math.floor((data.length * 3) / 4) > inlineFileBytes + 2)
34
+ tooLarge();
39
35
  // Node's base64 decoder reads both alphabets.
40
36
  const bytes = Buffer.from(data, "base64");
41
- if (bytes.byteLength > INLINE_FILE_MAX_BYTES)
42
- fail(413, `A file sent inline may hold at most ${INLINE_FILE_MAX_BYTES} bytes`, {
43
- code: "limit_exceeded",
44
- details: { limitBytes: INLINE_FILE_MAX_BYTES },
45
- });
37
+ if (bytes.byteLength > inlineFileBytes)
38
+ tooLarge();
46
39
  if (bytes.byteLength === 0)
47
40
  fail(400, `File "${file.name}" is empty`, { code: "invalid_request" });
48
41
  const contentType = normalizeContentType(file.mediaType) ??
@@ -73,8 +66,9 @@ export async function priorParts(ctx, sessionId, idempotencyKey) {
73
66
  */
74
67
  export async function messageParts(ctx, sessionId, idempotencyKey, inbound, access) {
75
68
  const parts = inbound.filter((part) => part.type !== "text" || part.text !== "");
76
- if (parts.length > MAX_MESSAGE_PARTS)
77
- fail(400, `A message may carry at most ${MAX_MESSAGE_PARTS} parts`, { code: "invalid_request" });
69
+ const { messageParts: most } = await ctx.store.tx((t) => readRuntimeLimits(t));
70
+ if (parts.length > most)
71
+ fail(400, `A message may carry at most ${most} parts (the Runtime limit messageParts)`, { code: "invalid_request" });
78
72
  const prior = parts.some((part) => part.type === "inline")
79
73
  ? (await priorParts(ctx, sessionId, idempotencyKey))?.filter((part) => part.type === "file")
80
74
  : undefined;