@nylorun/runtime 0.23.0-beta → 0.25.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 (301) hide show
  1. package/CHANGELOG.md +252 -0
  2. package/README.md +87 -28
  3. package/dist/adapters/execution/restate.js +1 -1
  4. package/dist/adapters/replication/pgoutput.d.ts +2 -0
  5. package/dist/adapters/replication/pgoutput.js +6 -3
  6. package/dist/adapters/sandbox/local.d.ts +9 -1
  7. package/dist/adapters/sandbox/local.js +16 -4
  8. package/dist/adapters/sandbox/virtual.js +4 -1
  9. package/dist/api/a2a/card.d.ts +11 -1
  10. package/dist/api/a2a/card.js +26 -2
  11. package/dist/api/a2a/endpoint.js +9 -3
  12. package/dist/api/a2a/protocol.d.ts +25 -2
  13. package/dist/api/a2a/protocol.js +20 -3
  14. package/dist/api/a2a/routes.d.ts +6 -1
  15. package/dist/api/a2a/routes.js +67 -9
  16. package/dist/api/a2a/tasks.js +2 -1
  17. package/dist/api/ag-ui/endpoint.js +8 -3
  18. package/dist/api/ag-ui/history.d.ts +6 -1
  19. package/dist/api/ag-ui/history.js +39 -3
  20. package/dist/api/ag-ui/routes.d.ts +4 -1
  21. package/dist/api/ag-ui/routes.js +63 -20
  22. package/dist/api/ag-ui/translate.js +3 -2
  23. package/dist/api/components.d.ts +5327 -1091
  24. package/dist/api/components.js +40 -16
  25. package/dist/api/gate/keys.d.ts +2 -1
  26. package/dist/api/gate/keys.js +14 -1
  27. package/dist/api/gate/routes.d.ts +6 -0
  28. package/dist/api/gate/routes.js +52 -3
  29. package/dist/api/http/app.js +17 -6
  30. package/dist/api/http/body.d.ts +3 -3
  31. package/dist/api/http/body.js +7 -7
  32. package/dist/api/http/define.d.ts +6 -0
  33. package/dist/api/http/define.js +13 -1
  34. package/dist/api/http/respond.js +1 -1
  35. package/dist/api/http/routes/artifacts.js +35 -8
  36. package/dist/api/http/routes/coverage.d.ts +9 -0
  37. package/dist/api/http/routes/coverage.js +34 -0
  38. package/dist/api/http/routes/environment-manifests.d.ts +9 -0
  39. package/dist/api/http/routes/environment-manifests.js +118 -0
  40. package/dist/api/http/routes/environments.d.ts +11 -0
  41. package/dist/api/http/routes/environments.js +332 -0
  42. package/dist/api/http/routes/mcp.d.ts +1 -1
  43. package/dist/api/http/routes/mcp.js +2 -2
  44. package/dist/api/http/routes/me.js +1 -1
  45. package/dist/api/http/routes/reads.d.ts +94 -9
  46. package/dist/api/http/routes/reads.js +54 -5
  47. package/dist/api/http/routes/sessions.js +24 -9
  48. package/dist/api/http/routes/tenant.js +65 -15
  49. package/dist/api/inbound-files.d.ts +65 -0
  50. package/dist/api/inbound-files.js +115 -0
  51. package/dist/api/openapi.js +48 -28
  52. package/dist/artifacts/disk.d.ts +59 -0
  53. package/dist/artifacts/disk.js +569 -0
  54. package/dist/artifacts/export.d.ts +1 -1
  55. package/dist/artifacts/export.js +2 -3
  56. package/dist/artifacts/folders.d.ts +6 -3
  57. package/dist/artifacts/folders.js +17 -12
  58. package/dist/artifacts/media-types.d.ts +15 -0
  59. package/dist/artifacts/media-types.js +56 -4
  60. package/dist/artifacts/parts.d.ts +12 -3
  61. package/dist/artifacts/parts.js +15 -4
  62. package/dist/artifacts/service.d.ts +2 -1
  63. package/dist/artifacts/service.js +6 -1
  64. package/dist/artifacts/workspace.d.ts +5 -5
  65. package/dist/artifacts/workspace.js +7 -19
  66. package/dist/core/flow-host.d.ts +3 -4
  67. package/dist/core/flow-host.js +5 -2
  68. package/dist/core/provider.d.ts +3 -2
  69. package/dist/core/provider.js +5 -37
  70. package/dist/core/sandbox-routes.d.ts +2 -21
  71. package/dist/core/sandbox-routes.js +11 -44
  72. package/dist/core/turn-manifest.d.ts +3 -2
  73. package/dist/core/turn-manifest.js +29 -5
  74. package/dist/execution/types.d.ts +1 -1
  75. package/dist/gates/contract.d.ts +3 -24
  76. package/dist/gates/contract.js +1 -36
  77. package/dist/gates/egress-credentials.d.ts +9 -0
  78. package/dist/gates/egress-credentials.js +11 -4
  79. package/dist/gates/egress.d.ts +22 -1
  80. package/dist/gates/egress.js +116 -10
  81. package/dist/gates/fixture-model.d.ts +28 -0
  82. package/dist/gates/fixture-model.js +92 -0
  83. package/dist/gates/handler.js +4 -4
  84. package/dist/gates/http-tool.d.ts +9 -6
  85. package/dist/gates/http-tool.js +11 -17
  86. package/dist/gates/in-process.d.ts +5 -0
  87. package/dist/gates/in-process.js +12 -1
  88. package/dist/gates/journal.d.ts +30 -0
  89. package/dist/gates/journal.js +51 -0
  90. package/dist/gates/mcp-handler.d.ts +4 -0
  91. package/dist/gates/mcp-handler.js +7 -4
  92. package/dist/gates/meter.d.ts +10 -2
  93. package/dist/gates/meter.js +20 -5
  94. package/dist/gates/policy.d.ts +49 -0
  95. package/dist/gates/policy.js +132 -0
  96. package/dist/gates/tenant-vaults.d.ts +7 -7
  97. package/dist/gates/tenant-vaults.js +5 -5
  98. package/dist/gates/tool-calls.d.ts +10 -5
  99. package/dist/gates/tool-calls.js +28 -10
  100. package/dist/gates/tool-client.d.ts +8 -0
  101. package/dist/gates/tool-client.js +27 -11
  102. package/dist/gates/tool-contract.d.ts +11 -69
  103. package/dist/gates/tool-contract.js +1 -85
  104. package/dist/gates/tool-gate.d.ts +1 -1
  105. package/dist/harness/calls.d.ts +14 -7
  106. package/dist/harness/calls.js +30 -24
  107. package/dist/harness/executors.js +12 -9
  108. package/dist/harness/main.js +24 -5
  109. package/dist/harness/pod.d.ts +39 -0
  110. package/dist/harness/pod.js +46 -0
  111. package/dist/harness/service.d.ts +0 -1
  112. package/dist/harness/service.js +17 -9
  113. package/dist/harness/setup.d.ts +29 -0
  114. package/dist/harness/setup.js +174 -0
  115. package/dist/harness/ws-client.js +3 -2
  116. package/dist/harness/ws-port.d.ts +1 -5
  117. package/dist/harness/ws-port.js +1 -5
  118. package/dist/harness-api/in-process.js +3 -3
  119. package/dist/harness-api/record.d.ts +15 -1
  120. package/dist/harness-api/record.js +180 -50
  121. package/dist/harness-api/redact.d.ts +3 -0
  122. package/dist/harness-api/redact.js +45 -0
  123. package/dist/harness-api/server.d.ts +35 -4
  124. package/dist/harness-api/server.js +130 -17
  125. package/dist/harness-api/start.d.ts +10 -3
  126. package/dist/harness-api/start.js +40 -10
  127. package/dist/harness-api/tool-journal.d.ts +105 -0
  128. package/dist/harness-api/tool-journal.js +132 -0
  129. package/dist/harness-api/tool-status.d.ts +13 -0
  130. package/dist/harness-api/tool-status.js +26 -0
  131. package/dist/harness-api/workspace.d.ts +12 -7
  132. package/dist/harness-api/workspace.js +47 -25
  133. package/dist/harness-api/ws-server.d.ts +11 -3
  134. package/dist/harness-api/ws-server.js +94 -15
  135. package/dist/host/gates.d.ts +2 -1
  136. package/dist/host/gates.js +10 -2
  137. package/dist/host/main.js +54 -5
  138. package/dist/host/operate.js +67 -5
  139. package/dist/host/stack-config.d.ts +64 -0
  140. package/dist/host/stack-config.js +62 -2
  141. package/dist/keys/client.js +4 -1
  142. package/dist/keys/keys.d.ts +13 -6
  143. package/dist/keys/keys.js +9 -8
  144. package/dist/management-openapi.json +1264 -2171
  145. package/dist/mcp/connect.d.ts +26 -22
  146. package/dist/mcp/connect.js +30 -34
  147. package/dist/mcp/pool.d.ts +3 -6
  148. package/dist/mcp/pool.js +14 -28
  149. package/dist/mcp/preview.d.ts +3 -3
  150. package/dist/mcp/preview.js +10 -21
  151. package/dist/mcp/snapshot.d.ts +16 -24
  152. package/dist/mcp/snapshot.js +33 -45
  153. package/dist/model/capabilities.d.ts +26 -0
  154. package/dist/model/capabilities.js +44 -0
  155. package/dist/model/catalog.d.ts +34 -3
  156. package/dist/model/catalog.js +38 -2
  157. package/dist/model/models.d.ts +2 -0
  158. package/dist/model/models.js +1 -1
  159. package/dist/model/native-blocks.d.ts +35 -0
  160. package/dist/model/native-blocks.js +170 -0
  161. package/dist/model/pi-model.js +114 -94
  162. package/dist/openapi.json +12822 -3943
  163. package/dist/reads/types.d.ts +16 -3
  164. package/dist/record/append.d.ts +3 -1
  165. package/dist/record/append.js +1 -0
  166. package/dist/record/envelope.d.ts +5 -1
  167. package/dist/record/envelope.js +7 -3
  168. package/dist/record/environment.d.ts +25 -0
  169. package/dist/record/environment.js +44 -0
  170. package/dist/record/index.d.ts +1 -1
  171. package/dist/record/index.js +1 -1
  172. package/dist/sandbox/disk-fs.d.ts +95 -0
  173. package/dist/sandbox/disk-fs.js +206 -0
  174. package/dist/sandbox/join.d.ts +17 -18
  175. package/dist/sandbox/join.js +46 -15
  176. package/dist/sandbox/manager.d.ts +47 -21
  177. package/dist/sandbox/manager.js +162 -107
  178. package/dist/sandbox/placement.d.ts +14 -13
  179. package/dist/sandbox/placement.js +31 -14
  180. package/dist/sandbox/pods/client.d.ts +9 -2
  181. package/dist/sandbox/pods/lifecycle.d.ts +36 -27
  182. package/dist/sandbox/pods/lifecycle.js +29 -26
  183. package/dist/sandbox/pods/reconcile.js +18 -12
  184. package/dist/sandbox/pods/spec.d.ts +15 -13
  185. package/dist/sandbox/pods/spec.js +17 -20
  186. package/dist/sandbox/records.d.ts +2 -2
  187. package/dist/sandbox/records.js +3 -3
  188. package/dist/sandbox/resolve.d.ts +37 -27
  189. package/dist/sandbox/resolve.js +73 -41
  190. package/dist/sandbox/runtime-tools.d.ts +9 -0
  191. package/dist/sandbox/runtime-tools.js +16 -0
  192. package/dist/sandbox/session-sandbox.d.ts +4 -6
  193. package/dist/sandbox/session-sandbox.js +47 -94
  194. package/dist/sandbox/setup.d.ts +64 -0
  195. package/dist/sandbox/setup.js +160 -0
  196. package/dist/sandbox/share.d.ts +21 -26
  197. package/dist/sandbox/share.js +36 -63
  198. package/dist/sandbox/skills.d.ts +8 -6
  199. package/dist/sandbox/skills.js +24 -23
  200. package/dist/sandbox/tenant-config.d.ts +12 -14
  201. package/dist/sandbox/tenant-config.js +12 -17
  202. package/dist/sandbox/types.d.ts +6 -0
  203. package/dist/store/postgres/drizzle/0020_environments.sql +63 -0
  204. package/dist/store/postgres/drizzle/0021_disk_versions.sql +7 -0
  205. package/dist/store/postgres/drizzle/0022_model_usage_timing.sql +5 -0
  206. package/dist/store/postgres/drizzle/0023_artifact_pages.sql +1 -0
  207. package/dist/store/postgres/drizzle/0024_flat_manifest.sql +7 -0
  208. package/dist/store/postgres/drizzle/0025_environment_manifests.sql +14 -0
  209. package/dist/store/postgres/drizzle/0026_environment_forks.sql +1 -0
  210. package/dist/store/postgres/drizzle/0027_environment_image_digest.sql +1 -0
  211. package/dist/store/postgres/drizzle/meta/_journal.json +56 -0
  212. package/dist/store/postgres/reads.js +123 -17
  213. package/dist/store/postgres/record-writer.d.ts +4 -4
  214. package/dist/store/postgres/record-writer.js +9 -9
  215. package/dist/store/postgres/record.d.ts +7 -0
  216. package/dist/store/postgres/record.js +23 -2
  217. package/dist/store/postgres/schema.d.ts +1126 -736
  218. package/dist/store/postgres/schema.js +136 -73
  219. package/dist/store/postgres/store.js +195 -67
  220. package/dist/store/types.d.ts +165 -50
  221. package/dist/tenant/advance.d.ts +7 -6
  222. package/dist/tenant/advance.js +118 -42
  223. package/dist/tenant/artifact-tool.d.ts +1 -1
  224. package/dist/tenant/artifact-tool.js +46 -26
  225. package/dist/tenant/commands.d.ts +15 -2
  226. package/dist/tenant/commands.js +115 -14
  227. package/dist/tenant/context.d.ts +56 -24
  228. package/dist/tenant/context.js +4 -15
  229. package/dist/tenant/effects.d.ts +1 -1
  230. package/dist/tenant/effects.js +44 -29
  231. package/dist/tenant/environment-manifests.d.ts +57 -0
  232. package/dist/tenant/environment-manifests.js +200 -0
  233. package/dist/tenant/environments.d.ts +174 -0
  234. package/dist/tenant/environments.js +1044 -0
  235. package/dist/tenant/harness-tokens.d.ts +21 -0
  236. package/dist/tenant/harness-tokens.js +61 -0
  237. package/dist/tenant/host-token.d.ts +1 -1
  238. package/dist/tenant/host-token.js +2 -4
  239. package/dist/tenant/identity-file.d.ts +4 -4
  240. package/dist/tenant/identity-file.js +17 -8
  241. package/dist/tenant/issuers.js +3 -3
  242. package/dist/tenant/model-setting.d.ts +14 -0
  243. package/dist/tenant/model-setting.js +51 -0
  244. package/dist/tenant/principals.js +1 -1
  245. package/dist/tenant/reset.js +3 -3
  246. package/dist/tenant/runtime.d.ts +6 -1
  247. package/dist/tenant/runtime.js +7 -1
  248. package/dist/tenant/session.d.ts +3 -3
  249. package/dist/tenant/session.js +0 -14
  250. package/dist/tenant/sessions.d.ts +18 -14
  251. package/dist/tenant/sessions.js +99 -143
  252. package/dist/tenant/signing-keys.d.ts +5 -1
  253. package/dist/tenant/skill-tool.d.ts +3 -3
  254. package/dist/tenant/skill-tool.js +6 -11
  255. package/dist/tenant/status.js +3 -3
  256. package/dist/tenant/sweep.js +13 -7
  257. package/dist/tenant/tool-results.js +1 -1
  258. package/dist/tenant/tool-search.d.ts +7 -11
  259. package/dist/tenant/tool-search.js +8 -5
  260. package/dist/tenant/transcript.d.ts +245 -36
  261. package/dist/tenant/transcript.js +64 -12
  262. package/dist/tenant/turn-timing.d.ts +43 -0
  263. package/dist/tenant/turn-timing.js +39 -0
  264. package/dist/tenant/types.d.ts +2 -0
  265. package/dist/traces/ids.d.ts +41 -0
  266. package/dist/traces/ids.js +81 -0
  267. package/dist/traces/key.d.ts +6 -0
  268. package/dist/traces/key.js +37 -0
  269. package/dist/traces/map.d.ts +113 -0
  270. package/dist/traces/map.js +289 -0
  271. package/dist/traces/options.d.ts +7 -0
  272. package/dist/traces/options.js +1 -0
  273. package/dist/traces/otlp.d.ts +42 -0
  274. package/dist/traces/otlp.js +84 -0
  275. package/dist/traces/projector.d.ts +58 -0
  276. package/dist/traces/projector.js +200 -0
  277. package/dist/traces/read.d.ts +23 -0
  278. package/dist/traces/read.js +16 -0
  279. package/dist/vault/coverage.d.ts +26 -0
  280. package/dist/vault/coverage.js +62 -0
  281. package/dist/vault/error.d.ts +11 -1
  282. package/dist/vault/error.js +5 -1
  283. package/dist/vault/host-model.d.ts +4 -1
  284. package/dist/vault/host-model.js +10 -2
  285. package/dist/vault/service.d.ts +92 -48
  286. package/dist/vault/service.js +462 -376
  287. package/dist/vault/sources.d.ts +5 -16
  288. package/dist/vault/sources.js +6 -8
  289. package/dist/version.d.ts +1 -1
  290. package/dist/version.js +2 -2
  291. package/package.json +13 -13
  292. package/dist/api/http/routes/sandboxes.d.ts +0 -9
  293. package/dist/api/http/routes/sandboxes.js +0 -153
  294. package/dist/api/http/routes/vaults.d.ts +0 -10
  295. package/dist/api/http/routes/vaults.js +0 -139
  296. package/dist/record/sandbox.d.ts +0 -25
  297. package/dist/record/sandbox.js +0 -43
  298. package/dist/sandbox/capability.d.ts +0 -3
  299. package/dist/sandbox/capability.js +0 -10
  300. package/dist/tenant/sandboxes.d.ts +0 -123
  301. package/dist/tenant/sandboxes.js +0 -566
