@attest-ai/core 0.4.2 → 0.5.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.
Files changed (43) hide show
  1. package/dist/cjs/index.cjs +2484 -0
  2. package/dist/cjs/index.cjs.map +1 -0
  3. package/dist/cjs/index.d.cts +1085 -0
  4. package/dist/cjs/proto/index.cjs +208 -0
  5. package/dist/cjs/proto/index.cjs.map +1 -0
  6. package/dist/cjs/proto/index.d.cts +228 -0
  7. package/dist/client.d.ts +7 -3
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +48 -9
  10. package/dist/client.js.map +1 -1
  11. package/dist/config.d.ts +21 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +31 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/delegate.d.ts.map +1 -1
  16. package/dist/delegate.js +1 -7
  17. package/dist/delegate.js.map +1 -1
  18. package/dist/esm/cli.d.ts +9 -0
  19. package/dist/esm/cli.js +154 -0
  20. package/dist/esm/cli.js.map +1 -0
  21. package/dist/esm/index.d.ts +1085 -0
  22. package/dist/esm/index.js +2385 -0
  23. package/dist/esm/index.js.map +1 -0
  24. package/dist/esm/proto/index.d.ts +228 -0
  25. package/dist/esm/proto/index.js +152 -0
  26. package/dist/esm/proto/index.js.map +1 -0
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/proto/errors.d.ts +5 -0
  32. package/dist/proto/errors.d.ts.map +1 -1
  33. package/dist/proto/errors.js +11 -0
  34. package/dist/proto/errors.js.map +1 -1
  35. package/dist/simulation.d.ts +8 -0
  36. package/dist/simulation.d.ts.map +1 -0
  37. package/dist/simulation.js +21 -0
  38. package/dist/simulation.js.map +1 -0
  39. package/dist/trace.d.ts +1 -0
  40. package/dist/trace.d.ts.map +1 -1
  41. package/dist/trace.js +3 -0
  42. package/dist/trace.js.map +1 -1
  43. package/package.json +34 -8
