@attest-ai/core 1.0.0-rc.4 → 1.0.0-rc.5

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.
@@ -5,8 +5,8 @@ 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.4";
9
- declare const ENGINE_VERSION = "1.0.0-rc.4";
8
+ declare const VERSION = "1.0.0-rc.5";
9
+ declare const ENGINE_VERSION = "1.0.0-rc.5";
10
10
 
11
11
  declare class EngineManager {
12
12
  private enginePath;
@@ -1337,6 +1337,20 @@ declare class PluginRegistry {
1337
1337
  listPlugins(pluginType?: string): string[];
1338
1338
  }
1339
1339
  declare function executePluginAssertion(plugin: AttestPlugin, trace: Trace, spec: Record<string, unknown>, client: AttestClient, traceId: string, assertionId: string, timeoutMs?: number): Promise<PluginResult>;
1340
+ /** Explicitly register a plugin instance into the registry. */
1341
+ declare function registerPlugin(registry: PluginRegistry, name: string, plugin: AttestPlugin): void;
1342
+ /**
1343
+ * Discover and load plugins declared by the project's direct dependencies.
1344
+ *
1345
+ * An installed dependency declares plugins in its `package.json` as
1346
+ * `"attest": {"plugins": ["./dist/plugin.js"]}`. Each entry is imported and
1347
+ * its default export (or, without one, every export implementing the
1348
+ * plugin shape) is registered under the plugin's `name`. A failure loading
1349
+ * one entry, or reading the project's `package.json`, is logged and does not
1350
+ * raise, as with Python's `load_entrypoint_plugins`. Dependencies that are declared but not
1351
+ * installed are skipped. Returns the number of plugins loaded.
1352
+ */
1353
+ declare function loadPackagePlugins(registry: PluginRegistry, projectRoot?: string): Promise<number>;
1340
1354
 
1341
1355
  declare class Sampler {
1342
1356
  private readonly rate;
@@ -1439,6 +1453,132 @@ declare const ADVERSARIAL_USER: SimulatePersona;
1439
1453
  declare const CONFUSED_USER: SimulatePersona;
1440
1454
  declare const COOPERATIVE_USER: SimulatePersona;
1441
1455
 
1456
+ /** Mock tool implementations active for the current async scope. */
1457
+ type MockToolFn = (args: Record<string, unknown>) => unknown;
1458
+
1459
+ /** Registry of mock tool implementations, activated for the duration of `run`. */
1460
+ declare class MockToolRegistry {
1461
+ private readonly tools;
1462
+ register(name: string, fn: MockToolFn): void;
1463
+ /**
1464
+ * Run `fn` with the registered mocks active. `TraceBuilder.addToolCall`
1465
+ * returns the mock's result for a registered tool name. Scopes are
1466
+ * isolated per async call chain (AsyncLocalStorage).
1467
+ */
1468
+ run<T>(fn: () => T): T;
1469
+ }
1470
+ type MockTool<F extends MockToolFn> = F & {
1471
+ readonly mockToolName: string;
1472
+ };
1473
+ /** Tag `fn` as the mock for tool `name`; the returned function behaves like `fn`. */
1474
+ declare function mockTool<F extends MockToolFn>(name: string, fn: F): MockTool<F>;
1475
+
1476
+ interface FaultInjectOptions {
1477
+ /** Probability in [0, 1] that a call throws. Default 0. */
1478
+ errorRate?: number;
1479
+ /** Upper bound of uniform random delay per call, in ms. Default 0. */
1480
+ latencyJitterMs?: number;
1481
+ /** Seed for a deterministic fault sequence. */
1482
+ seed?: number;
1483
+ }
1484
+ /**
1485
+ * Wrap `fn` so calls throw `Error("Injected fault in <name>")` at
1486
+ * `errorRate` and are delayed by up to `latencyJitterMs`. The RNG is
1487
+ * created once per wrapped function, so a fixed seed gives a fixed
1488
+ * sequence across calls.
1489
+ */
1490
+ declare function faultInject<A extends unknown[], R>(options: FaultInjectOptions, fn: (...args: A) => R | Promise<R>): (...args: A) => Promise<R>;
1491
+
1492
+ /**
1493
+ * Anything with a test outcome: `AgentResult`, `RepeatResult` and
1494
+ * `ScenarioResult`. Aggregates nest.
1495
+ */
1496
+ interface Verdict {
1497
+ readonly notEvaluatedReasons: Readonly<Record<string, number>>;
1498
+ outcome(options?: {
1499
+ strict?: boolean;
1500
+ }): Outcome;
1501
+ skipReason(): string;
1502
+ }
1503
+ type Renderable = Verdict & {
1504
+ renderDiagnostics?(options?: {
1505
+ color?: boolean;
1506
+ }): string;
1507
+ };
1508
+ /** Diagnostics of one verdict: an `AgentResult` or an aggregate. */
1509
+ declare function renderVerdictDiagnostics(verdict: Renderable, color?: boolean): string;
1510
+
1511
+ /** Results of `n` trials, aggregated under the assertion-status rules. */
1512
+ declare class RepeatResult implements Verdict {
1513
+ readonly results: readonly Verdict[];
1514
+ constructor(results?: readonly Verdict[]);
1515
+ get count(): number;
1516
+ /** Trials skipped because an assertion was not evaluated. */
1517
+ get notEvaluated(): number;
1518
+ /** Passing / evaluated trials; null when no trial was evaluated. */
1519
+ get passRate(): number | null;
1520
+ /** True when every trial's outcome is pass (soft failures included). */
1521
+ get allPassed(): boolean;
1522
+ outcome(options?: {
1523
+ strict?: boolean;
1524
+ }): Outcome;
1525
+ get notEvaluatedReasons(): Readonly<Record<string, number>>;
1526
+ skipReason(): string;
1527
+ renderDiagnostics(options?: {
1528
+ color?: boolean;
1529
+ }): string;
1530
+ }
1531
+ /** Run `fn` `n` times sequentially and collect the verdicts. */
1532
+ declare function repeat<A extends unknown[]>(n: number, fn: (...args: A) => Verdict | Promise<Verdict>): (...args: A) => Promise<RepeatResult>;
1533
+
1534
+ interface ScenarioConfig {
1535
+ persona?: SimulatePersona;
1536
+ mockTools: Readonly<Record<string, MockToolFn>>;
1537
+ faultErrorRate: number;
1538
+ faultLatencyJitterMs: number;
1539
+ maxTurns: number;
1540
+ seed?: number;
1541
+ }
1542
+ /** Passed to the scenario body on every turn. */
1543
+ interface ScenarioContext {
1544
+ readonly persona: SimulatePersona | undefined;
1545
+ /** Zero-based turn index. */
1546
+ readonly turn: number;
1547
+ }
1548
+ /** One verdict per turn; the aggregate follows the assertion-status rules. */
1549
+ declare class ScenarioResult implements Verdict {
1550
+ readonly config: ScenarioConfig;
1551
+ readonly results: readonly AgentResult[];
1552
+ constructor(config: ScenarioConfig, results?: readonly AgentResult[]);
1553
+ /** True when the aggregate `outcome()` is pass. */
1554
+ get passed(): boolean;
1555
+ outcome(options?: {
1556
+ strict?: boolean;
1557
+ }): Outcome;
1558
+ get notEvaluatedReasons(): Readonly<Record<string, number>>;
1559
+ skipReason(): string;
1560
+ renderDiagnostics(options?: {
1561
+ color?: boolean;
1562
+ }): string;
1563
+ }
1564
+ interface ScenarioOptions {
1565
+ persona?: SimulatePersona;
1566
+ mockTools?: Record<string, MockToolFn>;
1567
+ /** Probability per turn of throwing `Injected fault at turn N`. Default 0. */
1568
+ faultErrorRate?: number;
1569
+ /** Upper bound of uniform random delay per turn, in ms. Default 0. */
1570
+ faultLatencyJitterMs?: number;
1571
+ /** Turns to run. Default 1. */
1572
+ maxTurns?: number;
1573
+ /** Seed for a deterministic fault sequence. */
1574
+ seed?: number;
1575
+ }
1576
+ /**
1577
+ * Run `fn` for `maxTurns` turns with mock tools active, injecting faults
1578
+ * and latency per turn. `fn` receives the persona and turn index.
1579
+ */
1580
+ declare function scenario<A extends unknown[]>(options: ScenarioOptions, fn: (ctx: ScenarioContext, ...args: A) => AgentResult | Promise<AgentResult>): (...args: A) => Promise<ScenarioResult>;
1581
+
1442
1582
  declare class ManualAdapter {
1443
1583
  private readonly agentId;
1444
1584
  constructor(agentId?: string);
@@ -1663,5 +1803,5 @@ interface TraceAdapter {
1663
1803
  traceFromResponse(response: unknown, options?: Record<string, unknown>): Trace;
1664
1804
  }
1665
1805
 
1666
- export { ADVERSARIAL_USER, Agent, AgentResult, AlertDispatcher, AnthropicAdapter, Assertion, AssertionResult, AttestClient, BatchBudget, BatchContext, 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 };
1667
- 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 };
1806
+ export { ADVERSARIAL_USER, Agent, AgentResult, AlertDispatcher, AnthropicAdapter, Assertion, AssertionResult, AttestClient, BatchBudget, BatchContext, CONFUSED_USER, COOPERATIVE_USER, CaptureError, ContinuousEvalRunner, ConversationMessage, DriftReport, ENGINE_VERSION, EgressBlockedError, EngineManager, EvaluateBatchResult, ExpectChain, FRIENDLY_USER, GeminiAdapter, InitializeResult, LangChainAdapter, ManualAdapter, MockToolRegistry, OTelAdapter, OllamaAdapter, OpenAIAdapter, Outcome, PluginRegistry, ProtocolDiagnostic, ProtocolLogger, RepeatResult, ReplayError, ReplayMissError, ReplayNotEvaluatedError, Sampler, ScenarioResult, 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, faultInject, firstMiss, formatUsage, getSampleRate, installEgressGuard, isProviderHost, isSimulationMode, liveLine, loadFixture, loadLabelsCSV, loadLabelsJSONL, loadPackagePlugins, mockTool, parseUsage, promptHash, record, registerPlugin, renderAssertionFailure, renderDiagnostics, renderSummary, renderVerdictDiagnostics, renderVitest, repeat, requireSimulationCapability, resetConfig, resolveMode, scenario, simulationEnvEnabled, startReplay, startWorld, sumUsage, testPathFor, tier, uninstallEgressGuard, usageSummaryLine, zeroUsage };
1807
+ export type { AgreementResult, AlertPayload, AttestClientOptions, AttestPlugin, Capture, Contract, ContractResult, FaultInjectOptions, Fixture, LabelPair, LabeledRecord, MockTool, MockToolFn, PluginResult, RecordOptions, RecordResult, RenderOptions, ReplayMode, ReplayModeSetting, ReplayOptions, ReplayRecord, ReplaySession, ReplaySummary, ScenarioConfig, ScenarioContext, ScenarioOptions, TraceAdapter, Verdict, WorldOptions, WorldSession, WorldSnapshot };
package/dist/esm/cli.js CHANGED
@@ -8,8 +8,8 @@ import * as path4 from "path";
8
8
  import { fileURLToPath as fileURLToPath2 } from "url";
9
9
 
10
10
  // src/version.ts
11
- var VERSION = "1.0.0-rc.4";
12
- var ENGINE_VERSION = "1.0.0-rc.4";
11
+ var VERSION = "1.0.0-rc.5";
12
+ var ENGINE_VERSION = "1.0.0-rc.5";
13
13
 
14
14
  // src/engine-manager.ts
15
15
  import { spawn, spawnSync } from "child_process";
@@ -319,10 +319,17 @@ jobs:
319
319
  - name: Run tests
320
320
  id: tests
321
321
  continue-on-error: true
322
+ # Traces (prompts, outputs, tool args; not redacted) travel in the artifact; on a public
323
+ # repository any signed-in GitHub user can download it. Enable on private repositories only:
324
+ # env:
325
+ # ATTEST_REPORT_TRACES: "1"
322
326
  run: npx vitest run ${REPORT_ARGS}
323
327
  - name: Write the JUnit report
324
328
  if: always()
325
329
  run: npx attest report junit --report attest-report.json --out attest-junit.xml
330
+ - name: Write the failure viewer
331
+ if: always()
332
+ run: npx attest view attest-report.json --no-open --out attest-report.html
326
333
  - name: Upload the Attest report
327
334
  if: always()
328
335
  uses: actions/upload-artifact@v7
@@ -331,6 +338,7 @@ jobs:
331
338
  path: |
332
339
  attest-report.json
333
340
  attest-junit.xml
341
+ attest-report.html
334
342
  if-no-files-found: error
335
343
  - name: Evaluate the merge policy
336
344
  if: always()