@@ -1,12 +1,15 @@
1
1
  import { z } from "zod";
2
2
  /** Drizzle read projections on a separate, read-only Tenant pool. */
3
- import { and, asc, desc, eq, gt, inArray, isNull, lt, ne, or, sql, } from "drizzle-orm";
3
+ import { and, asc, desc, eq, exists, gt, inArray, isNull, lt, ne, or, sql, } from "drizzle-orm";
4
+ import { isArtifactId } from "@nylorun/core/compatibility";
4
5
  import { readCursor } from "../../reads/cursor.js";
5
6
  import { fail } from "../../tenant/http.js";
7
+ import { artifactView } from "../../artifacts/service.js";
6
8
  import { sandboxWorkspaceKey } from "../../sandbox/records.js";
7
9
  import { database, driverError } from "./db.js";
8
10
  import { createPostgresReadClient } from "./connect.js";
9
- import { modelUsage, sandboxResources, sandboxes, sessions, sessionEvents, } from "./schema.js";
11
+ import { toolCallDuration, toolCallStatus } from "../../harness-api/tool-status.js";
12
+ import { effects, artifacts, modelUsage, environments, sandboxes, sessions, sessionEvents, } from "./schema.js";
10
13
  const sessionFields = {
11
14
  id: sessions.id,
12
15
  agentId: sessions.agentId,
@@ -14,7 +17,7 @@ const sessionFields = {
14
17
  status: sessions.status,
15
18
  activeTurnId: sql `${sessions.body}->>'activeTurnId'`,
16
19
  lastTurnId: sql `${sessions.body}->>'lastTurnId'`,
17
- sandboxId: sessions.sandboxId,
20
+ environmentId: sessions.environmentId,
18
21
  createdAt: sessions.createdAt,
19
22
  };
20
23
  function accessWhere(access) {
@@ -23,6 +26,7 @@ function accessWhere(access) {
23
26
  function publicCall(row) {
24
27
  return {
25
28
  id: row.id,
29
+ effectId: row.effectKey,
26
30
  sessionId: row.sessionId,
27
31
  turnId: row.turnId,
28
32
  agentId: row.agentId,
@@ -44,6 +48,34 @@ function publicCall(row) {
44
48
  },
45
49
  };
46
50
  }
51
+ function publicToolCall(body) {
52
+ const { request } = body;
53
+ const status = toolCallStatus(body);
54
+ const value = body.outcome?.value;
55
+ const error = value?.kind === "failed"
56
+ ? { code: String(value.code ?? "tool.failed"), message: String(value.message ?? "") }
57
+ : status === "uncertain"
58
+ ? { code: "uncertain", message: body.error ?? "" }
59
+ : null;
60
+ return {
61
+ effectId: request.effectId,
62
+ turnId: request.turnId,
63
+ callId: typeof request.context?.callId === "string" ? request.context.callId : null,
64
+ toolName: request.toolName ?? null,
65
+ kind: body.toolKind ?? null,
66
+ server: body.server ?? null,
67
+ skill: body.skill ?? null,
68
+ plugin: body.plugin ?? null,
69
+ status,
70
+ // A row written before R5 counted no sends: it was sent once.
71
+ attempts: body.attempts ?? 1,
72
+ input: request.input ?? null,
73
+ error,
74
+ startedAt: body.startedAt ?? null,
75
+ settledAt: body.settledAt ?? null,
76
+ durationMs: toolCallDuration(body) ?? null,
77
+ };
78
+ }
47
79
  function keyOf(key, length, timestamp = false, nullable = false) {
48
80
  if (key &&
49
81
  (key.length !== length ||
@@ -87,6 +119,39 @@ export function createPostgresReadStore(source, tenantId) {
87
119
  }
88
120
  return {
89
121
  close: () => pool.end({ timeout: 2 }),
122
+ artifacts: (filters, page, access) => read(async (tx) => {
123
+ if (filters.sessionId !== undefined)
124
+ await requireSession(tx, filters.sessionId, access);
125
+ const cursor = readCursor(tenantId, "artifacts", {
126
+ sessionId: filters.sessionId ?? null,
127
+ kind: filters.kind ?? null,
128
+ labels: Object.entries(filters.labels).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)),
129
+ });
130
+ const key = keyOf(cursor.decode(page.cursor), 2, true);
131
+ if (key && !isArtifactId(key[1]))
132
+ fail(400, "Invalid artifact cursor key", { code: "cursor_invalid" });
133
+ const rows = await tx
134
+ .select()
135
+ .from(artifacts)
136
+ .where(and(access.owner === undefined && access.agents === undefined
137
+ ? undefined
138
+ : exists(tx.select({ id: sessions.id })
139
+ .from(sessions)
140
+ .where(and(eq(sessions.id, artifacts.sessionId), accessWhere(access)))), filters.sessionId === undefined
141
+ ? undefined
142
+ : eq(artifacts.sessionId, filters.sessionId), filters.kind === undefined ? undefined : eq(artifacts.kind, filters.kind),
143
+ // Labels are a flat string map serialized by JSON.stringify. Match its exact
144
+ // key/value pair: jsonb rejects NUL/unpaired surrogate escapes labels may hold.
145
+ ...Object.entries(filters.labels).map(([k, v]) => sql `strpos(${artifacts.labelsJson}, ${JSON.stringify(k) + ":" + JSON.stringify(v)}) > 0`), key ? sql `(${artifacts.createdAt}, ${artifacts.id}) < (${key[0]}, ${key[1]})` : undefined))
146
+ .orderBy(desc(artifacts.createdAt), desc(artifacts.id))
147
+ .limit(page.limit + 1);
148
+ const items = rows.slice(0, page.limit);
149
+ const last = items.at(-1);
150
+ return {
151
+ artifacts: items.map((row) => artifactView(row)),
152
+ nextCursor: rows.length > page.limit && last ? cursor.encode([last.createdAt, last.id]) : null,
153
+ };
154
+ }),
90
155
  sessions: (filters, page, access) => read(async (tx) => {
91
156
  const cursor = readCursor(tenantId, "sessions", filters);
92
157
  const key = keyOf(cursor.decode(page.cursor), 2, true, true);
@@ -98,9 +163,9 @@ export function createPostgresReadStore(source, tenantId) {
98
163
  const rows = await tx
99
164
  .select(fields)
100
165
  .from(sessions)
101
- .where(and(accessWhere(access), position, filters.agentId === undefined ? undefined : eq(sessions.agentId, filters.agentId), filters.status === undefined ? undefined : eq(sessions.status, filters.status), filters.sandboxId === undefined
166
+ .where(and(accessWhere(access), position, filters.agentId === undefined ? undefined : eq(sessions.agentId, filters.agentId), filters.status === undefined ? undefined : eq(sessions.status, filters.status), filters.environmentId === undefined
102
167
  ? undefined
103
- : eq(sessions.sandboxId, filters.sandboxId), filters.ownerUserId === undefined
168
+ : eq(sessions.environmentId, filters.environmentId), filters.ownerUserId === undefined
104
169
  ? undefined
105
170
  : eq(sessions.ownerUserId, filters.ownerUserId)))
106
171
  .orderBy(sql `${sessions.createdAt} desc nulls last`, desc(sessions.id))
@@ -182,6 +247,37 @@ export function createPostgresReadStore(source, tenantId) {
182
247
  asOf: new Date().toISOString(),
183
248
  };
184
249
  }),
250
+ toolCalls: (id, turnId, page, access) => read(async (tx) => {
251
+ await requireSession(tx, id, access);
252
+ const cursor = readCursor(tenantId, "tool-calls", { sessionId: id, turnId });
253
+ const key = keyOf(cursor.decode(page.cursor), 2);
254
+ // In the order of their first send; a row written before R5 has no `startedAt`.
255
+ const startedAt = sql `coalesce(${effects.body}->>'startedAt', '')`;
256
+ const rows = await tx
257
+ .select({ id: effects.id, body: effects.body, startedAt })
258
+ .from(effects)
259
+ .where(and(eq(effects.sessionId, id), eq(effects.kind, "tool"), turnId === undefined ? undefined : eq(effects.turnId, turnId), key ? sql `(${startedAt}, ${effects.id}) > (${key[0]}, ${key[1]})` : undefined))
260
+ .orderBy(asc(startedAt), asc(effects.id))
261
+ .limit(page.limit + 1);
262
+ const items = rows.slice(0, page.limit);
263
+ const last = items.at(-1);
264
+ return {
265
+ calls: items.map((row) => publicToolCall(row.body)),
266
+ nextCursor: rows.length > page.limit && last ? cursor.encode([last.startedAt, last.id]) : null,
267
+ asOf: new Date().toISOString(),
268
+ };
269
+ }),
270
+ turnEvents: (id, turnId, access) => read(async (tx) => {
271
+ await requireSession(tx, id, access);
272
+ // The record has no turn column: one session's rows, on the turn id in the event (no
273
+ // index yet, R8).
274
+ const rows = await tx
275
+ .select({ body: sessionEvents.body })
276
+ .from(sessionEvents)
277
+ .where(and(eq(sessionEvents.sessionId, id), sql `${sessionEvents.body}->>'turnId' = ${turnId}`))
278
+ .orderBy(asc(sessionEvents.seq));
279
+ return rows.map((row) => row.body);
280
+ }),
185
281
  exportModel: (after, limit) => read(async (tx) => {
186
282
  const cursor = readCursor(tenantId, "model-export", {});
187
283
  const key = keyOf(cursor.decode(after), 2);
@@ -205,19 +301,19 @@ export function createPostgresReadStore(source, tenantId) {
205
301
  asOf: new Date().toISOString(),
206
302
  };
207
303
  }),
208
- sandboxes: (labels, page, access, grants) => read(async (tx) => {
209
- const cursor = readCursor(tenantId, "sandboxes", labels);
304
+ environments: (labels, page, access, grants) => read(async (tx) => {
305
+ const cursor = readCursor(tenantId, "environments", labels);
210
306
  const key = keyOf(cursor.decode(page.cursor), 1);
211
307
  const allowed = grants === undefined
212
308
  ? undefined
213
309
  : or(...grants.map((grant) => grant.endsWith("/*")
214
- ? sql `starts_with(${sandboxResources.id}, ${grant.slice(0, -1)})`
215
- : eq(sandboxResources.id, grant)));
310
+ ? sql `starts_with(${environments.id}, ${grant.slice(0, -1)})`
311
+ : eq(environments.id, grant)));
216
312
  const rows = await tx
217
313
  .select()
218
- .from(sandboxResources)
219
- .where(and(grants?.length === 0 ? sql `false` : allowed, key ? gt(sandboxResources.id, key[0]) : undefined, or(isNull(sandboxResources.desired), ne(sandboxResources.desired, "deleted")), ...Object.entries(labels).map(([k, v]) => sql `${sandboxResources.labels}::jsonb->>${k} = ${v}`)))
220
- .orderBy(asc(sandboxResources.id))
314
+ .from(environments)
315
+ .where(and(grants?.length === 0 ? sql `false` : allowed, key ? gt(environments.id, key[0]) : undefined, or(isNull(environments.desired), ne(environments.desired, "deleted")), ...Object.entries(labels).map(([k, v]) => sql `${environments.labels}::jsonb->>${k} = ${v}`)))
316
+ .orderBy(asc(environments.id))
221
317
  .limit(page.limit + 1);
222
318
  const items = [];
223
319
  for (const row of rows.slice(0, page.limit)) {
@@ -226,7 +322,7 @@ export function createPostgresReadStore(source, tenantId) {
226
322
  items: sql `coalesce(json_agg(json_build_object('id', ${sessions.id}, 'activeTurnId', ${sessions.body}->>'activeTurnId') order by ${sessions.id}), '[]'::json)`,
227
323
  })
228
324
  .from(sessions)
229
- .where(and(eq(sessions.sandboxId, row.id), accessWhere(access)));
325
+ .where(and(eq(sessions.environmentId, row.id), accessWhere(access)));
230
326
  const [compute] = await tx
231
327
  .select({ body: sandboxes.body })
232
328
  .from(sandboxes)
@@ -237,14 +333,23 @@ export function createPostgresReadStore(source, tenantId) {
237
333
  id: row.id,
238
334
  kind: row.kind,
239
335
  labels: row.labels,
240
- spec: row.spec,
336
+ manifest: row.recipe,
337
+ ...(row.manifestName === null ? {} : { manifestName: row.manifestName }),
338
+ ...(row.manifestVersion === null ? {} : { manifestVersion: row.manifestVersion }),
339
+ ...(row.manifestHash === null ? {} : { manifestHash: row.manifestHash }),
340
+ ...(row.forkedFrom ? { forkedFrom: row.forkedFrom } : {}),
341
+ version: row.version,
342
+ appliedVersion: row.appliedVersion,
343
+ ownerUserId: row.ownerUserId,
241
344
  state: isPod
242
345
  ? row.observed === "running"
243
346
  ? "running"
244
347
  : row.observed === "creating"
245
348
  ? "creating"
246
349
  : "stopped"
247
- : (compute?.body?.state ?? "ready"),
350
+ : row.kind === "none"
351
+ ? "ready"
352
+ : (compute?.body?.state ?? "ready"),
248
353
  ...(isPod
249
354
  ? {
250
355
  pod: {
@@ -252,11 +357,12 @@ export function createPostgresReadStore(source, tenantId) {
252
357
  observed: row.observed,
253
358
  volumeGeneration: row.volumeGen,
254
359
  hostEpoch: row.hostEpoch,
255
- ...(row.expiresAt ? { expiresAt: new Date(row.expiresAt).toISOString() } : {}),
256
360
  ...(row.reason ? { reason: row.reason } : {}),
361
+ ...(row.imageDigest ? { imageDigest: row.imageDigest } : {}),
257
362
  },
258
363
  }
259
364
  : {}),
365
+ lastUsedAt: new Date(row.lastUsedAt).toISOString(),
260
366
  sessions: related.items,
261
367
  createdAt: row.createdAt,
262
368
  updatedAt: row.updatedAt,
@@ -264,7 +370,7 @@ export function createPostgresReadStore(source, tenantId) {
264
370
  }
265
371
  const last = items.at(-1);
266
372
  return {
267
- sandboxes: items,
373
+ environments: items,
268
374
  nextCursor: rows.length > page.limit && last ? cursor.encode([last.id]) : null,
269
375
  };
270
376
  }),
@@ -1,9 +1,9 @@
1
- import type { RecordWriter, SandboxRecordWriter } from "../../record/index.js";
1
+ import type { RecordWriter, EnvironmentRecordWriter } from "../../record/index.js";
2
2
  import type { Transaction } from "./db.js";
3
3
  /**
4
- * The sandbox stream writer of transaction `db` (`record/sandbox.ts`): the only inserts into
5
- * `sandbox_events`. The caller holds the sandbox row's lock, which orders its events.
4
+ * The Environment stream writer of transaction `db` (`record/environment.ts`): the only inserts
5
+ * into `environment_events`. The caller holds the Environment row's lock, which orders its events.
6
6
  */
7
- export declare function postgresSandboxRecordWriter(db: Transaction): SandboxRecordWriter;
7
+ export declare function postgresEnvironmentRecordWriter(db: Transaction): EnvironmentRecordWriter;
8
8
  /** The record writer of transaction `db`. */
9
9
  export declare function postgresRecordWriter(db: Transaction): RecordWriter;
@@ -5,22 +5,22 @@
5
5
  * run in the store's transaction under the caller's session row lock.
6
6
  */
7
7
  import { eq, sql } from "drizzle-orm";
8
- import { sandboxEvents, sessionEvents, sessionLogHeads, tenant } from "./schema.js";
8
+ import { environmentEvents, sessionEvents, sessionLogHeads, tenant } from "./schema.js";
9
9
  /**
10
- * The sandbox stream writer of transaction `db` (`record/sandbox.ts`): the only inserts into
11
- * `sandbox_events`. The caller holds the sandbox row's lock, which orders its events.
10
+ * The Environment stream writer of transaction `db` (`record/environment.ts`): the only inserts
11
+ * into `environment_events`. The caller holds the Environment row's lock, which orders its events.
12
12
  */
13
- export function postgresSandboxRecordWriter(db) {
13
+ export function postgresEnvironmentRecordWriter(db) {
14
14
  return {
15
- async nextSeq(sandboxId) {
15
+ async nextSeq(environmentId) {
16
16
  const [row] = await db
17
- .select({ next: sql `coalesce(max(${sandboxEvents.seq}) + 1, 0)`.mapWith(Number) })
18
- .from(sandboxEvents)
19
- .where(eq(sandboxEvents.sandboxId, sandboxId));
17
+ .select({ next: sql `coalesce(max(${environmentEvents.seq}) + 1, 0)`.mapWith(Number) })
18
+ .from(environmentEvents)
19
+ .where(eq(environmentEvents.environmentId, environmentId));
20
20
  return row?.next ?? 0;
21
21
  },
22
22
  async insert(row) {
23
- await db.insert(sandboxEvents).values(row);
23
+ await db.insert(environmentEvents).values(row);
24
24
  },
25
25
  };
26
26
  }
@@ -1,5 +1,12 @@
1
+ import type { LiveEvent } from "@nylorun/core/contracts";
1
2
  import type { Sql } from "postgres";
2
3
  import type { RecordReader } from "../../streams/relay/types.js";
3
4
  export declare function createPostgresRecordReader(sql: Sql, options: {
4
5
  tenantId: string;
5
6
  }): RecordReader;
7
+ /**
8
+ * The trace projector's read of a turn's start (R7.2): the `command.message` that started turn
9
+ * `turnId` of `sessionId`, or undefined when the log has none. One session's rows, filtered on
10
+ * the turn id in the event (the record has no turn column; no index yet, R8).
11
+ */
12
+ export declare function createPostgresTurnMessages(sql: Sql): (sessionId: string, turnId: string) => Promise<LiveEvent | undefined>;
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * Reads the record back for the stream relay (Durable Streams §7.2–7.3): a session's rows to
3
3
  * refill a gap in S2, every log head to reconcile after a fresh slot, and the Tenant's current
4
- * basin generation to tell obsolete rows apart.
4
+ * basin generation to tell obsolete rows apart. The trace projector reads a turn's start
5
+ * (`createPostgresTurnMessages`).
5
6
  *
6
7
  * The database holds one Tenant, so the record has no Tenant column: the reader is made for
7
8
  * that Tenant (`tenantId`), fills `RecordRow.tenantId` and `LogHead.tenantId` with it, and
8
9
  * reads nothing for any other id.
9
10
  */
10
- import { and, asc, eq, gt, gte, lt } from "drizzle-orm";
11
+ import { and, asc, eq, gt, gte, lt, sql as sql_ } from "drizzle-orm";
11
12
  import { database, driverError } from "./db.js";
12
13
  import { sessionEvents, sessionLogHeads, tenant } from "./schema.js";
13
14
  export function createPostgresRecordReader(sql, options) {
@@ -58,3 +59,23 @@ export function createPostgresRecordReader(sql, options) {
58
59
  },
59
60
  };
60
61
  }
62
+ /**
63
+ * The trace projector's read of a turn's start (R7.2): the `command.message` that started turn
64
+ * `turnId` of `sessionId`, or undefined when the log has none. One session's rows, filtered on
65
+ * the turn id in the event (the record has no turn column; no index yet, R8).
66
+ */
67
+ export function createPostgresTurnMessages(sql) {
68
+ const db = database(sql);
69
+ return async (sessionId, turnId) => {
70
+ const [row] = await db
71
+ .select({ body: sessionEvents.body })
72
+ .from(sessionEvents)
73
+ .where(and(eq(sessionEvents.sessionId, sessionId), eq(sessionEvents.type, "command.message"), sql_ `${sessionEvents.body}->>'turnId' = ${turnId}`))
74
+ .orderBy(asc(sessionEvents.seq))
75
+ .limit(1)
76
+ .catch((error) => {
77
+ throw driverError(error);
78
+ });
79
+ return row?.body;
80
+ };
81
+ }