@attest-ai/core 1.0.0-rc.1 → 1.0.0-rc.3

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.
@@ -1,12 +1,12 @@
1
- import { InitializeResult, ProtocolLogger, ProtocolDiagnostic, Trace, Assertion, EvaluateBatchResult, DriftReport, SimulatePersona, ConversationMessage, SimulateFaultConfig, Step, AssertionResult, Outcome } from './proto/index.cjs';
2
- export { AgentId, AssertionId, AssertionSpec, BiasProbe, ConstraintSpec, ContentSpec, ERR_ASSERTION_ERROR, ERR_ENGINE_ERROR, ERR_INVALID_TRACE, ERR_PROVIDER_ERROR, ERR_SESSION_ERROR, ERR_TIMEOUT, EmbeddingSpec, EngineTimeoutError, ErrorData, EvaluateBatchParams, FailureClass, GenerateUserMessageParams, GenerateUserMessageResult, InitializeParams, JudgeAgreement, JudgeMetadata, LlmJudgeSpec, OUTCOME_FAIL, OUTCOME_PASS, OUTCOME_SKIP, PluginSpec, ProtocolDesyncError, ProtocolDiagnosticBuffer, ProtocolDiagnosticKind, ProtocolError, QueryDriftParams, QueryDriftResult, REASON_MISSING_EVIDENCE, REASON_PROVIDER_NOT_CONFIGURED, REASON_PROVIDER_UNAVAILABLE, REASON_SHORT_CIRCUITED, REASON_SIMULATION, RPCError, RPCRequest, RPCResponse, STATUS_HARD_FAIL, STATUS_NOT_EVALUATED, STATUS_PASS, STATUS_SOFT_FAIL, STEP_AGENT_CALL, STEP_LLM_CALL, STEP_RETRIEVAL, STEP_TOOL_CALL, SchemaSpec, ShutdownResult, SubmitPluginResultParams, TYPE_CONSTRAINT, TYPE_CONTENT, TYPE_EMBEDDING, TYPE_LLM_JUDGE, TYPE_PLUGIN, TYPE_SCHEMA, TYPE_TRACE, TYPE_TRACE_TREE, TraceId, TraceMetadata, TraceSpec, TraceTreeSpec, agentId, assertionId, decodeResponse, encodeRequest, extractId, extractResult, layerForType, previewLine, traceId } from './proto/index.cjs';
1
+ import { InitializeResult, ProtocolLogger, ProtocolDiagnostic, Trace, Assertion, BatchBudget, EvaluateBatchResult, DriftReport, SimulatePersona, ConversationMessage, SimulateFaultConfig, Step, AssertionResult, Usage, Outcome } from './proto/index.cjs';
2
+ export { AgentId, AssertionId, AssertionSpec, BiasProbe, ConstraintSpec, ContentSpec, ERR_ASSERTION_ERROR, ERR_ENGINE_ERROR, ERR_INVALID_TRACE, ERR_PROVIDER_ERROR, ERR_SESSION_ERROR, ERR_TIMEOUT, EffectSpec, EmbeddingSpec, EngineTimeoutError, ErrorData, EvaluateBatchParams, Exchange, FailureClass, GenerateUserMessageParams, GenerateUserMessageResult, Handoff, InitializeParams, JudgeAgreement, JudgeMetadata, LlmJudgeSpec, OTLPConversionError, OUTCOME_FAIL, OUTCOME_PASS, OUTCOME_SKIP, PluginSpec, ProtocolDesyncError, ProtocolDiagnosticBuffer, ProtocolDiagnosticKind, ProtocolError, QueryDriftParams, QueryDriftResult, REASON_BUDGET_EXHAUSTED, REASON_JUDGE_ABSTAINED, REASON_MISSING_EVIDENCE, REASON_PROVIDER_NOT_CONFIGURED, REASON_PROVIDER_UNAVAILABLE, REASON_REPLAY_MISS, REASON_SHORT_CIRCUITED, REASON_SIMULATION, RPCError, RPCRequest, RPCResponse, STATUS_HARD_FAIL, STATUS_NOT_EVALUATED, STATUS_PASS, STATUS_SOFT_FAIL, STEP_AGENT_CALL, STEP_LLM_CALL, STEP_RETRIEVAL, STEP_TOOL_CALL, SchemaSpec, ShutdownResult, StepError, SubmitPluginResultParams, TYPE_CONSTRAINT, TYPE_CONTENT, TYPE_EFFECT, TYPE_EMBEDDING, TYPE_LLM_JUDGE, TYPE_PLUGIN, TYPE_SCHEMA, TYPE_TRACE, TYPE_TRACE_TREE, TraceId, TraceMetadata, TraceSpec, TraceTreeSpec, Turn, agentId, assertionId, decodeResponse, encodeRequest, extractId, extractResult, layerForType, previewLine, traceId } from './proto/index.cjs';
3
3
  import { ChildProcess } from 'node:child_process';
4
4
  import { Interface } from 'node:readline';
