@nylorun/runtime 0.25.0-beta → 0.27.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 (326) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/README.md +26 -16
  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.js +1 -1
  12. package/dist/api/a2a/endpoint.js +3 -4
  13. package/dist/api/a2a/protocol.js +4 -0
  14. package/dist/api/a2a/routes.d.ts +2 -6
  15. package/dist/api/a2a/routes.js +12 -18
  16. package/dist/api/ag-ui/endpoint.js +2 -3
  17. package/dist/api/ag-ui/routes.js +4 -4
  18. package/dist/api/components.d.ts +326 -45
  19. package/dist/api/components.js +5 -1
  20. package/dist/api/gate/keys.js +7 -4
  21. package/dist/api/gate/routes.d.ts +6 -2
  22. package/dist/api/gate/routes.js +15 -11
  23. package/dist/api/http/app.d.ts +2 -2
  24. package/dist/api/http/app.js +2 -2
  25. package/dist/api/http/body.d.ts +15 -3
  26. package/dist/api/http/body.js +15 -7
  27. package/dist/api/http/define.d.ts +1 -1
  28. package/dist/api/http/respond.js +7 -3
  29. package/dist/api/http/routes/access.js +5 -4
  30. package/dist/api/http/routes/artifacts.js +19 -7
  31. package/dist/api/http/routes/coverage.js +1 -1
  32. package/dist/api/http/routes/environment-manifests.js +1 -1
  33. package/dist/api/http/routes/environments.js +6 -6
  34. package/dist/api/http/routes/files.d.ts +2 -1
  35. package/dist/api/http/routes/files.js +31 -5
  36. package/dist/api/http/routes/mcp.js +1 -1
  37. package/dist/api/http/routes/reads.d.ts +35 -0
  38. package/dist/api/http/routes/reads.js +50 -22
  39. package/dist/api/http/routes/sessions.js +12 -11
  40. package/dist/api/http/routes/tenant.d.ts +2 -2
  41. package/dist/api/http/routes/tenant.js +69 -16
  42. package/dist/api/inbound-files.d.ts +3 -9
  43. package/dist/api/inbound-files.js +18 -24
  44. package/dist/api/openapi.js +6 -2
  45. package/dist/artifacts/disk.d.ts +0 -4
  46. package/dist/artifacts/disk.js +77 -73
  47. package/dist/artifacts/files.d.ts +13 -4
  48. package/dist/artifacts/files.js +27 -9
  49. package/dist/artifacts/folder-upload.d.ts +75 -0
  50. package/dist/artifacts/folder-upload.js +263 -0
  51. package/dist/artifacts/folders.d.ts +14 -8
  52. package/dist/artifacts/folders.js +19 -11
  53. package/dist/artifacts/links.js +7 -6
  54. package/dist/artifacts/parts.d.ts +9 -14
  55. package/dist/artifacts/parts.js +11 -9
  56. package/dist/artifacts/pipe.d.ts +15 -0
  57. package/dist/artifacts/pipe.js +71 -0
  58. package/dist/artifacts/quota.d.ts +36 -0
  59. package/dist/artifacts/quota.js +44 -0
  60. package/dist/artifacts/service.d.ts +25 -1
  61. package/dist/artifacts/service.js +70 -25
  62. package/dist/blob/fs.js +2 -1
  63. package/dist/blob/s3.d.ts +6 -2
  64. package/dist/blob/s3.js +9 -7
  65. package/dist/blob/types.d.ts +1 -1
  66. package/dist/blob/types.js +1 -1
  67. package/dist/core/limits.d.ts +11 -35
  68. package/dist/core/limits.js +5 -73
  69. package/dist/core/sandbox-routes.js +0 -1
  70. package/dist/core/turn-manifest.d.ts +1 -2
  71. package/dist/core/turn-manifest.js +4 -28
  72. package/dist/execution/memory.d.ts +8 -5
  73. package/dist/execution/memory.js +8 -6
  74. package/dist/execution/types.d.ts +1 -6
  75. package/dist/execution/types.js +0 -5
  76. package/dist/gates/contract.d.ts +3 -2
  77. package/dist/gates/contract.js +1 -1
  78. package/dist/gates/egress-credentials.js +4 -3
  79. package/dist/gates/egress.d.ts +9 -9
  80. package/dist/gates/egress.js +19 -19
  81. package/dist/gates/fixture-model.js +13 -2
  82. package/dist/gates/handler.d.ts +1 -3
  83. package/dist/gates/handler.js +4 -3
  84. package/dist/gates/http-client.d.ts +4 -3
  85. package/dist/gates/http-client.js +5 -7
  86. package/dist/gates/http-tool.d.ts +24 -4
  87. package/dist/gates/http-tool.js +53 -17
  88. package/dist/gates/in-process.d.ts +2 -1
  89. package/dist/gates/in-process.js +17 -9
  90. package/dist/gates/inflight.d.ts +2 -2
  91. package/dist/gates/inflight.js +3 -2
  92. package/dist/gates/journal.js +5 -7
  93. package/dist/gates/mcp-handler.d.ts +4 -3
  94. package/dist/gates/mcp-handler.js +15 -5
  95. package/dist/gates/model-gate.d.ts +11 -2
  96. package/dist/gates/policy.d.ts +28 -5
  97. package/dist/gates/policy.js +60 -17
  98. package/dist/gates/provider-gate.d.ts +22 -0
  99. package/dist/gates/provider-gate.js +30 -0
  100. package/dist/gates/tool-calls.d.ts +1 -3
  101. package/dist/gates/tool-calls.js +2 -3
  102. package/dist/gates/tool-client.d.ts +1 -1
  103. package/dist/gates/tool-client.js +5 -6
  104. package/dist/gates/tool-contract.d.ts +8 -5
  105. package/dist/gates/tool-contract.js +1 -1
  106. package/dist/gates/tool-gate.d.ts +18 -7
  107. package/dist/gates/tool-gate.js +49 -7
  108. package/dist/harness/calls.d.ts +27 -25
  109. package/dist/harness/calls.js +40 -46
  110. package/dist/harness/executors.d.ts +10 -3
  111. package/dist/harness/executors.js +53 -23
  112. package/dist/harness/main.js +2 -2
  113. package/dist/harness/pod.d.ts +0 -2
  114. package/dist/harness/pod.js +7 -6
  115. package/dist/harness/run-tokens.d.ts +4 -1
  116. package/dist/harness/run-tokens.js +6 -2
  117. package/dist/harness/service.d.ts +17 -14
  118. package/dist/harness/service.js +21 -35
  119. package/dist/harness/setup.d.ts +0 -2
  120. package/dist/harness/setup.js +4 -9
  121. package/dist/harness/ws-client.d.ts +2 -2
  122. package/dist/harness/ws-client.js +7 -5
  123. package/dist/harness/ws-port.d.ts +3 -4
  124. package/dist/harness/ws-port.js +3 -4
  125. package/dist/harness-api/artifacts.d.ts +20 -0
  126. package/dist/harness-api/artifacts.js +478 -0
  127. package/dist/harness-api/in-process.d.ts +2 -2
  128. package/dist/harness-api/in-process.js +18 -16
  129. package/dist/harness-api/record.d.ts +10 -9
  130. package/dist/harness-api/record.js +102 -157
  131. package/dist/harness-api/renew.d.ts +1 -1
  132. package/dist/harness-api/renew.js +2 -2
  133. package/dist/harness-api/server.d.ts +1 -16
  134. package/dist/harness-api/server.js +82 -73
  135. package/dist/harness-api/start.d.ts +20 -2
  136. package/dist/harness-api/start.js +57 -18
  137. package/dist/harness-api/tool-journal.d.ts +15 -10
  138. package/dist/harness-api/tool-journal.js +26 -24
  139. package/dist/harness-api/workspace.d.ts +0 -4
  140. package/dist/harness-api/workspace.js +2 -45
  141. package/dist/harness-api/ws-server.js +10 -10
  142. package/dist/host/create-host.js +2 -3
  143. package/dist/host/execution.js +2 -3
  144. package/dist/host/gates.d.ts +2 -9
  145. package/dist/host/gates.js +15 -12
  146. package/dist/host/http.d.ts +0 -2
  147. package/dist/host/http.js +0 -27
  148. package/dist/host/main.js +10 -3
  149. package/dist/host/operate.js +12 -3
  150. package/dist/host/stack-config.d.ts +11 -0
  151. package/dist/host/stack-config.js +21 -1
  152. package/dist/index.d.ts +0 -1
  153. package/dist/index.js +0 -1
  154. package/dist/infra/index.js +2 -1
  155. package/dist/infra/readiness.d.ts +0 -2
  156. package/dist/infra/readiness.js +4 -3
  157. package/dist/keys/client.d.ts +1 -0
  158. package/dist/keys/client.js +2 -3
  159. package/dist/keys/contract.d.ts +1 -3
  160. package/dist/keys/contract.js +1 -3
  161. package/dist/keys/egress-ca.d.ts +0 -2
  162. package/dist/keys/egress-ca.js +2 -3
  163. package/dist/keys/keys.js +6 -1
  164. package/dist/keys/x509.d.ts +8 -4
  165. package/dist/keys/x509.js +14 -5
  166. package/dist/management-openapi.json +1961 -994
  167. package/dist/mcp/connect.d.ts +35 -26
  168. package/dist/mcp/connect.js +112 -141
  169. package/dist/mcp/pool.d.ts +27 -22
  170. package/dist/mcp/pool.js +34 -48
  171. package/dist/mcp/preview.d.ts +13 -6
  172. package/dist/mcp/preview.js +37 -20
  173. package/dist/mcp/snapshot.d.ts +35 -86
  174. package/dist/mcp/snapshot.js +93 -135
  175. package/dist/model/auth-store.js +5 -3
  176. package/dist/model/capabilities.d.ts +1 -1
  177. package/dist/model/catalog.d.ts +9 -36
  178. package/dist/model/catalog.js +6 -33
  179. package/dist/model/descriptor.d.ts +51 -0
  180. package/dist/model/descriptor.js +83 -0
  181. package/dist/model/models.d.ts +0 -3
  182. package/dist/model/models.js +3 -5
  183. package/dist/model/native-blocks.js +1 -1
  184. package/dist/model/pi-model.d.ts +16 -5
  185. package/dist/model/pi-model.js +86 -105
  186. package/dist/openapi.json +866 -1218
  187. package/dist/reads/cursor.js +3 -1
  188. package/dist/record/append.d.ts +34 -2
  189. package/dist/record/append.js +50 -1
  190. package/dist/record/environment.d.ts +2 -0
  191. package/dist/record/environment.js +2 -0
  192. package/dist/record/index.d.ts +1 -1
  193. package/dist/record/index.js +1 -1
  194. package/dist/redact.d.ts +1 -1
  195. package/dist/redact.js +3 -2
  196. package/dist/sandbox/egress-token.d.ts +3 -3
  197. package/dist/sandbox/egress-token.js +3 -3
  198. package/dist/sandbox/join.js +3 -2
  199. package/dist/sandbox/manager.d.ts +41 -41
  200. package/dist/sandbox/manager.js +112 -44
  201. package/dist/sandbox/placement.d.ts +1 -1
  202. package/dist/sandbox/placement.js +5 -8
  203. package/dist/sandbox/pods/client.d.ts +1 -10
  204. package/dist/sandbox/pods/client.js +8 -4
  205. package/dist/sandbox/pods/lifecycle.d.ts +19 -11
  206. package/dist/sandbox/pods/lifecycle.js +45 -23
  207. package/dist/sandbox/pods/network-gate.d.ts +4 -5
  208. package/dist/sandbox/pods/network-gate.js +7 -7
  209. package/dist/sandbox/pods/reconcile.js +4 -1
  210. package/dist/sandbox/pods/spec.js +8 -5
  211. package/dist/sandbox/policy.d.ts +7 -1
  212. package/dist/sandbox/policy.js +10 -3
  213. package/dist/sandbox/resolve.d.ts +8 -3
  214. package/dist/sandbox/resolve.js +12 -2
  215. package/dist/sandbox/setup.d.ts +3 -1
  216. package/dist/sandbox/setup.js +34 -11
  217. package/dist/sandbox/share.d.ts +5 -14
  218. package/dist/sandbox/share.js +5 -34
  219. package/dist/sandbox/skills.d.ts +7 -13
  220. package/dist/sandbox/skills.js +16 -31
  221. package/dist/sandbox/tenant-config.d.ts +2 -2
  222. package/dist/sandbox/tenant-config.js +4 -3
  223. package/dist/sandbox/tools.d.ts +7 -1
  224. package/dist/sandbox/tools.js +26 -26
  225. package/dist/sandbox/types.d.ts +10 -3
  226. package/dist/sandbox/types.js +9 -0
  227. package/dist/store/postgres/connect.d.ts +6 -5
  228. package/dist/store/postgres/connect.js +14 -11
  229. package/dist/store/postgres/control.js +13 -13
  230. package/dist/store/postgres/drizzle/0028_artifact_write_keys.sql +2 -0
  231. package/dist/store/postgres/drizzle/0029_protocol_15.sql +11 -0
  232. package/dist/store/postgres/drizzle/0030_protocol_15_runtime_block.sql +11 -0
  233. package/dist/store/postgres/drizzle/0031_protocol_15_mcp_snapshot.sql +8 -0
  234. package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
  235. package/dist/store/postgres/migrate.js +1 -1
  236. package/dist/store/postgres/reads.js +10 -2
  237. package/dist/store/postgres/schema.d.ts +19 -0
  238. package/dist/store/postgres/schema.js +7 -0
  239. package/dist/store/postgres/store.js +55 -26
  240. package/dist/store/types.d.ts +17 -7
  241. package/dist/streams/relay/core.d.ts +3 -3
  242. package/dist/streams/relay/core.js +9 -10
  243. package/dist/tenant/advance.js +21 -31
  244. package/dist/tenant/commands.js +9 -16
  245. package/dist/tenant/context.d.ts +14 -17
  246. package/dist/tenant/definition-files.d.ts +25 -4
  247. package/dist/tenant/definition-files.js +85 -47
  248. package/dist/tenant/effects.js +9 -36
  249. package/dist/tenant/environment-manifests.js +9 -1
  250. package/dist/tenant/environments.d.ts +0 -2
  251. package/dist/tenant/environments.js +54 -30
  252. package/dist/tenant/ephemeral.d.ts +1 -1
  253. package/dist/tenant/ephemeral.js +2 -1
  254. package/dist/tenant/history.d.ts +1 -1
  255. package/dist/tenant/history.js +1 -1
  256. package/dist/tenant/host-token.d.ts +3 -3
  257. package/dist/tenant/host-token.js +12 -11
  258. package/dist/tenant/http.d.ts +5 -8
  259. package/dist/tenant/http.js +9 -0
  260. package/dist/tenant/identity-file.d.ts +24 -1
  261. package/dist/tenant/identity-file.js +35 -7
  262. package/dist/tenant/issuers.d.ts +5 -5
  263. package/dist/tenant/issuers.js +31 -23
  264. package/dist/tenant/jwt.d.ts +8 -2
  265. package/dist/tenant/jwt.js +10 -2
  266. package/dist/tenant/limits.d.ts +90 -0
  267. package/dist/tenant/limits.js +175 -0
  268. package/dist/tenant/module.d.ts +4 -1
  269. package/dist/tenant/module.js +9 -8
  270. package/dist/tenant/outbound.d.ts +17 -19
  271. package/dist/tenant/outbound.js +18 -21
  272. package/dist/tenant/run-grants.js +3 -2
  273. package/dist/tenant/run-token.d.ts +0 -4
  274. package/dist/tenant/run-token.js +6 -11
  275. package/dist/tenant/runtime-limits.d.ts +24 -0
  276. package/dist/tenant/runtime-limits.js +27 -0
  277. package/dist/tenant/runtime.js +30 -43
  278. package/dist/tenant/session-streams.js +7 -6
  279. package/dist/tenant/session.d.ts +1 -1
  280. package/dist/tenant/session.js +1 -1
  281. package/dist/tenant/sessions.js +32 -29
  282. package/dist/tenant/signing-keys.d.ts +1 -1
  283. package/dist/tenant/signing-keys.js +5 -6
  284. package/dist/tenant/status.js +4 -3
  285. package/dist/tenant/streams.js +18 -20
  286. package/dist/tenant/sweep.d.ts +1 -21
  287. package/dist/tenant/sweep.js +39 -48
  288. package/dist/tenant/transcript.d.ts +70 -23
  289. package/dist/tenant/transcript.js +28 -22
  290. package/dist/tenant/types.d.ts +11 -16
  291. package/dist/tenant/worker.d.ts +2 -10
  292. package/dist/tenant/worker.js +5 -14
  293. package/dist/traces/ids.js +5 -1
  294. package/dist/traces/map.d.ts +9 -6
  295. package/dist/traces/map.js +9 -11
  296. package/dist/traces/otlp.d.ts +3 -3
  297. package/dist/traces/otlp.js +5 -3
  298. package/dist/traces/projector.d.ts +9 -4
  299. package/dist/traces/projector.js +13 -7
  300. package/dist/traces/read.js +6 -1
  301. package/dist/tuning.d.ts +383 -0
  302. package/dist/tuning.js +658 -0
  303. package/dist/vault/headers.js +4 -2
  304. package/dist/version.d.ts +1 -1
  305. package/dist/version.js +1 -1
  306. package/package.json +3 -3
  307. package/dist/artifacts/export.d.ts +0 -8
  308. package/dist/artifacts/export.js +0 -204
  309. package/dist/artifacts/media-types.d.ts +0 -30
  310. package/dist/artifacts/media-types.js +0 -137
  311. package/dist/artifacts/workspace.d.ts +0 -60
  312. package/dist/artifacts/workspace.js +0 -45
  313. package/dist/media.d.ts +0 -10
  314. package/dist/media.js +0 -58
  315. package/dist/sandbox/runtime-tools.d.ts +0 -9
  316. package/dist/sandbox/runtime-tools.js +0 -16
  317. package/dist/sandbox/session-sandbox.d.ts +0 -16
  318. package/dist/sandbox/session-sandbox.js +0 -77
  319. package/dist/tenant/artifact-tool.d.ts +0 -13
  320. package/dist/tenant/artifact-tool.js +0 -243
  321. package/dist/tenant/skill-tool.d.ts +0 -20
  322. package/dist/tenant/skill-tool.js +0 -67
  323. package/dist/tenant/tool-results.d.ts +0 -57
  324. package/dist/tenant/tool-results.js +0 -298
  325. package/dist/tenant/tool-search.d.ts +0 -39
  326. package/dist/tenant/tool-search.js +0 -103
