@attest-ai/core 1.0.0-rc.4 → 1.0.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.
package/dist/esm/index.js CHANGED
@@ -219,8 +219,8 @@ function extractId(response) {
219
219
  }
220
220
 
221
221
  // src/version.ts
222
- var VERSION = "1.0.0-rc.4";
223
- var ENGINE_VERSION = "1.0.0-rc.4";
222
+ var VERSION = "1.0.0";
223
+ var ENGINE_VERSION = "1.0.0";
224
224
 
225
225
  // src/engine-manager.ts
226
226
  import { spawn, spawnSync } from "child_process";
@@ -288,7 +288,7 @@ function httpsGet(url, redirectCount = 0) {
288
288
  new Error(`Too many redirects (>${MAX_REDIRECTS}) following ${url}`)
289
289
  );
290
290
  }
291
- return new Promise((resolve4, reject) => {
291
+ return new Promise((resolve5, reject) => {
292
292
  const client = url.startsWith("https:") ? https : http;
293
293
  client.get(url, (res) => {
294
294
  const status = res.statusCode ?? 0;
@@ -299,7 +299,7 @@ function httpsGet(url, redirectCount = 0) {
299
299
  return;
300
300
  }
301
301
  res.resume();
302
- resolve4(httpsGet(location, redirectCount + 1));
302
+ resolve5(httpsGet(location, redirectCount + 1));
303
303
  return;
304
304
  }
305
305
  if (status < 200 || status >= 300) {
@@ -309,7 +309,7 @@ function httpsGet(url, redirectCount = 0) {
309
309
  }
310
310
  const chunks = [];
311
311
  res.on("data", (chunk) => chunks.push(chunk));
312
- res.on("end", () => resolve4(Buffer.concat(chunks)));
312
+ res.on("end", () => resolve5(Buffer.concat(chunks)));
313
313
  res.on("error", reject);
314
314
  }).on("error", reject);
315
315
  });
@@ -536,11 +536,11 @@ var EngineManager = class {
536
536
  }
537
537
  this.requestId += 1;
538
538
  const requestStr = encodeRequest(this.requestId, method, params);
539
- return new Promise((resolve4, reject) => {
539
+ return new Promise((resolve5, reject) => {
540
540
  const onLine = (line) => {
541
541
  try {
542
542
  const response = decodeResponse(line);
543
- resolve4(extractResult(response));
543
+ resolve5(extractResult(response));
544
544
  } catch (err) {
545
545
  reject(err);
546
546
  }
@@ -907,12 +907,12 @@ var AttestClient = class {
907
907
  throw new Error("Engine process not started.");
908
908
  }
909
909
  let capturedReqId;
910
- const requestPromise = new Promise((resolve4, reject) => {
910
+ const requestPromise = new Promise((resolve5, reject) => {
911
911
  this.writeChain = this.writeChain.then(() => {
912
912
  this.requestId += 1;
913
913
  const reqId = this.requestId;
914
914
  capturedReqId = reqId;
915
- this.pending.set(reqId, { resolve: resolve4, reject });
915
+ this.pending.set(reqId, { resolve: resolve5, reject });
916
916
  const requestStr = encodeRequest(reqId, method, params);
917
917
  cp.stdin.write(requestStr, (err) => {
918
918
  if (err) {
@@ -1027,6 +1027,26 @@ function requireSimulationCapability(init) {
1027
1027
 
1028
1028
  // src/trace.ts
1029
1029
  import { randomUUID } from "crypto";
1030
+
1031
+ // src/simulation/context.ts
1032
+ import { AsyncLocalStorage } from "async_hooks";
1033
+ var activeMockRegistry = new AsyncLocalStorage();
1034
+ function createRng(seed) {
1035
+ if (seed === void 0) return Math.random;
1036
+ let state = seed >>> 0;
1037
+ return () => {
1038
+ state = state + 1831565813 >>> 0;
1039
+ let t = state;
1040
+ t = Math.imul(t ^ t >>> 15, t | 1);
1041
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
1042
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
1043
+ };
1044
+ }
1045
+ function sleep(ms) {
1046
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
1047
+ }
1048
+
1049
+ // src/trace.ts
1030
1050
  var TraceBuilder = class {
1031
1051
  traceId;
1032
1052
  agentId;
@@ -1058,11 +1078,22 @@ var TraceBuilder = class {
1058
1078
  return this;
1059
1079
  }
1060
1080
  addToolCall(name, options2) {
1081
+ const mock = activeMockRegistry.getStore()?.get(name);
1082
+ let result = options2?.result;
1083
+ if (mock !== void 0) {
1084
+ const mocked = mock(options2?.args ?? {});
1085
+ if (typeof mocked?.then === "function") {
1086
+ throw new Error(`mock for tool '${name}' returned a Promise; mock tools must be synchronous`);
1087
+ }
1088
+ if (typeof mocked === "object" && mocked !== null && !Array.isArray(mocked)) {
1089
+ result = mocked;
1090
+ }
1091
+ }
1061
1092
  this.steps.push({
1062
1093
  type: STEP_TOOL_CALL,
1063
1094
  name,
1064
1095
  args: options2?.args,
1065
- result: options2?.result,
1096
+ result,
1066
1097
  metadata: options2?.metadata
1067
1098
  });
1068
1099
  return this;
@@ -2717,18 +2748,18 @@ function serve(engine, args) {
2717
2748
  let stdout = "";
2718
2749
  let stderr = "";
2719
2750
  let resolveReady = () => void 0;
2720
- const ready = new Promise((resolve4) => {
2721
- resolveReady = resolve4;
2751
+ const ready = new Promise((resolve5) => {
2752
+ resolveReady = resolve5;
2722
2753
  });
2723
- const exited = new Promise((resolve4) => {
2754
+ const exited = new Promise((resolve5) => {
2724
2755
  child.on("close", (code, signal) => {
2725
2756
  resolveReady(null);
2726
- resolve4({ code, signal });
2757
+ resolve5({ code, signal });
2727
2758
  });
2728
2759
  child.on("error", (err) => {
2729
2760
  stderr += err.message;
2730
2761
  resolveReady(null);
2731
- resolve4({ code: null, signal: null });
2762
+ resolve5({ code: null, signal: null });
2732
2763
  });
2733
2764
  });
2734
2765
  child.stdout.setEncoding("utf8").on("data", (chunk) => {
@@ -2820,11 +2851,14 @@ async function recordExclusive(name, fn, opts) {
2820
2851
  throw new CaptureError(`capture ${name} wrote no fixture (${exitDetail(exit)})`);
2821
2852
  }
2822
2853
  const outcome = JSON.parse(lines[lines.length - 1] ?? "");
2823
- if (exit.code !== 0 || !outcome.verified) {
2854
+ if (exit.code !== 0 || outcome.outcome === "not_verified") {
2824
2855
  throw new CaptureError(`capture ${name}: fixture ${outcome.fixture} is not verified; no test drafted`, outcome.fixture);
2825
2856
  }
2857
+ if (outcome.outcome === "nothing_to_verify") {
2858
+ return { value, fixture: outcome.fixture, verified: false, outcome: "nothing_to_verify", testFile: null };
2859
+ }
2826
2860
  const testFile = opts.emitTest === false ? null : emitVitest(outcome.fixture);
2827
- return { value, fixture: outcome.fixture, verified: true, testFile };
2861
+ return { value, fixture: outcome.fixture, verified: true, outcome: "verified", testFile };
2828
2862
  }
2829
2863
 
2830
2864
  // src/replay.ts
@@ -2985,18 +3019,18 @@ async function start(name, mode, opts) {
2985
3019
  let stdout = "";
2986
3020
  let stderr = "";
2987
3021
  let resolveReady = () => void 0;
2988
- const ready = new Promise((resolve4) => {
2989
- resolveReady = resolve4;
3022
+ const ready = new Promise((resolve5) => {
3023
+ resolveReady = resolve5;
2990
3024
  });
2991
- const exited = new Promise((resolve4) => {
3025
+ const exited = new Promise((resolve5) => {
2992
3026
  child.on("close", (code) => {
2993
3027
  resolveReady(null);
2994
- resolve4(code);
3028
+ resolve5(code);
2995
3029
  });
2996
3030
  child.on("error", (err) => {
2997
3031
  stderr += err.message;
2998
3032
  resolveReady(null);
2999
- resolve4(null);
3033
+ resolve5(null);
3000
3034
  });
3001
3035
  });
3002
3036
  child.stdout.setEncoding("utf8").on("data", (chunk) => {
@@ -3121,18 +3155,18 @@ async function start2(file, opts) {
3121
3155
  let stdout = "";
3122
3156
  let stderr = "";
3123
3157
  let resolveReady = () => void 0;
3124
- const ready = new Promise((resolve4) => {
3125
- resolveReady = resolve4;
3158
+ const ready = new Promise((resolve5) => {
3159
+ resolveReady = resolve5;
3126
3160
  });
3127
- const exited = new Promise((resolve4) => {
3161
+ const exited = new Promise((resolve5) => {
3128
3162
  child.on("close", (code) => {
3129
3163
  resolveReady(null);
3130
- resolve4(code);
3164
+ resolve5(code);
3131
3165
  });
3132
3166
  child.on("error", (err) => {
3133
3167
  stderr += err.message;
3134
3168
  resolveReady(null);
3135
- resolve4(null);
3169
+ resolve5(null);
3136
3170
  });
3137
3171
  });
3138
3172
  child.stdout.setEncoding("utf8").on("data", (chunk) => {
@@ -3213,8 +3247,8 @@ function parseFinal(out) {
3213
3247
  }
3214
3248
 
3215
3249
  // src/context.ts
3216
- import { AsyncLocalStorage } from "async_hooks";
3217
- var activeBuilder = new AsyncLocalStorage();
3250
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
3251
+ var activeBuilder = new AsyncLocalStorage2();
3218
3252
 
3219
3253
  // src/agent.ts
3220
3254
  var Agent = class {
@@ -3301,6 +3335,9 @@ function tier(level) {
3301
3335
  }
3302
3336
 
3303
3337
  // src/plugins.ts
3338
+ import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync } from "fs";
3339
+ import { dirname as dirname2, join as join4, relative as relative2, resolve as resolve4, isAbsolute, sep as sep2 } from "path";
3340
+ import { pathToFileURL } from "url";
3304
3341
  var PluginRegistry = class {
3305
3342
  plugins = /* @__PURE__ */ new Map();
3306
3343
  register(name, plugin) {
@@ -3331,10 +3368,19 @@ var PluginRegistry = class {
3331
3368
  };
3332
3369
  async function executePluginAssertion(plugin, trace, spec, client, traceId2, assertionId2, timeoutMs = 3e4) {
3333
3370
  const resultPromise = Promise.resolve(plugin.execute(trace, spec));
3371
+ let timer;
3334
3372
  const timeoutPromise = new Promise((_, reject) => {
3335
- setTimeout(() => reject(new Error(`Plugin '${plugin.name}' timed out after ${timeoutMs}ms`)), timeoutMs);
3373
+ timer = setTimeout(
3374
+ () => reject(new Error(`Plugin '${plugin.name}' timed out after ${timeoutMs}ms`)),
3375
+ timeoutMs
3376
+ );
3336
3377
  });
3337
- const result = await Promise.race([resultPromise, timeoutPromise]);
3378
+ let result;
3379
+ try {
3380
+ result = await Promise.race([resultPromise, timeoutPromise]);
3381
+ } finally {
3382
+ clearTimeout(timer);
3383
+ }
3338
3384
  await client.submitPluginResult(
3339
3385
  traceId2,
3340
3386
  plugin.name,
@@ -3345,6 +3391,100 @@ async function executePluginAssertion(plugin, trace, spec, client, traceId2, ass
3345
3391
  );
3346
3392
  return result;
3347
3393
  }
3394
+ function registerPlugin(registry, name, plugin) {
3395
+ registry.register(name, plugin);
3396
+ }
3397
+ function isAttestPlugin(value) {
3398
+ if (typeof value !== "object" || value === null) return false;
3399
+ const v = value;
3400
+ return typeof v["name"] === "string" && typeof v["pluginType"] === "string" && typeof v["execute"] === "function";
3401
+ }
3402
+ function readJson(path5) {
3403
+ return JSON.parse(readFileSync2(path5, "utf8"));
3404
+ }
3405
+ function findInstalledPackage(projectRoot, name) {
3406
+ let dir = resolve4(projectRoot);
3407
+ for (; ; ) {
3408
+ const candidate = join4(dir, "node_modules", name);
3409
+ if (existsSync2(join4(candidate, "package.json"))) return candidate;
3410
+ const parent = dirname2(dir);
3411
+ if (parent === dir) return void 0;
3412
+ dir = parent;
3413
+ }
3414
+ }
3415
+ function declaredPluginPaths(pkgJson, dep) {
3416
+ const attest = pkgJson["attest"];
3417
+ if (attest === void 0) return [];
3418
+ const plugins = typeof attest === "object" && attest !== null ? attest["plugins"] : void 0;
3419
+ if (plugins === void 0) return [];
3420
+ if (!Array.isArray(plugins) || !plugins.every((p) => typeof p === "string")) {
3421
+ throw new Error(`'${dep}': "attest.plugins" must be an array of strings`);
3422
+ }
3423
+ return plugins;
3424
+ }
3425
+ function pluginsOf(mod) {
3426
+ const def = mod["default"];
3427
+ const nested = typeof def === "object" && def !== null ? def : void 0;
3428
+ for (const candidate of [def, nested?.["default"]]) {
3429
+ if (isAttestPlugin(candidate)) return [candidate];
3430
+ }
3431
+ return [.../* @__PURE__ */ new Set([...Object.values(mod), ...Object.values(nested ?? {})])].filter(isAttestPlugin);
3432
+ }
3433
+ function isInside(root, file) {
3434
+ const within = (r, f) => {
3435
+ const rel = relative2(r, f);
3436
+ return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute(rel);
3437
+ };
3438
+ return within(root, file) && within(realpathSync(root), realpathSync(file));
3439
+ }
3440
+ async function loadPackagePlugins(registry, projectRoot = process.cwd()) {
3441
+ let project;
3442
+ try {
3443
+ project = readJson(join4(projectRoot, "package.json"));
3444
+ } catch (err) {
3445
+ console.error(`attest: cannot read ${join4(projectRoot, "package.json")}; no plugins loaded:`, err);
3446
+ return 0;
3447
+ }
3448
+ const depNames = /* @__PURE__ */ new Set();
3449
+ for (const field of ["dependencies", "devDependencies", "optionalDependencies"]) {
3450
+ const deps = project[field];
3451
+ if (typeof deps === "object" && deps !== null) {
3452
+ for (const dep of Object.keys(deps)) depNames.add(dep);
3453
+ }
3454
+ }
3455
+ let loaded = 0;
3456
+ for (const dep of depNames) {
3457
+ const pkgDir = findInstalledPackage(projectRoot, dep);
3458
+ if (pkgDir === void 0) continue;
3459
+ let entries;
3460
+ try {
3461
+ entries = declaredPluginPaths(readJson(join4(pkgDir, "package.json")), dep);
3462
+ } catch (err) {
3463
+ console.error(`attest: failed to read plugins declared by '${dep}':`, err);
3464
+ continue;
3465
+ }
3466
+ for (const entry of entries) {
3467
+ try {
3468
+ const file = resolve4(pkgDir, entry);
3469
+ if (!isInside(pkgDir, file)) {
3470
+ throw new Error(`plugin path '${entry}' escapes package '${dep}'`);
3471
+ }
3472
+ const mod = await import(pathToFileURL(file).href);
3473
+ const plugins = pluginsOf(mod);
3474
+ if (plugins.length === 0) {
3475
+ throw new Error(`'${entry}' exports no plugin (name, pluginType, execute)`);
3476
+ }
3477
+ for (const plugin of plugins) {
3478
+ registry.register(plugin.name, plugin);
3479
+ loaded++;
3480
+ }
3481
+ } catch (err) {
3482
+ console.error(`attest: failed to load plugin '${entry}' from '${dep}':`, err);
3483
+ }
3484
+ }
3485
+ }
3486
+ return loaded;
3487
+ }
3348
3488
 
3349
3489
  // src/continuous.ts
3350
3490
  import { EventEmitter } from "events";
@@ -3724,6 +3864,172 @@ the assistant's response meets your needs. Keep responses concise (1-3 sentences
3724
3864
  max_tokens: 200
3725
3865
  };
3726
3866
 
3867
+ // src/simulation/mock-tools.ts
3868
+ var MockToolRegistry = class {
3869
+ tools = /* @__PURE__ */ new Map();
3870
+ register(name, fn) {
3871
+ this.tools.set(name, fn);
3872
+ }
3873
+ /**
3874
+ * Run `fn` with the registered mocks active. `TraceBuilder.addToolCall`
3875
+ * returns the mock's result for a registered tool name. Scopes are
3876
+ * isolated per async call chain (AsyncLocalStorage).
3877
+ */
3878
+ run(fn) {
3879
+ return activeMockRegistry.run(new Map(this.tools), fn);
3880
+ }
3881
+ };
3882
+ function mockTool(name, fn) {
3883
+ const wrapper = ((args) => fn(args));
3884
+ return Object.assign(wrapper, { mockToolName: name });
3885
+ }
3886
+
3887
+ // src/simulation/fault-inject.ts
3888
+ function faultInject(options2, fn) {
3889
+ const errorRate = options2.errorRate ?? 0;
3890
+ const latencyJitterMs = options2.latencyJitterMs ?? 0;
3891
+ const rng = createRng(options2.seed);
3892
+ return async (...args) => {
3893
+ if (errorRate > 0 && rng() < errorRate) {
3894
+ throw new Error(`Injected fault in ${fn.name || "anonymous"}`);
3895
+ }
3896
+ if (latencyJitterMs > 0) {
3897
+ await sleep(rng() * latencyJitterMs);
3898
+ }
3899
+ return fn(...args);
3900
+ };
3901
+ }
3902
+
3903
+ // src/simulation/verdict.ts
3904
+ function aggregateOutcomes(outcomes) {
3905
+ if (outcomes.includes(OUTCOME_FAIL)) return OUTCOME_FAIL;
3906
+ if (outcomes.includes(OUTCOME_SKIP)) return OUTCOME_SKIP;
3907
+ return OUTCOME_PASS;
3908
+ }
3909
+ function sumNotEvaluatedReasons(results) {
3910
+ const counts = {};
3911
+ for (const r of results) {
3912
+ for (const [reason, n] of Object.entries(r.notEvaluatedReasons)) {
3913
+ counts[reason] = (counts[reason] ?? 0) + n;
3914
+ }
3915
+ }
3916
+ return counts;
3917
+ }
3918
+ function formatSkipReason(counts) {
3919
+ const parts = Object.entries(counts).map(([reason, n]) => n === 1 ? reason : `${reason} \xD7${n}`);
3920
+ return `not evaluated: ${parts.join(", ")}`;
3921
+ }
3922
+ function renderVerdictDiagnostics(verdict, color = false) {
3923
+ return verdict instanceof AgentResult ? renderDiagnostics(verdict, { color }) : verdict.renderDiagnostics?.({ color }) ?? "";
3924
+ }
3925
+ function verdictsDiagnostics(results, label, color = false) {
3926
+ const blocks = results.flatMap(
3927
+ (r, i) => r.outcome() === OUTCOME_PASS ? [] : [`${label} ${i + 1}/${results.length}:${renderVerdictDiagnostics(r, color)}`]
3928
+ );
3929
+ return blocks.length > 0 ? blocks.join("\n") : ` (no failing ${label}s)
3930
+ `;
3931
+ }
3932
+
3933
+ // src/simulation/repeat.ts
3934
+ var RepeatResult = class {
3935
+ results;
3936
+ constructor(results = []) {
3937
+ this.results = results;
3938
+ }
3939
+ get count() {
3940
+ return this.results.length;
3941
+ }
3942
+ /** Trials skipped because an assertion was not evaluated. */
3943
+ get notEvaluated() {
3944
+ return this.results.filter((r) => r.outcome() === OUTCOME_SKIP).length;
3945
+ }
3946
+ /** Passing / evaluated trials; null when no trial was evaluated. */
3947
+ get passRate() {
3948
+ const evaluated = this.count - this.notEvaluated;
3949
+ if (evaluated === 0) return null;
3950
+ return this.results.filter((r) => r.outcome() === OUTCOME_PASS).length / evaluated;
3951
+ }
3952
+ /** True when every trial's outcome is pass (soft failures included). */
3953
+ get allPassed() {
3954
+ return this.results.every((r) => r.outcome() === OUTCOME_PASS);
3955
+ }
3956
+ outcome(options2) {
3957
+ return aggregateOutcomes(this.results.map((r) => r.outcome(options2)));
3958
+ }
3959
+ get notEvaluatedReasons() {
3960
+ return sumNotEvaluatedReasons(this.results);
3961
+ }
3962
+ skipReason() {
3963
+ return formatSkipReason(this.notEvaluatedReasons);
3964
+ }
3965
+ renderDiagnostics(options2) {
3966
+ return verdictsDiagnostics(this.results, "trial", options2?.color);
3967
+ }
3968
+ };
3969
+ function repeat(n, fn) {
3970
+ return async (...args) => {
3971
+ const results = [];
3972
+ for (let i = 0; i < n; i++) {
3973
+ results.push(await fn(...args));
3974
+ }
3975
+ return new RepeatResult(results);
3976
+ };
3977
+ }
3978
+
3979
+ // src/simulation/scenario.ts
3980
+ var ScenarioResult = class {
3981
+ config;
3982
+ results;
3983
+ constructor(config2, results = []) {
3984
+ this.config = config2;
3985
+ this.results = results;
3986
+ }
3987
+ /** True when the aggregate `outcome()` is pass. */
3988
+ get passed() {
3989
+ return this.outcome() === OUTCOME_PASS;
3990
+ }
3991
+ outcome(options2) {
3992
+ return aggregateOutcomes(this.results.map((r) => r.outcome(options2)));
3993
+ }
3994
+ get notEvaluatedReasons() {
3995
+ return sumNotEvaluatedReasons(this.results);
3996
+ }
3997
+ skipReason() {
3998
+ return formatSkipReason(this.notEvaluatedReasons);
3999
+ }
4000
+ renderDiagnostics(options2) {
4001
+ return verdictsDiagnostics(this.results, "turn", options2?.color);
4002
+ }
4003
+ };
4004
+ function scenario(options2, fn) {
4005
+ const config2 = {
4006
+ persona: options2.persona,
4007
+ mockTools: { ...options2.mockTools },
4008
+ faultErrorRate: options2.faultErrorRate ?? 0,
4009
+ faultLatencyJitterMs: options2.faultLatencyJitterMs ?? 0,
4010
+ maxTurns: options2.maxTurns ?? 1,
4011
+ seed: options2.seed
4012
+ };
4013
+ return async (...args) => {
4014
+ const run = async () => {
4015
+ const results = [];
4016
+ const rng = createRng(config2.seed);
4017
+ for (let turn = 0; turn < config2.maxTurns; turn++) {
4018
+ if (config2.faultErrorRate > 0 && rng() < config2.faultErrorRate) {
4019
+ throw new Error(`Injected fault at turn ${turn}`);
4020
+ }
4021
+ if (config2.faultLatencyJitterMs > 0) {
4022
+ await sleep(rng() * config2.faultLatencyJitterMs);
4023
+ }
4024
+ results.push(await fn({ persona: config2.persona, turn }, ...args));
4025
+ }
4026
+ return new ScenarioResult(config2, results);
4027
+ };
4028
+ const mocks = new Map(Object.entries(config2.mockTools));
4029
+ return mocks.size > 0 ? activeMockRegistry.run(mocks, run) : run();
4030
+ };
4031
+ }
4032
+
3727
4033
  // src/adapters/manual.ts
3728
4034
  var ManualAdapter = class {
3729
4035
  agentId;
@@ -3935,7 +4241,7 @@ var OTelAdapter = class _OTelAdapter {
3935
4241
  }
3936
4242
  };
3937
4243
  function runConvert(engine, args, payload) {
3938
- return new Promise((resolve4, reject) => {
4244
+ return new Promise((resolve5, reject) => {
3939
4245
  const child = spawn5(engine, args, { stdio: ["pipe", "pipe", "pipe"] });
3940
4246
  let timer;
3941
4247
  child.on("error", (e) => {
@@ -3988,7 +4294,7 @@ function runConvert(engine, args, payload) {
3988
4294
  );
3989
4295
  return;
3990
4296
  }
3991
- resolve4(Buffer.concat(out).toString("utf8"));
4297
+ resolve5(Buffer.concat(out).toString("utf8"));
3992
4298
  });
3993
4299
  stdin.end(payload);
3994
4300
  });
@@ -4155,6 +4461,7 @@ export {
4155
4461
  GeminiAdapter,
4156
4462
  LangChainAdapter,
4157
4463
  ManualAdapter,
4464
+ MockToolRegistry,
4158
4465
  OTLPConversionError,
4159
4466
  OTelAdapter,
4160
4467
  OUTCOME_FAIL,
@@ -4174,6 +4481,7 @@ export {
4174
4481
  REASON_REPLAY_MISS,
4175
4482
  REASON_SHORT_CIRCUITED,
4176
4483
  REASON_SIMULATION,
4484
+ RepeatResult,
4177
4485
  ReplayError,
4178
4486
  ReplayMissError,
4179
4487
  ReplayNotEvaluatedError,
@@ -4186,6 +4494,7 @@ export {
4186
4494
  STEP_RETRIEVAL,
4187
4495
  STEP_TOOL_CALL,
4188
4496
  Sampler,
4497
+ ScenarioResult,
4189
4498
  TIER_1,
4190
4499
  TIER_2,
4191
4500
  TIER_3,
@@ -4220,6 +4529,7 @@ export {
4220
4529
  executePluginAssertion,
4221
4530
  extractId,
4222
4531
  extractResult,
4532
+ faultInject,
4223
4533
  firstMiss,
4224
4534
  formatUsage,
4225
4535
  getSampleRate,
@@ -4231,17 +4541,23 @@ export {
4231
4541
  loadFixture,
4232
4542
  loadLabelsCSV,
4233
4543
  loadLabelsJSONL,
4544
+ loadPackagePlugins,
4545
+ mockTool,
4234
4546
  parseUsage,
4235
4547
  previewLine,
4236
4548
  promptHash,
4237
4549
  record,
4550
+ registerPlugin,
4238
4551
  renderAssertionFailure,
4239
4552
  renderDiagnostics,
4240
4553
  renderSummary,
4554
+ renderVerdictDiagnostics,
4241
4555
  renderVitest,
4556
+ repeat,
4242
4557
  requireSimulationCapability,
4243
4558
  resetConfig,
4244
4559
  resolveMode,
4560
+ scenario,
4245
4561
  simulationEnvEnabled,
4246
4562
  startReplay,
4247
4563
  startWorld,