@nylorun/runtime 0.23.0-beta → 0.24.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.
- package/CHANGELOG.md +148 -0
- package/README.md +79 -28
- package/dist/adapters/execution/restate.js +1 -1
- package/dist/adapters/replication/pgoutput.d.ts +2 -0
- package/dist/adapters/replication/pgoutput.js +6 -3
- package/dist/adapters/sandbox/local.d.ts +9 -1
- package/dist/adapters/sandbox/local.js +16 -4
- package/dist/adapters/sandbox/virtual.js +4 -1
- package/dist/api/a2a/endpoint.js +5 -1
- package/dist/api/a2a/routes.d.ts +2 -0
- package/dist/api/a2a/routes.js +2 -2
- package/dist/api/a2a/tasks.js +2 -1
- package/dist/api/ag-ui/endpoint.js +4 -2
- package/dist/api/ag-ui/history.js +4 -1
- package/dist/api/ag-ui/routes.d.ts +4 -1
- package/dist/api/ag-ui/routes.js +11 -10
- package/dist/api/ag-ui/translate.js +3 -2
- package/dist/api/components.d.ts +4953 -1204
- package/dist/api/components.js +25 -16
- package/dist/api/gate/keys.js +7 -1
- package/dist/api/gate/routes.d.ts +6 -0
- package/dist/api/gate/routes.js +39 -3
- package/dist/api/http/app.js +4 -4
- package/dist/api/http/define.d.ts +6 -0
- package/dist/api/http/define.js +13 -1
- package/dist/api/http/respond.js +1 -1
- package/dist/api/http/routes/artifacts.js +35 -8
- package/dist/api/http/routes/coverage.d.ts +9 -0
- package/dist/api/http/routes/coverage.js +34 -0
- package/dist/api/http/routes/environments.d.ts +11 -0
- package/dist/api/http/routes/environments.js +283 -0
- package/dist/api/http/routes/mcp.d.ts +1 -1
- package/dist/api/http/routes/mcp.js +2 -2
- package/dist/api/http/routes/me.js +1 -1
- package/dist/api/http/routes/reads.d.ts +45 -9
- package/dist/api/http/routes/reads.js +54 -5
- package/dist/api/http/routes/sessions.js +11 -6
- package/dist/api/http/routes/tenant.js +32 -10
- package/dist/api/openapi.js +31 -26
- package/dist/artifacts/disk.d.ts +59 -0
- package/dist/artifacts/disk.js +563 -0
- package/dist/artifacts/export.d.ts +1 -1
- package/dist/artifacts/export.js +2 -3
- package/dist/artifacts/folders.d.ts +6 -3
- package/dist/artifacts/folders.js +17 -12
- package/dist/artifacts/service.d.ts +2 -1
- package/dist/artifacts/service.js +6 -1
- package/dist/artifacts/workspace.d.ts +1 -1
- package/dist/artifacts/workspace.js +1 -1
- package/dist/core/flow-host.d.ts +2 -3
- package/dist/core/flow-host.js +3 -0
- package/dist/core/provider.d.ts +3 -2
- package/dist/core/provider.js +5 -37
- package/dist/core/sandbox-routes.d.ts +2 -21
- package/dist/core/sandbox-routes.js +10 -43
- package/dist/execution/types.d.ts +1 -1
- package/dist/gates/contract.d.ts +3 -24
- package/dist/gates/contract.js +1 -36
- package/dist/gates/egress-credentials.d.ts +9 -0
- package/dist/gates/egress-credentials.js +11 -4
- package/dist/gates/egress.d.ts +28 -1
- package/dist/gates/egress.js +115 -10
- package/dist/gates/fixture-model.d.ts +28 -0
- package/dist/gates/fixture-model.js +92 -0
- package/dist/gates/handler.js +4 -4
- package/dist/gates/http-tool.d.ts +6 -2
- package/dist/gates/http-tool.js +3 -5
- package/dist/gates/in-process.d.ts +5 -0
- package/dist/gates/in-process.js +12 -1
- package/dist/gates/journal.d.ts +30 -0
- package/dist/gates/journal.js +52 -0
- package/dist/gates/mcp-handler.d.ts +4 -0
- package/dist/gates/mcp-handler.js +5 -1
- package/dist/gates/meter.d.ts +10 -2
- package/dist/gates/meter.js +20 -5
- package/dist/gates/policy.d.ts +49 -0
- package/dist/gates/policy.js +134 -0
- package/dist/gates/tenant-vaults.d.ts +7 -7
- package/dist/gates/tenant-vaults.js +5 -5
- package/dist/gates/tool-calls.d.ts +10 -5
- package/dist/gates/tool-calls.js +28 -10
- package/dist/gates/tool-client.d.ts +8 -0
- package/dist/gates/tool-client.js +27 -11
- package/dist/gates/tool-contract.d.ts +10 -68
- package/dist/gates/tool-contract.js +1 -85
- package/dist/gates/tool-gate.d.ts +1 -1
- package/dist/harness/calls.d.ts +12 -5
- package/dist/harness/calls.js +21 -12
- package/dist/harness/executors.js +12 -9
- package/dist/harness/main.js +18 -5
- package/dist/harness/pod.d.ts +34 -0
- package/dist/harness/pod.js +41 -0
- package/dist/harness/service.d.ts +0 -1
- package/dist/harness/service.js +13 -5
- package/dist/harness/setup.d.ts +27 -0
- package/dist/harness/setup.js +150 -0
- package/dist/harness/ws-client.js +3 -2
- package/dist/harness/ws-port.d.ts +1 -5
- package/dist/harness/ws-port.js +1 -5
- package/dist/harness-api/in-process.js +3 -3
- package/dist/harness-api/record.d.ts +15 -1
- package/dist/harness-api/record.js +174 -44
- package/dist/harness-api/redact.d.ts +3 -0
- package/dist/harness-api/redact.js +45 -0
- package/dist/harness-api/server.d.ts +8 -0
- package/dist/harness-api/server.js +93 -13
- package/dist/harness-api/start.d.ts +10 -3
- package/dist/harness-api/start.js +40 -10
- package/dist/harness-api/tool-journal.d.ts +96 -0
- package/dist/harness-api/tool-journal.js +102 -0
- package/dist/harness-api/tool-status.d.ts +13 -0
- package/dist/harness-api/tool-status.js +26 -0
- package/dist/harness-api/workspace.d.ts +6 -3
- package/dist/harness-api/workspace.js +27 -11
- package/dist/harness-api/ws-server.d.ts +11 -3
- package/dist/harness-api/ws-server.js +94 -15
- package/dist/host/gates.d.ts +2 -1
- package/dist/host/gates.js +10 -2
- package/dist/host/main.js +54 -5
- package/dist/host/operate.js +67 -5
- package/dist/host/stack-config.d.ts +64 -0
- package/dist/host/stack-config.js +61 -1
- package/dist/keys/client.js +4 -1
- package/dist/keys/keys.d.ts +5 -5
- package/dist/keys/keys.js +5 -7
- package/dist/management-openapi.json +999 -2211
- package/dist/mcp/connect.d.ts +25 -20
- package/dist/mcp/connect.js +29 -30
- package/dist/mcp/pool.d.ts +2 -2
- package/dist/mcp/pool.js +1 -1
- package/dist/mcp/preview.d.ts +3 -3
- package/dist/mcp/preview.js +10 -20
- package/dist/mcp/snapshot.d.ts +5 -11
- package/dist/mcp/snapshot.js +6 -7
- package/dist/model/pi-model.js +8 -0
- package/dist/openapi.json +6955 -2526
- package/dist/reads/types.d.ts +16 -3
- package/dist/record/append.d.ts +3 -1
- package/dist/record/append.js +1 -0
- package/dist/record/envelope.d.ts +5 -1
- package/dist/record/envelope.js +7 -3
- package/dist/record/environment.d.ts +25 -0
- package/dist/record/environment.js +44 -0
- package/dist/record/index.d.ts +1 -1
- package/dist/record/index.js +1 -1
- package/dist/sandbox/disk-fs.d.ts +95 -0
- package/dist/sandbox/disk-fs.js +206 -0
- package/dist/sandbox/join.d.ts +17 -18
- package/dist/sandbox/join.js +42 -15
- package/dist/sandbox/manager.d.ts +16 -8
- package/dist/sandbox/manager.js +33 -17
- package/dist/sandbox/placement.d.ts +13 -12
- package/dist/sandbox/placement.js +29 -12
- package/dist/sandbox/pods/client.d.ts +6 -1
- package/dist/sandbox/pods/lifecycle.d.ts +28 -27
- package/dist/sandbox/pods/lifecycle.js +14 -26
- package/dist/sandbox/pods/reconcile.js +18 -12
- package/dist/sandbox/pods/spec.d.ts +15 -13
- package/dist/sandbox/pods/spec.js +16 -20
- package/dist/sandbox/records.d.ts +2 -2
- package/dist/sandbox/records.js +3 -3
- package/dist/sandbox/resolve.d.ts +35 -27
- package/dist/sandbox/resolve.js +66 -41
- package/dist/sandbox/session-sandbox.js +1 -1
- package/dist/sandbox/setup.d.ts +61 -0
- package/dist/sandbox/setup.js +123 -0
- package/dist/sandbox/share.d.ts +11 -21
- package/dist/sandbox/share.js +12 -41
- package/dist/sandbox/tenant-config.d.ts +12 -14
- package/dist/sandbox/tenant-config.js +12 -17
- package/dist/sandbox/types.d.ts +6 -0
- package/dist/store/postgres/drizzle/0020_environments.sql +63 -0
- package/dist/store/postgres/drizzle/0021_disk_versions.sql +7 -0
- package/dist/store/postgres/drizzle/0022_model_usage_timing.sql +5 -0
- package/dist/store/postgres/drizzle/0023_artifact_pages.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/reads.js +117 -17
- package/dist/store/postgres/record-writer.d.ts +4 -4
- package/dist/store/postgres/record-writer.js +9 -9
- package/dist/store/postgres/record.d.ts +7 -0
- package/dist/store/postgres/record.js +23 -2
- package/dist/store/postgres/schema.d.ts +934 -761
- package/dist/store/postgres/schema.js +102 -73
- package/dist/store/postgres/store.js +119 -66
- package/dist/store/types.d.ts +109 -48
- package/dist/tenant/advance.d.ts +7 -6
- package/dist/tenant/advance.js +115 -42
- package/dist/tenant/artifact-tool.js +3 -4
- package/dist/tenant/commands.d.ts +15 -2
- package/dist/tenant/commands.js +93 -12
- package/dist/tenant/context.d.ts +48 -22
- package/dist/tenant/context.js +4 -15
- package/dist/tenant/effects.d.ts +1 -1
- package/dist/tenant/effects.js +37 -20
- package/dist/tenant/environments.d.ts +167 -0
- package/dist/tenant/environments.js +823 -0
- package/dist/tenant/harness-tokens.d.ts +21 -0
- package/dist/tenant/harness-tokens.js +61 -0
- package/dist/tenant/host-token.d.ts +1 -1
- package/dist/tenant/host-token.js +2 -4
- package/dist/tenant/identity-file.d.ts +4 -4
- package/dist/tenant/identity-file.js +17 -8
- package/dist/tenant/issuers.js +3 -3
- package/dist/tenant/principals.js +1 -1
- package/dist/tenant/reset.js +3 -3
- package/dist/tenant/runtime.d.ts +6 -1
- package/dist/tenant/runtime.js +7 -1
- package/dist/tenant/session.d.ts +3 -3
- package/dist/tenant/session.js +0 -14
- package/dist/tenant/sessions.d.ts +13 -13
- package/dist/tenant/sessions.js +61 -138
- package/dist/tenant/signing-keys.d.ts +5 -1
- package/dist/tenant/status.js +3 -3
- package/dist/tenant/sweep.js +12 -6
- package/dist/tenant/transcript.d.ts +210 -20
- package/dist/tenant/transcript.js +62 -11
- package/dist/tenant/turn-timing.d.ts +43 -0
- package/dist/tenant/turn-timing.js +39 -0
- package/dist/tenant/types.d.ts +2 -0
- package/dist/traces/ids.d.ts +42 -0
- package/dist/traces/ids.js +85 -0
- package/dist/traces/key.d.ts +6 -0
- package/dist/traces/key.js +37 -0
- package/dist/traces/map.d.ts +113 -0
- package/dist/traces/map.js +317 -0
- package/dist/traces/options.d.ts +7 -0
- package/dist/traces/options.js +1 -0
- package/dist/traces/otlp.d.ts +42 -0
- package/dist/traces/otlp.js +84 -0
- package/dist/traces/projector.d.ts +58 -0
- package/dist/traces/projector.js +200 -0
- package/dist/traces/read.d.ts +23 -0
- package/dist/traces/read.js +16 -0
- package/dist/vault/coverage.d.ts +26 -0
- package/dist/vault/coverage.js +64 -0
- package/dist/vault/error.d.ts +11 -1
- package/dist/vault/error.js +5 -1
- package/dist/vault/service.d.ts +47 -48
- package/dist/vault/service.js +321 -382
- package/dist/vault/sources.d.ts +5 -16
- package/dist/vault/sources.js +6 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/package.json +13 -13
- package/dist/api/http/routes/sandboxes.d.ts +0 -9
- package/dist/api/http/routes/sandboxes.js +0 -153
- package/dist/api/http/routes/vaults.d.ts +0 -10
- package/dist/api/http/routes/vaults.js +0 -139
- package/dist/record/sandbox.d.ts +0 -25
- package/dist/record/sandbox.js +0 -43
- package/dist/tenant/sandboxes.d.ts +0 -123
- 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 {
|
|
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
|
-
|
|
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,33 @@ 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
|
+
capabilityId: request.capabilityId ?? null,
|
|
65
|
+
toolName: request.toolName ?? null,
|
|
66
|
+
kind: body.toolKind ?? null,
|
|
67
|
+
server: body.server ?? null,
|
|
68
|
+
status,
|
|
69
|
+
// A row written before R5 counted no sends: it was sent once.
|
|
70
|
+
attempts: body.attempts ?? 1,
|
|
71
|
+
input: request.input ?? null,
|
|
72
|
+
error,
|
|
73
|
+
startedAt: body.startedAt ?? null,
|
|
74
|
+
settledAt: body.settledAt ?? null,
|
|
75
|
+
durationMs: toolCallDuration(body) ?? null,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
47
78
|
function keyOf(key, length, timestamp = false, nullable = false) {
|
|
48
79
|
if (key &&
|
|
49
80
|
(key.length !== length ||
|
|
@@ -87,6 +118,39 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
87
118
|
}
|
|
88
119
|
return {
|
|
89
120
|
close: () => pool.end({ timeout: 2 }),
|
|
121
|
+
artifacts: (filters, page, access) => read(async (tx) => {
|
|
122
|
+
if (filters.sessionId !== undefined)
|
|
123
|
+
await requireSession(tx, filters.sessionId, access);
|
|
124
|
+
const cursor = readCursor(tenantId, "artifacts", {
|
|
125
|
+
sessionId: filters.sessionId ?? null,
|
|
126
|
+
kind: filters.kind ?? null,
|
|
127
|
+
labels: Object.entries(filters.labels).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)),
|
|
128
|
+
});
|
|
129
|
+
const key = keyOf(cursor.decode(page.cursor), 2, true);
|
|
130
|
+
if (key && !isArtifactId(key[1]))
|
|
131
|
+
fail(400, "Invalid artifact cursor key", { code: "cursor_invalid" });
|
|
132
|
+
const rows = await tx
|
|
133
|
+
.select()
|
|
134
|
+
.from(artifacts)
|
|
135
|
+
.where(and(access.owner === undefined && access.agents === undefined
|
|
136
|
+
? undefined
|
|
137
|
+
: exists(tx.select({ id: sessions.id })
|
|
138
|
+
.from(sessions)
|
|
139
|
+
.where(and(eq(sessions.id, artifacts.sessionId), accessWhere(access)))), filters.sessionId === undefined
|
|
140
|
+
? undefined
|
|
141
|
+
: eq(artifacts.sessionId, filters.sessionId), filters.kind === undefined ? undefined : eq(artifacts.kind, filters.kind),
|
|
142
|
+
// Labels are a flat string map serialized by JSON.stringify. Match its exact
|
|
143
|
+
// key/value pair: jsonb rejects NUL/unpaired surrogate escapes labels may hold.
|
|
144
|
+
...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))
|
|
145
|
+
.orderBy(desc(artifacts.createdAt), desc(artifacts.id))
|
|
146
|
+
.limit(page.limit + 1);
|
|
147
|
+
const items = rows.slice(0, page.limit);
|
|
148
|
+
const last = items.at(-1);
|
|
149
|
+
return {
|
|
150
|
+
artifacts: items.map((row) => artifactView(row)),
|
|
151
|
+
nextCursor: rows.length > page.limit && last ? cursor.encode([last.createdAt, last.id]) : null,
|
|
152
|
+
};
|
|
153
|
+
}),
|
|
90
154
|
sessions: (filters, page, access) => read(async (tx) => {
|
|
91
155
|
const cursor = readCursor(tenantId, "sessions", filters);
|
|
92
156
|
const key = keyOf(cursor.decode(page.cursor), 2, true, true);
|
|
@@ -98,9 +162,9 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
98
162
|
const rows = await tx
|
|
99
163
|
.select(fields)
|
|
100
164
|
.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.
|
|
165
|
+
.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
166
|
? undefined
|
|
103
|
-
: eq(sessions.
|
|
167
|
+
: eq(sessions.environmentId, filters.environmentId), filters.ownerUserId === undefined
|
|
104
168
|
? undefined
|
|
105
169
|
: eq(sessions.ownerUserId, filters.ownerUserId)))
|
|
106
170
|
.orderBy(sql `${sessions.createdAt} desc nulls last`, desc(sessions.id))
|
|
@@ -182,6 +246,37 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
182
246
|
asOf: new Date().toISOString(),
|
|
183
247
|
};
|
|
184
248
|
}),
|
|
249
|
+
toolCalls: (id, turnId, page, access) => read(async (tx) => {
|
|
250
|
+
await requireSession(tx, id, access);
|
|
251
|
+
const cursor = readCursor(tenantId, "tool-calls", { sessionId: id, turnId });
|
|
252
|
+
const key = keyOf(cursor.decode(page.cursor), 2);
|
|
253
|
+
// In the order of their first send; a row written before R5 has no `startedAt`.
|
|
254
|
+
const startedAt = sql `coalesce(${effects.body}->>'startedAt', '')`;
|
|
255
|
+
const rows = await tx
|
|
256
|
+
.select({ id: effects.id, body: effects.body, startedAt })
|
|
257
|
+
.from(effects)
|
|
258
|
+
.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))
|
|
259
|
+
.orderBy(asc(startedAt), asc(effects.id))
|
|
260
|
+
.limit(page.limit + 1);
|
|
261
|
+
const items = rows.slice(0, page.limit);
|
|
262
|
+
const last = items.at(-1);
|
|
263
|
+
return {
|
|
264
|
+
calls: items.map((row) => publicToolCall(row.body)),
|
|
265
|
+
nextCursor: rows.length > page.limit && last ? cursor.encode([last.startedAt, last.id]) : null,
|
|
266
|
+
asOf: new Date().toISOString(),
|
|
267
|
+
};
|
|
268
|
+
}),
|
|
269
|
+
turnEvents: (id, turnId, access) => read(async (tx) => {
|
|
270
|
+
await requireSession(tx, id, access);
|
|
271
|
+
// The record has no turn column: one session's rows, on the turn id in the event (no
|
|
272
|
+
// index yet, R8).
|
|
273
|
+
const rows = await tx
|
|
274
|
+
.select({ body: sessionEvents.body })
|
|
275
|
+
.from(sessionEvents)
|
|
276
|
+
.where(and(eq(sessionEvents.sessionId, id), sql `${sessionEvents.body}->>'turnId' = ${turnId}`))
|
|
277
|
+
.orderBy(asc(sessionEvents.seq));
|
|
278
|
+
return rows.map((row) => row.body);
|
|
279
|
+
}),
|
|
185
280
|
exportModel: (after, limit) => read(async (tx) => {
|
|
186
281
|
const cursor = readCursor(tenantId, "model-export", {});
|
|
187
282
|
const key = keyOf(cursor.decode(after), 2);
|
|
@@ -205,19 +300,19 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
205
300
|
asOf: new Date().toISOString(),
|
|
206
301
|
};
|
|
207
302
|
}),
|
|
208
|
-
|
|
209
|
-
const cursor = readCursor(tenantId, "
|
|
303
|
+
environments: (labels, page, access, grants) => read(async (tx) => {
|
|
304
|
+
const cursor = readCursor(tenantId, "environments", labels);
|
|
210
305
|
const key = keyOf(cursor.decode(page.cursor), 1);
|
|
211
306
|
const allowed = grants === undefined
|
|
212
307
|
? undefined
|
|
213
308
|
: or(...grants.map((grant) => grant.endsWith("/*")
|
|
214
|
-
? sql `starts_with(${
|
|
215
|
-
: eq(
|
|
309
|
+
? sql `starts_with(${environments.id}, ${grant.slice(0, -1)})`
|
|
310
|
+
: eq(environments.id, grant)));
|
|
216
311
|
const rows = await tx
|
|
217
312
|
.select()
|
|
218
|
-
.from(
|
|
219
|
-
.where(and(grants?.length === 0 ? sql `false` : allowed, key ? gt(
|
|
220
|
-
.orderBy(asc(
|
|
313
|
+
.from(environments)
|
|
314
|
+
.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}`)))
|
|
315
|
+
.orderBy(asc(environments.id))
|
|
221
316
|
.limit(page.limit + 1);
|
|
222
317
|
const items = [];
|
|
223
318
|
for (const row of rows.slice(0, page.limit)) {
|
|
@@ -226,7 +321,7 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
226
321
|
items: sql `coalesce(json_agg(json_build_object('id', ${sessions.id}, 'activeTurnId', ${sessions.body}->>'activeTurnId') order by ${sessions.id}), '[]'::json)`,
|
|
227
322
|
})
|
|
228
323
|
.from(sessions)
|
|
229
|
-
.where(and(eq(sessions.
|
|
324
|
+
.where(and(eq(sessions.environmentId, row.id), accessWhere(access)));
|
|
230
325
|
const [compute] = await tx
|
|
231
326
|
.select({ body: sandboxes.body })
|
|
232
327
|
.from(sandboxes)
|
|
@@ -237,14 +332,19 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
237
332
|
id: row.id,
|
|
238
333
|
kind: row.kind,
|
|
239
334
|
labels: row.labels,
|
|
240
|
-
|
|
335
|
+
recipe: row.recipe,
|
|
336
|
+
version: row.version,
|
|
337
|
+
appliedVersion: row.appliedVersion,
|
|
338
|
+
ownerUserId: row.ownerUserId,
|
|
241
339
|
state: isPod
|
|
242
340
|
? row.observed === "running"
|
|
243
341
|
? "running"
|
|
244
342
|
: row.observed === "creating"
|
|
245
343
|
? "creating"
|
|
246
344
|
: "stopped"
|
|
247
|
-
:
|
|
345
|
+
: row.kind === "none"
|
|
346
|
+
? "ready"
|
|
347
|
+
: (compute?.body?.state ?? "ready"),
|
|
248
348
|
...(isPod
|
|
249
349
|
? {
|
|
250
350
|
pod: {
|
|
@@ -252,11 +352,11 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
252
352
|
observed: row.observed,
|
|
253
353
|
volumeGeneration: row.volumeGen,
|
|
254
354
|
hostEpoch: row.hostEpoch,
|
|
255
|
-
...(row.expiresAt ? { expiresAt: new Date(row.expiresAt).toISOString() } : {}),
|
|
256
355
|
...(row.reason ? { reason: row.reason } : {}),
|
|
257
356
|
},
|
|
258
357
|
}
|
|
259
358
|
: {}),
|
|
359
|
+
lastUsedAt: new Date(row.lastUsedAt).toISOString(),
|
|
260
360
|
sessions: related.items,
|
|
261
361
|
createdAt: row.createdAt,
|
|
262
362
|
updatedAt: row.updatedAt,
|
|
@@ -264,7 +364,7 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
264
364
|
}
|
|
265
365
|
const last = items.at(-1);
|
|
266
366
|
return {
|
|
267
|
-
|
|
367
|
+
environments: items,
|
|
268
368
|
nextCursor: rows.length > page.limit && last ? cursor.encode([last.id]) : null,
|
|
269
369
|
};
|
|
270
370
|
}),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { RecordWriter,
|
|
1
|
+
import type { RecordWriter, EnvironmentRecordWriter } from "../../record/index.js";
|
|
2
2
|
import type { Transaction } from "./db.js";
|
|
3
3
|
/**
|
|
4
|
-
* The
|
|
5
|
-
* `
|
|
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
|
|
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 {
|
|
8
|
+
import { environmentEvents, sessionEvents, sessionLogHeads, tenant } from "./schema.js";
|
|
9
9
|
/**
|
|
10
|
-
* The
|
|
11
|
-
* `
|
|
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
|
|
13
|
+
export function postgresEnvironmentRecordWriter(db) {
|
|
14
14
|
return {
|
|
15
|
-
async nextSeq(
|
|
15
|
+
async nextSeq(environmentId) {
|
|
16
16
|
const [row] = await db
|
|
17
|
-
.select({ next: sql `coalesce(max(${
|
|
18
|
-
.from(
|
|
19
|
-
.where(eq(
|
|
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(
|
|
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
|
+
}
|