@nylorun/runtime 0.15.2-beta → 0.17.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 +134 -0
- package/README.md +68 -29
- package/dist/adapters/execution/restate.d.ts +9 -1
- package/dist/adapters/execution/restate.js +64 -5
- package/dist/adapters/sandbox/local.d.ts +10 -0
- package/dist/adapters/sandbox/local.js +195 -0
- package/dist/adapters/sandbox/virtual.js +36 -1
- package/dist/admin-openapi.json +341 -7
- package/dist/api/a2a/tasks.js +6 -1
- package/dist/api/ag-ui/endpoint.js +1 -2
- package/dist/api/ag-ui/history.js +6 -1
- package/dist/api/ag-ui/routes.d.ts +1 -1
- package/dist/api/ag-ui/routes.js +15 -13
- package/dist/api/components.d.ts +2667 -711
- package/dist/api/components.js +24 -11
- package/dist/api/gate/keys.d.ts +4 -3
- package/dist/api/gate/routes.d.ts +19 -3
- package/dist/api/gate/routes.js +162 -53
- package/dist/api/http/app.js +6 -0
- package/dist/api/http/define.d.ts +19 -12
- package/dist/api/http/define.js +13 -27
- package/dist/api/http/routes/access.d.ts +3 -19
- package/dist/api/http/routes/access.js +12 -172
- package/dist/api/http/routes/actions.js +0 -1
- package/dist/api/http/routes/artifacts.d.ts +11 -0
- package/dist/api/http/routes/artifacts.js +516 -0
- package/dist/api/http/routes/me.d.ts +13 -0
- package/dist/api/http/routes/me.js +45 -0
- package/dist/api/http/routes/sandboxes.d.ts +9 -0
- package/dist/api/http/routes/sandboxes.js +150 -0
- package/dist/api/http/routes/sessions.js +9 -13
- package/dist/api/http/routes/tenant.js +36 -2
- package/dist/api/http/routes/vaults.d.ts +12 -3
- package/dist/api/http/routes/vaults.js +122 -54
- package/dist/api/openapi.js +4 -10
- package/dist/artifacts/config.d.ts +23 -0
- package/dist/artifacts/config.js +27 -0
- package/dist/artifacts/export.d.ts +8 -0
- package/dist/artifacts/export.js +205 -0
- package/dist/artifacts/files.d.ts +36 -0
- package/dist/artifacts/files.js +45 -0
- package/dist/artifacts/folders.d.ts +60 -0
- package/dist/artifacts/folders.js +209 -0
- package/dist/artifacts/links.d.ts +28 -0
- package/dist/artifacts/links.js +92 -0
- package/dist/artifacts/media-types.d.ts +13 -0
- package/dist/artifacts/media-types.js +80 -0
- package/dist/artifacts/parts.d.ts +34 -0
- package/dist/artifacts/parts.js +38 -0
- package/dist/artifacts/service.d.ts +74 -0
- package/dist/artifacts/service.js +301 -0
- package/dist/artifacts/workspace.d.ts +60 -0
- package/dist/artifacts/workspace.js +57 -0
- package/dist/artifacts/zip.d.ts +10 -0
- package/dist/artifacts/zip.js +126 -0
- package/dist/blob/fs.d.ts +13 -0
- package/dist/blob/fs.js +194 -0
- package/dist/blob/index.d.ts +9 -0
- package/dist/blob/index.js +9 -0
- package/dist/blob/s3.d.ts +42 -0
- package/dist/blob/s3.js +366 -0
- package/dist/blob/types.d.ts +108 -0
- package/dist/blob/types.js +85 -0
- package/dist/core/sandbox-routes.d.ts +2 -2
- package/dist/core/sandbox-routes.js +4 -3
- package/dist/execution/memory.d.ts +11 -1
- package/dist/execution/memory.js +77 -3
- package/dist/execution/types.d.ts +54 -1
- package/dist/execution/types.js +31 -0
- package/dist/gates/contract.d.ts +14 -13
- package/dist/gates/contract.js +13 -12
- package/dist/gates/egress.d.ts +72 -0
- package/dist/gates/egress.js +319 -0
- package/dist/gates/handler.d.ts +3 -0
- package/dist/gates/handler.js +3 -2
- package/dist/gates/http-client.d.ts +3 -2
- package/dist/gates/http-client.js +17 -6
- package/dist/gates/in-process.d.ts +13 -1
- package/dist/gates/in-process.js +11 -0
- package/dist/gates/inflight.d.ts +23 -4
- package/dist/gates/inflight.js +18 -4
- package/dist/gates/mcp-handler.js +5 -1
- package/dist/gates/model-gate.d.ts +6 -2
- package/dist/gates/tenant-vaults.d.ts +18 -9
- package/dist/gates/tenant-vaults.js +17 -12
- package/dist/gates/tool-calls.d.ts +9 -5
- package/dist/gates/tool-calls.js +6 -6
- package/dist/gates/tool-client.d.ts +9 -2
- package/dist/gates/tool-client.js +56 -22
- package/dist/gates/tool-contract.d.ts +12 -7
- package/dist/gates/tool-contract.js +10 -4
- package/dist/gates/tool-gate.d.ts +1 -0
- package/dist/harness/calls.d.ts +52 -0
- package/dist/harness/calls.js +113 -0
- package/dist/harness/executors.d.ts +22 -0
- package/dist/harness/executors.js +96 -0
- package/dist/harness/main.d.ts +6 -0
- package/dist/harness/main.js +103 -0
- package/dist/harness/pod.d.ts +21 -0
- package/dist/harness/pod.js +119 -0
- package/dist/harness/run-tokens.d.ts +18 -0
- package/dist/harness/run-tokens.js +15 -0
- package/dist/harness/service.d.ts +46 -0
- package/dist/harness/service.js +179 -0
- package/dist/harness/ws-client.d.ts +43 -0
- package/dist/harness/ws-client.js +122 -0
- package/dist/harness/ws-port.d.ts +22 -0
- package/dist/harness/ws-port.js +78 -0
- package/dist/harness-api/in-process.d.ts +24 -0
- package/dist/harness-api/in-process.js +119 -0
- package/dist/harness-api/record.d.ts +44 -0
- package/dist/harness-api/record.js +250 -0
- package/dist/harness-api/renew.d.ts +37 -0
- package/dist/harness-api/renew.js +77 -0
- package/dist/harness-api/server.d.ts +104 -0
- package/dist/harness-api/server.js +408 -0
- package/dist/harness-api/start.d.ts +36 -0
- package/dist/harness-api/start.js +118 -0
- package/dist/harness-api/workspace.d.ts +53 -0
- package/dist/harness-api/workspace.js +201 -0
- package/dist/harness-api/ws-server.d.ts +34 -0
- package/dist/harness-api/ws-server.js +227 -0
- package/dist/host/admin-api.d.ts +12 -5
- package/dist/host/admin-api.js +72 -6
- package/dist/host/app.d.ts +0 -1
- package/dist/host/app.js +35 -24
- package/dist/host/config-for.d.ts +4 -0
- package/dist/host/config-for.js +2 -0
- package/dist/host/config.d.ts +0 -6
- package/dist/host/create-host.d.ts +3 -10
- package/dist/host/create-host.js +4 -1
- package/dist/host/gates.d.ts +27 -2
- package/dist/host/gates.js +52 -2
- package/dist/host/http.d.ts +4 -1
- package/dist/host/http.js +6 -1
- package/dist/host/main.js +167 -37
- package/dist/host/stack-config.d.ts +112 -9
- package/dist/host/stack-config.js +222 -20
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/keys/client.js +9 -1
- package/dist/keys/keys.d.ts +12 -2
- package/dist/keys/keys.js +8 -0
- package/dist/mcp/connect.js +2 -1
- package/dist/mcp/pool.d.ts +1 -0
- package/dist/mcp/pool.js +1 -0
- package/dist/mcp/snapshot.d.ts +8 -1
- package/dist/mcp/snapshot.js +28 -0
- package/dist/media.d.ts +5 -24
- package/dist/media.js +5 -0
- package/dist/model/pi-model.d.ts +6 -2
- package/dist/model/pi-model.js +39 -22
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +1 -1
- package/dist/openapi.json +14084 -9426
- package/dist/record/index.d.ts +1 -0
- package/dist/record/index.js +1 -0
- package/dist/record/sandbox.d.ts +25 -0
- package/dist/record/sandbox.js +43 -0
- package/dist/sandbox/capability.d.ts +3 -0
- package/dist/sandbox/capability.js +10 -0
- package/dist/sandbox/egress-token.d.ts +26 -0
- package/dist/sandbox/egress-token.js +8 -0
- package/dist/sandbox/join.d.ts +37 -0
- package/dist/sandbox/join.js +165 -0
- package/dist/sandbox/manager.d.ts +99 -34
- package/dist/sandbox/manager.js +216 -84
- package/dist/sandbox/placement.d.ts +27 -0
- package/dist/sandbox/placement.js +44 -0
- package/dist/sandbox/pods/client.d.ts +90 -0
- package/dist/sandbox/pods/client.js +79 -0
- package/dist/sandbox/pods/lifecycle.d.ts +91 -0
- package/dist/sandbox/pods/lifecycle.js +178 -0
- package/dist/sandbox/pods/name.d.ts +1 -0
- package/dist/sandbox/pods/name.js +28 -0
- package/dist/sandbox/pods/network-gate.d.ts +25 -0
- package/dist/sandbox/pods/network-gate.js +71 -0
- package/dist/sandbox/pods/reconcile.d.ts +11 -0
- package/dist/sandbox/pods/reconcile.js +152 -0
- package/dist/sandbox/pods/spec.d.ts +45 -0
- package/dist/sandbox/pods/spec.js +62 -0
- package/dist/sandbox/records.d.ts +29 -0
- package/dist/sandbox/records.js +79 -0
- package/dist/sandbox/resolve.d.ts +5 -0
- package/dist/sandbox/resolve.js +3 -2
- package/dist/sandbox/session-sandbox.js +7 -5
- package/dist/sandbox/share.d.ts +11 -0
- package/dist/sandbox/share.js +10 -0
- package/dist/sandbox/tenant-config.d.ts +16 -1
- package/dist/sandbox/tenant-config.js +9 -0
- package/dist/sandbox/types.d.ts +29 -1
- package/dist/sandbox/types.js +13 -1
- package/dist/store/postgres/drizzle/0004_sandbox_resources.sql +20 -0
- package/dist/store/postgres/drizzle/0005_artifacts.sql +27 -0
- package/dist/store/postgres/drizzle/0006_folder_artifacts.sql +12 -0
- package/dist/store/postgres/drizzle/0007_sandbox_pods.sql +14 -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/meta/_journal.json +49 -0
- package/dist/store/postgres/record-writer.d.ts +6 -1
- package/dist/store/postgres/record-writer.js +20 -2
- package/dist/store/postgres/schema.d.ts +1168 -250
- package/dist/store/postgres/schema.js +174 -28
- package/dist/store/postgres/store.js +339 -103
- package/dist/store/postgres/tenant.d.ts +1 -1
- package/dist/store/postgres/tenant.js +2 -2
- package/dist/store/types.d.ts +163 -32
- package/dist/streams/control.d.ts +2 -5
- package/dist/streams/control.js +5 -8
- package/dist/streams/types.d.ts +8 -8
- package/dist/streams/types.js +1 -1
- package/dist/tenant/advance.js +218 -160
- package/dist/tenant/artifact-tool.d.ts +5 -0
- package/dist/tenant/artifact-tool.js +119 -0
- package/dist/tenant/auth.d.ts +13 -9
- package/dist/tenant/auth.js +25 -32
- package/dist/tenant/commands.js +31 -10
- package/dist/tenant/context.d.ts +83 -26
- package/dist/tenant/delivery-token.js +4 -4
- package/dist/tenant/effects.d.ts +24 -14
- package/dist/tenant/effects.js +10 -398
- package/dist/tenant/ephemeral.d.ts +14 -2
- package/dist/tenant/ephemeral.js +8 -1
- package/dist/tenant/history.d.ts +13 -23
- package/dist/tenant/history.js +14 -62
- package/dist/tenant/host-token.d.ts +92 -0
- package/dist/tenant/host-token.js +179 -0
- 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.js +1 -0
- package/dist/tenant/operator-keys.d.ts +18 -0
- package/dist/tenant/operator-keys.js +55 -0
- package/dist/tenant/outbound.d.ts +30 -0
- package/dist/tenant/outbound.js +142 -10
- package/dist/tenant/paths.d.ts +2 -1
- package/dist/tenant/paths.js +3 -1
- package/dist/tenant/principals.d.ts +2 -11
- package/dist/tenant/principals.js +10 -30
- package/dist/tenant/reset.d.ts +5 -2
- package/dist/tenant/reset.js +22 -2
- package/dist/tenant/run-grants.d.ts +49 -0
- package/dist/tenant/run-grants.js +62 -0
- package/dist/tenant/run-token.d.ts +70 -0
- package/dist/tenant/run-token.js +138 -0
- package/dist/tenant/runtime.d.ts +42 -0
- package/dist/tenant/runtime.js +134 -33
- package/dist/tenant/sandboxes.d.ts +119 -0
- package/dist/tenant/sandboxes.js +551 -0
- package/dist/tenant/session-streams.d.ts +6 -10
- package/dist/tenant/session-streams.js +9 -27
- package/dist/tenant/session.d.ts +2 -13
- package/dist/tenant/session.js +4 -28
- package/dist/tenant/sessions.d.ts +6 -1
- package/dist/tenant/sessions.js +29 -2
- package/dist/tenant/signing-keys.d.ts +2 -1
- package/dist/tenant/signing-keys.js +2 -2
- package/dist/tenant/status.d.ts +8 -3
- package/dist/tenant/status.js +5 -0
- package/dist/tenant/streams.d.ts +8 -2
- package/dist/tenant/streams.js +25 -6
- package/dist/tenant/sweep.js +37 -4
- package/dist/tenant/types.d.ts +39 -1
- package/dist/tenant/worker.d.ts +11 -5
- package/dist/tenant/worker.js +12 -6
- 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 +54 -0
- package/dist/vault/sources.js +185 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -10
- package/dist/adapters/media.d.ts +0 -24
- package/dist/adapters/media.js +0 -111
- package/dist/host/cors.d.ts +0 -27
- package/dist/host/cors.js +0 -64
- package/dist/tenant/access-policy.d.ts +0 -30
- package/dist/tenant/access-policy.js +0 -52
- package/dist/tenant/browser.d.ts +0 -15
- package/dist/tenant/browser.js +0 -39
- 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 -180
|
@@ -13,7 +13,17 @@
|
|
|
13
13
|
* listener (`NYLORUN_GATES_LISTEN_*`), and only one that runs loop parses
|
|
14
14
|
* where to reach the gate (`NYLORUN_GATES_URL`). Both read
|
|
15
15
|
* `NYLORUN_GATES_TOKEN`. In a container, loop requires the gate: the loop
|
|
16
|
-
* process must never hold a model credential.
|
|
16
|
+
* process must never hold a model credential. `egress` (egress-gate, F7.2) joins gates and keys
|
|
17
|
+
* in the gateway and parses its listener (`NYLORUN_EGRESS_LISTEN_*`, default `0.0.0.0:4200`).
|
|
18
|
+
* Only gates reads the operator's credential resolver (`NYLORUN_RESOLVER_URL`,
|
|
19
|
+
* `NYLORUN_RESOLVER_TOKEN`, F9 C1): remote MCP calls are authorized in the gateway.
|
|
20
|
+
*
|
|
21
|
+
* `harness` (F6.2) runs alone: it holds the harness credential and nothing else. It connects to
|
|
22
|
+
* core's Harness API listener (`NYLORUN_HARNESS_URL`, `NYLORUN_HARNESS_TOKEN`), calls models and
|
|
23
|
+
* remote MCP servers through the gates service (`NYLORUN_GATES_URL`, with run tokens only), and
|
|
24
|
+
* keeps its workspaces under `NYLORUN_HARNESS_ROOT`. It refuses to start with a database, the
|
|
25
|
+
* gates' or keys' credential, or Restate settings. A process running core starts the Harness API
|
|
26
|
+
* listener when `NYLORUN_HARNESS=remote` (`NYLORUN_HARNESS_LISTEN_*`, `NYLORUN_HARNESS_TOKEN`).
|
|
17
27
|
*
|
|
18
28
|
* Two listen modes:
|
|
19
29
|
* - **local** (no `NYLORUN_LISTEN_*` / `NYLORUN_ALLOWED_HOSTS`): the Host binds
|
|
@@ -24,21 +34,31 @@
|
|
|
24
34
|
* probes from inside the container.
|
|
25
35
|
*
|
|
26
36
|
* The Postgres, Restate and S2 endpoints are parsed and validated here;
|
|
27
|
-
* `infra/*` builds the clients from them. So is
|
|
28
|
-
*
|
|
37
|
+
* `infra/*` builds the clients from them. So is the Object store (`NYLORUN_OBJECT_STORE_*`),
|
|
38
|
+
* which every service may read; `host/main.ts` builds the `BlobStore` from it. So is who the Host's Tenant is when its database
|
|
39
|
+
* holds none yet (`NYLORUN_TENANT_ID`, `NYLORUN_TENANT_NAME`).
|
|
29
40
|
*/
|
|
30
|
-
import {
|
|
31
|
-
|
|
41
|
+
import { isTenantId } from "@nylorun/core/compatibility";
|
|
42
|
+
import { blockedAddresses } from "../sandbox/pods/network-gate.js";
|
|
43
|
+
export const RUNTIME_SERVICES = ["core", "loop", "gates", "keys", "egress", "harness"];
|
|
32
44
|
/**
|
|
33
45
|
* Services that may share a process (D12): they hold the same secrets and parse the same
|
|
34
|
-
* trust class of input. keys joins gates (F4.2)
|
|
46
|
+
* trust class of input. keys joins gates (F4.2), and egress joins them (F7.2). The harness
|
|
47
|
+
* (F6.2) runs agent code's neighbours and holds only its own credential: it shares with nothing.
|
|
35
48
|
*/
|
|
36
49
|
const SERVICE_GROUPS = [
|
|
37
50
|
["core", "loop"],
|
|
38
|
-
["gates", "keys"],
|
|
51
|
+
["gates", "keys", "egress"],
|
|
52
|
+
["harness"],
|
|
39
53
|
];
|
|
40
54
|
/** Where the gates service listens by default. */
|
|
41
55
|
export const DEFAULT_GATES_LISTEN_PORT = 4100;
|
|
56
|
+
/** Where egress-gate listens by default. */
|
|
57
|
+
export const DEFAULT_EGRESS_LISTEN_PORT = 4200;
|
|
58
|
+
/** Where core's Harness API listener listens by default. */
|
|
59
|
+
export const DEFAULT_HARNESS_LISTEN_PORT = 4200;
|
|
60
|
+
/** Where a harness process answers `/health` (loopback only). */
|
|
61
|
+
export const DEFAULT_HARNESS_HEALTH_PORT = 4300;
|
|
42
62
|
/** What a process runs without `--service`: core and loop, as `--role all` did. */
|
|
43
63
|
export const DEFAULT_SERVICES = new Set([
|
|
44
64
|
"core",
|
|
@@ -46,8 +66,6 @@ export const DEFAULT_SERVICES = new Set([
|
|
|
46
66
|
]);
|
|
47
67
|
/** Services of the blueprint this release doesn't have yet. */
|
|
48
68
|
const LATER_SERVICES = [
|
|
49
|
-
"egress",
|
|
50
|
-
"harness",
|
|
51
69
|
"sandboxd",
|
|
52
70
|
];
|
|
53
71
|
const ROLE_SERVICES = {
|
|
@@ -74,7 +92,7 @@ function read(env, name) {
|
|
|
74
92
|
const trimmed = value.trim();
|
|
75
93
|
return trimmed === "" ? undefined : trimmed;
|
|
76
94
|
}
|
|
77
|
-
const USAGE = "Usage: main.js [--service core,loop|gates]";
|
|
95
|
+
const USAGE = "Usage: main.js [--service core,loop|gates,keys,egress|harness]";
|
|
78
96
|
/** Parses `--service a,b` (or the deprecated `--role`); throws `StackConfigError`. */
|
|
79
97
|
export function parseServices(argv) {
|
|
80
98
|
let service;
|
|
@@ -248,11 +266,14 @@ function parseIdentityKeys(env) {
|
|
|
248
266
|
/** Parse the stack configuration; throws `StackConfigError` naming the variable. */
|
|
249
267
|
export function parseStackConfig(env, argv) {
|
|
250
268
|
const { services, deprecatedRole } = parseServices(argv);
|
|
269
|
+
if (services.has("harness"))
|
|
270
|
+
return { services, harness: parseHarnessService(env), endpoints: {} };
|
|
251
271
|
// The image sets NYLORUN_LISTEN_*: only the API's processes read them.
|
|
252
272
|
const servesApi = services.has("core") || services.has("loop");
|
|
253
273
|
const listen = servesApi ? parseListen(env) : undefined;
|
|
254
274
|
const operator = servesApi ? parseAdminListen(env) : undefined;
|
|
255
275
|
const gates = services.has("gates") || services.has("keys") ? parseGates(env) : undefined;
|
|
276
|
+
const egress = services.has("egress") ? parseEgress(env) : undefined;
|
|
256
277
|
// The gates service's clients: the loop's model and tool calls, and core's endpoint pings.
|
|
257
278
|
const modelGate = servesApi ? parseModelGate(env) : undefined;
|
|
258
279
|
// The keys service is the gateway's unless NYLORUN_KEYS_URL names another listener.
|
|
@@ -299,43 +320,198 @@ export function parseStackConfig(env, argv) {
|
|
|
299
320
|
if (restateIdentityKeys)
|
|
300
321
|
endpoints.restateIdentityKeys = restateIdentityKeys;
|
|
301
322
|
const publicUrl = parseUrl(env, "NYLORUN_PUBLIC_URL", http)?.replace(/\/+$/, "");
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
323
|
+
const harnessMode = servesApi ? parseHarnessMode(env) : undefined;
|
|
324
|
+
const sandboxes = servesApi ? parseSandboxes(env) : undefined;
|
|
325
|
+
// Pods connect to the Harness API listener even when the Tenant runs its own harness.
|
|
326
|
+
const harnessListener = harnessMode === "remote" || sandboxes
|
|
327
|
+
? parseHarnessListener(env, harnessMode === "remote")
|
|
328
|
+
: undefined;
|
|
329
|
+
if (harnessListener &&
|
|
330
|
+
[listen?.port, operator?.port].includes(harnessListener.listen.port))
|
|
331
|
+
throw new StackConfigError("NYLORUN_HARNESS_LISTEN_PORT must differ from NYLORUN_LISTEN_PORT and NYLORUN_ADMIN_LISTEN_PORT");
|
|
305
332
|
const delivery = parseDelivery(env);
|
|
306
333
|
const tenant = servesApi ? parseTenant(env) : undefined;
|
|
334
|
+
const objectStore = parseObjectStore(env);
|
|
307
335
|
return {
|
|
308
336
|
services,
|
|
309
337
|
...(deprecatedRole ? { deprecatedRole } : {}),
|
|
310
338
|
...(gates ? { gates } : {}),
|
|
339
|
+
...(egress ? { egress } : {}),
|
|
311
340
|
...(modelGate ? { modelGate } : {}),
|
|
312
341
|
...(keys ? { keys } : {}),
|
|
313
342
|
...(rawPacking ? { packing: rawPacking } : {}),
|
|
314
343
|
...(listen ? { listen } : {}),
|
|
315
344
|
endpoints,
|
|
316
345
|
...(publicUrl ? { publicUrl } : {}),
|
|
317
|
-
...(
|
|
346
|
+
...(harnessMode ? { harnessMode } : {}),
|
|
347
|
+
...(harnessListener ? { harnessListener } : {}),
|
|
348
|
+
...(sandboxes ? { sandboxes } : {}),
|
|
318
349
|
...(operator ? { operator } : {}),
|
|
319
350
|
...(delivery ? { delivery } : {}),
|
|
320
351
|
...(tenant ? { tenant } : {}),
|
|
352
|
+
...(objectStore ? { objectStore } : {}),
|
|
321
353
|
};
|
|
322
354
|
}
|
|
355
|
+
/** S3 bucket names: 3 to 63 lowercase letters, digits, dots and hyphens. */
|
|
356
|
+
const BUCKET = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;
|
|
357
|
+
/** `StackConfig.objectStore` from `NYLORUN_OBJECT_STORE_*`, or `undefined` without an endpoint. */
|
|
358
|
+
function parseObjectStore(env) {
|
|
359
|
+
const endpoint = parseUrl(env, "NYLORUN_OBJECT_STORE_ENDPOINT", ["http:", "https:"]);
|
|
360
|
+
const accessKeyId = read(env, "NYLORUN_OBJECT_STORE_ACCESS_KEY");
|
|
361
|
+
const secretAccessKey = read(env, "NYLORUN_OBJECT_STORE_SECRET_KEY");
|
|
362
|
+
if (endpoint === undefined) {
|
|
363
|
+
if (accessKeyId !== undefined || secretAccessKey !== undefined)
|
|
364
|
+
throw new StackConfigError("NYLORUN_OBJECT_STORE_ACCESS_KEY or _SECRET_KEY is set without NYLORUN_OBJECT_STORE_ENDPOINT: set the S3 endpoint, e.g. http://rustfs:9000");
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
367
|
+
if (accessKeyId === undefined || secretAccessKey === undefined)
|
|
368
|
+
throw new StackConfigError("NYLORUN_OBJECT_STORE_ACCESS_KEY and NYLORUN_OBJECT_STORE_SECRET_KEY are required with NYLORUN_OBJECT_STORE_ENDPOINT (`nylorun start` sets them)");
|
|
369
|
+
const bucket = read(env, "NYLORUN_OBJECT_STORE_BUCKET") ?? "nylorun";
|
|
370
|
+
if (!BUCKET.test(bucket))
|
|
371
|
+
throw new StackConfigError(`NYLORUN_OBJECT_STORE_BUCKET must be an S3 bucket name (3 to 63 of a-z 0-9 . -), not ${bucket}`);
|
|
372
|
+
const region = read(env, "NYLORUN_OBJECT_STORE_REGION") ?? "us-east-1";
|
|
373
|
+
if (!/^[a-z0-9-]+$/.test(region))
|
|
374
|
+
throw new StackConfigError(`NYLORUN_OBJECT_STORE_REGION is not a region: ${region}`);
|
|
375
|
+
return { endpoint: endpoint.replace(/\/+$/, ""), bucket, region, accessKeyId, secretAccessKey };
|
|
376
|
+
}
|
|
323
377
|
function parseTenant(env) {
|
|
324
378
|
const id = read(env, "NYLORUN_TENANT_ID");
|
|
325
379
|
if (id !== undefined && !isTenantId(id))
|
|
326
380
|
throw new StackConfigError(`NYLORUN_TENANT_ID must be a Tenant id (tn_ and 26 Crockford characters), not ${id}`);
|
|
327
|
-
const
|
|
328
|
-
const derivedPrincipals = raw === undefined ? ["project"] : raw.split(",").map((entry) => entry.trim());
|
|
329
|
-
for (const principal of derivedPrincipals)
|
|
330
|
-
if (!DERIVED_PRINCIPAL_ID_PATTERN.test(principal) || principal === "studio")
|
|
331
|
-
throw new StackConfigError(`NYLORUN_DERIVED_PRINCIPALS has '${principal}': each entry must match ${DERIVED_PRINCIPAL_ID_PATTERN} and not be studio`);
|
|
381
|
+
const identityFile = read(env, "NYLORUN_IDENTITY_FILE");
|
|
332
382
|
return {
|
|
333
383
|
...(id ? { id } : {}),
|
|
334
384
|
name: read(env, "NYLORUN_TENANT_NAME") ?? "default",
|
|
335
|
-
|
|
385
|
+
...(identityFile ? { identityFile } : {}),
|
|
336
386
|
};
|
|
337
387
|
}
|
|
338
388
|
const GATES_TOKEN = /^[0-9a-f]{64,}$/i;
|
|
389
|
+
/** `NYLORUN_HARNESS`: `in-process` (the default when unset) or `remote`. */
|
|
390
|
+
function parseHarnessMode(env) {
|
|
391
|
+
const raw = read(env, "NYLORUN_HARNESS");
|
|
392
|
+
if (raw === undefined)
|
|
393
|
+
return undefined;
|
|
394
|
+
if (raw !== "in-process" && raw !== "remote")
|
|
395
|
+
throw new StackConfigError(`NYLORUN_HARNESS must be in-process or remote, not ${raw}`);
|
|
396
|
+
return raw;
|
|
397
|
+
}
|
|
398
|
+
function parseHarnessToken(env, why) {
|
|
399
|
+
const token = read(env, "NYLORUN_HARNESS_TOKEN");
|
|
400
|
+
if (token === undefined)
|
|
401
|
+
throw new StackConfigError(`NYLORUN_HARNESS_TOKEN is required ${why} (\`nylorun start\` sets it)`);
|
|
402
|
+
if (!GATES_TOKEN.test(token))
|
|
403
|
+
throw new StackConfigError("NYLORUN_HARNESS_TOKEN must be at least 32 bytes as hex");
|
|
404
|
+
return token;
|
|
405
|
+
}
|
|
406
|
+
/** `StackConfig.sandboxes` from `NYLORUN_SANDBOXES_*`, or undefined without a URL. */
|
|
407
|
+
function parseSandboxes(env) {
|
|
408
|
+
const url = parseUrl(env, "NYLORUN_SANDBOXES_URL", ["http:", "https:"]);
|
|
409
|
+
if (url === undefined)
|
|
410
|
+
return undefined;
|
|
411
|
+
const token = read(env, "NYLORUN_SANDBOXES_TOKEN");
|
|
412
|
+
if (token === undefined || token.length < 32)
|
|
413
|
+
throw new StackConfigError("NYLORUN_SANDBOXES_TOKEN (at least 32 characters) is required with NYLORUN_SANDBOXES_URL (`nylorun sandbox enable` sets both)");
|
|
414
|
+
const harnessImage = read(env, "NYLORUN_SANDBOX_HARNESS_IMAGE");
|
|
415
|
+
if (harnessImage === undefined || /\s/.test(harnessImage))
|
|
416
|
+
throw new StackConfigError("NYLORUN_SANDBOX_HARNESS_IMAGE is required with NYLORUN_SANDBOXES_URL: the Runtime image sandbox pods copy the engine from (`nylorun start` sets it)");
|
|
417
|
+
return { url: url.replace(/\/+$/, ""), token, harnessImage };
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* `StackConfig.harnessListener` from `NYLORUN_HARNESS_LISTEN_*` and `NYLORUN_HARNESS_TOKEN`
|
|
421
|
+
* (required with `NYLORUN_HARNESS=remote`; optional when only sandbox pods connect).
|
|
422
|
+
*/
|
|
423
|
+
function parseHarnessListener(env, tokenRequired = true) {
|
|
424
|
+
const host = read(env, "NYLORUN_HARNESS_LISTEN_HOST") ?? DEFAULT_CONTAINER_LISTEN_HOST;
|
|
425
|
+
if (/\s|\//.test(host))
|
|
426
|
+
throw new StackConfigError(`NYLORUN_HARNESS_LISTEN_HOST is not an address: ${host}`);
|
|
427
|
+
const rawPort = read(env, "NYLORUN_HARNESS_LISTEN_PORT");
|
|
428
|
+
const port = rawPort === undefined
|
|
429
|
+
? DEFAULT_HARNESS_LISTEN_PORT
|
|
430
|
+
: parsePort("NYLORUN_HARNESS_LISTEN_PORT", rawPort);
|
|
431
|
+
const rawAllowed = read(env, "NYLORUN_HARNESS_ALLOWED_HOSTS");
|
|
432
|
+
const explicit = rawAllowed === undefined
|
|
433
|
+
? []
|
|
434
|
+
: rawAllowed
|
|
435
|
+
.split(",")
|
|
436
|
+
.map((entry) => entry.trim())
|
|
437
|
+
.filter((entry) => entry !== "")
|
|
438
|
+
.map((entry) => normalizeAllowedHost("NYLORUN_HARNESS_ALLOWED_HOSTS", entry));
|
|
439
|
+
if (explicit.length === 0 && !isLoopbackAddress(host))
|
|
440
|
+
throw new StackConfigError(`NYLORUN_HARNESS_ALLOWED_HOSTS is required when NYLORUN_HARNESS_LISTEN_HOST is ${host}: list the Host headers harnesses send, e.g. runtime:${port}`);
|
|
441
|
+
const token = tokenRequired || read(env, "NYLORUN_HARNESS_TOKEN") !== undefined
|
|
442
|
+
? parseHarnessToken(env, "with NYLORUN_HARNESS=remote: the credential harnesses present")
|
|
443
|
+
: undefined;
|
|
444
|
+
return {
|
|
445
|
+
listen: { host, port, allowedHosts: [...new Set([...explicit, ...loopbackForms(port)])] },
|
|
446
|
+
...(token ? { token } : {}),
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
/** What a harness process must not hold: it runs next to agent code. */
|
|
450
|
+
const HARNESS_REFUSED = ["NYLORUN_DATABASE_URL", "NYLORUN_GATES_TOKEN", "NYLORUN_KEYS_URL"];
|
|
451
|
+
/** `StackConfig.harness` from `NYLORUN_HARNESS_*` and `NYLORUN_GATES_URL`. */
|
|
452
|
+
function parseHarnessService(env) {
|
|
453
|
+
const held = [
|
|
454
|
+
...HARNESS_REFUSED.filter((name) => read(env, name) !== undefined),
|
|
455
|
+
...Object.keys(env)
|
|
456
|
+
.filter((name) => name.startsWith("NYLORUN_RESTATE_") && read(env, name) !== undefined)
|
|
457
|
+
.sort(),
|
|
458
|
+
];
|
|
459
|
+
if (held.length > 0)
|
|
460
|
+
throw new StackConfigError(`--service harness refuses to start with ${held.join(", ")} set: a harness reaches no database, no gate or keys credential and no Restate`);
|
|
461
|
+
const pod = read(env, "NYLORUN_SANDBOX_KIND") === "pod";
|
|
462
|
+
const url = parseUrl(env, "NYLORUN_HARNESS_URL", pod ? ["http:", "https:", "ws:", "wss:"] : ["ws:", "wss:"]);
|
|
463
|
+
if (url === undefined)
|
|
464
|
+
throw new StackConfigError("NYLORUN_HARNESS_URL is required for --service harness: core's Harness API, e.g. ws://runtime:4200/nylorun/harness/v1");
|
|
465
|
+
const gatesUrl = parseUrl(env, "NYLORUN_GATES_URL", ["http:", "https:"]);
|
|
466
|
+
if (gatesUrl === undefined)
|
|
467
|
+
throw new StackConfigError("NYLORUN_GATES_URL is required for --service harness: its model and MCP calls go through the gates service, e.g. http://gateway:4100");
|
|
468
|
+
const root = read(env, "NYLORUN_HARNESS_ROOT") ?? "/harness";
|
|
469
|
+
if (!root.startsWith("/"))
|
|
470
|
+
throw new StackConfigError(`NYLORUN_HARNESS_ROOT must be an absolute path, not ${root}`);
|
|
471
|
+
const rawHealth = read(env, "NYLORUN_HARNESS_HEALTH_PORT");
|
|
472
|
+
const podHost = pod ? parsePodHost(env, url) : undefined;
|
|
473
|
+
return {
|
|
474
|
+
url: podHost ? podHost.wsUrl : url,
|
|
475
|
+
...(podHost
|
|
476
|
+
? { pod: podHost.config }
|
|
477
|
+
: { token: parseHarnessToken(env, "for --service harness: the credential core's Harness API accepts") }),
|
|
478
|
+
gatesUrl: gatesUrl.replace(/\/+$/, ""),
|
|
479
|
+
root,
|
|
480
|
+
healthPort: rawHealth === undefined
|
|
481
|
+
? DEFAULT_HARNESS_HEALTH_PORT
|
|
482
|
+
: parsePort("NYLORUN_HARNESS_HEALTH_PORT", rawHealth),
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* The engine in a pod sandbox: the pod's identity and its join file, from the variables the
|
|
487
|
+
* sandboxes service renders into the pod. `NYLORUN_HARNESS_URL` is the listener's address on the
|
|
488
|
+
* Docker host (`http://<host>:<port>`); the WebSocket URL adds the Harness API path.
|
|
489
|
+
*/
|
|
490
|
+
function parsePodHost(env, url) {
|
|
491
|
+
const need = (name) => {
|
|
492
|
+
const value = read(env, name);
|
|
493
|
+
if (value === undefined)
|
|
494
|
+
throw new StackConfigError(`${name} is required for the engine in a sandbox pod (NYLORUN_SANDBOX_KIND=pod)`);
|
|
495
|
+
return value;
|
|
496
|
+
};
|
|
497
|
+
if (read(env, "NYLORUN_HARNESS_TOKEN") !== undefined)
|
|
498
|
+
throw new StackConfigError("A sandbox pod's engine holds no NYLORUN_HARNESS_TOKEN: it joins with its join token");
|
|
499
|
+
const base = new URL(url);
|
|
500
|
+
const secure = base.protocol === "https:" || base.protocol === "wss:";
|
|
501
|
+
const origin = `${secure ? "https" : "http"}://${base.host}`;
|
|
502
|
+
const egress = read(env, "NYLORUN_EGRESS_PROXY");
|
|
503
|
+
return {
|
|
504
|
+
wsUrl: `${secure ? "wss" : "ws"}://${base.host}/nylorun/harness/v1`,
|
|
505
|
+
config: {
|
|
506
|
+
sandboxId: need("NYLORUN_SANDBOX_ID"),
|
|
507
|
+
podUid: need("NYLORUN_POD_UID"),
|
|
508
|
+
joinFile: need("NYLORUN_SANDBOX_JOIN_FILE"),
|
|
509
|
+
httpUrl: origin,
|
|
510
|
+
...(egress ? { egressProxy: egress.replace(/\/+$/, "") } : {}),
|
|
511
|
+
blocked: blockedAddresses(env),
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
}
|
|
339
515
|
/** `StackConfig.gates` from `NYLORUN_GATES_*`. */
|
|
340
516
|
function parseGates(env) {
|
|
341
517
|
const host = read(env, "NYLORUN_GATES_LISTEN_HOST") ?? DEFAULT_CONTAINER_LISTEN_HOST;
|
|
@@ -360,11 +536,37 @@ function parseGates(env) {
|
|
|
360
536
|
throw new StackConfigError("NYLORUN_GATES_TOKEN is required for --service gates: the token the loop presents (`nylorun start` sets it)");
|
|
361
537
|
if (!GATES_TOKEN.test(token))
|
|
362
538
|
throw new StackConfigError("NYLORUN_GATES_TOKEN must be at least 32 bytes as hex");
|
|
539
|
+
const resolver = parseResolver(env);
|
|
363
540
|
return {
|
|
364
541
|
listen: { host, port, allowedHosts: [...new Set([...explicit, ...loopbackForms(port)])] },
|
|
365
542
|
token,
|
|
543
|
+
...(resolver ? { resolver } : {}),
|
|
366
544
|
};
|
|
367
545
|
}
|
|
546
|
+
/** `GatesConfig.resolver` from `NYLORUN_RESOLVER_URL` and `NYLORUN_RESOLVER_TOKEN`: both or neither. */
|
|
547
|
+
function parseResolver(env) {
|
|
548
|
+
const url = parseUrl(env, "NYLORUN_RESOLVER_URL", ["http:", "https:"]);
|
|
549
|
+
const token = read(env, "NYLORUN_RESOLVER_TOKEN");
|
|
550
|
+
if (url === undefined) {
|
|
551
|
+
if (token !== undefined)
|
|
552
|
+
throw new StackConfigError("NYLORUN_RESOLVER_TOKEN is set without NYLORUN_RESOLVER_URL: set the URL of your credential resolver");
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
if (token === undefined)
|
|
556
|
+
throw new StackConfigError("NYLORUN_RESOLVER_TOKEN is required with NYLORUN_RESOLVER_URL: the bearer the gateway presents to your credential resolver");
|
|
557
|
+
if (/\s/.test(token))
|
|
558
|
+
throw new StackConfigError("NYLORUN_RESOLVER_TOKEN cannot contain whitespace");
|
|
559
|
+
return { url, token };
|
|
560
|
+
}
|
|
561
|
+
/** `StackConfig.egress` from `NYLORUN_EGRESS_LISTEN_*`. CONNECT has no Host header to check. */
|
|
562
|
+
function parseEgress(env) {
|
|
563
|
+
const host = read(env, "NYLORUN_EGRESS_LISTEN_HOST") ?? DEFAULT_CONTAINER_LISTEN_HOST;
|
|
564
|
+
if (/\s|\//.test(host))
|
|
565
|
+
throw new StackConfigError(`NYLORUN_EGRESS_LISTEN_HOST is not an address: ${host}`);
|
|
566
|
+
const rawPort = read(env, "NYLORUN_EGRESS_LISTEN_PORT");
|
|
567
|
+
const port = rawPort === undefined ? DEFAULT_EGRESS_LISTEN_PORT : parsePort("NYLORUN_EGRESS_LISTEN_PORT", rawPort);
|
|
568
|
+
return { listen: { host, port } };
|
|
569
|
+
}
|
|
368
570
|
/** `StackConfig.modelGate` from `NYLORUN_GATES_URL` and `NYLORUN_GATES_TOKEN`. */
|
|
369
571
|
function parseModelGate(env) {
|
|
370
572
|
const url = parseUrl(env, "NYLORUN_GATES_URL", ["http:", "https:"]);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export { openTenantRuntime, type TenantOpenHooks, } from "./tenant/runtime.js";
|
|
2
2
|
export { startEphemeralRuntime, type StartEphemeralRuntimeOptions, type EphemeralRuntime, } from "./tenant/ephemeral.js";
|
|
3
|
+
export { parseIdentityFile, IdentityFileError, type TrustedIssuerConfig, } from "./tenant/identity-file.js";
|
|
4
|
+
export { createTrustedIssuers, type TrustedIssuers, type TrustedIssuersOptions, } from "./tenant/issuers.js";
|
|
3
5
|
export type { TenantConfig, TenantHandle, TenantPaths, Logger, OpenTenantRuntime, } from "./tenant/types.js";
|
|
4
6
|
export { scriptedModel, gatewayModel, type ModelProvider } from "./core/provider.js";
|
|
7
|
+
export type { ResolverConfig } from "./vault/sources.js";
|
|
5
8
|
export type { RuntimeAgent } from "./contracts.js";
|
|
6
9
|
export { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, validateImageBytes, } from "./media.js";
|
|
7
10
|
export type { RuntimeModelAdapter } from "./contracts.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { openTenantRuntime, } from "./tenant/runtime.js";
|
|
2
2
|
export { startEphemeralRuntime, } from "./tenant/ephemeral.js";
|
|
3
|
+
export { parseIdentityFile, IdentityFileError, } from "./tenant/identity-file.js";
|
|
4
|
+
export { createTrustedIssuers, } from "./tenant/issuers.js";
|
|
3
5
|
export { scriptedModel, gatewayModel } from "./core/provider.js";
|
|
4
6
|
export { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, validateImageBytes, } from "./media.js";
|
|
5
7
|
export { baselineEnvironment, hostProcessEnvironment, tenantChildEnvironment, } from "./host/environment.js";
|
package/dist/keys/client.js
CHANGED
|
@@ -12,10 +12,18 @@ import { KEYS_PATH } from "./contract.js";
|
|
|
12
12
|
import { KEYS_OPERATIONS } from "./keys.js";
|
|
13
13
|
/** Signing and vault writes are short; anything slower is a gateway in trouble. */
|
|
14
14
|
const KEYS_TIMEOUT_MS = 30_000;
|
|
15
|
+
/**
|
|
16
|
+
* MCP OAuth connect calls the authorization server several times (discovery, registration, the
|
|
17
|
+
* code exchange), each bounded by `guardedFetch`'s 30 s: these wait longer.
|
|
18
|
+
*/
|
|
19
|
+
const SLOW_OPERATIONS = {
|
|
20
|
+
startOAuth: 120_000,
|
|
21
|
+
finishOAuth: 60_000,
|
|
22
|
+
};
|
|
15
23
|
export function httpKeys(options) {
|
|
16
24
|
const where = new URL(options.url).origin;
|
|
17
|
-
const timeoutMs = options.timeoutMs ?? KEYS_TIMEOUT_MS;
|
|
18
25
|
function call(operation, args) {
|
|
26
|
+
const timeoutMs = Math.max(options.timeoutMs ?? KEYS_TIMEOUT_MS, SLOW_OPERATIONS[operation] ?? 0);
|
|
19
27
|
const url = new URL(`${KEYS_PATH}/${operation}`, options.url);
|
|
20
28
|
const send = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
21
29
|
const payload = Buffer.from(JSON.stringify({ args }), "utf8");
|
package/dist/keys/keys.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreateCredentialRequest, CredentialInfo, HostModelView, PutHostModelRequest, RotateCredentialRequest, SelectHostModelRequest, SigningKeyView } from "@nylorun/core/contracts";
|
|
2
2
|
import type { SessionStore } from "../store/types.js";
|
|
3
3
|
import { type SigningKeys } from "../tenant/signing-keys.js";
|
|
4
|
-
import type { VaultService } from "../vault/service.js";
|
|
4
|
+
import type { FinishOAuthInput, StartOAuthInput, VaultService } from "../vault/service.js";
|
|
5
5
|
/** One JWT to sign: its `typ` and every claim, `iss`, `aud`, `sub`, `iat`, `exp` and `jti` included. */
|
|
6
6
|
export interface SignRequest {
|
|
7
7
|
readonly typ: string;
|
|
@@ -26,9 +26,19 @@ export interface Keys {
|
|
|
26
26
|
}): Promise<SigningKeyView[]>;
|
|
27
27
|
/** Creates the current and standby keys when the Tenant has none. */
|
|
28
28
|
ensureSigningKeys(): Promise<void>;
|
|
29
|
+
/** Starts an MCP OAuth connect into an installation vault (`VaultService.startOAuth`). */
|
|
30
|
+
startOAuth(input: StartOAuthInput): Promise<{
|
|
31
|
+
authorizeUrl: string;
|
|
32
|
+
expiresAt: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** Finishes one from its callback (`VaultService.finishOAuth`). */
|
|
35
|
+
finishOAuth(input: FinishOAuthInput): Promise<{
|
|
36
|
+
vaultId: string;
|
|
37
|
+
credentialId: string;
|
|
38
|
+
}>;
|
|
29
39
|
}
|
|
30
40
|
/** The operations, by the name the HTTP route carries. */
|
|
31
|
-
export declare const KEYS_OPERATIONS: readonly ["createCredential", "rotateCredential", "putHostModel", "selectHostModel", "sign", "rotateSigningKeys", "ensureSigningKeys"];
|
|
41
|
+
export declare const KEYS_OPERATIONS: readonly ["createCredential", "rotateCredential", "putHostModel", "selectHostModel", "sign", "rotateSigningKeys", "ensureSigningKeys", "startOAuth", "finishOAuth"];
|
|
32
42
|
export type KeysOperation = (typeof KEYS_OPERATIONS)[number];
|
|
33
43
|
export interface InProcessKeysOptions {
|
|
34
44
|
readonly store: SessionStore;
|
package/dist/keys/keys.js
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* delivery tokens, signing-key rotation) run here, whole, so the process that calls them never
|
|
6
6
|
* holds the key or a private signing key.
|
|
7
7
|
*
|
|
8
|
+
* MCP OAuth connect (F9-D14) runs here too: discovery, registration, the code exchange and the
|
|
9
|
+
* credential it seals, so the plaintext tokens, the PKCE verifier and any client secret never
|
|
10
|
+
* reach the runtime container; core only routes the start and the callback.
|
|
11
|
+
*
|
|
8
12
|
* Two implementations: `inProcessKeys` (embedding, the ephemeral Runtime, tests, and the gates
|
|
9
13
|
* service itself, which serves the HTTP routes with it), and `httpKeys` (`client.ts`), the
|
|
10
14
|
* runtime container's client of the `keys` service in the gateway.
|
|
@@ -20,6 +24,8 @@ export const KEYS_OPERATIONS = [
|
|
|
20
24
|
"sign",
|
|
21
25
|
"rotateSigningKeys",
|
|
22
26
|
"ensureSigningKeys",
|
|
27
|
+
"startOAuth",
|
|
28
|
+
"finishOAuth",
|
|
23
29
|
];
|
|
24
30
|
export function inProcessKeys(options) {
|
|
25
31
|
const { store, vault, signingKeys, kek } = options;
|
|
@@ -28,6 +34,8 @@ export function inProcessKeys(options) {
|
|
|
28
34
|
rotateCredential: (vaultId, id, body) => vault.rotateCredential(vaultId, id, body),
|
|
29
35
|
putHostModel: (body) => vault.putHostModel(body),
|
|
30
36
|
selectHostModel: (body) => vault.selectHostModel(body),
|
|
37
|
+
startOAuth: (input) => vault.startOAuth(input),
|
|
38
|
+
finishOAuth: (input) => vault.finishOAuth(input),
|
|
31
39
|
async sign(request) {
|
|
32
40
|
const key = kek();
|
|
33
41
|
const row = await store.tx((t) => signingKeys.ensure(t, key));
|
package/dist/mcp/connect.js
CHANGED
|
@@ -162,7 +162,8 @@ function authorizedFetch(server, authorize) {
|
|
|
162
162
|
headers.set(key, value);
|
|
163
163
|
new Headers(init?.headers).forEach((value, key) => headers.set(key, value));
|
|
164
164
|
if (result.status === "authorized")
|
|
165
|
-
|
|
165
|
+
for (const [key, value] of Object.entries(result.headers))
|
|
166
|
+
headers.set(key, value);
|
|
166
167
|
return fetch(target, { ...init, headers, redirect: "error" });
|
|
167
168
|
};
|
|
168
169
|
}
|
package/dist/mcp/pool.d.ts
CHANGED
package/dist/mcp/pool.js
CHANGED
package/dist/mcp/snapshot.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { JsonObject } from "@nylorun/core/define";
|
|
2
|
-
import type
|
|
2
|
+
import { type AgentManifest } from "@nylorun/core/define";
|
|
3
|
+
import type { DurableSessionTool, HostEffect } from "@nylorun/harness/run";
|
|
3
4
|
export interface McpToolRecord {
|
|
4
5
|
/** The agent used as a tool that declares the server; absent for the session's root agent. */
|
|
5
6
|
readonly agentId?: string;
|
|
@@ -27,3 +28,9 @@ export interface McpDiagnostic {
|
|
|
27
28
|
}
|
|
28
29
|
export declare function modelToolName(serverName: string, serverToolName: string): string;
|
|
29
30
|
export declare function declaredToolNames(manifest: AgentManifest): Set<string>;
|
|
31
|
+
/** The tools of a snapshot, as the engine advertises them. */
|
|
32
|
+
export declare function sessionToolsOf(snapshot: McpSnapshot | undefined): readonly DurableSessionTool[] | undefined;
|
|
33
|
+
/** The snapshot's record of an MCP tool call, or undefined when the call is not an MCP tool. */
|
|
34
|
+
export declare function mcpToolOf(snapshot: McpSnapshot | undefined, request: Pick<HostEffect, "agent" | "capabilityId" | "toolName">): McpToolRecord | undefined;
|
|
35
|
+
/** The manifest of the agent an effect belongs to: the root, or an agent it uses as a tool. */
|
|
36
|
+
export declare function manifestFor(manifest: AgentManifest, agent: HostEffect["agent"]): AgentManifest | undefined;
|
package/dist/mcp/snapshot.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { delegateManifest } from "@nylorun/core/define";
|
|
1
2
|
export function modelToolName(serverName, serverToolName) {
|
|
2
3
|
return `${serverName}__${serverToolName}`;
|
|
3
4
|
}
|
|
@@ -8,3 +9,30 @@ export function declaredToolNames(manifest) {
|
|
|
8
9
|
names.add(tool.name);
|
|
9
10
|
return names;
|
|
10
11
|
}
|
|
12
|
+
/** The tools of a snapshot, as the engine advertises them. */
|
|
13
|
+
export function sessionToolsOf(snapshot) {
|
|
14
|
+
if (!snapshot?.mcpTools.length)
|
|
15
|
+
return undefined;
|
|
16
|
+
return snapshot.mcpTools.map((tool) => ({
|
|
17
|
+
...(tool.agentId === undefined ? {} : { agentId: tool.agentId }),
|
|
18
|
+
capabilityId: tool.capabilityId,
|
|
19
|
+
name: tool.name,
|
|
20
|
+
...(tool.description === undefined
|
|
21
|
+
? {}
|
|
22
|
+
: { description: tool.description }),
|
|
23
|
+
inputSchema: tool.inputSchema,
|
|
24
|
+
...(tool.outputSchema === undefined
|
|
25
|
+
? {}
|
|
26
|
+
: { outputSchema: tool.outputSchema }),
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
/** The snapshot's record of an MCP tool call, or undefined when the call is not an MCP tool. */
|
|
30
|
+
export function mcpToolOf(snapshot, request) {
|
|
31
|
+
return snapshot?.mcpTools.find((tool) => tool.agentId === request.agent?.id &&
|
|
32
|
+
tool.capabilityId === request.capabilityId &&
|
|
33
|
+
tool.name === request.toolName);
|
|
34
|
+
}
|
|
35
|
+
/** The manifest of the agent an effect belongs to: the root, or an agent it uses as a tool. */
|
|
36
|
+
export function manifestFor(manifest, agent) {
|
|
37
|
+
return agent ? delegateManifest(manifest, agent.id) : manifest;
|
|
38
|
+
}
|
package/dist/media.d.ts
CHANGED
|
@@ -1,29 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image checks for code that handles image bytes itself (an image tool in an Action endpoint):
|
|
3
|
+
* the supported types, the size cap and a signature check. Storing images is the job of file
|
|
4
|
+
* artifacts (`artifacts/`, protocol 6), which replaced `MediaStore`.
|
|
5
|
+
*/
|
|
1
6
|
export declare const IMAGE_MEDIA_TYPES: readonly string[];
|
|
2
7
|
export declare const MAX_IMAGE_BYTES: number;
|
|
3
|
-
export interface MediaAsset {
|
|
4
|
-
readonly id: string;
|
|
5
|
-
readonly mediaType: string;
|
|
6
|
-
readonly bytes: number;
|
|
7
|
-
readonly kind: "input" | "generated";
|
|
8
|
-
}
|
|
9
|
-
/** Opaque reference retained by Harness and resolved by the configured media adapter. */
|
|
10
|
-
export interface MediaReference {
|
|
11
|
-
readonly agentId: string;
|
|
12
|
-
readonly assetId: string;
|
|
13
|
-
}
|
|
14
8
|
export declare function decodeImageBase64(mediaType: string, base64: string): Uint8Array;
|
|
15
9
|
/** Verify the asserted media type and lightweight file signature for a supported image. */
|
|
16
10
|
export declare function validateImageBytes(mediaType: string, bytes: Uint8Array): void;
|
|
17
|
-
export interface RuntimeMedia {
|
|
18
|
-
saveInput(agentId: string, sessionId: string, mediaType: string, base64: string): Promise<MediaAsset>;
|
|
19
|
-
saveGenerated(agentId: string, sessionId: string, mediaType: string, bytes: Uint8Array): Promise<MediaAsset>;
|
|
20
|
-
dataUrl(reference: MediaReference, sessionId: string): Promise<{
|
|
21
|
-
readonly asset: MediaAsset;
|
|
22
|
-
readonly url: string;
|
|
23
|
-
} | undefined>;
|
|
24
|
-
latestInput(agentId: string, sessionId: string): Promise<MediaAsset | undefined>;
|
|
25
|
-
read(agentId: string, sessionId: string, assetId: string): Promise<{
|
|
26
|
-
asset: MediaAsset;
|
|
27
|
-
bytes: Uint8Array;
|
|
28
|
-
} | undefined>;
|
|
29
|
-
}
|
package/dist/media.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image checks for code that handles image bytes itself (an image tool in an Action endpoint):
|
|
3
|
+
* the supported types, the size cap and a signature check. Storing images is the job of file
|
|
4
|
+
* artifacts (`artifacts/`, protocol 6), which replaced `MediaStore`.
|
|
5
|
+
*/
|
|
1
6
|
export const IMAGE_MEDIA_TYPES = Object.freeze([
|
|
2
7
|
"image/jpeg",
|
|
3
8
|
"image/png",
|
package/dist/model/pi-model.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Credential } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { RuntimeModelAdapter } from "../contracts.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type FileResolver } from "../artifacts/files.js";
|
|
4
4
|
import type { HostModelSecret } from "../vault/service.js";
|
|
5
5
|
export interface ModelPreview {
|
|
6
6
|
readonly invocationId: string;
|
|
@@ -20,7 +20,11 @@ export interface ModelCallSettings {
|
|
|
20
20
|
export interface PiModelOptions {
|
|
21
21
|
readonly root?: string;
|
|
22
22
|
readonly onPreview?: (preview: ModelPreview) => void;
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Resolves the files a prompt names (media parts whose reference is an artifact version) to
|
|
25
|
+
* their bytes. Model-gate passes one over the Tenant's artifacts (`artifactFiles`).
|
|
26
|
+
*/
|
|
27
|
+
readonly files?: FileResolver;
|
|
24
28
|
readonly readHostModel?: () => HostModelSecret | undefined | Promise<HostModelSecret | undefined>;
|
|
25
29
|
readonly writeHostCredential?: (credential: Credential) => void | Promise<void>;
|
|
26
30
|
readonly settings?: ModelCallSettings;
|