@nylorun/agents 0.20.0-beta → 0.22.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.
@@ -1,16 +1,20 @@
1
1
  /**
2
2
  * Environments (protocol 11, D55, D56): `client.environments`. An Environment is one sandbox
3
- * (kind `virtual`, `pod` or `none`) with a recipe that can change, and one vault of secrets for
4
- * its shell, MCP servers and HTTP tools. It has its own id and outlives the sessions that name
5
- * it; whether it serves one session, one person or a project is the app's choice, made here:
3
+ * (kind `virtual`, `pod` or `none`) made from an environment manifest's version or from inline
4
+ * fields, and one vault of secrets for its shell, MCP servers and HTTP tools. It never changes
5
+ * what it runs after it is made (protocol 14, D63): a new version reaches an agent through a new
6
+ * Environment. It has its own id and outlives the sessions that name it; whether it serves one
7
+ * session, one person or a project is the app's choice, made here:
6
8
  *
7
9
  * - `environments.forSession(...)`: one Environment for one session. It creates the
8
10
  * Environment, opens the session on it, and `release()` deletes the Environment (and its
9
11
  * vault) when the session is done.
10
- * - `environments.put(id, recipe)`: one Environment per person or per project, by a
11
- * deterministic id (`users/alice/web`); get-or-create, or change its recipe, in one call.
12
- * Write its secrets with `environments.secrets.put(id, name, secret)` and open sessions on it
13
- * with `createSession({ environment: id })`.
12
+ * - `environments.put(id, { manifest: "analyst-box" })` (or inline fields): one Environment per
13
+ * person or per project, by a deterministic id (`users/alice/web`); get-or-create in one call.
14
+ * Write its secrets with `environments.secrets.put(id, name, { value })` and open sessions on
15
+ * it with `createSession({ environment: id })`.
16
+ * - `environments.manifests.save(manifest)`: save an environment manifest's next version, like
17
+ * `saveAgent`; `plan(manifest)` answers what a save would do and saves nothing.
14
18
  *
15
19
  * Ids may hold `/`; they are sent percent-encoded as one path segment. Secret values are
16
20
  * write-only: no call reads one back.
@@ -18,14 +22,39 @@
18
22
  * Disk versions (Host feature `environment-disk-versions`): `snapshot(id)` keeps a version of
19
23
  * the Environment's disk between turns, `restore(id, version)` puts one back, and
20
24
  * `put(id, { from: { environment, version } })` creates a new Environment from another's version.
25
+ *
26
+ * `fork(id, { id: next })` is how an Environment gets a new manifest version (Q15): a new
27
+ * Environment made from it, with the source's disk and secrets; `planFork` answers what it would do.
21
28
  */
22
- import { type DeleteEnvironmentResponse, type EnvironmentEvent, type EnvironmentRestore, type EnvironmentSecretView, type EnvironmentSnapshot, type EnvironmentVersions, type EnvironmentView, type PutEnvironmentRequest, type PutEnvironmentSecretRequest } from "@nylorun/core/contracts";
29
+ import { ENVIRONMENT_MANIFEST_SCHEMA_VERSION, type DeleteEnvironmentManifestResponse, type EnvironmentManifest, type EnvironmentManifestPlan, type EnvironmentManifestVersions, type EnvironmentForkPlan, type EnvironmentManifestView, type ForkEnvironmentRequest, type SaveEnvironmentManifestResponse, type DeleteEnvironmentResponse, type EnvironmentEvent, type EnvironmentEventType, type EnvironmentRestore, type EnvironmentSecretView, type EnvironmentSnapshot, type EnvironmentVersions, type EnvironmentView, type PutEnvironmentRequest, type PutEnvironmentSecretRequest } from "@nylorun/core/contracts";
23
30
  import { type Transport } from "./http.js";
24
31
  import type { CreateSessionOptions, SessionClient } from "./session-client.js";
25
- /** What an Environment is made of: its kind, recipe, labels and owner guard. */
26
- export type EnvironmentRecipeInput = Omit<PutEnvironmentRequest, "requestId">;
27
- /** One secret of an Environment's vault, as written. */
28
- export type EnvironmentSecretInput = PutEnvironmentSecretRequest;
32
+ /**
33
+ * What an Environment is made from: an environment manifest (`manifest: "name"` or `"name@n"`)
34
+ * or the inline fields, and its labels, owner guard and `from`.
35
+ */
36
+ export type EnvironmentInput = Omit<PutEnvironmentRequest, "requestId">;
37
+ /**
38
+ * One secret of an Environment's vault, as written: typed, or only its value (`{ value }`, or
39
+ * `{ headers }` for a `headers` secret) when what the Environment runs declares its slot (D64).
40
+ */
41
+ export type EnvironmentSecretInput = PutEnvironmentSecretRequest | {
42
+ readonly value: string;
43
+ } | {
44
+ readonly headers: Readonly<Record<string, string>>;
45
+ };
46
+ /** An environment manifest as authored: `manifestSchemaVersion` may be left out. */
47
+ export type EnvironmentManifestInput = Omit<EnvironmentManifest, "manifestSchemaVersion"> & {
48
+ readonly manifestSchemaVersion?: typeof ENVIRONMENT_MANIFEST_SCHEMA_VERSION;
49
+ /** For editors; dropped here, as the CLI drops it. */
50
+ readonly $schema?: string;
51
+ };
52
+ /**
53
+ * An environment manifest (protocol 14, D63): checked now against the schema the Runtime
54
+ * enforces, with `manifestSchemaVersion` filled in and `$schema` dropped. Save it with
55
+ * `client.environments.manifests.save()`, or make an Environment from it inline.
56
+ */
57
+ export declare function environmentManifest(input: EnvironmentManifestInput): EnvironmentManifest;
29
58
  /** A session opened on an Environment of its own (`environments.forSession`). */
