@tangle-network/agent-runtime 0.101.1 → 0.102.0

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.
@@ -0,0 +1,578 @@
1
+ import {
2
+ CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV,
3
+ CANDIDATE_KNOWLEDGE_ROOT_ENV,
4
+ candidateKnowledgeExecutionPaths,
5
+ canonicalCandidateBytes,
6
+ canonicalCandidateDigest,
7
+ immutableCandidateValue,
8
+ sha256Bytes
9
+ } from "./chunk-TGDHHHH4.js";
10
+
11
+ // src/candidate-execution/exact-process-executor.ts
12
+ import { posix } from "path";
13
+ import { isDeepStrictEqual } from "util";
14
+ var DEFAULT_PROVISION_TIMEOUT_MS = 12e4;
15
+ var DEFAULT_RECOVERY_RETENTION_MS = 15 * 6e4;
16
+ function exactProcessProviderAsCandidateExecutor(options) {
17
+ return new ExactProcessAgentCandidateExecutor(options);
18
+ }
19
+ var ExactProcessAgentCandidateExecutor = class {
20
+ constructor(options) {
21
+ this.options = options;
22
+ if (!options.provider.exactProcess) {
23
+ throw new Error(
24
+ `agent environment provider "${options.provider.name}" does not implement exact processes`
25
+ );
26
+ }
27
+ this.exactProcess = options.provider.exactProcess;
28
+ this.resources = exactResources(options.resources);
29
+ this.provisionTimeoutMs = positiveInteger(
30
+ options.provisionTimeoutMs ?? DEFAULT_PROVISION_TIMEOUT_MS,
31
+ "exact process provision timeout"
32
+ );
33
+ this.recoveryRetentionMs = positiveInteger(
34
+ options.recoveryRetentionMs ?? DEFAULT_RECOVERY_RETENTION_MS,
35
+ "exact process recovery retention"
36
+ );
37
+ this.providerOptions = options.providerOptions ? immutableCandidateValue(options.providerOptions) : void 0;
38
+ }
39
+ options;
40
+ states = /* @__PURE__ */ new Map();
41
+ exactProcess;
42
+ resources;
43
+ provisionTimeoutMs;
44
+ recoveryRetentionMs;
45
+ providerOptions;
46
+ capabilitiesPromise;
47
+ async execute(request, context) {
48
+ assertSupportedRequest(request);
49
+ const outcome = request.benchmark.task.outcome;
50
+ if (outcome.kind !== "output") throw new Error("exact process executor requires an output task");
51
+ const network = request.executionPlan.value.material.model.access.network;
52
+ const egress = network.mode === "disabled" ? { mode: "blocked" } : { mode: "strict", allowDomains: [...network.domains] };
53
+ await this.assertCapability(egress.mode);
54
+ context.signal.throwIfAborted();
55
+ const key = executionKey(request.executionId, request.executionPlan.value.digest);
56
+ if (this.states.has(key)) throw new Error("candidate execution environment is already active");
57
+ const image = exactImage(
58
+ request.executionPlan.value.material.container.image,
59
+ request.executionPlan.value.material.container.manifestDigest
60
+ );
61
+ const maxLifetimeMs = environmentLifetimeMs(
62
+ request.hardLimits.timeoutMs,
63
+ this.recoveryRetentionMs
64
+ );
65
+ const createMaterial = immutableCandidateValue({
66
+ kind: "agent-candidate-exact-process-create",
67
+ provider: this.options.provider.name,
68
+ executionId: request.executionId,
69
+ executionPlanDigest: request.executionPlan.value.digest,
70
+ image,
71
+ egress,
72
+ maxLifetimeMs,
73
+ provisionTimeoutMs: this.provisionTimeoutMs,
74
+ resources: this.resources,
75
+ output: { mediaType: outcome.mediaType, maxBytes: outcome.maxBytes },
76
+ ...this.providerOptions ? { providerOptions: this.providerOptions } : {}
77
+ });
78
+ const createInputDigest = canonicalCandidateDigest(createMaterial);
79
+ const metadata = immutableCandidateValue({
80
+ kind: "agent-candidate-execution",
81
+ provider: this.options.provider.name,
82
+ executionId: request.executionId,
83
+ executionPlanDigest: request.executionPlan.value.digest,
84
+ createInputDigest,
85
+ outputMediaType: outcome.mediaType,
86
+ outputMaxBytes: outcome.maxBytes
87
+ });
88
+ const environment = await this.exactProcess.create({
89
+ image,
90
+ egress,
91
+ maxLifetimeMs,
92
+ provisionTimeoutMs: this.provisionTimeoutMs,
93
+ resources: this.resources,
94
+ metadata,
95
+ idempotencyKey: executionIdempotencyKey(
96
+ request.executionId,
97
+ request.executionPlan.value.digest
98
+ ),
99
+ signal: context.signal,
100
+ ...this.providerOptions ? { providerOptions: this.providerOptions } : {}
101
+ });
102
+ try {
103
+ assertExecutionEnvironment(environment, metadata, this.options.provider.name);
104
+ } catch (error) {
105
+ try {
106
+ await environment.destroy();
107
+ } catch (cleanupError) {
108
+ throw new AggregateError(
109
+ [error, cleanupError],
110
+ "exact process validation and cleanup both failed"
111
+ );
112
+ }
113
+ throw error;
114
+ }
115
+ const state = { environment };
116
+ this.states.set(key, state);
117
+ const existing = await environment.process.list();
118
+ if (existing.length !== 0) {
119
+ throw new Error("fresh candidate environment already contains a process");
120
+ }
121
+ await materializeRequest(environment, request, context.signal);
122
+ const launch = exactLaunch(request);
123
+ const startedAt = Date.now();
124
+ state.trace = {
125
+ runId: request.trace.runId,
126
+ scenarioId: request.benchmark.task.scenario.id,
127
+ startedAt,
128
+ deadlineAtMs: context.deadlineAtMs,
129
+ timeoutMs: request.hardLimits.timeoutMs,
130
+ tags: {
131
+ ...request.trace.tags,
132
+ environmentId: environment.id,
133
+ environmentProvider: environment.provider
134
+ },
135
+ written: false
136
+ };
137
+ const process = await environment.process.spawn(launch, { signal: context.signal });
138
+ const outputPromise = collectOutput(process, outcome.maxBytes);
139
+ void outputPromise.catch(() => void 0);
140
+ let cancellation;
141
+ let processExited = false;
142
+ const cancel = () => {
143
+ if (!processExited) cancellation ??= stopProcess(process);
144
+ };
145
+ context.signal.addEventListener("abort", cancel, { once: true });
146
+ if (context.signal.aborted) cancel();
147
+ try {
148
+ const termination = await process.wait();
149
+ processExited = true;
150
+ context.signal.removeEventListener("abort", cancel);
151
+ if (cancellation) await cancellation;
152
+ const status = await process.status();
153
+ assertTerminalStatus(status, termination);
154
+ state.output = await awaitOutput(outputPromise, context.signal, context.deadlineAtMs);
155
+ state.termination = termination;
156
+ await appendExactProcessTrace(state, context.traceStore, status);
157
+ return { executionId: request.executionId, termination };
158
+ } finally {
159
+ context.signal.removeEventListener("abort", cancel);
160
+ }
161
+ }
162
+ async stop(request, context) {
163
+ await this.assertCapability();
164
+ context.signal.throwIfAborted();
165
+ const environment = await this.resolve(request, true);
166
+ if (!environment) return { stopped: true };
167
+ let statuses = await environment.process.list();
168
+ if (statuses.length > 1) {
169
+ throw new Error("candidate exact process environment contains more than one process");
170
+ }
171
+ const status = statuses[0];
172
+ if (status?.running) {
173
+ const process = await environment.process.get(status.pid);
174
+ if (!process) throw new Error("candidate environment lost its running process handle");
175
+ await stopProcess(process);
176
+ }
177
+ context.signal.throwIfAborted();
178
+ statuses = await environment.process.list();
179
+ if (statuses.some((entry) => entry.running)) {
180
+ throw new Error("candidate exact process termination is not proven");
181
+ }
182
+ const finalStatus = statuses[0];
183
+ if (finalStatus) assertTerminalStatus(finalStatus);
184
+ const state = this.states.get(executionKey(request.executionId, request.executionPlanDigest));
185
+ if (state) {
186
+ state.termination = finalStatus?.termination ?? state.termination;
187
+ if (context.reason === "timeout" && state.trace) {
188
+ state.runtimeTermination = {
189
+ kind: "timeout",
190
+ timeoutMs: state.trace.timeoutMs
191
+ };
192
+ }
193
+ await appendExactProcessTrace(state, context.traceStore, finalStatus);
194
+ }
195
+ return { stopped: true };
196
+ }
197
+ async capture(request, context) {
198
+ await this.assertCapability();
199
+ context.signal.throwIfAborted();
200
+ const environment = await this.resolve(request, false);
201
+ const statuses = await environment.process.list();
202
+ const status = statuses[0];
203
+ if (statuses.length !== 1 || !status || status.running) {
204
+ throw new Error("candidate environment must contain one stopped process before capture");
205
+ }
206
+ assertTerminalStatus(status);
207
+ const process = await environment.process.get(status.pid);
208
+ if (!process) throw new Error("candidate environment lost its captured process handle");
209
+ const currentStatus = await process.status();
210
+ assertTerminalStatus(currentStatus, status.termination);
211
+ const state = this.states.get(executionKey(request.executionId, request.executionPlanDigest));
212
+ const output = state?.output ?? await awaitOutput(
213
+ collectOutput(process, outputSpec(environment).maxBytes),
214
+ context.signal,
215
+ Date.now() + this.provisionTimeoutMs
216
+ );
217
+ context.signal.throwIfAborted();
218
+ const evidence = canonicalCandidateBytes({
219
+ kind: "agent-candidate-exact-process-capture",
220
+ provider: environment.provider,
221
+ environmentId: environment.id,
222
+ executionId: request.executionId,
223
+ executionPlanDigest: request.executionPlanDigest,
224
+ createInputDigest: environment.metadata?.createInputDigest,
225
+ process: {
226
+ pid: status.pid,
227
+ exitCode: status.exitCode,
228
+ ...status.exitSignal ? { exitSignal: status.exitSignal } : {},
229
+ termination: status.termination
230
+ },
231
+ ...state?.runtimeTermination ? { runtimeTermination: state.runtimeTermination } : {},
232
+ output: { sha256: sha256Bytes(output), byteLength: output.byteLength }
233
+ });
234
+ return {
235
+ taskOutcome: { kind: "output", bytes: output },
236
+ evidence
237
+ };
238
+ }
239
+ async dispose(request, context) {
240
+ await this.assertCapability();
241
+ context.signal.throwIfAborted();
242
+ const environment = await this.resolve(request, true);
243
+ if (!environment) return { disposed: true };
244
+ let destroyError;
245
+ try {
246
+ await environment.destroy();
247
+ } catch (error) {
248
+ destroyError = error;
249
+ }
250
+ const remaining = await this.exactProcess.get(environment.id);
251
+ if (remaining) {
252
+ throw new Error("exact process environment disposal is not proven", { cause: destroyError });
253
+ }
254
+ context.signal.throwIfAborted();
255
+ this.states.delete(executionKey(request.executionId, request.executionPlanDigest));
256
+ return { disposed: true };
257
+ }
258
+ async assertCapability(mode) {
259
+ const pending = this.capabilitiesPromise ?? Promise.resolve(this.options.provider.capabilities());
260
+ this.capabilitiesPromise = pending;
261
+ let capabilities;
262
+ try {
263
+ capabilities = await pending;
264
+ } catch (error) {
265
+ if (this.capabilitiesPromise === pending) this.capabilitiesPromise = void 0;
266
+ throw error;
267
+ }
268
+ const exact = capabilities.exactProcess;
269
+ if (!exact) {
270
+ throw new Error(
271
+ `agent environment provider "${this.options.provider.name}" does not declare exact process support`
272
+ );
273
+ }
274
+ if (mode && !exact.egress.includes(mode)) {
275
+ throw new Error(
276
+ `agent environment provider "${this.options.provider.name}" does not declare ${mode} exact egress`
277
+ );
278
+ }
279
+ }
280
+ async resolve(request, missingIsDeleted) {
281
+ const key = executionKey(request.executionId, request.executionPlanDigest);
282
+ const active = this.states.get(key)?.environment;
283
+ if (active) return active;
284
+ const metadata = {
285
+ kind: "agent-candidate-execution",
286
+ provider: this.options.provider.name,
287
+ executionId: request.executionId,
288
+ executionPlanDigest: request.executionPlanDigest
289
+ };
290
+ const listed = await this.exactProcess.list({
291
+ metadata,
292
+ ...this.providerOptions ? { providerOptions: this.providerOptions } : {}
293
+ });
294
+ const matches = listed.filter(
295
+ (environment2) => environment2.provider === this.options.provider.name && Object.entries(metadata).every(
296
+ ([name, value]) => isDeepStrictEqual(environment2.metadata?.[name], value)
297
+ )
298
+ );
299
+ if (matches.length > 1) {
300
+ throw new Error("multiple exact process environments match one candidate execution");
301
+ }
302
+ const environment = matches[0];
303
+ if (!environment) {
304
+ if (missingIsDeleted) return void 0;
305
+ throw new Error("candidate exact process evidence is unavailable");
306
+ }
307
+ if (!isSha256Digest(environment.metadata?.createInputDigest)) {
308
+ throw new Error("candidate exact process create-input digest is unavailable");
309
+ }
310
+ this.states.set(key, { environment });
311
+ return environment;
312
+ }
313
+ };
314
+ async function appendExactProcessTrace(state, traceStore, status) {
315
+ const trace = state.trace;
316
+ if (!trace || trace.written) return;
317
+ const endedAt = Math.max(trace.startedAt, Math.min(Date.now(), trace.deadlineAtMs));
318
+ const termination = state.runtimeTermination ?? state.termination ?? status?.termination;
319
+ await traceStore.appendRun({
320
+ runId: trace.runId,
321
+ scenarioId: trace.scenarioId,
322
+ startedAt: trace.startedAt,
323
+ endedAt,
324
+ status: termination?.kind === "exit" && termination.exitCode === 0 ? "completed" : "failed",
325
+ tags: trace.tags
326
+ });
327
+ trace.written = true;
328
+ }
329
+ function assertSupportedRequest(request) {
330
+ if (request.benchmark.task.outcome.kind !== "output") {
331
+ throw new Error(
332
+ "exact process candidate executor does not support workspace outcomes; use Pier"
333
+ );
334
+ }
335
+ if (request.executionPlan.value.material.codeKind !== "disabled" || request.inputs.candidate) {
336
+ throw new Error("exact process candidate executor does not support code workspaces; use Pier");
337
+ }
338
+ if (request.memory.mode !== "disabled") {
339
+ throw new Error("exact process candidate executor does not support isolated memory");
340
+ }
341
+ const mediaType = request.benchmark.task.outcome.mediaType.toLowerCase();
342
+ if (!(mediaType.startsWith("text/") || mediaType === "application/json" || mediaType.endsWith("+json"))) {
343
+ throw new Error("exact process candidate executor supports only UTF-8 text and JSON outputs");
344
+ }
345
+ if (!posix.isAbsolute(request.launch.executable) && !request.launch.env.PATH?.trim()) {
346
+ throw new Error("exact process candidate executable must be absolute or declare a signed PATH");
347
+ }
348
+ }
349
+ async function materializeRequest(environment, request, signal) {
350
+ const knowledgePaths = assertKnowledgeExecutionBinding(request);
351
+ for (const file of request.inputs.task.files) {
352
+ await environment.writeFile(beneath(request.roots.taskRoot, file.path), file.bytes, {
353
+ mode: file.mode,
354
+ signal
355
+ });
356
+ }
357
+ const profileRoot = request.executionPlan.value.material.profile.targetWorkspace === "task" ? request.roots.taskRoot : request.roots.candidateRoot;
358
+ if (!profileRoot) throw new Error("candidate profile targets a missing workspace");
359
+ for (const file of request.profileActivation.files) {
360
+ await environment.writeFile(
361
+ beneath(profileRoot, file.path),
362
+ Buffer.from(file.content, "utf8"),
363
+ { mode: file.mode, signal }
364
+ );
365
+ }
366
+ if (request.knowledge && knowledgePaths) {
367
+ for (const file of request.knowledge.files) {
368
+ await environment.writeFile(beneath(knowledgePaths.root, file.path), file.bytes, {
369
+ mode: file.mode,
370
+ signal
371
+ });
372
+ }
373
+ if (request.knowledge.retrievalConfig && knowledgePaths.retrievalConfig) {
374
+ await environment.writeFile(
375
+ knowledgePaths.retrievalConfig,
376
+ request.knowledge.retrievalConfig,
377
+ { mode: 420, signal }
378
+ );
379
+ }
380
+ }
381
+ if (request.instruction.delivery.kind === "utf8-file") {
382
+ await environment.writeFile(request.instruction.delivery.path, request.instruction.bytes, {
383
+ mode: 420,
384
+ signal
385
+ });
386
+ }
387
+ }
388
+ function assertKnowledgeExecutionBinding(request) {
389
+ const knowledge = request.knowledge;
390
+ if (!knowledge) {
391
+ if (request.launch.env[CANDIDATE_KNOWLEDGE_ROOT_ENV] !== void 0 || request.launch.env[CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV] !== void 0) {
392
+ throw new Error("candidate launch declares knowledge paths without verified knowledge");
393
+ }
394
+ return void 0;
395
+ }
396
+ const paths = candidateKnowledgeExecutionPaths(
397
+ request.roots.taskRoot,
398
+ knowledge.retrievalConfig !== void 0
399
+ );
400
+ if (request.launch.env[CANDIDATE_KNOWLEDGE_ROOT_ENV] !== paths.root || request.launch.env[CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV] !== paths.retrievalConfig) {
401
+ throw new Error("candidate knowledge paths do not match the signed launch environment");
402
+ }
403
+ const reserved = [paths.root, paths.retrievalConfig].filter(
404
+ (value) => value !== void 0
405
+ );
406
+ const profileRoot = request.executionPlan.value.material.profile.targetWorkspace === "task" ? request.roots.taskRoot : request.roots.candidateRoot;
407
+ const otherFiles = [
408
+ ...request.inputs.task.files.map((file) => beneath(request.roots.taskRoot, file.path)),
409
+ ...profileRoot ? request.profileActivation.files.map((file) => beneath(profileRoot, file.path)) : [],
410
+ ...request.instruction.delivery.kind === "utf8-file" ? [request.instruction.delivery.path] : []
411
+ ];
412
+ if (otherFiles.some(
413
+ (path) => reserved.some(
414
+ (reservedPath) => path === reservedPath || path.startsWith(`${reservedPath}/`) || reservedPath.startsWith(`${path}/`)
415
+ )
416
+ )) {
417
+ throw new Error("candidate knowledge paths overlap other execution inputs");
418
+ }
419
+ return paths;
420
+ }
421
+ function exactLaunch(request) {
422
+ const instruction = new TextDecoder("utf-8", { fatal: true }).decode(request.instruction.bytes);
423
+ const base = {
424
+ executable: request.launch.executable,
425
+ args: request.launch.args,
426
+ cwd: request.launch.cwd,
427
+ env: request.launch.env,
428
+ timeoutMs: 0
429
+ };
430
+ switch (request.instruction.delivery.kind) {
431
+ case "argv-append":
432
+ return { ...base, args: [...base.args, instruction] };
433
+ case "stdin-utf8":
434
+ return { ...base, stdin: instruction };
435
+ case "utf8-file":
436
+ return base;
437
+ }
438
+ }
439
+ async function collectOutput(process, maxBytes) {
440
+ const chunks = [];
441
+ let byteLength = 0;
442
+ for await (const chunk of process.stdout()) {
443
+ const bytes = Buffer.from(chunk, "utf8");
444
+ byteLength += bytes.byteLength;
445
+ if (byteLength > maxBytes) {
446
+ let stopError;
447
+ try {
448
+ await stopProcess(process);
449
+ } catch (error) {
450
+ stopError = error;
451
+ }
452
+ throw new Error(`candidate output exceeds its ${maxBytes}-byte maximum`, {
453
+ cause: stopError
454
+ });
455
+ }
456
+ chunks.push(bytes);
457
+ }
458
+ return Uint8Array.from(Buffer.concat(chunks, byteLength));
459
+ }
460
+ async function awaitOutput(output, signal, deadlineAtMs) {
461
+ signal.throwIfAborted();
462
+ const remainingMs = deadlineAtMs - Date.now();
463
+ if (remainingMs <= 0) throw new Error("candidate output deadline expired");
464
+ let timer;
465
+ let onAbort;
466
+ try {
467
+ return await Promise.race([
468
+ output,
469
+ new Promise((_resolve, reject) => {
470
+ onAbort = () => reject(signal.reason ?? new Error("candidate output cancelled"));
471
+ signal.addEventListener("abort", onAbort, { once: true });
472
+ timer = setTimeout(
473
+ () => reject(new Error("candidate output deadline expired")),
474
+ remainingMs
475
+ );
476
+ })
477
+ ]);
478
+ } finally {
479
+ if (onAbort) signal.removeEventListener("abort", onAbort);
480
+ if (timer) clearTimeout(timer);
481
+ }
482
+ }
483
+ async function stopProcess(process) {
484
+ const before = await process.status();
485
+ if (!before.running) return;
486
+ try {
487
+ await process.kill();
488
+ } catch (error) {
489
+ if ((await process.status()).running) throw error;
490
+ }
491
+ const termination = await process.wait();
492
+ assertTerminalStatus(await process.status(), termination);
493
+ }
494
+ function assertTerminalStatus(status, expected) {
495
+ if (status.running || !status.termination) {
496
+ throw new Error("exact process returned no terminal reason after exit");
497
+ }
498
+ if (expected && !isDeepStrictEqual(status.termination, expected)) {
499
+ throw new Error("exact process wait and status returned different terminal reasons");
500
+ }
501
+ }
502
+ function assertExecutionEnvironment(environment, metadata, providerName) {
503
+ if (!environment.id || environment.provider !== providerName) {
504
+ throw new Error("exact process provider returned the wrong environment identity");
505
+ }
506
+ if (!Object.entries(metadata).every(
507
+ ([name, value]) => isDeepStrictEqual(environment.metadata?.[name], value)
508
+ )) {
509
+ throw new Error("exact process provider did not persist candidate execution metadata");
510
+ }
511
+ }
512
+ function outputSpec(environment) {
513
+ const maxBytes = environment.metadata?.outputMaxBytes;
514
+ if (!Number.isSafeInteger(maxBytes) || Number(maxBytes) < 1) {
515
+ throw new Error("candidate exact process output bound is unavailable");
516
+ }
517
+ return { maxBytes: Number(maxBytes) };
518
+ }
519
+ function executionKey(executionId, executionPlanDigest) {
520
+ return `${executionId}\0${executionPlanDigest}`;
521
+ }
522
+ function executionIdempotencyKey(executionId, executionPlanDigest) {
523
+ return `candidate-${canonicalCandidateDigest({
524
+ kind: "agent-candidate-execution-identity",
525
+ executionId,
526
+ executionPlanDigest
527
+ }).slice("sha256:".length)}`;
528
+ }
529
+ function exactImage(image, manifestDigest) {
530
+ if (isSha256Digest(image)) {
531
+ if (image !== manifestDigest) {
532
+ throw new Error("candidate container image conflicts with its resolved manifest");
533
+ }
534
+ return image;
535
+ }
536
+ const marker = image.lastIndexOf("@");
537
+ if (marker < 0) return `${image}@${manifestDigest}`;
538
+ if (image.slice(marker + 1) !== manifestDigest) {
539
+ throw new Error("candidate container image conflicts with its resolved manifest");
540
+ }
541
+ return image;
542
+ }
543
+ function environmentLifetimeMs(timeoutMs, retentionMs) {
544
+ const total = positiveInteger(timeoutMs, "candidate execution timeout") + retentionMs;
545
+ if (!Number.isSafeInteger(total)) throw new Error("candidate environment lifetime is too large");
546
+ return Math.ceil(total / 1e3) * 1e3;
547
+ }
548
+ function exactResources(resources) {
549
+ if (!Number.isFinite(resources.cpu) || resources.cpu <= 0) {
550
+ throw new Error("exact process CPU must be positive and finite");
551
+ }
552
+ return Object.freeze({
553
+ cpu: resources.cpu,
554
+ memoryMb: positiveInteger(resources.memoryMb, "exact process memory"),
555
+ diskMb: positiveInteger(resources.diskMb, "exact process disk")
556
+ });
557
+ }
558
+ function positiveInteger(value, label) {
559
+ if (!Number.isSafeInteger(value) || value < 1)
560
+ throw new Error(`${label} must be a positive integer`);
561
+ return value;
562
+ }
563
+ function beneath(root, relativePath) {
564
+ if (posix.isAbsolute(relativePath)) throw new Error("candidate input path must be relative");
565
+ const path = posix.normalize(relativePath);
566
+ if (path === ".." || path.startsWith("../")) {
567
+ throw new Error("candidate input path escapes its execution root");
568
+ }
569
+ return posix.join(root, path);
570
+ }
571
+ function isSha256Digest(value) {
572
+ return typeof value === "string" && /^sha256:[a-f0-9]{64}$/.test(value);
573
+ }
574
+
575
+ export {
576
+ exactProcessProviderAsCandidateExecutor
577
+ };
578
+ //# sourceMappingURL=chunk-SPCD4IQQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/candidate-execution/exact-process-executor.ts"],"sourcesContent":["import { posix } from 'node:path'\nimport { isDeepStrictEqual } from 'node:util'\n\nimport type { TraceStore } from '@tangle-network/agent-eval'\nimport type { AgentCandidateTermination, Sha256Digest } from '@tangle-network/agent-interface'\nimport type {\n AgentEnvironmentCapabilities,\n AgentEnvironmentProvider,\n AgentExactProcess,\n AgentExactProcessEnvironment,\n AgentExactProcessLaunch,\n AgentExactProcessResources,\n AgentExactProcessStatus,\n} from '@tangle-network/agent-interface/environment-provider'\n\nimport {\n canonicalCandidateBytes,\n canonicalCandidateDigest,\n immutableCandidateValue,\n sha256Bytes,\n} from './digest'\nimport {\n CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV,\n CANDIDATE_KNOWLEDGE_ROOT_ENV,\n candidateKnowledgeExecutionPaths,\n} from './knowledge'\nimport type {\n AgentCandidateExecutorPort,\n AgentCandidateExecutorRequest,\n AgentCandidateExecutorStopRequest,\n} from './types'\n\nconst DEFAULT_PROVISION_TIMEOUT_MS = 120_000\nconst DEFAULT_RECOVERY_RETENTION_MS = 15 * 60_000\n\ninterface ExactProcessRunState {\n environment: AgentExactProcessEnvironment\n output?: Uint8Array\n termination?: AgentCandidateTermination\n runtimeTermination?: AgentCandidateTermination\n trace?: {\n runId: string\n scenarioId: string\n startedAt: number\n deadlineAtMs: number\n timeoutMs: number\n tags: Record<string, string>\n written: boolean\n }\n}\n\nexport interface ExactProcessCandidateExecutorOptions {\n provider: AgentEnvironmentProvider\n resources: AgentExactProcessResources\n provisionTimeoutMs?: number\n recoveryRetentionMs?: number\n providerOptions?: Record<string, unknown>\n}\n\n/** Adapt one neutral exact-process provider to Runtime's trusted candidate boundary. */\nexport function exactProcessProviderAsCandidateExecutor(\n options: ExactProcessCandidateExecutorOptions,\n): AgentCandidateExecutorPort {\n return new ExactProcessAgentCandidateExecutor(options)\n}\n\nclass ExactProcessAgentCandidateExecutor implements AgentCandidateExecutorPort {\n private readonly states = new Map<string, ExactProcessRunState>()\n private readonly exactProcess\n private readonly resources: AgentExactProcessResources\n private readonly provisionTimeoutMs: number\n private readonly recoveryRetentionMs: number\n private readonly providerOptions?: Record<string, unknown>\n private capabilitiesPromise?: Promise<AgentEnvironmentCapabilities>\n\n constructor(private readonly options: ExactProcessCandidateExecutorOptions) {\n if (!options.provider.exactProcess) {\n throw new Error(\n `agent environment provider \"${options.provider.name}\" does not implement exact processes`,\n )\n }\n this.exactProcess = options.provider.exactProcess\n this.resources = exactResources(options.resources)\n this.provisionTimeoutMs = positiveInteger(\n options.provisionTimeoutMs ?? DEFAULT_PROVISION_TIMEOUT_MS,\n 'exact process provision timeout',\n )\n this.recoveryRetentionMs = positiveInteger(\n options.recoveryRetentionMs ?? DEFAULT_RECOVERY_RETENTION_MS,\n 'exact process recovery retention',\n )\n this.providerOptions = options.providerOptions\n ? immutableCandidateValue(options.providerOptions)\n : undefined\n }\n\n async execute(\n request: AgentCandidateExecutorRequest,\n context: Parameters<AgentCandidateExecutorPort['execute']>[1],\n ) {\n assertSupportedRequest(request)\n const outcome = request.benchmark.task.outcome\n if (outcome.kind !== 'output') throw new Error('exact process executor requires an output task')\n const network = request.executionPlan.value.material.model.access.network\n const egress =\n network.mode === 'disabled'\n ? ({ mode: 'blocked' } as const)\n : ({ mode: 'strict', allowDomains: [...network.domains] } as const)\n await this.assertCapability(egress.mode)\n context.signal.throwIfAborted()\n\n const key = executionKey(request.executionId, request.executionPlan.value.digest)\n if (this.states.has(key)) throw new Error('candidate execution environment is already active')\n const image = exactImage(\n request.executionPlan.value.material.container.image,\n request.executionPlan.value.material.container.manifestDigest,\n )\n const maxLifetimeMs = environmentLifetimeMs(\n request.hardLimits.timeoutMs,\n this.recoveryRetentionMs,\n )\n const createMaterial = immutableCandidateValue({\n kind: 'agent-candidate-exact-process-create',\n provider: this.options.provider.name,\n executionId: request.executionId,\n executionPlanDigest: request.executionPlan.value.digest,\n image,\n egress,\n maxLifetimeMs,\n provisionTimeoutMs: this.provisionTimeoutMs,\n resources: this.resources,\n output: { mediaType: outcome.mediaType, maxBytes: outcome.maxBytes },\n ...(this.providerOptions ? { providerOptions: this.providerOptions } : {}),\n })\n const createInputDigest = canonicalCandidateDigest(createMaterial)\n const metadata = immutableCandidateValue({\n kind: 'agent-candidate-execution',\n provider: this.options.provider.name,\n executionId: request.executionId,\n executionPlanDigest: request.executionPlan.value.digest,\n createInputDigest,\n outputMediaType: outcome.mediaType,\n outputMaxBytes: outcome.maxBytes,\n })\n const environment = await this.exactProcess.create({\n image,\n egress,\n maxLifetimeMs,\n provisionTimeoutMs: this.provisionTimeoutMs,\n resources: this.resources,\n metadata,\n idempotencyKey: executionIdempotencyKey(\n request.executionId,\n request.executionPlan.value.digest,\n ),\n signal: context.signal,\n ...(this.providerOptions ? { providerOptions: this.providerOptions } : {}),\n })\n try {\n assertExecutionEnvironment(environment, metadata, this.options.provider.name)\n } catch (error) {\n try {\n await environment.destroy()\n } catch (cleanupError) {\n throw new AggregateError(\n [error, cleanupError],\n 'exact process validation and cleanup both failed',\n )\n }\n throw error\n }\n const state: ExactProcessRunState = { environment }\n this.states.set(key, state)\n\n const existing = await environment.process.list()\n if (existing.length !== 0) {\n throw new Error('fresh candidate environment already contains a process')\n }\n await materializeRequest(environment, request, context.signal)\n const launch = exactLaunch(request)\n const startedAt = Date.now()\n state.trace = {\n runId: request.trace.runId,\n scenarioId: request.benchmark.task.scenario.id,\n startedAt,\n deadlineAtMs: context.deadlineAtMs,\n timeoutMs: request.hardLimits.timeoutMs,\n tags: {\n ...request.trace.tags,\n environmentId: environment.id,\n environmentProvider: environment.provider,\n },\n written: false,\n }\n const process = await environment.process.spawn(launch, { signal: context.signal })\n const outputPromise = collectOutput(process, outcome.maxBytes)\n void outputPromise.catch(() => undefined)\n let cancellation: Promise<void> | undefined\n let processExited = false\n const cancel = () => {\n if (!processExited) cancellation ??= stopProcess(process)\n }\n context.signal.addEventListener('abort', cancel, { once: true })\n if (context.signal.aborted) cancel()\n try {\n const termination = await process.wait()\n processExited = true\n context.signal.removeEventListener('abort', cancel)\n if (cancellation) await cancellation\n const status = await process.status()\n assertTerminalStatus(status, termination)\n state.output = await awaitOutput(outputPromise, context.signal, context.deadlineAtMs)\n state.termination = termination\n await appendExactProcessTrace(state, context.traceStore, status)\n return { executionId: request.executionId, termination }\n } finally {\n context.signal.removeEventListener('abort', cancel)\n }\n }\n\n async stop(\n request: AgentCandidateExecutorStopRequest,\n context: Parameters<AgentCandidateExecutorPort['stop']>[1],\n ): Promise<{ readonly stopped: true }> {\n await this.assertCapability()\n context.signal.throwIfAborted()\n const environment = await this.resolve(request, true)\n if (!environment) return { stopped: true }\n let statuses = await environment.process.list()\n if (statuses.length > 1) {\n throw new Error('candidate exact process environment contains more than one process')\n }\n const status = statuses[0]\n if (status?.running) {\n const process = await environment.process.get(status.pid)\n if (!process) throw new Error('candidate environment lost its running process handle')\n await stopProcess(process)\n }\n context.signal.throwIfAborted()\n statuses = await environment.process.list()\n if (statuses.some((entry) => entry.running)) {\n throw new Error('candidate exact process termination is not proven')\n }\n const finalStatus = statuses[0]\n if (finalStatus) assertTerminalStatus(finalStatus)\n const state = this.states.get(executionKey(request.executionId, request.executionPlanDigest))\n if (state) {\n state.termination = finalStatus?.termination ?? state.termination\n if (context.reason === 'timeout' && state.trace) {\n state.runtimeTermination = {\n kind: 'timeout',\n timeoutMs: state.trace.timeoutMs,\n }\n }\n await appendExactProcessTrace(state, context.traceStore, finalStatus)\n }\n return { stopped: true }\n }\n\n async capture(\n request: AgentCandidateExecutorStopRequest,\n context: Parameters<AgentCandidateExecutorPort['capture']>[1],\n ) {\n await this.assertCapability()\n context.signal.throwIfAborted()\n const environment = await this.resolve(request, false)\n const statuses = await environment.process.list()\n const status = statuses[0]\n if (statuses.length !== 1 || !status || status.running) {\n throw new Error('candidate environment must contain one stopped process before capture')\n }\n assertTerminalStatus(status)\n const process = await environment.process.get(status.pid)\n if (!process) throw new Error('candidate environment lost its captured process handle')\n const currentStatus = await process.status()\n assertTerminalStatus(currentStatus, status.termination)\n const state = this.states.get(executionKey(request.executionId, request.executionPlanDigest))\n const output =\n state?.output ??\n (await awaitOutput(\n collectOutput(process, outputSpec(environment).maxBytes),\n context.signal,\n Date.now() + this.provisionTimeoutMs,\n ))\n context.signal.throwIfAborted()\n const evidence = canonicalCandidateBytes({\n kind: 'agent-candidate-exact-process-capture',\n provider: environment.provider,\n environmentId: environment.id,\n executionId: request.executionId,\n executionPlanDigest: request.executionPlanDigest,\n createInputDigest: environment.metadata?.createInputDigest,\n process: {\n pid: status.pid,\n exitCode: status.exitCode,\n ...(status.exitSignal ? { exitSignal: status.exitSignal } : {}),\n termination: status.termination,\n },\n ...(state?.runtimeTermination ? { runtimeTermination: state.runtimeTermination } : {}),\n output: { sha256: sha256Bytes(output), byteLength: output.byteLength },\n })\n return {\n taskOutcome: { kind: 'output' as const, bytes: output },\n evidence,\n }\n }\n\n async dispose(\n request: AgentCandidateExecutorStopRequest,\n context: { signal: AbortSignal },\n ): Promise<{ readonly disposed: true }> {\n await this.assertCapability()\n context.signal.throwIfAborted()\n const environment = await this.resolve(request, true)\n if (!environment) return { disposed: true }\n let destroyError: unknown\n try {\n await environment.destroy()\n } catch (error) {\n destroyError = error\n }\n const remaining = await this.exactProcess.get(environment.id)\n if (remaining) {\n throw new Error('exact process environment disposal is not proven', { cause: destroyError })\n }\n context.signal.throwIfAborted()\n this.states.delete(executionKey(request.executionId, request.executionPlanDigest))\n return { disposed: true }\n }\n\n private async assertCapability(mode?: 'blocked' | 'strict'): Promise<void> {\n const pending =\n this.capabilitiesPromise ?? Promise.resolve(this.options.provider.capabilities())\n this.capabilitiesPromise = pending\n let capabilities: AgentEnvironmentCapabilities\n try {\n capabilities = await pending\n } catch (error) {\n if (this.capabilitiesPromise === pending) this.capabilitiesPromise = undefined\n throw error\n }\n const exact = capabilities.exactProcess\n if (!exact) {\n throw new Error(\n `agent environment provider \"${this.options.provider.name}\" does not declare exact process support`,\n )\n }\n if (mode && !exact.egress.includes(mode)) {\n throw new Error(\n `agent environment provider \"${this.options.provider.name}\" does not declare ${mode} exact egress`,\n )\n }\n }\n\n private async resolve(\n request: AgentCandidateExecutorStopRequest,\n missingIsDeleted: false,\n ): Promise<AgentExactProcessEnvironment>\n private async resolve(\n request: AgentCandidateExecutorStopRequest,\n missingIsDeleted: true,\n ): Promise<AgentExactProcessEnvironment | undefined>\n private async resolve(\n request: AgentCandidateExecutorStopRequest,\n missingIsDeleted: boolean,\n ): Promise<AgentExactProcessEnvironment | undefined> {\n const key = executionKey(request.executionId, request.executionPlanDigest)\n const active = this.states.get(key)?.environment\n if (active) return active\n const metadata = {\n kind: 'agent-candidate-execution',\n provider: this.options.provider.name,\n executionId: request.executionId,\n executionPlanDigest: request.executionPlanDigest,\n }\n const listed = await this.exactProcess.list({\n metadata,\n ...(this.providerOptions ? { providerOptions: this.providerOptions } : {}),\n })\n const matches = listed.filter(\n (environment) =>\n environment.provider === this.options.provider.name &&\n Object.entries(metadata).every(([name, value]) =>\n isDeepStrictEqual(environment.metadata?.[name], value),\n ),\n )\n if (matches.length > 1) {\n throw new Error('multiple exact process environments match one candidate execution')\n }\n const environment = matches[0]\n if (!environment) {\n if (missingIsDeleted) return undefined\n throw new Error('candidate exact process evidence is unavailable')\n }\n if (!isSha256Digest(environment.metadata?.createInputDigest)) {\n throw new Error('candidate exact process create-input digest is unavailable')\n }\n this.states.set(key, { environment })\n return environment\n }\n}\n\nasync function appendExactProcessTrace(\n state: ExactProcessRunState,\n traceStore: TraceStore,\n status?: AgentExactProcessStatus,\n): Promise<void> {\n const trace = state.trace\n if (!trace || trace.written) return\n const endedAt = Math.max(trace.startedAt, Math.min(Date.now(), trace.deadlineAtMs))\n const termination = state.runtimeTermination ?? state.termination ?? status?.termination\n await traceStore.appendRun({\n runId: trace.runId,\n scenarioId: trace.scenarioId,\n startedAt: trace.startedAt,\n endedAt,\n status: termination?.kind === 'exit' && termination.exitCode === 0 ? 'completed' : 'failed',\n tags: trace.tags,\n })\n trace.written = true\n}\n\nfunction assertSupportedRequest(request: AgentCandidateExecutorRequest): void {\n if (request.benchmark.task.outcome.kind !== 'output') {\n throw new Error(\n 'exact process candidate executor does not support workspace outcomes; use Pier',\n )\n }\n if (request.executionPlan.value.material.codeKind !== 'disabled' || request.inputs.candidate) {\n throw new Error('exact process candidate executor does not support code workspaces; use Pier')\n }\n if (request.memory.mode !== 'disabled') {\n throw new Error('exact process candidate executor does not support isolated memory')\n }\n const mediaType = request.benchmark.task.outcome.mediaType.toLowerCase()\n if (\n !(\n mediaType.startsWith('text/') ||\n mediaType === 'application/json' ||\n mediaType.endsWith('+json')\n )\n ) {\n throw new Error('exact process candidate executor supports only UTF-8 text and JSON outputs')\n }\n if (!posix.isAbsolute(request.launch.executable) && !request.launch.env.PATH?.trim()) {\n throw new Error('exact process candidate executable must be absolute or declare a signed PATH')\n }\n}\n\nasync function materializeRequest(\n environment: AgentExactProcessEnvironment,\n request: AgentCandidateExecutorRequest,\n signal: AbortSignal,\n): Promise<void> {\n const knowledgePaths = assertKnowledgeExecutionBinding(request)\n for (const file of request.inputs.task.files) {\n await environment.writeFile(beneath(request.roots.taskRoot, file.path), file.bytes, {\n mode: file.mode,\n signal,\n })\n }\n const profileRoot =\n request.executionPlan.value.material.profile.targetWorkspace === 'task'\n ? request.roots.taskRoot\n : request.roots.candidateRoot\n if (!profileRoot) throw new Error('candidate profile targets a missing workspace')\n for (const file of request.profileActivation.files) {\n await environment.writeFile(\n beneath(profileRoot, file.path),\n Buffer.from(file.content, 'utf8'),\n { mode: file.mode, signal },\n )\n }\n if (request.knowledge && knowledgePaths) {\n for (const file of request.knowledge.files) {\n await environment.writeFile(beneath(knowledgePaths.root, file.path), file.bytes, {\n mode: file.mode,\n signal,\n })\n }\n if (request.knowledge.retrievalConfig && knowledgePaths.retrievalConfig) {\n await environment.writeFile(\n knowledgePaths.retrievalConfig,\n request.knowledge.retrievalConfig,\n { mode: 0o644, signal },\n )\n }\n }\n if (request.instruction.delivery.kind === 'utf8-file') {\n await environment.writeFile(request.instruction.delivery.path, request.instruction.bytes, {\n mode: 0o644,\n signal,\n })\n }\n}\n\nfunction assertKnowledgeExecutionBinding(\n request: AgentCandidateExecutorRequest,\n): ReturnType<typeof candidateKnowledgeExecutionPaths> | undefined {\n const knowledge = request.knowledge\n if (!knowledge) {\n if (\n request.launch.env[CANDIDATE_KNOWLEDGE_ROOT_ENV] !== undefined ||\n request.launch.env[CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV] !== undefined\n ) {\n throw new Error('candidate launch declares knowledge paths without verified knowledge')\n }\n return undefined\n }\n const paths = candidateKnowledgeExecutionPaths(\n request.roots.taskRoot,\n knowledge.retrievalConfig !== undefined,\n )\n if (\n request.launch.env[CANDIDATE_KNOWLEDGE_ROOT_ENV] !== paths.root ||\n request.launch.env[CANDIDATE_KNOWLEDGE_RETRIEVAL_CONFIG_ENV] !== paths.retrievalConfig\n ) {\n throw new Error('candidate knowledge paths do not match the signed launch environment')\n }\n const reserved = [paths.root, paths.retrievalConfig].filter(\n (value): value is string => value !== undefined,\n )\n const profileRoot =\n request.executionPlan.value.material.profile.targetWorkspace === 'task'\n ? request.roots.taskRoot\n : request.roots.candidateRoot\n const otherFiles = [\n ...request.inputs.task.files.map((file) => beneath(request.roots.taskRoot, file.path)),\n ...(profileRoot\n ? request.profileActivation.files.map((file) => beneath(profileRoot, file.path))\n : []),\n ...(request.instruction.delivery.kind === 'utf8-file'\n ? [request.instruction.delivery.path]\n : []),\n ]\n if (\n otherFiles.some((path) =>\n reserved.some(\n (reservedPath) =>\n path === reservedPath ||\n path.startsWith(`${reservedPath}/`) ||\n reservedPath.startsWith(`${path}/`),\n ),\n )\n ) {\n throw new Error('candidate knowledge paths overlap other execution inputs')\n }\n return paths\n}\n\nfunction exactLaunch(request: AgentCandidateExecutorRequest): AgentExactProcessLaunch {\n const instruction = new TextDecoder('utf-8', { fatal: true }).decode(request.instruction.bytes)\n const base = {\n executable: request.launch.executable,\n args: request.launch.args,\n cwd: request.launch.cwd,\n env: request.launch.env,\n timeoutMs: 0,\n }\n switch (request.instruction.delivery.kind) {\n case 'argv-append':\n return { ...base, args: [...base.args, instruction] }\n case 'stdin-utf8':\n return { ...base, stdin: instruction }\n case 'utf8-file':\n return base\n }\n}\n\nasync function collectOutput(process: AgentExactProcess, maxBytes: number): Promise<Uint8Array> {\n const chunks: Buffer[] = []\n let byteLength = 0\n for await (const chunk of process.stdout()) {\n const bytes = Buffer.from(chunk, 'utf8')\n byteLength += bytes.byteLength\n if (byteLength > maxBytes) {\n let stopError: unknown\n try {\n await stopProcess(process)\n } catch (error) {\n stopError = error\n }\n throw new Error(`candidate output exceeds its ${maxBytes}-byte maximum`, {\n cause: stopError,\n })\n }\n chunks.push(bytes)\n }\n return Uint8Array.from(Buffer.concat(chunks, byteLength))\n}\n\nasync function awaitOutput(\n output: Promise<Uint8Array>,\n signal: AbortSignal,\n deadlineAtMs: number,\n): Promise<Uint8Array> {\n signal.throwIfAborted()\n const remainingMs = deadlineAtMs - Date.now()\n if (remainingMs <= 0) throw new Error('candidate output deadline expired')\n let timer: ReturnType<typeof setTimeout> | undefined\n let onAbort: (() => void) | undefined\n try {\n return await Promise.race([\n output,\n new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(signal.reason ?? new Error('candidate output cancelled'))\n signal.addEventListener('abort', onAbort, { once: true })\n timer = setTimeout(\n () => reject(new Error('candidate output deadline expired')),\n remainingMs,\n )\n }),\n ])\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort)\n if (timer) clearTimeout(timer)\n }\n}\n\nasync function stopProcess(process: AgentExactProcess): Promise<void> {\n const before = await process.status()\n if (!before.running) return\n try {\n await process.kill()\n } catch (error) {\n if ((await process.status()).running) throw error\n }\n const termination = await process.wait()\n assertTerminalStatus(await process.status(), termination)\n}\n\nfunction assertTerminalStatus(\n status: AgentExactProcessStatus,\n expected?: AgentCandidateTermination,\n): asserts status is AgentExactProcessStatus & { termination: AgentCandidateTermination } {\n if (status.running || !status.termination) {\n throw new Error('exact process returned no terminal reason after exit')\n }\n if (expected && !isDeepStrictEqual(status.termination, expected)) {\n throw new Error('exact process wait and status returned different terminal reasons')\n }\n}\n\nfunction assertExecutionEnvironment(\n environment: AgentExactProcessEnvironment,\n metadata: Record<string, unknown>,\n providerName: string,\n): void {\n if (!environment.id || environment.provider !== providerName) {\n throw new Error('exact process provider returned the wrong environment identity')\n }\n if (\n !Object.entries(metadata).every(([name, value]) =>\n isDeepStrictEqual(environment.metadata?.[name], value),\n )\n ) {\n throw new Error('exact process provider did not persist candidate execution metadata')\n }\n}\n\nfunction outputSpec(environment: AgentExactProcessEnvironment): { maxBytes: number } {\n const maxBytes = environment.metadata?.outputMaxBytes\n if (!Number.isSafeInteger(maxBytes) || Number(maxBytes) < 1) {\n throw new Error('candidate exact process output bound is unavailable')\n }\n return { maxBytes: Number(maxBytes) }\n}\n\nfunction executionKey(executionId: string, executionPlanDigest: Sha256Digest): string {\n return `${executionId}\\0${executionPlanDigest}`\n}\n\nfunction executionIdempotencyKey(executionId: string, executionPlanDigest: Sha256Digest): string {\n return `candidate-${canonicalCandidateDigest({\n kind: 'agent-candidate-execution-identity',\n executionId,\n executionPlanDigest,\n }).slice('sha256:'.length)}`\n}\n\nfunction exactImage(image: string, manifestDigest: Sha256Digest): string {\n if (isSha256Digest(image)) {\n if (image !== manifestDigest) {\n throw new Error('candidate container image conflicts with its resolved manifest')\n }\n return image\n }\n const marker = image.lastIndexOf('@')\n if (marker < 0) return `${image}@${manifestDigest}`\n if (image.slice(marker + 1) !== manifestDigest) {\n throw new Error('candidate container image conflicts with its resolved manifest')\n }\n return image\n}\n\nfunction environmentLifetimeMs(timeoutMs: number, retentionMs: number): number {\n const total = positiveInteger(timeoutMs, 'candidate execution timeout') + retentionMs\n if (!Number.isSafeInteger(total)) throw new Error('candidate environment lifetime is too large')\n return Math.ceil(total / 1_000) * 1_000\n}\n\nfunction exactResources(resources: AgentExactProcessResources): AgentExactProcessResources {\n if (!Number.isFinite(resources.cpu) || resources.cpu <= 0) {\n throw new Error('exact process CPU must be positive and finite')\n }\n return Object.freeze({\n cpu: resources.cpu,\n memoryMb: positiveInteger(resources.memoryMb, 'exact process memory'),\n diskMb: positiveInteger(resources.diskMb, 'exact process disk'),\n })\n}\n\nfunction positiveInteger(value: number, label: string): number {\n if (!Number.isSafeInteger(value) || value < 1)\n throw new Error(`${label} must be a positive integer`)\n return value\n}\n\nfunction beneath(root: string, relativePath: string): string {\n if (posix.isAbsolute(relativePath)) throw new Error('candidate input path must be relative')\n const path = posix.normalize(relativePath)\n if (path === '..' || path.startsWith('../')) {\n throw new Error('candidate input path escapes its execution root')\n }\n return posix.join(root, path)\n}\n\nfunction isSha256Digest(value: unknown): value is Sha256Digest {\n return typeof value === 'string' && /^sha256:[a-f0-9]{64}$/.test(value)\n}\n"],"mappings":"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","names":["environment"]}