@nylorun/agents 0.4.0-beta → 0.6.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/dist/http.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { PROTOCOL_FEATURES, PROTOCOL_HEADER, PROTOCOL_VERSION, TENANT_HEADER, checkCompatibility, } from "@nylorun/core/compatibility";
1
2
  export function env(name) {
2
3
  return typeof process !== "undefined" ? process.env[name] : undefined;
3
4
  }
@@ -10,40 +11,156 @@ export class RuntimeError extends Error {
10
11
  this.body = body;
11
12
  }
12
13
  }
14
+ /** Host protocol is outside the client's supported range or missing required features. */
15
+ export class IncompatibleRuntimeError extends Error {
16
+ compatibility;
17
+ remedy;
18
+ host;
19
+ constructor(compatibility) {
20
+ const remedy = remedyFor(compatibility);
21
+ const detail = compatibility.reason === "version"
22
+ ? `client protocol ${compatibility.client} is outside Host range ${compatibility.host.min}–${compatibility.host.max}`
23
+ : `Host is missing required features: ${compatibility.missing.join(", ")}`;
24
+ super(`Incompatible Runtime: ${detail}. ${remedy}`);
25
+ this.name = "IncompatibleRuntimeError";
26
+ this.compatibility = compatibility;
27
+ this.remedy = remedy;
28
+ this.host = compatibility.host;
29
+ }
30
+ }
31
+ function remedyFor(compatibility) {
32
+ if (compatibility.reason === "feature") {
33
+ return "Upgrade the Runtime Host (nylorun runtime restart from a newer CLI) so it advertises the required features.";
34
+ }
35
+ if (compatibility.client < compatibility.host.min) {
36
+ return "Upgrade this client (npm i -D @nylorun/agents@latest) or use a CLI that matches the Host protocol.";
37
+ }
38
+ return "Upgrade the Runtime Host with nylorun runtime restart from a newer CLI, or install a matching older client (npm i -D @nylorun/cli@<compatible>).";
39
+ }
40
+ function parseProtocolRange(value) {
41
+ if (!value || typeof value !== "object" || Array.isArray(value))
42
+ return undefined;
43
+ const record = value;
44
+ if (typeof record.min !== "number" ||
45
+ typeof record.max !== "number" ||
46
+ !Array.isArray(record.features) ||
47
+ !record.features.every((f) => typeof f === "string"))
48
+ return undefined;
49
+ return {
50
+ min: record.min,
51
+ max: record.max,
52
+ features: record.features,
53
+ };
54
+ }
13
55
  export class Transport {
14
56
  url;
15
57
  key;
58
+ tenant;
16
59
  fetcher;
60
+ compatible = false;
17
61
  constructor(options = {}, role = "server") {
18
62
  const url = options.url ?? env("NYLORUN_RUNTIME_URL");
19
63
  const key = options.key ??
20
64
  env(role === "server" ? "NYLORUN_SERVER_KEY" : "NYLORUN_EXECUTOR_KEY");
65
+ const tenant = options.tenant ?? env("NYLORUN_TENANT");
21
66
  if (!url || !key)
22
67
  throw new Error(`Set Runtime url and ${role} key explicitly or via NYLORUN_RUNTIME_URL / NYLORUN_${role.toUpperCase()}_KEY`);
68
+ if (!tenant)
69
+ throw new Error("Set tenant explicitly or via NYLORUN_TENANT");
23
70
  const parsed = new URL(url);
24
71
  if (!["http:", "https:"].includes(parsed.protocol))
25
72
  throw new Error("Runtime requires an HTTP(S) URL");
26
73
  this.url = url.replace(/\/$/, "");
27
74
  this.key = key;
75
+ this.tenant = tenant;
28
76
  this.fetcher = options.fetch ?? globalThis.fetch;
29
77
  }
30
- async request(path, init = {}) {
78
+ /** Clears the cached Host compatibility result (used after a 426). */
79
+ clearCompatibilityCache() {
80
+ this.compatible = false;
81
+ }
82
+ async ensureCompatible(signal) {
83
+ if (this.compatible)
84
+ return;
85
+ const response = await this.fetcher(`${this.url}/health`, {
86
+ method: "GET",
87
+ redirect: "error",
88
+ signal,
89
+ });
90
+ const text = await response.text();
91
+ let body = text;
92
+ try {
93
+ body = JSON.parse(text);
94
+ }
95
+ catch {
96
+ /* keep text */
97
+ }
98
+ if (!response.ok)
99
+ throw new RuntimeError(response.status, body);
100
+ const protocol = parseProtocolRange(body && typeof body === "object" && !Array.isArray(body)
101
+ ? body.protocol
102
+ : undefined);
103
+ if (!protocol)
104
+ throw new IncompatibleRuntimeError({
105
+ ok: false,
106
+ reason: "feature",
107
+ missing: [...PROTOCOL_FEATURES],
108
+ host: { min: 0, max: 0, features: [] },
109
+ });
110
+ const result = checkCompatibility({ version: PROTOCOL_VERSION, required: [...PROTOCOL_FEATURES] }, protocol);
111
+ if (!result.ok)
112
+ throw new IncompatibleRuntimeError(result);
113
+ this.compatible = true;
114
+ }
115
+ authHeaders(init = {}) {
31
116
  const headers = new Headers(init.headers);
32
117
  headers.set("Authorization", `Bearer ${this.key}`);
118
+ headers.set(TENANT_HEADER, this.tenant);
119
+ headers.set(PROTOCOL_HEADER, String(PROTOCOL_VERSION));
33
120
  if (init.body)
34
121
  headers.set("Content-Type", "application/json");
122
+ return headers;
123
+ }
124
+ async request(path, init = {}, options = {}) {
125
+ await this.ensureCompatible(init.signal === null ? undefined : init.signal);
35
126
  const response = await this.fetcher(this.url + path, {
36
127
  ...init,
37
- headers,
128
+ headers: this.authHeaders(init),
38
129
  redirect: "error",
39
130
  });
131
+ if (response.status === 426) {
132
+ this.clearCompatibilityCache();
133
+ if (!options.retried426) {
134
+ await this.ensureCompatible(init.signal === null ? undefined : init.signal);
135
+ return this.request(path, init, { retried426: true });
136
+ }
137
+ const text = await response.text();
138
+ let body = text;
139
+ try {
140
+ body = JSON.parse(text);
141
+ }
142
+ catch {
143
+ /* keep text */
144
+ }
145
+ const protocol = parseProtocolRange(body && typeof body === "object" && !Array.isArray(body)
146
+ ? body.protocol
147
+ : undefined);
148
+ if (protocol) {
149
+ const result = checkCompatibility({ version: PROTOCOL_VERSION, required: [...PROTOCOL_FEATURES] }, protocol);
150
+ if (!result.ok)
151
+ throw new IncompatibleRuntimeError(result);
152
+ }
153
+ throw new RuntimeError(426, body);
154
+ }
40
155
  if (!response.ok) {
41
156
  const text = await response.text();
42
157
  let body = text;
43
158
  try {
44
159
  body = JSON.parse(text);
45
160
  }
46
- catch { }
161
+ catch {
162
+ /* keep text */
163
+ }
47
164
  throw new RuntimeError(response.status, body);
48
165
  }
49
166
  return response;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,18 @@
1
- export { Agent, AgentBuilder, AgentBuildError, AgentLifecycleError, capability, tool, defineSchema, ToolError, } from "@nylorun/core/define";
2
- export type { AgentOptions, AgentManifest, BuiltAgent, ToolDefinition, ToolExecutionContext, ToolOutcome, Patch, Decision, TurnDecision, HookScope, BeforeHook, AfterHook, JsonValue, JsonObject, } from "@nylorun/core/define";
1
+ export { hashManifest, PROTOCOL_VERSION, PROTOCOL_FEATURES, HOST_PROTOCOL, DEFINITION_SCHEMA_VERSION, TENANT_HEADER, PROTOCOL_HEADER, TENANT_ID_PATTERN, isTenantId, newTenantId, newPrincipalId, checkCompatibility, compareVersions, ERROR_CODES, } from "@nylorun/core/compatibility";
2
+ export type { ProtocolFeature, ProtocolRange, Compatibility, ErrorCode, } from "@nylorun/core/compatibility";
3
+ export { Agent, AgentBuilder, AgentBuildError, AgentLifecycleError, Loop, Chain, Switch, Parallel, Map, VerdictSchema, isVerdict, withInstructions, withoutTools, WorkflowBuildError, isBuiltWorkflow, capability, tool, defineSchema, ToolError, } from "@nylorun/core/define";
4
+ 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";
3
5
  export type { LiveEvent, SessionCommand, Action, ActionOutcome, CredentialInfo, CredentialSelection, VaultInfo, } from "@nylorun/core/contracts";
4
6
  export { AgentsClient, SessionClient, createClient } from "./client.js";
5
- export type { AgentSource, SessionView, CommandOptions } from "./client.js";
7
+ export type { AgentSource, SessionView, CommandOptions, SessionSandbox, } from "./client.js";
6
8
  export { connectAgents } from "./executor.js";
7
9
  export type { ConnectOptions, AgentConnection } from "./executor.js";
8
- export { RuntimeError } from "./http.js";
9
- export type { Destination } from "./http.js";
10
+ export type { ExecuteActionOptions, ExecutableDefinition, } from "./execute-action.js";
11
+ export { resolveConnection, ConnectionError } from "./connection.js";
12
+ export type { ResolvedConnection } from "./connection.js";
13
+ export { deriveExecutorToken } from "./derived-credentials.js";
14
+ export { RuntimeError, IncompatibleRuntimeError } from "./http.js";
15
+ export type { Destination, IncompatibleReason } from "./http.js";
10
16
  export { plugin } from "./plugins/plugin.js";
11
17
  export type { PluginCapability } from "./plugins/plugin.js";
12
18
  export { loadPlugin, PluginError } from "./plugins/load.js";
@@ -18,4 +24,5 @@ export type { SkillsCapability, SkillsOptions, SkillDiagnostic, } from "./skills
18
24
  export { mcp, McpError } from "./mcp/index.js";
19
25
  export type { McpCapability, McpOptions } from "./mcp/index.js";
20
26
  export { sandbox, SandboxError } from "./sandbox/index.js";
21
- export type { SandboxCapability, SandboxCapabilityOptions, SandboxOptions, } from "./sandbox/index.js";
27
+ export type { SandboxCapability, SandboxCapabilityOptions, SandboxOptions, ActionSandbox, ActionSandboxToolResult, CreateActionSandboxOptions, } from "./sandbox/index.js";
28
+ export { createActionSandbox, definitionDeclaresSandbox, isActionSandboxTool, } from "./sandbox/index.js";
package/dist/index.js CHANGED
@@ -1,11 +1,15 @@
1
1
  // Definition authoring and wire contracts are the only harness runtime imports.
2
- export { Agent, AgentBuilder, AgentBuildError, AgentLifecycleError, capability, tool, defineSchema, ToolError, } from "@nylorun/core/define";
2
+ export { hashManifest, PROTOCOL_VERSION, PROTOCOL_FEATURES, HOST_PROTOCOL, DEFINITION_SCHEMA_VERSION, TENANT_HEADER, PROTOCOL_HEADER, TENANT_ID_PATTERN, isTenantId, newTenantId, newPrincipalId, checkCompatibility, compareVersions, ERROR_CODES, } from "@nylorun/core/compatibility";
3
+ export { Agent, AgentBuilder, AgentBuildError, AgentLifecycleError, Loop, Chain, Switch, Parallel, Map, VerdictSchema, isVerdict, withInstructions, withoutTools, WorkflowBuildError, isBuiltWorkflow, capability, tool, defineSchema, ToolError, } from "@nylorun/core/define";
3
4
  export { AgentsClient, SessionClient, createClient } from "./client.js";
4
5
  export { connectAgents } from "./executor.js";
5
- export { RuntimeError } from "./http.js";
6
+ export { resolveConnection, ConnectionError } from "./connection.js";
7
+ export { deriveExecutorToken } from "./derived-credentials.js";
8
+ export { RuntimeError, IncompatibleRuntimeError } from "./http.js";
6
9
  export { plugin } from "./plugins/plugin.js";
7
10
  export { loadPlugin, PluginError } from "./plugins/load.js";
8
11
  export { prepareStdioLaunch, expandPluginPlaceholders } from "./plugins/launch.js";
9
12
  export { skills, loadSkillsFromDirectory, resolveSkillsRoot, parseSkill, SkillsError, formatSkillCatalog, SKILLS_USAGE, } from "./skills/index.js";
10
13
  export { mcp, McpError } from "./mcp/index.js";
11
14
  export { sandbox, SandboxError } from "./sandbox/index.js";
15
+ export { createActionSandbox, definitionDeclaresSandbox, isActionSandboxTool, } from "./sandbox/index.js";
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Claim-scoped sandbox client for executor actions (`ctx.sandbox`).
3
+ * Calls `POST /v1/actions/:id/sandbox/:tool` with the live claim.
4
+ */
5
+ import { type SandboxToolName } from "@nylorun/core/define";
6
+ import { type Transport } from "../http.js";
7
+ export type ActionSandboxToolResult = {
8
+ readonly kind: "completed";
9
+ readonly output: unknown;
10
+ } | {
11
+ readonly kind: "failed";
12
+ readonly code: string;
13
+ readonly message: string;
14
+ };
15
+ export type ActionSandbox = {
16
+ readonly bash: (input: {
17
+ command: string;
18
+ timeout?: number;
19
+ }) => Promise<ActionSandboxToolResult>;
20
+ readonly read: (input: {
21
+ path: string;
22
+ offset?: number;
23
+ limit?: number;
24
+ }) => Promise<ActionSandboxToolResult>;
25
+ readonly write: (input: {
26
+ path: string;
27
+ content: string;
28
+ }) => Promise<ActionSandboxToolResult>;
29
+ readonly edit: (input: {
30
+ path: string;
31
+ old_string: string;
32
+ new_string: string;
33
+ replace_all?: boolean;
34
+ }) => Promise<ActionSandboxToolResult>;
35
+ readonly grep: (input: {
36
+ pattern: string;
37
+ path?: string;
38
+ glob?: string;
39
+ ignore_case?: boolean;
40
+ max_results?: number;
41
+ }) => Promise<ActionSandboxToolResult>;
42
+ readonly glob: (input: {
43
+ pattern: string;
44
+ path?: string;
45
+ }) => Promise<ActionSandboxToolResult>;
46
+ };
47
+ export type CreateActionSandboxOptions = {
48
+ readonly transport: Transport;
49
+ readonly actionId: string;
50
+ readonly claimId: string;
51
+ readonly generation: number;
52
+ readonly signal?: AbortSignal;
53
+ };
54
+ /** Build `ctx.sandbox` for one claimed action. Undefined callers skip when the session has none. */
55
+ export declare function createActionSandbox(options: CreateActionSandboxOptions): ActionSandbox;
56
+ export declare function isActionSandboxTool(name: string): name is SandboxToolName;
57
+ /** True when the executable declares a sandbox the Runtime can share. */
58
+ export declare function definitionDeclaresSandbox(manifest: {
59
+ kind?: string;
60
+ sandbox?: unknown;
61
+ capabilities?: readonly {
62
+ sandbox?: unknown;
63
+ }[];
64
+ }): boolean;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Claim-scoped sandbox client for executor actions (`ctx.sandbox`).
3
+ * Calls `POST /v1/actions/:id/sandbox/:tool` with the live claim.
4
+ */
5
+ import { SANDBOX_TOOL_NAMES, } from "@nylorun/core/define";
6
+ import { segment } from "../http.js";
7
+ /** Build `ctx.sandbox` for one claimed action. Undefined callers skip when the session has none. */
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);
14
+ const sandbox = {
15
+ bash: (input) => call("bash", input),
16
+ read: (input) => call("read", input),
17
+ write: (input) => call("write", input),
18
+ edit: (input) => call("edit", input),
19
+ grep: (input) => call("grep", input),
20
+ glob: (input) => call("glob", input),
21
+ };
22
+ // Freeze so tools cannot replace built-ins.
23
+ return Object.freeze(sandbox);
24
+ }
25
+ export function isActionSandboxTool(name) {
26
+ return SANDBOX_TOOL_NAMES.includes(name);
27
+ }
28
+ /** True when the executable declares a sandbox the Runtime can share. */
29
+ export function definitionDeclaresSandbox(manifest) {
30
+ if (manifest.kind === "workflow")
31
+ return manifest.sandbox !== undefined;
32
+ return (manifest.capabilities ?? []).some((item) => item.sandbox !== undefined);
33
+ }
@@ -1,2 +1,4 @@
1
1
  export { sandbox, SandboxError } from "./sandbox.js";
2
2
  export type { SandboxCapability, SandboxCapabilityOptions, SandboxOptions, } from "./sandbox.js";
3
+ export { createActionSandbox, definitionDeclaresSandbox, isActionSandboxTool, } from "./client.js";
4
+ export type { ActionSandbox, ActionSandboxToolResult, CreateActionSandboxOptions, } from "./client.js";
@@ -1 +1,2 @@
1
1
  export { sandbox, SandboxError } from "./sandbox.js";
2
+ export { createActionSandbox, definitionDeclaresSandbox, isActionSandboxTool, } from "./client.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nylorun/agents",
3
- "version": "0.4.0-beta",
3
+ "version": "0.6.0-beta",
4
4
  "description": "Nylorun agent definitions, session client and connected executor",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -35,7 +35,7 @@
35
35
  "test": "vitest run --passWithNoTests"
36
36
  },
37
37
  "dependencies": {
38
- "@nylorun/core": "0.3.0-beta",
38
+ "@nylorun/core": "0.5.0-beta",
39
39
  "gray-matter": "^4.0.3"
40
40
  },
41
41
  "peerDependencies": {