@apo-ai/sdk 0.5.0 → 0.6.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,15 @@
1
1
  # apo SDK
2
2
 
3
3
  TypeScript/JavaScript SDK for the [apo](.) backend — an agent testing and
4
- observability platform. The SDK has three entry points:
4
+ observability platform. The SDK's entry points:
5
5
 
6
- - **`@apo-ai/sdk`** — config + error types shared across the surface.
7
6
  - **`@apo-ai/sdk/otel`** — OpenTelemetry-native tracing. Wrap your LLM calls and
8
7
  agent steps so they land in apo as structured spans, then attach scores.
9
8
  - **`@apo-ai/sdk/agent-task`** — the agent-task evaluation framework. Define tasks,
10
9
  adapters, and checks; run them against an agent and collect structured
11
10
  results.
11
+ - **`@apo-ai/sdk/agent-task/integrations/{ai-sdk,openai,anthropic}`** —
12
+ per-framework tracing wrappers re-exported for direct import.
12
13
 
13
14
  ## Installation
14
15
 
@@ -36,57 +37,23 @@ no long-lived npm token is stored in the repository.
36
37
 
37
38
  ## Configuration
38
39
 
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.
40
+ The tracing surface (`@apo-ai/sdk/otel`) reads credentials from environment
41
+ variables when they are not passed explicitly:
61
42
 
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
43
+ | Purpose | Env var | Used for |
44
+ |--------------------------|---------------------|--------------------------------------------|
45
+ | OTLP traces endpoint | `APO_OTLP_ENDPOINT` | Where spans are exported |
46
+ | Project (diagnostic) | `APO_PROJECT` | Resource attribute only — auth owns tenancy |
47
+ | Two-key auth (Basic) | `APO_PUBLIC_KEY` + `APO_SECRET_KEY` | `Authorization: Basic base64(pk:sk)` |
48
+ | Bearer token | `APO_AUTH_TOKEN` | Short-lived task-run tokens; used only when the key pair is absent |
86
49
 
87
- `ClientError` (Effect `Data.TaggedError`), `ConfigurationError`,
88
- `ClientErrorCode`. `ClientError` carries a `code` field for categorising
89
- failures.
50
+ Telemetry submission always requires both halves of an API-key pair sent as
51
+ HTTP Basic (`base64("pk-apo-…:sk-apo-…")`); the SDK never synthesizes partial
52
+ Basic credentials from only one half. There is deliberately no
53
+ `NEXT_PUBLIC_*` browser variant — a public identifier alone does not
54
+ authorize ingestion, and exposing it in a browser bundle creates a misleading
55
+ direct-browser integration. Use `buildApoAuthHeaders` (exported from
56
+ `@apo-ai/sdk/otel`) to build the headers explicitly.
90
57
 
91
58
  ## Tracing — `@apo-ai/sdk/otel`
92
59
 
@@ -115,7 +82,7 @@ call this if your app already configures OTel itself).
115
82
  ```ts
116
83
  const handle = await configureApoTelemetry({
117
84
  takeOwnership: true,
118
- endpoint: process.env.APO_OTLP_ENDPOINT ?? "http://localhost:8000/v1/otlp",
85
+ endpoint: process.env.APO_OTLP_ENDPOINT ?? "http://localhost:8000/api/public/otel/v1/traces",
119
86
  // headers, resource attributes, batch/simple processor, etc.
120
87
  });
121
88
 
@@ -199,12 +166,10 @@ import {
199
166
  - **`test(id, fn)`** — register a test through the scope returned by `task()`.
200
167
  The callback receives `t` (flat, eve-style assertions over the run's flow)
201
168
  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).
169
+ - **`runTask(taskDir, options?)`** — execute a task and return a
170
+ `TaskRunResult` (transcript + evaluation). The adapter comes from the task
171
+ definition.
204
172
  - **`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
173
 
209
174
  ### Testing (`*.eval.ts`)
210
175
 
@@ -277,8 +242,8 @@ anything). Matchers: `includes(substring|RegExp)`, `equals(value)` (deep),
277
242
  `satisfies(predicate, label)`, `similarity(expected, threshold = 0.8)` (fuzzy,
278
243
  normalized Levenshtein).
279
244
 
280
- For apo tasks the flow is built automatically from the run's trace (via
281
- `createFlowTee`) — no extra wiring.
245
+ For apo tasks the flow is built automatically from the run's trace
246
+ projection — no extra wiring.
282
247
 
283
248
  **`t.judge(value, instruction)` — LLM-backed assertions.** Configure the judge
284
249
  with `runTask(dir, { judge: { model, apiKey?, baseURL? } })`, or set
@@ -297,21 +262,22 @@ never revealed. The SDK appends its JSON response contract to any custom
297
262
  `system` constant per task and vary only `user` to preserve the cached prompt
298
263
  prefix across a task's criteria (issue #161).
299
264
 
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:
265
+ **Agents not built on apo's adapter.** `fromOpenAIMessages(messages)`,
266
+ `fromAnthropicMessages(messages)`, and `fromAISDK(result)` convert another
267
+ framework's output into the neutral `Flow` format so it can be inspected with
268
+ `FlowView`:
302
269
 
