@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.
- package/CHANGELOG.md +169 -0
- package/README.md +26 -16
- package/dist/adapters/execution/restate.d.ts +15 -18
- package/dist/adapters/execution/restate.js +31 -27
- package/dist/adapters/replication/pgoutput.d.ts +1 -1
- package/dist/adapters/replication/pgoutput.js +3 -2
- package/dist/adapters/sandbox/local.js +8 -5
- package/dist/adapters/sandbox/virtual.js +2 -2
- package/dist/adapters/streams/s2.d.ts +1 -1
- package/dist/adapters/streams/s2.js +18 -14
- package/dist/api/a2a/card.js +1 -1
- package/dist/api/a2a/endpoint.js +3 -4
- package/dist/api/a2a/protocol.js +4 -0
- package/dist/api/a2a/routes.d.ts +2 -6
- package/dist/api/a2a/routes.js +12 -18
- package/dist/api/ag-ui/endpoint.js +2 -3
- package/dist/api/ag-ui/routes.js +4 -4
- package/dist/api/components.d.ts +326 -45
- package/dist/api/components.js +5 -1
- package/dist/api/gate/keys.js +7 -4
- package/dist/api/gate/routes.d.ts +6 -2
- package/dist/api/gate/routes.js +15 -11
- package/dist/api/http/app.d.ts +2 -2
- package/dist/api/http/app.js +2 -2
- package/dist/api/http/body.d.ts +15 -3
- package/dist/api/http/body.js +15 -7
- package/dist/api/http/define.d.ts +1 -1
- package/dist/api/http/respond.js +7 -3
- package/dist/api/http/routes/access.js +5 -4
- package/dist/api/http/routes/artifacts.js +19 -7
- package/dist/api/http/routes/coverage.js +1 -1
- package/dist/api/http/routes/environment-manifests.js +1 -1
- package/dist/api/http/routes/environments.js +6 -6
- package/dist/api/http/routes/files.d.ts +2 -1
- package/dist/api/http/routes/files.js +31 -5
- package/dist/api/http/routes/mcp.js +1 -1
- package/dist/api/http/routes/reads.d.ts +35 -0
- package/dist/api/http/routes/reads.js +50 -22
- package/dist/api/http/routes/sessions.js +12 -11
- package/dist/api/http/routes/tenant.d.ts +2 -2
- package/dist/api/http/routes/tenant.js +69 -16
- package/dist/api/inbound-files.d.ts +3 -9
- package/dist/api/inbound-files.js +18 -24
- package/dist/api/openapi.js +6 -2
- package/dist/artifacts/disk.d.ts +0 -4
- package/dist/artifacts/disk.js +77 -73
- package/dist/artifacts/files.d.ts +13 -4
- package/dist/artifacts/files.js +27 -9
- package/dist/artifacts/folder-upload.d.ts +75 -0
- package/dist/artifacts/folder-upload.js +263 -0
- package/dist/artifacts/folders.d.ts +14 -8
- package/dist/artifacts/folders.js +19 -11
- package/dist/artifacts/links.js +7 -6
- package/dist/artifacts/parts.d.ts +9 -14
- package/dist/artifacts/parts.js +11 -9
- package/dist/artifacts/pipe.d.ts +15 -0
- package/dist/artifacts/pipe.js +71 -0
- package/dist/artifacts/quota.d.ts +36 -0
- package/dist/artifacts/quota.js +44 -0
- package/dist/artifacts/service.d.ts +25 -1
- package/dist/artifacts/service.js +70 -25
- package/dist/blob/fs.js +2 -1
- package/dist/blob/s3.d.ts +6 -2
- package/dist/blob/s3.js +9 -7
- package/dist/blob/types.d.ts +1 -1
- package/dist/blob/types.js +1 -1
- package/dist/core/limits.d.ts +11 -35
- package/dist/core/limits.js +5 -73
- package/dist/core/sandbox-routes.js +0 -1
- package/dist/core/turn-manifest.d.ts +1 -2
- package/dist/core/turn-manifest.js +4 -28
- package/dist/execution/memory.d.ts +8 -5
- package/dist/execution/memory.js +8 -6
- package/dist/execution/types.d.ts +1 -6
- package/dist/execution/types.js +0 -5
- package/dist/gates/contract.d.ts +3 -2
- package/dist/gates/contract.js +1 -1
- package/dist/gates/egress-credentials.js +4 -3
- package/dist/gates/egress.d.ts +9 -9
- package/dist/gates/egress.js +19 -19
- package/dist/gates/fixture-model.js +13 -2
- package/dist/gates/handler.d.ts +1 -3
- package/dist/gates/handler.js +4 -3
- package/dist/gates/http-client.d.ts +4 -3
- package/dist/gates/http-client.js +5 -7
- package/dist/gates/http-tool.d.ts +24 -4
- package/dist/gates/http-tool.js +53 -17
- package/dist/gates/in-process.d.ts +2 -1
- package/dist/gates/in-process.js +17 -9
- package/dist/gates/inflight.d.ts +2 -2
- package/dist/gates/inflight.js +3 -2
- package/dist/gates/journal.js +5 -7
- package/dist/gates/mcp-handler.d.ts +4 -3
- package/dist/gates/mcp-handler.js +15 -5
- package/dist/gates/model-gate.d.ts +11 -2
- package/dist/gates/policy.d.ts +28 -5
- package/dist/gates/policy.js +60 -17
- package/dist/gates/provider-gate.d.ts +22 -0
- package/dist/gates/provider-gate.js +30 -0
- package/dist/gates/tool-calls.d.ts +1 -3
- package/dist/gates/tool-calls.js +2 -3
- package/dist/gates/tool-client.d.ts +1 -1
- package/dist/gates/tool-client.js +5 -6
- package/dist/gates/tool-contract.d.ts +8 -5
- package/dist/gates/tool-contract.js +1 -1
- package/dist/gates/tool-gate.d.ts +18 -7
- package/dist/gates/tool-gate.js +49 -7
- package/dist/harness/calls.d.ts +27 -25
- package/dist/harness/calls.js +40 -46
- package/dist/harness/executors.d.ts +10 -3
- package/dist/harness/executors.js +53 -23
- package/dist/harness/main.js +2 -2
- package/dist/harness/pod.d.ts +0 -2
- package/dist/harness/pod.js +7 -6
- package/dist/harness/run-tokens.d.ts +4 -1
- package/dist/harness/run-tokens.js +6 -2
- package/dist/harness/service.d.ts +17 -14
- package/dist/harness/service.js +21 -35
- package/dist/harness/setup.d.ts +0 -2
- package/dist/harness/setup.js +4 -9
- package/dist/harness/ws-client.d.ts +2 -2
- package/dist/harness/ws-client.js +7 -5
- package/dist/harness/ws-port.d.ts +3 -4
- package/dist/harness/ws-port.js +3 -4
- package/dist/harness-api/artifacts.d.ts +20 -0
- package/dist/harness-api/artifacts.js +478 -0
- package/dist/harness-api/in-process.d.ts +2 -2
- package/dist/harness-api/in-process.js +18 -16
- package/dist/harness-api/record.d.ts +10 -9
- package/dist/harness-api/record.js +102 -157
- package/dist/harness-api/renew.d.ts +1 -1
- package/dist/harness-api/renew.js +2 -2
- package/dist/harness-api/server.d.ts +1 -16
- package/dist/harness-api/server.js +82 -73
- package/dist/harness-api/start.d.ts +20 -2
- package/dist/harness-api/start.js +57 -18
- package/dist/harness-api/tool-journal.d.ts +15 -10
- package/dist/harness-api/tool-journal.js +26 -24
- package/dist/harness-api/workspace.d.ts +0 -4
- package/dist/harness-api/workspace.js +2 -45
- package/dist/harness-api/ws-server.js +10 -10
- package/dist/host/create-host.js +2 -3
- package/dist/host/execution.js +2 -3
- package/dist/host/gates.d.ts +2 -9
- package/dist/host/gates.js +15 -12
- package/dist/host/http.d.ts +0 -2
- package/dist/host/http.js +0 -27
- package/dist/host/main.js +10 -3
- package/dist/host/operate.js +12 -3
- package/dist/host/stack-config.d.ts +11 -0
- package/dist/host/stack-config.js +21 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/infra/index.js +2 -1
- package/dist/infra/readiness.d.ts +0 -2
- package/dist/infra/readiness.js +4 -3
- package/dist/keys/client.d.ts +1 -0
- package/dist/keys/client.js +2 -3
- package/dist/keys/contract.d.ts +1 -3
- package/dist/keys/contract.js +1 -3
- package/dist/keys/egress-ca.d.ts +0 -2
- package/dist/keys/egress-ca.js +2 -3
- package/dist/keys/keys.js +6 -1
- package/dist/keys/x509.d.ts +8 -4
- package/dist/keys/x509.js +14 -5
- package/dist/management-openapi.json +1961 -994
- package/dist/mcp/connect.d.ts +35 -26
- package/dist/mcp/connect.js +112 -141
- package/dist/mcp/pool.d.ts +27 -22
- package/dist/mcp/pool.js +34 -48
- package/dist/mcp/preview.d.ts +13 -6
- package/dist/mcp/preview.js +37 -20
- package/dist/mcp/snapshot.d.ts +35 -86
- package/dist/mcp/snapshot.js +93 -135
- package/dist/model/auth-store.js +5 -3
- package/dist/model/capabilities.d.ts +1 -1
- package/dist/model/catalog.d.ts +9 -36
- package/dist/model/catalog.js +6 -33
- package/dist/model/descriptor.d.ts +51 -0
- package/dist/model/descriptor.js +83 -0
- package/dist/model/models.d.ts +0 -3
- package/dist/model/models.js +3 -5
- package/dist/model/native-blocks.js +1 -1
- package/dist/model/pi-model.d.ts +16 -5
- package/dist/model/pi-model.js +86 -105
- package/dist/openapi.json +866 -1218
- package/dist/reads/cursor.js +3 -1
- package/dist/record/append.d.ts +34 -2
- package/dist/record/append.js +50 -1
- package/dist/record/environment.d.ts +2 -0
- package/dist/record/environment.js +2 -0
- package/dist/record/index.d.ts +1 -1
- package/dist/record/index.js +1 -1
- package/dist/redact.d.ts +1 -1
- package/dist/redact.js +3 -2
- package/dist/sandbox/egress-token.d.ts +3 -3
- package/dist/sandbox/egress-token.js +3 -3
- package/dist/sandbox/join.js +3 -2
- package/dist/sandbox/manager.d.ts +41 -41
- package/dist/sandbox/manager.js +112 -44
- package/dist/sandbox/placement.d.ts +1 -1
- package/dist/sandbox/placement.js +5 -8
- package/dist/sandbox/pods/client.d.ts +1 -10
- package/dist/sandbox/pods/client.js +8 -4
- package/dist/sandbox/pods/lifecycle.d.ts +19 -11
- package/dist/sandbox/pods/lifecycle.js +45 -23
- package/dist/sandbox/pods/network-gate.d.ts +4 -5
- package/dist/sandbox/pods/network-gate.js +7 -7
- package/dist/sandbox/pods/reconcile.js +4 -1
- package/dist/sandbox/pods/spec.js +8 -5
- package/dist/sandbox/policy.d.ts +7 -1
- package/dist/sandbox/policy.js +10 -3
- package/dist/sandbox/resolve.d.ts +8 -3
- package/dist/sandbox/resolve.js +12 -2
- package/dist/sandbox/setup.d.ts +3 -1
- package/dist/sandbox/setup.js +34 -11
- package/dist/sandbox/share.d.ts +5 -14
- package/dist/sandbox/share.js +5 -34
- package/dist/sandbox/skills.d.ts +7 -13
- package/dist/sandbox/skills.js +16 -31
- package/dist/sandbox/tenant-config.d.ts +2 -2
- package/dist/sandbox/tenant-config.js +4 -3
- package/dist/sandbox/tools.d.ts +7 -1
- package/dist/sandbox/tools.js +26 -26
- package/dist/sandbox/types.d.ts +10 -3
- package/dist/sandbox/types.js +9 -0
- package/dist/store/postgres/connect.d.ts +6 -5
- package/dist/store/postgres/connect.js +14 -11
- package/dist/store/postgres/control.js +13 -13
- package/dist/store/postgres/drizzle/0028_artifact_write_keys.sql +2 -0
- package/dist/store/postgres/drizzle/0029_protocol_15.sql +11 -0
- package/dist/store/postgres/drizzle/0030_protocol_15_runtime_block.sql +11 -0
- package/dist/store/postgres/drizzle/0031_protocol_15_mcp_snapshot.sql +8 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/migrate.js +1 -1
- package/dist/store/postgres/reads.js +10 -2
- package/dist/store/postgres/schema.d.ts +19 -0
- package/dist/store/postgres/schema.js +7 -0
- package/dist/store/postgres/store.js +55 -26
- package/dist/store/types.d.ts +17 -7
- package/dist/streams/relay/core.d.ts +3 -3
- package/dist/streams/relay/core.js +9 -10
- package/dist/tenant/advance.js +21 -31
- package/dist/tenant/commands.js +9 -16
- package/dist/tenant/context.d.ts +14 -17
- package/dist/tenant/definition-files.d.ts +25 -4
- package/dist/tenant/definition-files.js +85 -47
- package/dist/tenant/effects.js +9 -36
- package/dist/tenant/environment-manifests.js +9 -1
- package/dist/tenant/environments.d.ts +0 -2
- package/dist/tenant/environments.js +54 -30
- package/dist/tenant/ephemeral.d.ts +1 -1
- package/dist/tenant/ephemeral.js +2 -1
- package/dist/tenant/history.d.ts +1 -1
- package/dist/tenant/history.js +1 -1
- package/dist/tenant/host-token.d.ts +3 -3
- package/dist/tenant/host-token.js +12 -11
- package/dist/tenant/http.d.ts +5 -8
- package/dist/tenant/http.js +9 -0
- package/dist/tenant/identity-file.d.ts +24 -1
- package/dist/tenant/identity-file.js +35 -7
- package/dist/tenant/issuers.d.ts +5 -5
- package/dist/tenant/issuers.js +31 -23
- package/dist/tenant/jwt.d.ts +8 -2
- package/dist/tenant/jwt.js +10 -2
- package/dist/tenant/limits.d.ts +90 -0
- package/dist/tenant/limits.js +175 -0
- package/dist/tenant/module.d.ts +4 -1
- package/dist/tenant/module.js +9 -8
- package/dist/tenant/outbound.d.ts +17 -19
- package/dist/tenant/outbound.js +18 -21
- package/dist/tenant/run-grants.js +3 -2
- package/dist/tenant/run-token.d.ts +0 -4
- package/dist/tenant/run-token.js +6 -11
- package/dist/tenant/runtime-limits.d.ts +24 -0
- package/dist/tenant/runtime-limits.js +27 -0
- package/dist/tenant/runtime.js +30 -43
- package/dist/tenant/session-streams.js +7 -6
- package/dist/tenant/session.d.ts +1 -1
- package/dist/tenant/session.js +1 -1
- package/dist/tenant/sessions.js +32 -29
- package/dist/tenant/signing-keys.d.ts +1 -1
- package/dist/tenant/signing-keys.js +5 -6
- package/dist/tenant/status.js +4 -3
- package/dist/tenant/streams.js +18 -20
- package/dist/tenant/sweep.d.ts +1 -21
- package/dist/tenant/sweep.js +39 -48
- package/dist/tenant/transcript.d.ts +70 -23
- package/dist/tenant/transcript.js +28 -22
- package/dist/tenant/types.d.ts +11 -16
- package/dist/tenant/worker.d.ts +2 -10
- package/dist/tenant/worker.js +5 -14
- package/dist/traces/ids.js +5 -1
- package/dist/traces/map.d.ts +9 -6
- package/dist/traces/map.js +9 -11
- package/dist/traces/otlp.d.ts +3 -3
- package/dist/traces/otlp.js +5 -3
- package/dist/traces/projector.d.ts +9 -4
- package/dist/traces/projector.js +13 -7
- package/dist/traces/read.js +6 -1
- package/dist/tuning.d.ts +383 -0
- package/dist/tuning.js +658 -0
- package/dist/vault/headers.js +4 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/artifacts/export.d.ts +0 -8
- package/dist/artifacts/export.js +0 -204
- package/dist/artifacts/media-types.d.ts +0 -30
- package/dist/artifacts/media-types.js +0 -137
- package/dist/artifacts/workspace.d.ts +0 -60
- package/dist/artifacts/workspace.js +0 -45
- package/dist/media.d.ts +0 -10
- package/dist/media.js +0 -58
- package/dist/sandbox/runtime-tools.d.ts +0 -9
- package/dist/sandbox/runtime-tools.js +0 -16
- package/dist/sandbox/session-sandbox.d.ts +0 -16
- package/dist/sandbox/session-sandbox.js +0 -77
- package/dist/tenant/artifact-tool.d.ts +0 -13
- package/dist/tenant/artifact-tool.js +0 -243
- package/dist/tenant/skill-tool.d.ts +0 -20
- package/dist/tenant/skill-tool.js +0 -67
- package/dist/tenant/tool-results.d.ts +0 -57
- package/dist/tenant/tool-results.js +0 -298
- package/dist/tenant/tool-search.d.ts +0 -39
- 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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
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 +=
|
|
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 +
|
|
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 +=
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
.from(artifactContent)
|
|
1260
|
-
|
|
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
|
|
1306
|
-
for (let at = 0; at < shas.length; at +=
|
|
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 +
|
|
1339
|
+
.where(inArray(definitionFiles.sha256, shas.slice(at, at + contentBatch())));
|
|
1311
1340
|
for (const row of rows)
|
|
1312
|
-
found.
|
|
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 +=
|
|
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 +
|
|
1350
|
+
.values(shas.slice(at, at + contentBatch()).map((sha256) => ({ agentId, manifestHash, sha256 })))
|
|
1322
1351
|
.onConflictDoNothing();
|
|
1323
1352
|
}
|
|
1324
1353
|
// --- settings ------------------------------------------------------------
|
package/dist/store/types.d.ts
CHANGED
|
@@ -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(
|
|
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
|
-
/**
|
|
763
|
-
|
|
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<
|
|
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
|
|
35
|
-
const
|
|
36
|
-
const
|
|
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 =
|
|
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 =
|
|
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,
|
|
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,
|
|
245
|
+
const page = await record.heads(after, tuning.relayHeadsPage);
|
|
247
246
|
if (page.length === 0)
|
|
248
247
|
break;
|
|
249
248
|
let next = 0;
|
package/dist/tenant/advance.js
CHANGED
|
@@ -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(
|
|
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:
|
|
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
|
-
|
|
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
|
|
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 ${
|
|
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`.
|
|
672
|
-
*
|
|
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;
|
package/dist/tenant/commands.js
CHANGED
|
@@ -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)
|
|
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
|
-
:
|
|
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.
|
|
160
|
-
//
|
|
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)
|
|
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] : []));
|
package/dist/tenant/context.d.ts
CHANGED
|
@@ -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;
|
|
53
|
-
*
|
|
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)
|
|
119
|
-
*
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
|
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
|
-
/**
|
|
22
|
-
|
|
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>;
|