5
5
  import { AsyncLocalStorage } from 'node:async_hooks';
6
6
  import { EventEmitter } from 'node:events';
7
7
 
8
- declare const VERSION = "1.0.0-rc.1";
9
- declare const ENGINE_VERSION = "1.0.0-rc.1";
8
+ declare const VERSION = "1.0.0-rc.3";
9
+ declare const ENGINE_VERSION = "1.0.0-rc.3";
10
10
 
11
11
  declare class EngineManager {
12
12
  private enginePath;
@@ -83,6 +83,7 @@ declare class AttestClient {
83
83
  sendRequest(method: string, params: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
84
84
  evaluateBatch(trace: Trace, assertions: readonly Assertion[], options?: {
85
85
  timeout?: number;
86
+ budget?: BatchBudget;
86
87
  }): Promise<EvaluateBatchResult>;
87
88
  submitPluginResult(traceId: string, pluginName: string, assertionId: string, status: string, score: number, explanation: string, options?: {
88
89
  timeout?: number;
@@ -146,7 +147,9 @@ declare class AgentResult {
146
147
  readonly assertionResults: readonly AssertionResult[];
147
148
  readonly totalCost: number;
148
149
  readonly totalDurationMs: number;
149
- constructor(trace: Trace, assertionResults?: readonly AssertionResult[], totalCost?: number, totalDurationMs?: number);
150
+ /** Attest model usage of the evaluation that produced this result. */
151
+ readonly usage: Usage;
152
+ constructor(trace: Trace, assertionResults?: readonly AssertionResult[], totalCost?: number, totalDurationMs?: number, usage?: Usage);
150
153
  /** True if every assertion has status "pass". */
151
154
  get passed(): boolean;
152
155
  /**
@@ -177,6 +180,29 @@ declare class AgentResult {
177
180
  skipReason(): string;
178
181
  }
179
182
 
183
+ /** Usage of an evaluation that made no model calls. */
184
+ declare function zeroUsage(): Usage;
185
+ /** Field-wise sum of two usages. */
186
+ declare function addUsage(a: Usage, b: Usage): Usage;
187
+ /** Field-wise sum of any number of usages; zero for none. */
188
+ declare function sumUsage(usages: Iterable<Usage>): Usage;
189
+ /**
190
+ * Validate the `usage` object of an evaluate_batch result: all nine fields
191
+ * present, non-negative, integers except the two `*_usd` amounts.
192
+ */
193
+ declare function parseUsage(raw: unknown): Usage;
194
+ /**
195
+ * "{model_calls} model calls · {tokens} tokens ({cached} cached) · ${cost} · retry cost ${retry}",
196
+ * plus refused and unpriced calls when present. Same format as the engine's
197
+ * report.FormatUsage.
198
+ */
199
+ declare function formatUsage(u: Usage): string;
200
+ /**
201
+ * The run-summary line "attest usage: …" when the session made a model call
202
+ * or refused one by budget; undefined otherwise.
203
+ */
204
+ declare function usageSummaryLine(u: Usage): string | undefined;
205
+
180
206
  /**
181
207
  * Terminal-grade rendering of Attest assertion failures.
182
208
  *
@@ -220,9 +246,54 @@ declare class TraceTree {
220
246
  get aggregateLatency(): number;
221
247
  }
222
248
 
249
+ type TrajectoryMode = "strict" | "unordered" | "subset" | "superset";
250
+ type ArgOperator = "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in";
251
+ /** A resource's records filtered by exact field values. */
252
+ type Where = Record<string, unknown>;
253
+ /**
254
+ * Effect checks against one world snapshot, from {@link ExpectChain.world}. Each method adds
255
+ * an `effect` assertion (Layer 3) to the parent chain and returns it.
256
+ */
257
+ declare class WorldChecks<C> {
258
+ private readonly _snapshot;
259
+ private readonly _add;
260
+ constructor(snapshot: Record<string, unknown> | null, add: (spec: Record<string, unknown>) => C);
261
+ private addCheck;
262
+ /**
263
+ * Assert how many records of `resource` match `where`. Give `equals`, or `atMost` and/or
264
+ * `atLeast`. A violation reads `effect violated: 2 refunds for O-1042 (expected 1)`.
265
+ *
266
+ * @throws Error when no bound is given, or `equals` is combined with another bound.
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * expect(trace).world(await world.state()).count("refunds", { equals: 1, where: { order_id: "O-1042" } });
271
+ * ```
272
+ */
273
+ count(resource: string, opts: {
274
+ equals?: number;
275
+ atMost?: number;
276
+ atLeast?: number;
277
+ where?: Where;
278
+ }): C;
279
+ /** Assert no two matching records share the same values for field(s) `by`. */
280
+ unique(resource: string, opts: {
281
+ by: string | string[];
282
+ where?: Where;
283
+ }): C;
284
+ /**
285
+ * Assert every matching record carries a distinct value in field `key` (default
286
+ * `idempotency_key`), the record field that stores the idempotency key.
287
+ */
288
+ idempotent(resource: string, opts?: {
289
+ key?: string;
290
+ where?: Where;
291
+ }): C;
292
+ }
223
293
  declare class ExpectChain {
224
294
  private readonly _result;
225
295
  private readonly _assertions;
296
+ private _worldBytes;
226
297
  constructor(result: AgentResult);
227
298
  get assertions(): Assertion[];
228
299
  get trace(): Trace;
@@ -484,6 +555,65 @@ declare class ExpectChain {
484
555
  forbiddenTools(tools: string[], opts?: {
485
556
  soft?: boolean;
486
557
  }): this;
558
+ /**
559
+ * Assert how many times a tool is called, per value of argument `per` when set.
560
+ *
561
+ * @example
562
+ * ```ts
563
+ * // fails with "issue_refund called 2× for order_id=O-1042 (max 1)"
564
+ * expect(result).toolCardinality("issue_refund", { per: "order_id", atMost: 1 });
565
+ * ```
566
+ */
567
+ toolCardinality(tool: string, opts: {
568
+ per?: string;
569
+ atMost?: number;
570
+ atLeast?: number;
571
+ soft?: boolean;
572
+ }): this;
573
+ /**
574
+ * Assert the tool-call trajectory matches `tools`: `strict` (same sequence,
575
+ * the default), `unordered` (same calls, any order), `subset` (no call
576
+ * outside `tools`) or `superset` (every call in `tools` made). Use
577
+ * {@link trajectoryPartialOrder} for ordering constraints.
578
+ */
579
+ trajectory(tools: string[], opts?: {
580
+ mode?: TrajectoryMode;
581
+ soft?: boolean;
582
+ }): this;
583
+ /**
584
+ * Assert every tool in `tools` and `order` is called and each
585
+ * `[before, after]` pair holds as in {@link toolCalledBefore}.
586
+ */
587
+ trajectoryPartialOrder(order: Array<[string, string]>, opts?: {
588
+ tools?: string[];
589
+ soft?: boolean;
590
+ }): this;
591
+ /** Assert every call to `after` has an earlier call to `before`; holds when `after` is never called. */
592
+ toolCalledBefore(before: string, after: string, opts?: {
593
+ soft?: boolean;
594
+ }): this;
595
+ /** Assert no block of `period` (1–4) tool calls repeats `minRepeats` (default 2) times in a row; A→B→A→B fails period 2. */
596
+ noToolCycles(period: number, opts?: {
597
+ minRepeats?: number;
598
+ soft?: boolean;
599
+ }): this;
600
+ /** Assert at most `maxStreak` consecutive tool calls end in error (trace v2). */
601
+ maxToolFailureStreak(maxStreak: number, opts?: {
602
+ soft?: boolean;
603
+ }): this;
604
+ /**
605
+ * Assert every call to `tool` has argument `arg` (a dot path) satisfying
606
+ * `op value`; holds when `tool` is never called.
607
+ */
608
+ toolArgSatisfies(tool: string, arg: string, op: ArgOperator, value: unknown, opts?: {
609
+ soft?: boolean;
610
+ }): this;
611
+ /**
612
+ * Check effects in a world snapshot:
613
+ * `expect(trace).world(await world.state()).count(...)`. `null` means the test ran without
614
+ * a world helper: the checks are `not_evaluated` (`missing_evidence`).
615
+ */
616
+ world(snapshot: Record<string, unknown> | null): WorldChecks<this>;
487
617
  /**
488
618
  * Assert the output message contains the given string.
489
619
  *
@@ -874,6 +1004,264 @@ declare class ExpectChain {
874
1004
  */
875
1005
  declare function attestExpect(result: AgentResult | Trace): ExpectChain;
876
1006
 
1007
+ /**
1008
+ * Capture: turn a run into a verified fixture, and fixtures into tests.
1009
+ *
1010
+ * `attest capture --name <name> -- <command>` (the engine) records a run's trace and model
1011
+ * exchanges into `tests/attest/fixtures/<name>.attest.json`. This module is the TypeScript
1012
+ * side:
1013
+ *
1014
+ * - `record()` captures the code in a callback in this process.
1015
+ * - `loadFixture()` reads a fixture (`proto/attest/v1/fixture-v1.schema.json`).
1016
+ * - `emitVitest()` writes the fixture's drafted contracts as a Vitest file, using the
1017
+ * `attestExpect()` DSL. `attest capture` and `record()` call it.
1018
+ */
1019
+
1020
+ /** A capture did not produce a fixture, or produced one that is not verified. */
1021
+ declare class CaptureError extends Error {
1022
+ /** The fixture written, when the engine wrote one. */
1023
+ readonly fixture: string | null;
1024
+ constructor(message: string, fixture?: string | null);
1025
+ }
1026
+ /** A drafted contract: an engine assertion spec plus its id and description. */
1027
+ interface Contract {
1028
+ id: string;
1029
+ kind: string;
1030
+ description: string;
1031
+ type: string;
1032
+ spec: Record<string, unknown>;
1033
+ }
1034
+ /** A contract's status on the captured trace. */
1035
+ interface ContractResult {
1036
+ contract: string;
1037
+ status: string;
1038
+ explanation: string;
1039
+ }
1040
+ /** A capture fixture (fixture-v1). */
1041
+ interface Fixture {
1042
+ name: string;
1043
+ source: {
1044
+ kind: string;
1045
+ replay_capable: boolean;
1046
+ command?: string[];
1047
+ exit_code?: number;
1048
+ };
1049
+ trace: Trace;
1050
+ exchanges: Record<string, unknown>[];
1051
+ contracts: Contract[];
1052
+ verification: {
1053
+ verified: boolean;
1054
+ expect_fail: boolean;
1055
+ trace_check: {
1056
+ ok: boolean;
1057
+ errors: number;
1058
+ warnings: number;
1059
+ };
1060
+ results: ContractResult[];
1061
+ expected_failures: string[];
1062
+ };
1063
+ world: Record<string, unknown> | null;
1064
+ }
1065
+ /** Read a capture fixture written by `attest capture` or `record()`. */
1066
+ declare function loadFixture(file: string | URL): Fixture;
1067
+ /** The `ExpectChain` method call that emits `contract`'s spec; throws when there is none. */
1068
+ declare function dslCall(contract: Contract): string;
1069
+ /**
1070
+ * Where the drafted test for a fixture goes: `tests/attest/<name>.test.ts` for
1071
+ * `tests/attest/fixtures/<name>.attest.json`.
1072
+ */
1073
+ declare function testPathFor(fixturePath: string): string;
1074
+ /**
1075
+ * Render a fixture's drafted contracts as a Vitest module.
1076
+ *
1077
+ * A verified fixture becomes a test that enforces every contract with `evaluate`. An
1078
+ * incident reproduction (`expect_fail`) becomes a test that checks, with `inspect`, that
1079
+ * the expected failures still fail and the other contracts still pass; it stays green
1080
+ * while it reproduces the incident.
1081
+ */
1082
+ declare function renderVitest(fixture: Fixture, fixturePath: string, testPath: string): string;
1083
+ /**
1084
+ * Write the drafted Vitest file for a fixture unless it already exists. Returns the path
1085
+ * written, or null when a test file is already there (re-capturing never overwrites an
1086
+ * edited test).
1087
+ */
1088
+ declare function emitVitest(fixturePath: string): string | null;
1089
+ /** A running in-process capture. */
1090
+ interface Capture {
1091
+ name: string;
1092
+ /** The variables `record()` set in `process.env` for the callback. */
1093
+ env: Record<string, string>;
1094
+ }
1095
+ interface RecordOptions {
1096
+ /** Fixture directory (default `tests/attest/fixtures`). */
1097
+ outDir?: string;
1098
+ /** Save an incident reproduction: verified when drafted contracts fail. */
1099
+ expectFail?: boolean;
1100
+ /** Trace `agent_id` (default: the first turn's agent name). */
1101
+ agentId?: string;
1102
+ /** Write the drafted Vitest file (default true). */
1103
+ emitTest?: boolean;
1104
+ /** Engine binary (default: the SDK's engine discovery). */
1105
+ enginePath?: string;
1106
+ /**
1107
+ * A `world.yaml` to host for the callback (the engine's `--world`): its base URL variable
1108
+ * (`PAYMENTS_BASE_URL`) is set for the callback and the world's final state is saved in
1109
+ * the fixture's `world` section.
1110
+ */
1111
+ world?: string;
1112
+ /**
1113
+ * Called after the callback returns and before the fixture is built; pass the tracer
1114
+ * provider's `forceFlush` so batched spans reach the receiver.
1115
+ */
1116
+ flush?: () => unknown;
1117
+ }
1118
+ interface RecordResult<T> {
1119
+ value: T;
1120
+ fixture: string;
1121
+ verified: boolean;
1122
+ testFile: string | null;
1123
+ }
1124
+ /**
1125
+ * Capture `fn` as fixture `<outDir>/<name>.attest.json`.
1126
+ *
1127
+ * Starts `attest-engine capture --serve`, which hosts the recording proxy and the
1128
+ * OTLP/HTTP receiver on 127.0.0.1, and sets `OPENAI_BASE_URL`, `ANTHROPIC_BASE_URL` and
1129
+ * `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` while `fn` runs. Model clients and the
1130
+ * OpenTelemetry exporter read these when they are constructed, so construct them inside
1131
+ * `fn`, and pass the tracer provider's `forceFlush` as `flush`. Afterwards the variables
1132
+ * are restored and the engine writes the fixture; for a verified fixture with `emitTest`
1133
+ * the drafted Vitest file is written unless one exists. If `fn` throws, the capture is
1134
+ * abandoned and no fixture is written. Captures cannot overlap.
1135
+ *
1136
+ * @throws CaptureError when another capture is running, the engine writes no fixture,
1137
+ * or the fixture is not verified (its drafted contracts did not hold; the fixture is
1138
+ * still written and no test is drafted).
1139
+ */
1140
+ declare function record<T>(name: string, fn: (capture: Capture) => T | Promise<T>, opts?: RecordOptions): Promise<RecordResult<T>>;
1141
+
1142
+ /**
1143
+ * Replay: run the agent's real code with model responses served from a fixture.
1144
+ *
1145
+ * `startReplay(name)` starts `attest-engine replay --serve`, which hosts the replay
1146
+ * proxy on 127.0.0.1, and sets `OPENAI_BASE_URL`, `ANTHROPIC_BASE_URL` and
1147
+ * `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` until `finish()`. The proxy answers every model
1148
+ * request from `<fixturesDir>/<name>.attest.json` and makes no provider call. A request
1149
+ * that matches no recording is a miss; `finish()` returns the engine's summary.
1150
+ */
1151
+ type ReplayMode = "strict" | "auto";
1152
+ type ReplayModeSetting = ReplayMode | "off";
1153
+ /** One request the agent made during the replay. */
1154
+ interface ReplayRecord {
1155
+ seq: number;
1156
+ provider: string;
1157
+ api: string;
1158
+ outcome: "replayed" | "live" | "miss";
1159
+ exchange?: number;
1160
+ message?: string;
1161
+ }
1162
+ /** What the replay session served, as the engine reports it. */
1163
+ interface ReplaySummary {
1164
+ fixture: string;
1165
+ mode: ReplayMode;
1166
+ replayed: number;
1167
+ live: number;
1168
+ misses: number;
1169
+ unused: number;
1170
+ live_cost_usd: number;
1171
+ unpriced_live_calls: number;
1172
+ records: ReplayRecord[];
1173
+ }
1174
+ /** A strict-mode replay request matched no recording. `message` is the engine's miss message. */
1175
+ declare class ReplayMissError extends Error {
1176
+ readonly summary: ReplaySummary;
1177
+ constructor(message: string, summary: ReplaySummary);
1178
+ }
1179
+ /** An auto-mode replay request matched no recording and no provider key was set: `not_evaluated: replay_miss`. */
1180
+ declare class ReplayNotEvaluatedError extends Error {
1181
+ readonly summary: ReplaySummary;
1182
+ constructor(message: string, summary: ReplaySummary);
1183
+ }
1184
+ declare class ReplayError extends Error {
1185
+ constructor(message: string);
1186
+ }
1187
+ interface ReplayOptions {
1188
+ /** Fixture directory (default `tests/attest/fixtures`). */
1189
+ fixturesDir?: string;
1190
+ /** `strict`, `auto` or `off`; default per `resolveMode`. `off` starts nothing. */
1191
+ mode?: ReplayModeSetting;
1192
+ /**
1193
+ * Pass `--no-live` to the engine: no miss is forwarded live. Default: `ATTEST_EGRESS=block`.
1194
+ * An installed egress guard always implies it.
1195
+ */
1196
+ noLive?: boolean;
1197
+ /** Engine binary (default: the SDK's engine discovery). */
1198
+ enginePath?: string;
1199
+ }
1200
+ interface ReplaySession {
1201
+ readonly name: string;
1202
+ readonly mode: ReplayModeSetting;
1203
+ /** The variables the session set in `process.env`. */
1204
+ readonly env: Record<string, string>;
1205
+ /** The summary once `finish()` has run, else `null`. */
1206
+ readonly summary: ReplaySummary | null;
1207
+ /** Stop the engine, restore the environment and return the summary (`null` for `off`). Idempotent. */
1208
+ finish(): Promise<ReplaySummary | null>;
1209
+ /** The error a miss raises (valid after `finish()`): strict => miss, auto => not evaluated. */
1210
+ error(): ReplayMissError | ReplayNotEvaluatedError | null;
1211
+ /** `finish()`, then throw `error()` if any. */
1212
+ check(): Promise<void>;
1213
+ }
1214
+ /**
1215
+ * Replay mode from `explicit`, else `ATTEST_REPLAY` (`strict|auto|off`), else `strict`
1216
+ * when `CI` is set, else `auto`.
1217
+ */
1218
+ declare function resolveMode(explicit?: ReplayModeSetting, env?: NodeJS.ProcessEnv): ReplayModeSetting;
1219
+ /** Start a replay session for fixture `name`. Sessions cannot overlap. */
1220
+ declare function startReplay(name: string, opts?: ReplayOptions): Promise<ReplaySession>;
1221
+ /** The first miss message of a summary, or `null`. */
1222
+ declare function firstMiss(summary: ReplaySummary): string | null;
1223
+ /** `N live model calls · $X.XX`, plus ` (+N unpriced)`. */
1224
+ declare function liveLine(live: number, costUsd: number, unpriced?: number): string;
1225
+
1226
+ /** A world-v1 snapshot. */
1227
+ type WorldSnapshot = Record<string, unknown>;
1228
+ declare class WorldError extends Error {
1229
+ constructor(message: string);
1230
+ }
1231
+ interface WorldOptions {
1232
+ /** Engine binary (default: the SDK's engine discovery). */
1233
+ enginePath?: string;
1234
+ }
1235
+ interface WorldSession {
1236
+ /** The absolute `world.yaml` path. */
1237
+ readonly path: string;
1238
+ /** The variable the session set in `process.env`: the world's base URL. */
1239
+ readonly env: Record<string, string>;
1240
+ /** The world's base URL. */
1241
+ readonly baseUrl: string;
1242
+ /** The current world-v1 snapshot, read from the running world. */
1243
+ state(): Promise<WorldSnapshot>;
1244
+ /** Stop the world, restore the environment and return the final snapshot. Idempotent. */
1245
+ stop(): Promise<WorldSnapshot>;
1246
+ }
1247
+ /** Host the world defined by `worldFile` until the session stops. Worlds cannot overlap. */
1248
+ declare function startWorld(worldFile: string, opts?: WorldOptions): Promise<WorldSession>;
1249
+
1250
+ declare class EgressBlockedError extends Error {
1251
+ readonly host: string;
1252
+ constructor(host: string);
1253
+ }
1254
+ declare function isProviderHost(host: string): boolean;
1255
+ /** True when `ATTEST_EGRESS=block`. */
1256
+ declare function egressBlockRequested(env?: NodeJS.ProcessEnv): boolean;
1257
+ /**
1258
+ * Install the guard. Installs are counted: the returned function releases only this
1259
+ * install (once), and the guard comes off when every install has been released.
1260
+ */
1261
+ declare function installEgressGuard(): () => void;
1262
+ /** Remove the guard now, whatever the install count. */
1263
+ declare function uninstallEgressGuard(): void;
1264
+
877
1265
  declare class Agent {
878
1266
  readonly name: string;
879
1267
  private readonly fn;
@@ -1163,27 +1551,51 @@ declare class OllamaAdapter {
1163
1551
  }): Trace;
1164
1552
  }
1165
1553
 
1166
- interface OTelSpanContext {
1167
- traceId: string;
1168
- }
1554
+ type AttributeValue = string | number | boolean | readonly (string | number | boolean | null | undefined)[];
1555
+ /** The parts of an `@opentelemetry/sdk-trace-base` `ReadableSpan` the adapter reads. */
1169
1556
  interface OTelSpan {
1170
- name: string;
1171
- startTime: [number, number];
1172
- endTime: [number, number];
1173
- attributes?: Record<string, unknown>;
1174
- parentSpanId?: string;
1175
- spanContext(): OTelSpanContext;
1557
+ readonly name: string;
1558
+ /** `[seconds, nanoseconds]` */
1559
+ readonly startTime: readonly [number, number];
1560
+ readonly endTime: readonly [number, number];
1561
+ readonly attributes?: Readonly<Record<string, AttributeValue | undefined>>;
1562
+ /** Parent span id (sdk-trace-base 1.x). */
1563
+ readonly parentSpanId?: string;
1564
+ /** Parent span context (sdk-trace-base 2.x). */
1565
+ readonly parentSpanContext?: {
1566
+ readonly spanId: string;
1567
+ };
1568
+ readonly status?: {
1569
+ readonly code: number;
1570
+ readonly message?: string;
1571
+ };
1572
+ spanContext(): {
1573
+ readonly traceId: string;
1574
+ readonly spanId: string;
1575
+ };
1176
1576
  }
1577
+ /** An OTLP/JSON export: a parsed `ExportTraceServiceRequest`, its JSON text, or its bytes. */
1578
+ type OTLPInput = Record<string, unknown> | string | Uint8Array;
1177
1579
  declare class OTelAdapter {
1178
- private readonly agentId;
1179
- constructor(agentId?: string);
1180
- static fromSpans(spans: OTelSpan[], agentId?: string): Trace;
1181
- private buildTrace;
1182
- private findRootSpan;
1183
- private classifySpan;
1184
- private extractLlmStep;
1185
- private extractToolStep;
1186
- private spanMetadata;
1580
+ /**
1581
+ * Build a trace from finished OpenTelemetry spans of one trace.
1582
+ *
1583
+ * @param agentId Trace `agent_id`; defaults to the first turn's `gen_ai.agent.name`.
1584
+ * @throws OTLPConversionError when the engine rejects the spans.
1585
+ */
1586
+ static fromSpans(spans: readonly OTelSpan[], agentId?: string): Promise<Trace>;
1587
+ /**
1588
+ * Convert an OTLP/JSON export (`resourceSpans` → `scopeSpans` → `spans`).
1589
+ *
1590
+ * @param agentId Trace `agent_id`; defaults to the first turn's `gen_ai.agent.name`.
1591
+ * @throws OTLPConversionError when the engine rejects the export (malformed JSON, invalid
1592
+ * ids or timestamps, more than one trace, non-numeric token counts, ...).
1593
+ * @throws RangeError when a parsed export holds a non-finite number.
1594
+ * @throws OTLPConversionError when the engine times out, overflows the output buffer or
1595
+ * prints no trace.
1596
+ * @throws Error when the engine cannot start.
1597
+ */
1598
+ static fromOtlp(otlp: OTLPInput, agentId?: string): Promise<Trace>;
1187
1599
  }
1188
1600
 
1189
1601
  /**
@@ -1250,4 +1662,5 @@ interface TraceAdapter {
1250
1662
  traceFromResponse(response: unknown, options?: Record<string, unknown>): Trace;
1251
1663
  }
1252
1664
 
1253
- export { ADVERSARIAL_USER, Agent, AgentResult, type AgreementResult, AlertDispatcher, type AlertPayload, AnthropicAdapter, Assertion, AssertionResult, AttestClient, type AttestClientOptions, type AttestPlugin, CONFUSED_USER, COOPERATIVE_USER, ContinuousEvalRunner, ConversationMessage, DriftReport, ENGINE_VERSION, EngineManager, EvaluateBatchResult, ExpectChain, FRIENDLY_USER, GeminiAdapter, InitializeResult, type LabelPair, type LabeledRecord, LangChainAdapter, ManualAdapter, OTelAdapter, OllamaAdapter, OpenAIAdapter, Outcome, PluginRegistry, type PluginResult, ProtocolDiagnostic, ProtocolLogger, type RenderOptions, Sampler, SimulateFaultConfig, SimulatePersona, Step, TIER_1, TIER_2, TIER_3, Trace, type TraceAdapter, TraceBuilder, TraceTree, VERSION, activeBuilder, agent, attestExpect, computeAgreement, config, delegate, executePluginAssertion, getSampleRate, isSimulationMode, loadLabelsCSV, loadLabelsJSONL, promptHash, renderAssertionFailure, renderDiagnostics, renderSummary, requireSimulationCapability, resetConfig, simulationEnvEnabled, tier };
1665
+ export { ADVERSARIAL_USER, Agent, AgentResult, AlertDispatcher, AnthropicAdapter, Assertion, AssertionResult, AttestClient, BatchBudget, CONFUSED_USER, COOPERATIVE_USER, CaptureError, ContinuousEvalRunner, ConversationMessage, DriftReport, ENGINE_VERSION, EgressBlockedError, EngineManager, EvaluateBatchResult, ExpectChain, FRIENDLY_USER, GeminiAdapter, InitializeResult, LangChainAdapter, ManualAdapter, OTelAdapter, OllamaAdapter, OpenAIAdapter, Outcome, PluginRegistry, ProtocolDiagnostic, ProtocolLogger, ReplayError, ReplayMissError, ReplayNotEvaluatedError, Sampler, SimulateFaultConfig, SimulatePersona, Step, TIER_1, TIER_2, TIER_3, Trace, TraceBuilder, TraceTree, Usage, VERSION, WorldChecks, WorldError, activeBuilder, addUsage, agent, attestExpect, computeAgreement, config, delegate, dslCall, egressBlockRequested, emitVitest, executePluginAssertion, firstMiss, formatUsage, getSampleRate, installEgressGuard, isProviderHost, isSimulationMode, liveLine, loadFixture, loadLabelsCSV, loadLabelsJSONL, parseUsage, promptHash, record, renderAssertionFailure, renderDiagnostics, renderSummary, renderVitest, requireSimulationCapability, resetConfig, resolveMode, simulationEnvEnabled, startReplay, startWorld, sumUsage, testPathFor, tier, uninstallEgressGuard, usageSummaryLine, zeroUsage };
1666
+ export type { AgreementResult, AlertPayload, AttestClientOptions, AttestPlugin, Capture, Contract, ContractResult, Fixture, LabelPair, LabeledRecord, PluginResult, RecordOptions, RecordResult, RenderOptions, ReplayMode, ReplayModeSetting, ReplayOptions, ReplayRecord, ReplaySession, ReplaySummary, TraceAdapter, WorldOptions, WorldSession, WorldSnapshot };
@@ -28,15 +28,19 @@ __export(proto_exports, {
28
28
  ERR_TIMEOUT: () => ERR_TIMEOUT,
29
29
  EngineTimeoutError: () => EngineTimeoutError,
30
30
  FailureClass: () => FailureClass,
31
+ OTLPConversionError: () => OTLPConversionError,
31
32
  OUTCOME_FAIL: () => OUTCOME_FAIL,
32
33
  OUTCOME_PASS: () => OUTCOME_PASS,
33
34
  OUTCOME_SKIP: () => OUTCOME_SKIP,
34
35
  ProtocolDesyncError: () => ProtocolDesyncError,
35
36
  ProtocolDiagnosticBuffer: () => ProtocolDiagnosticBuffer,
36
37
  ProtocolError: () => ProtocolError,
38
+ REASON_BUDGET_EXHAUSTED: () => REASON_BUDGET_EXHAUSTED,
39
+ REASON_JUDGE_ABSTAINED: () => REASON_JUDGE_ABSTAINED,
37
40
  REASON_MISSING_EVIDENCE: () => REASON_MISSING_EVIDENCE,
38
41
  REASON_PROVIDER_NOT_CONFIGURED: () => REASON_PROVIDER_NOT_CONFIGURED,
39
42
  REASON_PROVIDER_UNAVAILABLE: () => REASON_PROVIDER_UNAVAILABLE,
43
+ REASON_REPLAY_MISS: () => REASON_REPLAY_MISS,
40
44
  REASON_SHORT_CIRCUITED: () => REASON_SHORT_CIRCUITED,
41
45
  REASON_SIMULATION: () => REASON_SIMULATION,
42
46
  STATUS_HARD_FAIL: () => STATUS_HARD_FAIL,
@@ -49,6 +53,7 @@ __export(proto_exports, {
49
53
  STEP_TOOL_CALL: () => STEP_TOOL_CALL,
50
54
  TYPE_CONSTRAINT: () => TYPE_CONSTRAINT,
51
55
  TYPE_CONTENT: () => TYPE_CONTENT,
56
+ TYPE_EFFECT: () => TYPE_EFFECT,
52
57
  TYPE_EMBEDDING: () => TYPE_EMBEDDING,
53
58
  TYPE_LLM_JUDGE: () => TYPE_LLM_JUDGE,
54
59
  TYPE_PLUGIN: () => TYPE_PLUGIN,
@@ -81,12 +86,16 @@ var REASON_PROVIDER_NOT_CONFIGURED = "provider_not_configured";
81
86
  var REASON_SIMULATION = "simulation";
82
87
  var REASON_MISSING_EVIDENCE = "missing_evidence";
83
88
  var REASON_SHORT_CIRCUITED = "short_circuited";
89
+ var REASON_BUDGET_EXHAUSTED = "budget_exhausted";
90
+ var REASON_JUDGE_ABSTAINED = "judge_abstained";
91
+ var REASON_REPLAY_MISS = "replay_miss";
84
92
  var OUTCOME_PASS = "pass";
85
93
  var OUTCOME_FAIL = "fail";
86
94
  var OUTCOME_SKIP = "skip";
87
95
  var TYPE_SCHEMA = "schema";
88
96
  var TYPE_CONSTRAINT = "constraint";
89
97
  var TYPE_TRACE = "trace";
98
+ var TYPE_EFFECT = "effect";
90
99
  var TYPE_CONTENT = "content";
91
100
  var TYPE_EMBEDDING = "embedding";
92
101
  var TYPE_LLM_JUDGE = "llm_judge";
@@ -124,6 +133,7 @@ function layerForType(assertionType) {
124
133
  return 2;
125
134
  case "trace":
126
135
  case "trace_tree":
136
+ case "effect":
127
137
  return 3;
128
138
  case "content":
129
139
  return 4;
@@ -171,6 +181,12 @@ var ProtocolDesyncError = class extends Error {
171
181
  this.diagnostics = diagnostics;
172
182
  }
173
183
  };
184
+ var OTLPConversionError = class extends Error {
185
+ constructor(message) {
186
+ super(message);
187
+ this.name = "OTLPConversionError";
188
+ }
189
+ };
174
190
 
175
191
  // src/proto/diagnostics.ts
176
192
  var DEFAULT_BUFFER_SIZE = 32;
@@ -285,15 +301,19 @@ function extractId(response) {
285
301
  ERR_TIMEOUT,
286
302
  EngineTimeoutError,
287
303
  FailureClass,
304
+ OTLPConversionError,
288
305
  OUTCOME_FAIL,
289
306
  OUTCOME_PASS,
290
307
  OUTCOME_SKIP,
291
308
  ProtocolDesyncError,
292
309
  ProtocolDiagnosticBuffer,
293
310
  ProtocolError,
311
+ REASON_BUDGET_EXHAUSTED,
312
+ REASON_JUDGE_ABSTAINED,
294
313
  REASON_MISSING_EVIDENCE,
295
314
  REASON_PROVIDER_NOT_CONFIGURED,
296
315
  REASON_PROVIDER_UNAVAILABLE,
316
+ REASON_REPLAY_MISS,
297
317
  REASON_SHORT_CIRCUITED,
298
318
  REASON_SIMULATION,
299
319
  STATUS_HARD_FAIL,
@@ -306,6 +326,7 @@ function extractId(response) {
306
326
  STEP_TOOL_CALL,
307
327
  TYPE_CONSTRAINT,
308
328
  TYPE_CONTENT,
329
+ TYPE_EFFECT,
309
330
  TYPE_EMBEDDING,
310
331
  TYPE_LLM_JUDGE,
311
332
  TYPE_PLUGIN,