@apo-ai/sdk 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,18 @@
1
1
  # apo SDK
2
2
 
3
- TypeScript/JavaScript SDK for the [apo](.) backend — an agent testing and
4
- observability platform. The SDK has three entry points:
3
+ TypeScript/JavaScript SDK for [apo](https://github.com/samikuikka/apo), the
4
+ testing and engineering system that turns expert knowledge into executable
5
+ capability specifications for agent harnesses. The task API runs a real harness
6
+ against that definition of done; the tracing API preserves the evidence a human
7
+ or coding agent needs to improve it. The SDK's entry points:
5
8
 
6
- - **`@apo-ai/sdk`** — config + error types shared across the surface.
7
9
  - **`@apo-ai/sdk/otel`** — OpenTelemetry-native tracing. Wrap your LLM calls and
8
10
  agent steps so they land in apo as structured spans, then attach scores.
9
- - **`@apo-ai/sdk/agent-task`** — the agent-task evaluation framework. Define tasks,
10
- adapters, and checks; run them against an agent and collect structured
11
- results.
11
+ - **`@apo-ai/sdk/agent-task`** — the primary capability-testing surface. Define
12
+ tasks, adapters, and tests; run them against the real harness and collect a
13
+ verdict with structured evidence.
14
+ - **`@apo-ai/sdk/agent-task/integrations/{ai-sdk,openai,anthropic}`** —
15
+ per-framework tracing wrappers re-exported for direct import.
12
16
 
13
17
  ## Installation
14
18
 
@@ -36,57 +40,23 @@ no long-lived npm token is stored in the repository.
36
40
 
37
41
  ## Configuration
38
42
 
39
- `readConfig()` reads backend/project/credentials from environment variables.
40
-
41
- | Field | Env var (server) | Env var (Next.js, browser-safe) | Required |
42
- |-------------|-----------------------------|--------------------------------------|----------|
43
- | `endpoint` | `APO_BACKEND_URL` | `NEXT_PUBLIC_APO_BACKEND_URL` | yes |
44
- | `project` | `APO_PROJECT` | `NEXT_PUBLIC_APO_PROJECT` | yes |
45
- | `publicKey` | `APO_PUBLIC_KEY` | — *(server-side only — see below)* | two-key |
46
- | `secretKey` | `APO_SECRET_KEY` | — | two-key |
47
- | `apiKey` | `APO_API_KEY` | — | legacy |
48
-
49
- The Next.js (`NEXT_PUBLIC_*`) variants are read first, then the plain server
50
- variants. `apiKey` is the legacy single-key format (`sk-…`); prefer the
51
- two-key model (`publicKey` + `secretKey`, generated as `pk-apo-…` / `sk-apo-…`
52
- in the dashboard).
53
-
54
- there is no browser-safe variant of `APO_PUBLIC_KEY`. The public
55
- identifier alone does not authorize ingestion, and exposing it in a
56
- browser bundle creates a misleading direct-browser integration.
57
- `NEXT_PUBLIC_APO_PUBLIC_KEY` is intentionally not read. Telemetry
58
- submission always requires both halves of an API-key pair sent as HTTP
59
- Basic (`base64("pk-apo-…:sk-apo-…")`); the SDK never synthesizes partial
60
- Basic credentials from only one half.
43
+ The tracing surface (`@apo-ai/sdk/otel`) reads credentials from environment
44
+ variables when they are not passed explicitly:
61
45
 
62
- ```ts
63
- import { readConfig, type EnvConfig } from "@apo-ai/sdk";
64
-
65
- const config: EnvConfig = readConfig();
66
- ```
67
-
68
- ## API reference — `@apo-ai/sdk`
69
-
70
- The root entry is intentionally thin: shared types + config + errors. The
71
- actual tracing surface lives at `@apo-ai/sdk/otel`.
72
-
73
- ### Types
74
-
75
- The trace/observation parameter types used by the OTel helpers:
76
- `CreateTraceParams`, `CreateSpanParams`, `EndSpanParams`, `TraceRunContext`,
77
- `TraceRunOptions`, `TraceStepOptions`, `TraceEventOptions`, `IngestionEvent`,
78
- `CreateScoreParams`, `ClientOptions`, `ParameterOverrides`, `ObserveOptions`,
79
- `ObservationContext`.
80
-
81
- ### `readConfig(): EnvConfig`
82
-
83
- Read endpoint/project/keys from environment variables (table above).
84
-
85
- ### Errors
46
+ | Purpose | Env var | Used for |
47
+ |--------------------------|---------------------|--------------------------------------------|
48
+ | OTLP traces endpoint | `APO_OTLP_ENDPOINT` | Where spans are exported |
49
+ | Project (diagnostic) | `APO_PROJECT` | Resource attribute only — auth owns tenancy |
50
+ | Two-key auth (Basic) | `APO_PUBLIC_KEY` + `APO_SECRET_KEY` | `Authorization: Basic base64(pk:sk)` |
51
+ | Bearer token | `APO_AUTH_TOKEN` | Short-lived task-run tokens; used only when the key pair is absent |
86
52
 
87
- `ClientError` (Effect `Data.TaggedError`), `ConfigurationError`,
88
- `ClientErrorCode`. `ClientError` carries a `code` field for categorising
89
- failures.
53
+ Telemetry submission always requires both halves of an API-key pair sent as
54
+ HTTP Basic (`base64("pk-apo-…:sk-apo-…")`); the SDK never synthesizes partial
55
+ Basic credentials from only one half. There is deliberately no
56
+ `NEXT_PUBLIC_*` browser variant — a public identifier alone does not
57
+ authorize ingestion, and exposing it in a browser bundle creates a misleading
58
+ direct-browser integration. Use `buildApoAuthHeaders` (exported from
59
+ `@apo-ai/sdk/otel`) to build the headers explicitly.
90
60
 
91
61
  ## Tracing — `@apo-ai/sdk/otel`
92
62
 
@@ -115,7 +85,7 @@ call this if your app already configures OTel itself).
115
85
  ```ts
116
86
  const handle = await configureApoTelemetry({
117
87
  takeOwnership: true,
118
- endpoint: process.env.APO_OTLP_ENDPOINT ?? "http://localhost:8000/v1/otlp",
88
+ endpoint: process.env.APO_OTLP_ENDPOINT ?? "http://localhost:8000/api/public/otel/v1/traces",
119
89
  // headers, resource attributes, batch/simple processor, etc.
120
90
  });
121
91
 
@@ -199,12 +169,10 @@ import {
199
169
  - **`test(id, fn)`** — register a test through the scope returned by `task()`.
200
170
  The callback receives `t` (flat, eve-style assertions over the run's flow)
201
171
  and the task-selected deliverables, inferred from the adapter.
202
- - **`runTask(task, adapter, options?)`** — execute a single task and return a
203
- `TaskRunResult` (transcript + evaluation).
172
+ - **`runTask(taskDir, options?)`** — execute a task and return a
173
+ `TaskRunResult` (transcript + evaluation). The adapter comes from the task
174
+ definition.
204
175
  - **`loadTask(dir)` / `discoverAgentTaskDirs()`** — load tasks from disk.
205
- - **`createAgentTaskTraceClient(config)`** — the adapter-side trace client
206
- passed into runs; the auth token is supplied by the backend runner via
207
- `APO_AUTH_TOKEN`.
208
176
 
209
177
  ### Testing (`*.eval.ts`)
210
178
 
@@ -277,8 +245,8 @@ anything). Matchers: `includes(substring|RegExp)`, `equals(value)` (deep),
277
245
  `satisfies(predicate, label)`, `similarity(expected, threshold = 0.8)` (fuzzy,
278
246
  normalized Levenshtein).
279
247
 
280
- For apo tasks the flow is built automatically from the run's trace (via
281
- `createFlowTee`) — no extra wiring.
248
+ For apo tasks the flow is built automatically from the run's trace
249
+ projection — no extra wiring.
282
250
 
283
251
  **`t.judge(value, instruction)` — LLM-backed assertions.** Configure the judge
284
252
  with `runTask(dir, { judge: { model, apiKey?, baseURL? } })`, or set
@@ -297,21 +265,22 @@ never revealed. The SDK appends its JSON response contract to any custom
297
265
  `system` constant per task and vary only `user` to preserve the cached prompt
298
266
  prefix across a task's criteria (issue #161).
299
267
 
300
- **Testing agents not built on apo's adapter.** Build a `Flow` from the
301
- framework's own output with a normalizer, then run the same checks:
268
+ **Agents not built on apo's adapter.** `fromOpenAIMessages(messages)`,
269
+ `fromAnthropicMessages(messages)`, and `fromAISDK(result)` convert another
270
+ framework's output into the neutral `Flow` format so it can be inspected with
271
+ `FlowView`:
302
272
 
303
273
  ```ts