@@ -52,10 +52,12 @@ import { AsyncLocalStorage } from "node:async_hooks";
52
52
  import { randomUUID } from "node:crypto";
53
53
  import { and, count, desc, eq, getTableColumns, gte, gt, inArray, isNotNull, isNull, lt, lte, ne, or, sql, } from "drizzle-orm";
54
54
  import { appendEnvironmentEvent, appendEvent } from "../../record/index.js";
55
+ import { readRuntimeLimits } from "../../tenant/runtime-limits.js";
55
56
  import { OwnershipLostError, PrincipalRoleConflict } from "../ownership.js";
56
57
  import { followControlSignals, pruneSignals, writeSignal } from "./control.js";
57
58
  import { database, driverError } from "./db.js";
58
59
  import { expectedSchemaVersion, readSchemaVersion } from "./migrate.js";
60
+ import { hostTuning } from "../../tuning.js";
59
61
  import { createPostgresRecordReader } from "./record.js";
60
62
  import { postgresEnvironmentRecordWriter, postgresRecordWriter } from "./record-writer.js";
61
63
  import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, environmentEvents, environments, environmentManifests, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, sandboxSignals, wakes, } from "./schema.js";
@@ -63,8 +65,8 @@ export function createPostgresSessionStore(options) {
63
65
  return new PostgresSessionStore(options);
64
66
  }
