@effect-agent/testing 0.1.0-beta.44 → 0.1.0-beta.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{certification.d.mts → Certification.d.mts} +7 -4
- package/dist/{certification.mjs → Certification.mjs} +30 -14
- package/dist/Certification.mjs.map +1 -0
- package/dist/{chaos.d.mts → Chaos.d.mts} +7 -5
- package/dist/{chaos.mjs → Chaos.mjs} +25 -9
- package/dist/Chaos.mjs.map +1 -0
- package/dist/{code-executor.d.mts → CodeExecutorConformance.d.mts} +6 -21
- package/dist/{code-executor.mjs → CodeExecutorConformance.mjs} +6 -340
- package/dist/CodeExecutorConformance.mjs.map +1 -0
- package/dist/CodeExecutorSubstitute.d.mts +21 -0
- package/dist/CodeExecutorSubstitute.mjs +341 -0
- package/dist/CodeExecutorSubstitute.mjs.map +1 -0
- package/dist/{docs-researcher.d.mts → DocsResearcher.d.mts} +24 -17
- package/dist/{docs-researcher.mjs → DocsResearcher.mjs} +15 -5
- package/dist/DocsResearcher.mjs.map +1 -0
- package/dist/{scripted-model-dOa_e0-n.d.mts → ScriptedModel-Dx8aW73W.d.mts} +5 -3
- package/dist/ScriptedModel.d.mts +2 -0
- package/dist/{scripted-model-C2y0ztuj.mjs → ScriptedModel.mjs} +13 -3
- package/dist/ScriptedModel.mjs.map +1 -0
- package/dist/{travel-planner.d.mts → TravelPlanner.d.mts} +37 -26
- package/dist/{travel-planner.mjs → TravelPlanner.mjs} +19 -8
- package/dist/TravelPlanner.mjs.map +1 -0
- package/dist/{deterministic-layers-CKyYxBhN.mjs → deterministic-layers-Eka0fMZq.mjs} +7 -3
- package/dist/deterministic-layers-Eka0fMZq.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +1 -1
- package/src/{certification.ts → Certification.ts} +70 -56
- package/src/{chaos.ts → Chaos.ts} +49 -33
- package/src/{code-executor-conformance.ts → CodeExecutorConformance.ts} +5 -3
- package/src/{code-executor-substitute.ts → CodeExecutorSubstitute.ts} +2 -2
- package/src/{fixtures/docs-researcher/index.ts → DocsResearcher.ts} +67 -4
- package/src/TravelPlanner.ts +244 -0
- package/src/fixtures/docs-researcher/definition.ts +5 -3
- package/src/fixtures/docs-researcher/harness.ts +10 -17
- package/src/fixtures/docs-researcher/mcp.ts +1 -1
- package/src/fixtures/travel-planner/definition.ts +2 -1
- package/src/fixtures/travel-planner/deterministic-layers.ts +4 -2
- package/src/fixtures/travel-planner/phase2.ts +2 -1
- package/src/fixtures/travel-planner/phase3.ts +4 -4
- package/src/fixtures/travel-planner/phase4.ts +8 -8
- package/src/fixtures/travel-planner/phase5.ts +14 -7
- package/src/fixtures/travel-planner/phase6.ts +6 -7
- package/src/fixtures/travel-planner/scenarios.ts +1 -1
- package/src/fixtures/travel-planner/subagents-durable.ts +11 -17
- package/src/fixtures/travel-planner/subagents.ts +6 -4
- package/src/index.ts +1 -2
- package/dist/certification.mjs.map +0 -1
- package/dist/chaos.mjs.map +0 -1
- package/dist/code-executor.mjs.map +0 -1
- package/dist/deterministic-layers-CKyYxBhN.mjs.map +0 -1
- package/dist/docs-researcher.mjs.map +0 -1
- package/dist/scripted-model-C2y0ztuj.mjs.map +0 -1
- package/dist/travel-planner.mjs.map +0 -1
- package/src/code-executor.ts +0 -3
- package/src/docs-researcher.ts +0 -2
- package/src/fixtures/travel-planner/index.ts +0 -11
- package/src/travel-planner.ts +0 -2
- /package/src/{scripted-model.ts → ScriptedModel.ts} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CodeExecutionHost, CodeExecutionLimits, CodeExecutionNamespace,
|
|
3
|
-
|
|
1
|
+
import { Deferred, Duration, Effect, Fiber, Schema } from "effect";
|
|
2
|
+
import { CodeExecutionHost, CodeExecutionLimits, CodeExecutionNamespace, CodeExecutionRequest, CodeExecutor, CodeHostCallFailure, CodeHostCallSuccess } from "@effect-agent/sandbox/CodeExecutor";
|
|
3
|
+
import { NetworkAllowlist, NetworkDisabled } from "@effect-agent/sandbox/Sandbox";
|
|
4
|
+
//#region src/CodeExecutorConformance.ts
|
|
4
5
|
/**
|
|
5
6
|
* Shared `CodeExecutor` conformance (TEST-015). Every adapter — the
|
|
6
7
|
* deterministic `unisolated` substitute and each isolated adapter — runs
|
|
@@ -225,341 +226,6 @@ const codeExecutorConformanceCases = (options) => {
|
|
|
225
226
|
];
|
|
226
227
|
};
|
|
227
228
|
//#endregion
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* The deterministic in-process executor substitute (C1 of ADR-0017). It runs
|
|
231
|
-
* the generated program on the host JavaScript engine with best-effort global
|
|
232
|
-
* shadowing only, so it self-identifies as `unisolated` and is never a
|
|
233
|
-
* security boundary (CAP-010, CAP-015). It exists to prove the public
|
|
234
|
-
* `CodeExecutor` contract and to drive deterministic capability tests.
|
|
235
|
-
*/
|
|
236
|
-
const inProcessCodeExecutorImplementation = SandboxImplementation.make({
|
|
237
|
-
isolation: "unisolated",
|
|
238
|
-
identity: "in-process-javascript"
|
|
239
|
-
});
|
|
240
|
-
const MAX_LOG_LINES = 4096;
|
|
241
|
-
const MAX_LOG_LINE_CHARACTERS = 16e3;
|
|
242
|
-
const MAX_THROWN_CHARACTERS = 4e3;
|
|
243
|
-
const utf8ByteLength = (value) => new TextEncoder().encode(value).byteLength;
|
|
244
|
-
/**
|
|
245
|
-
* Ambient globals shadowed inside the harness. Shadowing blocks the obvious
|
|
246
|
-
* identifier paths only; a determined program can still escape, which is
|
|
247
|
-
* exactly why this executor reports `unisolated` and the isolated network and
|
|
248
|
-
* CPU enforcement conformance cases run only against isolated adapters.
|
|
249
|
-
*/
|
|
250
|
-
const shadowedGlobals = [
|
|
251
|
-
"fetch",
|
|
252
|
-
"process",
|
|
253
|
-
"require",
|
|
254
|
-
"module",
|
|
255
|
-
"exports",
|
|
256
|
-
"global",
|
|
257
|
-
"globalThis",
|
|
258
|
-
"XMLHttpRequest",
|
|
259
|
-
"WebSocket",
|
|
260
|
-
"Deno",
|
|
261
|
-
"Bun"
|
|
262
|
-
];
|
|
263
|
-
var LogLimitSignal = class {
|
|
264
|
-
observed;
|
|
265
|
-
constructor(observed) {
|
|
266
|
-
this.observed = observed;
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
var EvaluationThrew = class {
|
|
270
|
-
inner;
|
|
271
|
-
constructor(inner) {
|
|
272
|
-
this.inner = inner;
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
var NotAFunction = class {
|
|
276
|
-
actual;
|
|
277
|
-
constructor(actual) {
|
|
278
|
-
this.actual = actual;
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
/**
|
|
282
|
-
* Total, defect-free rendering of untrusted values: a hostile Proxy can throw
|
|
283
|
-
* from property access, `toString`, and `Symbol.toPrimitive`, and an expected
|
|
284
|
-
* program failure must never escape the typed channel as a defect while its
|
|
285
|
-
* diagnostics are being serialized.
|
|
286
|
-
*/
|
|
287
|
-
const formatLogValue = (value) => {
|
|
288
|
-
try {
|
|
289
|
-
if (typeof value === "string") return value;
|
|
290
|
-
return JSON.stringify(value) ?? String(value);
|
|
291
|
-
} catch {
|
|
292
|
-
try {
|
|
293
|
-
return String(value);
|
|
294
|
-
} catch {
|
|
295
|
-
return "[unprintable value]";
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
const makeConsole = (capture, limits) => {
|
|
300
|
-
const write = (...values) => {
|
|
301
|
-
const joined = values.map(formatLogValue).join(" ");
|
|
302
|
-
const line = joined.length > MAX_LOG_LINE_CHARACTERS ? `${joined.slice(0, 15999)}…` : joined;
|
|
303
|
-
const bytes = utf8ByteLength(line);
|
|
304
|
-
if (capture.lines.length >= MAX_LOG_LINES || capture.bytes + bytes > limits.maxLogBytes) throw new LogLimitSignal(capture.bytes + bytes);
|
|
305
|
-
capture.lines.push(line);
|
|
306
|
-
capture.bytes += bytes;
|
|
307
|
-
};
|
|
308
|
-
return {
|
|
309
|
-
debug: write,
|
|
310
|
-
error: write,
|
|
311
|
-
info: write,
|
|
312
|
-
log: write,
|
|
313
|
-
warn: write
|
|
314
|
-
};
|
|
315
|
-
};
|
|
316
|
-
const buildNamespaceObject = (namespace, offer) => {
|
|
317
|
-
const methods = {};
|
|
318
|
-
for (const method of namespace.methods) methods[method] = (argument) => new Promise((resolve, reject) => {
|
|
319
|
-
offer({
|
|
320
|
-
namespace: namespace.name,
|
|
321
|
-
method,
|
|
322
|
-
argument,
|
|
323
|
-
resolve,
|
|
324
|
-
reject
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
return methods;
|
|
328
|
-
};
|
|
329
|
-
const boundedText = (value) => {
|
|
330
|
-
try {
|
|
331
|
-
return (value instanceof Error ? `${value.name}: ${value.message}` : formatLogValue(value)).slice(0, MAX_THROWN_CHARACTERS);
|
|
332
|
-
} catch {
|
|
333
|
-
return "[unserializable thrown value]";
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
/** Schema decoding of hostile values may itself throw through trap getters. */
|
|
337
|
-
const safeDecodeJson = (value) => {
|
|
338
|
-
try {
|
|
339
|
-
return Schema.decodeUnknownOption(Schema.Json)(value);
|
|
340
|
-
} catch {
|
|
341
|
-
return Option.none();
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
const boundedThrown = (value) => {
|
|
345
|
-
const decoded = safeDecodeJson(value);
|
|
346
|
-
if (Option.isSome(decoded)) try {
|
|
347
|
-
const encoded = JSON.stringify(decoded.value);
|
|
348
|
-
if (encoded !== void 0 && encoded.length <= MAX_THROWN_CHARACTERS) return decoded.value;
|
|
349
|
-
} catch {}
|
|
350
|
-
return boundedText(value);
|
|
351
|
-
};
|
|
352
|
-
const encodedJsonByteLength = (value) => {
|
|
353
|
-
try {
|
|
354
|
-
const encoded = JSON.stringify(value);
|
|
355
|
-
return encoded === void 0 ? void 0 : utf8ByteLength(encoded);
|
|
356
|
-
} catch {
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
/** Host outcomes are protocol input; a hostile value must not defect mid-decode. */
|
|
361
|
-
const decodeHostOutcome = (value) => {
|
|
362
|
-
try {
|
|
363
|
-
return Schema.decodeUnknownOption(CodeHostCallResult)(value);
|
|
364
|
-
} catch {
|
|
365
|
-
return Option.none();
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
const validateRequest = (request) => Effect.gen(function* () {
|
|
369
|
-
if (request.network._tag !== "NetworkDisabled") return yield* CodeExecutorUnsupportedError.make({
|
|
370
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
371
|
-
feature: "network",
|
|
372
|
-
message: "The unisolated in-process executor cannot enforce an egress allowlist; only NetworkDisabled is accepted, and even that is shadowed rather than enforced"
|
|
373
|
-
});
|
|
374
|
-
if (request.limits.cpuMillis !== void 0) return yield* CodeExecutorUnsupportedError.make({
|
|
375
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
376
|
-
feature: "cpu-limit",
|
|
377
|
-
message: "The unisolated in-process executor shares the host engine and cannot enforce a CPU limit"
|
|
378
|
-
});
|
|
379
|
-
const reservedNames = /* @__PURE__ */ new Set([...shadowedGlobals, "console"]);
|
|
380
|
-
const seen = /* @__PURE__ */ new Set();
|
|
381
|
-
for (const namespace of request.namespaces) {
|
|
382
|
-
if (reservedNames.has(namespace.name) || seen.has(namespace.name)) return yield* CodeExecutorUnsupportedError.make({
|
|
383
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
384
|
-
feature: "namespaces",
|
|
385
|
-
message: `Namespace ${namespace.name} collides with a harness binding or another namespace`
|
|
386
|
-
});
|
|
387
|
-
seen.add(namespace.name);
|
|
388
|
-
}
|
|
389
|
-
const sourceBytes = utf8ByteLength(request.source);
|
|
390
|
-
if (sourceBytes > request.limits.maxSourceBytes) return yield* CodeSourceError.make({
|
|
391
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
392
|
-
reason: "oversized",
|
|
393
|
-
message: `Source is ${sourceBytes} bytes; the request allows ${request.limits.maxSourceBytes}`
|
|
394
|
-
});
|
|
395
|
-
});
|
|
396
|
-
const serveHostCalls = (host, queue, limits, capture, counter) => Effect.gen(function* () {
|
|
397
|
-
while (true) {
|
|
398
|
-
const pending = yield* Queue.take(queue);
|
|
399
|
-
counter.calls += 1;
|
|
400
|
-
if (counter.calls > limits.maxHostCalls) return yield* CodeHostCallLimitError.make({
|
|
401
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
402
|
-
limit: limits.maxHostCalls,
|
|
403
|
-
logs: [...capture.lines]
|
|
404
|
-
});
|
|
405
|
-
const argument = safeDecodeJson(pending.argument);
|
|
406
|
-
if (Option.isNone(argument)) {
|
|
407
|
-
pending.reject(/* @__PURE__ */ new TypeError("host call arguments must be JSON values"));
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
const argumentBytes = encodedJsonByteLength(argument.value);
|
|
411
|
-
if (argumentBytes === void 0 || argumentBytes > limits.maxHostCallArgumentBytes) return yield* CodeOutputLimitError.make({
|
|
412
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
413
|
-
surface: "host-call-argument",
|
|
414
|
-
limit: limits.maxHostCallArgumentBytes,
|
|
415
|
-
observed: argumentBytes ?? 0,
|
|
416
|
-
logs: [...capture.lines]
|
|
417
|
-
});
|
|
418
|
-
const rawOutcome = yield* host.call(CodeHostCall.make({
|
|
419
|
-
namespace: pending.namespace,
|
|
420
|
-
method: pending.method,
|
|
421
|
-
argument: argument.value
|
|
422
|
-
}));
|
|
423
|
-
const outcome = decodeHostOutcome(rawOutcome);
|
|
424
|
-
if (Option.isNone(outcome)) return yield* CodeExecutionProtocolError.make({
|
|
425
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
426
|
-
message: "The execution host returned a value outside the CodeHostCallResult schema"
|
|
427
|
-
});
|
|
428
|
-
if (outcome.value._tag === "CodeHostCallFailure") {
|
|
429
|
-
pending.reject(outcome.value.error);
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
const resultBytes = encodedJsonByteLength(outcome.value.value);
|
|
433
|
-
if (resultBytes === void 0 || resultBytes > limits.maxHostCallResultBytes) return yield* CodeOutputLimitError.make({
|
|
434
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
435
|
-
surface: "host-call-result",
|
|
436
|
-
limit: limits.maxHostCallResultBytes,
|
|
437
|
-
observed: resultBytes ?? 0,
|
|
438
|
-
logs: [...capture.lines]
|
|
439
|
-
});
|
|
440
|
-
pending.resolve(outcome.value.value);
|
|
441
|
-
}
|
|
442
|
-
});
|
|
443
|
-
const classifyProgramFailure = (thrown, limits, capture) => {
|
|
444
|
-
const inner = thrown instanceof EvaluationThrew ? thrown.inner : thrown;
|
|
445
|
-
if (inner instanceof LogLimitSignal) return CodeOutputLimitError.make({
|
|
446
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
447
|
-
surface: "logs",
|
|
448
|
-
limit: limits.maxLogBytes,
|
|
449
|
-
observed: inner.observed,
|
|
450
|
-
logs: [...capture.lines]
|
|
451
|
-
});
|
|
452
|
-
if (inner instanceof NotAFunction) return CodeSourceError.make({
|
|
453
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
454
|
-
reason: "not-a-function",
|
|
455
|
-
message: `The source expression evaluated to ${inner.actual}; it must evaluate to one async function`
|
|
456
|
-
});
|
|
457
|
-
const reason = thrown instanceof EvaluationThrew || inner instanceof Error ? "threw" : "rejected";
|
|
458
|
-
return CodeProgramFailedError.make({
|
|
459
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
460
|
-
reason,
|
|
461
|
-
thrown: boundedThrown(inner),
|
|
462
|
-
message: boundedText(inner),
|
|
463
|
-
logs: [...capture.lines]
|
|
464
|
-
});
|
|
465
|
-
};
|
|
466
|
-
const executeInProcess = Effect.fn("InProcessCodeExecutor.execute")(function* (request) {
|
|
467
|
-
yield* validateRequest(request);
|
|
468
|
-
const host = yield* CodeExecutionHost;
|
|
469
|
-
const capture = {
|
|
470
|
-
lines: [],
|
|
471
|
-
bytes: 0
|
|
472
|
-
};
|
|
473
|
-
const counter = { calls: 0 };
|
|
474
|
-
const queue = yield* Queue.unbounded();
|
|
475
|
-
const factory = yield* Effect.try({
|
|
476
|
-
try: () => new Function(...shadowedGlobals, "console", ...request.namespaces.map((namespace) => namespace.name), `"use strict";\nreturn (\n${request.source}\n);`),
|
|
477
|
-
catch: (cause) => CodeSourceError.make({
|
|
478
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
479
|
-
reason: "invalid",
|
|
480
|
-
message: boundedText(cause)
|
|
481
|
-
})
|
|
482
|
-
});
|
|
483
|
-
const harnessConsole = makeConsole(capture, request.limits);
|
|
484
|
-
let issuedHostCalls = 0;
|
|
485
|
-
const namespaceObjects = request.namespaces.map((namespace) => buildNamespaceObject(namespace, (pending) => {
|
|
486
|
-
issuedHostCalls += 1;
|
|
487
|
-
if (issuedHostCalls > request.limits.maxHostCalls + 1) {
|
|
488
|
-
pending.reject(/* @__PURE__ */ new Error(`host-call limit of ${request.limits.maxHostCalls} exceeded`));
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
Queue.offerUnsafe(queue, pending);
|
|
492
|
-
}));
|
|
493
|
-
const server = yield* serveHostCalls(host, queue, request.limits, capture, counter).pipe(Effect.forkScoped);
|
|
494
|
-
const program = Effect.tryPromise({
|
|
495
|
-
try: async () => {
|
|
496
|
-
let candidate;
|
|
497
|
-
try {
|
|
498
|
-
candidate = factory(...shadowedGlobals.map(() => void 0), harnessConsole, ...namespaceObjects);
|
|
499
|
-
} catch (cause) {
|
|
500
|
-
throw new EvaluationThrew(cause);
|
|
501
|
-
}
|
|
502
|
-
if (typeof candidate !== "function") throw new EvaluationThrew(new NotAFunction(typeof candidate));
|
|
503
|
-
let outcome;
|
|
504
|
-
try {
|
|
505
|
-
outcome = candidate();
|
|
506
|
-
} catch (cause) {
|
|
507
|
-
throw new EvaluationThrew(cause);
|
|
508
|
-
}
|
|
509
|
-
return await Promise.resolve(outcome);
|
|
510
|
-
},
|
|
511
|
-
catch: (thrown) => classifyProgramFailure(thrown, request.limits, capture)
|
|
512
|
-
});
|
|
513
|
-
const startedAt = yield* Clock.currentTimeMillis;
|
|
514
|
-
const returned = yield* Effect.raceFirst(program, Fiber.join(server)).pipe(Effect.timeoutOrElse({
|
|
515
|
-
duration: request.limits.maxWallTime,
|
|
516
|
-
orElse: () => CodeExecutionTimeoutError.make({
|
|
517
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
518
|
-
kind: "wall-clock",
|
|
519
|
-
maxWallTime: request.limits.maxWallTime,
|
|
520
|
-
logs: [...capture.lines]
|
|
521
|
-
})
|
|
522
|
-
}), Effect.ensuring(Fiber.interrupt(server)));
|
|
523
|
-
const finishedAt = yield* Clock.currentTimeMillis;
|
|
524
|
-
if (issuedHostCalls > request.limits.maxHostCalls) return yield* CodeHostCallLimitError.make({
|
|
525
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
526
|
-
limit: request.limits.maxHostCalls,
|
|
527
|
-
logs: [...capture.lines]
|
|
528
|
-
});
|
|
529
|
-
const value = yield* Schema.decodeUnknownEffect(Schema.Json)(returned).pipe(Effect.mapError(() => CodeProgramFailedError.make({
|
|
530
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
531
|
-
reason: "non-json-result",
|
|
532
|
-
thrown: null,
|
|
533
|
-
message: "The program must return a JSON value",
|
|
534
|
-
logs: [...capture.lines]
|
|
535
|
-
})));
|
|
536
|
-
const resultBytes = encodedJsonByteLength(value);
|
|
537
|
-
if (resultBytes === void 0 || resultBytes > request.limits.maxResultBytes) return yield* CodeOutputLimitError.make({
|
|
538
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
539
|
-
surface: "result",
|
|
540
|
-
limit: request.limits.maxResultBytes,
|
|
541
|
-
observed: resultBytes ?? 0,
|
|
542
|
-
logs: [...capture.lines]
|
|
543
|
-
});
|
|
544
|
-
return CodeExecutionResult.make({
|
|
545
|
-
implementation: inProcessCodeExecutorImplementation,
|
|
546
|
-
value,
|
|
547
|
-
logs: [...capture.lines],
|
|
548
|
-
resourceUse: CodeExecutionResourceUse.make({
|
|
549
|
-
wallTime: Duration.millis(Math.max(0, finishedAt - startedAt)),
|
|
550
|
-
hostCalls: counter.calls,
|
|
551
|
-
logBytes: capture.bytes,
|
|
552
|
-
resultBytes
|
|
553
|
-
})
|
|
554
|
-
});
|
|
555
|
-
});
|
|
556
|
-
/**
|
|
557
|
-
* Layer providing the unisolated in-process `CodeExecutor` substitute. The
|
|
558
|
-
* per-pass `CodeExecutionHost` stays in the caller's requirement channel, the
|
|
559
|
-
* same as every real adapter.
|
|
560
|
-
*/
|
|
561
|
-
const inProcessCodeExecutorLayer = Layer.succeed(CodeExecutor)(CodeExecutor.of({ execute: executeInProcess }));
|
|
562
|
-
//#endregion
|
|
563
|
-
export { CodeExecutorConformanceViolation, codeExecutorConformanceCases, inProcessCodeExecutorImplementation, inProcessCodeExecutorLayer };
|
|
229
|
+
export { CodeExecutorConformanceViolation, codeExecutorConformanceCases };
|
|
564
230
|
|
|
565
|
-
//# sourceMappingURL=
|
|
231
|
+
//# sourceMappingURL=CodeExecutorConformance.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeExecutorConformance.mjs","names":[],"sources":["../src/CodeExecutorConformance.ts"],"sourcesContent":["import {\n CodeExecutionHost,\n CodeExecutionLimits,\n CodeExecutionNamespace,\n CodeExecutionRequest,\n CodeExecutor,\n CodeHostCallFailure,\n CodeHostCallSuccess,\n type CodeExecutionError,\n type CodeExecutionResult,\n type CodeHostCall,\n type CodeHostCallResult,\n} from \"@effect-agent/sandbox/CodeExecutor\";\nimport {\n NetworkAllowlist,\n NetworkDisabled,\n type SandboxImplementation,\n} from \"@effect-agent/sandbox/Sandbox\";\nimport { Deferred, Duration, Effect, Fiber, Schema } from \"effect\";\n\n/**\n * Shared `CodeExecutor` conformance (TEST-015). Every adapter — the\n * deterministic `unisolated` substitute and each isolated adapter — runs\n * `codeExecutorConformanceCases` verbatim. Enforcement cases that only genuine\n * isolation can prove (ambient network denial, synchronous CPU runaway\n * termination) are NOT here; they belong to isolated adapters only\n * (testing spec §8.1).\n *\n * Cases assume the live `Clock` (the wall-clock case uses a short real\n * deadline) and take one fresh executor pass per case, so a suite may share\n * one executor Layer across cases.\n */\nexport class CodeExecutorConformanceViolation extends Schema.TaggedError<CodeExecutorConformanceViolation>()(\n \"CodeExecutorConformanceViolation\",\n {\n caseName: Schema.String,\n message: Schema.String,\n },\n) {}\n\nexport interface CodeExecutorConformanceCase {\n readonly name: string;\n readonly run: Effect.Effect<void, CodeExecutorConformanceViolation, CodeExecutor>;\n}\n\nexport interface CodeExecutorConformanceOptions {\n /** The posture the adapter under test must stamp on results and errors. */\n readonly implementation: SandboxImplementation;\n}\n\nconst baseLimits = CodeExecutionLimits.make({\n maxSourceBytes: 64 * 1024,\n maxWallTime: Duration.seconds(10),\n maxLogBytes: 16 * 1024,\n maxResultBytes: 64 * 1024,\n maxHostCalls: 8,\n maxHostCallArgumentBytes: 16 * 1024,\n maxHostCallResultBytes: 32 * 1024,\n});\n\nconst warehouseNamespace = CodeExecutionNamespace.make({\n name: \"warehouse\",\n methods: [\"query\", \"count\"],\n});\n\nconst makeRequest = (\n source: string,\n overrides?: {\n readonly limits?: CodeExecutionLimits;\n readonly namespaces?: ReadonlyArray<CodeExecutionNamespace>;\n readonly network?: CodeExecutionRequest[\"network\"];\n },\n): CodeExecutionRequest =>\n CodeExecutionRequest.make({\n language: \"javascript\",\n source,\n namespaces: overrides?.namespaces ?? [],\n network: overrides?.network ?? NetworkDisabled.make(),\n limits: overrides?.limits ?? baseLimits,\n });\n\nconst unusedHost: CodeExecutionHost[\"Service\"] = {\n call: () =>\n Effect.die(\n new Error(\"this conformance case expected no host call to reach the CodeExecutionHost\"),\n ),\n};\n\nconst respondingHost = (\n respond: (call: CodeHostCall) => CodeHostCallResult,\n): { readonly host: CodeExecutionHost[\"Service\"]; readonly calls: Array<CodeHostCall> } => {\n const calls: Array<CodeHostCall> = [];\n\n return {\n calls,\n host: {\n call: (call) =>\n Effect.sync(() => {\n calls.push(call);\n\n return respond(call);\n }),\n },\n };\n};\n\nconst runPass = (\n request: CodeExecutionRequest,\n host: CodeExecutionHost[\"Service\"],\n): Effect.Effect<CodeExecutionResult, CodeExecutionError, CodeExecutor> =>\n Effect.gen(function* () {\n const executor = yield* CodeExecutor;\n\n return yield* executor\n .execute(request)\n .pipe(Effect.provideService(CodeExecutionHost, CodeExecutionHost.of(host)));\n }).pipe(Effect.scoped);\n\nconst violation = (caseName: string, message: string) =>\n CodeExecutorConformanceViolation.make({ caseName, message });\n\nconst preview = (value: unknown): string => {\n try {\n return JSON.stringify(value)?.slice(0, 200) ?? String(value).slice(0, 200);\n } catch {\n return String(value).slice(0, 200);\n }\n};\n\nconst expectSuccess = (\n caseName: string,\n request: CodeExecutionRequest,\n host: CodeExecutionHost[\"Service\"],\n check: (result: CodeExecutionResult) => string | undefined,\n): Effect.Effect<void, CodeExecutorConformanceViolation, CodeExecutor> =>\n runPass(request, host).pipe(\n Effect.mapError((error) =>\n violation(caseName, `expected success, got ${error._tag}: ${preview(error)}`),\n ),\n Effect.flatMap((result) => {\n const complaint = check(result);\n\n return complaint === undefined ? Effect.void : Effect.fail(violation(caseName, complaint));\n }),\n );\n\nconst expectFailure = (\n caseName: string,\n request: CodeExecutionRequest,\n host: CodeExecutionHost[\"Service\"],\n tag: CodeExecutionError[\"_tag\"],\n check?: (error: CodeExecutionError) => string | undefined,\n): Effect.Effect<void, CodeExecutorConformanceViolation, CodeExecutor> =>\n runPass(request, host).pipe(\n Effect.flip,\n Effect.mapError((result) =>\n violation(caseName, `expected ${tag}, but the pass succeeded with ${preview(result.value)}`),\n ),\n Effect.flatMap((error) => {\n if (error._tag !== tag) {\n return Effect.fail(\n violation(caseName, `expected ${tag}, got ${error._tag}: ${preview(error)}`),\n );\n }\n const complaint = check?.(error);\n\n return complaint === undefined ? Effect.void : Effect.fail(violation(caseName, complaint));\n }),\n );\n\nexport const codeExecutorConformanceCases = (\n options: CodeExecutorConformanceOptions,\n): ReadonlyArray<CodeExecutorConformanceCase> => {\n const posture = options.implementation;\n\n return [\n {\n name: \"TEST-015 executes bounded JSON computation and returns the program value\",\n run: expectSuccess(\n \"TEST-015 executes bounded JSON computation and returns the program value\",\n makeRequest(\n \"async () => { const xs = [1, 2, 3].map((n) => n * 2); return { xs, sum: xs.reduce((a, b) => a + b, 0) }; }\",\n ),\n unusedHost,\n (result) =>\n JSON.stringify(result.value) === JSON.stringify({ xs: [2, 4, 6], sum: 12 })\n ? undefined\n : `unexpected program value ${preview(result.value)}`,\n ),\n },\n {\n name: \"CAP-015 reports its isolation posture honestly in results and errors\",\n run: Effect.gen(function* () {\n const caseName = \"CAP-015 reports its isolation posture honestly in results and errors\";\n\n const result = yield* runPass(makeRequest(\"async () => 1\"), unusedHost).pipe(\n Effect.mapError((error) => violation(caseName, `expected success, got ${error._tag}`)),\n );\n\n if (\n result.implementation.isolation !== posture.isolation ||\n result.implementation.identity !== posture.identity\n ) {\n return yield* violation(\n caseName,\n `result posture ${preview(result.implementation)} does not match the declared ${preview(posture)}`,\n );\n }\n\n const error = yield* runPass(makeRequest(\"async () => {\"), unusedHost).pipe(\n Effect.flip,\n Effect.mapError(() => violation(caseName, \"expected the invalid-source pass to fail\")),\n );\n\n // Every expected execution failure carries the posture; an adapter\n // omitting the field must fail this case, not slip past a probe.\n if (\n error.implementation === undefined ||\n error.implementation.isolation !== posture.isolation ||\n error.implementation.identity !== posture.identity\n ) {\n return yield* violation(\n caseName,\n `error posture ${preview(error.implementation)} does not match the declared ${preview(posture)}`,\n );\n }\n }),\n },\n {\n name: \"TEST-015 routes host calls through the CodeExecutionHost in program order\",\n run: Effect.gen(function* () {\n const caseName =\n \"TEST-015 routes host calls through the CodeExecutionHost in program order\";\n\n const { host, calls } = respondingHost((call) =>\n call.method === \"query\"\n ? CodeHostCallSuccess.make({ value: { rows: [1, 2, 3] } })\n : CodeHostCallSuccess.make({ value: 3 }),\n );\n\n const result = yield* runPass(\n makeRequest(\n \"async () => { const q = await warehouse.query({ sql: 'select' }); const c = await warehouse.count({ table: 't' }); return { rows: q.rows, count: c }; }\",\n { namespaces: [warehouseNamespace] },\n ),\n host,\n ).pipe(\n Effect.mapError((error) =>\n violation(caseName, `expected success, got ${error._tag}: ${preview(error)}`),\n ),\n );\n\n if (JSON.stringify(result.value) !== JSON.stringify({ rows: [1, 2, 3], count: 3 })) {\n return yield* violation(caseName, `unexpected value ${preview(result.value)}`);\n }\n const observed = calls.map((call) => `${call.namespace}.${call.method}`);\n\n if (JSON.stringify(observed) !== JSON.stringify([\"warehouse.query\", \"warehouse.count\"])) {\n return yield* violation(caseName, `unexpected host call order ${preview(observed)}`);\n }\n if (result.resourceUse.hostCalls !== 2) {\n return yield* violation(\n caseName,\n `expected 2 accounted host calls, got ${result.resourceUse.hostCalls}`,\n );\n }\n }),\n },\n {\n name: \"TEST-015 a caught failed host call lets the program branch on the envelope\",\n run: expectSuccess(\n \"TEST-015 a caught failed host call lets the program branch on the envelope\",\n makeRequest(\n \"async () => { try { await warehouse.query({ sql: 'x' }); return 'unreachable'; } catch (envelope) { return { caught: envelope }; } }\",\n { namespaces: [warehouseNamespace] },\n ),\n respondingHost(() =>\n CodeHostCallFailure.make({ error: { _tag: \"ToolInputError\", message: \"bad input\" } }),\n ).host,\n (result) =>\n JSON.stringify(result.value) ===\n JSON.stringify({ caught: { _tag: \"ToolInputError\", message: \"bad input\" } })\n ? undefined\n : `the envelope did not round-trip: ${preview(result.value)}`,\n ),\n },\n {\n name: \"TEST-015 an uncaught failed host call fails the program with the envelope\",\n run: expectFailure(\n \"TEST-015 an uncaught failed host call fails the program with the envelope\",\n makeRequest(\"async () => warehouse.query({ sql: 'x' })\", {\n namespaces: [warehouseNamespace],\n }),\n respondingHost(() =>\n CodeHostCallFailure.make({ error: { _tag: \"PolicyDenied\", message: \"denied\" } }),\n ).host,\n \"CodeProgramFailedError\",\n (error) =>\n error._tag === \"CodeProgramFailedError\" &&\n error.reason === \"rejected\" &&\n JSON.stringify(error.thrown) ===\n JSON.stringify({ _tag: \"PolicyDenied\", message: \"denied\" })\n ? undefined\n : `unexpected failure detail ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 fails typed on syntactically invalid source\",\n run: expectFailure(\n \"TEST-015 fails typed on syntactically invalid source\",\n makeRequest(\"async () => {\"),\n unusedHost,\n \"CodeSourceError\",\n (error) =>\n error._tag === \"CodeSourceError\" && error.reason === \"invalid\"\n ? undefined\n : `expected reason invalid, got ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 fails typed when the expression is not one async function\",\n run: expectFailure(\n \"TEST-015 fails typed when the expression is not one async function\",\n makeRequest(\"1 + 1\"),\n unusedHost,\n \"CodeSourceError\",\n (error) =>\n error._tag === \"CodeSourceError\" && error.reason === \"not-a-function\"\n ? undefined\n : `expected reason not-a-function, got ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 fails typed on source larger than the declared byte limit\",\n run: expectFailure(\n \"TEST-015 fails typed on source larger than the declared byte limit\",\n makeRequest(`async () => \"${\"x\".repeat(2_000)}\"`, {\n limits: CodeExecutionLimits.make({ ...baseLimits, maxSourceBytes: 256 }),\n }),\n unusedHost,\n \"CodeSourceError\",\n (error) =>\n error._tag === \"CodeSourceError\" && error.reason === \"oversized\"\n ? undefined\n : `expected reason oversized, got ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 terminates a never-settling program at the wall-clock deadline\",\n run: expectFailure(\n \"TEST-015 terminates a never-settling program at the wall-clock deadline\",\n makeRequest(\"async () => { await new Promise(() => {}); return 1; }\", {\n limits: CodeExecutionLimits.make({ ...baseLimits, maxWallTime: Duration.millis(250) }),\n }),\n unusedHost,\n \"CodeExecutionTimeoutError\",\n ),\n },\n {\n name: \"TEST-015 fails typed when console output exceeds its byte budget\",\n run: expectFailure(\n \"TEST-015 fails typed when console output exceeds its byte budget\",\n makeRequest(\n \"async () => { for (let i = 0; i < 64; i += 1) { console.log('x'.repeat(256)); } return 1; }\",\n { limits: CodeExecutionLimits.make({ ...baseLimits, maxLogBytes: 2_048 }) },\n ),\n unusedHost,\n \"CodeOutputLimitError\",\n (error) =>\n error._tag === \"CodeOutputLimitError\" && error.surface === \"logs\"\n ? undefined\n : `expected surface logs, got ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 fails typed when the final result exceeds its byte budget\",\n run: expectFailure(\n \"TEST-015 fails typed when the final result exceeds its byte budget\",\n makeRequest(\"async () => 'y'.repeat(4096)\", {\n limits: CodeExecutionLimits.make({ ...baseLimits, maxResultBytes: 1_024 }),\n }),\n unusedHost,\n \"CodeOutputLimitError\",\n (error) =>\n error._tag === \"CodeOutputLimitError\" && error.surface === \"result\"\n ? undefined\n : `expected surface result, got ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 fails typed when host calls exceed the executor cap\",\n run: Effect.gen(function* () {\n const caseName = \"TEST-015 fails typed when host calls exceed the executor cap\";\n const { host, calls } = respondingHost(() => CodeHostCallSuccess.make({ value: null }));\n\n yield* expectFailure(\n caseName,\n makeRequest(\n \"async () => { await warehouse.query({}); await warehouse.query({}); await warehouse.query({}); return 1; }\",\n {\n namespaces: [warehouseNamespace],\n limits: CodeExecutionLimits.make({ ...baseLimits, maxHostCalls: 2 }),\n },\n ),\n host,\n \"CodeHostCallLimitError\",\n );\n // The cap is enforced before dispatch: the over-limit call must never\n // have reached the host, or an unauthorized side effect already ran.\n if (calls.length !== 2) {\n return yield* violation(\n caseName,\n `expected exactly 2 dispatched host calls under a cap of 2, observed ${calls.length}`,\n );\n }\n }),\n },\n {\n name: \"TEST-015 fails typed on a host outcome outside the protocol schema\",\n run: expectFailure(\n \"TEST-015 fails typed on a host outcome outside the protocol schema\",\n makeRequest(\"async () => warehouse.query({})\", { namespaces: [warehouseNamespace] }),\n {\n // Deliberately violate the compile-time host contract to verify that an adapter\n // independently decodes the runtime protocol boundary.\n call: () => Effect.succeed({ bogus: true } as unknown as CodeHostCallResult),\n },\n \"CodeExecutionProtocolError\",\n ),\n },\n {\n name: \"TEST-015 surfaces an uncaught program throw with its bounded log capture\",\n run: expectFailure(\n \"TEST-015 surfaces an uncaught program throw with its bounded log capture\",\n makeRequest(\n \"async () => { console.log('before the failure'); throw new Error('deliberate'); }\",\n ),\n unusedHost,\n \"CodeProgramFailedError\",\n (error) =>\n error._tag === \"CodeProgramFailedError\" &&\n error.reason === \"threw\" &&\n error.logs.some((line) => line.includes(\"before the failure\"))\n ? undefined\n : `expected a threw failure carrying the log capture, got ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 fails typed when the program returns a non-JSON value\",\n run: expectFailure(\n \"TEST-015 fails typed when the program returns a non-JSON value\",\n makeRequest(\"async () => (() => 1)\"),\n unusedHost,\n \"CodeProgramFailedError\",\n (error) =>\n error._tag === \"CodeProgramFailedError\" && error.reason === \"non-json-result\"\n ? undefined\n : `expected reason non-json-result, got ${preview(error)}`,\n ),\n },\n {\n name: \"CAP-015 rejects a network allowlist it cannot enforce with a typed unsupported error\",\n run: expectFailure(\n \"CAP-015 rejects a network allowlist it cannot enforce with a typed unsupported error\",\n makeRequest(\"async () => 1\", {\n network: NetworkAllowlist.make({ domains: [\"example.com\"], ports: [443] }),\n }),\n unusedHost,\n \"CodeExecutorUnsupportedError\",\n (error) =>\n error._tag === \"CodeExecutorUnsupportedError\" && error.feature === \"network\"\n ? undefined\n : `expected feature network, got ${preview(error)}`,\n ),\n },\n {\n name: \"TEST-015 interruption reaches in-flight host calls and pass teardown\",\n run: Effect.gen(function* () {\n const caseName = \"TEST-015 interruption reaches in-flight host calls and pass teardown\";\n const started = yield* Deferred.make<void>();\n const witness = { hostCallInterrupted: false };\n\n const host: CodeExecutionHost[\"Service\"] = {\n call: () =>\n Deferred.succeed(started, undefined).pipe(\n Effect.andThen(Effect.never),\n Effect.ensuring(\n Effect.sync(() => {\n witness.hostCallInterrupted = true;\n }),\n ),\n ),\n };\n\n const fiber = yield* runPass(\n makeRequest(\"async () => warehouse.query({})\", { namespaces: [warehouseNamespace] }),\n host,\n ).pipe(Effect.forkChild);\n\n // Guard against a broken adapter that settles the pass without ever\n // reaching the host: the case must report a violation, not hang.\n const winner = yield* Effect.raceFirst(\n Deferred.await(started).pipe(Effect.as(\"started\" as const)),\n Fiber.join(fiber).pipe(Effect.exit, Effect.as(\"exited\" as const)),\n );\n\n if (winner === \"exited\") {\n return yield* violation(\n caseName,\n \"the pass settled before any host call reached the CodeExecutionHost\",\n );\n }\n yield* Fiber.interrupt(fiber);\n if (!witness.hostCallInterrupted) {\n return yield* violation(\n caseName,\n \"interrupting the pass did not interrupt the in-flight host call\",\n );\n }\n }),\n },\n ];\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { CodeExecutor } from "@effect-agent/sandbox/CodeExecutor";
|
|
3
|
+
import { SandboxImplementation } from "@effect-agent/sandbox/Sandbox";
|
|
4
|
+
//#region src/CodeExecutorSubstitute.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The deterministic in-process executor substitute (C1 of ADR-0017). It runs
|
|
7
|
+
* the generated program on the host JavaScript engine with best-effort global
|
|
8
|
+
* shadowing only, so it self-identifies as `unisolated` and is never a
|
|
9
|
+
* security boundary (CAP-010, CAP-015). It exists to prove the public
|
|
10
|
+
* `CodeExecutor` contract and to drive deterministic capability tests.
|
|
11
|
+
*/
|
|
12
|
+
declare const inProcessCodeExecutorImplementation: SandboxImplementation;
|
|
13
|
+
/**
|
|
14
|
+
* Layer providing the unisolated in-process `CodeExecutor` substitute. The
|
|
15
|
+
* per-pass `CodeExecutionHost` stays in the caller's requirement channel, the
|
|
16
|
+
* same as every real adapter.
|
|
17
|
+
*/
|
|
18
|
+
declare const inProcessCodeExecutorLayer: Layer.Layer<CodeExecutor>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { inProcessCodeExecutorImplementation, inProcessCodeExecutorLayer };
|
|
21
|
+
//# sourceMappingURL=CodeExecutorSubstitute.d.mts.map
|