303
270
  ```ts
304
- import { runFlowChecks, test } from "@apo-ai/sdk/agent-task";
305
- import { fromAISDK } from "@apo-ai/sdk/agent-task"; // or fromOpenAIMessages / fromAnthropicMessages
271
+ import { fromAISDK, FlowView } from "@apo-ai/sdk/agent-task";
306
272
 
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 } });
273
+ const view = new FlowView(fromAISDK(myGenerateTextResult));
274
+ view.toolNamesInOrder; // e.g. ["read_file", "search_content"]
275
+ view.reply; // last assistant message text
310
276
  ```
311
277
 
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.
278
+ These normalizers are **deprecated** compatibility adapters — the canonical
279
+ path emits standard OTel spans (see the tracing integrations above), which
280
+ apo projects into the same view without a Flow intermediary.
315
281
 
316
282
  ### CLI / runtime
317
283
 
@@ -1,4 +1,4 @@
1
- import { A as AgentTaskTraceContext } from '../../tracing-D5Yhzq8e.js';
1
+ import { A as AgentTaskTraceContext } from '../../tracing-CTmq4PSw.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-H7ITLBWU.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-CTmq4PSw.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-CTmq4PSw.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-CTmq4PSw.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;
@@ -443,10 +450,10 @@ type EvaluationItemResult = {
443
450
  */
444
451
  assertions?: AssertionResult[];
445
452
  /**
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).
453
+ * the snapshot source the checks ran against. ``"local"`` marks locally
454
+ * recorded snapshots; ``"legacy-flow"`` survives only on results recorded
455
+ * by the removed Flow-path loader. Absent on projection-first results
456
+ * (the default).
450
457
  */
451
458
  source?: "canonical" | "local" | "legacy-flow";
452
459
  /**
@@ -927,6 +934,40 @@ interface PreparedTaskResult {
927
934
  */
928
935
  declare function persistFileArtifacts(deliverables: Record<string, unknown>, config: ArtifactUploadConfig): Promise<PreparedTaskResult>;
929
936
 
937
+ /**
938
+ * Check submission compaction (issue #175).
939
+ *
940
+ * The backend's ``check_report_storage.normalize_check_report`` truncates
941
+ * every ``received`` over 4 KiB and every judge prompt/response segment over
942
+ * 16 KiB into a marker before storing anything — the full value never
943
+ * survives server-side. This module applies the same limits at the producer,
944
+ * so a task judging N criteria against one large document sends N tiny
945
+ * markers instead of N copies of the document (a 43 MB result body becomes
946
+ * single-digit MB). Local rendering keeps the uncompacted values.
947
+ *
948
+ * The markers are byte-compatible with the backend's (same field names,
949
+ * preview length, and hash subject), so server-side normalization passes
950
+ * them through unchanged and old servers store them as-is.
951
+ */
952
+
953
+ /** Mirrors backend RECEIVED_VALUE_LIMIT (check_report_storage.py). */
954
+ declare const RECEIVED_VALUE_LIMIT: number;
955
+ /** Mirrors backend JUDGE_SEGMENT_LIMIT. */
956
+ declare const JUDGE_SEGMENT_LIMIT: number;
957
+ interface CheckCompaction {
958
+ /** Copy of ``checks`` with oversized fields replaced by markers. */
959
+ checks: EvaluationItemResult[];
960
+ /** How many ``received`` values were replaced. */
961
+ truncatedValues: number;
962
+ /** How many judge prompt/response segments were replaced. */
963
+ truncatedSegments: number;
964
+ }
965
+ /**
966
+ * Return a submission-safe copy of ``checks``. Touched paths are copied;
967
+ * untouched values are shared. Input is never mutated.
968
+ */
969
+ declare function compactChecksForSubmission(checks: readonly EvaluationItemResult[]): CheckCompaction;
970
+
930
971
  /**
931
972
  * Flow — the canonical, source-agnostic recording of "what happened" during
932
973
  * an agent run. This is the single substrate the testing framework reads.
@@ -1018,8 +1059,7 @@ declare class FlowView {
1018
1059
  * not the primary testing architecture. The canonical path is now the Trace
1019
1060
  * Projection snapshot (`TraceProjectionSnapshot` → `TraceView` →
1020
1061
  * `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
1062
+ * deprecation period. New integrations should emit standard OTel spans
1023
1063
  * instead of producing a Flow.
1024
1064
  */
1025
1065
 
@@ -1241,7 +1281,7 @@ type DeliverableValidationResult = {
1241
1281
  *
1242
1282
  * The processor is global, but run isolation is maintained via
1243
1283
  * {@link AsyncLocalStorage}: {@link getActiveApoRun} returns the current
1244
- * run's trace context, so each span is routed to the correct run's FlowTee.
1284
+ * run's trace context, so each span is routed to the correct run's trace.
1245
1285
  *
1246
1286
  * **Design: eager creation, deferred completion.** The apo span is created
1247
1287
  * at `onStart` (when initial attributes like tool name and model are
@@ -1465,4 +1505,4 @@ declare function canonicalManifestJson(manifest: TaskRevisionManifestV1): string
1465
1505
  /** SHA-256 (lowercase hex) of the canonical manifest JSON's UTF-8 bytes. */
1466
1506
  declare function contentSha256(manifest: TaskRevisionManifestV1): string;
1467
1507
 
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 };
1508
+ 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 CheckCompaction, 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, 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 };