@@ -0,0 +1,2484 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ Agent: () => Agent,
34
+ AgentResult: () => AgentResult,
35
+ AlertDispatcher: () => AlertDispatcher,
36
+ AnthropicAdapter: () => AnthropicAdapter,
37
+ AttestClient: () => AttestClient,
38
+ ContinuousEvalRunner: () => ContinuousEvalRunner,
39
+ ENGINE_VERSION: () => ENGINE_VERSION,
40
+ ERR_ASSERTION_ERROR: () => ERR_ASSERTION_ERROR,
41
+ ERR_ENGINE_ERROR: () => ERR_ENGINE_ERROR,
42
+ ERR_INVALID_TRACE: () => ERR_INVALID_TRACE,
43
+ ERR_PROVIDER_ERROR: () => ERR_PROVIDER_ERROR,
44
+ ERR_SESSION_ERROR: () => ERR_SESSION_ERROR,
45
+ ERR_TIMEOUT: () => ERR_TIMEOUT,
46
+ EngineManager: () => EngineManager,
47
+ EngineTimeoutError: () => EngineTimeoutError,
48
+ ExpectChain: () => ExpectChain,
49
+ GeminiAdapter: () => GeminiAdapter,
50
+ LangChainAdapter: () => LangChainAdapter,
51
+ ManualAdapter: () => ManualAdapter,
52
+ OTelAdapter: () => OTelAdapter,
53
+ OllamaAdapter: () => OllamaAdapter,
54
+ OpenAIAdapter: () => OpenAIAdapter,
55
+ PluginRegistry: () => PluginRegistry,
56
+ ProtocolError: () => ProtocolError,
57
+ STATUS_HARD_FAIL: () => STATUS_HARD_FAIL,
58
+ STATUS_PASS: () => STATUS_PASS,
59
+ STATUS_SOFT_FAIL: () => STATUS_SOFT_FAIL,
60
+ STEP_AGENT_CALL: () => STEP_AGENT_CALL,
61
+ STEP_LLM_CALL: () => STEP_LLM_CALL,
62
+ STEP_RETRIEVAL: () => STEP_RETRIEVAL,
63
+ STEP_TOOL_CALL: () => STEP_TOOL_CALL,
64
+ Sampler: () => Sampler,
65
+ TIER_1: () => TIER_1,
66
+ TIER_2: () => TIER_2,
67
+ TIER_3: () => TIER_3,
68
+ TYPE_CONSTRAINT: () => TYPE_CONSTRAINT,
69
+ TYPE_CONTENT: () => TYPE_CONTENT,
70
+ TYPE_EMBEDDING: () => TYPE_EMBEDDING,
71
+ TYPE_LLM_JUDGE: () => TYPE_LLM_JUDGE,
72
+ TYPE_PLUGIN: () => TYPE_PLUGIN,
73
+ TYPE_SCHEMA: () => TYPE_SCHEMA,
74
+ TYPE_TRACE: () => TYPE_TRACE,
75
+ TYPE_TRACE_TREE: () => TYPE_TRACE_TREE,
76
+ TraceBuilder: () => TraceBuilder,
77
+ TraceTree: () => TraceTree,
78
+ VERSION: () => VERSION,
79
+ activeBuilder: () => activeBuilder,
80
+ agent: () => agent,
81
+ agentId: () => agentId,
82
+ assertionId: () => assertionId,
83
+ attestExpect: () => attestExpect,
84
+ config: () => config,
85
+ decodeResponse: () => decodeResponse,
86
+ delegate: () => delegate,
87
+ encodeRequest: () => encodeRequest,
88
+ executePluginAssertion: () => executePluginAssertion,
89
+ extractId: () => extractId,
90
+ extractResult: () => extractResult,
91
+ isSimulationMode: () => isSimulationMode,
92
+ resetConfig: () => resetConfig,
93
+ tier: () => tier,
94
+ traceId: () => traceId
95
+ });
96
+ module.exports = __toCommonJS(index_exports);
97
+
98
+ // src/proto/constants.ts
99
+ var STEP_LLM_CALL = "llm_call";
100
+ var STEP_TOOL_CALL = "tool_call";
101
+ var STEP_RETRIEVAL = "retrieval";
102
+ var STEP_AGENT_CALL = "agent_call";
103
+ var STATUS_PASS = "pass";
104
+ var STATUS_SOFT_FAIL = "soft_fail";
105
+ var STATUS_HARD_FAIL = "hard_fail";
106
+ var TYPE_SCHEMA = "schema";
107
+ var TYPE_CONSTRAINT = "constraint";
108
+ var TYPE_TRACE = "trace";
109
+ var TYPE_CONTENT = "content";
110
+ var TYPE_EMBEDDING = "embedding";
111
+ var TYPE_LLM_JUDGE = "llm_judge";
112
+ var TYPE_TRACE_TREE = "trace_tree";
113
+ var TYPE_PLUGIN = "plugin";
114
+ var ERR_INVALID_TRACE = 1001;
115
+ var ERR_ASSERTION_ERROR = 1002;
116
+ var ERR_PROVIDER_ERROR = 2001;
117
+ var ERR_ENGINE_ERROR = 3001;
118
+ var ERR_TIMEOUT = 3002;
119
+ var ERR_SESSION_ERROR = 3003;
120
+
121
+ // src/proto/types.ts
122
+ function traceId(id) {
123
+ return id;
124
+ }
125
+ function assertionId(id) {
126
+ return id;
127
+ }
128
+ function agentId(id) {
129
+ return id;
130
+ }
131
+
132
+ // src/proto/errors.ts
133
+ var ProtocolError = class extends Error {
134
+ code;
135
+ errorMessage;
136
+ data;
137
+ constructor(code, message, data) {
138
+ super(message);
139
+ this.name = "ProtocolError";
140
+ this.code = code;
141
+ this.errorMessage = message;
142
+ this.data = data;
143
+ }
144
+ };
145
+ var EngineTimeoutError = class extends Error {
146
+ method;
147
+ timeoutMs;
148
+ constructor(method, timeoutMs) {
149
+ super(
150
+ `Engine request '${method}' timed out after ${timeoutMs}ms. Set ATTEST_ENGINE_TIMEOUT to increase the limit.`
151
+ );
152
+ this.name = "EngineTimeoutError";
153
+ this.method = method;
154
+ this.timeoutMs = timeoutMs;
155
+ }
156
+ };
157
+
158
+ // src/proto/codec.ts
159
+ function encodeRequest(id, method, params) {
160
+ const msg = {
161
+ jsonrpc: "2.0",
162
+ id,
163
+ method,
164
+ params
165
+ };
166
+ return JSON.stringify(msg) + "\n";
167
+ }
168
+ function decodeResponse(line) {
169
+ const text = line.trim();
170
+ if (!text) {
171
+ throw new Error("empty response line");
172
+ }
173
+ let data;
174
+ try {
175
+ data = JSON.parse(text);
176
+ } catch (e) {
177
+ throw new Error(`malformed JSON response: ${e instanceof Error ? e.message : String(e)}`);
178
+ }
179
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
180
+ throw new Error(`expected JSON object, got ${Array.isArray(data) ? "array" : typeof data}`);
181
+ }
182
+ const obj = data;
183
+ if (obj.jsonrpc !== "2.0") {
184
+ throw new Error(`invalid jsonrpc version: ${String(obj.jsonrpc)}`);
185
+ }
186
+ if (obj.error != null) {
187
+ const err = obj.error;
188
+ let errorData;
189
+ if (err.data != null) {
190
+ const raw = err.data;
191
+ errorData = {
192
+ error_type: raw.error_type ?? "",
193
+ retryable: raw.retryable ?? false,
194
+ detail: raw.detail ?? ""
195
+ };
196
+ }
197
+ throw new ProtocolError(
198
+ err.code ?? -1,
199
+ err.message ?? "unknown error",
200
+ errorData
201
+ );
202
+ }
203
+ return obj;
204
+ }
205
+ function extractResult(response) {
206
+ if (response.result === void 0) {
207
+ throw new Error("response missing 'result' field");
208
+ }
209
+ return response.result;
210
+ }
211
+ function extractId(response) {
212
+ if (response.id === void 0) {
213
+ throw new Error("response missing 'id' field");
214
+ }
215
+ return Number(response.id);
216
+ }
217
+
218
+ // src/version.ts
219
+ var VERSION = "0.5.0";
220
+ var ENGINE_VERSION = "0.5.0";
221
+
222
+ // src/engine-manager.ts
223
+ var import_node_child_process = require("child_process");
224
+ var import_node_readline = require("readline");
225
+ var import_node_fs = require("fs");
226
+ var import_node_path = require("path");
227
+ var import_node_url = require("url");
228
+
229
+ // src/engine-downloader.ts
230
+ var https = __toESM(require("https"), 1);
231
+ var http = __toESM(require("http"), 1);
232
+ var fs = __toESM(require("fs"), 1);
233
+ var path = __toESM(require("path"), 1);
234
+ var os = __toESM(require("os"), 1);
235
+ var crypto = __toESM(require("crypto"), 1);
236
+ var RELEASE_BASE = `https://github.com/attest-framework/attest/releases/download/v${ENGINE_VERSION}`;
237
+ var CHECKSUMS_URL = `${RELEASE_BASE}/checksums-sha256.txt`;
238
+ var MAX_REDIRECTS = 5;
239
+ function attestBinDir() {
240
+ const dir = path.join(os.homedir(), ".attest", "bin");
241
+ fs.mkdirSync(dir, { recursive: true });
242
+ return dir;
243
+ }
244
+ function platformKey() {
245
+ const platform2 = os.platform();
246
+ const arch2 = os.arch();
247
+ const mapping = {
248
+ darwin: { arm64: "darwin-arm64", x64: "darwin-amd64" },
249
+ linux: { arm64: "linux-arm64", x64: "linux-amd64" },
250
+ win32: { x64: "windows-amd64", arm64: "windows-arm64" }
251
+ };
252
+ const osMap = mapping[platform2];
253
+ if (!osMap) {
254
+ throw new Error(
255
+ `Unsupported platform: ${platform2}. Supported: darwin, linux, win32.`
256
+ );
257
+ }
258
+ const key = osMap[arch2];
259
+ if (!key) {
260
+ throw new Error(
261
+ `Unsupported architecture '${arch2}' on platform '${platform2}'. Supported architectures: ${Object.keys(osMap).join(", ")}.`
262
+ );
263
+ }
264
+ return key;
265
+ }
266
+ function binaryFilename() {
267
+ return os.platform() === "win32" ? "attest-engine.exe" : "attest-engine";
268
+ }
269
+ function cachedEnginePath() {
270
+ const dir = path.join(os.homedir(), ".attest", "bin");
271
+ const binPath = path.join(dir, binaryFilename());
272
+ const versionFile = path.join(dir, ".engine-version");
273
+ if (!fs.existsSync(binPath)) {
274
+ return null;
275
+ }
276
+ if (!fs.existsSync(versionFile)) {
277
+ return null;
278
+ }
279
+ const cachedVersion = fs.readFileSync(versionFile, "utf-8").trim();
280
+ if (cachedVersion !== ENGINE_VERSION) {
281
+ return null;
282
+ }
283
+ return binPath;
284
+ }
285
+ function parseChecksums(text) {
286
+ const checksums = /* @__PURE__ */ new Map();
287
+ for (const line of text.split("\n")) {
288
+ const trimmed = line.trim();
289
+ if (!trimmed) continue;
290
+ const match = trimmed.match(/^([a-f0-9]{64})\s+(.+)$/);
291
+ if (match) {
292
+ checksums.set(match[2], match[1]);
293
+ }
294
+ }
295
+ return checksums;
296
+ }
297
+ function httpsGet(url, redirectCount = 0) {
298
+ if (redirectCount > MAX_REDIRECTS) {
299
+ return Promise.reject(
300
+ new Error(`Too many redirects (>${MAX_REDIRECTS}) following ${url}`)
301
+ );
302
+ }
303
+ return new Promise((resolve2, reject) => {
304
+ const client = url.startsWith("https:") ? https : http;
305
+ client.get(url, (res) => {
306
+ const status = res.statusCode ?? 0;
307
+ if (status === 301 || status === 302) {
308
+ const location = res.headers.location;
309
+ if (!location) {
310
+ reject(new Error(`Redirect ${status} without Location header from ${url}`));
311
+ return;
312
+ }
313
+ res.resume();
314
+ resolve2(httpsGet(location, redirectCount + 1));
315
+ return;
316
+ }
317
+ if (status < 200 || status >= 300) {
318
+ res.resume();
319
+ reject(new Error(`HTTP ${status} fetching ${url}`));
320
+ return;
321
+ }
322
+ const chunks = [];
323
+ res.on("data", (chunk) => chunks.push(chunk));
324
+ res.on("end", () => resolve2(Buffer.concat(chunks)));
325
+ res.on("error", reject);
326
+ }).on("error", reject);
327
+ });
328
+ }
329
+ async function downloadEngine() {
330
+ const key = platformKey();
331
+ const filename = `attest-engine-${key}`;
332
+ const binaryUrl = `${RELEASE_BASE}/${filename}`;
333
+ process.stderr.write(`[attest] Downloading engine v${ENGINE_VERSION} for ${key}...
334
+ `);
335
+ process.stderr.write(`[attest] Fetching checksums...
336
+ `);
337
+ const checksumsText = (await httpsGet(CHECKSUMS_URL)).toString("utf-8");
338
+ const checksums = parseChecksums(checksumsText);
339
+ const expectedHash = checksums.get(filename);
340
+ if (!expectedHash) {
341
+ throw new Error(
342
+ `No checksum found for '${filename}' in checksums-sha256.txt. Available files: ${[...checksums.keys()].join(", ")}`
343
+ );
344
+ }
345
+ process.stderr.write(`[attest] Downloading ${binaryUrl}...
346
+ `);
347
+ const data = await httpsGet(binaryUrl);
348
+ const actualHash = crypto.createHash("sha256").update(data).digest("hex");
349
+ if (actualHash !== expectedHash) {
350
+ throw new Error(
351
+ `SHA256 mismatch for ${filename}. Expected: ${expectedHash}, got: ${actualHash}. The download may be corrupted. Delete ~/.attest/bin/ and retry.`
352
+ );
353
+ }
354
+ process.stderr.write(`[attest] Checksum verified.
355
+ `);
356
+ const dir = attestBinDir();
357
+ const destFilename = binaryFilename();
358
+ const destPath = path.join(dir, destFilename);
359
+ const tmpPath = path.join(dir, `.${destFilename}.tmp.${process.pid}`);
360
+ fs.writeFileSync(tmpPath, data);
361
+ fs.chmodSync(tmpPath, 493);
362
+ fs.renameSync(tmpPath, destPath);
363
+ fs.writeFileSync(path.join(dir, ".engine-version"), ENGINE_VERSION);
364
+ process.stderr.write(`[attest] Engine installed at ${destPath}
365
+ `);
366
+ return destPath;
367
+ }
368
+
369
+ // src/engine-manager.ts
370
+ var import_meta = {};
371
+ var ENGINE_BINARY_NAME = "attest-engine";
372
+ async function findEngineBinary() {
373
+ const envPath = process.env["ATTEST_ENGINE_PATH"];
374
+ if (envPath) {
375
+ if (!(0, import_node_fs.existsSync)(envPath)) {
376
+ throw new Error(
377
+ `ATTEST_ENGINE_PATH is set to '${envPath}' but the file does not exist.`
378
+ );
379
+ }
380
+ return envPath;
381
+ }
382
+ try {
383
+ const cmd = process.platform === "win32" ? "where" : "which";
384
+ const found = (0, import_node_child_process.execSync)(`${cmd} ${ENGINE_BINARY_NAME}`, { encoding: "utf-8" }).trim();
385
+ if (found) return found;
386
+ } catch {
387
+ }
388
+ const cached = cachedEnginePath();
389
+ if (cached) return cached;
390
+ const candidates = [
391
+ (0, import_node_path.join)((0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta.url)), "..", "..", "..", "..", "..", "bin", ENGINE_BINARY_NAME),
392
+ (0, import_node_path.join)(process.cwd(), "bin", ENGINE_BINARY_NAME)
393
+ ];
394
+ for (const candidate of candidates) {
395
+ const resolved = (0, import_node_path.resolve)(candidate);
396
+ try {
397
+ (0, import_node_fs.accessSync)(resolved, import_node_fs.constants.X_OK);
398
+ if ((0, import_node_fs.existsSync)(resolved)) return resolved;
399
+ } catch {
400
+ }
401
+ }
402
+ const noDownload = process.env["ATTEST_ENGINE_NO_DOWNLOAD"];
403
+ if (noDownload === "1" || noDownload === "true" || noDownload === "yes") {
404
+ throw new Error(
405
+ `Cannot find '${ENGINE_BINARY_NAME}' binary and auto-download is disabled (ATTEST_ENGINE_NO_DOWNLOAD is set). Install the engine manually:
406
+ 1. Download from https://github.com/attest-framework/attest/releases
407
+ 2. Place the binary on your PATH or set ATTEST_ENGINE_PATH`
408
+ );
409
+ }
410
+ return downloadEngine();
411
+ }
412
+ var EngineManager = class {
413
+ enginePath;
414
+ logLevel;
415
+ process = null;
416
+ reader = null;
417
+ initialized = false;
418
+ requestId = 0;
419
+ initResult = null;
420
+ constructor(options) {
421
+ this.enginePath = options?.enginePath ?? "";
422
+ this.logLevel = options?.logLevel ?? "warn";
423
+ }
424
+ async start() {
425
+ if (!this.enginePath) {
426
+ this.enginePath = await findEngineBinary();
427
+ }
428
+ this.process = (0, import_node_child_process.spawn)(this.enginePath, [`--log-level=${this.logLevel}`], {
429
+ stdio: ["pipe", "pipe", "pipe"]
430
+ });
431
+ this.reader = (0, import_node_readline.createInterface)({ input: this.process.stdout });
432
+ const result = await this.sendRequestInternal("initialize", {
433
+ sdk_name: "attest-typescript",
434
+ sdk_version: VERSION,
435
+ protocol_version: 1,
436
+ required_capabilities: ["layers_1_4"],
437
+ preferred_encoding: "json"
438
+ });
439
+ this.initResult = result;
440
+ if (!this.initResult.compatible) {
441
+ throw new Error(
442
+ `Engine incompatible. Missing capabilities: ${JSON.stringify(this.initResult.missing)}`
443
+ );
444
+ }
445
+ this.initialized = true;
446
+ return this.initResult;
447
+ }
448
+ async stop() {
449
+ if (this.process === null) return;
450
+ if (this.initialized) {
451
+ try {
452
+ await this.sendRequestInternal("shutdown", {});
453
+ } catch {
454
+ }
455
+ }
456
+ if (this.reader) {
457
+ this.reader.close();
458
+ this.reader = null;
459
+ }
460
+ if (this.process.exitCode === null) {
461
+ this.process.kill("SIGTERM");
462
+ await new Promise((res) => {
463
+ const timer = setTimeout(() => {
464
+ this.process?.kill("SIGKILL");
465
+ }, 5e3);
466
+ this.process.on("exit", () => {
467
+ clearTimeout(timer);
468
+ res();
469
+ });
470
+ });
471
+ }
472
+ this.initialized = false;
473
+ this.process = null;
474
+ }
475
+ async sendRequest(method, params) {
476
+ if (!this.initialized && method !== "initialize") {
477
+ throw new Error("Engine not initialized. Call start() first.");
478
+ }
479
+ return this.sendRequestInternal(method, params);
480
+ }
481
+ async sendRequestInternal(method, params) {
482
+ if (this.process === null || this.process.stdin === null || this.reader === null) {
483
+ throw new Error("Engine process not started.");
484
+ }
485
+ this.requestId += 1;
486
+ const requestStr = encodeRequest(this.requestId, method, params);
487
+ return new Promise((resolve2, reject) => {
488
+ const onLine = (line) => {
489
+ try {
490
+ const response = decodeResponse(line);
491
+ resolve2(extractResult(response));
492
+ } catch (err) {
493
+ reject(err);
494
+ }
495
+ };
496
+ this.reader.once("line", onLine);
497
+ const ok = this.process.stdin.write(requestStr, (err) => {
498
+ if (err) {
499
+ this.reader.removeListener("line", onLine);
500
+ reject(err);
501
+ }
502
+ });
503
+ if (!ok) {
504
+ this.process.stdin.once("drain", () => {
505
+ });
506
+ }
507
+ });
508
+ }
509
+ get isRunning() {
510
+ return this.process !== null && this.process.exitCode === null;
511
+ }
512
+ /** Expose process for AttestClient reader loop access */
513
+ get childProcess() {
514
+ return this.process;
515
+ }
516
+ /** Expose readline interface for AttestClient reader loop */
517
+ get readlineInterface() {
518
+ return this.reader;
519
+ }
520
+ };
521
+
522
+ // src/config.ts
523
+ var _simulationMode = false;
524
+ function config(options) {
525
+ if (options.simulation !== void 0) {
526
+ _simulationMode = options.simulation;
527
+ }
528
+ }
529
+ function isSimulationMode() {
530
+ return _simulationMode || process.env["ATTEST_SIMULATION"] === "1" || process.env["ATTEST_SIMULATION"] === "true" || process.env["ATTEST_SIMULATION"] === "yes";
531
+ }
532
+ function resetConfig() {
533
+ _simulationMode = false;
534
+ }
535
+
536
+ // src/simulation.ts
537
+ function simulationEvaluateBatch(assertions) {
538
+ const results = assertions.map((assertion) => ({
539
+ assertion_id: assertion.assertion_id,
540
+ status: "pass",
541
+ score: 1,
542
+ explanation: `[simulation] assertion '${assertion.assertion_id}' passed (type: ${assertion.type})`,
543
+ cost: 0,
544
+ duration_ms: 0
545
+ }));
546
+ return {
547
+ results,
548
+ total_cost: 0,
549
+ total_duration_ms: 0
550
+ };
551
+ }
552
+
553
+ // src/client.ts
554
+ var DEFAULT_TIMEOUT_MS = 3e4;
555
+ function resolveTimeoutMs(override) {
556
+ if (override !== void 0) return override;
557
+ const env = process.env["ATTEST_ENGINE_TIMEOUT"];
558
+ if (env !== void 0 && env !== "") {
559
+ const parsed = Number(env);
560
+ if (!Number.isFinite(parsed) || parsed <= 0) {
561
+ throw new Error(
562
+ `ATTEST_ENGINE_TIMEOUT must be a positive number of milliseconds, got: '${env}'`
563
+ );
564
+ }
565
+ return parsed;
566
+ }
567
+ return DEFAULT_TIMEOUT_MS;
568
+ }
569
+ function makeTimeoutPromise(method, timeoutMs) {
570
+ return new Promise((_, reject) => {
571
+ setTimeout(() => {
572
+ reject(new EngineTimeoutError(method, timeoutMs));
573
+ }, timeoutMs);
574
+ });
575
+ }
576
+ var AttestClient = class {
577
+ engine;
578
+ requestId = 0;
579
+ pending = /* @__PURE__ */ new Map();
580
+ writeChain = Promise.resolve();
581
+ readerActive = false;
582
+ lineHandler = null;
583
+ constructor(engine) {
584
+ this.engine = engine;
585
+ }
586
+ startReader() {
587
+ if (this.readerActive) return;
588
+ const rl = this.engine.readlineInterface;
589
+ if (rl === null) {
590
+ throw new Error("Engine readline interface not available. Call engine.start() first.");
591
+ }
592
+ this.readerActive = true;
593
+ this.lineHandler = (line) => this.handleLine(line);
594
+ rl.on("line", this.lineHandler);
595
+ rl.on("close", () => {
596
+ this.failAll(new Error("Engine closed stdout."));
597
+ this.readerActive = false;
598
+ });
599
+ }
600
+ stopReader() {
601
+ if (!this.readerActive) return;
602
+ const rl = this.engine.readlineInterface;
603
+ if (rl !== null && this.lineHandler !== null) {
604
+ rl.removeListener("line", this.lineHandler);
605
+ }
606
+ this.lineHandler = null;
607
+ this.readerActive = false;
608
+ }
609
+ handleLine(line) {
610
+ let reqId;
611
+ try {
612
+ const response = decodeResponse(line);
613
+ reqId = extractId(response);
614
+ const pending = this.pending.get(reqId);
615
+ if (pending === void 0) return;
616
+ this.pending.delete(reqId);
617
+ try {
618
+ const result = extractResult(response);
619
+ pending.resolve(result);
620
+ } catch (err) {
621
+ pending.reject(err);
622
+ }
623
+ } catch (err) {
624
+ if (err instanceof ProtocolError) {
625
+ try {
626
+ const raw = JSON.parse(line.trim());
627
+ reqId = Number(raw.id ?? -1);
628
+ } catch {
629
+ reqId = -1;
630
+ }
631
+ const pending = this.pending.get(reqId);
632
+ if (pending !== void 0) {
633
+ this.pending.delete(reqId);
634
+ pending.reject(err);
635
+ }
636
+ }
637
+ }
638
+ }
639
+ failAll(err) {
640
+ for (const pending of this.pending.values()) {
641
+ pending.reject(err);
642
+ }
643
+ this.pending.clear();
644
+ }
645
+ async sendRequest(method, params, timeoutMs) {
646
+ const resolvedTimeout = resolveTimeoutMs(timeoutMs);
647
+ if (!this.readerActive) {
648
+ return Promise.race([
649
+ this.engine.sendRequest(method, params),
650
+ makeTimeoutPromise(method, resolvedTimeout)
651
+ ]);
652
+ }
653
+ const cp = this.engine.childProcess;
654
+ if (cp === null || cp.stdin === null) {
655
+ throw new Error("Engine process not started.");
656
+ }
657
+ let capturedReqId;
658
+ const requestPromise = new Promise((resolve2, reject) => {
659
+ this.writeChain = this.writeChain.then(() => {
660
+ this.requestId += 1;
661
+ const reqId = this.requestId;
662
+ capturedReqId = reqId;
663
+ this.pending.set(reqId, { resolve: resolve2, reject });
664
+ const requestStr = encodeRequest(reqId, method, params);
665
+ cp.stdin.write(requestStr, (err) => {
666
+ if (err) {
667
+ this.pending.delete(reqId);
668
+ reject(err);
669
+ }
670
+ });
671
+ });
672
+ });
673
+ const timeoutPromise = makeTimeoutPromise(method, resolvedTimeout);
674
+ return Promise.race([requestPromise, timeoutPromise]).catch((err) => {
675
+ if (err instanceof EngineTimeoutError && capturedReqId !== void 0) {
676
+ this.pending.delete(capturedReqId);
677
+ }
678
+ throw err;
679
+ });
680
+ }
681
+ async evaluateBatch(trace, assertions, options) {
682
+ if (isSimulationMode()) {
683
+ return simulationEvaluateBatch(assertions);
684
+ }
685
+ const params = {
686
+ trace,
687
+ assertions: [...assertions]
688
+ };
689
+ const raw = await this.sendRequest(
690
+ "evaluate_batch",
691
+ params,
692
+ options?.timeout
693
+ );
694
+ return raw;
695
+ }
696
+ async submitPluginResult(traceId2, pluginName, assertionId2, status, score, explanation, options) {
697
+ const result = {
698
+ assertion_id: assertionId2,
699
+ status,
700
+ score,
701
+ explanation,
702
+ cost: 0,
703
+ duration_ms: 0
704
+ };
705
+ const params = {
706
+ trace_id: traceId2,
707
+ plugin_name: pluginName,
708
+ assertion_id: assertionId2,
709
+ result
710
+ };
711
+ const raw = await this.sendRequest(
712
+ "submit_plugin_result",
713
+ params,
714
+ options?.timeout
715
+ );
716
+ return Boolean(raw?.accepted ?? false);
717
+ }
718
+ };
719
+
720
+ // src/trace.ts
721
+ var import_node_crypto = require("crypto");
722
+ var TraceBuilder = class {
723
+ traceId;
724
+ agentId;
725
+ input;
726
+ steps = [];
727
+ output;
728
+ metadata;
729
+ parentTraceId;
730
+ constructor(agentId2) {
731
+ this.traceId = `trc_${(0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12)}`;
732
+ this.agentId = agentId2;
733
+ }
734
+ setTraceId(traceId2) {
735
+ this.traceId = traceId2;
736
+ return this;
737
+ }
738
+ setInput(input) {
739
+ this.input = input;
740
+ return this;
741
+ }
742
+ addLlmCall(name, options) {
743
+ this.steps.push({
744
+ type: STEP_LLM_CALL,
745
+ name,
746
+ args: options?.args,
747
+ result: options?.result,
748
+ metadata: options?.metadata
749
+ });
750
+ return this;
751
+ }
752
+ addToolCall(name, options) {
753
+ this.steps.push({
754
+ type: STEP_TOOL_CALL,
755
+ name,
756
+ args: options?.args,
757
+ result: options?.result,
758
+ metadata: options?.metadata
759
+ });
760
+ return this;
761
+ }
762
+ addRetrieval(name, options) {
763
+ this.steps.push({
764
+ type: STEP_RETRIEVAL,
765
+ name,
766
+ args: options?.args,
767
+ result: options?.result,
768
+ metadata: options?.metadata
769
+ });
770
+ return this;
771
+ }
772
+ addStep(step) {
773
+ this.steps.push(step);
774
+ return this;
775
+ }
776
+ setOutput(output) {
777
+ this.output = output;
778
+ return this;
779
+ }
780
+ setMetadata(metadata) {
781
+ this.metadata = metadata;
782
+ return this;
783
+ }
784
+ getTraceId() {
785
+ return this.traceId;
786
+ }
787
+ setParentTraceId(parentId) {
788
+ this.parentTraceId = parentId;
789
+ return this;
790
+ }
791
+ build() {
792
+ if (this.output === void 0) {
793
+ throw new Error("Trace output is required. Call setOutput() before build().");
794
+ }
795
+ return {
796
+ trace_id: this.traceId,
797
+ output: this.output,
798
+ schema_version: 1,
799
+ agent_id: this.agentId,
800
+ input: this.input,
801
+ steps: [...this.steps],
802
+ metadata: this.metadata,
803
+ parent_trace_id: this.parentTraceId
804
+ };
805
+ }
806
+ };
807
+
808
+ // src/result.ts
809
+ var AgentResult = class {
810
+ trace;
811
+ assertionResults;
812
+ totalCost;
813
+ totalDurationMs;
814
+ constructor(trace, assertionResults = [], totalCost = 0, totalDurationMs = 0) {
815
+ this.trace = trace;
816
+ this.assertionResults = assertionResults;
817
+ this.totalCost = totalCost;
818
+ this.totalDurationMs = totalDurationMs;
819
+ }
820
+ get passed() {
821
+ return this.assertionResults.every((r) => r.status === STATUS_PASS);
822
+ }
823
+ get failedAssertions() {
824
+ return this.assertionResults.filter((r) => r.status !== STATUS_PASS);
825
+ }
826
+ get hardFailures() {
827
+ return this.assertionResults.filter((r) => r.status === STATUS_HARD_FAIL);
828
+ }
829
+ get softFailures() {
830
+ return this.assertionResults.filter((r) => r.status === STATUS_SOFT_FAIL);
831
+ }
832
+ get passCount() {
833
+ return this.assertionResults.filter((r) => r.status === STATUS_PASS).length;
834
+ }
835
+ get failCount() {
836
+ return this.assertionResults.length - this.passCount;
837
+ }
838
+ };
839
+
840
+ // src/trace-tree.ts
841
+ var TraceTree = class {
842
+ root;
843
+ constructor(root) {
844
+ this.root = root;
845
+ }
846
+ get agents() {
847
+ const result = [];
848
+ this.collectAgents(this.root, result);
849
+ return result;
850
+ }
851
+ collectAgents(trace, acc) {
852
+ if (trace.agent_id != null) {
853
+ acc.push(trace.agent_id);
854
+ }
855
+ for (const step of trace.steps) {
856
+ if (step.type === STEP_AGENT_CALL && step.sub_trace != null) {
857
+ this.collectAgents(step.sub_trace, acc);
858
+ }
859
+ }
860
+ }
861
+ findAgent(agentId2) {
862
+ return this.findAgentIn(this.root, agentId2);
863
+ }
864
+ findAgentIn(trace, agentId2) {
865
+ if (trace.agent_id === agentId2) return trace;
866
+ for (const step of trace.steps) {
867
+ if (step.type === STEP_AGENT_CALL && step.sub_trace != null) {
868
+ const found = this.findAgentIn(step.sub_trace, agentId2);
869
+ if (found !== void 0) return found;
870
+ }
871
+ }
872
+ return void 0;
873
+ }
874
+ get depth() {
875
+ return this.computeDepth(this.root);
876
+ }
877
+ computeDepth(trace) {
878
+ let maxChild = -1;
879
+ for (const step of trace.steps) {
880
+ if (step.type === STEP_AGENT_CALL && step.sub_trace != null) {
881
+ const childDepth = this.computeDepth(step.sub_trace);
882
+ if (childDepth > maxChild) maxChild = childDepth;
883
+ }
884
+ }
885
+ return maxChild >= 0 ? maxChild + 1 : 0;
886
+ }
887
+ flatten() {
888
+ const result = [];
889
+ this.flattenInto(this.root, result);
890
+ return result;
891
+ }
892
+ flattenInto(trace, acc) {
893
+ acc.push(trace);
894
+ for (const step of trace.steps) {
895
+ if (step.type === STEP_AGENT_CALL && step.sub_trace != null) {
896
+ this.flattenInto(step.sub_trace, acc);
897
+ }
898
+ }
899
+ }
900
+ get delegations() {
901
+ const result = [];
902
+ this.collectDelegations(this.root, result);
903
+ return result;
904
+ }
905
+ collectDelegations(trace, acc) {
906
+ const parentId = trace.agent_id ?? "";
907
+ for (const step of trace.steps) {
908
+ if (step.type === STEP_AGENT_CALL && step.sub_trace != null) {
909
+ const childId = step.sub_trace.agent_id ?? "";
910
+ acc.push([parentId, childId]);
911
+ this.collectDelegations(step.sub_trace, acc);
912
+ }
913
+ }
914
+ }
915
+ allToolCalls() {
916
+ return this.flatten().flatMap(
917
+ (t) => t.steps.filter((step) => step.type === STEP_TOOL_CALL)
918
+ );
919
+ }
920
+ get aggregateTokens() {
921
+ return this.flatten().reduce(
922
+ (sum, t) => sum + (t.metadata?.total_tokens ?? 0),
923
+ 0
924
+ );
925
+ }
926
+ get aggregateCost() {
927
+ return this.flatten().reduce(
928
+ (sum, t) => sum + (t.metadata?.cost_usd ?? 0),
929
+ 0
930
+ );
931
+ }
932
+ get aggregateLatency() {
933
+ return this.flatten().reduce(
934
+ (sum, t) => sum + (t.metadata?.latency_ms ?? 0),
935
+ 0
936
+ );
937
+ }
938
+ };
939
+
940
+ // src/expect.ts
941
+ var import_node_crypto2 = require("crypto");
942
+ var ExpectChain = class {
943
+ _result;
944
+ _assertions = [];
945
+ constructor(result) {
946
+ this._result = result;
947
+ }
948
+ get assertions() {
949
+ return [...this._assertions];
950
+ }
951
+ get trace() {
952
+ return this._result.trace;
953
+ }
954
+ add(assertionType, spec) {
955
+ this._assertions.push({
956
+ assertion_id: `assert_${(0, import_node_crypto2.randomUUID)().replace(/-/g, "").slice(0, 8)}`,
957
+ type: assertionType,
958
+ spec
959
+ });
960
+ return this;
961
+ }
962
+ // -- Layer 1: Schema --
963
+ /**
964
+ * Assert that `output.structured` conforms to the given JSON Schema.
965
+ *
966
+ * @param schema - A JSON Schema object to validate against.
967
+ * @returns The chain for fluent composition.
968
+ *
969
+ * @example
970
+ * ```ts
971
+ * expect(result).outputMatchesSchema({ type: "object", required: ["answer"] });
972
+ * ```
973
+ */
974
+ outputMatchesSchema(schema) {
975
+ return this.add(TYPE_SCHEMA, { target: "output.structured", schema });
976
+ }
977
+ /**
978
+ * Assert that a specific output field conforms to the given JSON Schema.
979
+ *
980
+ * @param field - Dot-delimited path under `output` (e.g. `"structured.items"`).
981
+ * @param schema - A JSON Schema object to validate against.
982
+ * @returns The chain for fluent composition.
983
+ *
984
+ * @example
985
+ * ```ts
986
+ * expect(result).outputFieldMatchesSchema("structured.items", { type: "array" });
987
+ * ```
988
+ */
989
+ outputFieldMatchesSchema(field, schema) {
990
+ return this.add(TYPE_SCHEMA, { target: `output.${field}`, schema });
991
+ }
992
+ /**
993
+ * Assert that a named tool's arguments conform to the given JSON Schema.
994
+ *
995
+ * @param toolName - The tool name to match in `steps`.
996
+ * @param schema - A JSON Schema object to validate against.
997
+ * @returns The chain for fluent composition.
998
+ *
999
+ * @example
1000
+ * ```ts
1001
+ * expect(result).toolArgsMatchSchema("search", { type: "object", required: ["query"] });
1002
+ * ```
1003
+ */
1004
+ toolArgsMatchSchema(toolName, schema) {
1005
+ return this.add(TYPE_SCHEMA, {
1006
+ target: `steps[?name=='${toolName}'].args`,
1007
+ schema
1008
+ });
1009
+ }
1010
+ /**
1011
+ * Assert that a named tool's result conforms to the given JSON Schema.
1012
+ *
1013
+ * @param toolName - The tool name to match in `steps`.
1014
+ * @param schema - A JSON Schema object to validate against.
1015
+ * @returns The chain for fluent composition.
1016
+ *
1017
+ * @example
1018
+ * ```ts
1019
+ * expect(result).toolResultMatchesSchema("search", { type: "object" });
1020
+ * ```
1021
+ */
1022
+ toolResultMatchesSchema(toolName, schema) {
1023
+ return this.add(TYPE_SCHEMA, {
1024
+ target: `steps[?name=='${toolName}'].result`,
1025
+ schema
1026
+ });
1027
+ }
1028
+ // -- Layer 2: Constraints --
1029
+ /**
1030
+ * Assert total cost (in USD) is at or below `maxCost`.
1031
+ *
1032
+ * @param maxCost - Maximum allowed cost in USD.
1033
+ * @param opts.soft - When `true` the failure is non-blocking.
1034
+ * @returns The chain for fluent composition.
1035
+ *
1036
+ * @example
1037
+ * ```ts
1038
+ * expect(result).costUnder(0.05);
1039
+ * expect(result).costUnder(0.05, { soft: true });
1040
+ * ```
1041
+ */
1042
+ costUnder(maxCost, opts) {
1043
+ return this.add(TYPE_CONSTRAINT, {
1044
+ field: "metadata.cost_usd",
1045
+ operator: "lte",
1046
+ value: maxCost,
1047
+ soft: opts?.soft ?? false
1048
+ });
1049
+ }
1050
+ /**
1051
+ * Assert total latency is at or below `maxMs` milliseconds.
1052
+ *
1053
+ * @param maxMs - Maximum allowed latency in milliseconds.
1054
+ * @param opts.soft - When `true` the failure is non-blocking.
1055
+ * @returns The chain for fluent composition.
1056
+ *
1057
+ * @example
1058
+ * ```ts
1059
+ * expect(result).latencyUnder(2000);
1060
+ * ```
1061
+ */
1062
+ latencyUnder(maxMs, opts) {
1063
+ return this.add(TYPE_CONSTRAINT, {
1064
+ field: "metadata.latency_ms",
1065
+ operator: "lte",
1066
+ value: maxMs,
1067
+ soft: opts?.soft ?? false
1068
+ });
1069
+ }
1070
+ /**
1071
+ * Assert total token usage is at or below `maxTokens`.
1072
+ *
1073
+ * @param maxTokens - Maximum allowed token count.
1074
+ * @param opts.soft - When `true` the failure is non-blocking.
1075
+ * @returns The chain for fluent composition.
1076
+ *
1077
+ * @example
1078
+ * ```ts
1079
+ * expect(result).tokensUnder(500);
1080
+ * ```
1081
+ */
1082
+ tokensUnder(maxTokens, opts) {
1083
+ return this.add(TYPE_CONSTRAINT, {
1084
+ field: "metadata.total_tokens",
1085
+ operator: "lte",
1086
+ value: maxTokens,
1087
+ soft: opts?.soft ?? false
1088
+ });
1089
+ }
1090
+ /**
1091
+ * Assert total token usage is between `minTokens` and `maxTokens` (inclusive).
1092
+ *
1093
+ * @param minTokens - Minimum allowed token count.
1094
+ * @param maxTokens - Maximum allowed token count.
1095
+ * @param opts.soft - When `true` the failure is non-blocking.
1096
+ * @returns The chain for fluent composition.
1097
+ *
1098
+ * @example
1099
+ * ```ts
1100
+ * expect(result).tokensBetween(100, 500);
1101
+ * ```
1102
+ */
1103
+ tokensBetween(minTokens, maxTokens, opts) {
1104
+ return this.add(TYPE_CONSTRAINT, {
1105
+ field: "metadata.total_tokens",
1106
+ operator: "between",
1107
+ min: minTokens,
1108
+ max: maxTokens,
1109
+ soft: opts?.soft ?? false
1110
+ });
1111
+ }
1112
+ /**
1113
+ * Assert the number of steps satisfies the given comparison.
1114
+ *
1115
+ * @param operator - Comparison operator (e.g. `"eq"`, `"lte"`, `"gte"`).
1116
+ * @param value - The reference count to compare against.
1117
+ * @param opts.soft - When `true` the failure is non-blocking.
1118
+ * @returns The chain for fluent composition.
1119
+ *
1120
+ * @example
1121
+ * ```ts
1122
+ * expect(result).stepCount("lte", 5);
1123
+ * ```
1124
+ */
1125
+ stepCount(operator, value, opts) {
1126
+ return this.add(TYPE_CONSTRAINT, {
1127
+ field: "steps.length",
1128
+ operator,
1129
+ value,
1130
+ soft: opts?.soft ?? false
1131
+ });
1132
+ }
1133
+ /**
1134
+ * Assert the number of tool-call steps satisfies the given comparison.
1135
+ *
1136
+ * @param operator - Comparison operator (e.g. `"eq"`, `"lte"`, `"gte"`).
1137
+ * @param value - The reference count to compare against.
1138
+ * @param opts.soft - When `true` the failure is non-blocking.
1139
+ * @returns The chain for fluent composition.
1140
+ *
1141
+ * @example
1142
+ * ```ts
1143
+ * expect(result).toolCallCount("gte", 1);
1144
+ * ```
1145
+ */
1146
+ toolCallCount(operator, value, opts) {
1147
+ return this.add(TYPE_CONSTRAINT, {
1148
+ field: "steps[?type=='tool_call'].length",
1149
+ operator,
1150
+ value,
1151
+ soft: opts?.soft ?? false
1152
+ });
1153
+ }
1154
+ /**
1155
+ * Generic constraint assertion on any field.
1156
+ *
1157
+ * @param field - Dot-delimited path into the trace (e.g. `"metadata.cost_usd"`).
1158
+ * @param operator - Comparison operator.
1159
+ * @param opts.value - Reference value for single-operand operators.
1160
+ * @param opts.min - Minimum for `"between"` operator.
1161
+ * @param opts.max - Maximum for `"between"` operator.
1162
+ * @param opts.soft - When `true` the failure is non-blocking.
1163
+ * @returns The chain for fluent composition.
1164
+ *
1165
+ * @example
1166
+ * ```ts
1167
+ * expect(result).constraint("metadata.cost_usd", "lte", { value: 0.1 });
1168
+ * ```
1169
+ */
1170
+ constraint(field, operator, opts) {
1171
+ const spec = {
1172
+ field,
1173
+ operator,
1174
+ soft: opts?.soft ?? false
1175
+ };
1176
+ if (opts?.value !== void 0) spec.value = opts.value;
1177
+ if (opts?.min !== void 0) spec.min = opts.min;
1178
+ if (opts?.max !== void 0) spec.max = opts.max;
1179
+ return this.add(TYPE_CONSTRAINT, spec);
1180
+ }
1181
+ // -- Layer 3: Trace --
1182
+ /**
1183
+ * Assert that tools were called in the given order (non-contiguous allowed).
1184
+ *
1185
+ * @param tools - Ordered list of tool names expected.
1186
+ * @param opts.soft - When `true` the failure is non-blocking.
1187
+ * @returns The chain for fluent composition.
1188
+ *
1189
+ * @example
1190
+ * ```ts
1191
+ * expect(result).toolsCalledInOrder(["search", "write"]);
1192
+ * ```
1193
+ */
1194
+ toolsCalledInOrder(tools, opts) {
1195
+ return this.add(TYPE_TRACE, {
1196
+ check: "contains_in_order",
1197
+ tools,
1198
+ soft: opts?.soft ?? false
1199
+ });
1200
+ }
1201
+ /**
1202
+ * Assert that tools were called in exact contiguous order.
1203
+ *
1204
+ * @param tools - Exact ordered list of tool names.
1205
+ * @param opts.soft - When `true` the failure is non-blocking.
1206
+ * @returns The chain for fluent composition.
1207
+ *
1208
+ * @example
1209
+ * ```ts
1210
+ * expect(result).toolsCalledExactly(["search", "summarize", "respond"]);
1211
+ * ```
1212
+ */
1213
+ toolsCalledExactly(tools, opts) {
1214
+ return this.add(TYPE_TRACE, {
1215
+ check: "exact_order",
1216
+ tools,
1217
+ soft: opts?.soft ?? false
1218
+ });
1219
+ }
1220
+ /**
1221
+ * Assert a tool is not called more than `maxRepetitions` times consecutively.
1222
+ *
1223
+ * @param tool - The tool name to check.
1224
+ * @param maxRepetitions - Maximum allowed consecutive calls (default `1`).
1225
+ * @param opts.soft - When `true` the failure is non-blocking.
1226
+ * @returns The chain for fluent composition.
1227
+ *
1228
+ * @example
1229
+ * ```ts
1230
+ * expect(result).noToolLoops("fetch", 2);
1231
+ * ```
1232
+ */
1233
+ noToolLoops(tool, maxRepetitions = 1, opts) {
1234
+ return this.add(TYPE_TRACE, {
1235
+ check: "loop_detection",
1236
+ tool,
1237
+ max_repetitions: maxRepetitions,
1238
+ soft: opts?.soft ?? false
1239
+ });
1240
+ }
1241
+ /**
1242
+ * Assert no tool is called more than once.
1243
+ *
1244
+ * @param opts.soft - When `true` the failure is non-blocking.
1245
+ * @returns The chain for fluent composition.
1246
+ *
1247
+ * @example
1248
+ * ```ts
1249
+ * expect(result).noDuplicateTools();
1250
+ * ```
1251
+ */
1252
+ noDuplicateTools(opts) {
1253
+ return this.add(TYPE_TRACE, { check: "no_duplicates", soft: opts?.soft ?? false });
1254
+ }
1255
+ /**
1256
+ * Assert that all listed tools were called at least once.
1257
+ *
1258
+ * @param tools - Tool names that must appear in the trace.
1259
+ * @param opts.soft - When `true` the failure is non-blocking.
1260
+ * @returns The chain for fluent composition.
1261
+ *
1262
+ * @example
1263
+ * ```ts
1264
+ * expect(result).requiredTools(["search", "respond"]);
1265
+ * ```
1266
+ */
1267
+ requiredTools(tools, opts) {
1268
+ return this.add(TYPE_TRACE, {
1269
+ check: "required_tools",
1270
+ tools,
1271
+ soft: opts?.soft ?? false
1272
+ });
1273
+ }
1274
+ /**
1275
+ * Assert that none of the listed tools were called.
1276
+ *
1277
+ * @param tools - Tool names that must not appear in the trace.
1278
+ * @param opts.soft - When `true` the failure is non-blocking.
1279
+ * @returns The chain for fluent composition.
1280
+ *
1281
+ * @example
1282
+ * ```ts
1283
+ * expect(result).forbiddenTools(["delete_user", "drop_table"]);
1284
+ * ```
1285
+ */
1286
+ forbiddenTools(tools, opts) {
1287
+ return this.add(TYPE_TRACE, {
1288
+ check: "forbidden_tools",
1289
+ tools,
1290
+ soft: opts?.soft ?? false
1291
+ });
1292
+ }
1293
+ // -- Layer 4: Content --
1294
+ /**
1295
+ * Assert the output message contains the given string.
1296
+ *
1297
+ * @param value - Substring to search for.
1298
+ * @param opts.caseSensitive - Enable case-sensitive matching (default `false`).
1299
+ * @param opts.soft - When `true` the failure is non-blocking.
1300
+ * @returns The chain for fluent composition.
1301
+ *
1302
+ * @example
1303
+ * ```ts
1304
+ * expect(result).outputContains("refund approved");
1305
+ * ```
1306
+ */
1307
+ outputContains(value, opts) {
1308
+ return this.add(TYPE_CONTENT, {
1309
+ target: "output.message",
1310
+ check: "contains",
1311
+ value,
1312
+ case_sensitive: opts?.caseSensitive ?? false,
1313
+ soft: opts?.soft ?? false
1314
+ });
1315
+ }
1316
+ /**
1317
+ * Assert the output message does not contain the given string.
1318
+ *
1319
+ * @param value - Substring that must be absent.
1320
+ * @param opts.caseSensitive - Enable case-sensitive matching (default `false`).
1321
+ * @param opts.soft - When `true` the failure is non-blocking.
1322
+ * @returns The chain for fluent composition.
1323
+ *
1324
+ * @example
1325
+ * ```ts
1326
+ * expect(result).outputNotContains("internal error");
1327
+ * ```
1328
+ */
1329
+ outputNotContains(value, opts) {
1330
+ return this.add(TYPE_CONTENT, {
1331
+ target: "output.message",
1332
+ check: "not_contains",
1333
+ value,
1334
+ case_sensitive: opts?.caseSensitive ?? false,
1335
+ soft: opts?.soft ?? false
1336
+ });
1337
+ }
1338
+ /**
1339
+ * Assert the output message matches the given regular expression.
1340
+ *
1341
+ * @param pattern - Regex pattern string.
1342
+ * @param opts.soft - When `true` the failure is non-blocking.
1343
+ * @returns The chain for fluent composition.
1344
+ *
1345
+ * @example
1346
+ * ```ts
1347
+ * expect(result).outputMatchesRegex("order #\\d{5}");
1348
+ * ```
1349
+ */
1350
+ outputMatchesRegex(pattern, opts) {
1351
+ return this.add(TYPE_CONTENT, {
1352
+ target: "output.message",
1353
+ check: "regex_match",
1354
+ value: pattern,
1355
+ soft: opts?.soft ?? false
1356
+ });
1357
+ }
1358
+ /**
1359
+ * Assert the output message contains all of the given keywords.
1360
+ *
1361
+ * @param keywords - Keywords that must all be present.
1362
+ * @param opts.caseSensitive - Enable case-sensitive matching (default `false`).
1363
+ * @param opts.soft - When `true` the failure is non-blocking.
1364
+ * @returns The chain for fluent composition.
1365
+ *
1366
+ * @example
1367
+ * ```ts
1368
+ * expect(result).outputHasAllKeywords(["refund", "processed"]);
1369
+ * ```
1370
+ */
1371
+ outputHasAllKeywords(keywords, opts) {
1372
+ return this.add(TYPE_CONTENT, {
1373
+ target: "output.message",
1374
+ check: "keyword_all",
1375
+ values: keywords,
1376
+ case_sensitive: opts?.caseSensitive ?? false,
1377
+ soft: opts?.soft ?? false
1378
+ });
1379
+ }
1380
+ /**
1381
+ * Assert the output message contains at least one of the given keywords.
1382
+ *
1383
+ * @param keywords - Keywords where at least one must be present.
1384
+ * @param opts.caseSensitive - Enable case-sensitive matching (default `false`).
1385
+ * @param opts.soft - When `true` the failure is non-blocking.
1386
+ * @returns The chain for fluent composition.
1387
+ *
1388
+ * @example
1389
+ * ```ts
1390
+ * expect(result).outputHasAnyKeyword(["yes", "confirmed"]);
1391
+ * ```
1392
+ */
1393
+ outputHasAnyKeyword(keywords, opts) {
1394
+ return this.add(TYPE_CONTENT, {
1395
+ target: "output.message",
1396
+ check: "keyword_any",
1397
+ values: keywords,
1398
+ case_sensitive: opts?.caseSensitive ?? false,
1399
+ soft: opts?.soft ?? false
1400
+ });
1401
+ }
1402
+ /**
1403
+ * Assert the output message contains none of the forbidden terms.
1404
+ *
1405
+ * @param terms - Terms that must not appear in the output.
1406
+ * @returns The chain for fluent composition.
1407
+ *
1408
+ * @example
1409
+ * ```ts
1410
+ * expect(result).outputForbids(["password", "api_key"]);
1411
+ * ```
1412
+ */
1413
+ outputForbids(terms) {
1414
+ return this.add(TYPE_CONTENT, {
1415
+ target: "output.message",
1416
+ check: "forbidden",
1417
+ values: terms
1418
+ });
1419
+ }
1420
+ /**
1421
+ * Generic content-contains check on any target path.
1422
+ *
1423
+ * @param target - Dot-delimited path into the trace.
1424
+ * @param value - Substring to search for.
1425
+ * @param opts.caseSensitive - Enable case-sensitive matching (default `false`).
1426
+ * @param opts.soft - When `true` the failure is non-blocking.
1427
+ * @returns The chain for fluent composition.
1428
+ *
1429
+ * @example
1430
+ * ```ts
1431
+ * expect(result).contentContains("steps[0].result.text", "success");
1432
+ * ```
1433
+ */
1434
+ contentContains(target, value, opts) {
1435
+ return this.add(TYPE_CONTENT, {
1436
+ target,
1437
+ check: "contains",
1438
+ value,
1439
+ case_sensitive: opts?.caseSensitive ?? false,
1440
+ soft: opts?.soft ?? false
1441
+ });
1442
+ }
1443
+ // -- Layer 5: Embedding Similarity --
1444
+ /**
1445
+ * Assert the output is semantically similar to a reference string via embeddings.
1446
+ *
1447
+ * @param reference - The reference text to compare against.
1448
+ * @param opts.threshold - Minimum cosine similarity (default `0.8`).
1449
+ * @param opts.model - Override the embedding model.
1450
+ * @param opts.soft - When `true` the failure is non-blocking.
1451
+ * @returns The chain for fluent composition.
1452
+ *
1453
+ * @example
1454
+ * ```ts
1455
+ * expect(result).outputSimilarTo("The order has been refunded", { threshold: 0.85 });
1456
+ * ```
1457
+ */
1458
+ outputSimilarTo(reference, opts) {
1459
+ return this.add(TYPE_EMBEDDING, {
1460
+ target: "output.message",
1461
+ reference,
1462
+ threshold: opts?.threshold ?? 0.8,
1463
+ model: opts?.model,
1464
+ soft: opts?.soft ?? false
1465
+ });
1466
+ }
1467
+ // -- Layer 6: LLM Judge --
1468
+ /**
1469
+ * Assert the output passes LLM judge evaluation against given criteria.
1470
+ *
1471
+ * @param criteria - Natural language description of what makes a good response.
1472
+ * @param opts.rubric - Rubric name (default `"default"`).
1473
+ * @param opts.threshold - Minimum passing score (default `0.8`).
1474
+ * @param opts.model - Override the judge model.
1475
+ * @param opts.soft - When `true` the failure is non-blocking.
1476
+ * @returns The chain for fluent composition.
1477
+ *
1478
+ * @example
1479
+ * ```ts
1480
+ * expect(result).passesJudge("Response is polite and helpful", { threshold: 0.9 });
1481
+ * ```
1482
+ */
1483
+ passesJudge(criteria, opts) {
1484
+ return this.add(TYPE_LLM_JUDGE, {
1485
+ target: "output.message",
1486
+ criteria,
1487
+ rubric: opts?.rubric ?? "default",
1488
+ threshold: opts?.threshold ?? 0.8,
1489
+ model: opts?.model,
1490
+ soft: opts?.soft ?? false
1491
+ });
1492
+ }
1493
+ // -- Layer 7: Trace Tree (Multi-Agent) --
1494
+ /**
1495
+ * Assert that a specific agent was called in the trace tree.
1496
+ *
1497
+ * @param agentId - The agent identifier to look for.
1498
+ * @param opts.soft - When `true` the failure is non-blocking.
1499
+ * @returns The chain for fluent composition.
1500
+ *
1501
+ * @example
1502
+ * ```ts
1503
+ * expect(result).agentCalled("summarizer");
1504
+ * ```
1505
+ */
1506
+ agentCalled(agentId2, opts) {
1507
+ return this.add(TYPE_TRACE_TREE, {
1508
+ check: "agent_called",
1509
+ agent_id: agentId2,
1510
+ soft: opts?.soft ?? false
1511
+ });
1512
+ }
1513
+ /**
1514
+ * Assert the trace tree delegation depth does not exceed `maxDepth`.
1515
+ *
1516
+ * @param maxDepth - Maximum allowed delegation depth.
1517
+ * @param opts.soft - When `true` the failure is non-blocking.
1518
+ * @returns The chain for fluent composition.
1519
+ *
1520
+ * @example
1521
+ * ```ts
1522
+ * expect(result).delegationDepth(3);
1523
+ * ```
1524
+ */
1525
+ delegationDepth(maxDepth, opts) {
1526
+ return this.add(TYPE_TRACE_TREE, {
1527
+ check: "delegation_depth",
1528
+ max_depth: maxDepth,
1529
+ soft: opts?.soft ?? false
1530
+ });
1531
+ }
1532
+ /**
1533
+ * Assert a sub-agent's output contains the given string.
1534
+ *
1535
+ * @param agentId - The agent whose output to check.
1536
+ * @param value - Substring to search for.
1537
+ * @param opts.caseSensitive - Enable case-sensitive matching (default `false`).
1538
+ * @param opts.soft - When `true` the failure is non-blocking.
1539
+ * @returns The chain for fluent composition.
1540
+ *
1541
+ * @example
1542
+ * ```ts
1543
+ * expect(result).agentOutputContains("summarizer", "key findings");
1544
+ * ```
1545
+ */
1546
+ agentOutputContains(agentId2, value, opts) {
1547
+ return this.add(TYPE_TRACE_TREE, {
1548
+ check: "agent_output_contains",
1549
+ agent_id: agentId2,
1550
+ value,
1551
+ case_sensitive: opts?.caseSensitive ?? false,
1552
+ soft: opts?.soft ?? false
1553
+ });
1554
+ }
1555
+ /**
1556
+ * Assert data flows from one agent's output to another agent's input.
1557
+ *
1558
+ * @param fromAgent - Source agent ID.
1559
+ * @param toAgent - Destination agent ID.
1560
+ * @param field - The data field that must flow between agents.
1561
+ * @param opts.soft - When `true` the failure is non-blocking.
1562
+ * @returns The chain for fluent composition.
1563
+ *
1564
+ * @example
1565
+ * ```ts
1566
+ * expect(result).crossAgentDataFlow("researcher", "writer", "findings");
1567
+ * ```
1568
+ */
1569
+ crossAgentDataFlow(fromAgent, toAgent, field, opts) {
1570
+ return this.add(TYPE_TRACE_TREE, {
1571
+ check: "cross_agent_data_flow",
1572
+ from_agent: fromAgent,
1573
+ to_agent: toAgent,
1574
+ field,
1575
+ soft: opts?.soft ?? false
1576
+ });
1577
+ }
1578
+ /**
1579
+ * Assert agent delegations follow the specified transitions.
1580
+ *
1581
+ * @param transitions - Array of `[fromAgent, toAgent]` pairs.
1582
+ * @param opts.soft - When `true` the failure is non-blocking.
1583
+ * @returns The chain for fluent composition.
1584
+ *
1585
+ * @example
1586
+ * ```ts
1587
+ * expect(result).followsTransitions([["root", "planner"], ["planner", "executor"]]);
1588
+ * ```
1589
+ */
1590
+ followsTransitions(transitions, opts) {
1591
+ return this.add(TYPE_TRACE_TREE, {
1592
+ check: "follows_transitions",
1593
+ transitions,
1594
+ soft: opts?.soft ?? false
1595
+ });
1596
+ }
1597
+ /**
1598
+ * Assert aggregate cost across the entire trace tree is at or below `maxCost`.
1599
+ *
1600
+ * @param maxCost - Maximum allowed aggregate cost in USD.
1601
+ * @param opts.soft - When `true` the failure is non-blocking.
1602
+ * @returns The chain for fluent composition.
1603
+ *
1604
+ * @example
1605
+ * ```ts
1606
+ * expect(result).aggregateCostUnder(0.50);
1607
+ * ```
1608
+ */
1609
+ aggregateCostUnder(maxCost, opts) {
1610
+ return this.add(TYPE_TRACE_TREE, {
1611
+ check: "aggregate_cost",
1612
+ operator: "lte",
1613
+ value: maxCost,
1614
+ soft: opts?.soft ?? false
1615
+ });
1616
+ }
1617
+ /**
1618
+ * Assert aggregate tokens across the entire trace tree is at or below `maxTokens`.
1619
+ *
1620
+ * @param maxTokens - Maximum allowed aggregate token count.
1621
+ * @param opts.soft - When `true` the failure is non-blocking.
1622
+ * @returns The chain for fluent composition.
1623
+ *
1624
+ * @example
1625
+ * ```ts
1626
+ * expect(result).aggregateTokensUnder(10000);
1627
+ * ```
1628
+ */
1629
+ aggregateTokensUnder(maxTokens, opts) {
1630
+ return this.add(TYPE_TRACE_TREE, {
1631
+ check: "aggregate_tokens",
1632
+ operator: "lte",
1633
+ value: maxTokens,
1634
+ soft: opts?.soft ?? false
1635
+ });
1636
+ }
1637
+ /**
1638
+ * Assert `agentA` started before `agentB` in the trace tree.
1639
+ *
1640
+ * @param agentA - The agent expected to run first.
1641
+ * @param agentB - The agent expected to run second.
1642
+ * @param opts.soft - When `true` the failure is non-blocking.
1643
+ * @returns The chain for fluent composition.
1644
+ *
1645
+ * @example
1646
+ * ```ts
1647
+ * expect(result).agentOrderedBefore("planner", "executor");
1648
+ * ```
1649
+ */
1650
+ agentOrderedBefore(agentA, agentB, opts) {
1651
+ return this.add(TYPE_TRACE_TREE, {
1652
+ check: "agent_ordered_before",
1653
+ agent_a: agentA,
1654
+ agent_b: agentB,
1655
+ soft: opts?.soft ?? false
1656
+ });
1657
+ }
1658
+ /**
1659
+ * Assert `agentA` and `agentB` ran concurrently (overlapping wall-clock time).
1660
+ *
1661
+ * @param agentA - First agent ID.
1662
+ * @param agentB - Second agent ID.
1663
+ * @param opts.soft - When `true` the failure is non-blocking.
1664
+ * @returns The chain for fluent composition.
1665
+ *
1666
+ * @example
1667
+ * ```ts
1668
+ * expect(result).agentsOverlap("worker-1", "worker-2");
1669
+ * ```
1670
+ */
1671
+ agentsOverlap(agentA, agentB, opts) {
1672
+ return this.add(TYPE_TRACE_TREE, {
1673
+ check: "agents_overlap",
1674
+ agent_a: agentA,
1675
+ agent_b: agentB,
1676
+ soft: opts?.soft ?? false
1677
+ });
1678
+ }
1679
+ /**
1680
+ * Assert a specific agent's wall-clock duration is under `maxMs` milliseconds.
1681
+ *
1682
+ * @param agentId - The agent to check.
1683
+ * @param maxMs - Maximum allowed wall-clock time in milliseconds.
1684
+ * @param opts.soft - When `true` the failure is non-blocking.
1685
+ * @returns The chain for fluent composition.
1686
+ *
1687
+ * @example
1688
+ * ```ts
1689
+ * expect(result).agentWallTimeUnder("summarizer", 5000);
1690
+ * ```
1691
+ */
1692
+ agentWallTimeUnder(agentId2, maxMs, opts) {
1693
+ return this.add(TYPE_TRACE_TREE, {
1694
+ check: "agent_wall_time_under",
1695
+ agent_id: agentId2,
1696
+ max_ms: maxMs,
1697
+ soft: opts?.soft ?? false
1698
+ });
1699
+ }
1700
+ /**
1701
+ * Assert agents ran in ordered groups (parallel within each group, sequential across groups).
1702
+ *
1703
+ * @param groups - Array of agent-ID arrays. Each sub-array is a parallel group.
1704
+ * @param opts.soft - When `true` the failure is non-blocking.
1705
+ * @returns The chain for fluent composition.
1706
+ *
1707
+ * @example
1708
+ * ```ts
1709
+ * expect(result).orderedAgents([["planner"], ["worker-1", "worker-2"], ["aggregator"]]);
1710
+ * ```
1711
+ */
1712
+ orderedAgents(groups, opts) {
1713
+ return this.add(TYPE_TRACE_TREE, {
1714
+ check: "ordered_agents",
1715
+ groups,
1716
+ soft: opts?.soft ?? false
1717
+ });
1718
+ }
1719
+ // -- Layer 8: Plugin --
1720
+ /**
1721
+ * Assert via a registered plugin (Layer 8).
1722
+ *
1723
+ * @param pluginId - Identifier of the plugin registered with the engine.
1724
+ * @param config - Plugin-specific configuration passed at evaluation time.
1725
+ * @param opts.soft - When `true` the failure is non-blocking.
1726
+ * @returns The chain for fluent composition.
1727
+ *
1728
+ * @example
1729
+ * ```ts
1730
+ * expect(result).plugin("custom-safety-check", { threshold: 0.95 });
1731
+ * ```
1732
+ */
1733
+ plugin(pluginId, config2, opts) {
1734
+ const spec = { plugin_id: pluginId, soft: opts?.soft ?? false };
1735
+ if (config2 !== void 0) spec.config = config2;
1736
+ return this.add(TYPE_PLUGIN, spec);
1737
+ }
1738
+ // -- TraceTree Analytics (P9 parity) --
1739
+ /**
1740
+ * Assert aggregate latency across the trace tree is at or below `maxMs`.
1741
+ *
1742
+ * @param maxMs - Maximum allowed aggregate latency in milliseconds.
1743
+ * @param opts.soft - When `true` the failure is non-blocking.
1744
+ * @returns The chain for fluent composition.
1745
+ *
1746
+ * @example
1747
+ * ```ts
1748
+ * expect(result).aggregateLatencyUnder(5000);
1749
+ * ```
1750
+ */
1751
+ aggregateLatencyUnder(maxMs, opts) {
1752
+ return this.add(TYPE_TRACE_TREE, {
1753
+ check: "aggregate_latency",
1754
+ operator: "lte",
1755
+ value: maxMs,
1756
+ soft: opts?.soft ?? false
1757
+ });
1758
+ }
1759
+ /**
1760
+ * Assert that all specified tools were called across the entire trace tree.
1761
+ *
1762
+ * @param toolNames - Tool names that must appear somewhere in the tree.
1763
+ * @param opts.soft - When `true` the failure is non-blocking.
1764
+ * @returns The chain for fluent composition.
1765
+ *
1766
+ * @example
1767
+ * ```ts
1768
+ * expect(result).allToolsCalled(["search", "summarize"]);
1769
+ * ```
1770
+ */
1771
+ allToolsCalled(toolNames, opts) {
1772
+ return this.add(TYPE_TRACE_TREE, {
1773
+ check: "all_tools_called",
1774
+ tools: toolNames,
1775
+ soft: opts?.soft ?? false
1776
+ });
1777
+ }
1778
+ };
1779
+ function attestExpect(result) {
1780
+ if (result instanceof AgentResult) {
1781
+ return new ExpectChain(result);
1782
+ }
1783
+ return new ExpectChain(new AgentResult(result));
1784
+ }
1785
+
1786
+ // src/context.ts
1787
+ var import_node_async_hooks = require("async_hooks");
1788
+ var activeBuilder = new import_node_async_hooks.AsyncLocalStorage();
1789
+
1790
+ // src/agent.ts
1791
+ var Agent = class {
1792
+ name;
1793
+ fn;
1794
+ constructor(name, fn) {
1795
+ this.name = name;
1796
+ this.fn = fn;
1797
+ }
1798
+ run(args = {}) {
1799
+ if (this.fn === void 0) {
1800
+ throw new Error("No agent function provided. Pass fn to Agent().");
1801
+ }
1802
+ const builder = new TraceBuilder(this.name);
1803
+ builder.setInput(args);
1804
+ const output = activeBuilder.run(builder, () => this.fn(builder, args));
1805
+ this.setOutput(builder, output);
1806
+ return new AgentResult(builder.build());
1807
+ }
1808
+ async arun(args = {}) {
1809
+ if (this.fn === void 0) {
1810
+ throw new Error("No agent function provided. Pass fn to Agent().");
1811
+ }
1812
+ const builder = new TraceBuilder(this.name);
1813
+ builder.setInput(args);
1814
+ const output = await activeBuilder.run(builder, async () => this.fn(builder, args));
1815
+ this.setOutput(builder, output);
1816
+ return new AgentResult(builder.build());
1817
+ }
1818
+ setOutput(builder, output) {
1819
+ if (output !== null && output !== void 0 && typeof output === "object" && !Array.isArray(output)) {
1820
+ builder.setOutput(output);
1821
+ } else if (output !== void 0) {
1822
+ builder.setOutput({ result: output });
1823
+ } else {
1824
+ builder.setOutput({ result: null });
1825
+ }
1826
+ }
1827
+ withTrace(trace) {
1828
+ return new AgentResult(trace);
1829
+ }
1830
+ };
1831
+ function agent(name, fn) {
1832
+ const wrapped = new Agent(name, fn);
1833
+ const wrapper = (args) => {
1834
+ return wrapped.run(args ?? {});
1835
+ };
1836
+ wrapper.agent = wrapped;
1837
+ return wrapper;
1838
+ }
1839
+
1840
+ // src/delegate.ts
1841
+ async function delegate(agentId2, fn) {
1842
+ const parent = activeBuilder.getStore();
1843
+ if (parent === void 0) {
1844
+ throw new Error(
1845
+ "delegate() must be used within an Agent.run() context. No active TraceBuilder found."
1846
+ );
1847
+ }
1848
+ const child = new TraceBuilder(agentId2);
1849
+ child.setParentTraceId(parent.getTraceId());
1850
+ await activeBuilder.run(child, async () => {
1851
+ await fn(child);
1852
+ });
1853
+ const childTrace = child.build();
1854
+ parent.addStep({
1855
+ type: STEP_AGENT_CALL,
1856
+ name: agentId2,
1857
+ args: void 0,
1858
+ result: childTrace.output,
1859
+ sub_trace: childTrace
1860
+ });
1861
+ }
1862
+
1863
+ // src/tier.ts
1864
+ var TIER_1 = 1;
1865
+ var TIER_2 = 2;
1866
+ var TIER_3 = 3;
1867
+ function tier(level) {
1868
+ return (fn) => {
1869
+ fn._attest_tier = level;
1870
+ return fn;
1871
+ };
1872
+ }
1873
+
1874
+ // src/plugins.ts
1875
+ var PluginRegistry = class {
1876
+ plugins = /* @__PURE__ */ new Map();
1877
+ register(name, plugin) {
1878
+ const pluginType = plugin.pluginType;
1879
+ let typeMap = this.plugins.get(pluginType);
1880
+ if (typeMap === void 0) {
1881
+ typeMap = /* @__PURE__ */ new Map();
1882
+ this.plugins.set(pluginType, typeMap);
1883
+ }
1884
+ typeMap.set(name, plugin);
1885
+ }
1886
+ get(pluginType, name) {
1887
+ return this.plugins.get(pluginType)?.get(name);
1888
+ }
1889
+ listPlugins(pluginType) {
1890
+ if (pluginType !== void 0) {
1891
+ const typeMap = this.plugins.get(pluginType);
1892
+ return typeMap !== void 0 ? [...typeMap.keys()] : [];
1893
+ }
1894
+ const result = [];
1895
+ for (const [ptype, typeMap] of this.plugins) {
1896
+ for (const pname of typeMap.keys()) {
1897
+ result.push(`${ptype}/${pname}`);
1898
+ }
1899
+ }
1900
+ return result;
1901
+ }
1902
+ };
1903
+ async function executePluginAssertion(plugin, trace, spec, client, traceId2, assertionId2, timeoutMs = 3e4) {
1904
+ const resultPromise = Promise.resolve(plugin.execute(trace, spec));
1905
+ const timeoutPromise = new Promise((_, reject) => {
1906
+ setTimeout(() => reject(new Error(`Plugin '${plugin.name}' timed out after ${timeoutMs}ms`)), timeoutMs);
1907
+ });
1908
+ const result = await Promise.race([resultPromise, timeoutPromise]);
1909
+ await client.submitPluginResult(
1910
+ traceId2,
1911
+ plugin.name,
1912
+ assertionId2,
1913
+ result.status,
1914
+ result.score,
1915
+ result.explanation
1916
+ );
1917
+ return result;
1918
+ }
1919
+
1920
+ // src/continuous.ts
1921
+ var import_node_events = require("events");
1922
+ var DEFAULT_QUEUE_SIZE = 1e3;
1923
+ function resolveQueueSize() {
1924
+ const raw = process.env["ATTEST_CONTINUOUS_QUEUE_SIZE"];
1925
+ if (raw !== void 0 && raw !== "") {
1926
+ const parsed = Number(raw);
1927
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
1928
+ }
1929
+ return DEFAULT_QUEUE_SIZE;
1930
+ }
1931
+ var Sampler = class {
1932
+ rate;
1933
+ constructor(rate) {
1934
+ if (rate < 0 || rate > 1) {
1935
+ throw new Error(`sample_rate must be in [0.0, 1.0], got ${rate}`);
1936
+ }
1937
+ this.rate = rate;
1938
+ }
1939
+ shouldSample() {
1940
+ return Math.random() < this.rate;
1941
+ }
1942
+ };
1943
+ var AlertDispatcher = class extends import_node_events.EventEmitter {
1944
+ webhookUrl;
1945
+ slackUrl;
1946
+ constructor(webhookUrl, slackUrl) {
1947
+ super();
1948
+ this.webhookUrl = webhookUrl;
1949
+ this.slackUrl = slackUrl;
1950
+ }
1951
+ async dispatch(alert) {
1952
+ this.emit("alert", alert);
1953
+ const tasks = [];
1954
+ if (this.webhookUrl) {
1955
+ tasks.push(this.postJson(this.webhookUrl, alert));
1956
+ }
1957
+ if (this.slackUrl) {
1958
+ const text = `[attest] drift alert -- type=${alert.drift_type} score=${alert.score} trace_id=${alert.trace_id}`;
1959
+ tasks.push(this.postJson(this.slackUrl, { text }));
1960
+ }
1961
+ const results = await Promise.allSettled(tasks);
1962
+ for (const result of results) {
1963
+ if (result.status === "rejected") {
1964
+ this.emit("alertError", result.reason);
1965
+ }
1966
+ }
1967
+ }
1968
+ async postJson(url, payload) {
1969
+ const response = await fetch(url, {
1970
+ method: "POST",
1971
+ headers: { "Content-Type": "application/json" },
1972
+ body: JSON.stringify(payload),
1973
+ signal: AbortSignal.timeout(1e4)
1974
+ });
1975
+ if (!response.ok) {
1976
+ throw new Error(`POST to ${url} returned ${response.status}`);
1977
+ }
1978
+ }
1979
+ };
1980
+ var ContinuousEvalRunner = class {
1981
+ client;
1982
+ assertions;
1983
+ sampler;
1984
+ dispatcher;
1985
+ queue = [];
1986
+ maxSize;
1987
+ running = false;
1988
+ loopTimer = null;
1989
+ constructor(client, assertions, options) {
1990
+ this.client = client;
1991
+ this.assertions = assertions;
1992
+ this.sampler = new Sampler(options?.sampleRate ?? 1);
1993
+ this.dispatcher = new AlertDispatcher(options?.alertWebhook, options?.alertSlackUrl);
1994
+ this.maxSize = options?.maxSize ?? resolveQueueSize();
1995
+ }
1996
+ get alertEmitter() {
1997
+ return this.dispatcher;
1998
+ }
1999
+ async evaluateTrace(trace) {
2000
+ if (!this.sampler.shouldSample()) return null;
2001
+ return this.client.evaluateBatch(trace, this.assertions);
2002
+ }
2003
+ submit(trace) {
2004
+ if (this.queue.length >= this.maxSize) {
2005
+ return false;
2006
+ }
2007
+ this.queue.push(trace);
2008
+ return true;
2009
+ }
2010
+ start() {
2011
+ if (this.running) return;
2012
+ this.running = true;
2013
+ this.scheduleNext();
2014
+ }
2015
+ stop() {
2016
+ this.running = false;
2017
+ if (this.loopTimer !== null) {
2018
+ clearTimeout(this.loopTimer);
2019
+ this.loopTimer = null;
2020
+ }
2021
+ }
2022
+ get queueLength() {
2023
+ return this.queue.length;
2024
+ }
2025
+ get isRunning() {
2026
+ return this.running;
2027
+ }
2028
+ scheduleNext() {
2029
+ if (!this.running) return;
2030
+ this.loopTimer = setTimeout(async () => {
2031
+ if (!this.running) return;
2032
+ const trace = this.queue.shift();
2033
+ if (trace !== void 0) {
2034
+ try {
2035
+ await this.evaluateTrace(trace);
2036
+ } catch {
2037
+ }
2038
+ }
2039
+ this.scheduleNext();
2040
+ }, this.queue.length > 0 ? 0 : 100);
2041
+ }
2042
+ };
2043
+
2044
+ // src/adapters/manual.ts
2045
+ var ManualAdapter = class {
2046
+ agentId;
2047
+ constructor(agentId2) {
2048
+ this.agentId = agentId2;
2049
+ }
2050
+ capture(builderFn) {
2051
+ const builder = new TraceBuilder(this.agentId);
2052
+ builderFn(builder);
2053
+ return builder.build();
2054
+ }
2055
+ createBuilder() {
2056
+ return new TraceBuilder(this.agentId);
2057
+ }
2058
+ };
2059
+
2060
+ // src/adapters/openai.ts
2061
+ var OpenAIAdapter = class {
2062
+ agentId;
2063
+ constructor(agentId2) {
2064
+ this.agentId = agentId2;
2065
+ }
2066
+ traceFromResponse(response, options) {
2067
+ const builder = new TraceBuilder(this.agentId);
2068
+ if (options?.inputMessages) {
2069
+ builder.setInput({ messages: options.inputMessages });
2070
+ }
2071
+ const message = response.choices[0].message;
2072
+ const completionText = message.content ?? "";
2073
+ const stepArgs = {};
2074
+ if (response.model !== void 0) stepArgs.model = response.model;
2075
+ const stepResult = { completion: completionText };
2076
+ if (response.usage?.total_tokens !== void 0) {
2077
+ stepResult.tokens = response.usage.total_tokens;
2078
+ }
2079
+ builder.addLlmCall("completion", { args: stepArgs, result: stepResult });
2080
+ if (message.tool_calls) {
2081
+ for (const tc of message.tool_calls) {
2082
+ builder.addToolCall(tc.function.name, {
2083
+ args: { arguments: tc.function.arguments }
2084
+ });
2085
+ }
2086
+ }
2087
+ builder.setOutput({
2088
+ message: completionText,
2089
+ structured: options?.structuredOutput ?? {}
2090
+ });
2091
+ builder.setMetadata({
2092
+ total_tokens: response.usage?.total_tokens,
2093
+ cost_usd: options?.costUsd,
2094
+ latency_ms: options?.latencyMs,
2095
+ model: response.model
2096
+ });
2097
+ return builder.build();
2098
+ }
2099
+ };
2100
+
2101
+ // src/adapters/anthropic.ts
2102
+ var AnthropicAdapter = class {
2103
+ agentId;
2104
+ constructor(agentId2) {
2105
+ this.agentId = agentId2;
2106
+ }
2107
+ traceFromResponse(response, options) {
2108
+ const builder = new TraceBuilder(this.agentId);
2109
+ if (options?.inputMessages) {
2110
+ builder.setInput({ messages: options.inputMessages });
2111
+ }
2112
+ const completionParts = [];
2113
+ for (const block of response.content) {
2114
+ if (block.type === "text") {
2115
+ completionParts.push(block.text);
2116
+ } else if (block.type === "tool_use") {
2117
+ builder.addToolCall(block.name, {
2118
+ args: block.input
2119
+ });
2120
+ }
2121
+ }
2122
+ const completionText = completionParts.join("\n");
2123
+ const stepArgs = {};
2124
+ if (response.model !== void 0) stepArgs.model = response.model;
2125
+ builder.addLlmCall("completion", { args: stepArgs, result: { completion: completionText } });
2126
+ builder.setOutput({ message: completionText });
2127
+ let totalTokens;
2128
+ if (response.usage) {
2129
+ totalTokens = response.usage.input_tokens + response.usage.output_tokens;
2130
+ }
2131
+ builder.setMetadata({
2132
+ total_tokens: totalTokens,
2133
+ cost_usd: options?.costUsd,
2134
+ latency_ms: options?.latencyMs,
2135
+ model: response.model
2136
+ });
2137
+ return builder.build();
2138
+ }
2139
+ };
2140
+
2141
+ // src/adapters/gemini.ts
2142
+ var GeminiAdapter = class {
2143
+ agentId;
2144
+ constructor(agentId2) {
2145
+ this.agentId = agentId2;
2146
+ }
2147
+ traceFromResponse(response, options) {
2148
+ const builder = new TraceBuilder(this.agentId);
2149
+ if (options?.inputText) {
2150
+ builder.setInput({ text: options.inputText });
2151
+ }
2152
+ let completionText = "";
2153
+ if (response.text != null) {
2154
+ completionText = response.text;
2155
+ } else if (response.candidates && response.candidates.length > 0) {
2156
+ completionText = response.candidates[0].content.parts.filter((p) => p.text != null).map((p) => p.text).join("");
2157
+ }
2158
+ if (response.candidates && response.candidates.length > 0) {
2159
+ for (const part of response.candidates[0].content.parts) {
2160
+ if (part.functionCall) {
2161
+ builder.addToolCall(part.functionCall.name, {
2162
+ args: part.functionCall.args ?? {}
2163
+ });
2164
+ }
2165
+ }
2166
+ }
2167
+ builder.addLlmCall("completion", { result: { completion: completionText } });
2168
+ builder.setOutput({ message: completionText });
2169
+ builder.setMetadata({
2170
+ cost_usd: options?.costUsd,
2171
+ latency_ms: options?.latencyMs,
2172
+ model: options?.model
2173
+ });
2174
+ return builder.build();
2175
+ }
2176
+ };
2177
+
2178
+ // src/adapters/ollama.ts
2179
+ var OllamaAdapter = class {
2180
+ agentId;
2181
+ constructor(agentId2) {
2182
+ this.agentId = agentId2;
2183
+ }
2184
+ traceFromResponse(response, options) {
2185
+ const builder = new TraceBuilder(this.agentId);
2186
+ if (options?.inputMessages) {
2187
+ builder.setInput({ messages: options.inputMessages });
2188
+ }
2189
+ const completionText = response.message?.content ?? "";
2190
+ builder.addLlmCall("completion", {
2191
+ args: { model: response.model ?? "" },
2192
+ result: { completion: completionText }
2193
+ });
2194
+ builder.setOutput({ message: completionText });
2195
+ let totalTokens;
2196
+ if (response.eval_count !== void 0 && response.prompt_eval_count !== void 0) {
2197
+ totalTokens = response.eval_count + response.prompt_eval_count;
2198
+ }
2199
+ builder.setMetadata({
2200
+ total_tokens: totalTokens,
2201
+ latency_ms: options?.latencyMs,
2202
+ model: response.model
2203
+ });
2204
+ return builder.build();
2205
+ }
2206
+ };
2207
+
2208
+ // src/adapters/otel.ts
2209
+ var OTelAdapter = class _OTelAdapter {
2210
+ agentId;
2211
+ constructor(agentId2) {
2212
+ this.agentId = agentId2;
2213
+ }
2214
+ static fromSpans(spans, agentId2) {
2215
+ const adapter = new _OTelAdapter(agentId2);
2216
+ return adapter.buildTrace(spans);
2217
+ }
2218
+ buildTrace(spans) {
2219
+ const sorted = [...spans].sort((a, b) => {
2220
+ const aTime = a.startTime[0] * 1e9 + a.startTime[1];
2221
+ const bTime = b.startTime[0] * 1e9 + b.startTime[1];
2222
+ return aTime - bTime;
2223
+ });
2224
+ const builder = new TraceBuilder(this.agentId);
2225
+ const rootSpan = this.findRootSpan(sorted);
2226
+ if (rootSpan) {
2227
+ const traceId2 = rootSpan.spanContext().traceId;
2228
+ if (traceId2) {
2229
+ builder.setTraceId(`otel_${traceId2.slice(0, 16)}`);
2230
+ }
2231
+ }
2232
+ let outputMessage = "";
2233
+ let totalTokens;
2234
+ let latencyMs;
2235
+ let model;
2236
+ for (const span of sorted) {
2237
+ const attrs = span.attributes ?? {};
2238
+ const stepType = this.classifySpan(attrs, span.name);
2239
+ if (stepType === "llm_call") {
2240
+ const [stepArgs, stepResult] = this.extractLlmStep(attrs);
2241
+ builder.addLlmCall(span.name, {
2242
+ args: stepArgs,
2243
+ result: stepResult,
2244
+ metadata: this.spanMetadata(span)
2245
+ });
2246
+ const completion = attrs["gen_ai.completion"];
2247
+ if (completion) outputMessage = String(completion);
2248
+ const inputTokens = Number(attrs["gen_ai.usage.input_tokens"] ?? 0);
2249
+ const outputTokens = Number(attrs["gen_ai.usage.output_tokens"] ?? 0);
2250
+ const spanTokens = inputTokens + outputTokens;
2251
+ if (spanTokens > 0) totalTokens = (totalTokens ?? 0) + spanTokens;
2252
+ if (model === void 0) {
2253
+ const responseModel = attrs["gen_ai.response.model"];
2254
+ const requestModel = attrs["gen_ai.request.model"];
2255
+ if (responseModel) model = String(responseModel);
2256
+ else if (requestModel) model = String(requestModel);
2257
+ }
2258
+ } else if (stepType === "tool_call") {
2259
+ const [stepArgs, stepResult] = this.extractToolStep(attrs);
2260
+ const toolName = String(attrs["gen_ai.tool.name"] ?? span.name);
2261
+ builder.addToolCall(toolName, {
2262
+ args: stepArgs,
2263
+ result: stepResult,
2264
+ metadata: this.spanMetadata(span)
2265
+ });
2266
+ }
2267
+ }
2268
+ if (rootSpan) {
2269
+ const startNs = rootSpan.startTime[0] * 1e9 + rootSpan.startTime[1];
2270
+ const endNs = rootSpan.endTime[0] * 1e9 + rootSpan.endTime[1];
2271
+ latencyMs = Math.floor((endNs - startNs) / 1e6);
2272
+ }
2273
+ builder.setOutput({ message: outputMessage });
2274
+ builder.setMetadata({ total_tokens: totalTokens, latency_ms: latencyMs, model });
2275
+ return builder.build();
2276
+ }
2277
+ findRootSpan(spans) {
2278
+ for (const span of spans) {
2279
+ if (!span.parentSpanId) return span;
2280
+ }
2281
+ return spans[0];
2282
+ }
2283
+ classifySpan(attrs, name) {
2284
+ const op = String(attrs["gen_ai.operation.name"] ?? "");
2285
+ if (op === "chat" || op === "completion" || op === "generate_content" || "gen_ai.completion" in attrs) {
2286
+ return "llm_call";
2287
+ }
2288
+ if (op === "tool" || "gen_ai.tool.name" in attrs) {
2289
+ return "tool_call";
2290
+ }
2291
+ const lower = name.toLowerCase();
2292
+ if (lower.includes("completion") || lower.includes("chat")) return "llm_call";
2293
+ if (lower.includes("tool")) return "tool_call";
2294
+ return void 0;
2295
+ }
2296
+ extractLlmStep(attrs) {
2297
+ const args = {};
2298
+ const result = {};
2299
+ if ("gen_ai.request.model" in attrs) args.model = String(attrs["gen_ai.request.model"]);
2300
+ if ("gen_ai.system" in attrs) args.system = String(attrs["gen_ai.system"]);
2301
+ if ("gen_ai.prompt" in attrs) args.prompt = String(attrs["gen_ai.prompt"]);
2302
+ if ("gen_ai.completion" in attrs) result.completion = String(attrs["gen_ai.completion"]);
2303
+ if ("gen_ai.usage.input_tokens" in attrs) result.input_tokens = Number(attrs["gen_ai.usage.input_tokens"]);
2304
+ if ("gen_ai.usage.output_tokens" in attrs) result.output_tokens = Number(attrs["gen_ai.usage.output_tokens"]);
2305
+ if ("gen_ai.response.model" in attrs) result.model = String(attrs["gen_ai.response.model"]);
2306
+ return [args, result];
2307
+ }
2308
+ extractToolStep(attrs) {
2309
+ const args = {};
2310
+ const result = {};
2311
+ if ("gen_ai.tool.call.id" in attrs) args.call_id = String(attrs["gen_ai.tool.call.id"]);
2312
+ if ("gen_ai.tool.parameters" in attrs) args.parameters = attrs["gen_ai.tool.parameters"];
2313
+ if ("gen_ai.tool.output" in attrs) result.output = attrs["gen_ai.tool.output"];
2314
+ return [args, result];
2315
+ }
2316
+ spanMetadata(span) {
2317
+ const startNs = span.startTime[0] * 1e9 + span.startTime[1];
2318
+ const endNs = span.endTime[0] * 1e9 + span.endTime[1];
2319
+ return { duration_ms: Math.floor((endNs - startNs) / 1e6) };
2320
+ }
2321
+ };
2322
+
2323
+ // src/adapters/langchain.ts
2324
+ var LangChainAdapter = class {
2325
+ agentId;
2326
+ llmCalls = [];
2327
+ toolCalls = [];
2328
+ chainOutput = "";
2329
+ startTime = 0;
2330
+ constructor(agentId2) {
2331
+ this.agentId = agentId2;
2332
+ }
2333
+ /**
2334
+ * Reset accumulated state for a new trace capture session.
2335
+ */
2336
+ reset() {
2337
+ this.llmCalls.length = 0;
2338
+ this.toolCalls.length = 0;
2339
+ this.chainOutput = "";
2340
+ this.startTime = 0;
2341
+ }
2342
+ /**
2343
+ * Call this when a chain starts (maps to `handleChainStart`).
2344
+ */
2345
+ handleChainStart() {
2346
+ if (this.startTime === 0) {
2347
+ this.startTime = Date.now();
2348
+ }
2349
+ }
2350
+ /**
2351
+ * Call this when an LLM call completes (maps to `handleLLMEnd`).
2352
+ */
2353
+ handleLLMEnd(output) {
2354
+ const text = output.generations[0]?.[0]?.text ?? "";
2355
+ const tokens = output.llmOutput?.["tokenUsage"];
2356
+ const model = output.llmOutput?.["modelName"];
2357
+ this.llmCalls.push({
2358
+ name: "completion",
2359
+ text,
2360
+ tokens: tokens?.totalTokens,
2361
+ model
2362
+ });
2363
+ }
2364
+ /**
2365
+ * Call this when a tool call completes (maps to `handleToolEnd`).
2366
+ */
2367
+ handleToolEnd(output, metadata) {
2368
+ this.toolCalls.push({
2369
+ name: metadata?.name ?? "unknown_tool",
2370
+ output
2371
+ });
2372
+ }
2373
+ /**
2374
+ * Call this when a chain completes (maps to `handleChainEnd`).
2375
+ */
2376
+ handleChainEnd(output) {
2377
+ const text = output["output"] ?? output["text"] ?? output["result"];
2378
+ if (typeof text === "string") {
2379
+ this.chainOutput = text;
2380
+ }
2381
+ }
2382
+ /**
2383
+ * Build a Trace from accumulated callback events.
2384
+ *
2385
+ * @param options.costUsd - Total cost override.
2386
+ * @param options.model - Model name override.
2387
+ * @returns A finalized Trace object.
2388
+ */
2389
+ buildTrace(options) {
2390
+ const builder = new TraceBuilder(this.agentId);
2391
+ const latencyMs = this.startTime > 0 ? Date.now() - this.startTime : void 0;
2392
+ let totalTokens;
2393
+ for (const llm of this.llmCalls) {
2394
+ const args = {};
2395
+ if (llm.model ?? options?.model) args.model = llm.model ?? options?.model;
2396
+ const result = { completion: llm.text };
2397
+ if (llm.tokens !== void 0) {
2398
+ result.tokens = llm.tokens;
2399
+ totalTokens = (totalTokens ?? 0) + llm.tokens;
2400
+ }
2401
+ builder.addLlmCall(llm.name, { args, result });
2402
+ }
2403
+ for (const tool of this.toolCalls) {
2404
+ builder.addToolCall(tool.name, {
2405
+ result: { output: tool.output }
2406
+ });
2407
+ }
2408
+ const outputMessage = this.chainOutput || (this.llmCalls.length > 0 ? this.llmCalls[this.llmCalls.length - 1].text : "");
2409
+ builder.setOutput({ message: outputMessage });
2410
+ builder.setMetadata({
2411
+ total_tokens: totalTokens,
2412
+ cost_usd: options?.costUsd,
2413
+ latency_ms: latencyMs,
2414
+ model: options?.model ?? this.llmCalls[0]?.model
2415
+ });
2416
+ return builder.build();
2417
+ }
2418
+ };
2419
+ // Annotate the CommonJS export names for ESM import in node:
2420
+ 0 && (module.exports = {
2421
+ Agent,
2422
+ AgentResult,
2423
+ AlertDispatcher,
2424
+ AnthropicAdapter,
2425
+ AttestClient,
2426
+ ContinuousEvalRunner,
2427
+ ENGINE_VERSION,
2428
+ ERR_ASSERTION_ERROR,
2429
+ ERR_ENGINE_ERROR,
2430
+ ERR_INVALID_TRACE,
2431
+ ERR_PROVIDER_ERROR,
2432
+ ERR_SESSION_ERROR,
2433
+ ERR_TIMEOUT,
2434
+ EngineManager,
2435
+ EngineTimeoutError,
2436
+ ExpectChain,
2437
+ GeminiAdapter,
2438
+ LangChainAdapter,
2439
+ ManualAdapter,
2440
+ OTelAdapter,
2441
+ OllamaAdapter,
2442
+ OpenAIAdapter,
2443
+ PluginRegistry,
2444
+ ProtocolError,
2445
+ STATUS_HARD_FAIL,
2446
+ STATUS_PASS,
2447
+ STATUS_SOFT_FAIL,
2448
+ STEP_AGENT_CALL,
2449
+ STEP_LLM_CALL,
2450
+ STEP_RETRIEVAL,
2451
+ STEP_TOOL_CALL,
2452
+ Sampler,
2453
+ TIER_1,
2454
+ TIER_2,
2455
+ TIER_3,
2456
+ TYPE_CONSTRAINT,
2457
+ TYPE_CONTENT,
2458
+ TYPE_EMBEDDING,
2459
+ TYPE_LLM_JUDGE,
2460
+ TYPE_PLUGIN,
2461
+ TYPE_SCHEMA,
2462
+ TYPE_TRACE,
2463
+ TYPE_TRACE_TREE,
2464
+ TraceBuilder,
2465
+ TraceTree,
2466
+ VERSION,
2467
+ activeBuilder,
2468
+ agent,
2469
+ agentId,
2470
+ assertionId,
2471
+ attestExpect,
2472
+ config,
2473
+ decodeResponse,
2474
+ delegate,
2475
+ encodeRequest,
2476
+ executePluginAssertion,
2477
+ extractId,
2478
+ extractResult,
2479
+ isSimulationMode,
2480
+ resetConfig,
2481
+ tier,
2482
+ traceId
2483
+ });
2484
+ //# sourceMappingURL=index.cjs.map