@nylorun/agents 0.9.0-beta → 0.10.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 +131 -0
- package/README.md +287 -69
- package/dist/a2a/handler.d.ts +59 -0
- package/dist/a2a/handler.js +178 -0
- package/dist/a2a/index.d.ts +8 -0
- package/dist/a2a/index.js +7 -0
- package/dist/access.d.ts +101 -0
- package/dist/access.js +111 -0
- package/dist/action-handler.d.ts +64 -0
- package/dist/action-handler.js +283 -0
- package/dist/ag-ui/handler.d.ts +12 -4
- package/dist/ag-ui/handler.js +87 -281
- package/dist/ag-ui/index.d.ts +2 -1
- package/dist/ag-ui/index.js +2 -1
- package/dist/browser.d.ts +97 -0
- package/dist/browser.js +277 -0
- package/dist/client.d.ts +3 -230
- package/dist/client.js +2 -357
- package/dist/connection.d.ts +0 -1
- package/dist/connection.js +3 -9
- package/dist/delivery-token.d.ts +57 -0
- package/dist/delivery-token.js +150 -0
- package/dist/execute-action.d.ts +6 -0
- package/dist/execute-action.js +24 -0
- package/dist/http.d.ts +31 -1
- package/dist/http.js +74 -14
- package/dist/index.d.ts +9 -7
- package/dist/index.js +3 -3
- package/dist/sandbox/client.d.ts +4 -5
- package/dist/sandbox/client.js +4 -8
- package/dist/sandbox/index.d.ts +0 -2
- package/dist/sandbox/index.js +0 -1
- package/dist/served-definitions.d.ts +20 -0
- package/dist/served-definitions.js +100 -0
- package/dist/session-client.d.ts +282 -0
- package/dist/session-client.js +375 -0
- package/dist/sse.js +12 -0
- package/dist/studio-embed.d.ts +9 -0
- package/dist/studio-embed.js +8 -0
- package/dist/token-endpoint.d.ts +23 -0
- package/dist/token-endpoint.js +30 -0
- package/package.json +15 -8
- package/dist/ag-ui/history.d.ts +0 -7
- package/dist/ag-ui/history.js +0 -60
- package/dist/ag-ui/sse.d.ts +0 -9
- package/dist/ag-ui/sse.js +0 -7
- package/dist/ag-ui/translate.d.ts +0 -38
- package/dist/ag-ui/translate.js +0 -222
- package/dist/derived-credentials.d.ts +0 -5
- package/dist/derived-credentials.js +0 -17
- package/dist/executor.d.ts +0 -20
- package/dist/executor.js +0 -417
package/dist/http.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { type Compatibility, type ProtocolRange } from "@nylorun/core/compatibility";
|
|
2
|
+
/**
|
|
3
|
+
* Subject tokens for a client that holds no Tenant key (a browser or an app; Host feature
|
|
4
|
+
* `subject-tokens`). `get` returns a current token and may fetch a new one; `invalidate`
|
|
5
|
+
* drops the cached one after the Runtime answered `401 token_expired`.
|
|
6
|
+
*/
|
|
7
|
+
export interface TokenSource {
|
|
8
|
+
get(signal?: AbortSignal): Promise<string>;
|
|
9
|
+
invalidate(): void;
|
|
10
|
+
}
|
|
2
11
|
export interface Destination {
|
|
3
12
|
url?: string;
|
|
4
13
|
key?: string;
|
|
5
14
|
tenant?: string;
|
|
6
15
|
fetch?: typeof fetch;
|
|
16
|
+
/** Instead of `key`: subject tokens. The client then skips the `/health` check. */
|
|
17
|
+
token?: TokenSource;
|
|
18
|
+
/** A publishable key (Host feature `browser-access`); it also names the Tenant. */
|
|
19
|
+
publishableKey?: string;
|
|
7
20
|
}
|
|
8
21
|
export declare function env(name: string): string | undefined;
|
|
9
22
|
export declare class RuntimeError extends Error {
|
|
@@ -23,27 +36,44 @@ export declare class IncompatibleRuntimeError extends Error {
|
|
|
23
36
|
}
|
|
24
37
|
export declare class Transport {
|
|
25
38
|
readonly url: string;
|
|
39
|
+
/** The Tenant key; empty for a client that uses subject tokens. */
|
|
26
40
|
readonly key: string;
|
|
41
|
+
/** The Tenant id; empty when a publishable key names it. */
|
|
27
42
|
readonly tenant: string;
|
|
43
|
+
readonly token: TokenSource | undefined;
|
|
44
|
+
readonly publishableKey: string | undefined;
|
|
28
45
|
readonly fetcher: typeof fetch;
|
|
29
46
|
/** Sent on every request, e.g. `Nylorun-Subject` and `Nylorun-Scopes` (`withHeaders`). */
|
|
30
47
|
readonly headers: Readonly<Record<string, string>>;
|
|
31
48
|
private readonly check;
|
|
32
|
-
constructor(options?: Destination
|
|
49
|
+
constructor(options?: Destination);
|
|
33
50
|
/**
|
|
34
51
|
* The same destination with `headers` added to every request. The copy shares this
|
|
35
52
|
* transport's compatibility check, so a copy made per request does not repeat `/health`.
|
|
36
53
|
*/
|
|
37
54
|
withHeaders(headers: Readonly<Record<string, string>>): Transport;
|
|
55
|
+
/**
|
|
56
|
+
* The same destination with another bearer (a delivery token for an Action endpoint's
|
|
57
|
+
* callbacks). Like `withHeaders`, the copy shares this transport's compatibility check.
|
|
58
|
+
*/
|
|
59
|
+
withKey(key: string): Transport;
|
|
38
60
|
/** Clears the cached Host compatibility result (used after a 426). */
|
|
39
61
|
clearCompatibilityCache(): void;
|
|
40
62
|
private ensureCompatible;
|
|
63
|
+
/** Throws `IncompatibleRuntimeError` before anything is sent when the Host lacks `feature`. */
|
|
64
|
+
requireFeature(feature: string, signal?: AbortSignal): Promise<void>;
|
|
41
65
|
/** The Host's protocol features, including optional ones, from its `/health`. */
|
|
42
66
|
hostFeatures(signal?: AbortSignal): Promise<readonly string[]>;
|
|
43
67
|
private authHeaders;
|
|
44
68
|
request(path: string, init?: RequestInit, options?: {
|
|
45
69
|
retried426?: boolean;
|
|
70
|
+
retried401?: boolean;
|
|
46
71
|
}): Promise<Response>;
|
|
72
|
+
/**
|
|
73
|
+
* Sends a request with this client's credentials and returns the Runtime's response as it
|
|
74
|
+
* is, errors included (an app server passing a response through, e.g. the AG-UI handler).
|
|
75
|
+
*/
|
|
76
|
+
forward(path: string, init?: RequestInit): Promise<Response>;
|
|
47
77
|
json<T>(path: string, method?: string, body?: unknown, signal?: AbortSignal): Promise<T>;
|
|
48
78
|
}
|
|
49
79
|
export declare const id: () => `${string}-${string}-${string}-${string}-${string}`;
|
package/dist/http.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PROTOCOL_FEATURES, PROTOCOL_HEADER, PROTOCOL_VERSION, TENANT_HEADER, checkCompatibility, } from "@nylorun/core/compatibility";
|
|
1
|
+
import { PROTOCOL_FEATURES, PROTOCOL_HEADER, PROTOCOL_VERSION, PUBLISHABLE_KEY_HEADER, TENANT_HEADER, checkCompatibility, } from "@nylorun/core/compatibility";
|
|
2
2
|
export function env(name) {
|
|
3
3
|
return typeof process !== "undefined" ? process.env[name] : undefined;
|
|
4
4
|
}
|
|
@@ -54,28 +54,41 @@ function parseProtocolRange(value) {
|
|
|
54
54
|
}
|
|
55
55
|
export class Transport {
|
|
56
56
|
url;
|
|
57
|
+
/** The Tenant key; empty for a client that uses subject tokens. */
|
|
57
58
|
key;
|
|
59
|
+
/** The Tenant id; empty when a publishable key names it. */
|
|
58
60
|
tenant;
|
|
61
|
+
token;
|
|
62
|
+
publishableKey;
|
|
59
63
|
fetcher;
|
|
60
64
|
/** Sent on every request, e.g. `Nylorun-Subject` and `Nylorun-Scopes` (`withHeaders`). */
|
|
61
65
|
headers = {};
|
|
62
66
|
check = { compatible: false, features: [] };
|
|
63
|
-
constructor(options = {}
|
|
67
|
+
constructor(options = {}) {
|
|
64
68
|
const url = options.url ?? env("NYLORUN_RUNTIME_URL");
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
const tenant = options.tenant ?? env("NYLORUN_TENANT");
|
|
68
|
-
if (!url || !key)
|
|
69
|
-
throw new Error(
|
|
70
|
-
if (
|
|
69
|
+
const token = options.token;
|
|
70
|
+
const key = token ? "" : options.key ?? env("NYLORUN_SERVER_KEY");
|
|
71
|
+
const tenant = options.tenant ?? (token ? undefined : env("NYLORUN_TENANT"));
|
|
72
|
+
if (!url || (!token && !key))
|
|
73
|
+
throw new Error("Set Runtime url and server key explicitly or via NYLORUN_RUNTIME_URL / NYLORUN_SERVER_KEY");
|
|
74
|
+
if (token && options.key)
|
|
75
|
+
throw new Error("Use a Tenant key or subject tokens, not both");
|
|
76
|
+
if (!tenant && !options.publishableKey)
|
|
71
77
|
throw new Error("Set tenant explicitly or via NYLORUN_TENANT");
|
|
72
78
|
const parsed = new URL(url);
|
|
73
79
|
if (!["http:", "https:"].includes(parsed.protocol))
|
|
74
80
|
throw new Error("Runtime requires an HTTP(S) URL");
|
|
75
81
|
this.url = url.replace(/\/$/, "");
|
|
76
82
|
this.key = key;
|
|
77
|
-
this.tenant = tenant;
|
|
78
|
-
this.
|
|
83
|
+
this.tenant = tenant ?? "";
|
|
84
|
+
this.token = token;
|
|
85
|
+
this.publishableKey = options.publishableKey;
|
|
86
|
+
// Browsers may not call `/health` (it refuses `Origin`); token clients rely on `426`.
|
|
87
|
+
if (token)
|
|
88
|
+
this.check.compatible = true;
|
|
89
|
+
// Called as a method on a page's window would otherwise lose `this`.
|
|
90
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
91
|
+
this.fetcher = options.fetch ? fetcher : (input, init) => fetcher(input, init);
|
|
79
92
|
}
|
|
80
93
|
/**
|
|
81
94
|
* The same destination with `headers` added to every request. The copy shares this
|
|
@@ -87,6 +100,14 @@ export class Transport {
|
|
|
87
100
|
headers: Object.freeze({ ...this.headers, ...headers }),
|
|
88
101
|
});
|
|
89
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* The same destination with another bearer (a delivery token for an Action endpoint's
|
|
105
|
+
* callbacks). Like `withHeaders`, the copy shares this transport's compatibility check.
|
|
106
|
+
*/
|
|
107
|
+
withKey(key) {
|
|
108
|
+
const copy = Object.create(Transport.prototype);
|
|
109
|
+
return Object.assign(copy, this, { key });
|
|
110
|
+
}
|
|
90
111
|
/** Clears the cached Host compatibility result (used after a 426). */
|
|
91
112
|
clearCompatibilityCache() {
|
|
92
113
|
this.check.compatible = false;
|
|
@@ -123,19 +144,37 @@ export class Transport {
|
|
|
123
144
|
if (!result.ok)
|
|
124
145
|
throw new IncompatibleRuntimeError(result);
|
|
125
146
|
this.check.features = [...protocol.features];
|
|
147
|
+
this.check.range = protocol;
|
|
126
148
|
this.check.compatible = true;
|
|
127
149
|
}
|
|
150
|
+
/** Throws `IncompatibleRuntimeError` before anything is sent when the Host lacks `feature`. */
|
|
151
|
+
async requireFeature(feature, signal) {
|
|
152
|
+
const features = await this.hostFeatures(signal);
|
|
153
|
+
if (!features.includes(feature))
|
|
154
|
+
throw new IncompatibleRuntimeError({
|
|
155
|
+
ok: false,
|
|
156
|
+
reason: "feature",
|
|
157
|
+
missing: [feature],
|
|
158
|
+
host: this.check.range ?? { min: 0, max: 0, features },
|
|
159
|
+
});
|
|
160
|
+
}
|
|
128
161
|
/** The Host's protocol features, including optional ones, from its `/health`. */
|
|
129
162
|
async hostFeatures(signal) {
|
|
130
163
|
await this.ensureCompatible(signal);
|
|
131
164
|
return this.check.features;
|
|
132
165
|
}
|
|
133
|
-
authHeaders(init = {}) {
|
|
166
|
+
async authHeaders(init = {}) {
|
|
134
167
|
const headers = new Headers(init.headers);
|
|
135
168
|
for (const [name, value] of Object.entries(this.headers))
|
|
136
169
|
headers.set(name, value);
|
|
137
|
-
|
|
138
|
-
|
|
170
|
+
const bearer = this.token
|
|
171
|
+
? await this.token.get(init.signal ?? undefined)
|
|
172
|
+
: this.key;
|
|
173
|
+
headers.set("Authorization", `Bearer ${bearer}`);
|
|
174
|
+
if (this.tenant)
|
|
175
|
+
headers.set(TENANT_HEADER, this.tenant);
|
|
176
|
+
if (this.publishableKey)
|
|
177
|
+
headers.set(PUBLISHABLE_KEY_HEADER, this.publishableKey);
|
|
139
178
|
headers.set(PROTOCOL_HEADER, String(PROTOCOL_VERSION));
|
|
140
179
|
if (init.body)
|
|
141
180
|
headers.set("Content-Type", "application/json");
|
|
@@ -145,9 +184,18 @@ export class Transport {
|
|
|
145
184
|
await this.ensureCompatible(init.signal === null ? undefined : init.signal);
|
|
146
185
|
const response = await this.fetcher(this.url + path, {
|
|
147
186
|
...init,
|
|
148
|
-
headers: this.authHeaders(init),
|
|
187
|
+
headers: await this.authHeaders(init),
|
|
149
188
|
redirect: "error",
|
|
150
189
|
});
|
|
190
|
+
// An expired or revoked subject token: get a new one and try once more.
|
|
191
|
+
if (response.status === 401 && this.token && !options.retried401) {
|
|
192
|
+
const body = (await response.clone().json().catch(() => undefined));
|
|
193
|
+
if (body?.code === "token_expired") {
|
|
194
|
+
await response.body?.cancel().catch(() => { });
|
|
195
|
+
this.token.invalidate();
|
|
196
|
+
return this.request(path, init, { ...options, retried401: true });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
151
199
|
if (response.status === 426) {
|
|
152
200
|
this.clearCompatibilityCache();
|
|
153
201
|
if (!options.retried426) {
|
|
@@ -185,6 +233,18 @@ export class Transport {
|
|
|
185
233
|
}
|
|
186
234
|
return response;
|
|
187
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Sends a request with this client's credentials and returns the Runtime's response as it
|
|
238
|
+
* is, errors included (an app server passing a response through, e.g. the AG-UI handler).
|
|
239
|
+
*/
|
|
240
|
+
async forward(path, init = {}) {
|
|
241
|
+
await this.ensureCompatible(init.signal === null ? undefined : init.signal);
|
|
242
|
+
return this.fetcher(this.url + path, {
|
|
243
|
+
...init,
|
|
244
|
+
headers: await this.authHeaders(init),
|
|
245
|
+
redirect: "error",
|
|
246
|
+
});
|
|
247
|
+
}
|
|
188
248
|
async json(path, method = "GET", body, signal) {
|
|
189
249
|
const response = await this.request(path, {
|
|
190
250
|
method,
|
package/dist/index.d.ts
CHANGED
|
@@ -4,18 +4,21 @@ export { Agent, AgentBuilder } from "./builder.js";
|
|
|
4
4
|
export { AgentBuildError, AgentLifecycleError, Loop, Chain, Switch, Parallel, Map, VerdictSchema, isVerdict, withInstructions, withoutTools, WorkflowBuildError, isBuiltWorkflow, capability, CapabilityBuilder, flow, tool, defineSchema, ToolError, } from "@nylorun/core/define";
|
|
5
5
|
export type { FlowAgentBuilder, Flow, Named, StageArgs, NestedStageArgs, CapabilityIdentity, } from "@nylorun/core/define";
|
|
6
6
|
export type { AgentOptions, AgentManifest, BuiltAgent, BuiltWorkflow, LoopOptions, LoopDecideArgs, LoopVerifyArgs, LoopDecision, ChainOptions, SwitchOptions, ParallelOptions, MapOptions, Verdict, WorkflowBinding, WorkflowManifest, ToolDefinition, ToolExecutionContext, ToolOutcome, Patch, Decision, TurnDecision, HookScope, BeforeHook, AfterHook, JsonValue, JsonObject, } from "@nylorun/core/define";
|
|
7
|
-
export type { LiveEvent, SessionCommand, Action, ActionOutcome, CredentialInfo, CredentialSelection, VaultInfo, SubjectScope, } from "@nylorun/core/contracts";
|
|
7
|
+
export type { LiveEvent, SessionEvent, SessionEventOf, EventType, SessionCommand, Action, ActionOutcome, CredentialInfo, CredentialSelection, VaultInfo, SubjectScope, } from "@nylorun/core/contracts";
|
|
8
8
|
export { SUBJECT_SCOPES } from "@nylorun/core/contracts";
|
|
9
9
|
export { AgentsClient, SessionClient, createClient } from "./client.js";
|
|
10
10
|
export type { ActAsOptions, AgentSource, SessionView, CommandOptions, SessionSandbox, } from "./client.js";
|
|
11
|
-
export {
|
|
12
|
-
export type {
|
|
11
|
+
export { AccessClient, PublishableKeysClient, SigningKeysClient, TokensClient, } from "./access.js";
|
|
12
|
+
export type { CreateTokenOptions } from "./access.js";
|
|
13
|
+
export { createTokenEndpoint } from "./token-endpoint.js";
|
|
14
|
+
export type { TokenEndpointOptions } from "./token-endpoint.js";
|
|
15
|
+
export { createActionHandler } from "./action-handler.js";
|
|
16
|
+
export type { ActionHandler, ActionHandlerOptions, RegisterOptions, } from "./action-handler.js";
|
|
13
17
|
export type { ExecuteActionOptions, ExecutableDefinition, } from "./execute-action.js";
|
|
14
18
|
export { resolveConnection, ConnectionError } from "./connection.js";
|
|
15
19
|
export type { ResolvedConnection } from "./connection.js";
|
|
16
|
-
export { deriveExecutorToken } from "./derived-credentials.js";
|
|
17
20
|
export { RuntimeError, IncompatibleRuntimeError } from "./http.js";
|
|
18
|
-
export type { Destination, IncompatibleReason } from "./http.js";
|
|
21
|
+
export type { Destination, IncompatibleReason, TokenSource } from "./http.js";
|
|
19
22
|
export { plugin } from "./plugins/plugin.js";
|
|
20
23
|
export type { PluginCapability } from "./plugins/plugin.js";
|
|
21
24
|
export { loadPlugin, PluginError } from "./plugins/load.js";
|
|
@@ -26,6 +29,5 @@ export { skills, loadSkillsFromDirectory, resolveSkillsRoot, parseSkill, SkillsE
|
|
|
26
29
|
export type { SkillsCapability, SkillsOptions, SkillDiagnostic, } from "./skills/index.js";
|
|
27
30
|
export { mcp, McpError } from "./mcp/index.js";
|
|
28
31
|
export type { McpCapability, McpOptions, McpServerSpec } from "./mcp/index.js";
|
|
29
|
-
export {
|
|
30
|
-
export type { SandboxCapability, SandboxCapabilityOptions, SandboxOptions, ActionSandbox, ActionSandboxToolResult, CreateActionSandboxOptions, } from "./sandbox/index.js";
|
|
32
|
+
export type { ActionSandbox, ActionSandboxToolResult, CreateActionSandboxOptions, } from "./sandbox/index.js";
|
|
31
33
|
export { createActionSandbox, definitionDeclaresSandbox, isActionSandboxTool, } from "./sandbox/index.js";
|
package/dist/index.js
CHANGED
|
@@ -4,14 +4,14 @@ export { Agent, AgentBuilder } from "./builder.js";
|
|
|
4
4
|
export { AgentBuildError, AgentLifecycleError, Loop, Chain, Switch, Parallel, Map, VerdictSchema, isVerdict, withInstructions, withoutTools, WorkflowBuildError, isBuiltWorkflow, capability, CapabilityBuilder, flow, tool, defineSchema, ToolError, } from "@nylorun/core/define";
|
|
5
5
|
export { SUBJECT_SCOPES } from "@nylorun/core/contracts";
|
|
6
6
|
export { AgentsClient, SessionClient, createClient } from "./client.js";
|
|
7
|
-
export {
|
|
7
|
+
export { AccessClient, PublishableKeysClient, SigningKeysClient, TokensClient, } from "./access.js";
|
|
8
|
+
export { createTokenEndpoint } from "./token-endpoint.js";
|
|
9
|
+
export { createActionHandler } from "./action-handler.js";
|
|
8
10
|
export { resolveConnection, ConnectionError } from "./connection.js";
|
|
9
|
-
export { deriveExecutorToken } from "./derived-credentials.js";
|
|
10
11
|
export { RuntimeError, IncompatibleRuntimeError } from "./http.js";
|
|
11
12
|
export { plugin } from "./plugins/plugin.js";
|
|
12
13
|
export { loadPlugin, PluginError } from "./plugins/load.js";
|
|
13
14
|
export { prepareStdioLaunch, expandPluginPlaceholders } from "./plugins/launch.js";
|
|
14
15
|
export { skills, loadSkillsFromDirectory, resolveSkillsRoot, parseSkill, SkillsError, formatSkillCatalog, SKILLS_USAGE, } from "./skills/index.js";
|
|
15
16
|
export { mcp, McpError } from "./mcp/index.js";
|
|
16
|
-
export { sandbox, SandboxError } from "./sandbox/index.js";
|
|
17
17
|
export { createActionSandbox, definitionDeclaresSandbox, isActionSandboxTool, } from "./sandbox/index.js";
|
package/dist/sandbox/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Action-scoped sandbox client (`ctx.sandbox`). Calls `POST /v1/actions/:id/sandbox/:tool`
|
|
3
|
+
* over a transport whose credential is the Action's delivery token.
|
|
4
4
|
*/
|
|
5
5
|
import { type SandboxToolName } from "@nylorun/core/define";
|
|
6
6
|
import { type Transport } from "../http.js";
|
|
@@ -45,13 +45,12 @@ export type ActionSandbox = {
|
|
|
45
45
|
}) => Promise<ActionSandboxToolResult>;
|
|
46
46
|
};
|
|
47
47
|
export type CreateActionSandboxOptions = {
|
|
48
|
+
/** The transport's key is the delivery token, which names the Action and its generation. */
|
|
48
49
|
readonly transport: Transport;
|
|
49
50
|
readonly actionId: string;
|
|
50
|
-
readonly claimId: string;
|
|
51
|
-
readonly generation: number;
|
|
52
51
|
readonly signal?: AbortSignal;
|
|
53
52
|
};
|
|
54
|
-
/** Build `ctx.sandbox` for one
|
|
53
|
+
/** Build `ctx.sandbox` for one delivered action. Callers skip it when the session has none. */
|
|
55
54
|
export declare function createActionSandbox(options: CreateActionSandboxOptions): ActionSandbox;
|
|
56
55
|
export declare function isActionSandboxTool(name: string): name is SandboxToolName;
|
|
57
56
|
/** True when the executable declares a sandbox the Runtime can share. */
|
package/dist/sandbox/client.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Action-scoped sandbox client (`ctx.sandbox`). Calls `POST /v1/actions/:id/sandbox/:tool`
|
|
3
|
+
* over a transport whose credential is the Action's delivery token.
|
|
4
4
|
*/
|
|
5
5
|
import { SANDBOX_TOOL_NAMES, } from "@nylorun/core/define";
|
|
6
6
|
import { segment } from "../http.js";
|
|
7
|
-
/** Build `ctx.sandbox` for one
|
|
7
|
+
/** Build `ctx.sandbox` for one delivered action. Callers skip it when the session has none. */
|
|
8
8
|
export function createActionSandbox(options) {
|
|
9
|
-
const call = (tool, input) => options.transport.json(`/v1/actions/${segment(options.actionId)}/sandbox/${tool}`, "POST",
|
|
10
|
-
claimId: options.claimId,
|
|
11
|
-
generation: options.generation,
|
|
12
|
-
...input,
|
|
13
|
-
}, options.signal);
|
|
9
|
+
const call = (tool, input) => options.transport.json(`/v1/actions/${segment(options.actionId)}/sandbox/${tool}`, "POST", input, options.signal);
|
|
14
10
|
const sandbox = {
|
|
15
11
|
bash: (input) => call("bash", input),
|
|
16
12
|
read: (input) => call("read", input),
|
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
export { sandbox, SandboxError } from "@nylorun/core/define";
|
|
2
|
-
export type { SandboxCapability, SandboxCapabilityOptions, SandboxOptions, } from "@nylorun/core/define";
|
|
3
1
|
export { createActionSandbox, definitionDeclaresSandbox, isActionSandboxTool, } from "./client.js";
|
|
4
2
|
export type { ActionSandbox, ActionSandboxToolResult, CreateActionSandboxOptions, } from "./client.js";
|
package/dist/sandbox/index.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type BuiltWorkflow } from "@nylorun/core/define";
|
|
2
|
+
import { type AgentSource } from "./client.js";
|
|
3
|
+
import type { ExecutableDefinition } from "./execute-action.js";
|
|
4
|
+
/** The implementation version to register: the option, `NYLORUN_IMPLEMENTATION_VERSION`, or `dev`. */
|
|
5
|
+
export declare function implementationVersionOf(options: {
|
|
6
|
+
implementationVersion?: string;
|
|
7
|
+
}): string;
|
|
8
|
+
/** The ids among `agents` that are saved only as part of another definition. */
|
|
9
|
+
export declare function embeddedIn(agents: Map<string, ExecutableDefinition>): ReadonlySet<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Every definition `sources` serves, by id: the agents and workflows passed in, the agents
|
|
12
|
+
* a v2 workflow embeds, and flow agents used as tools. `owner` names the caller in errors.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildAgents(sources: readonly (AgentSource | BuiltWorkflow)[], owner: string): Map<string, ExecutableDefinition>;
|
|
15
|
+
/**
|
|
16
|
+
* The manifest hash served for a workflow's flow actions. A run is pinned to one workflow
|
|
17
|
+
* manifest, and its stage keys may shift between deploys, so flow actions for another hash
|
|
18
|
+
* are left for whoever serves it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function flowManifestHash(agent: ExecutableDefinition): string | undefined;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** The definitions an application serves Actions for (`createActionHandler`). */
|
|
2
|
+
import { AgentManifestSchema } from "@nylorun/core/contracts";
|
|
3
|
+
import { agentFrom, delegateOf, hashManifest, isFlowDelegate, isBuiltWorkflow, } from "@nylorun/core/define";
|
|
4
|
+
import { assertNoMiddlewareClosures } from "./client.js";
|
|
5
|
+
import { env } from "./http.js";
|
|
6
|
+
/** The implementation version to register: the option, `NYLORUN_IMPLEMENTATION_VERSION`, or `dev`. */
|
|
7
|
+
export function implementationVersionOf(options) {
|
|
8
|
+
return (options.implementationVersion ??
|
|
9
|
+
env("NYLORUN_IMPLEMENTATION_VERSION") ??
|
|
10
|
+
"dev");
|
|
11
|
+
}
|
|
12
|
+
/** Agents embedded in a v2 workflow: served here, but saved only as part of the workflow. */
|
|
13
|
+
const embeddedAgents = new WeakMap();
|
|
14
|
+
/** The ids among `agents` that are saved only as part of another definition. */
|
|
15
|
+
export function embeddedIn(agents) {
|
|
16
|
+
return embeddedAgents.get(agents) ?? new Set();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Every definition `sources` serves, by id: the agents and workflows passed in, the agents
|
|
20
|
+
* a v2 workflow embeds, and flow agents used as tools. `owner` names the caller in errors.
|
|
21
|
+
*/
|
|
22
|
+
export function buildAgents(sources, owner) {
|
|
23
|
+
const agents = new Map();
|
|
24
|
+
const embedded = new Set();
|
|
25
|
+
/**
|
|
26
|
+
* Agents embedded in another definition (a v2 flow's agents, a flow agent used as a
|
|
27
|
+
* tool) may be reached from more than one place; the same definition is served once.
|
|
28
|
+
*/
|
|
29
|
+
const sameAsServed = (id, manifest) => {
|
|
30
|
+
const served = agents.get(id);
|
|
31
|
+
if (!served)
|
|
32
|
+
return false;
|
|
33
|
+
if (hashManifest(served.manifest) === hashManifest(manifest))
|
|
34
|
+
return true;
|
|
35
|
+
throw new Error(`Duplicate connected agent ${id}`);
|
|
36
|
+
};
|
|
37
|
+
const addAgent = (built, shared = false) => {
|
|
38
|
+
assertNoMiddlewareClosures(built);
|
|
39
|
+
AgentManifestSchema.parse(built.manifest);
|
|
40
|
+
if (shared ? sameAsServed(built.id, built.manifest) : agents.has(built.id)) {
|
|
41
|
+
if (!shared)
|
|
42
|
+
throw new Error(`Duplicate connected agent ${built.id}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
agents.set(built.id, built);
|
|
46
|
+
for (const tool of built.getBinding().tools) {
|
|
47
|
+
const delegate = delegateOf(tool);
|
|
48
|
+
if (!delegate || !isFlowDelegate(delegate))
|
|
49
|
+
continue;
|
|
50
|
+
// A flow agent used as a tool runs in its own linked session: serve its code too.
|
|
51
|
+
if (!delegate.workflow)
|
|
52
|
+
throw new Error(`Flow agent '${delegate.manifest.id}' is used as a tool by '${built.id}' but has no local implementation`);
|
|
53
|
+
addWorkflow(delegate.workflow, true);
|
|
54
|
+
embedded.add(delegate.workflow.id);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const addWorkflow = (workflow, shared = false) => {
|
|
58
|
+
if (shared ? sameAsServed(workflow.id, workflow.manifest) : agents.has(workflow.id)) {
|
|
59
|
+
if (!shared)
|
|
60
|
+
throw new Error(`Duplicate connected agent ${workflow.id}`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
agents.set(workflow.id, workflow);
|
|
64
|
+
const v2 = workflow.manifest.workflowSchemaVersion === 2;
|
|
65
|
+
for (const binding of Object.values(workflow.getBinding().agents)) {
|
|
66
|
+
addAgent(agentFrom(binding.manifest, binding.implementations), v2);
|
|
67
|
+
if (v2)
|
|
68
|
+
embedded.add(binding.manifest.id);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
for (const source of sources) {
|
|
72
|
+
if (isBuiltWorkflow(source)) {
|
|
73
|
+
addWorkflow(source);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const built = source.build?.() ?? source;
|
|
77
|
+
if (isBuiltWorkflow(built)) {
|
|
78
|
+
addWorkflow(built);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
addAgent(built);
|
|
82
|
+
}
|
|
83
|
+
if (!agents.size)
|
|
84
|
+
throw new Error(`${owner} requires at least one agent`);
|
|
85
|
+
// A definition passed in directly is saved on its own, even if another one embeds it.
|
|
86
|
+
for (const source of sources)
|
|
87
|
+
embedded.delete(source.id);
|
|
88
|
+
embeddedAgents.set(agents, embedded);
|
|
89
|
+
return agents;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The manifest hash served for a workflow's flow actions. A run is pinned to one workflow
|
|
93
|
+
* manifest, and its stage keys may shift between deploys, so flow actions for another hash
|
|
94
|
+
* are left for whoever serves it.
|
|
95
|
+
*/
|
|
96
|
+
export function flowManifestHash(agent) {
|
|
97
|
+
return isBuiltWorkflow(agent) && agent.manifest.workflowSchemaVersion === 2
|
|
98
|
+
? hashManifest(agent.manifest)
|
|
99
|
+
: undefined;
|
|
100
|
+
}
|