@nylorun/runtime 0.23.0-beta → 0.24.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +148 -0
- package/README.md +79 -28
- package/dist/adapters/execution/restate.js +1 -1
- package/dist/adapters/replication/pgoutput.d.ts +2 -0
- package/dist/adapters/replication/pgoutput.js +6 -3
- package/dist/adapters/sandbox/local.d.ts +9 -1
- package/dist/adapters/sandbox/local.js +16 -4
- package/dist/adapters/sandbox/virtual.js +4 -1
- package/dist/api/a2a/endpoint.js +5 -1
- package/dist/api/a2a/routes.d.ts +2 -0
- package/dist/api/a2a/routes.js +2 -2
- package/dist/api/a2a/tasks.js +2 -1
- package/dist/api/ag-ui/endpoint.js +4 -2
- package/dist/api/ag-ui/history.js +4 -1
- package/dist/api/ag-ui/routes.d.ts +4 -1
- package/dist/api/ag-ui/routes.js +11 -10
- package/dist/api/ag-ui/translate.js +3 -2
- package/dist/api/components.d.ts +4953 -1204
- package/dist/api/components.js +25 -16
- package/dist/api/gate/keys.js +7 -1
- package/dist/api/gate/routes.d.ts +6 -0
- package/dist/api/gate/routes.js +39 -3
- package/dist/api/http/app.js +4 -4
- package/dist/api/http/define.d.ts +6 -0
- package/dist/api/http/define.js +13 -1
- package/dist/api/http/respond.js +1 -1
- package/dist/api/http/routes/artifacts.js +35 -8
- package/dist/api/http/routes/coverage.d.ts +9 -0
- package/dist/api/http/routes/coverage.js +34 -0
- package/dist/api/http/routes/environments.d.ts +11 -0
- package/dist/api/http/routes/environments.js +283 -0
- package/dist/api/http/routes/mcp.d.ts +1 -1
- package/dist/api/http/routes/mcp.js +2 -2
- package/dist/api/http/routes/me.js +1 -1
- package/dist/api/http/routes/reads.d.ts +45 -9
- package/dist/api/http/routes/reads.js +54 -5
- package/dist/api/http/routes/sessions.js +11 -6
- package/dist/api/http/routes/tenant.js +32 -10
- package/dist/api/openapi.js +31 -26
- package/dist/artifacts/disk.d.ts +59 -0
- package/dist/artifacts/disk.js +563 -0
- package/dist/artifacts/export.d.ts +1 -1
- package/dist/artifacts/export.js +2 -3
- package/dist/artifacts/folders.d.ts +6 -3
- package/dist/artifacts/folders.js +17 -12
- package/dist/artifacts/service.d.ts +2 -1
- package/dist/artifacts/service.js +6 -1
- package/dist/artifacts/workspace.d.ts +1 -1
- package/dist/artifacts/workspace.js +1 -1
- package/dist/core/flow-host.d.ts +2 -3
- package/dist/core/flow-host.js +3 -0
- package/dist/core/provider.d.ts +3 -2
- package/dist/core/provider.js +5 -37
- package/dist/core/sandbox-routes.d.ts +2 -21
- package/dist/core/sandbox-routes.js +10 -43
- package/dist/execution/types.d.ts +1 -1
- package/dist/gates/contract.d.ts +3 -24
- package/dist/gates/contract.js +1 -36
- package/dist/gates/egress-credentials.d.ts +9 -0
- package/dist/gates/egress-credentials.js +11 -4
- package/dist/gates/egress.d.ts +28 -1
- package/dist/gates/egress.js +115 -10
- package/dist/gates/fixture-model.d.ts +28 -0
- package/dist/gates/fixture-model.js +92 -0
- package/dist/gates/handler.js +4 -4
- package/dist/gates/http-tool.d.ts +6 -2
- package/dist/gates/http-tool.js +3 -5
- package/dist/gates/in-process.d.ts +5 -0
- package/dist/gates/in-process.js +12 -1
- package/dist/gates/journal.d.ts +30 -0
- package/dist/gates/journal.js +52 -0
- package/dist/gates/mcp-handler.d.ts +4 -0
- package/dist/gates/mcp-handler.js +5 -1
- package/dist/gates/meter.d.ts +10 -2
- package/dist/gates/meter.js +20 -5
- package/dist/gates/policy.d.ts +49 -0
- package/dist/gates/policy.js +134 -0
- package/dist/gates/tenant-vaults.d.ts +7 -7
- package/dist/gates/tenant-vaults.js +5 -5
- package/dist/gates/tool-calls.d.ts +10 -5
- package/dist/gates/tool-calls.js +28 -10
- package/dist/gates/tool-client.d.ts +8 -0
- package/dist/gates/tool-client.js +27 -11
- package/dist/gates/tool-contract.d.ts +10 -68
- package/dist/gates/tool-contract.js +1 -85
- package/dist/gates/tool-gate.d.ts +1 -1
- package/dist/harness/calls.d.ts +12 -5
- package/dist/harness/calls.js +21 -12
- package/dist/harness/executors.js +12 -9
- package/dist/harness/main.js +18 -5
- package/dist/harness/pod.d.ts +34 -0
- package/dist/harness/pod.js +41 -0
- package/dist/harness/service.d.ts +0 -1
- package/dist/harness/service.js +13 -5
- package/dist/harness/setup.d.ts +27 -0
- package/dist/harness/setup.js +150 -0
- package/dist/harness/ws-client.js +3 -2
- package/dist/harness/ws-port.d.ts +1 -5
- package/dist/harness/ws-port.js +1 -5
- package/dist/harness-api/in-process.js +3 -3
- package/dist/harness-api/record.d.ts +15 -1
- package/dist/harness-api/record.js +174 -44
- package/dist/harness-api/redact.d.ts +3 -0
- package/dist/harness-api/redact.js +45 -0
- package/dist/harness-api/server.d.ts +8 -0
- package/dist/harness-api/server.js +93 -13
- package/dist/harness-api/start.d.ts +10 -3
- package/dist/harness-api/start.js +40 -10
- package/dist/harness-api/tool-journal.d.ts +96 -0
- package/dist/harness-api/tool-journal.js +102 -0
- package/dist/harness-api/tool-status.d.ts +13 -0
- package/dist/harness-api/tool-status.js +26 -0
- package/dist/harness-api/workspace.d.ts +6 -3
- package/dist/harness-api/workspace.js +27 -11
- package/dist/harness-api/ws-server.d.ts +11 -3
- package/dist/harness-api/ws-server.js +94 -15
- package/dist/host/gates.d.ts +2 -1
- package/dist/host/gates.js +10 -2
- package/dist/host/main.js +54 -5
- package/dist/host/operate.js +67 -5
- package/dist/host/stack-config.d.ts +64 -0
- package/dist/host/stack-config.js +61 -1
- package/dist/keys/client.js +4 -1
- package/dist/keys/keys.d.ts +5 -5
- package/dist/keys/keys.js +5 -7
- package/dist/management-openapi.json +999 -2211
- package/dist/mcp/connect.d.ts +25 -20
- package/dist/mcp/connect.js +29 -30
- package/dist/mcp/pool.d.ts +2 -2
- package/dist/mcp/pool.js +1 -1
- package/dist/mcp/preview.d.ts +3 -3
- package/dist/mcp/preview.js +10 -20
- package/dist/mcp/snapshot.d.ts +5 -11
- package/dist/mcp/snapshot.js +6 -7
- package/dist/model/pi-model.js +8 -0
- package/dist/openapi.json +6955 -2526
- package/dist/reads/types.d.ts +16 -3
- package/dist/record/append.d.ts +3 -1
- package/dist/record/append.js +1 -0
- package/dist/record/envelope.d.ts +5 -1
- package/dist/record/envelope.js +7 -3
- package/dist/record/environment.d.ts +25 -0
- package/dist/record/environment.js +44 -0
- package/dist/record/index.d.ts +1 -1
- package/dist/record/index.js +1 -1
- package/dist/sandbox/disk-fs.d.ts +95 -0
- package/dist/sandbox/disk-fs.js +206 -0
- package/dist/sandbox/join.d.ts +17 -18
- package/dist/sandbox/join.js +42 -15
- package/dist/sandbox/manager.d.ts +16 -8
- package/dist/sandbox/manager.js +33 -17
- package/dist/sandbox/placement.d.ts +13 -12
- package/dist/sandbox/placement.js +29 -12
- package/dist/sandbox/pods/client.d.ts +6 -1
- package/dist/sandbox/pods/lifecycle.d.ts +28 -27
- package/dist/sandbox/pods/lifecycle.js +14 -26
- package/dist/sandbox/pods/reconcile.js +18 -12
- package/dist/sandbox/pods/spec.d.ts +15 -13
- package/dist/sandbox/pods/spec.js +16 -20
- package/dist/sandbox/records.d.ts +2 -2
- package/dist/sandbox/records.js +3 -3
- package/dist/sandbox/resolve.d.ts +35 -27
- package/dist/sandbox/resolve.js +66 -41
- package/dist/sandbox/session-sandbox.js +1 -1
- package/dist/sandbox/setup.d.ts +61 -0
- package/dist/sandbox/setup.js +123 -0
- package/dist/sandbox/share.d.ts +11 -21
- package/dist/sandbox/share.js +12 -41
- package/dist/sandbox/tenant-config.d.ts +12 -14
- package/dist/sandbox/tenant-config.js +12 -17
- package/dist/sandbox/types.d.ts +6 -0
- package/dist/store/postgres/drizzle/0020_environments.sql +63 -0
- package/dist/store/postgres/drizzle/0021_disk_versions.sql +7 -0
- package/dist/store/postgres/drizzle/0022_model_usage_timing.sql +5 -0
- package/dist/store/postgres/drizzle/0023_artifact_pages.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/reads.js +117 -17
- package/dist/store/postgres/record-writer.d.ts +4 -4
- package/dist/store/postgres/record-writer.js +9 -9
- package/dist/store/postgres/record.d.ts +7 -0
- package/dist/store/postgres/record.js +23 -2
- package/dist/store/postgres/schema.d.ts +934 -761
- package/dist/store/postgres/schema.js +102 -73
- package/dist/store/postgres/store.js +119 -66
- package/dist/store/types.d.ts +109 -48
- package/dist/tenant/advance.d.ts +7 -6
- package/dist/tenant/advance.js +115 -42
- package/dist/tenant/artifact-tool.js +3 -4
- package/dist/tenant/commands.d.ts +15 -2
- package/dist/tenant/commands.js +93 -12
- package/dist/tenant/context.d.ts +48 -22
- package/dist/tenant/context.js +4 -15
- package/dist/tenant/effects.d.ts +1 -1
- package/dist/tenant/effects.js +37 -20
- package/dist/tenant/environments.d.ts +167 -0
- package/dist/tenant/environments.js +823 -0
- package/dist/tenant/harness-tokens.d.ts +21 -0
- package/dist/tenant/harness-tokens.js +61 -0
- package/dist/tenant/host-token.d.ts +1 -1
- package/dist/tenant/host-token.js +2 -4
- package/dist/tenant/identity-file.d.ts +4 -4
- package/dist/tenant/identity-file.js +17 -8
- package/dist/tenant/issuers.js +3 -3
- package/dist/tenant/principals.js +1 -1
- package/dist/tenant/reset.js +3 -3
- package/dist/tenant/runtime.d.ts +6 -1
- package/dist/tenant/runtime.js +7 -1
- package/dist/tenant/session.d.ts +3 -3
- package/dist/tenant/session.js +0 -14
- package/dist/tenant/sessions.d.ts +13 -13
- package/dist/tenant/sessions.js +61 -138
- package/dist/tenant/signing-keys.d.ts +5 -1
- package/dist/tenant/status.js +3 -3
- package/dist/tenant/sweep.js +12 -6
- package/dist/tenant/transcript.d.ts +210 -20
- package/dist/tenant/transcript.js +62 -11
- package/dist/tenant/turn-timing.d.ts +43 -0
- package/dist/tenant/turn-timing.js +39 -0
- package/dist/tenant/types.d.ts +2 -0
- package/dist/traces/ids.d.ts +42 -0
- package/dist/traces/ids.js +85 -0
- package/dist/traces/key.d.ts +6 -0
- package/dist/traces/key.js +37 -0
- package/dist/traces/map.d.ts +113 -0
- package/dist/traces/map.js +317 -0
- package/dist/traces/options.d.ts +7 -0
- package/dist/traces/options.js +1 -0
- package/dist/traces/otlp.d.ts +42 -0
- package/dist/traces/otlp.js +84 -0
- package/dist/traces/projector.d.ts +58 -0
- package/dist/traces/projector.js +200 -0
- package/dist/traces/read.d.ts +23 -0
- package/dist/traces/read.js +16 -0
- package/dist/vault/coverage.d.ts +26 -0
- package/dist/vault/coverage.js +64 -0
- package/dist/vault/error.d.ts +11 -1
- package/dist/vault/error.js +5 -1
- package/dist/vault/service.d.ts +47 -48
- package/dist/vault/service.js +321 -382
- package/dist/vault/sources.d.ts +5 -16
- package/dist/vault/sources.js +6 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/package.json +13 -13
- package/dist/api/http/routes/sandboxes.d.ts +0 -9
- package/dist/api/http/routes/sandboxes.js +0 -153
- package/dist/api/http/routes/vaults.d.ts +0 -10
- package/dist/api/http/routes/vaults.js +0 -139
- package/dist/record/sandbox.d.ts +0 -25
- package/dist/record/sandbox.js +0 -43
- package/dist/tenant/sandboxes.d.ts +0 -123
- package/dist/tenant/sandboxes.js +0 -566
package/dist/tenant/context.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ import type { SessionHistory } from "./history.js";
|
|
|
18
18
|
import type { IssuerScope, SubjectScope, TenantEnvelope } from "@nylorun/core/contracts";
|
|
19
19
|
import type { DurableCheckpoint, FlowCheckpoint } from "@nylorun/harness/run";
|
|
20
20
|
import type { AgentManifest, JsonValue, SandboxManifest } from "@nylorun/core/define";
|
|
21
|
-
import type { CredentialSelection } from "@nylorun/core/contracts";
|
|
22
21
|
import type { OutboxRequest, SessionStore, Tx } from "../store/types.js";
|
|
23
22
|
import type { FlowLimits } from "../core/limits.js";
|
|
24
23
|
import type { ModelProvider } from "../core/provider.js";
|
|
@@ -40,6 +39,8 @@ import type { SigningKeys } from "./signing-keys.js";
|
|
|
40
39
|
import type { BlobStore } from "../blob/index.js";
|
|
41
40
|
import type { WorkspaceReader } from "../artifacts/workspace.js";
|
|
42
41
|
import type { RunGrants } from "./run-grants.js";
|
|
42
|
+
import type { TraceOptions } from "../traces/options.js";
|
|
43
|
+
import type { TraceContext } from "../traces/ids.js";
|
|
43
44
|
export interface Session {
|
|
44
45
|
id: string;
|
|
45
46
|
agentId: string;
|
|
@@ -74,26 +75,49 @@ export interface Session {
|
|
|
74
75
|
* turn it started (`linkedTurnEnd` in `core/flow-host.ts`).
|
|
75
76
|
*/
|
|
76
77
|
lastTurnId?: string;
|
|
78
|
+
/** When the active turn started (R7.1, `turn-timing.ts`); absent on a turn started before. */
|
|
79
|
+
turnStartedAt?: string;
|
|
80
|
+
/** How long the active turn has waited paused for a person, in ms (R7.1). */
|
|
81
|
+
pausedMs?: number;
|
|
82
|
+
/** Since when the active turn waits paused (R7.1); absent while it runs. */
|
|
83
|
+
pausedAt?: string;
|
|
84
|
+
/**
|
|
85
|
+
* The trace context the active turn's message arrived with (R7.4): its trace is the caller's,
|
|
86
|
+
* and the context core hands on (to the harness, tools and sandbox commands) is in it.
|
|
87
|
+
*/
|
|
88
|
+
turnTrace?: TraceContext;
|
|
77
89
|
creation: unknown;
|
|
78
|
-
vaultIds?: readonly string[];
|
|
79
|
-
credentialSelections?: readonly CredentialSelection[];
|
|
80
90
|
mcpSnapshot?: McpSnapshot;
|
|
81
91
|
mcpDiagnostics?: readonly McpDiagnostic[];
|
|
82
|
-
/** Session id that keys the shared sandbox; absent means this session owns it. */
|
|
83
|
-
sandboxOwnerId?: string;
|
|
84
92
|
/**
|
|
85
|
-
* The
|
|
86
|
-
*
|
|
93
|
+
* The Environment the session names (`environment`, protocol 11): its sandbox is the
|
|
94
|
+
* session's (the Environment's id keys the workspace) and its vault holds the session's
|
|
95
|
+
* credentials. It outlives the session.
|
|
96
|
+
*/
|
|
97
|
+
environmentId?: string;
|
|
98
|
+
/** The Environment's recipe version when the session opened (shown, never enforced). */
|
|
99
|
+
environmentVersion?: number;
|
|
100
|
+
/**
|
|
101
|
+
* The harness that runs the session's turns (R4.1), pinned when it opened: its Environment's
|
|
102
|
+
* harness, else `nylorun`. Absent on a session opened before R4: ours (`harnessOf`).
|
|
103
|
+
*/
|
|
104
|
+
harness?: string;
|
|
105
|
+
/**
|
|
106
|
+
* A flow agent's linked session: the session whose turn opened the flow tree. Its sessions
|
|
107
|
+
* share the tree's Environment, and their turns nest in the root's, so they do not hold the
|
|
108
|
+
* Environment against each other (`checkEnvironmentTurn`).
|
|
87
109
|
*/
|
|
88
|
-
|
|
110
|
+
flowRootId?: string;
|
|
89
111
|
/**
|
|
90
|
-
* The sandbox
|
|
91
|
-
*
|
|
92
|
-
* definition declares one (`.sandbox()`).
|
|
112
|
+
* The Environment's sandbox spec when the session opened (kinds `virtual` and `pod`).
|
|
113
|
+
* Absent without an Environment, or for kind `none`.
|
|
93
114
|
*/
|
|
94
115
|
sandbox?: SandboxManifest;
|
|
95
|
-
/**
|
|
96
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Why the session takes no new turn: `protocol_11` for a session opened before protocol 11
|
|
118
|
+
* (migration 0020). Its history stays readable.
|
|
119
|
+
*/
|
|
120
|
+
closedReason?: string;
|
|
97
121
|
}
|
|
98
122
|
export type AuthScope = {
|
|
99
123
|
kind: "application";
|
|
@@ -110,7 +134,7 @@ export type AuthScope = {
|
|
|
110
134
|
}
|
|
111
135
|
/**
|
|
112
136
|
* A trusted issuer's token (Host feature `trusted-issuers`, F9-D12): one subject, with the
|
|
113
|
-
* issuer's scopes, agents and
|
|
137
|
+
* issuer's scopes, agents and Environment grants, until `expiresAt` (ms). Only its expiry ends it.
|
|
114
138
|
*/
|
|
115
139
|
| {
|
|
116
140
|
kind: "token";
|
|
@@ -120,8 +144,8 @@ export type AuthScope = {
|
|
|
120
144
|
/** The issuer's scopes the token holds, which may add `studio`. */
|
|
121
145
|
scopes: ReadonlySet<IssuerScope>;
|
|
122
146
|
agents: ReadonlySet<string> | "*";
|
|
123
|
-
/** The
|
|
124
|
-
|
|
147
|
+
/** The Environments it reaches: exact ids or `p/*` prefixes. Absent or empty reaches none. */
|
|
148
|
+
environments?: readonly string[];
|
|
125
149
|
expiresAt: number;
|
|
126
150
|
/** The token's `jti`, or a hash of it. */
|
|
127
151
|
tokenId: string;
|
|
@@ -183,6 +207,11 @@ export interface TenantContext {
|
|
|
183
207
|
* this process's `sandbox` today; over the Harness API's `workspace.read` from F6.2.
|
|
184
208
|
*/
|
|
185
209
|
readonly workspaces: WorkspaceReader;
|
|
210
|
+
/**
|
|
211
|
+
* How the trace route (R7.5) makes spans: the resource and the content the installation exports
|
|
212
|
+
* (R7.2). Absent: `service.name` `nylorun`, no content.
|
|
213
|
+
*/
|
|
214
|
+
readonly traces?: TraceOptions;
|
|
186
215
|
/**
|
|
187
216
|
* The run token of each session an advance of this process owns (F5): the credential the
|
|
188
217
|
* HTTP gate clients present for that session's model and MCP calls (`run-grants.ts`).
|
|
@@ -232,7 +261,7 @@ export interface TenantContext {
|
|
|
232
261
|
abortLocal(sessionId: string, turnId?: string): void;
|
|
233
262
|
/**
|
|
234
263
|
* Sandbox pods (F7.2): the sandboxes service and the Runtime image pods copy the engine from.
|
|
235
|
-
* Absent without a cluster (`nylorun sandbox enable`): kind `pod` is `
|
|
264
|
+
* Absent without a cluster (`nylorun sandbox enable`): kind `pod` is `environment_unavailable`.
|
|
236
265
|
*/
|
|
237
266
|
readonly pods?: TenantPods;
|
|
238
267
|
/**
|
|
@@ -275,14 +304,11 @@ export interface Lease {
|
|
|
275
304
|
export declare function ownedSession(t: Tx, lease: Lease, id: string): Promise<Session>;
|
|
276
305
|
/** The session read in its own transaction, or a 404. */
|
|
277
306
|
export declare function loadSession(ctx: TenantContext, id: string, access?: SessionAccess): Promise<Session>;
|
|
278
|
-
/**
|
|
279
|
-
* A synchronous lookup over `start` and every session its `sandboxOwnerId` chain names, for
|
|
280
|
-
* the sandbox-sharing helpers, which walk that chain synchronously.
|
|
281
|
-
*/
|
|
282
|
-
export declare function sandboxLookup(t: Tx, start: string | undefined): Promise<(id: string) => Session | undefined>;
|
|
283
307
|
/** The sandboxes service a Tenant drives its pod sandboxes with (`TenantContext.pods`). */
|
|
284
308
|
export interface TenantPods {
|
|
285
309
|
readonly client: SandboxesClient;
|
|
286
310
|
/** The Runtime image the pods copy the engine from (`NYLORUN_SANDBOX_HARNESS_IMAGE`). */
|
|
287
311
|
readonly harnessImage: string;
|
|
288
312
|
}
|
|
313
|
+
/** The harness a session runs (R4.1): the one it pinned, else ours. */
|
|
314
|
+
export declare function harnessOf(session: Pick<Session, "harness">): string;
|
package/dist/tenant/context.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_HARNESS } from "@nylorun/core/contracts";
|
|
1
2
|
import { fail } from "./http.js";
|
|
2
3
|
/**
|
|
3
4
|
* `access`, when set, limits the request to the owner's sessions of the allowed agents:
|
|
@@ -34,19 +35,7 @@ export async function ownedSession(t, lease, id) {
|
|
|
34
35
|
export function loadSession(ctx, id, access) {
|
|
35
36
|
return ctx.store.tx((t) => sessionOf(t, id, access));
|
|
36
37
|
}
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*/
|
|
41
|
-
export async function sandboxLookup(t, start) {
|
|
42
|
-
const found = new Map();
|
|
43
|
-
let id = start;
|
|
44
|
-
while (id && !found.has(id)) {
|
|
45
|
-
const session = await t.get("sessions", id);
|
|
46
|
-
if (!session)
|
|
47
|
-
break;
|
|
48
|
-
found.set(id, session);
|
|
49
|
-
id = session.sandboxOwnerId;
|
|
50
|
-
}
|
|
51
|
-
return (sid) => found.get(sid);
|
|
38
|
+
/** The harness a session runs (R4.1): the one it pinned, else ours. */
|
|
39
|
+
export function harnessOf(session) {
|
|
40
|
+
return session.harness ?? DEFAULT_HARNESS;
|
|
52
41
|
}
|
package/dist/tenant/effects.d.ts
CHANGED
|
@@ -42,6 +42,6 @@ export declare function recoversModelCalls(ctx: TenantContext): boolean;
|
|
|
42
42
|
export declare function resolveNewFlowEffect(ctx: TenantContext, request: HostEffect, signal: AbortSignal, lease: Lease): Promise<EffectResolution>;
|
|
43
43
|
/**
|
|
44
44
|
* The credential of an MCP server or HTTP tool request made on behalf of a session: from its
|
|
45
|
-
*
|
|
45
|
+
* Environment's vault (`vault/sources.ts`).
|
|
46
46
|
*/
|
|
47
47
|
export declare function authorize(ctx: TenantContext, sessionId: string, request: McpCredentialRequest): Promise<AuthorizeResult>;
|
package/dist/tenant/effects.js
CHANGED
|
@@ -4,9 +4,9 @@ import { mayDispatchMore } from "../core/limits.js";
|
|
|
4
4
|
import { sessionCredentials } from "../vault/sources.js";
|
|
5
5
|
import { isRemoteMcpCall } from "../harness/calls.js";
|
|
6
6
|
import { isHttpToolCall } from "../gates/http-tool.js";
|
|
7
|
-
import {
|
|
7
|
+
import { sandboxSpecOf } from "../sandbox/share.js";
|
|
8
8
|
import { withPlatformTools, withSandboxCapability } from "../sandbox/session-sandbox.js";
|
|
9
|
-
import { loadSession, ownedSession,
|
|
9
|
+
import { loadSession, ownedSession, sessionOf, } from "./context.js";
|
|
10
10
|
import { fail } from "./http.js";
|
|
11
11
|
import { turnManifestOf } from "./session.js";
|
|
12
12
|
import { command } from "./commands.js";
|
|
@@ -85,11 +85,14 @@ export async function resolveNewFlowEffect(ctx, request, signal, lease) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
const active = await countActiveFlowWork(t, request.sessionId, request.turnId);
|
|
88
|
+
// When the run journaled the effect (R7.1); a queued effect keeps it once dispatched.
|
|
89
|
+
const startedAt = existing?.startedAt ?? new Date().toISOString();
|
|
88
90
|
if (!mayDispatchMore(active, ctx.flowLimits)) {
|
|
89
91
|
if (!existing || existing.status !== "queued")
|
|
90
92
|
await t.put("effects", request.effectId, {
|
|
91
93
|
request,
|
|
92
94
|
status: "queued",
|
|
95
|
+
startedAt,
|
|
93
96
|
});
|
|
94
97
|
return resolved({ status: "pending" });
|
|
95
98
|
}
|
|
@@ -101,19 +104,32 @@ export async function resolveNewFlowEffect(ctx, request, signal, lease) {
|
|
|
101
104
|
value: {
|
|
102
105
|
kind: "failed",
|
|
103
106
|
code: "tool.unavailable",
|
|
104
|
-
message: `The tool stage '${request.key ?? request.path ?? ""}' runs your code,
|
|
107
|
+
message: `The tool stage '${request.key ?? request.path ?? ""}' runs your code, but the Runtime runs agents from their manifests alone`,
|
|
105
108
|
},
|
|
106
109
|
};
|
|
107
|
-
await t.put("effects", request.effectId, {
|
|
108
|
-
|
|
110
|
+
await t.put("effects", request.effectId, {
|
|
111
|
+
request,
|
|
112
|
+
status: "completed",
|
|
113
|
+
outcome,
|
|
114
|
+
startedAt,
|
|
115
|
+
settledAt: startedAt,
|
|
116
|
+
});
|
|
117
|
+
const node = {
|
|
109
118
|
path: request.path,
|
|
110
119
|
kind: "tool",
|
|
111
120
|
key: request.key,
|
|
112
121
|
...(request.iterations !== undefined ? { iterations: request.iterations } : {}),
|
|
122
|
+
};
|
|
123
|
+
await t.event(workflow.id, workflow.activeTurnId, "node.started", node);
|
|
124
|
+
// Nothing ran (R7.1): the stage's outcome row says so.
|
|
125
|
+
await t.event(workflow.id, workflow.activeTurnId, "node.completed", {
|
|
126
|
+
...node,
|
|
127
|
+
effectId: request.effectId,
|
|
128
|
+
status: "failed",
|
|
113
129
|
});
|
|
114
130
|
return resolved({ status: "completed", outcome });
|
|
115
131
|
}
|
|
116
|
-
return { kind: "agent", workflow };
|
|
132
|
+
return { kind: "agent", workflow, startedAt };
|
|
117
133
|
});
|
|
118
134
|
if (step.kind === "resolved")
|
|
119
135
|
return step.resolution;
|
|
@@ -130,6 +146,7 @@ export async function resolveNewFlowEffect(ctx, request, signal, lease) {
|
|
|
130
146
|
request,
|
|
131
147
|
status: "pending",
|
|
132
148
|
agentSessionId,
|
|
149
|
+
startedAt: step.startedAt,
|
|
133
150
|
});
|
|
134
151
|
await t.put("links", agentSessionId, {
|
|
135
152
|
workflowSessionId: workflow.id,
|
|
@@ -145,12 +162,8 @@ export async function resolveNewFlowEffect(ctx, request, signal, lease) {
|
|
|
145
162
|
if (exists)
|
|
146
163
|
return;
|
|
147
164
|
const definition = leafDefinition(workflow, body, request);
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
? owningSandboxSessionId(workflow, lookup)
|
|
151
|
-
: undefined;
|
|
152
|
-
// A sandbox chosen when the tree was opened reaches every agent in it, with its tools.
|
|
153
|
-
const inherited = inheritedSandbox(sandboxOwnerId === undefined ? undefined : lookup(sandboxOwnerId) ?? workflow, definition);
|
|
165
|
+
// The tree's Environment reaches every agent in it: its sandbox, with its tools, and its vault.
|
|
166
|
+
const inherited = inheritedSandbox(workflow, definition);
|
|
154
167
|
// Without one, an agent with MCP or HTTP tools still reads its stored results (R2b C11).
|
|
155
168
|
const pinned = inherited?.manifest ? inherited : platformTools(definition.manifest);
|
|
156
169
|
const created = {
|
|
@@ -167,14 +180,18 @@ export async function resolveNewFlowEffect(ctx, request, signal, lease) {
|
|
|
167
180
|
requestId: `flow-put-${request.effectId}`,
|
|
168
181
|
agentId: body.agentId,
|
|
169
182
|
ownerUserId: workflow.ownerUserId,
|
|
170
|
-
...(
|
|
183
|
+
...(workflow.environmentId === undefined ? {} : { environment: workflow.environmentId }),
|
|
171
184
|
},
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
185
|
+
flowRootId: workflow.flowRootId ?? workflow.id,
|
|
186
|
+
...(workflow.environmentId === undefined
|
|
187
|
+
? {}
|
|
188
|
+
: {
|
|
189
|
+
environmentId: workflow.environmentId,
|
|
190
|
+
...(workflow.environmentVersion === undefined
|
|
191
|
+
? {}
|
|
192
|
+
: { environmentVersion: workflow.environmentVersion }),
|
|
193
|
+
}),
|
|
194
|
+
...(inherited ? { sandbox: inherited.spec } : {}),
|
|
178
195
|
};
|
|
179
196
|
await t.put("sessions", agentSessionId, created);
|
|
180
197
|
});
|
|
@@ -258,7 +275,7 @@ function platformTools(manifest) {
|
|
|
258
275
|
}
|
|
259
276
|
/**
|
|
260
277
|
* The credential of an MCP server or HTTP tool request made on behalf of a session: from its
|
|
261
|
-
*
|
|
278
|
+
* Environment's vault (`vault/sources.ts`).
|
|
262
279
|
*/
|
|
263
280
|
export async function authorize(ctx, sessionId, request) {
|
|
264
281
|
const s = await loadSession(ctx, sessionId);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environments (D55, D56, protocol 11): `PUT`, `GET` and `DELETE /v1/environments/{id}`, the
|
|
3
|
+
* list by label, stop, reset and the lifecycle stream; sessions naming one with `environment`,
|
|
4
|
+
* and the checks every turn start makes on it.
|
|
5
|
+
*
|
|
6
|
+
* - **No scope.** The Runtime decides nothing about who uses an Environment: the app maps its
|
|
7
|
+
* people and agents to ids. It stores the id, kind, recipe, labels and the optional owner
|
|
8
|
+
* guard; the session body names the Environment (`Session.environmentId`), and deleting a
|
|
9
|
+
* session (a sessions reset) only detaches it.
|
|
10
|
+
* - **One sandbox, one vault.** Kind `virtual` (a just-bash workspace in the harness container,
|
|
11
|
+
* keyed by the Environment id and created on the first tool call), `pod` (an agent-sandbox pod
|
|
12
|
+
* on the Tenant's cluster, Host feature `sandbox-pods`, created at once) or `none` (no compute).
|
|
13
|
+
* Each has one vault (`vault/service.ts`), created and deleted with it in one transaction.
|
|
14
|
+
* - **A recipe that changes.** `PUT` on an existing id compares the fields sent: `kind` and
|
|
15
|
+
* `storage` are fixed (`409`), labels replace, and any other change writes the recipe and bumps
|
|
16
|
+
* `version`. A pod runs `applied`: image and resources reach it when it is next asked to run
|
|
17
|
+
* from stopped (`wantRunning`), so nothing swaps them mid-turn; so does `harness`, which picks
|
|
18
|
+
* what the pod runs (R4.4). Network and lifecycle apply at once. A virtual or `none`
|
|
19
|
+
* Environment applies every change at once.
|
|
20
|
+
* - **Access.** An application key reaches every Environment, and so does an application key
|
|
21
|
+
* acting for a subject (`Nylorun-Subject`), which needs `environments:write` to change one. A
|
|
22
|
+
* token caller reaches only the ids its grants match, and changes them only with
|
|
23
|
+
* `environments:write`; any other id is the 404 of a missing one.
|
|
24
|
+
* - **The owner guard.** When `ownerUserId` is set, only that owner's sessions may name the
|
|
25
|
+
* Environment, checked when a session opens and at every turn start (`403
|
|
26
|
+
* environment_owner_mismatch`; the opaque 404 to a caller acting for a person).
|
|
27
|
+
* - **Serial turns.** One turn at a time per Environment with a sandbox: a session whose
|
|
28
|
+
* Environment another session's turn holds is refused (`409 environment_busy`).
|
|
29
|
+
* - **Lifecycle.** `POST .../stop` suspends a pod (the volume is kept; the next turn starts it),
|
|
30
|
+
* `POST .../reset` gives it a new pod on a new volume. A lost pod refuses turns
|
|
31
|
+
* (`environment_lost`) until a reset. `lifecycle.deleteAfter` deletes an Environment unused
|
|
32
|
+
* for that long (the Tenant sweep, `sweepUnusedEnvironments`). Deleting a pod Environment keeps
|
|
33
|
+
* its row (`desired: deleted`, invisible here) until its Sandbox is gone; its vault goes at once.
|
|
34
|
+
* - **Lifecycle events** go to the Environment's own stream in the record (`Tx.environmentEvent`,
|
|
35
|
+
* `record/environment.ts`); the session's log records `environment.attached` too.
|
|
36
|
+
*/
|
|
37
|
+
import { type EnvironmentView, type PutEnvironmentRequest } from "@nylorun/core/contracts";
|
|
38
|
+
import type { Environment, Tx } from "../store/types.js";
|
|
39
|
+
import type { SandboxRouteDeps } from "../core/sandbox-routes.js";
|
|
40
|
+
import { type AuthScope, type Session, type TenantContext } from "./context.js";
|
|
41
|
+
/** The Environment grants that limit `scope`, or undefined when it reaches every Environment. */
|
|
42
|
+
export declare function environmentGrantsOf(scope: AuthScope): readonly string[] | undefined;
|
|
43
|
+
/** Who the vault's audit rows name for a request: the subject, else the application. */
|
|
44
|
+
export declare function actorOf(scope: AuthScope): string;
|
|
45
|
+
/** Refuses (the 404 of a missing one) Environment `id` when the caller's grants miss it. */
|
|
46
|
+
export declare function assertReaches(scope: AuthScope, id: string): void;
|
|
47
|
+
/** An Environment, unless it is gone or being deleted. */
|
|
48
|
+
export declare function liveEnvironment(t: Tx, id: string, options?: {
|
|
49
|
+
lock?: boolean;
|
|
50
|
+
}): Promise<Environment | undefined>;
|
|
51
|
+
/**
|
|
52
|
+
* `PUT /v1/environments/{id}`: creates the Environment and its vault (within the Tenant's limit
|
|
53
|
+
* on their number), or finds the one with this id, so "get or create" is one call. On an
|
|
54
|
+
* existing one, `kind` and `storage` must match, labels replace, the owner guard is set or
|
|
55
|
+
* cleared, and a recipe change bumps `version`. Every `PUT` counts as the Environment's use.
|
|
56
|
+
*/
|
|
57
|
+
export declare function putEnvironment(ctx: TenantContext, id: string, body: PutEnvironmentRequest, scope: AuthScope): Promise<EnvironmentView>;
|
|
58
|
+
/** `GET /v1/environments/{id}`. */
|
|
59
|
+
export declare function getEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<EnvironmentView>;
|
|
60
|
+
/** `GET /v1/environments?label=k=v`: every Environment with all the labels, that the caller reaches. */
|
|
61
|
+
export declare function listEnvironments(ctx: TenantContext, labels: Record<string, string>, scope: AuthScope): Promise<{
|
|
62
|
+
environments: EnvironmentView[];
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Asks pod Environment `id` to run when it is stopped or failed (a disk copy needs its engine),
|
|
66
|
+
* with its recipe applied, as a turn start would.
|
|
67
|
+
*/
|
|
68
|
+
export declare function wakePod(ctx: TenantContext, id: string): Promise<void>;
|
|
69
|
+
/** Whether a disk lease (R2d step 3) holds `environment` now. */
|
|
70
|
+
export declare function diskHeld(environment: Environment, now?: number): boolean;
|
|
71
|
+
/** Refused while a snapshot or restore copies the disk (a pending seed does not count). */
|
|
72
|
+
export declare function refuseDiskCopy(environment: Environment): void;
|
|
73
|
+
/**
|
|
74
|
+
* `DELETE /v1/environments/{id}`: deletes the Environment, its vault and its workspace. Refused
|
|
75
|
+
* while a session that names it has an active turn. Sessions keep its id: their next turn is
|
|
76
|
+
* refused (`environment_unavailable`) unless an Environment with this id exists again.
|
|
77
|
+
*/
|
|
78
|
+
export declare function deleteEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<{
|
|
79
|
+
id: string;
|
|
80
|
+
deleted: boolean;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Deletes every Environment unused for its `lifecycle.deleteAfter` (Q13): no turn, recipe
|
|
84
|
+
* change, secret write, stop or reset since. One with a turn running waits for the next sweep.
|
|
85
|
+
* Run by the Tenant sweep.
|
|
86
|
+
*/
|
|
87
|
+
export declare function sweepUnusedEnvironments(ctx: TenantContext, now?: number): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* `POST /v1/environments/{id}/stop`: suspends a pod Environment. Its volume is kept, and the next
|
|
90
|
+
* turn of a session that names it starts it again. Refused during a turn.
|
|
91
|
+
*/
|
|
92
|
+
export declare function stopEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<EnvironmentView>;
|
|
93
|
+
/**
|
|
94
|
+
* `POST /v1/environments/{id}/reset`: a new pod on a new, empty volume (the next volume
|
|
95
|
+
* generation), with a new join token and the recipe applied; the old Sandbox and volume are
|
|
96
|
+
* deleted. Leaves `lost` and `failed`. Refused during a turn, and while an earlier reset's
|
|
97
|
+
* Sandbox is still being deleted.
|
|
98
|
+
*/
|
|
99
|
+
export declare function resetEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<EnvironmentView>;
|
|
100
|
+
/**
|
|
101
|
+
* Gives pod Environment `environment` (locked) a new pod on a new, empty volume, the next volume
|
|
102
|
+
* generation, with its recipe applied: the old Sandbox and volume are retired. With `seed`, the
|
|
103
|
+
* new volume starts from that disk version before any turn (R2d step 3): a restore, or the
|
|
104
|
+
* recovery of a lost volume.
|
|
105
|
+
*/
|
|
106
|
+
export declare function newVolume(ctx: TenantContext, t: Tx, environment: Environment, options?: {
|
|
107
|
+
seed?: {
|
|
108
|
+
artifactId: string;
|
|
109
|
+
version: number;
|
|
110
|
+
};
|
|
111
|
+
reason?: "restore" | "lost";
|
|
112
|
+
}): Promise<number>;
|
|
113
|
+
/** How long a pending seed holds the disk before another process may take it over. */
|
|
114
|
+
export declare const SEED_LEASE_MS: number;
|
|
115
|
+
/** `GET /v1/environments/{id}/events`: the Environment's lifecycle stream. */
|
|
116
|
+
export declare function environmentEventsOf(ctx: TenantContext, id: string, scope: AuthScope, fromSeq: number | undefined): Promise<{
|
|
117
|
+
events: {
|
|
118
|
+
schema: "nylorun.environment-event/1";
|
|
119
|
+
eventId: string;
|
|
120
|
+
tenantId: string;
|
|
121
|
+
environmentId: string;
|
|
122
|
+
seq: number;
|
|
123
|
+
time: string;
|
|
124
|
+
type: "environment.attached" | "environment.created" | "environment.deleted" | "environment.detached" | "environment.egress" | "environment.failed" | "environment.lost" | "environment.relaunched" | "environment.reset" | "environment.running" | "environment.suspended";
|
|
125
|
+
payload: Record<string, unknown>;
|
|
126
|
+
}[];
|
|
127
|
+
}>;
|
|
128
|
+
/**
|
|
129
|
+
* Opens a new session on Environment `id` (`PutSessionRequest.environment`): it must exist, be
|
|
130
|
+
* reachable with `grants` and pass its owner guard. Runs in the session's transaction, after
|
|
131
|
+
* its session row lock; holds the Environment's row lock.
|
|
132
|
+
*/
|
|
133
|
+
export declare function openEnvironment(t: Tx, id: string, options: {
|
|
134
|
+
grants?: readonly string[];
|
|
135
|
+
ownerUserId: string;
|
|
136
|
+
opaque: boolean;
|
|
137
|
+
}): Promise<Environment>;
|
|
138
|
+
/** Records the attachment on the session's log and on the Environment's stream. */
|
|
139
|
+
export declare function recordAttachment(t: Tx, sessionId: string, environmentId: string): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Checks a turn start on a session that names an Environment, in the command's transaction
|
|
142
|
+
* after the session row lock: the Environment still exists, a token caller's grants reach it,
|
|
143
|
+
* its owner guard admits the session's owner, and, with a sandbox, no other session's turn
|
|
144
|
+
* holds it. Holds the Environment row's lock until the transaction ends, so two turn starts on
|
|
145
|
+
* one Environment are decided one after the other.
|
|
146
|
+
*
|
|
147
|
+
* A pod Environment must also be usable: not lost (`environment_lost`), on a Runtime with
|
|
148
|
+
* sandbox pods (`environment_unavailable`). A stopped or failed pod is asked to run again, with
|
|
149
|
+
* its recipe applied, after the commit.
|
|
150
|
+
*/
|
|
151
|
+
export declare function checkEnvironmentTurn(t: Tx, session: Session, scope: AuthScope, ctx?: TenantContext): Promise<void>;
|
|
152
|
+
/** A sessions reset detaches every session from its Environment: each one's stream says so. */
|
|
153
|
+
export declare function detachAllSessions(t: Tx): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Marks the end of a turn's segment on Environment `id`: it was used now (`deleteAfter` counts
|
|
156
|
+
* from here), and for a running pod idle counts from now and the idle timer is armed (D34).
|
|
157
|
+
* Best effort.
|
|
158
|
+
*/
|
|
159
|
+
export declare function touchEnvironment(ctx: TenantContext, id: string): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Re-arms the idle timer of every running pod after the Tenant's settings change, so a shorter
|
|
162
|
+
* `limits.idle` applies to pods already idle (D36: the settings are read whenever a timer is
|
|
163
|
+
* set). Best effort.
|
|
164
|
+
*/
|
|
165
|
+
export declare function rearmPodTimers(ctx: TenantContext): Promise<void>;
|
|
166
|
+
/** Session lookups for the sandbox route handlers (`core/sandbox-routes.ts`). */
|
|
167
|
+
export declare function sandboxRouteDeps(ctx: TenantContext): SandboxRouteDeps;
|