65
67
  const OPEN_SESSION = ["running", "runnable"];
66
- /** Rows per statement when a folder version names many files. */
67
- const CONTENT_BATCH = 1000;
68
+ /** Rows per statement when a folder version or a definition names many files (Host tuning). */
69
+ const contentBatch = () => hostTuning().postgres.contentBatchRows;
68
70
  const DOCUMENTS = {
69
71
  definitions,
70
72
  sessions: sessions,
@@ -430,6 +432,7 @@ class PostgresTx {
430
432
  type,
431
433
  payload,
432
434
  ...(writer ? { writer } : {}),
435
+ maxEntryBytes: await this.maxEntryBytes(),
433
436
  });
434
437
  this.events.push(event);
435
438
  this.generations.push(generation);
@@ -770,16 +773,22 @@ class PostgresTx {
770
773
  time: this.now(),
771
774
  type,
772
775
  payload,
776
+ maxEntryBytes: await this.maxEntryBytes(),
773
777
  });
774
778
  }
779
+ /** The Tenant's Runtime limit `recordEntryBytes`, read in this transaction for each write. */
780
+ async maxEntryBytes() {
781
+ return (await readRuntimeLimits(this)).recordEntryBytes;
782
+ }
775
783
  async environmentEvents(environmentId, options = {}) {
776
784
  this.check();
777
- const rows = await this.db
785
+ const query = this.db
778
786
  .select({ body: environmentEvents.body })
779
787
  .from(environmentEvents)
780
788
  .where(and(eq(environmentEvents.environmentId, environmentId), options.fromSeq === undefined ? undefined : gte(environmentEvents.seq, options.fromSeq), options.types === undefined ? undefined : inArray(environmentEvents.type, [...options.types]), options.since === undefined ? undefined : gte(environmentEvents.committedAt, options.since), options.until === undefined ? undefined : lt(environmentEvents.committedAt, options.until)))
781
789
  .orderBy(environmentEvents.seq)
782
- .limit(options.limit ?? 1000);
790
+ .$dynamic();
791
+ const rows = await (options.limit === undefined ? query : query.limit(options.limit));
783
792
  return rows.map((row) => row.body);
784
793
  }
