@nylorun/runtime 0.24.0-beta → 0.26.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 +143 -0
- package/README.md +18 -4
- package/dist/api/a2a/card.d.ts +11 -1
- package/dist/api/a2a/card.js +26 -2
- package/dist/api/a2a/endpoint.js +4 -2
- package/dist/api/a2a/protocol.d.ts +25 -2
- package/dist/api/a2a/protocol.js +20 -3
- package/dist/api/a2a/routes.d.ts +4 -1
- package/dist/api/a2a/routes.js +65 -7
- package/dist/api/ag-ui/endpoint.js +5 -2
- package/dist/api/ag-ui/history.d.ts +6 -1
- package/dist/api/ag-ui/history.js +35 -2
- package/dist/api/ag-ui/routes.js +53 -11
- package/dist/api/components.d.ts +1165 -678
- package/dist/api/components.js +16 -1
- package/dist/api/gate/keys.d.ts +2 -1
- package/dist/api/gate/keys.js +7 -0
- package/dist/api/gate/routes.js +13 -0
- package/dist/api/http/app.d.ts +2 -2
- package/dist/api/http/app.js +15 -4
- package/dist/api/http/body.d.ts +3 -3
- package/dist/api/http/body.js +7 -7
- package/dist/api/http/define.d.ts +1 -1
- package/dist/api/http/respond.js +1 -1
- package/dist/api/http/routes/environment-manifests.d.ts +9 -0
- package/dist/api/http/routes/environment-manifests.js +118 -0
- package/dist/api/http/routes/environments.js +61 -12
- package/dist/api/http/routes/reads.d.ts +52 -3
- package/dist/api/http/routes/sessions.js +14 -4
- package/dist/api/http/routes/tenant.js +35 -7
- package/dist/api/inbound-files.d.ts +65 -0
- package/dist/api/inbound-files.js +115 -0
- package/dist/api/openapi.js +18 -3
- package/dist/artifacts/disk.js +20 -14
- package/dist/artifacts/media-types.d.ts +15 -0
- package/dist/artifacts/media-types.js +56 -4
- package/dist/artifacts/parts.d.ts +12 -3
- package/dist/artifacts/parts.js +15 -4
- package/dist/artifacts/workspace.d.ts +4 -4
- package/dist/artifacts/workspace.js +6 -18
- package/dist/core/flow-host.d.ts +1 -1
- package/dist/core/flow-host.js +2 -2
- package/dist/core/sandbox-routes.js +2 -2
- package/dist/core/turn-manifest.d.ts +3 -2
- package/dist/core/turn-manifest.js +29 -5
- package/dist/gates/egress-credentials.js +1 -1
- package/dist/gates/egress.d.ts +13 -19
- package/dist/gates/egress.js +32 -29
- package/dist/gates/http-tool.d.ts +3 -4
- package/dist/gates/http-tool.js +23 -19
- package/dist/gates/journal.js +0 -1
- package/dist/gates/mcp-handler.js +2 -3
- package/dist/gates/policy.js +1 -3
- package/dist/gates/tool-contract.d.ts +1 -1
- package/dist/harness/calls.d.ts +2 -2
- package/dist/harness/calls.js +9 -12
- package/dist/harness/main.js +7 -1
- package/dist/harness/pod.d.ts +6 -1
- package/dist/harness/pod.js +5 -0
- package/dist/harness/service.js +5 -5
- package/dist/harness/setup.d.ts +2 -0
- package/dist/harness/setup.js +25 -1
- package/dist/harness-api/record.d.ts +1 -1
- package/dist/harness-api/record.js +13 -13
- package/dist/harness-api/server.d.ts +27 -4
- package/dist/harness-api/server.js +41 -8
- package/dist/harness-api/tool-journal.d.ts +17 -8
- package/dist/harness-api/tool-journal.js +41 -11
- package/dist/harness-api/workspace.d.ts +7 -5
- package/dist/harness-api/workspace.js +25 -19
- package/dist/host/gates.js +2 -2
- package/dist/host/stack-config.js +1 -1
- package/dist/keys/contract.d.ts +1 -1
- package/dist/keys/contract.js +1 -1
- package/dist/keys/keys.d.ts +9 -2
- package/dist/keys/keys.js +4 -1
- package/dist/management-openapi.json +366 -61
- package/dist/mcp/connect.d.ts +1 -2
- package/dist/mcp/connect.js +1 -4
- package/dist/mcp/pool.d.ts +1 -4
- package/dist/mcp/pool.js +13 -27
- package/dist/mcp/preview.d.ts +1 -1
- package/dist/mcp/preview.js +1 -2
- package/dist/mcp/snapshot.d.ts +11 -13
- package/dist/mcp/snapshot.js +27 -38
- package/dist/model/capabilities.d.ts +26 -0
- package/dist/model/capabilities.js +44 -0
- package/dist/model/catalog.d.ts +34 -3
- package/dist/model/catalog.js +38 -2
- package/dist/model/models.d.ts +2 -0
- package/dist/model/models.js +1 -1
- package/dist/model/native-blocks.d.ts +35 -0
- package/dist/model/native-blocks.js +170 -0
- package/dist/model/pi-model.js +106 -94
- package/dist/openapi.json +9554 -5076
- package/dist/record/environment.js +1 -1
- package/dist/sandbox/join.js +4 -0
- package/dist/sandbox/manager.d.ts +32 -14
- package/dist/sandbox/manager.js +132 -93
- package/dist/sandbox/placement.d.ts +1 -1
- package/dist/sandbox/placement.js +2 -2
- package/dist/sandbox/pods/client.d.ts +3 -1
- package/dist/sandbox/pods/lifecycle.d.ts +8 -0
- package/dist/sandbox/pods/lifecycle.js +15 -0
- package/dist/sandbox/pods/spec.js +2 -1
- package/dist/sandbox/resolve.d.ts +5 -3
- package/dist/sandbox/resolve.js +9 -2
- package/dist/sandbox/runtime-tools.d.ts +9 -0
- package/dist/sandbox/runtime-tools.js +16 -0
- package/dist/sandbox/session-sandbox.d.ts +4 -6
- package/dist/sandbox/session-sandbox.js +47 -94
- package/dist/sandbox/setup.d.ts +4 -1
- package/dist/sandbox/setup.js +46 -9
- package/dist/sandbox/share.d.ts +12 -7
- package/dist/sandbox/share.js +27 -25
- package/dist/sandbox/skills.d.ts +8 -6
- package/dist/sandbox/skills.js +24 -23
- package/dist/store/postgres/drizzle/0024_flat_manifest.sql +7 -0
- package/dist/store/postgres/drizzle/0025_environment_manifests.sql +14 -0
- package/dist/store/postgres/drizzle/0026_environment_forks.sql +1 -0
- package/dist/store/postgres/drizzle/0027_environment_image_digest.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/migrate.js +1 -1
- package/dist/store/postgres/reads.js +8 -2
- package/dist/store/postgres/schema.d.ts +217 -0
- package/dist/store/postgres/schema.js +36 -2
- package/dist/store/postgres/store.js +79 -4
- package/dist/store/types.d.ts +68 -14
- package/dist/tenant/advance.js +3 -0
- package/dist/tenant/artifact-tool.d.ts +1 -1
- package/dist/tenant/artifact-tool.js +43 -22
- package/dist/tenant/commands.js +24 -4
- package/dist/tenant/context.d.ts +10 -4
- package/dist/tenant/effects.js +7 -9
- package/dist/tenant/environment-manifests.d.ts +57 -0
- package/dist/tenant/environment-manifests.js +200 -0
- package/dist/tenant/environments.d.ts +54 -47
- package/dist/tenant/environments.js +309 -85
- package/dist/tenant/ephemeral.d.ts +1 -1
- package/dist/tenant/host-token.js +1 -1
- package/dist/tenant/identity-file.d.ts +1 -1
- package/dist/tenant/identity-file.js +1 -1
- package/dist/tenant/model-setting.d.ts +14 -0
- package/dist/tenant/model-setting.js +51 -0
- package/dist/tenant/outbound.d.ts +6 -5
- package/dist/tenant/outbound.js +8 -6
- package/dist/tenant/sessions.d.ts +5 -1
- package/dist/tenant/sessions.js +45 -12
- package/dist/tenant/skill-tool.d.ts +3 -3
- package/dist/tenant/skill-tool.js +6 -11
- package/dist/tenant/sweep.js +1 -1
- package/dist/tenant/tool-results.js +1 -1
- package/dist/tenant/tool-search.d.ts +7 -11
- package/dist/tenant/tool-search.js +8 -5
- package/dist/tenant/transcript.d.ts +51 -32
- package/dist/tenant/transcript.js +2 -1
- package/dist/tenant/types.d.ts +2 -2
- package/dist/traces/ids.d.ts +0 -1
- package/dist/traces/ids.js +0 -4
- package/dist/traces/map.d.ts +2 -2
- package/dist/traces/map.js +1 -29
- package/dist/vault/coverage.js +11 -13
- package/dist/vault/host-model.d.ts +4 -1
- package/dist/vault/host-model.js +10 -2
- package/dist/vault/service.d.ts +49 -4
- package/dist/vault/service.js +153 -6
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/sandbox/capability.d.ts +0 -3
- package/dist/sandbox/capability.js +0 -10
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Tenant's model settings: the fixture model, and the inputs the operator added to catalog
|
|
3
|
+
* models (`model.inputs`, below).
|
|
4
|
+
*
|
|
5
|
+
* The Tenant-level fixture model: Tenant setting `model.fixture`, seeded with
|
|
6
|
+
* `fixtureModel: true` (`PUT /v1/tenant/config/seed`, Host feature `tenant-fixture-model`).
|
|
7
|
+
* A Tenant with it answers every model call with the Runtime's deterministic fixture model
|
|
8
|
+
* (`core/provider.ts` `toolFixtureModel`) instead of its configured model. Smoke checks seed
|
|
9
|
+
* it (scripts/lib/stack-tenant.mjs).
|
|
10
|
+
*
|
|
11
|
+
* The setting is read once per advance, in a transaction the advance makes anyway, so a Tenant
|
|
12
|
+
* seeded on another node takes it at its next advance.
|
|
13
|
+
*/
|
|
14
|
+
import { ModelInputSchema } from "@nylorun/core/contracts";
|
|
1
15
|
export const FIXTURE_MODEL_SETTING = "model.fixture";
|
|
2
16
|
/** Whether the Tenant uses the fixture model. */
|
|
3
17
|
export async function usesFixtureModel(t) {
|
|
@@ -10,3 +24,40 @@ export async function seedFixtureModel(t) {
|
|
|
10
24
|
await t.putSetting(FIXTURE_MODEL_SETTING, "true");
|
|
11
25
|
return true;
|
|
12
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* The inputs the operator added to catalog models (protocol 12, `PUT /v1/tenant/models/inputs`):
|
|
29
|
+
* Tenant setting `model.inputs`, JSON `{ "<provider>/<model>": ModelInput[] }`. A custom
|
|
30
|
+
* endpoint keeps its own in its `settings.inputs` instead.
|
|
31
|
+
*/
|
|
32
|
+
export const MODEL_INPUTS_SETTING = "model.inputs";
|
|
33
|
+
/** The added inputs by `<provider>/<model>`. Bad JSON, keys and inputs are left out: never throws. */
|
|
34
|
+
export async function readAddedInputs(t) {
|
|
35
|
+
const raw = await t.getSetting(MODEL_INPUTS_SETTING);
|
|
36
|
+
if (raw === undefined)
|
|
37
|
+
return {};
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(raw);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
46
|
+
return {};
|
|
47
|
+
const added = {};
|
|
48
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
49
|
+
if (!key.includes("/") || !Array.isArray(value))
|
|
50
|
+
continue;
|
|
51
|
+
added[key] = value.filter((input) => ModelInputSchema.safeParse(input).success);
|
|
52
|
+
}
|
|
53
|
+
return added;
|
|
54
|
+
}
|
|
55
|
+
/** Sets the inputs added to `<provider>/<model>`; an empty list removes its entry. */
|
|
56
|
+
export async function writeAddedInputs(t, key, inputs) {
|
|
57
|
+
const added = await readAddedInputs(t);
|
|
58
|
+
if (inputs.length === 0)
|
|
59
|
+
delete added[key];
|
|
60
|
+
else
|
|
61
|
+
added[key] = [...inputs];
|
|
62
|
+
await t.putSetting(MODEL_INPUTS_SETTING, JSON.stringify(added));
|
|
63
|
+
}
|
|
@@ -37,14 +37,15 @@ export declare function isPrivateAddress(address: string): boolean;
|
|
|
37
37
|
/** Why the Host refuses `url`, or `undefined` when it may be called. */
|
|
38
38
|
export declare function refusal(url: URL, policy: OutboundPolicy): string | undefined;
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
40
|
+
* Sends one request to `url` under `policy`: with `method` (default `POST`) and the JSON `body`,
|
|
41
|
+
* or with no body (and no `content-type`) when `body` is undefined, as for a `GET`. Never
|
|
41
42
|
* throws; `signal` aborts the request.
|
|
42
43
|
*/
|
|
43
|
-
export declare function
|
|
44
|
+
export declare function send(target: string, body: string | undefined, headers: Record<string, string>, options: {
|
|
44
45
|
policy: OutboundPolicy;
|
|
45
46
|
signal: AbortSignal;
|
|
46
47
|
maxResponseBytes?: number;
|
|
47
|
-
method?: "POST" | "PUT" | "PATCH";
|
|
48
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
48
49
|
}): Promise<OutboundResult>;
|
|
49
50
|
/**
|
|
50
51
|
* A refusal of `guardedFetch`: the Host's policy forbids the URL or every address it resolves
|
|
@@ -59,13 +60,13 @@ export declare class OutboundRefused extends Error {
|
|
|
59
60
|
export declare class OutboundFailed extends Error {
|
|
60
61
|
readonly code: string;
|
|
61
62
|
/**
|
|
62
|
-
* The request was sent in full before it failed, as `
|
|
63
|
+
* The request was sent in full before it failed, as `send()`'s `lost` (R2b C7): the server
|
|
63
64
|
* may have acted on it. False for a failure to resolve or connect.
|
|
64
65
|
*/
|
|
65
66
|
readonly sent: boolean;
|
|
66
67
|
constructor(message: string, code: string,
|
|
67
68
|
/**
|
|
68
|
-
* The request was sent in full before it failed, as `
|
|
69
|
+
* The request was sent in full before it failed, as `send()`'s `lost` (R2b C7): the server
|
|
69
70
|
* may have acted on it. False for a failure to resolve or connect.
|
|
70
71
|
*/
|
|
71
72
|
sent?: boolean);
|
package/dist/tenant/outbound.js
CHANGED
|
@@ -76,10 +76,11 @@ function guardedLookup(policy) {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
/**
|
|
79
|
-
*
|
|
79
|
+
* Sends one request to `url` under `policy`: with `method` (default `POST`) and the JSON `body`,
|
|
80
|
+
* or with no body (and no `content-type`) when `body` is undefined, as for a `GET`. Never
|
|
80
81
|
* throws; `signal` aborts the request.
|
|
81
82
|
*/
|
|
82
|
-
export async function
|
|
83
|
+
export async function send(target, body, headers, options) {
|
|
83
84
|
const { policy, signal } = options;
|
|
84
85
|
const limit = options.maxResponseBytes ?? MAX_RESPONSE_BYTES;
|
|
85
86
|
const url = new URL(target);
|
|
@@ -108,8 +109,9 @@ export async function post(target, body, headers, options) {
|
|
|
108
109
|
headers: {
|
|
109
110
|
...headers,
|
|
110
111
|
host: originalHost,
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
...(body === undefined
|
|
113
|
+
? {}
|
|
114
|
+
: { "content-type": "application/json", "content-length": String(Buffer.byteLength(body)) }),
|
|
113
115
|
},
|
|
114
116
|
lookup: lookup,
|
|
115
117
|
signal,
|
|
@@ -156,7 +158,7 @@ export class OutboundFailed extends Error {
|
|
|
156
158
|
sent;
|
|
157
159
|
constructor(message, code,
|
|
158
160
|
/**
|
|
159
|
-
* The request was sent in full before it failed, as `
|
|
161
|
+
* The request was sent in full before it failed, as `send()`'s `lost` (R2b C7): the server
|
|
160
162
|
* may have acted on it. False for a failure to resolve or connect.
|
|
161
163
|
*/
|
|
162
164
|
sent = false) {
|
|
@@ -223,7 +225,7 @@ export function guardedFetch(policy, options = {}) {
|
|
|
223
225
|
outgoing["content-length"] = String(body.byteLength);
|
|
224
226
|
return await new Promise((resolve, reject) => {
|
|
225
227
|
let settled = false;
|
|
226
|
-
// Set when the request is fully sent, as `
|
|
228
|
+
// Set when the request is fully sent, as `send()` does: a failure after it may follow
|
|
227
229
|
// the server acting on the request.
|
|
228
230
|
let delivered = false;
|
|
229
231
|
const settle = (fn) => {
|
|
@@ -25,10 +25,14 @@ export declare function listAgentsPublic(ctx: TenantContext, agents: ReadonlySet
|
|
|
25
25
|
description?: any;
|
|
26
26
|
}[];
|
|
27
27
|
}>;
|
|
28
|
-
export declare function putDefinition(ctx: TenantContext, agentId: string, body: PutAgentRequest
|
|
28
|
+
export declare function putDefinition(ctx: TenantContext, agentId: string, body: PutAgentRequest, options?: {
|
|
29
|
+
/** Run every check and save nothing (`?dryRun=true`, protocol 14). */
|
|
30
|
+
dryRun?: boolean;
|
|
31
|
+
}): Promise<{
|
|
29
32
|
agentId: string;
|
|
30
33
|
manifestHash: string;
|
|
31
34
|
implementationVersion: string;
|
|
35
|
+
dryRun?: boolean | undefined;
|
|
32
36
|
}>;
|
|
33
37
|
/**
|
|
34
38
|
* `access`, when the request acts for a person, limits the list to that person's sessions of
|
package/dist/tenant/sessions.js
CHANGED
|
@@ -9,8 +9,8 @@ import { approvalRefusal, codeToolRefusal } from "@nylorun/core/define";
|
|
|
9
9
|
import { aggregateWaits, isWorkflowManifest } from "../core/flow-host.js";
|
|
10
10
|
import { canonical } from "../store/canonical.js";
|
|
11
11
|
import { sandboxSpecOf } from "../sandbox/resolve.js";
|
|
12
|
-
import {
|
|
13
|
-
import { declaredSandboxes } from "../sandbox/share.js";
|
|
12
|
+
import { withRuntimeTools, withSandbox } from "../sandbox/session-sandbox.js";
|
|
13
|
+
import { authoredRuntimeBlocks, declaredSandboxes } from "../sandbox/share.js";
|
|
14
14
|
import { effectiveSandboxConfig, readSandboxConfig } from "../sandbox/tenant-config.js";
|
|
15
15
|
import { HARNESS_ID, checkPlacement, requirePods } from "../sandbox/placement.js";
|
|
16
16
|
import { openEnvironment, recordAttachment } from "./environments.js";
|
|
@@ -51,7 +51,7 @@ export async function listAgentsPublic(ctx, agents) {
|
|
|
51
51
|
})),
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
export async function putDefinition(ctx, agentId, body) {
|
|
54
|
+
export async function putDefinition(ctx, agentId, body, options = {}) {
|
|
55
55
|
if (body.manifest.id !== agentId)
|
|
56
56
|
fail(400, "Agent id mismatch");
|
|
57
57
|
DefinitionDocumentSchema.parse(body.manifest);
|
|
@@ -66,6 +66,9 @@ export async function putDefinition(ctx, agentId, body) {
|
|
|
66
66
|
const declared = declaredSandboxes(body.manifest);
|
|
67
67
|
if (declared.length > 0)
|
|
68
68
|
fail(400, `${declared.join(", ")} declares a sandbox. Agents no longer declare one: remove .sandbox(), create an Environment with the sandbox (PUT /v1/environments/{id}) and open the session on it, createSession({ environment }). See MIGRATION.md.`);
|
|
69
|
+
const runtime = authoredRuntimeBlocks(body.manifest);
|
|
70
|
+
if (runtime.length > 0)
|
|
71
|
+
fail(400, `${runtime.join(", ")} sets runtime, which only the Runtime writes when it pins a session's agent. Remove it and register the manifest your builder makes.`);
|
|
69
72
|
const definition = {
|
|
70
73
|
...body,
|
|
71
74
|
manifestHash: hashManifest(body.manifest),
|
|
@@ -75,6 +78,8 @@ export async function putDefinition(ctx, agentId, body) {
|
|
|
75
78
|
const missing = await missingDefinitionFiles(t, body.manifest);
|
|
76
79
|
if (missing.length > 0)
|
|
77
80
|
fail(400, `The definition names ${missing.length} file(s) the Runtime does not hold; upload each with PUT /v1/files/<sha256> first: ${missing.join(", ")}`, { code: "definition_files_missing", details: { missing } });
|
|
81
|
+
if (options.dryRun)
|
|
82
|
+
return;
|
|
78
83
|
await t.put("definitions", agentId, definition);
|
|
79
84
|
await t.insertDefinitionFileUses(agentId, definition.manifestHash, files);
|
|
80
85
|
});
|
|
@@ -82,6 +87,7 @@ export async function putDefinition(ctx, agentId, body) {
|
|
|
82
87
|
agentId,
|
|
83
88
|
manifestHash: definition.manifestHash,
|
|
84
89
|
implementationVersion: body.implementationVersion,
|
|
90
|
+
...(options.dryRun ? { dryRun: true } : {}),
|
|
85
91
|
};
|
|
86
92
|
}
|
|
87
93
|
/**
|
|
@@ -150,6 +156,8 @@ export async function putSession(ctx, id, body, access, options = {}) {
|
|
|
150
156
|
ownerUserId: body.ownerUserId,
|
|
151
157
|
opaque,
|
|
152
158
|
});
|
|
159
|
+
if (!isWorkflowManifest(definition.manifest))
|
|
160
|
+
await checkRequirements(t, definition.manifest, environment);
|
|
153
161
|
const config = await readSandboxConfig(t);
|
|
154
162
|
// The harness the session runs for its life (R4.1): its Environment's, else ours. A flow
|
|
155
163
|
// runs in core and our engine, whatever its Environment names.
|
|
@@ -163,7 +171,7 @@ export async function putSession(ctx, id, body, access, options = {}) {
|
|
|
163
171
|
const spec = environment === undefined || environment.kind === "none"
|
|
164
172
|
? undefined
|
|
165
173
|
: sandboxSpecOf(environment.applied, effectiveSandboxConfig(config).limits.idle);
|
|
166
|
-
const pinned = spec === undefined ?
|
|
174
|
+
const pinned = spec === undefined ? runtimeTools(definition) : pin(definition, spec);
|
|
167
175
|
const created = {
|
|
168
176
|
id,
|
|
169
177
|
agentId: body.agentId,
|
|
@@ -189,25 +197,50 @@ export async function putSession(ctx, id, body, access, options = {}) {
|
|
|
189
197
|
});
|
|
190
198
|
}
|
|
191
199
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
200
|
+
* Refuses a session whose agent requires what its Environment lacks (protocol 14, D65): a
|
|
201
|
+
* sandbox (`any`: kind `virtual` or `pod`), a pod, or a secret its vault does not hold. Every
|
|
202
|
+
* gap is named in one `409 environment_unsuitable`.
|
|
194
203
|
*/
|
|
195
|
-
function
|
|
204
|
+
async function checkRequirements(t, manifest, environment) {
|
|
205
|
+
const requires = manifest.requires;
|
|
206
|
+
if (requires === undefined)
|
|
207
|
+
return;
|
|
208
|
+
const missing = [];
|
|
209
|
+
const kind = environment?.kind;
|
|
210
|
+
if (requires.sandbox === "any" && kind !== "virtual" && kind !== "pod")
|
|
211
|
+
missing.push("sandbox");
|
|
212
|
+
if (requires.sandbox === "pod" && kind !== "pod")
|
|
213
|
+
missing.push("pod");
|
|
214
|
+
if (requires.secrets?.length) {
|
|
215
|
+
const vault = environment === undefined ? undefined : await t.vaultOfEnvironment(environment.id);
|
|
216
|
+
const held = new Set(vault ? (await t.credentialsForVault(vault.id)).map((row) => row.name) : []);
|
|
217
|
+
for (const name of requires.secrets)
|
|
218
|
+
if (!held.has(name))
|
|
219
|
+
missing.push(`secret:${name}`);
|
|
220
|
+
}
|
|
221
|
+
if (missing.length === 0)
|
|
222
|
+
return;
|
|
223
|
+
const where = environment === undefined ? "the session names no Environment" : `Environment ${environment.id} lacks it`;
|
|
224
|
+
fail(409, `Agent ${manifest.id} requires ${missing.map((gap) => (gap.startsWith("secret:") ? `the secret ${gap.slice(7)}` : gap === "pod" ? "a pod Environment" : "a sandbox")).join(", ")}, and ${where}.`, { code: "environment_unsuitable", details: { missing } });
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* The manifest a session without a sandbox pins: each agent's `runtime` block, with
|
|
228
|
+
* `read_artifact` (R2b C11) and its skill tools; nothing for a workflow.
|
|
229
|
+
*/
|
|
230
|
+
function runtimeTools(definition) {
|
|
196
231
|
if (isWorkflowManifest(definition.manifest))
|
|
197
232
|
return {};
|
|
198
|
-
const pinned =
|
|
199
|
-
if (pinned === undefined)
|
|
200
|
-
return {};
|
|
233
|
+
const pinned = withRuntimeTools(definition.manifest);
|
|
201
234
|
if (!pinned.ok)
|
|
202
235
|
return fail(400, pinned.message);
|
|
203
236
|
return { manifest: pinned.manifest, manifestHash: pinned.manifestHash };
|
|
204
237
|
}
|
|
205
|
-
/** The manifest a session with a sandbox pins: the definition with the sandbox
|
|
238
|
+
/** The manifest a session with a sandbox pins: the definition with the sandbox in its `runtime` block. */
|
|
206
239
|
function pin(definition, spec) {
|
|
207
240
|
// A workflow's manifest stays as registered: its agents inherit the sandbox when they start.
|
|
208
241
|
if (isWorkflowManifest(definition.manifest))
|
|
209
242
|
return {};
|
|
210
|
-
const sandboxed =
|
|
243
|
+
const sandboxed = withSandbox(definition.manifest, spec);
|
|
211
244
|
if (!sandboxed.ok)
|
|
212
245
|
return fail(400, sandboxed.message);
|
|
213
246
|
return { manifest: sandboxed.manifest, manifestHash: sandboxed.manifestHash };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The skill tools (track R2 M4): `load_skill` and `read_skill_resource`, which the
|
|
3
|
-
* the
|
|
2
|
+
* The skill tools (track R2 M4): `load_skill` and `read_skill_resource`, which the Runtime pins
|
|
3
|
+
* in the `runtime` block of an agent with skills. The Runtime runs them itself, like `save_artifact`, from the
|
|
4
4
|
* definition files uploaded with the agent: no developer process is involved.
|
|
5
5
|
*
|
|
6
6
|
* - `load_skill`: the skill's instructions (its `SKILL.md` after the frontmatter), the paths of
|
|
7
7
|
* its other files, and, when the session has a sandbox, where they are in it
|
|
8
|
-
* (`/skills/<name>/`, read-only).
|
|
8
|
+
* (`/skills/<name>@<hash>/`, read-only, D66).
|
|
9
9
|
* - `read_skill_resource`: one text file of the skill. A binary file is refused: the model reads
|
|
10
10
|
* it in the sandbox, when there is one.
|
|
11
11
|
*
|
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
import { LOAD_SKILL_TOOL,
|
|
2
|
-
import {
|
|
1
|
+
import { LOAD_SKILL_TOOL, SKILL_ENTRY, skillFolderOf, isSkillTool, skillInstructions, } from "@nylorun/core/define";
|
|
2
|
+
import { sandboxToolSpec } from "../sandbox/runtime-tools.js";
|
|
3
3
|
import { readDefinitionFile } from "./definition-files.js";
|
|
4
4
|
const failed = (code, message) => ({ kind: "failed", code, message });
|
|
5
5
|
/** True when `request` calls a skill tool the Runtime serves for `manifest`'s agent. */
|
|
6
6
|
export function isSkillToolCall(manifest, request) {
|
|
7
|
-
return
|
|
8
|
-
isSkillTool(manifest?.capabilities.find((capability) => capability.id === request.capabilityId), request.toolName));
|
|
7
|
+
return request.kind === "tool" && isSkillTool(manifest, request.toolName);
|
|
9
8
|
}
|
|
10
9
|
/** Every skill of the agent, by name. */
|
|
11
10
|
function skillsOf(manifest) {
|
|
12
|
-
|
|
13
|
-
for (const capability of manifest.capabilities)
|
|
14
|
-
for (const skill of Object.values(capability.skills ?? {}))
|
|
15
|
-
skills.set(skill.name, skill);
|
|
16
|
-
return skills;
|
|
11
|
+
return new Map(Object.values(manifest.skills ?? {}).map((skill) => [skill.name, skill]));
|
|
17
12
|
}
|
|
18
13
|
/** UTF-8 text, or undefined for bytes that are not (a NUL byte, or invalid UTF-8). */
|
|
19
14
|
function textOf(bytes) {
|
|
@@ -35,8 +30,8 @@ export async function callSkillTool(ctx, manifest, request, signal) {
|
|
|
35
30
|
return request.toolName === LOAD_SKILL_TOOL
|
|
36
31
|
? { kind: "completed", output: { unknown: name, available: [...skills.keys()].sort() } }
|
|
37
32
|
: failed("skill.unknown", `There is no skill '${name}'.`);
|
|
38
|
-
const sandboxed =
|
|
39
|
-
const directory = `${
|
|
33
|
+
const sandboxed = sandboxToolSpec(manifest, "bash") !== undefined;
|
|
34
|
+
const directory = `${skillFolderOf(skill)}/`;
|
|
40
35
|
const read = async (path) => {
|
|
41
36
|
const bytes = await readDefinitionFile(ctx.blobs, skill.files[path], signal);
|
|
42
37
|
if (!bytes)
|
package/dist/tenant/sweep.js
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* wiped (§17.11), or a parked outbox row.
|
|
30
30
|
* 4. **Sandboxes.** Idle sandboxes are stopped, records of compute no longer held are marked
|
|
31
31
|
* stopped, and sandboxes whose session or Environment is gone are removed, by the
|
|
32
|
-
* workspace
|
|
32
|
+
* workspace feature (`harness-api/workspace.ts`: here, or in the harness that serves
|
|
33
33
|
* workspaces). Idle MCP connections of the in-process harness are closed. As often as the
|
|
34
34
|
* orphan scan, pod Environments whose change stalled get a reconcile (`reconcileStalePods`).
|
|
35
35
|
* Environments unused for their `lifecycle.deleteAfter` are deleted
|
|
@@ -170,7 +170,7 @@ async function shapeBinary(shaping, part, index) {
|
|
|
170
170
|
kept.size <= MODEL_FILE_MAX_BYTES)
|
|
171
171
|
shaping.files.push({
|
|
172
172
|
mediaType: contentType,
|
|
173
|
-
reference: { artifactId: kept.artifactId, version: kept.version, name },
|
|
173
|
+
reference: { artifactId: kept.artifactId, version: kept.version, name, size: kept.size },
|
|
174
174
|
});
|
|
175
175
|
return {
|
|
176
176
|
type: part.type,
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `tool_search` (R2b C10, Q20): core finds an agent's deferred MCP tools in the session's pinned
|
|
3
|
-
* snapshot, ranked with BM25 over their names and descriptions, and returns each match's name,
|
|
4
|
-
* description and `inputSchema`, for the model to run with `tool_call`. It reads only the pinned
|
|
5
|
-
* snapshot, so the same query finds the same tools for the session's life; a tool the turn's
|
|
6
|
-
* manifest disables is never found.
|
|
7
|
-
*/
|
|
8
|
-
import { type AgentManifest } from "@nylorun/core/define";
|
|
9
1
|
import type { HostEffect } from "@nylorun/harness/run";
|
|
10
|
-
import { type McpToolRecord } from "../mcp/snapshot.js";
|
|
2
|
+
import { type McpSnapshot, type McpToolRecord } from "../mcp/snapshot.js";
|
|
11
3
|
import { type TenantContext } from "./context.js";
|
|
12
|
-
/**
|
|
13
|
-
|
|
4
|
+
/**
|
|
5
|
+
* True when `request` calls `tool_search`, the session tool an agent gets when the session's
|
|
6
|
+
* pinned snapshot holds deferred tools of its own. The name is reserved: no tool of the agent's
|
|
7
|
+
* own takes it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isToolSearchCall(snapshot: McpSnapshot | undefined, request: HostEffect): boolean;
|
|
14
10
|
/** Runs `tool_search` for the run's agent. */
|
|
15
11
|
export declare function callToolSearch(ctx: TenantContext, request: HostEffect): Promise<{
|
|
16
12
|
output?: undefined;
|
|
@@ -5,19 +5,22 @@
|
|
|
5
5
|
* snapshot, so the same query finds the same tools for the session's life; a tool the turn's
|
|
6
6
|
* manifest disables is never found.
|
|
7
7
|
*/
|
|
8
|
-
import { TOOL_SEARCH_DEFAULT_LIMIT, TOOL_SEARCH_MAX_LIMIT, TOOL_SEARCH_TOOL,
|
|
8
|
+
import { TOOL_SEARCH_DEFAULT_LIMIT, TOOL_SEARCH_MAX_LIMIT, TOOL_SEARCH_TOOL, } from "@nylorun/core/define";
|
|
9
9
|
import { isEnabledIn } from "../mcp/snapshot.js";
|
|
10
10
|
import { sessionOf } from "./context.js";
|
|
11
11
|
import { turnManifestOf } from "./session.js";
|
|
12
12
|
/** BM25's term saturation and length normalization, the usual values. */
|
|
13
13
|
const K1 = 1.2;
|
|
14
14
|
const B = 0.75;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* True when `request` calls `tool_search`, the session tool an agent gets when the session's
|
|
17
|
+
* pinned snapshot holds deferred tools of its own. The name is reserved: no tool of the agent's
|
|
18
|
+
* own takes it.
|
|
19
|
+
*/
|
|
20
|
+
export function isToolSearchCall(snapshot, request) {
|
|
17
21
|
return (request.kind === "tool" &&
|
|
18
|
-
request.capabilityId === TOOLS_CAPABILITY_ID &&
|
|
19
22
|
request.toolName === TOOL_SEARCH_TOOL &&
|
|
20
|
-
|
|
23
|
+
snapshot?.mcpTools.some((tool) => tool.deferred === true && tool.agentId === request.agent?.id) === true);
|
|
21
24
|
}
|
|
22
25
|
/** Runs `tool_search` for the run's agent. */
|
|
23
26
|
export async function callToolSearch(ctx, request) {
|