@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.
- package/dist/cjs/index.cjs +1256 -200
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +437 -24
- package/dist/cjs/proto/index.cjs +21 -0
- package/dist/cjs/proto/index.cjs.map +1 -1
- package/dist/cjs/proto/index.d.cts +91 -2
- package/dist/esm/cli.d.ts +6 -1
- package/dist/esm/cli.js +310 -20
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/index.d.ts +437 -24
- package/dist/esm/index.js +1222 -199
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/proto/index.d.ts +91 -2
- package/dist/esm/proto/index.js +16 -0
- package/dist/esm/proto/index.js.map +1 -1
- package/package.json +3 -3
package/dist/cjs/index.d.cts
CHANGED
|
@@ -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.
|
|
9
|
-
declare const ENGINE_VERSION = "1.0.0-rc.
|
|
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
|
-
|
|
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
|
-
|
|
1167
|
-
|
|
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
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
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,
|
|
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 };
|
package/dist/cjs/proto/index.cjs
CHANGED
|
@@ -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,
|