@nylorun/runtime 0.16.0-beta → 0.19.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 +207 -0
- package/README.md +105 -63
- package/dist/adapters/execution/restate.d.ts +1 -3
- package/dist/adapters/execution/restate.js +4 -31
- package/dist/adapters/replication/pgoutput.js +1 -1
- package/dist/adapters/sandbox/local.js +1 -1
- package/dist/adapters/sandbox/virtual.js +1 -1
- package/dist/api/ag-ui/endpoint.js +1 -2
- package/dist/api/ag-ui/routes.d.ts +1 -1
- package/dist/api/ag-ui/routes.js +11 -13
- package/dist/api/ag-ui/translate.d.ts +1 -3
- package/dist/api/ag-ui/translate.js +2 -17
- package/dist/api/components.d.ts +4783 -2588
- package/dist/api/components.js +19 -21
- package/dist/api/gate/routes.d.ts +7 -8
- package/dist/api/gate/routes.js +58 -52
- package/dist/api/http/app.d.ts +6 -0
- package/dist/api/http/app.js +20 -14
- package/dist/api/http/define.d.ts +22 -13
- package/dist/api/http/define.js +43 -39
- package/dist/api/http/routes/access.d.ts +3 -19
- package/dist/api/http/routes/access.js +25 -184
- package/dist/api/http/routes/artifacts.js +3 -7
- package/dist/api/http/routes/files.d.ts +8 -0
- package/dist/api/http/routes/files.js +77 -0
- package/dist/api/http/routes/keys.d.ts +10 -0
- package/dist/api/http/routes/keys.js +64 -0
- package/dist/api/http/routes/me.d.ts +13 -0
- package/dist/api/http/routes/me.js +48 -0
- package/dist/api/http/routes/reads.d.ts +66 -0
- package/dist/api/http/routes/reads.js +127 -0
- package/dist/api/http/routes/sandboxes.d.ts +2 -2
- package/dist/api/http/routes/sandboxes.js +8 -7
- package/dist/api/http/routes/sessions.js +31 -20
- package/dist/api/http/routes/tenant.js +15 -18
- package/dist/api/http/routes/vaults.d.ts +13 -3
- package/dist/api/http/routes/vaults.js +136 -64
- package/dist/api/openapi.d.ts +10 -11
- package/dist/api/openapi.js +292 -68
- package/dist/artifacts/links.js +6 -6
- package/dist/artifacts/service.js +1 -1
- package/dist/core/flow-host.d.ts +44 -23
- package/dist/core/flow-host.js +88 -106
- package/dist/core/provider.d.ts +4 -1
- package/dist/core/provider.js +6 -1
- package/dist/core/sandbox-routes.d.ts +0 -9
- package/dist/core/sandbox-routes.js +2 -21
- package/dist/execution/memory.d.ts +4 -5
- package/dist/execution/memory.js +11 -25
- package/dist/execution/types.d.ts +3 -33
- package/dist/execution/types.js +2 -12
- package/dist/gates/http-tool.d.ts +86 -0
- package/dist/gates/http-tool.js +197 -0
- package/dist/gates/mcp-handler.d.ts +3 -0
- package/dist/gates/mcp-handler.js +6 -4
- package/dist/gates/meter.d.ts +2 -2
- package/dist/gates/meter.js +6 -0
- package/dist/gates/tenant-vaults.d.ts +19 -14
- package/dist/gates/tenant-vaults.js +17 -12
- package/dist/gates/tool-calls.d.ts +7 -15
- package/dist/gates/tool-calls.js +4 -4
- package/dist/gates/tool-client.d.ts +1 -1
- package/dist/gates/tool-client.js +23 -47
- package/dist/gates/tool-contract.d.ts +27 -39
- package/dist/gates/tool-contract.js +30 -21
- package/dist/gates/tool-gate.d.ts +25 -24
- package/dist/gates/tool-gate.js +11 -7
- package/dist/harness/calls.d.ts +10 -4
- package/dist/harness/calls.js +15 -6
- package/dist/harness/executors.d.ts +1 -1
- package/dist/harness/executors.js +17 -12
- package/dist/harness/main.d.ts +2 -2
- package/dist/harness/main.js +5 -13
- package/dist/harness/service.d.ts +4 -5
- package/dist/harness/service.js +9 -2
- package/dist/harness-api/in-process.js +2 -2
- package/dist/harness-api/record.d.ts +6 -3
- package/dist/harness-api/record.js +65 -72
- package/dist/harness-api/server.d.ts +1 -9
- package/dist/harness-api/server.js +19 -17
- package/dist/harness-api/start.js +1 -5
- package/dist/harness-api/workspace.js +2 -3
- package/dist/harness-api/ws-server.js +1 -1
- package/dist/host/app.d.ts +2 -10
- package/dist/host/app.js +24 -44
- package/dist/host/config-for.d.ts +5 -5
- package/dist/host/config-for.js +2 -3
- package/dist/host/config.d.ts +0 -11
- package/dist/host/create-host.d.ts +3 -40
- package/dist/host/create-host.js +18 -91
- package/dist/host/environment.d.ts +0 -3
- package/dist/host/environment.js +0 -9
- package/dist/host/gates.d.ts +4 -1
- package/dist/host/gates.js +9 -3
- package/dist/host/http.d.ts +1 -2
- package/dist/host/http.js +1 -7
- package/dist/host/index.d.ts +2 -2
- package/dist/host/index.js +2 -2
- package/dist/host/main.js +55 -40
- package/dist/host/operate.d.ts +29 -0
- package/dist/host/operate.js +223 -0
- package/dist/host/stack-config.d.ts +23 -20
- package/dist/host/stack-config.js +28 -44
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/infra/workers.d.ts +1 -1
- package/dist/keys/client.js +9 -1
- package/dist/keys/keys.d.ts +12 -2
- package/dist/keys/keys.js +10 -2
- package/dist/management-openapi.json +6491 -0
- package/dist/mcp/connect.d.ts +8 -4
- package/dist/mcp/connect.js +8 -27
- package/dist/mcp/pool.d.ts +6 -9
- package/dist/mcp/pool.js +8 -18
- package/dist/mcp/snapshot.d.ts +8 -2
- package/dist/mcp/snapshot.js +29 -2
- package/dist/media.d.ts +1 -1
- package/dist/media.js +1 -1
- package/dist/model/pi-model.js +3 -0
- package/dist/openapi.json +6228 -15615
- package/dist/reads/access.d.ts +4 -0
- package/dist/reads/access.js +12 -0
- package/dist/reads/cursor.d.ts +11 -0
- package/dist/reads/cursor.js +80 -0
- package/dist/reads/types.d.ts +25 -0
- package/dist/reads/types.js +1 -0
- package/dist/sandbox/manager.d.ts +16 -0
- package/dist/sandbox/manager.js +40 -0
- package/dist/sandbox/session-sandbox.js +13 -3
- package/dist/sandbox/skills.d.ts +13 -0
- package/dist/sandbox/skills.js +46 -0
- package/dist/sandbox/types.d.ts +2 -2
- package/dist/store/ownership.d.ts +9 -0
- package/dist/store/ownership.js +13 -0
- package/dist/store/postgres/connect.d.ts +2 -0
- package/dist/store/postgres/connect.js +29 -0
- package/dist/store/postgres/drizzle/0008_installation_vaults.sql +2 -0
- package/dist/store/postgres/drizzle/0009_oauth_pending.sql +19 -0
- package/dist/store/postgres/drizzle/0010_oss_auth_removals.sql +3 -0
- package/dist/store/postgres/drizzle/0011_key_roles.sql +3 -0
- package/dist/store/postgres/drizzle/0012_session_reads.sql +8 -0
- package/dist/store/postgres/drizzle/0013_definition_files.sql +16 -0
- package/dist/store/postgres/drizzle/0014_action_endpoints_removed.sql +2 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +49 -0
- package/dist/store/postgres/reads.d.ts +3 -0
- package/dist/store/postgres/reads.js +272 -0
- package/dist/store/postgres/schema.d.ts +423 -594
- package/dist/store/postgres/schema.js +84 -101
- package/dist/store/postgres/store.js +96 -248
- package/dist/store/postgres/tenant.d.ts +34 -2
- package/dist/store/postgres/tenant.js +16 -32
- package/dist/store/types.d.ts +44 -119
- package/dist/store/types.js +0 -1
- package/dist/streams/control.d.ts +0 -7
- package/dist/streams/control.js +0 -13
- package/dist/streams/types.d.ts +2 -20
- package/dist/streams/types.js +1 -1
- package/dist/tenant/advance.d.ts +3 -3
- package/dist/tenant/advance.js +10 -7
- package/dist/tenant/auth.d.ts +24 -15
- package/dist/tenant/auth.js +44 -55
- package/dist/tenant/cause.d.ts +3 -3
- package/dist/tenant/cause.js +1 -1
- package/dist/tenant/commands.d.ts +2 -18
- package/dist/tenant/commands.js +38 -179
- package/dist/tenant/context.d.ts +33 -45
- package/dist/tenant/definition-files.d.ts +24 -0
- package/dist/tenant/definition-files.js +103 -0
- package/dist/tenant/effects.d.ts +20 -18
- package/dist/tenant/effects.js +59 -133
- package/dist/tenant/ephemeral.d.ts +21 -8
- package/dist/tenant/ephemeral.js +11 -12
- package/dist/tenant/host-token.js +5 -5
- package/dist/tenant/identity-file.d.ts +75 -0
- package/dist/tenant/identity-file.js +202 -0
- package/dist/tenant/issuers.d.ts +48 -0
- package/dist/tenant/issuers.js +311 -0
- package/dist/tenant/jwt.js +3 -3
- package/dist/tenant/module.d.ts +1 -4
- package/dist/tenant/module.js +3 -12
- package/dist/tenant/operator-keys.d.ts +44 -0
- package/dist/tenant/operator-keys.js +87 -0
- package/dist/tenant/outbound.d.ts +40 -1
- package/dist/tenant/outbound.js +167 -18
- package/dist/tenant/paths.d.ts +1 -1
- package/dist/tenant/paths.js +1 -3
- package/dist/tenant/principals.d.ts +13 -13
- package/dist/tenant/principals.js +35 -36
- package/dist/tenant/run-token.js +6 -6
- package/dist/tenant/runtime.d.ts +5 -3
- package/dist/tenant/runtime.js +29 -15
- package/dist/tenant/sandboxes.d.ts +9 -6
- package/dist/tenant/sandboxes.js +16 -5
- package/dist/tenant/scheduler.d.ts +1 -5
- package/dist/tenant/scheduler.js +2 -5
- package/dist/tenant/session-streams.d.ts +8 -11
- package/dist/tenant/session-streams.js +48 -32
- package/dist/tenant/session.d.ts +8 -41
- package/dist/tenant/session.js +0 -37
- package/dist/tenant/sessions.d.ts +2 -2
- package/dist/tenant/sessions.js +17 -9
- package/dist/tenant/signing-keys.d.ts +3 -2
- package/dist/tenant/signing-keys.js +5 -5
- package/dist/tenant/skill-tool.d.ts +20 -0
- package/dist/tenant/skill-tool.js +72 -0
- package/dist/tenant/slim.d.ts +1 -1
- package/dist/tenant/slim.js +1 -1
- package/dist/tenant/status.js +7 -12
- package/dist/tenant/store-pg.d.ts +15 -0
- package/dist/tenant/store-pg.js +7 -3
- package/dist/tenant/streams.d.ts +3 -11
- package/dist/tenant/streams.js +2 -29
- package/dist/tenant/sweep.js +0 -5
- package/dist/tenant/transcript.d.ts +2 -2
- package/dist/tenant/transcript.js +2 -2
- package/dist/tenant/types.d.ts +33 -19
- package/dist/tenant/worker.d.ts +1 -3
- package/dist/tenant/worker.js +3 -8
- package/dist/vault/crypto.d.ts +7 -0
- package/dist/vault/crypto.js +16 -0
- package/dist/vault/oauth.d.ts +55 -0
- package/dist/vault/oauth.js +186 -0
- package/dist/vault/service.d.ts +54 -7
- package/dist/vault/service.js +261 -17
- package/dist/vault/sources.d.ts +60 -0
- package/dist/vault/sources.js +196 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -4
- package/dist/admin-openapi.json +0 -604
- package/dist/api/http/routes/actions.d.ts +0 -8
- package/dist/api/http/routes/actions.js +0 -76
- package/dist/api/http/routes/endpoints.d.ts +0 -7
- package/dist/api/http/routes/endpoints.js +0 -100
- package/dist/host/admin-api.d.ts +0 -23
- package/dist/host/admin-api.js +0 -74
- package/dist/host/cors.d.ts +0 -27
- package/dist/host/cors.js +0 -64
- package/dist/mcp/stdio.d.ts +0 -17
- package/dist/mcp/stdio.js +0 -82
- package/dist/tenant/access-policy.d.ts +0 -30
- package/dist/tenant/access-policy.js +0 -52
- package/dist/tenant/actions.d.ts +0 -14
- package/dist/tenant/actions.js +0 -29
- package/dist/tenant/browser.d.ts +0 -15
- package/dist/tenant/browser.js +0 -39
- package/dist/tenant/delivery-token.d.ts +0 -41
- package/dist/tenant/delivery-token.js +0 -104
- package/dist/tenant/delivery.d.ts +0 -62
- package/dist/tenant/delivery.js +0 -481
- package/dist/tenant/endpoints.d.ts +0 -67
- package/dist/tenant/endpoints.js +0 -90
- package/dist/tenant/subject-limits.d.ts +0 -16
- package/dist/tenant/subject-limits.js +0 -45
- package/dist/tenant/tokens.d.ts +0 -14
- package/dist/tenant/tokens.js +0 -187
package/dist/tenant/runtime.js
CHANGED
|
@@ -5,6 +5,7 @@ import { tenantModelGate } from "../gates/in-process.js";
|
|
|
5
5
|
import { createKekFile, readVaultKek } from "../vault/kek.js";
|
|
6
6
|
import { SigningKeys } from "./signing-keys.js";
|
|
7
7
|
import { VaultService } from "../vault/service.js";
|
|
8
|
+
import { CredentialSources } from "../vault/sources.js";
|
|
8
9
|
import { McpPool } from "../mcp/pool.js";
|
|
9
10
|
import { SandboxManager } from "../sandbox/manager.js";
|
|
10
11
|
import { storeSandboxRecords } from "../sandbox/records.js";
|
|
@@ -17,10 +18,10 @@ import { closeStreams, streamsStatus, wireStreams, } from "./streams.js";
|
|
|
17
18
|
import { abortAll, abortLocal, createWorkState, drain, waitForIdle, } from "./scheduler.js";
|
|
18
19
|
import { advance } from "./advance.js";
|
|
19
20
|
import { sweep } from "./sweep.js";
|
|
20
|
-
import { deliverAction } from "./delivery.js";
|
|
21
21
|
import { TenantWorkers, WORKER_ID, } from "./worker.js";
|
|
22
22
|
import { authorize } from "./effects.js";
|
|
23
23
|
import { inProcessToolGate } from "../gates/tool-gate.js";
|
|
24
|
+
import { guardedFetch } from "./outbound.js";
|
|
24
25
|
import { inProcessKeys } from "../keys/keys.js";
|
|
25
26
|
import { tenantApi } from "../api/http/app.js";
|
|
26
27
|
import { createFsBlobStore } from "../blob/index.js";
|
|
@@ -31,6 +32,7 @@ import { localWorkspace, remoteWorkspace, withPodWorkspaces, } from "../harness-
|
|
|
31
32
|
import { hostAuthority } from "../sandbox/join.js";
|
|
32
33
|
import { reconcileSandbox } from "../sandbox/pods/reconcile.js";
|
|
33
34
|
import { sandboxWorkspaceReader } from "../artifacts/workspace.js";
|
|
35
|
+
import { readDefinitionFile } from "./definition-files.js";
|
|
34
36
|
/** Default ownership lease of an advance; the heartbeat renews it every third. */
|
|
35
37
|
const DEFAULT_OWNER_LEASE_MS = 30_000;
|
|
36
38
|
function validateConfig(config) {
|
|
@@ -79,9 +81,7 @@ export class TenantRuntime {
|
|
|
79
81
|
const paths = config.paths;
|
|
80
82
|
mkdirSync(paths.root, { recursive: true });
|
|
81
83
|
mkdirSync(paths.home, { recursive: true });
|
|
82
|
-
mkdirSync(paths.tmp, { recursive: true });
|
|
83
84
|
mkdirSync(paths.sandboxes, { recursive: true });
|
|
84
|
-
mkdirSync(paths.pluginData, { recursive: true });
|
|
85
85
|
mkdirSync(paths.logs, { recursive: true });
|
|
86
86
|
const store = hooks.store;
|
|
87
87
|
let wired;
|
|
@@ -119,11 +119,21 @@ export class TenantRuntime {
|
|
|
119
119
|
const vault = new VaultService({
|
|
120
120
|
store: opened,
|
|
121
121
|
kek: ensureKek,
|
|
122
|
-
|
|
122
|
+
// OAuth refresh and connect follow the Host's address policy (F9 C2).
|
|
123
|
+
fetch: config.vaultFetch ?? guardedFetch(config.delivery ?? {}),
|
|
124
|
+
});
|
|
125
|
+
const credentials = new CredentialSources({
|
|
126
|
+
vault,
|
|
127
|
+
...(config.resolver ? { resolver: config.resolver } : {}),
|
|
123
128
|
});
|
|
124
129
|
// `ctx` is assigned below; these callbacks only run once the Tenant is open.
|
|
125
130
|
let ctx;
|
|
126
|
-
const toolGate = hooks.toolGate ??
|
|
131
|
+
const toolGate = hooks.toolGate ??
|
|
132
|
+
inProcessToolGate(config.delivery ?? {}, {
|
|
133
|
+
session: (sessionId) => opened.tx((t) => t.get("sessions", sessionId)),
|
|
134
|
+
authorize: (sessionId, request) => authorize(ctx, sessionId, request),
|
|
135
|
+
logger: config.logger,
|
|
136
|
+
});
|
|
127
137
|
const signingKeys = new SigningKeys({ tenantId: config.tenantId, kek: ensureKek });
|
|
128
138
|
const keys = hooks.keys ?? inProcessKeys({ store: opened, vault, signingKeys, kek: ensureKek });
|
|
129
139
|
const harnessMode = hooks.harness ?? "memory";
|
|
@@ -133,9 +143,8 @@ export class TenantRuntime {
|
|
|
133
143
|
// executors; otherwise the harness holds both (F6.2).
|
|
134
144
|
const mcp = inProcess
|
|
135
145
|
? new McpPool({
|
|
136
|
-
pluginData: paths.pluginData,
|
|
137
|
-
childEnv: config.childEnv,
|
|
138
146
|
authorize: (sessionId, request) => authorize(ctx, sessionId, request),
|
|
147
|
+
policy: config.delivery ?? {},
|
|
139
148
|
...(toolGate.openMcp ? { openRemote: (server) => toolGate.openMcp(server) } : {}),
|
|
140
149
|
})
|
|
141
150
|
: undefined;
|
|
@@ -148,6 +157,12 @@ export class TenantRuntime {
|
|
|
148
157
|
defaultSandboxBackends({ root: paths.sandboxes }),
|
|
149
158
|
preference,
|
|
150
159
|
ephemeral,
|
|
160
|
+
definitionFile: async (sha256) => {
|
|
161
|
+
const bytes = await readDefinitionFile(blobs, sha256);
|
|
162
|
+
if (!bytes)
|
|
163
|
+
throw new Error(`The Object store has no bytes for ${sha256}`);
|
|
164
|
+
return bytes;
|
|
165
|
+
},
|
|
151
166
|
emit: async (sessionId, turnId, type, payload) => {
|
|
152
167
|
if (ctx.closed)
|
|
153
168
|
return;
|
|
@@ -222,8 +237,10 @@ export class TenantRuntime {
|
|
|
222
237
|
ctx = {
|
|
223
238
|
config,
|
|
224
239
|
envelope,
|
|
240
|
+
reads: hooks.reads,
|
|
225
241
|
store: opened,
|
|
226
242
|
vault,
|
|
243
|
+
credentials,
|
|
227
244
|
...(mcp ? { mcp } : {}),
|
|
228
245
|
sandbox,
|
|
229
246
|
flowLimits,
|
|
@@ -251,11 +268,6 @@ export class TenantRuntime {
|
|
|
251
268
|
await execution.wake(config.tenantId, sessionId, wake);
|
|
252
269
|
},
|
|
253
270
|
abortLocal: (sessionId, turnId) => abortLocal(ctx, sessionId, "cancel", turnId),
|
|
254
|
-
deliver: async (actionId) => {
|
|
255
|
-
if (ctx.closing || ctx.closed)
|
|
256
|
-
return;
|
|
257
|
-
await execution.deliver(config.tenantId, actionId);
|
|
258
|
-
},
|
|
259
271
|
...(hooks.pods ? { pods: hooks.pods } : {}),
|
|
260
272
|
sandboxSignal: async (sandboxId, signal) => {
|
|
261
273
|
if (ctx.closing || ctx.closed || !execution.sandbox)
|
|
@@ -295,7 +307,6 @@ export class TenantRuntime {
|
|
|
295
307
|
// sessions a previous process left runnable or running (takeover handles the rest).
|
|
296
308
|
const worker = {
|
|
297
309
|
advance: (sessionId, signal) => advance(ctx, sessionId, signal),
|
|
298
|
-
deliver: (actionId, signal) => deliverAction(ctx, actionId, signal),
|
|
299
310
|
sweep: () => sweep(ctx),
|
|
300
311
|
sandbox: (sandboxId, trigger) => reconcileSandbox(ctx, sandboxId, trigger),
|
|
301
312
|
};
|
|
@@ -313,6 +324,7 @@ export class TenantRuntime {
|
|
|
313
324
|
await detach?.().catch(() => undefined);
|
|
314
325
|
await harness?.stop().catch(() => undefined);
|
|
315
326
|
await wired?.close().catch(() => undefined);
|
|
327
|
+
await hooks.reads?.close().catch(() => undefined);
|
|
316
328
|
await store.close().catch(() => undefined);
|
|
317
329
|
throw error;
|
|
318
330
|
}
|
|
@@ -329,8 +341,6 @@ export class TenantRuntime {
|
|
|
329
341
|
return {
|
|
330
342
|
ready: !this.ctx.closing && !this.ctx.closed,
|
|
331
343
|
runningSessions: counts.runningSessions,
|
|
332
|
-
inFlightDeliveries: [...this.ctx.work.deliveries.values()].reduce((n, set) => n + set.size, 0),
|
|
333
|
-
pendingActions: counts.pendingActions,
|
|
334
344
|
uncertainEffects: counts.uncertainEffects,
|
|
335
345
|
harness: harnessStatusOf(this.ctx),
|
|
336
346
|
};
|
|
@@ -359,6 +369,9 @@ export class TenantRuntime {
|
|
|
359
369
|
attachHarness(channel, peer) {
|
|
360
370
|
return this.ctx.harness.attach(channel, peer);
|
|
361
371
|
}
|
|
372
|
+
harnessStatus() {
|
|
373
|
+
return harnessStatusOf(this.ctx);
|
|
374
|
+
}
|
|
362
375
|
async close() {
|
|
363
376
|
const ctx = this.ctx;
|
|
364
377
|
ctx.closing = true;
|
|
@@ -389,6 +402,7 @@ export class TenantRuntime {
|
|
|
389
402
|
return closeStreams(ctx);
|
|
390
403
|
},
|
|
391
404
|
],
|
|
405
|
+
["reads", () => ctx.reads?.close()],
|
|
392
406
|
["store", () => ctx.store.close()],
|
|
393
407
|
];
|
|
394
408
|
let failure;
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* sandbox's id, kind, spec and labels, and the session body names the sandbox it is attached
|
|
8
8
|
* to (`Session.sandboxId`); deleting a session (a sessions reset) only detaches it.
|
|
9
9
|
* - **Access.** An application key reaches every sandbox, and so does an application key acting
|
|
10
|
-
* for a subject (`Nylorun-Subject`), which needs `sandboxes:write` to change one. A
|
|
11
|
-
* token reaches only the ids its
|
|
12
|
-
* `sandboxes:write`; any other id is the 404 of a missing one.
|
|
10
|
+
* for a subject (`Nylorun-Subject`), which needs `sandboxes:write` to change one. A token
|
|
11
|
+
* caller (a trusted issuer's token) reaches only the ids its grants match, and changes them
|
|
12
|
+
* only with `sandboxes:write`; any other id is the 404 of a missing one.
|
|
13
13
|
* - **Serial turns.** One turn at a time per sandbox: a session whose sandbox another attached
|
|
14
14
|
* session's turn holds is refused (`409 sandbox_busy`), as the session sandbox route is
|
|
15
15
|
* refused while its session's turn runs. Commands within the workspace keep queueing in the
|
|
@@ -30,8 +30,9 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { type PutSandboxRequest, type SandboxView } from "@nylorun/core/contracts";
|
|
32
32
|
import type { SandboxResource, Tx } from "../store/types.js";
|
|
33
|
-
import type {
|
|
34
|
-
|
|
33
|
+
import type { SandboxRouteDeps } from "../core/sandbox-routes.js";
|
|
34
|
+
import { type AuthScope, type Session, type TenantContext } from "./context.js";
|
|
35
|
+
/** The sandbox grants that limit `scope`, or undefined when it reaches every sandbox. */
|
|
35
36
|
export declare function sandboxGrantsOf(scope: AuthScope): readonly string[] | undefined;
|
|
36
37
|
/** A sandbox resource, unless it is gone or being deleted. */
|
|
37
38
|
export declare function liveSandbox(t: Tx, id: string, options?: {
|
|
@@ -95,7 +96,7 @@ export declare function attachSandbox(t: Tx, id: string, grants: readonly string
|
|
|
95
96
|
export declare function recordAttachment(t: Tx, sessionId: string, sandboxId: string): Promise<void>;
|
|
96
97
|
/**
|
|
97
98
|
* Checks a turn start on a session attached to a sandbox, in the command's transaction after
|
|
98
|
-
* the session row lock: the sandbox still exists, a
|
|
99
|
+
* the session row lock: the sandbox still exists, a token caller's grants reach it, and
|
|
99
100
|
* no other session attached to it has a turn running. Holds the sandbox row's lock until the
|
|
100
101
|
* transaction ends, so two turn starts on one sandbox are decided one after the other.
|
|
101
102
|
*
|
|
@@ -117,3 +118,5 @@ export declare function touchPodSandbox(ctx: TenantContext, id: string): Promise
|
|
|
117
118
|
* timer is set). Best effort.
|
|
118
119
|
*/
|
|
119
120
|
export declare function rearmPodTimers(ctx: TenantContext): Promise<void>;
|
|
121
|
+
/** Session lookups for the sandbox route handlers (`core/sandbox-routes.ts`). */
|
|
122
|
+
export declare function sandboxRouteDeps(ctx: TenantContext): SandboxRouteDeps;
|
package/dist/tenant/sandboxes.js
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* sandbox's id, kind, spec and labels, and the session body names the sandbox it is attached
|
|
8
8
|
* to (`Session.sandboxId`); deleting a session (a sessions reset) only detaches it.
|
|
9
9
|
* - **Access.** An application key reaches every sandbox, and so does an application key acting
|
|
10
|
-
* for a subject (`Nylorun-Subject`), which needs `sandboxes:write` to change one. A
|
|
11
|
-
* token reaches only the ids its
|
|
12
|
-
* `sandboxes:write`; any other id is the 404 of a missing one.
|
|
10
|
+
* for a subject (`Nylorun-Subject`), which needs `sandboxes:write` to change one. A token
|
|
11
|
+
* caller (a trusted issuer's token) reaches only the ids its grants match, and changes them
|
|
12
|
+
* only with `sandboxes:write`; any other id is the 404 of a missing one.
|
|
13
13
|
* - **Serial turns.** One turn at a time per sandbox: a session whose sandbox another attached
|
|
14
14
|
* session's turn holds is refused (`409 sandbox_busy`), as the session sandbox route is
|
|
15
15
|
* refused while its session's turn runs. Commands within the workspace keep queueing in the
|
|
@@ -37,8 +37,9 @@ import { podName } from "../sandbox/pods/name.js";
|
|
|
37
37
|
import { expiresAtOf, podLifecycleConfig } from "../sandbox/pods/spec.js";
|
|
38
38
|
import { requirePods } from "../sandbox/placement.js";
|
|
39
39
|
import { parseSandboxDuration } from "@nylorun/core/define";
|
|
40
|
+
import { sandboxLookup, sessionOf } from "./context.js";
|
|
40
41
|
import { fail } from "./http.js";
|
|
41
|
-
/** The
|
|
42
|
+
/** The sandbox grants that limit `scope`, or undefined when it reaches every sandbox. */
|
|
42
43
|
export function sandboxGrantsOf(scope) {
|
|
43
44
|
return scope.kind === "token" ? (scope.sandboxes ?? []) : undefined;
|
|
44
45
|
}
|
|
@@ -435,7 +436,7 @@ export async function recordAttachment(t, sessionId, sandboxId) {
|
|
|
435
436
|
}
|
|
436
437
|
/**
|
|
437
438
|
* Checks a turn start on a session attached to a sandbox, in the command's transaction after
|
|
438
|
-
* the session row lock: the sandbox still exists, a
|
|
439
|
+
* the session row lock: the sandbox still exists, a token caller's grants reach it, and
|
|
439
440
|
* no other session attached to it has a turn running. Holds the sandbox row's lock until the
|
|
440
441
|
* transaction ends, so two turn starts on one sandbox are decided one after the other.
|
|
441
442
|
*
|
|
@@ -549,3 +550,13 @@ export async function rearmPodTimers(ctx) {
|
|
|
549
550
|
});
|
|
550
551
|
}
|
|
551
552
|
}
|
|
553
|
+
/** Session lookups for the sandbox route handlers (`core/sandbox-routes.ts`). */
|
|
554
|
+
export function sandboxRouteDeps(ctx) {
|
|
555
|
+
return {
|
|
556
|
+
sandbox: ctx.sandbox,
|
|
557
|
+
session: (id) => ctx.store.tx(async (t) => {
|
|
558
|
+
const session = await sessionOf(t, id);
|
|
559
|
+
return { session, lookup: await sandboxLookup(t, id) };
|
|
560
|
+
}),
|
|
561
|
+
};
|
|
562
|
+
}
|
|
@@ -5,14 +5,10 @@ export interface WorkState {
|
|
|
5
5
|
readonly running: Map<string, AbortController>;
|
|
6
6
|
/** The turn each running advance belongs to, by session id (`null`: none). */
|
|
7
7
|
readonly runningTurns: Map<string, string | null>;
|
|
8
|
-
/** Deliveries to Action endpoints in flight on this process, by their Action's session id. */
|
|
9
|
-
readonly deliveries: Map<string, Set<AbortController>>;
|
|
10
|
-
/** When each Action last reported a failed delivery (`action.delivery_failed` throttling). */
|
|
11
|
-
readonly deliveryNotices: Map<string, number>;
|
|
12
8
|
}
|
|
13
9
|
export declare function createWorkState(): WorkState;
|
|
14
10
|
/**
|
|
15
|
-
* Abort the advance of `id` if it runs on this process
|
|
11
|
+
* Abort the advance of `id` if it runs on this process.
|
|
16
12
|
* Cancel calls it after committing `cancelled`, and so does the control stream for cancels made
|
|
17
13
|
* elsewhere. With `turnId`, an advance of another turn keeps running: the signal came late.
|
|
18
14
|
*/
|
package/dist/tenant/scheduler.js
CHANGED
|
@@ -13,7 +13,7 @@ import { randomUUID } from "node:crypto";
|
|
|
13
13
|
import { command } from "./commands.js";
|
|
14
14
|
import { AdvanceAbort } from "./worker.js";
|
|
15
15
|
export function createWorkState() {
|
|
16
|
-
return { running: new Map(), runningTurns: new Map()
|
|
16
|
+
return { running: new Map(), runningTurns: new Map() };
|
|
17
17
|
}
|
|
18
18
|
const MESSAGES = {
|
|
19
19
|
cancel: "Turn cancelled",
|
|
@@ -26,7 +26,7 @@ function abortWith(controller, kind) {
|
|
|
26
26
|
controller.abort(new AdvanceAbort(kind, MESSAGES[kind]));
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Abort the advance of `id` if it runs on this process
|
|
29
|
+
* Abort the advance of `id` if it runs on this process.
|
|
30
30
|
* Cancel calls it after committing `cancelled`, and so does the control stream for cancels made
|
|
31
31
|
* elsewhere. With `turnId`, an advance of another turn keeps running: the signal came late.
|
|
32
32
|
*/
|
|
@@ -34,9 +34,6 @@ export function abortLocal(ctx, id, kind = "cancel", turnId) {
|
|
|
34
34
|
const controller = ctx.work.running.get(id);
|
|
35
35
|
if (controller && (turnId === undefined || ctx.work.runningTurns.get(id) === turnId))
|
|
36
36
|
abortWith(controller, kind);
|
|
37
|
-
// A cancel also closes the session's deliveries, which aborts the tools' `ctx.signal`.
|
|
38
|
-
for (const delivery of ctx.work.deliveries.get(id) ?? [])
|
|
39
|
-
abortWith(delivery, kind);
|
|
40
37
|
}
|
|
41
38
|
/** Reset: abort every advance running on this process; their sessions are being cleared. */
|
|
42
39
|
export function clearWork(ctx) {
|
|
@@ -20,23 +20,24 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
22
22
|
import type { LiveEvent } from "@nylorun/core/contracts";
|
|
23
|
-
import type { TenantContext } from "./context.js";
|
|
23
|
+
import type { AuthScope, TenantContext } from "./context.js";
|
|
24
24
|
import type { StreamsWiring } from "./streams.js";
|
|
25
|
-
/** Why the Runtime ended a stream a
|
|
26
|
-
export type StreamEndReason = "token_expired"
|
|
25
|
+
/** Why the Runtime ended a stream a token opened. */
|
|
26
|
+
export type StreamEndReason = "token_expired";
|
|
27
27
|
/** Where an observer's events go: an SSE response, or an in-process reader. */
|
|
28
28
|
export interface ObserverSink {
|
|
29
29
|
write(event: LiveEvent): void;
|
|
30
30
|
/** Ends the stream; with a reason, the client is told why before it ends. */
|
|
31
31
|
end(reason?: StreamEndReason): void;
|
|
32
32
|
}
|
|
33
|
-
/** The
|
|
33
|
+
/** The token a stream was opened with (a trusted issuer's): the stream ends at its expiry. */
|
|
34
34
|
export interface StreamHolder {
|
|
35
35
|
readonly subject: string;
|
|
36
|
-
readonly epoch: number;
|
|
37
36
|
/** Epoch ms when the token expires. */
|
|
38
37
|
readonly expiresAt: number;
|
|
39
38
|
}
|
|
39
|
+
/** The holder a stream opened with `scope` records: token callers only. */
|
|
40
|
+
export declare function streamHolderOf(scope: AuthScope): StreamHolder | undefined;
|
|
40
41
|
/** One client of a session: the next sequence it needs. */
|
|
41
42
|
interface Observer {
|
|
42
43
|
readonly sink: ObserverSink;
|
|
@@ -78,9 +79,10 @@ export declare function currentBasin(ctx: TenantContext): string;
|
|
|
78
79
|
* read starts. The cursor returned is the last record read (the request's cursor when none
|
|
79
80
|
* was), whatever the `agent` filter kept.
|
|
80
81
|
*/
|
|
81
|
-
export declare function readHistory(ctx: TenantContext, sessionId: string, cursor: string | undefined, agent: string | undefined): Promise<{
|
|
82
|
+
export declare function readHistory(ctx: TenantContext, sessionId: string, cursor: string | undefined, agent: string | undefined, limit?: number): Promise<{
|
|
82
83
|
items: LiveEvent[];
|
|
83
84
|
cursor: string | null;
|
|
85
|
+
tail?: boolean;
|
|
84
86
|
}>;
|
|
85
87
|
/**
|
|
86
88
|
* `GET /v1/sessions/:id/events`: joins the session's shared read at the client's cursor and
|
|
@@ -114,11 +116,6 @@ export declare function served(event: LiveEvent): boolean;
|
|
|
114
116
|
* the Tenant end too.
|
|
115
117
|
*/
|
|
116
118
|
export declare function checkSessionStreams(ctx: TenantContext): Promise<void>;
|
|
117
|
-
/**
|
|
118
|
-
* Ends the streams of `subject` opened with a token older than `epoch` (a revocation), on
|
|
119
|
-
* this process. Other processes do the same on the `subject.revoked` signal.
|
|
120
|
-
*/
|
|
121
|
-
export declare function endSubjectStreams(hub: SessionStreams, subject: string, epoch: number): void;
|
|
122
119
|
/** Reset or close: end every session observer and stop every shared read. */
|
|
123
120
|
export declare function clearObservers(hub: SessionStreams): void;
|
|
124
121
|
/** Close: end every session observer. */
|
|
@@ -1,7 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live delivery over Durable Streams (architecture §12.4, "Reading"): session history
|
|
3
|
+
* (`GET /v1/sessions/:id/items`) and session SSE (`GET /v1/sessions/:id/events`).
|
|
4
|
+
*
|
|
5
|
+
* - **Streams.** A session's events are in `sessions/<id>` in the Tenant's current basin
|
|
6
|
+
* generation (`currentBasin`); cursors carry only the session id and sequence.
|
|
7
|
+
* - **History** reads the session's stream from the cursor up to the tail seen when the read
|
|
8
|
+
* starts. The `agent` filter runs here, and the response cursor is the last record read. If
|
|
9
|
+
* the streams fail, history answers `503`.
|
|
10
|
+
* - **SSE** shares one stream read per observed session in this process (a `SessionStream`)
|
|
11
|
+
* among that session's observers. Each observer keeps the next sequence it needs and skips
|
|
12
|
+
* what it already has, so a client resuming from `Last-Event-ID` sees no gap and no
|
|
13
|
+
* duplicate. An observer behind the feed restarts the shared read from its own position.
|
|
14
|
+
* A feed follows one basin generation: it ends once its session is gone or the Tenant moved
|
|
15
|
+
* to a new generation (a reset, possibly on another node), checked when a client joins, when
|
|
16
|
+
* its read fails, on a `sessions.reset` signal, and periodically (`checkSessionStreams`).
|
|
17
|
+
*
|
|
18
|
+
* Business code never writes here: events reach streams only through the stream relay, from
|
|
19
|
+
* the record, after commit.
|
|
20
|
+
*/
|
|
21
|
+
import { historyCursor, historyResume } from "../reads/cursor.js";
|
|
1
22
|
import { decodeCursor, encodeCursor } from "../record/index.js";
|
|
2
23
|
import { basinOf } from "../streams/basin.js";
|
|
3
24
|
import { sessionStream, } from "../streams/types.js";
|
|
4
25
|
import { fail } from "./http.js";
|
|
26
|
+
/** The holder a stream opened with `scope` records: token callers only. */
|
|
27
|
+
export function streamHolderOf(scope) {
|
|
28
|
+
if (scope.kind !== "token")
|
|
29
|
+
return undefined;
|
|
30
|
+
return { subject: scope.subject, expiresAt: scope.expiresAt };
|
|
31
|
+
}
|
|
5
32
|
export function createSessionStreams() {
|
|
6
33
|
return { wiring: undefined, generation: 0, sessions: new Map() };
|
|
7
34
|
}
|
|
@@ -79,17 +106,27 @@ function streamsOf(ctx) {
|
|
|
79
106
|
* read starts. The cursor returned is the last record read (the request's cursor when none
|
|
80
107
|
* was), whatever the `agent` filter kept.
|
|
81
108
|
*/
|
|
82
|
-
export async function readHistory(ctx, sessionId, cursor, agent) {
|
|
83
|
-
const
|
|
109
|
+
export async function readHistory(ctx, sessionId, cursor, agent, limit) {
|
|
110
|
+
const codec = limit === undefined ? undefined : historyCursor(ctx.config.tenantId, sessionId, agent);
|
|
111
|
+
const from = startSeq(sessionId, codec ? codec.decode(cursor) : historyResume(ctx.config.tenantId, sessionId, cursor));
|
|
84
112
|
const streams = streamsOf(ctx);
|
|
85
113
|
const ref = (await currentStream(ctx, sessionId)) ?? fail(404, "Session not found");
|
|
86
114
|
const items = [];
|
|
87
115
|
let last;
|
|
116
|
+
let atTail = true;
|
|
117
|
+
let examined = 0;
|
|
88
118
|
try {
|
|
119
|
+
const tail = limit === undefined ? undefined : await streams.tail(ref.basin, ref.stream);
|
|
89
120
|
for await (const record of streams.read(ref.basin, ref.stream, from, { follow: false })) {
|
|
121
|
+
if (tail !== undefined && record.seq >= tail)
|
|
122
|
+
break;
|
|
90
123
|
last = record.seq;
|
|
91
124
|
if (served(record.body) && (agent === undefined || belongsTo(record.body, agent)))
|
|
92
125
|
items.push(record.body);
|
|
126
|
+
if (limit !== undefined && ++examined >= limit) {
|
|
127
|
+
atTail = last >= tail - 1;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
93
130
|
}
|
|
94
131
|
}
|
|
95
132
|
catch (error) {
|
|
@@ -101,7 +138,10 @@ export async function readHistory(ctx, sessionId, cursor, agent) {
|
|
|
101
138
|
}
|
|
102
139
|
return {
|
|
103
140
|
items,
|
|
104
|
-
|
|
141
|
+
...(limit === undefined ? {} : { tail: atTail }),
|
|
142
|
+
cursor: last !== undefined
|
|
143
|
+
? (codec ? codec.encode(encodeCursor(sessionId, last)) : encodeCursor(sessionId, last))
|
|
144
|
+
: cursor ?? null,
|
|
105
145
|
};
|
|
106
146
|
}
|
|
107
147
|
/**
|
|
@@ -111,7 +151,7 @@ export async function readHistory(ctx, sessionId, cursor, agent) {
|
|
|
111
151
|
export async function streamSessionEvents(ctx, request, response, sessionId, cursor, holder) {
|
|
112
152
|
const observer = {
|
|
113
153
|
sink: sseSink(response),
|
|
114
|
-
next: startSeq(sessionId, cursor),
|
|
154
|
+
next: startSeq(sessionId, historyResume(ctx.config.tenantId, sessionId, cursor)),
|
|
115
155
|
...(holder ? { holder } : {}),
|
|
116
156
|
};
|
|
117
157
|
const joined = await join(ctx, sessionId, observer);
|
|
@@ -156,7 +196,7 @@ export async function* observeSession(ctx, sessionId, cursor, options) {
|
|
|
156
196
|
notify();
|
|
157
197
|
},
|
|
158
198
|
},
|
|
159
|
-
next: startSeq(sessionId, cursor),
|
|
199
|
+
next: startSeq(sessionId, historyResume(ctx.config.tenantId, sessionId, cursor)),
|
|
160
200
|
...(options.holder ? { holder: options.holder } : {}),
|
|
161
201
|
};
|
|
162
202
|
const joined = await join(ctx, sessionId, observer);
|
|
@@ -233,7 +273,7 @@ async function join(ctx, sessionId, observer) {
|
|
|
233
273
|
feed.observers.add(observer);
|
|
234
274
|
return feed;
|
|
235
275
|
}
|
|
236
|
-
/** Ends one observer early (its token expired
|
|
276
|
+
/** Ends one observer early (its token expired). */
|
|
237
277
|
function endObserver(hub, feed, observer, reason) {
|
|
238
278
|
if (!feed.observers.has(observer))
|
|
239
279
|
return;
|
|
@@ -328,24 +368,12 @@ async function stillCurrent(ctx, feed) {
|
|
|
328
368
|
*/
|
|
329
369
|
export async function checkSessionStreams(ctx) {
|
|
330
370
|
const feeds = [...ctx.sessionStreams.sessions.values()];
|
|
331
|
-
|
|
332
|
-
const subjects = new Set();
|
|
333
|
-
for (const feed of feeds)
|
|
334
|
-
for (const observer of feed.observers)
|
|
335
|
-
if (observer.holder)
|
|
336
|
-
subjects.add(observer.holder.subject);
|
|
337
|
-
const { exists, epochs, generation } = await ctx.store.tx(async (t) => {
|
|
371
|
+
const { exists, generation } = await ctx.store.tx(async (t) => {
|
|
338
372
|
const exists = new Set();
|
|
339
373
|
for (const feed of feeds)
|
|
340
374
|
if (await t.get("sessions", feed.sessionId))
|
|
341
375
|
exists.add(feed.sessionId);
|
|
342
|
-
return {
|
|
343
|
-
exists,
|
|
344
|
-
generation: (await t.basinGenerations()).current,
|
|
345
|
-
epochs: subjects.size === 0
|
|
346
|
-
? new Map()
|
|
347
|
-
: await t.subjectEpochs([...subjects]),
|
|
348
|
-
};
|
|
376
|
+
return { exists, generation: (await t.basinGenerations()).current };
|
|
349
377
|
});
|
|
350
378
|
if (generation !== ctx.sessionStreams.generation)
|
|
351
379
|
ctx.sessionStreams.wiring?.moveTo(generation);
|
|
@@ -355,18 +383,6 @@ export async function checkSessionStreams(ctx) {
|
|
|
355
383
|
? { basin: currentBasin(ctx), stream: sessionStream(feed.sessionId) }
|
|
356
384
|
: undefined))
|
|
357
385
|
endFeed(ctx.sessionStreams, feed);
|
|
358
|
-
for (const [subject, epoch] of epochs)
|
|
359
|
-
endSubjectStreams(ctx.sessionStreams, subject, epoch);
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Ends the streams of `subject` opened with a token older than `epoch` (a revocation), on
|
|
363
|
-
* this process. Other processes do the same on the `subject.revoked` signal.
|
|
364
|
-
*/
|
|
365
|
-
export function endSubjectStreams(hub, subject, epoch) {
|
|
366
|
-
for (const feed of [...hub.sessions.values()])
|
|
367
|
-
for (const observer of [...feed.observers])
|
|
368
|
-
if (observer.holder?.subject === subject && observer.holder.epoch < epoch)
|
|
369
|
-
endObserver(hub, feed, observer, "revoked");
|
|
370
386
|
}
|
|
371
387
|
function endFeed(hub, feed) {
|
|
372
388
|
feed.read.abort();
|
package/dist/tenant/session.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers over the session document: turn-manifest pins and variants, and state rebasing.
|
|
3
|
+
* No store access and no I/O. (The tools of an MCP snapshot
|
|
4
|
+
* live in `mcp/snapshot.ts`.)
|
|
5
|
+
*
|
|
6
|
+
* Later waves: stable; the async store conversion (Wave 1 / A) does not change these.
|
|
7
|
+
*/
|
|
8
|
+
import type { AgentManifest } from "@nylorun/core/define";
|
|
3
9
|
import { type TurnManifestStore } from "../core/turn-manifest.js";
|
|
4
10
|
import type { Session } from "./context.js";
|
|
5
11
|
export { manifestFor, sessionToolsOf } from "../mcp/snapshot.js";
|
|
@@ -7,43 +13,4 @@ export { manifestFor, sessionToolsOf } from "../mcp/snapshot.js";
|
|
|
7
13
|
export declare function variantStore(session: Session): TurnManifestStore;
|
|
8
14
|
/** Manifest this turn's checkpoint is pinned to (session pin or a stored variant). */
|
|
9
15
|
export declare function turnManifestOf(session: Session): AgentManifest;
|
|
10
|
-
/** Wrap a linked agent turn so the Loop learns the turn's manifest (SD-I4 pin stays on session). */
|
|
11
|
-
export declare function linkedAgentOutput(session: Session, output: JsonValue | undefined): JsonValue;
|
|
12
16
|
export declare function rebaseSessionState(session: Session, turnHash: string): void;
|
|
13
|
-
export declare function pinnedTool(manifest: AgentManifest, capabilityId?: string, toolName?: string): import("@nylorun/core/define").ToolManifest | undefined;
|
|
14
|
-
/** What an action runs, for events: a tool name, or a hook point and its capabilities. */
|
|
15
|
-
export declare function actionTarget(action: Action): {
|
|
16
|
-
hook: {
|
|
17
|
-
at: "after" | "before";
|
|
18
|
-
scope: "step" | "turn";
|
|
19
|
-
capabilityIds: string[];
|
|
20
|
-
};
|
|
21
|
-
agent?: {
|
|
22
|
-
id: string;
|
|
23
|
-
path: string;
|
|
24
|
-
delegationId?: string | undefined;
|
|
25
|
-
} | undefined;
|
|
26
|
-
} | {
|
|
27
|
-
toolName: string;
|
|
28
|
-
agent?: {
|
|
29
|
-
id: string;
|
|
30
|
-
path: string;
|
|
31
|
-
delegationId?: string | undefined;
|
|
32
|
-
} | undefined;
|
|
33
|
-
} | {
|
|
34
|
-
path: string;
|
|
35
|
-
key: string;
|
|
36
|
-
agent?: {
|
|
37
|
-
id: string;
|
|
38
|
-
path: string;
|
|
39
|
-
delegationId?: string | undefined;
|
|
40
|
-
} | {
|
|
41
|
-
id: string;
|
|
42
|
-
path: string;
|
|
43
|
-
delegationId?: string | undefined;
|
|
44
|
-
} | {
|
|
45
|
-
id: string;
|
|
46
|
-
path: string;
|
|
47
|
-
delegationId?: string | undefined;
|
|
48
|
-
} | undefined;
|
|
49
|
-
};
|
package/dist/tenant/session.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure helpers over the session document: turn-manifest pins and variants, state rebasing,
|
|
3
|
-
* and the event target of an Action. No store access and no I/O. (The tools of an MCP snapshot
|
|
4
|
-
* live in `mcp/snapshot.ts`.)
|
|
5
|
-
*
|
|
6
|
-
* Later waves: stable; the async store conversion (Wave 1 / A) does not change these.
|
|
7
|
-
*/
|
|
8
|
-
import { agentTurnValue } from "@nylorun/harness/run";
|
|
9
|
-
import { isWorkflowManifest } from "../core/flow-host.js";
|
|
10
1
|
import { allowedManifestHashes, rebaseTurnState, } from "../core/turn-manifest.js";
|
|
11
2
|
export { manifestFor, sessionToolsOf } from "../mcp/snapshot.js";
|
|
12
3
|
/** Turn-manifest store backed by the session's `variants` map (no schema change). */
|
|
@@ -27,12 +18,6 @@ export function turnManifestOf(session) {
|
|
|
27
18
|
return session.manifest;
|
|
28
19
|
return session.variants?.[hash] ?? session.manifest;
|
|
29
20
|
}
|
|
30
|
-
/** Wrap a linked agent turn so the Loop learns the turn's manifest (SD-I4 pin stays on session). */
|
|
31
|
-
export function linkedAgentOutput(session, output) {
|
|
32
|
-
if (isWorkflowManifest(session.manifest))
|
|
33
|
-
return output ?? null;
|
|
34
|
-
return agentTurnValue(output ?? null, turnManifestOf(session));
|
|
35
|
-
}
|
|
36
21
|
export function rebaseSessionState(session, turnHash) {
|
|
37
22
|
const allowed = allowedManifestHashes({
|
|
38
23
|
pinnedHash: session.manifestHash,
|
|
@@ -46,25 +31,3 @@ export function rebaseSessionState(session, turnHash) {
|
|
|
46
31
|
if (next !== session.state)
|
|
47
32
|
session.state = next;
|
|
48
33
|
}
|
|
49
|
-
export function pinnedTool(manifest, capabilityId, toolName) {
|
|
50
|
-
const capability = manifest.capabilities.find((item) => item.id === capabilityId);
|
|
51
|
-
return capability?.tools?.find((tool) => tool.name === toolName);
|
|
52
|
-
}
|
|
53
|
-
/** What an action runs, for events: a tool name, or a hook point and its capabilities. */
|
|
54
|
-
export function actionTarget(action) {
|
|
55
|
-
if (action.kind === "hook")
|
|
56
|
-
return {
|
|
57
|
-
hook: action.hook,
|
|
58
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
59
|
-
};
|
|
60
|
-
if (action.kind === "tool" && "toolName" in action)
|
|
61
|
-
return {
|
|
62
|
-
toolName: action.toolName,
|
|
63
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
64
|
-
};
|
|
65
|
-
return {
|
|
66
|
-
path: action.path,
|
|
67
|
-
key: action.key,
|
|
68
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
69
|
-
};
|
|
70
|
-
}
|
|
@@ -15,7 +15,7 @@ export declare function listDefinitions(ctx: TenantContext): Promise<{
|
|
|
15
15
|
}[];
|
|
16
16
|
}>;
|
|
17
17
|
/**
|
|
18
|
-
* The agents a
|
|
18
|
+
* The agents a token caller may see: id, name and description only, never
|
|
19
19
|
* instructions, tools or MCP servers, and only the agents allowed.
|
|
20
20
|
*/
|
|
21
21
|
export declare function listAgentsPublic(ctx: TenantContext, agents: ReadonlySet<string> | "*"): Promise<{
|
|
@@ -60,7 +60,7 @@ export declare function putSession(ctx: TenantContext, id: string, body: PutSess
|
|
|
60
60
|
*/
|
|
61
61
|
createOnly?: boolean;
|
|
62
62
|
/**
|
|
63
|
-
* The sandboxes the caller reaches (a
|
|
63
|
+
* The sandboxes the caller reaches (a token caller's grants, `sandboxGrantsOf`); undefined
|
|
64
64
|
* reaches every one. `sandbox: { id }` must name one of them.
|
|
65
65
|
*/
|
|
66
66
|
sandboxGrants?: readonly string[];
|