304
- import { runFlowChecks, test } from "@apo-ai/sdk/agent-task";
305
- import { fromAISDK } from "@apo-ai/sdk/agent-task"; // or fromOpenAIMessages / fromAnthropicMessages
274
+ import { fromAISDK, FlowView } from "@apo-ai/sdk/agent-task";
306
275
 
307
- const flow = fromAISDK(myGenerateTextResult); // their framework → Flow
308
- test("used-tools", (t) => { t.calledTool("read_file"); });
309
- const results = await runFlowChecks({ flow, deliverables: { reply: myGenerateTextResult.text } });
276
+ const view = new FlowView(fromAISDK(myGenerateTextResult));
277
+ view.toolNamesInOrder; // e.g. ["read_file", "search_content"]
278
+ view.reply; // last assistant message text
310
279
  ```
311
280
 
312
- `fromOpenAIMessages(messages)`, `fromAnthropicMessages(messages)`, and
313
- `fromAISDK(result)` each convert one source into the neutral `Flow` the checks
314
- read — the plugs that make the testing framework reusable across agent stacks.
281
+ These normalizers are **deprecated** compatibility adapters — the canonical
282
+ path emits standard OTel spans (see the tracing integrations above), which
283
+ apo projects into the same view without a Flow intermediary.
315
284
 
316
285
  ### CLI / runtime
317
286
 
@@ -1,4 +1,4 @@
1
- import { A as AgentTaskTraceContext } from '../../tracing-D5Yhzq8e.js';
1
+ import { A as AgentTaskTraceContext } from '../../tracing-DVLUqD-i.js';
2
2
 
3
3
  /**
4
4
  * Vercel AI SDK tracing integration for apo.
@@ -6,9 +6,9 @@ import { A as AgentTaskTraceContext } from '../../tracing-D5Yhzq8e.js';
6
6
  * Pass the result of {@link createApoTracer} to `generateText`'s
7
7
  * `experimental_telemetry` option. The AI SDK already emits OpenTelemetry
8
8
  * spans natively (e.g. `ai.toolCall`, `ai.generateText`); this tracer
9
- * intercepts them and translates them into apo trace spans. The FlowTee
10
- * picks up TOOL/GENERATION observations and builds the Flow that
11
- * `t.calledTool`, `t.noFailedActions`, and `t.messageIncludes` read.
9
+ * intercepts them and translates them into apo trace spans, where they
10
+ * become the TOOL/GENERATION observations that `t.calledTool`,
11
+ * `t.noFailedActions`, and `t.messageIncludes` read.
12
12
  *
13
13
  * The adapter author writes zero manual span code.
14
14
  *
@@ -109,8 +109,8 @@ interface CreateApoTracerOptions {
109
109
  * - `ai.generateText` → a GENERATION span (so `t.messageIncludes(text)` works)
110
110
  * and error status → `t.noFailedActions()` catches it
111
111
  *
112
- * Other spans (`ai.generateText.doGenerate`, etc.) are ignored — the FlowTee
113
- * only cares about TOOL/AGENT/GENERATION observation types.
112
+ * Other spans (`ai.generateText.doGenerate`, etc.) are ignored — only
113
+ * TOOL/AGENT/GENERATION observation types are visible to `t.*` assertions.
114
114
  */
115
115
  declare function createApoTracer(options: CreateApoTracerOptions): {
116
116
  isEnabled: true;
@@ -2,7 +2,7 @@
2
2
  // Do not edit by hand — edit the src/ originals and rebuild.
3
3
  import {
4
4
  createApoTracer
5
- } from "../../chunk-HKLBPIB4.js";
5
+ } from "../../chunk-QHRWPVPZ.js";
6
6
  import "../../chunk-HWZVL6TS.js";
7
7
  export {
8
8
  createApoTracer
@@ -1,4 +1,4 @@
1
- import { A as AgentTaskTraceContext } from '../../tracing-D5Yhzq8e.js';
1
+ import { A as AgentTaskTraceContext } from '../../tracing-DVLUqD-i.js';
2
2
 
3
3
  /**
4
4
  * Anthropic JS SDK tracing integration for apo.
@@ -1,4 +1,4 @@
1
- import { A as AgentTaskTraceContext } from '../../tracing-D5Yhzq8e.js';
1
+ import { A as AgentTaskTraceContext } from '../../tracing-DVLUqD-i.js';
2
2
 
3
3
  /**
4
4
  * OpenAI JS SDK tracing integration for apo.
@@ -8,8 +8,8 @@ import { A as AgentTaskTraceContext } from '../../tracing-D5Yhzq8e.js';
8
8
  * any manual span code in the adapter.
9
9
  *
10
10
  * Uses a Proxy to intercept the `create` method, then emits GENERATION +
11
- * TOOL spans through the trace context. The FlowTee picks these up and
12
- * builds the Flow that `t.calledTool` reads.
11
+ * TOOL spans through the trace context, where they become the observations
12
+ * that `t.calledTool` reads.
13
13
  *
14
14
  * @example
15
15
  * ```ts