785
794
  async effectBodies(where) {
@@ -1181,6 +1190,11 @@ class PostgresTx {
1181
1190
  .where(and(eq(artifactVersions.artifactId, artifactId), eq(artifactVersions.version, version)));
1182
1191
  return row;
1183
1192
  }
1193
+ async artifactVersionByWriteKey(writeKey) {
1194
+ this.check();
1195
+ const [row] = await this.db.select().from(artifactVersions).where(eq(artifactVersions.writeKey, writeKey));
1196
+ return row;
1197
+ }
1184
1198
  async artifactVersions(artifactId) {
1185
1199
  this.check();
1186
1200
  return this.db
@@ -1220,21 +1234,32 @@ class PostgresTx {
1220
1234
  this.check();
1221
1235
  await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext('nylorun.artifacts'))`);
1222
1236
  }
1223
- async artifactBytes() {
1237
+ /** The artifacts of Environment `environmentId`: its disk versions, and its sessions'. */
1238
+ artifactsOfEnvironment(environmentId) {
1239
+ return or(eq(artifacts.environmentId, environmentId), inArray(artifacts.sessionId, this.db.select({ id: sessions.id }).from(sessions).where(eq(sessions.environmentId, environmentId))));
1240
+ }
1241
+ async artifactBytes(scope) {
1224
1242
  this.check();
1243
+ const within = scope === undefined ? undefined : this.artifactsOfEnvironment(scope.environmentId);
1225
1244
  const [files] = await this.db
1226
1245
  .select({
1227
1246
  bytes: sql `coalesce(sum(${artifactVersions.size}), 0)::bigint`.mapWith(Number),
1228
1247
  })
1229
1248
  .from(artifactVersions)
1230
1249
  .innerJoin(artifacts, eq(artifacts.id, artifactVersions.artifactId))
1231
- .where(eq(artifacts.kind, "file"));
1250
+ .where(within === undefined ? eq(artifacts.kind, "file") : and(eq(artifacts.kind, "file"), within));
1232
1251
  // A folder's files are stored once per distinct hash, however many versions name them.
1233
- const distinct = this.db
1234
- .select({ size: sql `max(${artifactContent.size})`.as("size") })
1235
- .from(artifactContent)
1236
- .groupBy(artifactContent.sha256)
1237
- .as("distinct_content");
1252
+ const distinct = (within === undefined
1253
+ ? this.db
1254
+ .select({ size: sql `max(${artifactContent.size})`.as("size") })
1255
+ .from(artifactContent)
1256
+ .groupBy(artifactContent.sha256)
1257
+ : this.db
1258
+ .select({ size: sql `max(${artifactContent.size})`.as("size") })
1259
+ .from(artifactContent)
1260
+ .innerJoin(artifacts, eq(artifacts.id, artifactContent.artifactId))
1261
+ .where(within)
1262
+ .groupBy(artifactContent.sha256)).as("distinct_content");
1238
1263
  const [content] = await this.db
1239
1264
  .select({ bytes: sql `coalesce(sum(${distinct.size}), 0)::bigint`.mapWith(Number) })
1240
1265
  .from(distinct);
@@ -1242,22 +1267,26 @@ class PostgresTx {
1242
1267
  }
1243
1268
  async insertArtifactContent(artifactId, version, files) {
1244
1269
  this.check();
1245
- for (let at = 0; at < files.length; at += CONTENT_BATCH)
1270
+ for (let at = 0; at < files.length; at += contentBatch())
1246
1271
  await this.db
1247
1272
  .insert(artifactContent)
1248
1273
  .values(files
1249
- .slice(at, at + CONTENT_BATCH)
1274
+ .slice(at, at + contentBatch())
1250
1275
  .map((file) => ({ artifactId, version, sha256: file.sha256, size: file.size })))
1251
1276
  .onConflictDoNothing();
1252
1277
  }
1253
- async referencedArtifactContent(shas) {
1278
+ async referencedArtifactContent(shas, scope) {
1254
1279
  this.check();
1255
1280
  const found = new Set();
1256
- for (let at = 0; at < shas.length; at += CONTENT_BATCH) {
1257
- const rows = await this.db
1258
- .selectDistinct({ sha256: artifactContent.sha256 })
1259
- .from(artifactContent)
1260
- .where(inArray(artifactContent.sha256, shas.slice(at, at + CONTENT_BATCH)));
1281
+ for (let at = 0; at < shas.length; at += contentBatch()) {
1282
+ const batch = inArray(artifactContent.sha256, shas.slice(at, at + contentBatch()));
1283
+ const rows = scope === undefined
1284
+ ? await this.db.selectDistinct({ sha256: artifactContent.sha256 }).from(artifactContent).where(batch)
1285
+ : await this.db
1286
+ .selectDistinct({ sha256: artifactContent.sha256 })
1287
+ .from(artifactContent)
1288
+ .innerJoin(artifacts, eq(artifacts.id, artifactContent.artifactId))
1289
+ .where(and(batch, this.artifactsOfEnvironment(scope.environmentId)));
1261
1290
  for (const row of rows)
1262
1291
  found.add(row.sha256);
1263
1292
  }
@@ -1302,23 +1331,23 @@ class PostgresTx {
1302
1331
  }
1303
1332
  async heldDefinitionFiles(shas) {
1304
1333
  this.check();
1305
- const found = new Set();
1306
- for (let at = 0; at < shas.length; at += CONTENT_BATCH) {
1334
+ const found = new Map();
1335
+ for (let at = 0; at < shas.length; at += contentBatch()) {
1307
1336
  const rows = await this.db
1308
- .select({ sha256: definitionFiles.sha256 })
1337
+ .select({ sha256: definitionFiles.sha256, size: definitionFiles.size })
1309
1338
  .from(definitionFiles)
1310
- .where(inArray(definitionFiles.sha256, shas.slice(at, at + CONTENT_BATCH)));
1339
+ .where(inArray(definitionFiles.sha256, shas.slice(at, at + contentBatch())));
1311
1340
  for (const row of rows)
1312
- found.add(row.sha256);
1341
+ found.set(row.sha256, row.size);
1313
1342
  }
1314
1343
  return found;
1315
1344
  }
1316
1345
  async insertDefinitionFileUses(agentId, manifestHash, shas) {
1317
1346
  this.check();
1318
- for (let at = 0; at < shas.length; at += CONTENT_BATCH)
1347
+ for (let at = 0; at < shas.length; at += contentBatch())
1319
1348
  await this.db
1320
1349
  .insert(definitionFileUses)
1321
- .values(shas.slice(at, at + CONTENT_BATCH).map((sha256) => ({ agentId, manifestHash, sha256 })))
1350
+ .values(shas.slice(at, at + contentBatch()).map((sha256) => ({ agentId, manifestHash, sha256 })))
1322
1351
  .onConflictDoNothing();
1323
1352
  }
1324
1353
  // --- settings ------------------------------------------------------------
@@ -408,7 +408,7 @@ export type ControlSignal = {
408
408
  epoch: number;
409
409
  };
410
410
  export interface FollowSignalsOptions {
411
- /** How often recent signals are read back. Default 5 s. */
411
+ /** How often recent signals are read back. Default `postgres.controlPollMs` (Host tuning, 5 s). */
412
412
  pollMs?: number;
413
413
  onError?: (error: unknown) => void;
414
414
  }
@@ -732,6 +732,8 @@ export interface Tx {
732
732
  /** One version, or every version oldest first. */
733
733
  artifactVersion(artifactId: string, version: number): Promise<ArtifactVersionRow | undefined>;
734
734
  artifactVersions(artifactId: string): Promise<ArtifactVersionRow[]>;
735
+ /** The version a harness write with this key stored (`artifact_versions.write_key`), if any. */
736
+ artifactVersionByWriteKey(writeKey: string): Promise<ArtifactVersionRow | undefined>;
735
737
  /** Deletes the artifact and its versions; returns the versions' blob keys (empty when none). */
736
738
  deleteArtifact(id: string): Promise<string[]>;
737
739
  /**
@@ -746,9 +748,12 @@ export interface Tx {
746
748
  lockArtifactQuota(): Promise<void>;
747
749
  /**
748
750
  * The bytes the artifacts store: every file version, plus each distinct content-addressed file
749
- * of the folders once (F8.2).
751
+ * of the folders once (F8.2). With `environmentId`, only that Environment's artifacts: its disk
752
+ * versions and its sessions' artifacts.
750
753
  */
751
- artifactBytes(): Promise<number>;
754
+ artifactBytes(scope?: {
755
+ environmentId: string;
756
+ }): Promise<number>;
752
757
  /**
753
758
  * The blob keys of every artifact version (a folder's: its manifests): of session artifacts
754
759
  * only, or of all of them.
@@ -759,8 +764,13 @@ export interface Tx {
759
764
  sha256: string;
760
765
  size: number;
761
766
  }[]): Promise<void>;
762
- /** Those of `shas` some committed folder version references. */
763
- referencedArtifactContent(shas: readonly string[]): Promise<Set<string>>;
767
+ /**
768
+ * Those of `shas` some committed folder version references; with `environmentId`, a version
769
+ * of one of that Environment's artifacts.
770
+ */
771
+ referencedArtifactContent(shas: readonly string[], scope?: {
772
+ environmentId: string;
773
+ }): Promise<Set<string>>;
764
774
  /**
765
775
  * The distinct content-addressed files folder versions reference: of one artifact, of session
766
776
  * artifacts only, or of all of them.
@@ -772,8 +782,8 @@ export interface Tx {
772
782
  definitionFile(sha256: string): Promise<DefinitionFileRow | undefined>;
773
783
  /** Records a stored definition file; false when the Tenant held it already. */
774
784
  insertDefinitionFile(row: DefinitionFileRow): Promise<boolean>;
775
- /** Those of `shas` the Tenant holds. */
776
- heldDefinitionFiles(shas: readonly string[]): Promise<Set<string>>;
785
+ /** Those of `shas` the Tenant holds, with each one's size in bytes. */
786
+ heldDefinitionFiles(shas: readonly string[]): Promise<Map<string, number>>;
777
787
  /** Records that version `manifestHash` of definition `agentId` names each of `shas`. */
778
788
  insertDefinitionFileUses(agentId: string, manifestHash: string, shas: readonly string[]): Promise<void>;
779
789
  getSetting(key: string): Promise<string | undefined>;
@@ -6,11 +6,11 @@ export interface StreamRelayOptions {
6
6
  streams: DurableStreams;
7
7
  /** Relay events: lag, errors, reconciliations. */
8
8
  log?: (message: string, fields?: Record<string, unknown>) => void;
9
- /** Records per append (S2 allows 1000). */
9
+ /** Records per append (S2 allows 1000). Default `streams.relayBatchRecords` (Host tuning, 500). */
10
10
  maxBatchRecords?: number;
11
- /** Bytes per append (S2 allows 1 MiB). */
11
+ /** Bytes per append (S2 allows 1 MiB). Default `streams.relayBatchBytes` (768 KiB). */
12
12
  maxBatchBytes?: number;
13
- /** Sessions reconciled at once. */
13
+ /** Sessions reconciled at once. Default `streams.relayReconcileConcurrency` (8). */
14
14
  reconcileConcurrency?: number;
15
15
  }
16
16
  export interface StreamRelayStatus {
@@ -23,17 +23,16 @@
23
23
  * The relay never writes the record and never deletes from S2.
24
24
  */
25
25
  import { sleep } from "../../retry.js";
26
+ import { hostTuning } from "../../tuning.js";
26
27
  import { basinOf } from "../basin.js";
27
28
  import { sessionStream } from "../types.js";
28
- const RETRY_MIN_MS = 50;
29
- const RETRY_MAX_MS = 2000;
30
- const HEADS_PAGE = 500;
31
29
  export function createStreamRelay(options) {
32
30
  const { source, record, streams } = options;
33
31
  const log = options.log ?? (() => { });
34
- const maxRecords = options.maxBatchRecords ?? 500;
35
- const maxBytes = options.maxBatchBytes ?? 768 * 1024;
36
- const concurrency = options.reconcileConcurrency ?? 8;
32
+ const tuning = hostTuning().streams;
33
+ const maxRecords = options.maxBatchRecords ?? tuning.relayBatchRecords;
34
+ const maxBytes = options.maxBatchBytes ?? tuning.relayBatchBytes;
35
+ const concurrency = options.reconcileConcurrency ?? tuning.relayReconcileConcurrency;
37
36
  /** Committed transactions not yet fully in S2, in commit order. */
38
37
  const txs = [];
39
38
  const sessions = new Map();
@@ -101,7 +100,7 @@ export function createStreamRelay(options) {
101
100
  }
102
101
  async function pump(queue) {
103
102
  queue.running = true;
104
- let delay = RETRY_MIN_MS;
103
+ let delay = tuning.relayRetry.minMs;
105
104
  try {
106
105
  while (queue.rows.length > 0 && !stopped) {
107
106
  // Duplicates (a replay overlapping a refill) and stale rows sort out here.
@@ -122,7 +121,7 @@ export function createStreamRelay(options) {
122
121
  // S2 is behind the record: re-send the gap first.
123
122
  await refill(queue, first.generation, result.tail, first.seq);
124
123
  }
125
- delay = RETRY_MIN_MS;
124
+ delay = tuning.relayRetry.minMs;
126
125
  lastError = null;
127
126
  }
128
127
  catch (error) {
@@ -143,7 +142,7 @@ export function createStreamRelay(options) {
143
142
  // The basin may be missing (S2 lost it, or it was never created).
144
143
  await streams.ensureTenant(basin).catch(() => undefined);
145
144
  await sleep(delay, stopping.signal);
146
- delay = Math.min(delay * 2, RETRY_MAX_MS);
145
+ delay = Math.min(delay * 2, tuning.relayRetry.maxMs);
147
146
  }
148
147
  }
149
148
  }
@@ -243,7 +242,7 @@ export function createStreamRelay(options) {
243
242
  for (;;) {
244
243
  if (!current())
245
244
  return false;
246
- const page = await record.heads(after, HEADS_PAGE);
245
+ const page = await record.heads(after, tuning.relayHeadsPage);
247
246
  if (page.length === 0)
248
247
  break;
249
248
  let next = 0;
@@ -47,15 +47,16 @@ import { endAdvance } from "./scheduler.js";
47
47
  import { harnessOf } from "./context.js";
48
48
  import { HARNESS_ID } from "../sandbox/placement.js";
49
49
  import { recoversModelCalls } from "./effects.js";
50
+ import { contextCompacted } from "./transcript.js";
50
51
  import { slimModelEffects } from "./slim.js";
51
52
  import { applyUpdates, leanState, transcriptShadow, withTranscript, } from "./history.js";
52
53
  import { command } from "./commands.js";
53
- import { exportOutputs } from "../artifacts/export.js";
54
54
  import { dropRunGrant, grantRun } from "./run-grants.js";
55
55
  import { startHeartbeat } from "../harness-api/renew.js";
56
56
  import { buildTurnStart, startSegment } from "../harness-api/start.js";
57
57
  import { touchEnvironment } from "./environments.js";
58
58
  import { endTurn, pauseTurn } from "./turn-timing.js";
59
+ import { hostTuning } from "../tuning.js";
59
60
  import { AdvanceAbort, AdvanceDeadlineError, abortKind, } from "./worker.js";
60
61
  /**
61
62
  * A segment stopped by a `shutdown` or `ownership.lost` abort before it settled. Never
@@ -95,15 +96,6 @@ class HarnessUnavailable extends Error {
95
96
  }
96
97
  }
97
98
  const DONE = { status: "done" };
98
- /** How soon an advance whose segment no harness took is tried again. */
99
- const UNAVAILABLE_RETRY_MS = 1000;
100
- /**
101
- * How long a pod sandbox's segment waits for its engine (F7.2): a pod that is starting, or
102
- * resuming, takes longer than a harness that is already connected.
103
- */
104
- const POD_OFFER_WAIT_MS = 60_000;
105
- /** Shortest `busy` retry, so a lease about to lapse is not polled in a tight loop. */
106
- const MIN_RETRY_MS = 25;
107
99
  /**
108
100
  * Advance session `id` if it has a runnable checkpoint (`WorkerHandlers.advance`). Returns
109
101
  * `busy` when another advance holds a live lease, `done` otherwise.
@@ -115,7 +107,10 @@ export async function advance(ctx, id, signal) {
115
107
  if (taken.status === "busy")
116
108
  return {
117
109
  status: "busy",
118
- retryAfterMs: Math.min(Math.max(Date.parse(taken.ownerExpiresAt) - Date.now(), MIN_RETRY_MS), ctx.ownerLeaseMs),
110
+ retryAfterMs: Math.min(
111
+ // The shortest `busy` retry (`tenant.busyRetryMinMs`), so a lease about to lapse is not
112
+ // polled in a tight loop.
113
+ Math.max(Date.parse(taken.ownerExpiresAt) - Date.now(), hostTuning().tenant.busyRetryMinMs), ctx.ownerLeaseMs),
119
114
  };
120
115
  if (taken.status === "idle")
121
116
  return DONE;
@@ -152,7 +147,7 @@ export async function advance(ctx, id, signal) {
152
147
  sessionId: id,
153
148
  epoch: lease.epoch,
154
149
  });
155
- result = { status: "busy", retryAfterMs: UNAVAILABLE_RETRY_MS };
150
+ result = { status: "busy", retryAfterMs: hostTuning().tenant.unavailableRetryMs };
156
151
  }
157
152
  else if (error instanceof SegmentStopped && error.kind === "shutdown") {
158
153
  // Left for the next advance, which resumes from the checkpoint once this one releases.
@@ -302,7 +297,8 @@ async function runRemoteSegment(ctx, lease, started, controller, run, onTaken, p
302
297
  onTaken,
303
298
  // Only a connection of the session's harness takes its runs (R4.1).
304
299
  harness: harnessOf(segment.current),
305
- ...(pod === undefined ? {} : { pod, waitMs: POD_OFFER_WAIT_MS }),
300
+ // A pod that is starting, or resuming, takes longer than a harness already connected.
301
+ ...(pod === undefined ? {} : { pod, waitMs: hostTuning().harnessApi.podOfferWaitMs }),
306
302
  });
307
303
  if (end.kind === "unavailable") {
308
304
  // A pod stopped, or not yet started: make sure it is asked to run.
@@ -313,9 +309,6 @@ async function runRemoteSegment(ctx, lease, started, controller, run, onTaken, p
313
309
  // Aborted before a harness took it: settled as an abort of the engine would be.
314
310
  if (end.kind === "aborted")
315
311
  throw signal.reason;
316
- // The harness's own tools take names of this turn's tools (Harness API 3): the turn fails.
317
- if (end.kind === "refused")
318
- throw new Error(end.message);
319
312
  // Checked before the abort: whatever core's signal says, the run's effects are unaccounted for.
320
313
  if (end.kind === "released" && end.reason === "connection.lost")
321
314
  throw new RunLost();
@@ -333,7 +326,7 @@ async function runRemoteSegment(ctx, lease, started, controller, run, onTaken, p
333
326
  await settleFailure(ctx, lease, started, signal.reason);
334
327
  else {
335
328
  const recorded = result.status === "yielded" || result.status === "completed" || result.status === "paused";
336
- cursor = await settleTurn(ctx, lease, started, result, recorded ? output.transcript ?? [] : [], signal, segment.cursor,
329
+ cursor = await settle(ctx, lease, started, result, recorded ? output.transcript ?? [] : [], segment.cursor,
337
330
  // The turn's end and its transcript are what the harness reported (R4.9).
338
331
  { source: { kind: "harness", id: harnessOf(started) }, evidence: "claimed", runId: output.runId });
339
332
  }
@@ -419,17 +412,6 @@ async function wakeWorkflowOf(ctx, t, agent, turnId, type, payload) {
419
412
  error: "Agent turn was cancelled",
420
413
  });
421
414
  }
422
- /**
423
- * `settle`, then, for a completed turn, the turn-end export of its sandbox outputs (F8.2): after
424
- * the turn has committed and while the advance still holds the lease. The harness hears back
425
- * after the export. The export never throws.
426
- */
427
- async function settleTurn(ctx, lease, s, result, updates, signal, cursor, writer) {
428
- const kept = await settle(ctx, lease, s, result, updates, cursor, writer);
429
- if (result.status === "completed")
430
- await exportOutputs(ctx, lease.sessionId, s.activeTurnId, signal);
431
- return kept;
432
- }
433
415
  /**
434
416
  * Record a segment result, then cancel failed siblings and wake a linked workflow. Returns the
435
417
  * cursor of the transcript it recorded (`cursor` when it recorded no edit), or undefined when
@@ -613,6 +595,10 @@ async function heldCalls(t, effectIds) {
613
595
  const request = row.request;
614
596
  const context = (request.context ?? {});
615
597
  const toolName = request.toolName ?? request.key ?? effectId;
598
+ // A person approves the tool by its identity (protocol 15): an MCP tool by server and tool.
599
+ const what = row.server !== undefined && row.tool !== undefined && row.toolKind === "mcp"
600
+ ? `${row.server} / ${row.tool}`
601
+ : (row.tool ?? toolName);
616
602
  const reason = row.hold?.reason ?? "The Tenant's tool policy asks a person about this call";
617
603
  held.push({
618
604
  invocationId: typeof context.invocationId === "string" ? context.invocationId : effectId,
@@ -620,9 +606,10 @@ async function heldCalls(t, effectIds) {
620
606
  interaction: {
621
607
  id: effectId,
622
608
  kind: "approval",
623
- prompt: `Approve ${toolName}?`,
609
+ prompt: `Approve ${what}?`,
624
610
  reason,
625
611
  ...(row.server === undefined ? {} : { server: row.server }),
612
+ ...(row.tool === undefined ? {} : { tool: row.tool }),
626
613
  input: request.input ?? null,
627
614
  },
628
615
  status: "interaction",
@@ -668,13 +655,16 @@ function leanCheckpoint(session, checkpoint) {
668
655
  return { ...checkpoint, state: leanOf(session, state) };
669
656
  }
670
657
  /**
671
- * Appends a segment's transcript edits; a snapshot moves `history.snapshot`. Returns the seq of
672
- * the last edit, if any.
658
+ * Appends a segment's transcript edits; a snapshot moves `history.snapshot`. An edit the harness
659
+ * marks as a compaction (`kind: "compaction"`, Q4) also writes `context.compacted`, from its facts
660
+ * and the summary calls it names. Returns the seq of the last edit, if any.
673
661
  */
674
662
  async function recordTranscript(t, id, turnId, s, updates, writer) {
675
663
  let last;
676
664
  for (const update of updates) {
677
665
  const event = await t.event(id, turnId, "transcript.updated", update, writer);
666
+ if ("compaction" in update)
667
+ await t.event(id, turnId, "context.compacted", await contextCompacted(t, id, turnId, update.compaction), writer);
678
668
  if (update.keep === 0)
679
669
  s.history = { from: s.history?.from ?? event.seq, snapshot: event.seq };
680
670
  last = event.seq;
@@ -28,7 +28,6 @@ import { checkEnvironmentTurn } from "./environments.js";
28
28
  import { turnManifestOf, variantStore } from "./session.js";
29
29
  import { slimModelEffects } from "./slim.js";
30
30
  import { resolveMessageParts } from "../artifacts/parts.js";
31
- import { currentModelInputs } from "../model/catalog.js";
32
31
  import { endTurn, resumeTurn, startTurn } from "./turn-timing.js";
33
32
  /** A command's identity for idempotency: everything but the request id. */
34
33
  const semantic = (value) => {
@@ -43,11 +42,6 @@ export async function command(ctx, id, input, scope,
43
42
  options = {}) {
44
43
  const { store } = ctx;
45
44
  const cascadeCancelIds = [];
46
- // What the Tenant's model reads, for a message that names a file (protocol 12): read before
47
- // the session's transaction. Undefined without a model in the vault: nothing is refused.
48
- const inputs = input.type === "message" && "parts" in input && input.parts.some((part) => part.type === "file")
49
- ? await currentModelInputs(ctx)
50
- : undefined;
51
45
  const response = await store.tx(async (t) => {
52
46
  const s = await lockedSession(t, id, accessOf(scope));
53
47
  const command = input;
@@ -134,12 +128,14 @@ options = {}) {
134
128
  }
135
129
  }
136
130
  else {
137
- // A session opened before protocol 11 (migration 0020) or 13 (migration 0024) keeps its
138
- // history but takes no turn.
131
+ // A session opened before protocol 11 (migration 0020), 13 (migration 0024) or 15
132
+ // (migrations 0029, 0030) keeps its history but takes no turn.
139
133
  if (s.closedReason !== undefined)
140
134
  fail(409, s.closedReason === "protocol_11"
141
135
  ? "This session was opened before protocol 11: open a new session that names an Environment."
142
- : "This session was opened before protocol 13, on a manifest the Runtime no longer runs: register the agent again (manifest 7) and open a new session.", { code: "session_closed" });
136
+ : s.closedReason === "protocol_15"
137
+ ? "This session was opened before protocol 15, and its pinned manifest holds a runtime block: our harness now writes the model's instructions and defines its tools itself. Open a new session."
138
+ : "This session was opened before protocol 13, on a manifest the Runtime no longer runs: register the agent again (manifest 7) and open a new session.", { code: "session_closed" });
143
139
  if (command.type === "message") {
144
140
  if (!["idle", "completed", "failed", "cancelled"].includes(s.status))
145
141
  fail(409, "Session has active or unresolved work");
@@ -156,15 +152,12 @@ options = {}) {
156
152
  s.turnTrace = options.trace;
157
153
  else
158
154
  delete s.turnTrace;
159
- // File parts name artifacts the caller may read; each is pinned to a version now. An
160
- // agent's model must read each one (a workflow passes them on as data).
155
+ // File parts name artifacts the caller may read; each is pinned to a version now. Any
156
+ // file goes (protocol 15): the harness decides how the model sees it, and a workflow
157
+ // passes it on as data.
161
158
  const parts = "parts" in command
162
- ? await resolveMessageParts(t, command.parts, id, accessOf(scope), isWorkflowManifest(s.manifest) ? undefined : inputs)
159
+ ? await resolveMessageParts(t, command.parts, id, accessOf(scope))
163
160
  : undefined;
164
- if (parts && parts.refused.length > 0)
165
- fail(422, `The model does not read ${parts.refused
166
- .map((part) => `${part.name} (${part.reason})`)
167
- .join(", ")}.`, { code: "attachment_unsupported", details: { parts: parts.refused } });
168
161
  // The files the session's messages named: `read_artifact` reads them again (protocol 12).
169
162
  if (parts) {
170
163
  const named = parts.pinned.flatMap((part) => (part.type === "file" ? [part.artifactId] : []));
@@ -19,8 +19,6 @@ import type { IssuerScope, SubjectScope, TenantEnvelope } from "@nylorun/core/co
19
19
  import type { DurableCheckpoint, FlowCheckpoint } from "@nylorun/harness/run";
20
20
  import type { AgentManifest, JsonValue, SandboxManifest } from "@nylorun/core/define";
21
21
  import type { OutboxRequest, SessionStore, Tx } from "../store/types.js";
22
- import type { FlowLimits } from "../core/limits.js";
23
- import type { ModelProvider } from "../core/provider.js";
24
22
  import type { ModelGate } from "../gates/model-gate.js";
25
23
  import type { ToolGate } from "../gates/tool-gate.js";
26
24
  import type { Keys } from "../keys/keys.js";
@@ -37,7 +35,6 @@ import type { StuckInvocation, Wake } from "../execution/types.js";
37
35
  import type { WorkState } from "./scheduler.js";
38
36
  import type { SigningKeys } from "./signing-keys.js";
39
37
  import type { BlobStore } from "../blob/index.js";
40
- import type { WorkspaceReader } from "../artifacts/workspace.js";
41
38
  import type { RunGrants } from "./run-grants.js";
42
39
  import type { TraceOptions } from "../traces/options.js";
43
40
  import type { TraceContext } from "../traces/ids.js";
@@ -49,8 +46,8 @@ export interface Session {
49
46
  manifest: any;
50
47
  manifestHash: string;
51
48
  /**
52
- * The hash of the definition the session was opened from; `manifestHash` differs when the
53
- * Runtime pinned its `runtime` block on it (R2b C11). Absent on older sessions.
49
+ * The hash of the definition the session was opened from (R2b C11); since protocol 15 it equals
50
+ * `manifestHash`. Absent on older sessions.
54
51
  */
55
52
  definitionHash?: string;
56
53
  /** Validated turn-manifest variants, keyed by hash (loops.md §4.2). */
@@ -115,8 +112,9 @@ export interface Session {
115
112
  sandbox?: SandboxManifest;
116
113
  /**
117
114
  * Why the session takes no new turn: `protocol_11` for a session opened before protocol 11
118
- * (migration 0020), `protocol_13` for one opened before protocol 13 (migration 0024). Its
119
- * history stays readable.
115
+ * (migration 0020), `protocol_13` for one opened before protocol 13 (migration 0024),
116
+ * `protocol_15` for an agent session that pinned a `runtime` block before protocol 15
117
+ * (migrations 0029, 0030). Its history stays readable.
120
118
  */
121
119
  closedReason?: string;
122
120
  /**
@@ -185,11 +183,15 @@ export interface TenantContext {
185
183
  * else the harness that serves workspaces (`harness-api/workspace.ts`).
186
184
  */
187
185
  readonly sandbox: WorkspacePort;
188
- readonly flowLimits: FlowLimits;
189
- readonly modelProvider: ModelProvider;
190
- /** True when the model comes from the Tenant vault selection, served by `modelGate`. */
191
- readonly useVaultModel: boolean;
192
- /** Serves vault-backed model calls (blueprint §15): in this process, or the gates service. */
186
+ /**
187
+ * True when the Runtime's model is not the vault's (scripted, the fixture model, an embedder's
188
+ * provider): `modelGate` serves it, and no vault model need be configured.
189
+ */
190
+ readonly scriptedModel: boolean;
191
+ /**
192
+ * Serves every model call (blueprint §15, protocol 15): the vault's model in this process or
193
+ * the gates service, or a scripted model (`providerModelGate`).
194
+ */
193
195
  readonly modelGate: ModelGate;
194
196
  /**
195
197
  * Serves remote MCP servers and HTTP tools (blueprint §12, F4.1): in this process, or the
@@ -208,11 +210,6 @@ export interface TenantContext {
208
210
  * they mean, and a blob counts once a committed row names its key.
209
211
  */
210
212
  readonly blobs: BlobStore;
211
- /**
212
- * How core reads a session's sandbox workspace at turn end, to export its outputs (F8.2): over
213
- * this process's `sandbox` today; over the Harness API's `workspace.read` from F6.2.
214
- */
215
- readonly workspaces: WorkspaceReader;
216
213
  /**
217
214
  * How the trace route (R7.5) makes spans: the resource and the content the installation exports
218
215
  * (R7.2). Absent: `service.name` `nylorun`, no content.
@@ -1,5 +1,5 @@
1
1
  import { type DefinitionFileView } from "@nylorun/core/contracts";
2
- import type { BlobStore } from "../blob/index.js";
2
+ import { type BlobStore } from "../blob/index.js";
3
3
  import type { Tx } from "../store/types.js";
4
4
  import type { TenantContext } from "./context.js";
5
5
  /** Where a definition file's bytes are in the Object store. */
@@ -8,7 +8,10 @@ export declare function definitionFileKey(sha256: string): string;
8
8
  export declare function hasDefinitionFile(ctx: TenantContext, file: string): Promise<boolean>;
9
9
  /**
10
10
  * Stores the bytes of definition file `file`: `201` when they are new, `200` when the Tenant
11
- * holds them already (the body is not read). Bytes that do not hash to `file` are a `400`.
11
+ * holds them already (the body is not read). Bytes that do not hash to `file` are a `400`; more
12
+ * than the Tenant's skill limit (`skills.config`) a `413`. The body streams to a staging key and is copied to
13
+ * the file's key only once its hash is checked, so no file is held in memory and bytes of
14
+ * another hash never replace a file at its key.
12
15
  */
13
16
  export declare function putDefinitionFile(ctx: TenantContext, file: string, request: {
14
17
  body: ReadableStream<Uint8Array> | null;
@@ -18,7 +21,25 @@ export declare function putDefinitionFile(ctx: TenantContext, file: string, requ
18
21
  status: 200 | 201;
19
22
  view: DefinitionFileView;
20
23
  }>;
21
- /** The definition files `document` names that the Tenant does not hold, in order. */
22
- export declare function missingDefinitionFiles(t: Tx, document: unknown): Promise<string[]>;
24
+ /**
25
+ * Why `document` cannot be stored for the files it names: the files the Tenant does not hold
26
+ * (`missing`), else each skill whose files hold more than `limitBytes` together (`oversized`).
27
+ * A file a skill names at two paths counts twice: a sandbox holds both.
28
+ */
29
+ export declare function definitionFileIssues(t: Tx, document: unknown, limitBytes: number): Promise<{
30
+ missing: string[];
31
+ oversized: {
32
+ name: string;
33
+ bytes: number;
34
+ }[];
35
+ }>;
36
+ /** A definition file's bytes as a stream, or undefined when the Object store does not have them. */
37
+ export declare function openDefinitionFile(blobs: BlobStore, sha256: string, options?: {
38
+ range?: {
39
+ start: number;
40
+ end?: number;
41
+ };
42
+ signal?: AbortSignal;
43
+ }): Promise<ReadableStream<Uint8Array> | undefined>;
23
44
  /** A definition file's bytes, or undefined when the Object store does not have them. */
24
45
  export declare function readDefinitionFile(blobs: BlobStore, sha256: string, signal?: AbortSignal): Promise<Uint8Array | undefined>;