@nylorun/agents 0.23.0-beta → 0.24.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 +33 -0
- package/README.md +136 -105
- package/dist/a2a/handler.d.ts +9 -4
- package/dist/a2a/handler.js +9 -0
- package/dist/ag-ui/handler.d.ts +13 -9
- package/dist/ag-ui/handler.js +8 -5
- package/dist/agent-manifests.d.ts +127 -0
- package/dist/agent-manifests.js +208 -0
- package/dist/agents.d.ts +456 -0
- package/dist/agents.js +331 -0
- package/dist/compose.d.ts +23 -0
- package/dist/compose.js +246 -0
- package/dist/files.d.ts +2 -2
- package/dist/files.js +2 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.js +5 -4
- package/dist/plugins/load.d.ts +10 -0
- package/dist/plugins/load.js +25 -14
- package/dist/plugins/plugin.d.ts +1 -1
- package/dist/plugins/plugin.js +1 -1
- package/dist/reads.d.ts +3 -1
- package/dist/session-client.d.ts +77 -48
- package/dist/session-client.js +22 -72
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.js +1 -1
- package/dist/skills/load.d.ts +10 -0
- package/dist/skills/load.js +15 -5
- package/dist/skills/skills.d.ts +2 -2
- package/dist/skills/skills.js +2 -2
- package/package.json +5 -5
- package/dist/environments.d.ts +0 -413
- package/dist/environments.js +0 -299
package/dist/environments.js
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environments (protocol 11, D55, D56): `client.environments`. An Environment is one sandbox
|
|
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:
|
|
8
|
-
*
|
|
9
|
-
* - `environments.forSession(...)`: one Environment for one session. It creates the
|
|
10
|
-
* Environment, opens the session on it, and `release()` deletes the Environment (and its
|
|
11
|
-
* vault) when the session is done.
|
|
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.
|
|
18
|
-
*
|
|
19
|
-
* Ids may hold `/`; they are sent percent-encoded as one path segment. Secret values are
|
|
20
|
-
* write-only: no call reads one back.
|
|
21
|
-
*
|
|
22
|
-
* Disk versions (Host feature `environment-disk-versions`): `snapshot(id)` keeps a version of
|
|
23
|
-
* the Environment's disk between turns, `restore(id, version)` puts one back, and
|
|
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.
|
|
28
|
-
*/
|
|
29
|
-
import { ENVIRONMENT_MANIFEST_SCHEMA_VERSION, EnvironmentManifestSchema, EnvironmentPageSchema, isEnvironmentId, isEnvironmentManifestName, } from "@nylorun/core/contracts";
|
|
30
|
-
import { definitionFileHash, FilesClient } from "./files.js";
|
|
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
|
-
}
|
|
41
|
-
/** An Environment's secrets: `client.environments.secrets`. */
|
|
42
|
-
export class EnvironmentSecretsClient {
|
|
43
|
-
transport;
|
|
44
|
-
path;
|
|
45
|
-
constructor(transport, path) {
|
|
46
|
-
this.transport = transport;
|
|
47
|
-
this.path = path;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Creates or replaces secret `name` (`PUT /v1/environments/{id}/secrets/{name}`): for
|
|
51
|
-
* `environment_secret` and `environment_variable` the name is the variable's. A second
|
|
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`.
|
|
55
|
-
*/
|
|
56
|
-
async put(environmentId, name, secret, options = {}) {
|
|
57
|
-
return this.transport.json(`${this.path(environmentId)}/secrets/${segment(name)}`, "PUT", { requestId: id(), ...secret }, options.signal);
|
|
58
|
-
}
|
|
59
|
-
/** The secrets' names, types and bindings; never a value. */
|
|
60
|
-
async list(environmentId, options = {}) {
|
|
61
|
-
const reply = await this.transport.json(`${this.path(environmentId)}/secrets`, "GET", undefined, options.signal);
|
|
62
|
-
return reply.secrets;
|
|
63
|
-
}
|
|
64
|
-
async get(environmentId, name, options = {}) {
|
|
65
|
-
return this.transport.json(`${this.path(environmentId)}/secrets/${segment(name)}`, "GET", undefined, options.signal);
|
|
66
|
-
}
|
|
67
|
-
async delete(environmentId, name, options = {}) {
|
|
68
|
-
return this.transport.json(`${this.path(environmentId)}/secrets/${segment(name)}`, "DELETE", undefined, options.signal);
|
|
69
|
-
}
|
|
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 2 GiB.
|
|
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
|
-
}
|
|
136
|
-
export class EnvironmentsClient {
|
|
137
|
-
transport;
|
|
138
|
-
createSession;
|
|
139
|
-
constructor(transport,
|
|
140
|
-
/** `AgentsClient.createSession`, bound. */
|
|
141
|
-
createSession) {
|
|
142
|
-
this.transport = transport;
|
|
143
|
-
this.createSession = createSession;
|
|
144
|
-
}
|
|
145
|
-
path(environmentId) {
|
|
146
|
-
if (!isEnvironmentId(environmentId))
|
|
147
|
-
throw new TypeError(`${environmentId} is not an Environment id: up to 200 characters, /-separated segments of letters, digits, '.', '_' and '-'`);
|
|
148
|
-
return `/v1/environments/${segment(environmentId)}`;
|
|
149
|
-
}
|
|
150
|
-
/** The Environment's secrets. */
|
|
151
|
-
get secrets() {
|
|
152
|
-
return new EnvironmentSecretsClient(this.transport, (environmentId) => this.path(environmentId));
|
|
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
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Creates the Environment and its vault, or finds the one with this id
|
|
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`.
|
|
165
|
-
*/
|
|
166
|
-
async put(environmentId, recipe = {}, options = {}) {
|
|
167
|
-
return this.transport.json(this.path(environmentId), "PUT", { requestId: id(), ...recipe }, options.signal);
|
|
168
|
-
}
|
|
169
|
-
async get(environmentId, options = {}) {
|
|
170
|
-
return this.transport.json(this.path(environmentId), "GET", undefined, options.signal);
|
|
171
|
-
}
|
|
172
|
-
/** The Environments with every label in `labels` that this client reaches. */
|
|
173
|
-
async list(options = {}) {
|
|
174
|
-
const query = new URLSearchParams();
|
|
175
|
-
for (const [key, value] of Object.entries(options.labels ?? {}))
|
|
176
|
-
query.append("label", `${key}=${value}`);
|
|
177
|
-
const search = query.toString();
|
|
178
|
-
const reply = await this.transport.json(`/v1/environments${search ? `?${search}` : ""}`, "GET", undefined, options.signal);
|
|
179
|
-
return reply.environments;
|
|
180
|
-
}
|
|
181
|
-
async page(options = {}) {
|
|
182
|
-
await this.transport.requireFeature("session-reads", options.signal);
|
|
183
|
-
const query = new URLSearchParams({ limit: String(options.limit ?? 50) });
|
|
184
|
-
if (options.cursor !== undefined)
|
|
185
|
-
query.set("cursor", options.cursor);
|
|
186
|
-
for (const [key, value] of Object.entries(options.labels ?? {}))
|
|
187
|
-
query.append("label", `${key}=${value}`);
|
|
188
|
-
return EnvironmentPageSchema.parse(await this.transport.json(`/v1/environments?${query}`, "GET", undefined, options.signal));
|
|
189
|
-
}
|
|
190
|
-
/** Stops a pod Environment: its volume is kept, and the next turn starts it again. */
|
|
191
|
-
async stop(environmentId, options = {}) {
|
|
192
|
-
return this.transport.json(`${this.path(environmentId)}/stop`, "POST", {}, options.signal);
|
|
193
|
-
}
|
|
194
|
-
/** Resets a pod Environment: a new pod on a new, empty volume, with its recipe applied. */
|
|
195
|
-
async reset(environmentId, options = {}) {
|
|
196
|
-
return this.transport.json(`${this.path(environmentId)}/reset`, "POST", {}, options.signal);
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Keeps a version of the Environment's disk (`POST /v1/environments/{id}/snapshot`), between
|
|
200
|
-
* turns; `unchanged` when the disk is as the latest version has it.
|
|
201
|
-
*/
|
|
202
|
-
async snapshot(environmentId, options = {}) {
|
|
203
|
-
await this.transport.requireFeature("environment-disk-versions", options.signal);
|
|
204
|
-
return this.transport.json(`${this.path(environmentId)}/snapshot`, "POST", {}, options.signal);
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Puts disk version `version` back: at once for a virtual Environment (`done`), on a new volume
|
|
208
|
-
* seeded before the next turn for a pod (`pending`).
|
|
209
|
-
*/
|
|
210
|
-
async restore(environmentId, version, options = {}) {
|
|
211
|
-
await this.transport.requireFeature("environment-disk-versions", options.signal);
|
|
212
|
-
return this.transport.json(`${this.path(environmentId)}/restore`, "POST", { requestId: id(), version }, options.signal);
|
|
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
|
-
}
|
|
234
|
-
/** The Environment's disk versions, newest first. */
|
|
235
|
-
async versions(environmentId, options = {}) {
|
|
236
|
-
await this.transport.requireFeature("environment-disk-versions", options.signal);
|
|
237
|
-
return this.transport.json(`${this.path(environmentId)}/versions`, "GET", undefined, options.signal);
|
|
238
|
-
}
|
|
239
|
-
/** Deletes disk version `version`; `deleted` is false when there was none. */
|
|
240
|
-
async deleteVersion(environmentId, version, options = {}) {
|
|
241
|
-
return this.transport.json(`${this.path(environmentId)}/versions/${version}`, "DELETE", undefined, options.signal);
|
|
242
|
-
}
|
|
243
|
-
/** Deletes the Environment, its vault and its files; `deleted` is false when there was none. */
|
|
244
|
-
async delete(environmentId, options = {}) {
|
|
245
|
-
return this.transport.json(this.path(environmentId), "DELETE", undefined, options.signal);
|
|
246
|
-
}
|
|
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
|
-
*/
|
|
252
|
-
async events(environmentId, options = {}) {
|
|
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);
|
|
265
|
-
return reply.events;
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* One Environment for one session: creates the Environment (`sessions/<session id>` unless
|
|
269
|
-
* `environmentId` names another), writes `secrets`, opens the session on it, and returns both
|
|
270
|
-
* with `release()`, which deletes the Environment. If the session cannot be opened, the
|
|
271
|
-
* Environment is deleted again.
|
|
272
|
-
*/
|
|
273
|
-
async forSession(options) {
|
|
274
|
-
const sessionId = options.session.id ?? id();
|
|
275
|
-
const environmentId = options.environmentId ??
|
|
276
|
-
(isEnvironmentId(`sessions/${sessionId}`) ? `sessions/${sessionId}` : `sessions/${id()}`);
|
|
277
|
-
const signal = options.signal ? { signal: options.signal } : {};
|
|
278
|
-
const environment = await this.put(environmentId, options.recipe ?? {}, signal);
|
|
279
|
-
let session;
|
|
280
|
-
try {
|
|
281
|
-
for (const [name, secret] of Object.entries(options.secrets ?? {}))
|
|
282
|
-
await this.secrets.put(environmentId, name, secret, signal);
|
|
283
|
-
session = await this.createSession({
|
|
284
|
-
...options.session,
|
|
285
|
-
id: sessionId,
|
|
286
|
-
environment: environmentId,
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
catch (error) {
|
|
290
|
-
await this.delete(environmentId).catch(() => undefined);
|
|
291
|
-
throw error;
|
|
292
|
-
}
|
|
293
|
-
return {
|
|
294
|
-
session,
|
|
295
|
-
environment,
|
|
296
|
-
release: (release = {}) => this.delete(environmentId, release),
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
}
|