@@ -2,7 +2,7 @@
2
2
  // Do not edit by hand — edit the src/ originals and rebuild.
3
3
  import {
4
4
  createApoOpenAI
5
- } from "../../chunk-DT2LMB7O.js";
5
+ } from "../../chunk-6ZRW5IW6.js";
6
6
  import "../../chunk-GDB6SDGN.js";
7
7
  export {
8
8
  createApoOpenAI
@@ -1,4 +1,4 @@
1
- import { A as AgentTaskTraceContext, a as AgentTaskTraceOptions } from '../tracing-D5Yhzq8e.js';
1
+ import { A as AgentTaskTraceContext, a as AgentTaskTraceOptions } from '../tracing-DVLUqD-i.js';
2
2
  export { CreateApoTracerOptions, createApoTracer } from './integrations/ai-sdk.js';
3
3
  export { CreateApoOpenAIOptions, createApoOpenAI } from './integrations/openai.js';
4
4
  export { CreateApoAnthropicOptions, createApoAnthropic } from './integrations/anthropic.js';
@@ -323,6 +323,13 @@ type AssertionOutcome = "pass" | "fail" | "unsupported";
323
323
  type JudgeMetadata = {
324
324
  /** Model identifier, e.g. ``"google/gemini-2.5-flash-lite"``. */
325
325
  model?: string;
326
+ /**
327
+ * Which response contract elicited this judgment (#163): reasoning-first
328
+ * (the default) or the legacy verdict-first (``pass`` before
329
+ * ``reasoning``, via ``APO_JUDGE_VERDICT_FIRST``). Group comparisons
330
+ * across the default flip on this field, not on time.
331
+ */
332
+ contract?: "verdict-first" | "reasoning-first";
326
333
  /** The messages sent to the judge LLM. */
327
334
  prompt?: {
328
335
  system?: string;
@@ -343,6 +350,102 @@ type JudgeMetadata = {
343
350
  latency_ms?: number;
344
351
  /** Temperature or other sampling parameters, if relevant. */
345
352
  temperature?: number;
353
+ /**
354
+ * Agentic-judge session transcript (`t.agent`). Absent for single-shot
355
+ * `t.judge` calls. Records every investigation step (tool calls with
356
+ * truncated results), the session outcome, per-step usage, and the
357
+ * content-hashed evidence manifest (replay audit backbone).
358
+ */
359
+ session?: AgentJudgeSession;
360
+ /**
361
+ * Second-grader evidence: a typed-decision model (Jev via OpenRouter's
362
+ * `/alpha/decisions`) graded the same deliverable + instruction alongside
363
+ * the primary judge. Opt-in via `APO_SECOND_JUDGE_MODEL`. The primary
364
+ * verdict is never changed by it — the point is agreement and confidence
365
+ * as extra signals per check, not a second vote.
366
+ */
367
+ secondJudge?: SecondJudgeEvidence;
368
+ };
369
+ /**
370
+ * Evidence from the second grader. `error` is set when the decisions
371
+ * endpoint could not be reached — a failed second opinion must never
372
+ * affect the check's verdict.
373
+ */
374
+ type SecondJudgeEvidence = {
375
+ /** Decision-model id that graded, e.g. `typesafe/jev-1.13`. */
376
+ model: string;
377
+ /** The typed verdict the model returned. */
378
+ choice?: "pass" | "fail";
379
+ /** P(pass) from the model's probability distribution over the choice. */
380
+ passProbability?: number;
381
+ /** The model's own confidence in its choice (0-1). */
382
+ confidence?: number;
383
+ /** Input tokens billed for the decision, when the provider reports usage. */
384
+ inputTokens?: number;
385
+ /** Cost in USD, when the provider reports it. */
386
+ costUsd?: number;
387
+ /** Wall-clock latency of the decision call in milliseconds. */
388
+ latencyMs?: number;
389
+ /** Why no verdict was recorded (transport/HTTP/parse failure). */
390
+ error?: string;
391
+ };
392
+ /**
393
+ * One investigation step of an agentic judge session. Tool results are
394
+ * truncated text; the sha256 + byte size are always kept so the full value
395
+ * stays recoverable from the evidence store (the transcript is an index,
396
+ * not a copy).
397
+ */
398
+ type AgentJudgeStep = {
399
+ index: number;
400
+ tool_calls?: {
401
+ name: string;
402
+ input?: string;
403
+ result?: string;
404
+ result_sha256?: string;
405
+ result_bytes?: number;
406
+ }[];
407
+ /** Assistant prose, if the model produced text alongside tool calls. */
408
+ text?: string;
409
+ tokens?: {
410
+ input?: number;
411
+ output?: number;
412
+ cost?: number;
413
+ };
414
+ latency_ms?: number;
415
+ };
416
+ /** How an agentic judge session ended. */
417
+ type AgentJudgeOutcome = "verdict" | "budget_exhausted" | "error";
418
+ /**
419
+ * A fingerprint of one piece of evidence the judge consumed — the
420
+ * content-addressed manifest. Never truncated.
421
+ */
422
+ type EvidenceFingerprint = {
423
+ step: number;
424
+ tool: string;
425
+ args_sha256?: string;
426
+ result_sha256: string;
427
+ result_bytes: number;
428
+ };
429
+ /** Transcript-shaped record of one `t.agent` session. */
430
+ type AgentJudgeSession = {
431
+ /** Tool names offered to the judge. */
432
+ tools?: string[];
433
+ /** Turn-0 context: system briefing and the rubric (user message). */
434
+ briefing?: {
435
+ system?: string;
436
+ rubric?: string;
437
+ };
438
+ /** Ordered investigation steps. */
439
+ steps?: AgentJudgeStep[];
440
+ outcome: AgentJudgeOutcome;
441
+ /** Evidence manifest — what this session consumed, hashed. Never truncated. */
442
+ evidence?: EvidenceFingerprint[];
443
+ usage?: {
444
+ steps?: number;
445
+ input_tokens?: number;
446
+ output_tokens?: number;
447
+ cache_read_tokens?: number;
448
+ };
346
449
  };
347
450
  /**
348
451
  * A source location for a failed code check — lets the dashboard render the
@@ -386,7 +489,7 @@ type AssertionResult = {
386
489
  */
387
490
  received?: unknown;
388
491
  location?: CheckLocation;
389
- evaluator_type?: "llm" | "code";
492
+ evaluator_type?: "llm" | "code" | "agent";
390
493
  judge?: JudgeMetadata;
391
494
  };
392
495
  /**
@@ -416,7 +519,7 @@ type EvaluationItemResult = {
416
519
  * - ``"regex"`` — pattern matching
417
520
  * Older persisted results may still use ``"llm"`` at this level.
418
521
  */
419
- evaluator_type?: "llm" | "code" | "regex";
522
+ evaluator_type?: "llm" | "code" | "agent" | "regex";
420
523
  /**
421
524
  * If this check was judged by an LLM, details about the judge call
422
525
  * (model, prompt, response, tokens, cost, latency). Populated by the
@@ -443,10 +546,10 @@ type EvaluationItemResult = {
443
546
  */
444
547
  assertions?: AssertionResult[];
445
548
  /**
446
- * the snapshot source the checks ran against. Set to
447
- * ``"legacy-flow"`` by the deprecated {@link runFlowChecks} wrapper so
448
- * consumers can detect they're on the compatibility path. Absent on
449
- * projection-first results (the default).
549
+ * the snapshot source the checks ran against. ``"local"`` marks locally
550
+ * recorded snapshots; ``"legacy-flow"`` survives only on results recorded
551
+ * by the removed Flow-path loader. Absent on projection-first results
552
+ * (the default).
450
553
  */
451
554
  source?: "canonical" | "local" | "legacy-flow";
452
555
  /**
@@ -557,6 +660,101 @@ type JudgePromptBuilder = (ctx: JudgeContext) => {
557
660
  user?: string;
558
661
  };
559
662
 
663
+ /** One prior attempt of this task, as frozen at evaluation start. */
664
+ type FrozenRunSummary = {
665
+ id: string;
666
+ status: string;
667
+ passed: boolean | null;
668
+ started_at?: string;
669
+ primary_model?: string | null;
670
+ passed_checks?: number | null;
671
+ failed_checks?: number | null;
672
+ corrected_tests?: unknown[];
673
+ /** True when this entry IS the run under judgment. */
674
+ is_run_under_judgment?: boolean;
675
+ };
676
+ /** A prior run's full check report (merged view, like the run detail page). */
677
+ type HistoryRunDetail = {
678
+ id: string;
679
+ status: string;
680
+ checks: {
681
+ id: string;
682
+ pass: boolean;
683
+ evaluator: string;
684
+ reasoning?: string;
685
+ assertions?: {
686
+ pass: boolean;
687
+ expected?: string;
688
+ received?: string;
689
+ }[];
690
+ }[];
691
+ /** Human corrections recorded against this run; "none" when empty. */
692
+ human_corrections: unknown[] | "none";
693
+ };
694
+ /** The frozen evidence plane handed to every `t.agent` session. */
695
+ type AgentHistoryPlane = {
696
+ /** Prior attempts of this task, frozen at evaluation start. */
697
+ runs: FrozenRunSummary[];
698
+ /**
699
+ * Fetch one prior run's merged check report. The run-under-judgment id
700
+ * returns an honest "you are deciding this run" answer instead of data
701
+ * whose checks are still being evaluated.
702
+ */
703
+ getRun(runId: string): Promise<HistoryRunDetail | {
704
+ error: string;
705
+ }>;
706
+ /** The backend's id for the run under judgment, when known. */
707
+ selfRunId?: string;
708
+ };
709
+
710
+ /**
711
+ * The agentic judge — `t.agent`. A tool-using LLM session that investigates
712
+ * the run's own evidence (deliverables, trace) before verdicting, powered by
713
+ * a lazy-loaded Vercel AI SDK engine. The judge semantics live here at the
714
+ * call site; the loop itself is engine-level: forced tool choice plus a
715
+ * done-tool verdict means the only exits are a verdict or the budget — every
716
+ * other ending is recorded as a failure with an explanation.
717
+ *
718
+ * Sessions are stateless per check: no memory crosses sessions (upstream
719
+ * ablations showed remembered judgments cascade errors). Everything the
720
+ * session consumed is recorded as a content-hashed manifest
721
+ * ({@link EvidenceFingerprint}) — the transcript is an index, not a copy.
722
+ */
723
+
724
+ /** Hard ceilings for one agentic session. Every field overrides a default. */
725
+ type AgentBudget = {
726
+ /** Max LLM turns (steps). Default 12. */
727
+ maxTurns?: number;
728
+ /** Max total tool executions. Default 24. */
729
+ maxToolCalls?: number;
730
+ /** Wall-clock ceiling. Default 300_000 ms. */
731
+ timeoutMs?: number;
732
+ /** Max cumulative bytes served by read/search tools. Default 2 MiB. */
733
+ maxReadBytes?: number;
734
+ };
735
+ /** Options for `t.agent(instruction, opts)`. */
736
+ type AgentJudgeOptions = {
737
+ /** Pre-staged values rendered into turn 0, like `t.judge` values. */
738
+ exhibits?: unknown | unknown[];
739
+ /** Judge config override for this call only (merges field-by-field). */
740
+ judge?: Partial<JudgeConfig>;
741
+ /** Tool families; deliverables are always on. `trace: false` drops get_trace. */
742
+ tools?: {
743
+ trace?: boolean;
744
+ };
745
+ budget?: AgentBudget;
746
+ label?: string;
747
+ };
748
+ /** The local evidence plane a session can investigate. */
749
+ type AgentEvidence = {
750
+ /** The run's deliverables, by name. */
751
+ deliverables: Record<string, unknown>;
752
+ /** The frozen trace projection; absent = no trace evidence plane. */
753
+ view?: TraceView;
754
+ /** This task's prior runs; absent = history plane unavailable. */
755
+ history?: AgentHistoryPlane;
756
+ };
757
+
560
758
  /**
561
759
  * The assertion surface — `t`. Flat and eve-style: reads the trace (via
562
760
  * {@link TraceView}) for behavioural checks and grades explicit values via
@@ -652,6 +850,21 @@ interface TestContext {
652
850
  label?: string;
653
851
  judge?: Partial<JudgeConfig>;
654
852
  }): Promise<void>;
853
+ /**
854
+ * Agentic judge: a tool-using LLM session that investigates the run's own
855
+ * evidence (deliverables via `read_deliverable`/`search_deliverable`, the
856
+ * trace via `get_trace`) before verdicting with `finish_verdict`. Async —
857
+ * the check function must `await` it. Records a single assertion tagged
858
+ * ``evaluator_type: "agent"`` with the full session transcript attached.
859
+ *
860
+ * Unlike `t.judge`, the author states a rubric and the judge gathers its
861
+ * own evidence; `opts.exhibits` optionally pre-stages values into turn 0.
862
+ * The session is budgeted (defaults: 12 turns / 24 tool calls / 300 s /
863
+ * 2 MiB read) and fail-closed: a session that ends without a verdict is a
864
+ * recorded failure, never a silent pass. Costs more and runs minutes, not
865
+ * seconds — reserve it for rubrics that need investigation.
866
+ */
867
+ agent(instruction: string, opts?: AgentJudgeOptions): Promise<void>;
655
868
  }
656
869
  /**
657
870
  * Canonical names of every assertion method on {@link TestContext}.
@@ -665,7 +878,7 @@ interface TestContext {
665
878
  * adding a method to the interface without registering it here is a type
666
879
  * error, and vice versa. See ``tests/test-context-methods.test.ts``.
667
880
  */
668
- declare const TEST_METHOD_NAMES: readonly ["calledTool", "notCalledTool", "toolOrder", "usedNoTools", "maxToolCalls", "noFailedActions", "loadedSkill", "calledSubagent", "messageIncludes", "maxTurns", "maxDurationMs", "assert", "check", "judge"];
881
+ declare const TEST_METHOD_NAMES: readonly ["calledTool", "notCalledTool", "toolOrder", "usedNoTools", "maxToolCalls", "noFailedActions", "loadedSkill", "calledSubagent", "messageIncludes", "maxTurns", "maxDurationMs", "assert", "check", "judge", "agent"];
669
882
 
670
883
  type TaskDefinition<TAdapterName extends string = string, TDeliverable extends string = string> = {
671
884
  id: string;
@@ -927,6 +1140,40 @@ interface PreparedTaskResult {
927
1140
  */
928
1141
  declare function persistFileArtifacts(deliverables: Record<string, unknown>, config: ArtifactUploadConfig): Promise<PreparedTaskResult>;
929
1142
 
1143
+ /**
1144
+ * Check submission compaction (issue #175).
1145
+ *
1146
+ * The backend's ``check_report_storage.normalize_check_report`` truncates
1147
+ * every ``received`` over 4 KiB and every judge prompt/response segment over
1148
+ * 16 KiB into a marker before storing anything — the full value never
1149
+ * survives server-side. This module applies the same limits at the producer,
1150
+ * so a task judging N criteria against one large document sends N tiny
1151
+ * markers instead of N copies of the document (a 43 MB result body becomes
1152
+ * single-digit MB). Local rendering keeps the uncompacted values.
1153
+ *
1154
+ * The markers are byte-compatible with the backend's (same field names,
1155
+ * preview length, and hash subject), so server-side normalization passes
1156
+ * them through unchanged and old servers store them as-is.
1157
+ */
1158
+
1159
+ /** Mirrors backend RECEIVED_VALUE_LIMIT (check_report_storage.py). */
1160
+ declare const RECEIVED_VALUE_LIMIT: number;
1161
+ /** Mirrors backend JUDGE_SEGMENT_LIMIT. */
1162
+ declare const JUDGE_SEGMENT_LIMIT: number;
1163
+ interface CheckCompaction {
1164
+ /** Copy of ``checks`` with oversized fields replaced by markers. */
1165
+ checks: EvaluationItemResult[];
1166
+ /** How many ``received`` values were replaced. */
1167
+ truncatedValues: number;
1168
+ /** How many judge prompt/response segments were replaced. */
1169
+ truncatedSegments: number;
1170
+ }
1171
+ /**
1172
+ * Return a submission-safe copy of ``checks``. Touched paths are copied;
1173
+ * untouched values are shared. Input is never mutated.
1174
+ */
1175
+ declare function compactChecksForSubmission(checks: readonly EvaluationItemResult[]): CheckCompaction;
1176
+
930
1177
  /**
931
1178
  * Flow — the canonical, source-agnostic recording of "what happened" during
932
1179
  * an agent run. This is the single substrate the testing framework reads.
@@ -1018,8 +1265,7 @@ declare class FlowView {
1018
1265
  * not the primary testing architecture. The canonical path is now the Trace
1019
1266
  * Projection snapshot (`TraceProjectionSnapshot` → `TraceView` →
1020
1267
  * `runTraceChecks`). These normalizers remain available during the
1021
- * deprecation period; `snapshotFromFlow` bridges their output into the
1022
- * projection contract. New integrations should emit standard OTel spans
1268
+ * deprecation period. New integrations should emit standard OTel spans
1023
1269
  * instead of producing a Flow.
1024
1270
  */
1025
1271
 
@@ -1241,7 +1487,7 @@ type DeliverableValidationResult = {
1241
1487
  *
1242
1488
  * The processor is global, but run isolation is maintained via
1243
1489
  * {@link AsyncLocalStorage}: {@link getActiveApoRun} returns the current
1244
- * run's trace context, so each span is routed to the correct run's FlowTee.
1490
+ * run's trace context, so each span is routed to the correct run's trace.
1245
1491
  *
1246
1492
  * **Design: eager creation, deferred completion.** The apo span is created
1247
1493
  * at `onStart` (when initial attributes like tool name and model are
@@ -1465,4 +1711,4 @@ declare function canonicalManifestJson(manifest: TaskRevisionManifestV1): string
1465
1711
  /** SHA-256 (lowercase hex) of the canonical manifest JSON's UTF-8 bytes. */
1466
1712
  declare function contentSha256(manifest: TaskRevisionManifestV1): string;
1467
1713
 
1468
- export { type AISDKResult, type AdapterDefinition, type AdapterRuntimeState, type AdapterSession, type AgentTaskCliOptions, type AgentTaskRunConfiguration, AgentTaskRunError, type AgentTaskRunSummary, type AgentTaskRuntime, AgentTaskTraceContext, AgentTaskTraceOptions, type AgentTurnResult, type AnthropicMessage, type ApoRunContext, ApoSpanProcessor, type ArtifactUploadConfig, type CheckContext, type CheckGroup, type CleanupContext, type CollectDeliverablesContext, type CollectedDeliverables, type DeliverableDefinition, type DeliverableSummary, type DeliverableValidationResult, type DescribeRegistration, type FileArtifact, type FileArtifactOptions, type FileEntry, type Flow, type FlowEvent, FlowView, type InitializeContext, type JudgeConfig, type JudgeContext, type JudgePromptBuilder, type JudgeScope, type LoadedTask, type ManifestFile, type ManifestFileInput, type Matcher, type ModeClass, type NameMatcher, type OpenAIMessage, type PreparedTaskResult, type RegisterApoTracingOptions, type RejudgeCheckStability, type RejudgeEndpoints, RejudgeError, type RejudgeOptions, type RejudgeOutcome, type RunTaskOptions, type StartSessionContext, TEST_METHOD_NAMES, type TaskConfig, type TaskDefinition, type TaskEvaluationResult, TaskFiles, type TaskRevisionManifestV1, type TaskRunResult, type TaskScope, type TaskTranscript, type TaskTranscriptTurn, type TestContext, type TestRegistration, type ToolCallOptions, type ToolCallStatus, type TurnContext, type TurnFn, type TurnRecord, type TypedAdapterDefinition, type ValueMatcher, buildManifest, canonicalManifestJson, contentSha256, defineAdapter, defineTask, describe, discoverAgentTaskDirs, equals, fileArtifact, filePaths, fromAISDK, fromAnthropicMessages, fromOpenAIMessages, getActiveApoRun, getTaskTurn, includes, isFileArtifact, loadTask, loadTaskRuntime, matchValue, matches, normalizeManifestPath, parseAgentTaskCliArgs, persistFileArtifacts, registerApoTracing, rejudgeTaskRun, resetApoTracing, resetFlowChecks, resetTaskRegistry, resetTaskTurn, resolveTurn, runAgentTaskCli, runTask, runTaskDir, satisfies, sha256Hex, similarity, task, defineCheck as test, turn, withApoRun, withApoRunSync };
1714
+ export { type AISDKResult, type AdapterDefinition, type AdapterRuntimeState, type AdapterSession, type AgentBudget, type AgentEvidence, type AgentJudgeOptions, type AgentJudgeOutcome, type AgentJudgeSession, type AgentJudgeStep, type AgentTaskCliOptions, type AgentTaskRunConfiguration, AgentTaskRunError, type AgentTaskRunSummary, type AgentTaskRuntime, AgentTaskTraceContext, AgentTaskTraceOptions, type AgentTurnResult, type AnthropicMessage, type ApoRunContext, ApoSpanProcessor, type ArtifactUploadConfig, type CheckCompaction, type CheckContext, type CheckGroup, type CleanupContext, type CollectDeliverablesContext, type CollectedDeliverables, type DeliverableDefinition, type DeliverableSummary, type DeliverableValidationResult, type DescribeRegistration, type EvidenceFingerprint, type FileArtifact, type FileArtifactOptions, type FileEntry, type Flow, type FlowEvent, FlowView, type InitializeContext, JUDGE_SEGMENT_LIMIT, type JudgeConfig, type JudgeContext, type JudgePromptBuilder, type JudgeScope, type LoadedTask, type ManifestFile, type ManifestFileInput, type Matcher, type ModeClass, type NameMatcher, type OpenAIMessage, type PreparedTaskResult, RECEIVED_VALUE_LIMIT, type RegisterApoTracingOptions, type RejudgeCheckStability, type RejudgeEndpoints, RejudgeError, type RejudgeOptions, type RejudgeOutcome, type RunTaskOptions, type StartSessionContext, TEST_METHOD_NAMES, type TaskConfig, type TaskDefinition, type TaskEvaluationResult, TaskFiles, type TaskRevisionManifestV1, type TaskRunResult, type TaskScope, type TaskTranscript, type TaskTranscriptTurn, type TestContext, type TestRegistration, type ToolCallOptions, type ToolCallStatus, type TurnContext, type TurnFn, type TurnRecord, type TypedAdapterDefinition, type ValueMatcher, buildManifest, canonicalManifestJson, compactChecksForSubmission, contentSha256, defineAdapter, defineTask, describe, discoverAgentTaskDirs, equals, fileArtifact, filePaths, fromAISDK, fromAnthropicMessages, fromOpenAIMessages, getActiveApoRun, getTaskTurn, includes, isFileArtifact, loadTask, loadTaskRuntime, matchValue, matches, normalizeManifestPath, parseAgentTaskCliArgs, persistFileArtifacts, registerApoTracing, rejudgeTaskRun, resetApoTracing, resetFlowChecks, resetTaskRegistry, resetTaskTurn, resolveTurn, runAgentTaskCli, runTask, runTaskDir, satisfies, sha256Hex, similarity, task, defineCheck as test, turn, withApoRun, withApoRunSync };