30
59
  export interface SessionEnvironmentHandle {
31
60
  readonly session: SessionClient;
@@ -38,8 +67,11 @@ export interface SessionEnvironmentHandle {
38
67
  export interface ForSessionOptions {
39
68
  /** The session to open, as `createSession` takes it, without `environment`. */
40
69
  readonly session: Omit<CreateSessionOptions, "environment">;
41
- /** The Environment's recipe and labels. Default: a virtual one within the Tenant's defaults. */
42
- readonly recipe?: EnvironmentRecipeInput;
70
+ /**
71
+ * What the Environment is made from (a `manifest` or inline fields) and its labels. Default: a
72
+ * virtual one within the Tenant's defaults.
73
+ */
74
+ readonly recipe?: EnvironmentInput;
43
75
  /** Secrets to write before the session opens, by name. */
44
76
  readonly secrets?: Readonly<Record<string, EnvironmentSecretInput>>;
45
77
  /** The Environment's id. Default: `sessions/<session id>`. */
@@ -54,7 +86,9 @@ export declare class EnvironmentSecretsClient {
54
86
  /**
55
87
  * Creates or replaces secret `name` (`PUT /v1/environments/{id}/secrets/{name}`): for
56
88
  * `environment_secret` and `environment_variable` the name is the variable's. A second
57
- * credential for a host or a URL is a 409 `credential_conflict`.
89
+ * credential for a host or a URL is a 409 `credential_conflict`. When what the Environment
90
+ * runs declares the secret's slot (D64), send only `{ value }` (or `{ headers }`); a name it
91
+ * does not declare is `409 secret_not_in_manifest`.
58
92
  */
59
93
  put(environmentId: string, name: string, secret: EnvironmentSecretInput, options?: {
60
94
  signal?: AbortSignal;
@@ -72,6 +106,64 @@ export declare class EnvironmentSecretsClient {
72
106
  id: string;
73
107
  }>;
74
108
  }
109
+ /**
110
+ * Environment manifests (protocol 14, D63): `client.environments.manifests`. A save writes the
111
+ * manifest's next version, or answers the latest unchanged, and changes no Environment: an
112
+ * Environment keeps the version it was made from.
113
+ */
114
+ /** The bytes of files by hash, by `sha256:<hex>` (`environmentFiles(...).bytes`). */
115
+ export type EnvironmentFileBytes = Readonly<Record<string, Uint8Array>>;
116
+ /**
117
+ * A manifest `files` entry by content hash (Q6): `contents` (each file's path under `path` and
118
+ * its bytes or text) hashed, as `entry` for the manifest and `bytes` for `manifests.save`'s
119
+ * `files`, which uploads them. Each file holds at most 10 MiB.
120
+ */
121
+ export declare function environmentFiles(path: string, contents: Readonly<Record<string, Uint8Array | string>>): Promise<{
122
+ entry: {
123
+ path: string;
124
+ files: Record<string, string>;
125
+ };
126
+ bytes: Record<string, Uint8Array>;
127
+ }>;
128
+ export declare class EnvironmentManifestsClient {
129
+ private readonly transport;
130
+ constructor(transport: Transport);
131
+ private path;
132
+ private send;
133
+ /**
134
+ * Saves `manifest` (`PUT /v1/environment-manifests/{name}`). `ifMatch`: the version you read
135
+ * (`0` for none yet); a save over a newer one is `412 manifest_changed`. `files`: the bytes of
136
+ * its files by hash (`environmentFiles(...).bytes`), uploaded first when the Runtime lacks them.
137
+ */
138
+ save(manifest: EnvironmentManifestInput, options?: {
139
+ ifMatch?: number;
140
+ files?: EnvironmentFileBytes;
141
+ signal?: AbortSignal;
142
+ }): Promise<SaveEnvironmentManifestResponse>;
143
+ /** What saving `manifest` would do (`?dryRun=true`): changes, errors, warnings, and the Environments behind. */
144
+ plan(manifest: EnvironmentManifestInput, options?: {
145
+ ifMatch?: number;
146
+ files?: EnvironmentFileBytes;
147
+ signal?: AbortSignal;
148
+ }): Promise<EnvironmentManifestPlan>;
149
+ /** The latest version of manifest `name`, or version `version`. */
150
+ get(name: string, options?: {
151
+ version?: number;
152
+ signal?: AbortSignal;
153
+ }): Promise<EnvironmentManifestView>;
154
+ /** Each manifest's latest version. */
155
+ list(options?: {
156
+ signal?: AbortSignal;
157
+ }): Promise<EnvironmentManifestView[]>;
158
+ /** Every version of manifest `name`, newest first. */
159
+ versions(name: string, options?: {
160
+ signal?: AbortSignal;
161
+ }): Promise<EnvironmentManifestVersions>;
162
+ /** Deletes every version; refused while an Environment was made from one (`409 manifest_in_use`). */
163
+ delete(name: string, options?: {
164
+ signal?: AbortSignal;
165
+ }): Promise<DeleteEnvironmentManifestResponse>;
166
+ }
75
167
  export declare class EnvironmentsClient {
76
168
  private readonly transport;
77
169
  /** `AgentsClient.createSession`, bound. */
@@ -82,13 +174,17 @@ export declare class EnvironmentsClient {
82
174
  private path;
83
175
  /** The Environment's secrets. */
84
176
  get secrets(): EnvironmentSecretsClient;
177
+ /** Environment manifests (protocol 14, D63): named, versioned definitions of a kind of Environment. */
178
+ get manifests(): EnvironmentManifestsClient;
85
179
  /**
86
180
  * Creates the Environment and its vault, or finds the one with this id
87
- * (`PUT /v1/environments/{id}`). On an existing one, `kind` and `storage` are fixed (a
88
- * different one is a 409), labels replace, and any other change writes the recipe and bumps
89
- * its `version`: a pod's image and resources apply when it next starts from stopped.
181
+ * (`PUT /v1/environments/{id}`), from an environment manifest (`{ manifest: "name" }` takes
182
+ * the latest version, `"name@n"` version n) or from inline fields. It never changes what it
183
+ * runs after that (protocol 14): on an existing one, labels replace and `ownerUserId` sets or
184
+ * clears the owner guard, fields that match are accepted, and anything else is
185
+ * `409 environment_immutable`.
90
186
  */
91
- put(environmentId: string, recipe?: EnvironmentRecipeInput, options?: {
187
+ put(environmentId: string, recipe?: EnvironmentInput, options?: {
92
188
  signal?: AbortSignal;
93
189
  }): Promise<EnvironmentView>;
94
190
  get(environmentId: string, options?: {
@@ -109,7 +205,7 @@ export declare class EnvironmentsClient {
109
205
  id: string;
110
206
  kind: "none" | "pod" | "virtual";
111
207
  labels: Record<string, string>;
112
- recipe: {
208
+ manifest: {
113
209
  image?: string | undefined;
114
210
  resources?: {
115
211
  cpus: number;
@@ -129,12 +225,60 @@ export declare class EnvironmentsClient {
129
225
  cwd?: string | undefined;
130
226
  timeout?: string | undefined;
131
227
  }[] | undefined;
132
- files?: {
228
+ files?: ({
133
229
  artifactId: string;
134
230
  version: number;
135
231
  path: string;
136
- }[] | undefined;
232
+ } | {
233
+ path: string;
234
+ files: Record<string, string>;
235
+ })[] | undefined;
236
+ secrets?: Record<string, {
237
+ required?: boolean | undefined;
238
+ description?: string | undefined;
239
+ type: "environment_secret";
240
+ allowedHosts: string[];
241
+ inject?: {
242
+ header: string;
243
+ format: string;
244
+ } | undefined;
245
+ } | {
246
+ required?: boolean | undefined;
247
+ description?: string | undefined;
248
+ type: "environment_variable";
249
+ } | {
250
+ via?: string | undefined;
251
+ identity?: {
252
+ header: string;
253
+ } | undefined;
254
+ required?: boolean | undefined;
255
+ description?: string | undefined;
256
+ type: "bearer";
257
+ url: string;
258
+ } | {
259
+ via?: string | undefined;
260
+ identity?: {
261
+ header: string;
262
+ } | undefined;
263
+ required?: boolean | undefined;
264
+ description?: string | undefined;
265
+ type: "headers";
266
+ url: string;
267
+ }> | undefined;
137
268
  };
269
+ manifestName?: string | undefined;
270
+ manifestVersion?: number | undefined;
271
+ manifestHash?: string | undefined;
272
+ forkedFrom?: {
273
+ environment: string;
274
+ disk: number | null;
275
+ } | undefined;
276
+ slots?: {
277
+ name: string;
278
+ type: string;
279
+ required: boolean;
280
+ set: boolean;
281
+ }[] | undefined;
138
282
  version: number;
139
283
  appliedVersion: number;
140
284
  ownerUserId: string | null;
@@ -145,6 +289,7 @@ export declare class EnvironmentsClient {
145
289
  volumeGeneration: number;
146
290
  hostEpoch: number;
147
291
  reason?: string | undefined;
292
+ imageDigest?: string | undefined;
148
293
  } | undefined;
149
294
  lastUsedAt: string;
150
295
  disk?: {
@@ -186,6 +331,24 @@ export declare class EnvironmentsClient {
186
331
  restore(environmentId: string, version: number | "latest", options?: {
187
332
  signal?: AbortSignal;
188
333
  }): Promise<EnvironmentRestore>;
334
+ /**
335
+ * Forks the Environment into a new one, `options.id` (Q15): how an Environment gets a new
336
+ * manifest version, since none ever changes what it runs. It is made from `options.manifest`
337
+ * (default the source's manifest at its latest version), its disk starts from `options.disk`
338
+ * (`latest`, the default, snapshots first; a version; or `empty`) and the secrets the new
339
+ * manifest declares are copied (`options.secrets: "none"` copies none). The source keeps what
340
+ * it runs, its disk and its sessions. Answers the new Environment and the plan it ran.
341
+ */
342
+ fork(environmentId: string, options: Omit<ForkEnvironmentRequest, "requestId" | "dryRun"> & {
343
+ signal?: AbortSignal;
344
+ }): Promise<{
345
+ environment: EnvironmentView;
346
+ plan: EnvironmentForkPlan;
347
+ }>;
348
+ /** What `fork` would do (the disk, the secrets copied and left behind, the changes), making nothing. */
349
+ planFork(environmentId: string, options: Omit<ForkEnvironmentRequest, "requestId" | "dryRun"> & {
350
+ signal?: AbortSignal;
351
+ }): Promise<EnvironmentForkPlan>;
189
352
  /** The Environment's disk versions, newest first. */
190
353
  versions(environmentId: string, options?: {
191
354
  signal?: AbortSignal;
@@ -202,9 +365,16 @@ export declare class EnvironmentsClient {
202
365
  delete(environmentId: string, options?: {
203
366
  signal?: AbortSignal;
204
367
  }): Promise<DeleteEnvironmentResponse>;
205
- /** The Environment's lifecycle events, from `from` on. */
368
+ /**
369
+ * The Environment's events, from `from` on: its lifecycle, and `environment.egress` for every
370
+ * connection its sandbox opens (with the turns that were running). `types` keeps only those
371
+ * types; `since` and `until` keep events recorded in that window (ISO times or `Date`s).
372
+ */
206
373
  events(environmentId: string, options?: {
207
374
  from?: number;
375
+ types?: readonly EnvironmentEventType[];
376
+ since?: string | Date;
377
+ until?: string | Date;
208
378
  signal?: AbortSignal;
209
379
  }): Promise<EnvironmentEvent[]>;
210
380
  /**
@@ -1,16 +1,20 @@
1
1
  /**
2
2
  * Environments (protocol 11, D55, D56): `client.environments`. An Environment is one sandbox
3
- * (kind `virtual`, `pod` or `none`) with a recipe that can change, and one vault of secrets for
4
- * its shell, MCP servers and HTTP tools. It has its own id and outlives the sessions that name
5
- * it; whether it serves one session, one person or a project is the app's choice, made here:
3
+ * (kind `virtual`, `pod` or `none`) made from an environment manifest's version or from inline
4
+ * fields, and one vault of secrets for its shell, MCP servers and HTTP tools. It never changes
5
+ * what it runs after it is made (protocol 14, D63): a new version reaches an agent through a new
6
+ * Environment. It has its own id and outlives the sessions that name it; whether it serves one
7
+ * session, one person or a project is the app's choice, made here:
6
8
  *
7
9
  * - `environments.forSession(...)`: one Environment for one session. It creates the
8
10
  * Environment, opens the session on it, and `release()` deletes the Environment (and its
9
11
  * vault) when the session is done.
10
- * - `environments.put(id, recipe)`: one Environment per person or per project, by a
11
- * deterministic id (`users/alice/web`); get-or-create, or change its recipe, in one call.
12
- * Write its secrets with `environments.secrets.put(id, name, secret)` and open sessions on it
13
- * with `createSession({ environment: id })`.
12
+ * - `environments.put(id, { manifest: "analyst-box" })` (or inline fields): one Environment per
13
+ * person or per project, by a deterministic id (`users/alice/web`); get-or-create in one call.
14
+ * Write its secrets with `environments.secrets.put(id, name, { value })` and open sessions on
15
+ * it with `createSession({ environment: id })`.
16
+ * - `environments.manifests.save(manifest)`: save an environment manifest's next version, like
17
+ * `saveAgent`; `plan(manifest)` answers what a save would do and saves nothing.
14
18
  *
15
19
  * Ids may hold `/`; they are sent percent-encoded as one path segment. Secret values are
16
20
  * write-only: no call reads one back.
@@ -18,9 +22,22 @@
18
22
  * Disk versions (Host feature `environment-disk-versions`): `snapshot(id)` keeps a version of
19
23
  * the Environment's disk between turns, `restore(id, version)` puts one back, and
20
24
  * `put(id, { from: { environment, version } })` creates a new Environment from another's version.
25
+ *
26
+ * `fork(id, { id: next })` is how an Environment gets a new manifest version (Q15): a new
27
+ * Environment made from it, with the source's disk and secrets; `planFork` answers what it would do.
21
28
  */
22
- import { EnvironmentPageSchema, isEnvironmentId, } from "@nylorun/core/contracts";
29
+ import { ENVIRONMENT_MANIFEST_SCHEMA_VERSION, EnvironmentManifestSchema, EnvironmentPageSchema, isEnvironmentId, isEnvironmentManifestName, } from "@nylorun/core/contracts";
30
+ import { definitionFileHash, FilesClient } from "./files.js";
23
31
  import { id, segment } from "./http.js";
32
+ /**
33
+ * An environment manifest (protocol 14, D63): checked now against the schema the Runtime
34
+ * enforces, with `manifestSchemaVersion` filled in and `$schema` dropped. Save it with
35
+ * `client.environments.manifests.save()`, or make an Environment from it inline.
36
+ */
37
+ export function environmentManifest(input) {
38
+ const { $schema: _, ...rest } = input;
39
+ return EnvironmentManifestSchema.parse({ manifestSchemaVersion: ENVIRONMENT_MANIFEST_SCHEMA_VERSION, ...rest });
40
+ }
24
41
  /** An Environment's secrets: `client.environments.secrets`. */
25
42
  export class EnvironmentSecretsClient {
26
43
  transport;
@@ -32,7 +49,9 @@ export class EnvironmentSecretsClient {
32
49
  /**
33
50
  * Creates or replaces secret `name` (`PUT /v1/environments/{id}/secrets/{name}`): for
34
51
  * `environment_secret` and `environment_variable` the name is the variable's. A second
35
- * credential for a host or a URL is a 409 `credential_conflict`.
52
+ * credential for a host or a URL is a 409 `credential_conflict`. When what the Environment
53
+ * runs declares the secret's slot (D64), send only `{ value }` (or `{ headers }`); a name it
54
+ * does not declare is `409 secret_not_in_manifest`.
36
55
  */
37
56
  async put(environmentId, name, secret, options = {}) {
38
57
  return this.transport.json(`${this.path(environmentId)}/secrets/${segment(name)}`, "PUT", { requestId: id(), ...secret }, options.signal);
@@ -49,6 +68,71 @@ export class EnvironmentSecretsClient {
49
68
  return this.transport.json(`${this.path(environmentId)}/secrets/${segment(name)}`, "DELETE", undefined, options.signal);
50
69
  }
51
70
  }
71
+ /**
72
+ * A manifest `files` entry by content hash (Q6): `contents` (each file's path under `path` and
73
+ * its bytes or text) hashed, as `entry` for the manifest and `bytes` for `manifests.save`'s
74
+ * `files`, which uploads them. Each file holds at most 10 MiB.
75
+ */
76
+ export async function environmentFiles(path, contents) {
77
+ const files = {};
78
+ const bytes = {};
79
+ for (const [name, content] of Object.entries(contents).sort(([a], [b]) => a.localeCompare(b))) {
80
+ const data = typeof content === "string" ? new TextEncoder().encode(content) : content;
81
+ const sha256 = await definitionFileHash(data);
82
+ files[name] = sha256;
83
+ bytes[sha256] = data;
84
+ }
85
+ return { entry: { path, files }, bytes };
86
+ }
87
+ export class EnvironmentManifestsClient {
88
+ transport;
89
+ constructor(transport) {
90
+ this.transport = transport;
91
+ }
92
+ path(name) {
93
+ if (!isEnvironmentManifestName(name))
94
+ throw new TypeError(`${name} is not an environment manifest's name: 1-64 letters, digits, '.', '_' and '-'`);
95
+ return `/v1/environment-manifests/${segment(name)}`;
96
+ }
97
+ async send(manifest, query, options) {
98
+ const { ifMatch, signal } = options;
99
+ const body = environmentManifest(manifest);
100
+ // Its files by hash (Q6): uploaded first, each only when the Runtime does not hold it.
101
+ if (options.files)
102
+ await new FilesClient(this.transport).ensure(new Map(Object.entries(options.files).map(([sha256, bytes]) => [sha256, { size: bytes.byteLength, read: async () => bytes }])), signal ? { signal } : {});
103
+ const transport = ifMatch === undefined ? this.transport : this.transport.withHeaders({ "If-Match": String(ifMatch) });
104
+ return transport.json(`${this.path(body.name)}${query}`, "PUT", { requestId: id(), ...body }, signal);
105
+ }
106
+ /**
107
+ * Saves `manifest` (`PUT /v1/environment-manifests/{name}`). `ifMatch`: the version you read
108
+ * (`0` for none yet); a save over a newer one is `412 manifest_changed`. `files`: the bytes of
109
+ * its files by hash (`environmentFiles(...).bytes`), uploaded first when the Runtime lacks them.
110
+ */
111
+ async save(manifest, options = {}) {
112
+ return this.send(manifest, "", options);
113
+ }
114
+ /** What saving `manifest` would do (`?dryRun=true`): changes, errors, warnings, and the Environments behind. */
115
+ async plan(manifest, options = {}) {
116
+ return this.send(manifest, "?dryRun=true", options);
117
+ }
118
+ /** The latest version of manifest `name`, or version `version`. */
119
+ async get(name, options = {}) {
120
+ return this.transport.json(`${this.path(name)}${options.version === undefined ? "" : `/versions/${options.version}`}`, "GET", undefined, options.signal);
121
+ }
122
+ /** Each manifest's latest version. */
123
+ async list(options = {}) {
124
+ const reply = await this.transport.json("/v1/environment-manifests", "GET", undefined, options.signal);
125
+ return reply.manifests;
126
+ }
127
+ /** Every version of manifest `name`, newest first. */
128
+ async versions(name, options = {}) {
129
+ return this.transport.json(`${this.path(name)}/versions`, "GET", undefined, options.signal);
130
+ }
131
+ /** Deletes every version; refused while an Environment was made from one (`409 manifest_in_use`). */
132
+ async delete(name, options = {}) {
133
+ return this.transport.json(this.path(name), "DELETE", undefined, options.signal);
134
+ }
135
+ }
52
136
  export class EnvironmentsClient {
53
137
  transport;
54
138
  createSession;
@@ -67,11 +151,17 @@ export class EnvironmentsClient {
67
151
  get secrets() {
68
152
  return new EnvironmentSecretsClient(this.transport, (environmentId) => this.path(environmentId));
69
153
  }
154
+ /** Environment manifests (protocol 14, D63): named, versioned definitions of a kind of Environment. */
155
+ get manifests() {
156
+ return new EnvironmentManifestsClient(this.transport);
157
+ }
70
158
  /**
71
159
  * Creates the Environment and its vault, or finds the one with this id
72
- * (`PUT /v1/environments/{id}`). On an existing one, `kind` and `storage` are fixed (a
73
- * different one is a 409), labels replace, and any other change writes the recipe and bumps
74
- * its `version`: a pod's image and resources apply when it next starts from stopped.
160
+ * (`PUT /v1/environments/{id}`), from an environment manifest (`{ manifest: "name" }` takes
161
+ * the latest version, `"name@n"` version n) or from inline fields. It never changes what it
162
+ * runs after that (protocol 14): on an existing one, labels replace and `ownerUserId` sets or
163
+ * clears the owner guard, fields that match are accepted, and anything else is
164
+ * `409 environment_immutable`.
75
165
  */
76
166
  async put(environmentId, recipe = {}, options = {}) {
77
167
  return this.transport.json(this.path(environmentId), "PUT", { requestId: id(), ...recipe }, options.signal);
@@ -121,6 +211,26 @@ export class EnvironmentsClient {
121
211
  await this.transport.requireFeature("environment-disk-versions", options.signal);
122
212
  return this.transport.json(`${this.path(environmentId)}/restore`, "POST", { requestId: id(), version }, options.signal);
123
213
  }
214
+ /**
215
+ * Forks the Environment into a new one, `options.id` (Q15): how an Environment gets a new
216
+ * manifest version, since none ever changes what it runs. It is made from `options.manifest`
217
+ * (default the source's manifest at its latest version), its disk starts from `options.disk`
218
+ * (`latest`, the default, snapshots first; a version; or `empty`) and the secrets the new
219
+ * manifest declares are copied (`options.secrets: "none"` copies none). The source keeps what
220
+ * it runs, its disk and its sessions. Answers the new Environment and the plan it ran.
221
+ */
222
+ async fork(environmentId, options) {
223
+ const { signal, ...body } = options;
224
+ await this.transport.requireFeature("environment-manifests", signal);
225
+ return this.transport.json(`${this.path(environmentId)}/fork`, "POST", { requestId: id(), ...body }, signal);
226
+ }
227
+ /** What `fork` would do (the disk, the secrets copied and left behind, the changes), making nothing. */
228
+ async planFork(environmentId, options) {
229
+ const { signal, ...body } = options;
230
+ await this.transport.requireFeature("environment-manifests", signal);
231
+ const answer = await this.transport.json(`${this.path(environmentId)}/fork`, "POST", { ...body, dryRun: true }, signal);
232
+ return answer.plan;
233
+ }
124
234
  /** The Environment's disk versions, newest first. */
125
235
  async versions(environmentId, options = {}) {
126
236
  await this.transport.requireFeature("environment-disk-versions", options.signal);
@@ -134,9 +244,24 @@ export class EnvironmentsClient {
134
244
  async delete(environmentId, options = {}) {
135
245
  return this.transport.json(this.path(environmentId), "DELETE", undefined, options.signal);
136
246
  }
137
- /** The Environment's lifecycle events, from `from` on. */
247
+ /**
248
+ * The Environment's events, from `from` on: its lifecycle, and `environment.egress` for every
249
+ * connection its sandbox opens (with the turns that were running). `types` keeps only those
250
+ * types; `since` and `until` keep events recorded in that window (ISO times or `Date`s).
251
+ */
138
252
  async events(environmentId, options = {}) {
139
- const reply = await this.transport.json(`${this.path(environmentId)}/events${options.from === undefined ? "" : `?from=${options.from}`}`, "GET", undefined, options.signal);
253
+ const query = new URLSearchParams();
254
+ if (options.from !== undefined)
255
+ query.set("from", String(options.from));
256
+ if (options.types !== undefined && options.types.length > 0)
257
+ query.set("types", options.types.join(","));
258
+ const iso = (at) => (at instanceof Date ? at.toISOString() : at);
259
+ if (options.since !== undefined)
260
+ query.set("since", iso(options.since));
261
+ if (options.until !== undefined)
262
+ query.set("until", iso(options.until));
263
+ const search = query.toString();
264
+ const reply = await this.transport.json(`${this.path(environmentId)}/events${search === "" ? "" : `?${search}`}`, "GET", undefined, options.signal);
140
265
  return reply.events;
141
266
  }
142
267
  /**
package/dist/http.js CHANGED
@@ -28,12 +28,12 @@ export class IncompatibleRuntimeError extends Error {
28
28
  }
29
29
  function remedyFor(compatibility) {
30
30
  if (compatibility.reason === "feature") {
31
- return "Upgrade the Runtime Host (nylorun runtime restart from a newer CLI) so it advertises the required features.";
31
+ return "Upgrade the Runtime so it advertises the required features (a local Tenant: npx nylorun@latest start).";
32
32
  }
33
33
  if (compatibility.client < compatibility.host.min) {
34
34
  return "Upgrade this client (npm i -D @nylorun/agents@latest) or use a CLI that matches the Host protocol.";
35
35
  }
36
- 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>).";
36
+ return "Upgrade the Runtime (a local Tenant: npx nylorun@latest start), or install a matching older client (npm i -D @nylorun/agents@<compatible>).";
37
37
  }
38
38
  export class Transport {
39
39
  url;
package/dist/index.d.ts CHANGED
@@ -3,28 +3,26 @@ export type { ProtocolFeature, ProtocolRange, Compatibility, ErrorCode, } from "
3
3
  export { checkHealth, describeIncompatibility, parseProtocolRange, } from "@nylorun/core/transport";
4
4
  export type { HealthCheck, Incompatibility } from "@nylorun/core/transport";
5
5
  export { Agent, AgentBuilder } from "./builder.js";
6
- export { AgentBuildError, AgentLifecycleError, VerdictSchema, isVerdict, WorkflowBuildError, isBuiltWorkflow, capability, CapabilityBuilder, flow, tool, http, defineSchema, ToolError, } from "@nylorun/core/define";
7
- export type { FlowAgentBuilder, Flow, Named, LoopOptions, StageOptions, CapabilityIdentity, HttpTarget, } from "@nylorun/core/define";
6
+ export { AgentBuildError, AgentLifecycleError, VerdictSchema, isVerdict, WorkflowBuildError, isBuiltWorkflow, flow, tool, http, defineSchema, ToolError, } from "@nylorun/core/define";
7
+ export type { FlowAgentBuilder, Flow, Named, LoopOptions, StageOptions, HttpTarget, } from "@nylorun/core/define";
8
8
  export type { AgentOptions, AgentManifest, BuiltAgent, BuiltWorkflow, Verdict, WorkflowBinding, WorkflowManifest, ToolDefinition, ToolExecutionContext, ToolOutcome, JsonValue, JsonObject, } from "@nylorun/core/define";
9
- export type { SessionPage, SessionListItem, SessionManifestView, HistoryPage, SessionUsageTotals, ModelCall, ModelCallsPage, EnvironmentPage, ToolCall, ToolCallsPage, LiveEvent, SessionEvent, SessionEventOf, EventType, SessionCommand, SubjectScope, EnvironmentView, EnvironmentEvent, EnvironmentKind, EnvironmentRecipe, EnvironmentSecretView, EnvironmentSnapshot, EnvironmentRestore, EnvironmentVersions, RestoreEnvironmentRequest, MessagePart, ArtifactView, ArtifactKind, ArtifactListItem, ArtifactPage, ArtifactVersionView, ArtifactLink, UploadArtifactResponse, DefinitionFileView, ArtifactTree, ArtifactDiff, FolderEntry, } from "@nylorun/core/contracts";
10
- export { SUBJECT_SCOPES } from "@nylorun/core/contracts";
9
+ export type { SessionPage, SessionListItem, SessionManifestView, HistoryPage, SessionUsageTotals, ModelCall, ModelCallsPage, EnvironmentPage, ToolCall, ToolCallsPage, LiveEvent, SessionEvent, SessionEventOf, EventType, SessionCommand, SubjectScope, EnvironmentView, EnvironmentEvent, EnvironmentEventType, EgressRunningTurn, EnvironmentKind, EnvironmentRecipe, EnvironmentSecretView, EnvironmentSnapshot, EnvironmentRestore, EnvironmentVersions, RestoreEnvironmentRequest, EnvironmentForkPlan, ForkEnvironmentRequest, ForkEnvironmentResponse, EnvironmentManifest, EnvironmentManifestPlan, EnvironmentManifestView, EnvironmentManifestVersions, SaveEnvironmentManifestResponse, MessagePart, ArtifactView, ArtifactKind, ArtifactListItem, ArtifactPage, ArtifactVersionView, ArtifactLink, UploadArtifactResponse, DefinitionFileView, ArtifactTree, ArtifactDiff, FolderEntry, } from "@nylorun/core/contracts";
10
+ export { ENVIRONMENT_EVENT_TYPES, SUBJECT_SCOPES } from "@nylorun/core/contracts";
11
11
  export { AgentsClient, SessionClient, createClient } from "./client.js";
12
12
  export { ArtifactsClient } from "./artifacts.js";
13
13
  export { FilesClient, definitionFileHash } from "./files.js";
14
14
  export type { ArtifactBody, ArtifactPageOptions, ArtifactLinkWithUrl, UploadArtifactOptions, } from "./artifacts.js";
15
- export type { ActAsOptions, AgentSource, SessionView, CommandOptions, CreateSessionOptions, SessionSandbox, ForSessionOptions, EnvironmentRecipeInput, EnvironmentSecretInput, SessionEnvironmentHandle, } from "./client.js";
16
- export { EnvironmentsClient, EnvironmentSecretsClient } from "./client.js";
15
+ export type { ActAsOptions, AgentSource, SessionView, CommandOptions, CreateSessionOptions, SessionSandbox, ForSessionOptions, EnvironmentFileBytes, EnvironmentInput, EnvironmentManifestInput, EnvironmentSecretInput, SessionEnvironmentHandle, } from "./client.js";
16
+ export { EnvironmentManifestsClient, EnvironmentsClient, EnvironmentSecretsClient, environmentFiles, environmentManifest, } from "./client.js";
17
17
  export { AccessClient } from "./access.js";
18
18
  export { resolveConnection, ConnectionError } from "./connection.js";
19
19
  export type { ResolvedConnection } from "./connection.js";
20
20
  export { RuntimeError, IncompatibleRuntimeError } from "./http.js";
21
21
  export type { Destination, IncompatibleReason, TokenSource } from "./http.js";
22
- export { plugin } from "./plugins/plugin.js";
23
- export type { PluginCapability } from "./plugins/plugin.js";
24
22
  export { loadPlugin, PluginError } from "./plugins/load.js";
25
23
  export type { LoadedPlugin, PluginDiagnostic } from "./plugins/load.js";
26
- export { skills, loadSkillsFromDirectory, resolveSkillsRoot, parseSkill, SkillsError, formatSkillCatalog, SKILLS_USAGE, } from "./skills/index.js";
27
- export type { SkillsCapability, SkillsOptions, SkillDiagnostic, } from "./skills/index.js";
28
- export { mcp, McpError } from "./mcp/index.js";
29
- export type { McpCapability, McpOptions, McpServerSpec } from "./mcp/index.js";
24
+ export { loadSkillsFromDirectory, resolveSkillsRoot, parseSkill, SkillsError, formatSkillCatalog, SKILLS_USAGE, } from "./skills/index.js";
25
+ export type { SkillDiagnostic } from "./skills/index.js";
26
+ export { McpError } from "./mcp/index.js";
27
+ export type { McpServerSpec } from "./mcp/index.js";
30
28
  export type { SessionPageOptions } from "./reads.js";
package/dist/index.js CHANGED
@@ -3,16 +3,15 @@ export { hashManifest, PROTOCOL_VERSION, PROTOCOL_FEATURES, HOST_PROTOCOL, DEFIN
3
3
  // The `/health` compatibility probe every Runtime client shares (Studio's server uses it).
4
4
  export { checkHealth, describeIncompatibility, parseProtocolRange, } from "@nylorun/core/transport";
5
5
  export { Agent, AgentBuilder } from "./builder.js";
6
- export { AgentBuildError, AgentLifecycleError, VerdictSchema, isVerdict, WorkflowBuildError, isBuiltWorkflow, capability, CapabilityBuilder, flow, tool, http, defineSchema, ToolError, } from "@nylorun/core/define";
7
- export { SUBJECT_SCOPES } from "@nylorun/core/contracts";
6
+ export { AgentBuildError, AgentLifecycleError, VerdictSchema, isVerdict, WorkflowBuildError, isBuiltWorkflow, flow, tool, http, defineSchema, ToolError, } from "@nylorun/core/define";
7
+ export { ENVIRONMENT_EVENT_TYPES, SUBJECT_SCOPES } from "@nylorun/core/contracts";
8
8
  export { AgentsClient, SessionClient, createClient } from "./client.js";
9
9
  export { ArtifactsClient } from "./artifacts.js";
10
10
  export { FilesClient, definitionFileHash } from "./files.js";
11
- export { EnvironmentsClient, EnvironmentSecretsClient } from "./client.js";
11
+ export { EnvironmentManifestsClient, EnvironmentsClient, EnvironmentSecretsClient, environmentFiles, environmentManifest, } from "./client.js";
12
12
  export { AccessClient } from "./access.js";
13
13
  export { resolveConnection, ConnectionError } from "./connection.js";
14
14
  export { RuntimeError, IncompatibleRuntimeError } from "./http.js";
15
- export { plugin } from "./plugins/plugin.js";
16
15
  export { loadPlugin, PluginError } from "./plugins/load.js";
17
- export { skills, loadSkillsFromDirectory, resolveSkillsRoot, parseSkill, SkillsError, formatSkillCatalog, SKILLS_USAGE, } from "./skills/index.js";
18
- export { mcp, McpError } from "./mcp/index.js";
16
+ export { loadSkillsFromDirectory, resolveSkillsRoot, parseSkill, SkillsError, formatSkillCatalog, SKILLS_USAGE, } from "./skills/index.js";
17
+ export { McpError } from "./mcp/index.js";
@@ -1,2 +1,2 @@
1
- export { mcp, McpError, normalizeMcpServers } from "@nylorun/core/define";
2
- export type { McpCapability, McpOptions, McpServerSpec } from "@nylorun/core/define";
1
+ export { McpError, normalizeMcpServers } from "@nylorun/core/define";
2
+ export type { McpServerSpec } from "@nylorun/core/define";
package/dist/mcp/index.js CHANGED
@@ -1 +1 @@
1
- export { mcp, McpError, normalizeMcpServers } from "@nylorun/core/define";
1
+ export { McpError, normalizeMcpServers } from "@nylorun/core/define";
@@ -16,6 +16,7 @@ export declare class PluginError extends Error {
16
16
  export interface LoadedPlugin {
17
17
  readonly root: string;
18
18
  readonly name: string;
19
+ readonly version?: string;
19
20
  readonly description?: string;
20
21
  readonly skills: Readonly<Record<string, LoadedSkill>>;
21
22
  readonly mcpServers: Readonly<Record<string, McpServerManifest>>;
@@ -80,6 +80,7 @@ export function loadPlugin(directory) {
80
80
  return {
81
81
  root,
82
82
  name: parsed.name,
83
+ ...(typeof parsed.version === "string" ? { version: parsed.version } : {}),
83
84
  ...(typeof parsed.description === "string" ? { description: parsed.description } : {}),
84
85
  skills,
85
86
  mcpServers,