@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/executor.js
DELETED
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
import { AgentManifestSchema, ActionSchema, ActionClaimResponseSchema, } from "@nylorun/core/contracts";
|
|
2
|
-
import { agentFrom, delegateOf, hashManifest, isFlowDelegate, isBuiltWorkflow, } from "@nylorun/core/define";
|
|
3
|
-
import { AgentsClient, assertNoMiddlewareClosures, } from "./client.js";
|
|
4
|
-
import { resolveConnection } from "./connection.js";
|
|
5
|
-
import { deriveExecutorToken } from "./derived-credentials.js";
|
|
6
|
-
import { Transport, RuntimeError, delay, env, id, segment, } from "./http.js";
|
|
7
|
-
import { readSSE } from "./sse.js";
|
|
8
|
-
import { executeAction } from "./execute-action.js";
|
|
9
|
-
import { createActionSandbox, definitionDeclaresSandbox, } from "./sandbox/client.js";
|
|
10
|
-
function implementationVersionOf(options) {
|
|
11
|
-
return (options.implementationVersion ??
|
|
12
|
-
env("NYLORUN_IMPLEMENTATION_VERSION") ??
|
|
13
|
-
"dev");
|
|
14
|
-
}
|
|
15
|
-
/** Agents embedded in a v2 workflow: served here, but saved only as part of the workflow. */
|
|
16
|
-
const embeddedAgents = new WeakMap();
|
|
17
|
-
function buildAgents(options) {
|
|
18
|
-
const agents = new Map();
|
|
19
|
-
const embedded = new Set();
|
|
20
|
-
/**
|
|
21
|
-
* Agents embedded in another definition (a v2 flow's agents, a flow agent used as a
|
|
22
|
-
* tool) may be reached from more than one place; the same definition is served once.
|
|
23
|
-
*/
|
|
24
|
-
const sameAsServed = (id, manifest) => {
|
|
25
|
-
const served = agents.get(id);
|
|
26
|
-
if (!served)
|
|
27
|
-
return false;
|
|
28
|
-
if (hashManifest(served.manifest) === hashManifest(manifest))
|
|
29
|
-
return true;
|
|
30
|
-
throw new Error(`Duplicate connected agent ${id}`);
|
|
31
|
-
};
|
|
32
|
-
const addAgent = (built, shared = false) => {
|
|
33
|
-
assertNoMiddlewareClosures(built);
|
|
34
|
-
AgentManifestSchema.parse(built.manifest);
|
|
35
|
-
if (shared ? sameAsServed(built.id, built.manifest) : agents.has(built.id)) {
|
|
36
|
-
if (!shared)
|
|
37
|
-
throw new Error(`Duplicate connected agent ${built.id}`);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
agents.set(built.id, built);
|
|
41
|
-
for (const tool of built.getBinding().tools) {
|
|
42
|
-
const delegate = delegateOf(tool);
|
|
43
|
-
if (!delegate || !isFlowDelegate(delegate))
|
|
44
|
-
continue;
|
|
45
|
-
// A flow agent used as a tool runs in its own linked session: serve its code too.
|
|
46
|
-
if (!delegate.workflow)
|
|
47
|
-
throw new Error(`Flow agent '${delegate.manifest.id}' is used as a tool by '${built.id}' but has no local implementation`);
|
|
48
|
-
addWorkflow(delegate.workflow, true);
|
|
49
|
-
embedded.add(delegate.workflow.id);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
const addWorkflow = (workflow, shared = false) => {
|
|
53
|
-
if (shared ? sameAsServed(workflow.id, workflow.manifest) : agents.has(workflow.id)) {
|
|
54
|
-
if (!shared)
|
|
55
|
-
throw new Error(`Duplicate connected agent ${workflow.id}`);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
agents.set(workflow.id, workflow);
|
|
59
|
-
const v2 = workflow.manifest.workflowSchemaVersion === 2;
|
|
60
|
-
for (const binding of Object.values(workflow.getBinding().agents)) {
|
|
61
|
-
addAgent(agentFrom(binding.manifest, binding.implementations), v2);
|
|
62
|
-
if (v2)
|
|
63
|
-
embedded.add(binding.manifest.id);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
for (const source of options.agents) {
|
|
67
|
-
if (isBuiltWorkflow(source)) {
|
|
68
|
-
addWorkflow(source);
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
const built = source.build?.() ?? source;
|
|
72
|
-
if (isBuiltWorkflow(built)) {
|
|
73
|
-
addWorkflow(built);
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
addAgent(built);
|
|
77
|
-
}
|
|
78
|
-
if (!agents.size)
|
|
79
|
-
throw new Error("connectAgents requires at least one agent");
|
|
80
|
-
// A definition passed in directly is saved on its own, even if another one embeds it.
|
|
81
|
-
for (const source of options.agents)
|
|
82
|
-
embedded.delete(source.id);
|
|
83
|
-
embeddedAgents.set(agents, embedded);
|
|
84
|
-
return agents;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* The manifest hash an executor serves for a workflow's flow actions. A run is pinned to
|
|
88
|
-
* one workflow manifest, and its stage keys may shift between deploys, so flow actions
|
|
89
|
-
* for another hash are left for the executor that serves it.
|
|
90
|
-
*/
|
|
91
|
-
function flowManifestHash(agent) {
|
|
92
|
-
return isBuiltWorkflow(agent) && agent.manifest.workflowSchemaVersion === 2
|
|
93
|
-
? hashManifest(agent.manifest)
|
|
94
|
-
: undefined;
|
|
95
|
-
}
|
|
96
|
-
function connectExecutorMode(options, runtime, agents) {
|
|
97
|
-
const transport = new Transport(runtime, "executor");
|
|
98
|
-
const version = implementationVersionOf(options);
|
|
99
|
-
const controller = new AbortController();
|
|
100
|
-
const signal = controller.signal;
|
|
101
|
-
const active = new Map();
|
|
102
|
-
let resolveReady;
|
|
103
|
-
let rejectReady;
|
|
104
|
-
const ready = new Promise((resolve, reject) => {
|
|
105
|
-
resolveReady = resolve;
|
|
106
|
-
rejectReady = reject;
|
|
107
|
-
});
|
|
108
|
-
// Avoid an unhandled rejection for callers that immediately close the handle.
|
|
109
|
-
void ready.catch(() => { });
|
|
110
|
-
const report = (error) => {
|
|
111
|
-
try {
|
|
112
|
-
options.onError?.(error);
|
|
113
|
-
}
|
|
114
|
-
catch { }
|
|
115
|
-
};
|
|
116
|
-
const skipped = new Set();
|
|
117
|
-
let discovering = false, dirty = false;
|
|
118
|
-
const discover = async () => {
|
|
119
|
-
dirty = true;
|
|
120
|
-
if (discovering)
|
|
121
|
-
return;
|
|
122
|
-
discovering = true;
|
|
123
|
-
try {
|
|
124
|
-
while (dirty && !signal.aborted) {
|
|
125
|
-
dirty = false;
|
|
126
|
-
const response = await transport.json("/v1/actions", "GET", undefined, signal);
|
|
127
|
-
for (const item of response.actions) {
|
|
128
|
-
// Skip actions this SDK cannot run (e.g. from an older Runtime) instead of stalling discovery.
|
|
129
|
-
const parsed = ActionSchema.safeParse(item);
|
|
130
|
-
if (!parsed.success) {
|
|
131
|
-
report(parsed.error);
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
const action = parsed.data;
|
|
135
|
-
const agent = agents.get(action.agentId);
|
|
136
|
-
if (!agent || action.status !== "pending" || active.has(action.actionId))
|
|
137
|
-
continue;
|
|
138
|
-
const served = flowManifestHash(agent);
|
|
139
|
-
if (served !== undefined && "key" in action && action.manifestHash !== served) {
|
|
140
|
-
if (!skipped.has(action.actionId)) {
|
|
141
|
-
skipped.add(action.actionId);
|
|
142
|
-
report(new Error(`Skipped action ${action.actionId}: it belongs to manifest ${action.manifestHash} of '${action.agentId}', and this executor serves ${served}`));
|
|
143
|
-
}
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
const work = new AbortController();
|
|
147
|
-
active.set(action.actionId, work);
|
|
148
|
-
let delivered = false;
|
|
149
|
-
void processAction(action, agent, work)
|
|
150
|
-
.then(() => {
|
|
151
|
-
delivered = true;
|
|
152
|
-
})
|
|
153
|
-
.catch((error) => {
|
|
154
|
-
if (!signal.aborted)
|
|
155
|
-
report(error);
|
|
156
|
-
})
|
|
157
|
-
.finally(() => {
|
|
158
|
-
active.delete(action.actionId);
|
|
159
|
-
// Completion-driven discovery drains bounded server pages without periodic polling.
|
|
160
|
-
if (delivered && !signal.aborted)
|
|
161
|
-
void discover().catch(report);
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
finally {
|
|
167
|
-
discovering = false;
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
const processAction = async (action, agent, work) => {
|
|
171
|
-
const stop = () => work.abort(signal.reason);
|
|
172
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
173
|
-
let renewal;
|
|
174
|
-
let renewing = true;
|
|
175
|
-
let wakeRenewal;
|
|
176
|
-
try {
|
|
177
|
-
const claim = ActionClaimResponseSchema.parse(await transport.json(`/v1/actions/${segment(action.actionId)}/claim`, "POST", {
|
|
178
|
-
requestId: id(),
|
|
179
|
-
implementationVersion: version,
|
|
180
|
-
}, work.signal));
|
|
181
|
-
if (claim.action.actionId !== action.actionId)
|
|
182
|
-
throw new Error("Claim definition mismatch");
|
|
183
|
-
let expires = Date.parse(claim.leaseExpiresAt);
|
|
184
|
-
renewal = (async () => {
|
|
185
|
-
while (renewing && !work.signal.aborted) {
|
|
186
|
-
const remaining = expires - Date.now();
|
|
187
|
-
if (!Number.isFinite(remaining) || remaining <= 0)
|
|
188
|
-
throw new Error("Executor lease expired");
|
|
189
|
-
await new Promise((resolve) => {
|
|
190
|
-
const finish = () => {
|
|
191
|
-
clearTimeout(timer);
|
|
192
|
-
work.signal.removeEventListener("abort", finish);
|
|
193
|
-
resolve();
|
|
194
|
-
};
|
|
195
|
-
const timer = setTimeout(finish, Math.max(50, Math.floor(remaining / 3)));
|
|
196
|
-
wakeRenewal = finish;
|
|
197
|
-
work.signal.addEventListener("abort", finish, { once: true });
|
|
198
|
-
});
|
|
199
|
-
if (!renewing || work.signal.aborted)
|
|
200
|
-
return;
|
|
201
|
-
const renewed = await transport.json(`/v1/actions/${segment(action.actionId)}/heartbeat`, "POST", {
|
|
202
|
-
requestId: id(),
|
|
203
|
-
claimId: claim.claimId,
|
|
204
|
-
generation: claim.generation,
|
|
205
|
-
}, work.signal);
|
|
206
|
-
expires = Date.parse(renewed.leaseExpiresAt);
|
|
207
|
-
}
|
|
208
|
-
})().catch((error) => {
|
|
209
|
-
if (renewing && !work.signal.aborted) {
|
|
210
|
-
work.abort(error);
|
|
211
|
-
report(error);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
const outcome = await executeAction(claim.action, agent, work.signal, {
|
|
215
|
-
sandbox: definitionDeclaresSandbox(agent.manifest)
|
|
216
|
-
? createActionSandbox({
|
|
217
|
-
transport,
|
|
218
|
-
actionId: action.actionId,
|
|
219
|
-
claimId: claim.claimId,
|
|
220
|
-
generation: claim.generation,
|
|
221
|
-
signal: work.signal,
|
|
222
|
-
})
|
|
223
|
-
: undefined,
|
|
224
|
-
});
|
|
225
|
-
work.signal.throwIfAborted();
|
|
226
|
-
const command = {
|
|
227
|
-
type: "action_result",
|
|
228
|
-
requestId: id(),
|
|
229
|
-
idempotencyKey: `action:${action.actionId}:${claim.generation}`,
|
|
230
|
-
actionId: action.actionId,
|
|
231
|
-
claimId: claim.claimId,
|
|
232
|
-
generation: claim.generation,
|
|
233
|
-
outcome,
|
|
234
|
-
};
|
|
235
|
-
// Retrying delivery never re-invokes the tool/hook. Lost acknowledgements use the same receipt key.
|
|
236
|
-
for (let attempt = 0;; attempt++) {
|
|
237
|
-
try {
|
|
238
|
-
await transport.json(`/v1/sessions/${segment(action.sessionId)}/commands`, "POST", command, work.signal);
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
catch (error) {
|
|
242
|
-
if (work.signal.aborted ||
|
|
243
|
-
attempt >= 4 ||
|
|
244
|
-
(error instanceof RuntimeError &&
|
|
245
|
-
error.status < 500 &&
|
|
246
|
-
![408, 429].includes(error.status)))
|
|
247
|
-
throw error;
|
|
248
|
-
await delay(Math.min(4000, 250 * 2 ** attempt), work.signal);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
finally {
|
|
253
|
-
renewing = false;
|
|
254
|
-
wakeRenewal?.();
|
|
255
|
-
await renewal;
|
|
256
|
-
signal.removeEventListener("abort", stop);
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
const loop = (async () => {
|
|
260
|
-
let retry = 250;
|
|
261
|
-
while (!signal.aborted) {
|
|
262
|
-
const subscription = new AbortController();
|
|
263
|
-
const stop = () => subscription.abort(signal.reason);
|
|
264
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
265
|
-
try {
|
|
266
|
-
const response = await transport.request("/v1/executors/connect", {
|
|
267
|
-
signal: subscription.signal,
|
|
268
|
-
headers: { Accept: "text/event-stream" },
|
|
269
|
-
});
|
|
270
|
-
if (!response.headers.get("content-type")?.includes("text/event-stream"))
|
|
271
|
-
throw new Error("Executor endpoint did not return SSE");
|
|
272
|
-
// Subscription exists before initial discovery; notifications can safely accumulate in its stream.
|
|
273
|
-
await discover();
|
|
274
|
-
resolveReady();
|
|
275
|
-
for await (const frame of readSSE(response, subscription.signal)) {
|
|
276
|
-
retry = 250;
|
|
277
|
-
if (frame.event === "work_available" ||
|
|
278
|
-
(frame.data && JSON.parse(frame.data).type === "work_available"))
|
|
279
|
-
await discover();
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
catch (error) {
|
|
283
|
-
if (signal.aborted)
|
|
284
|
-
break;
|
|
285
|
-
report(error);
|
|
286
|
-
if (error instanceof RuntimeError &&
|
|
287
|
-
[400, 401, 403, 404].includes(error.status)) {
|
|
288
|
-
rejectReady(error);
|
|
289
|
-
controller.abort(error);
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
finally {
|
|
294
|
-
subscription.abort();
|
|
295
|
-
signal.removeEventListener("abort", stop);
|
|
296
|
-
}
|
|
297
|
-
if (!signal.aborted)
|
|
298
|
-
await delay(retry, signal).catch(() => { });
|
|
299
|
-
retry = Math.min(30000, retry * 2);
|
|
300
|
-
}
|
|
301
|
-
rejectReady(signal.reason ?? new Error("Executor connection closed"));
|
|
302
|
-
})();
|
|
303
|
-
return {
|
|
304
|
-
ready,
|
|
305
|
-
async close() {
|
|
306
|
-
controller.abort(new Error("Executor connection closed"));
|
|
307
|
-
for (const work of active.values())
|
|
308
|
-
work.abort(signal.reason);
|
|
309
|
-
await loop;
|
|
310
|
-
},
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
function connectApplicationMode(options, application, agents) {
|
|
314
|
-
const version = implementationVersionOf(options);
|
|
315
|
-
const children = [];
|
|
316
|
-
let resolveReady;
|
|
317
|
-
let rejectReady;
|
|
318
|
-
const ready = new Promise((resolve, reject) => {
|
|
319
|
-
resolveReady = resolve;
|
|
320
|
-
rejectReady = reject;
|
|
321
|
-
});
|
|
322
|
-
void ready.catch(() => { });
|
|
323
|
-
const boot = (async () => {
|
|
324
|
-
const embedded = embeddedAgents.get(agents) ?? new Set();
|
|
325
|
-
for (const agent of agents.values()) {
|
|
326
|
-
if (embedded.has(agent.id))
|
|
327
|
-
continue;
|
|
328
|
-
await application.saveAgent(agent, { implementationVersion: version });
|
|
329
|
-
}
|
|
330
|
-
const registrations = [...agents.values()].map((agent) => {
|
|
331
|
-
const manifestHash = flowManifestHash(agent);
|
|
332
|
-
return {
|
|
333
|
-
agentId: agent.id,
|
|
334
|
-
token: deriveExecutorToken(application.transport.key, application.transport.tenant, agent.id),
|
|
335
|
-
implementationVersion: version,
|
|
336
|
-
...(manifestHash === undefined ? {} : { manifestHash }),
|
|
337
|
-
};
|
|
338
|
-
});
|
|
339
|
-
await application.transport.json("/v1/executors", "PUT", {
|
|
340
|
-
executors: registrations,
|
|
341
|
-
});
|
|
342
|
-
for (const agent of agents.values()) {
|
|
343
|
-
const token = deriveExecutorToken(application.transport.key, application.transport.tenant, agent.id);
|
|
344
|
-
const child = connectExecutorMode({
|
|
345
|
-
agents: [agent],
|
|
346
|
-
implementationVersion: version,
|
|
347
|
-
onError: options.onError,
|
|
348
|
-
}, {
|
|
349
|
-
url: application.transport.url,
|
|
350
|
-
tenant: application.transport.tenant,
|
|
351
|
-
key: token,
|
|
352
|
-
fetch: application.transport.fetcher,
|
|
353
|
-
}, new Map([[agent.id, agent]]));
|
|
354
|
-
children.push(child);
|
|
355
|
-
}
|
|
356
|
-
await Promise.all(children.map((child) => child.ready));
|
|
357
|
-
resolveReady();
|
|
358
|
-
})().catch((error) => {
|
|
359
|
-
rejectReady(error);
|
|
360
|
-
});
|
|
361
|
-
return {
|
|
362
|
-
ready,
|
|
363
|
-
async close() {
|
|
364
|
-
await boot.catch(() => { });
|
|
365
|
-
await Promise.allSettled(children.map((child) => child.close()));
|
|
366
|
-
},
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
export function connectAgents(options) {
|
|
370
|
-
const agents = buildAgents(options);
|
|
371
|
-
// D§7.2 mode table: runtime → executor; application → application;
|
|
372
|
-
// neither → resolveConnection() role.
|
|
373
|
-
if (options.runtime) {
|
|
374
|
-
return connectExecutorMode(options, options.runtime, agents);
|
|
375
|
-
}
|
|
376
|
-
if (options.application) {
|
|
377
|
-
return connectApplicationMode(options, options.application, agents);
|
|
378
|
-
}
|
|
379
|
-
let resolveReady;
|
|
380
|
-
let rejectReady;
|
|
381
|
-
const ready = new Promise((resolve, reject) => {
|
|
382
|
-
resolveReady = resolve;
|
|
383
|
-
rejectReady = reject;
|
|
384
|
-
});
|
|
385
|
-
void ready.catch(() => { });
|
|
386
|
-
let handle;
|
|
387
|
-
const boot = (async () => {
|
|
388
|
-
const connection = await resolveConnection();
|
|
389
|
-
if (connection.role === "executor") {
|
|
390
|
-
handle = connectExecutorMode(options, {
|
|
391
|
-
url: connection.url,
|
|
392
|
-
tenant: connection.tenant,
|
|
393
|
-
key: connection.key,
|
|
394
|
-
}, agents);
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
const application = new AgentsClient({
|
|
398
|
-
url: connection.url,
|
|
399
|
-
tenant: connection.tenant,
|
|
400
|
-
key: connection.key,
|
|
401
|
-
});
|
|
402
|
-
handle = connectApplicationMode(options, application, agents);
|
|
403
|
-
}
|
|
404
|
-
await handle.ready;
|
|
405
|
-
resolveReady();
|
|
406
|
-
})().catch((error) => {
|
|
407
|
-
rejectReady(error);
|
|
408
|
-
});
|
|
409
|
-
return {
|
|
410
|
-
ready,
|
|
411
|
-
async close() {
|
|
412
|
-
await boot.catch(() => { });
|
|
413
|
-
await handle?.close();
|
|
414
|
-
},
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
export { deriveExecutorToken };
|