import { type EffortLevel, type SDKResultMessage, type ThinkingConfig } from '@anthropic-ai/claude-agent-sdk'; import { AgentProviderError, buildPromptModePrompt, extractJsonObject, validateAgainstSchema } from './structured-json'; import type { LLMProvider, ProviderRequest, ProviderResult } from './types'; export { AgentProviderError, buildPromptModePrompt, extractJsonObject, validateAgainstSchema }; /** * The two output modes {@link AnthropicAgentProvider} can drive `query()` in. * * - `'json_schema'` (the DEFAULT) uses the SDK's structured-output mode: it sets * `outputFormat: { type: 'json_schema', schema }`, the SDK asks the model to * emit an object, re-prompts on schema mismatch over several internal turns * (`maxTurns: 6`), and the validated object is read back from the terminal * result's `structured_output`. SDK-validated, multi-turn, robust — but the * generate → emit → validate loop is the latency cost the benchmark probes. * - `'prompt'` OMITS `outputFormat` entirely: it appends a directive to the user * prompt asking the model to emit raw JSON conforming to the schema, runs a * SMALL turn budget (one generation turn + headroom), then parses the terminal * `result` TEXT and validates it LOCALLY (see {@link extractJsonObject} and * {@link validateAgainstSchema}). Single-turn, faster, on the SAME subscription * path — at the cost of doing the parse/validate ourselves and retrying once. */ export type AnthropicAgentOutputMode = 'json_schema' | 'prompt'; /** Construction options for {@link AnthropicAgentProvider}. */ export interface AnthropicAgentProviderOptions { /** * Default model id or alias for calls that do not override it. Defaults to * {@link DEFAULT_MODEL} (`haiku`). */ model?: string; /** * Subscription OAuth token. When omitted, falls back to * `process.env.CLAUDE_CODE_OAUTH_TOKEN`. Injected explicitly here mostly so * tests can exercise {@link resolveAuthEnv} without a real environment. */ oauthToken?: string; /** * The ambient environment to derive auth from. Defaults to * `process.env`. Injectable so {@link resolveAuthEnv} is testable with a * synthetic env that has/lacks `ANTHROPIC_API_KEY`. */ env?: Record; /** * Run the Agent SDK HERMETICALLY. DEFAULT TRUE — this is the permanent fix. * * Each `query()` call spawns a `claude-code` subprocess, and by the SDK's * defaults that subprocess loads ALL filesystem settings + every project / * user `CLAUDE.md` and connects to every configured MCP server BEFORE it * generates — pure per-call startup overhead this provider never needs (it * does one pure schema-constrained generation with the side-effecting tools * already banned). When `true` we pass `settingSources: []`, `mcpServers: * {}`, and `strictMcpConfig: true` so NO settings, NO `CLAUDE.md`, and NO MCP * servers load — eliminating that config/MCP startup cost. The * structured-output (`outputFormat: json_schema`) path is UNAFFECTED. * * When `false`, those keys are omitted and the SDK's defaults load all * settings + MCP again (the original, slow behavior). This escape hatch * exists ONLY for the benchmark/comparison driver (`scripts/bench-isolation.ts`); * production never sets it, so isolation is simply on. */ isolate?: boolean; /** * Suppress claude.ai cloud connectors. DEFAULT TRUE — part of the hermetic fix. * * claude.ai cloud connectors (the user's Notion / Strava / Safari / etc. * connectors) are auto-fetched and connected by the spawned `claude-code` * subprocess by DEFAULT, and they are NOT covered by the isolation keys above: * `strictMcpConfig` + `mcpServers: {}` only gate explicitly-configured MCP * servers, and `settingSources: []` actually makes this WORSE — the SDK reads * the gating flag (`Settings.disableClaudeAiConnectors`) FROM settings sources, * so emptying them defaults connectors back ON. Each connector is an external * handshake the provider never needs for a pure schema-constrained generation, * and a suspected source of variable per-call latency. * * When `true` (and isolation is on) we pass * `managedSettings: { disableClaudeAiConnectors: true }` — the SDK option that * forces the gating flag regardless of settings sources — so the subprocess * never auto-fetches or connects them. When `false` the `managedSettings` key * is omitted and the SDK's default (connectors auto-fetch) stands; this escape * hatch exists ONLY for the connector benchmark (`scripts/bench-connectors.ts`), * production never sets it. Has no effect when `isolate` is `false` (all * settings load anyway, so a forced managed override is meaningless). */ disableClaudeAiConnectors?: boolean; /** * How the provider asks for + reads back the structured object. DEFAULT * `'json_schema'` so existing behavior is UNCHANGED. * * - `'json_schema'` — the SDK's structured-output mode: `outputFormat` is set, * the SDK runs its multi-turn generate → emit → validate loop, and the * SDK-validated object is read from `result.structured_output`. Robust but * pays the multi-turn latency the benchmark targets. * - `'prompt'` — OMIT `outputFormat`, append a "emit raw JSON conforming to * this schema" directive to the prompt, run a small turn budget, then PARSE * the terminal text and VALIDATE it locally in a single turn — faster and * fewer turns, on the same subscription path. See * {@link AnthropicAgentOutputMode}. * * This is a provider-internal toggle the benchmark exercises; the production * factory explicitly selects `'json_schema'`. */ outputMode?: AnthropicAgentOutputMode; /** * Reasoning EFFORT level forwarded to the SDK's `query()` as `effort`. Tunes * how much thinking/reasoning the model applies: `'low'` is minimal thinking / * fastest, up through `'high'` (the SDK default) / `'xhigh'` / `'max'`. Lowering * it trades reasoning depth for latency — appropriate for the MECHANICAL propose * task, which does not need deep reasoning. * * UNSET (the default) does NOT forward `effort` at all, so the SDK's own default * (`'high'` — "Deep reasoning") stands and production behavior is unchanged. This * is a pass-through knob the benchmark exercises; the factory leaves it unset. */ effort?: EffortLevel; /** * Extended-THINKING configuration forwarded to the SDK's `query()` as `thinking`. * `{ type: 'disabled' }` turns off extended thinking entirely; `{ type: 'adaptive' }` * lets the model decide (the SDK default), and `{ type: 'enabled', budgetTokens }` * pins a budget. Disabling it trades reasoning for latency — appropriate for the * MECHANICAL propose task. * * UNSET (the class default) does NOT forward `thinking` at all, so the SDK's own * default (adaptive thinking) stands. This is a pass-through knob the benchmark * exercises; the production factory explicitly disables thinking. */ thinking?: ThinkingConfig; } /** * Build the per-call `options.env` for the subscription path from an ambient * environment and an optional explicit OAuth token. * * PURE and OFFLINE — the api-key-shadowing guard that this function encodes is * the security-critical bit, so it lives here, unit-tested, separate from the * network call: * - The resolved `CLAUDE_CODE_OAUTH_TOKEN` is whatever the explicit token is, * else the ambient `CLAUDE_CODE_OAUTH_TOKEN`. Missing both is a hard error — * the subscription path cannot authenticate. * - `ANTHROPIC_API_KEY` is deliberately OMITTED from the returned env even when * present ambiently, because it OUTRANKS the OAuth token and would silently * divert the call onto the metered API-key path (development-plan §7). The * returned record is the ENTIRE env handed to the SDK for the call, so an * omitted key cannot leak in. */ export declare function resolveAuthEnv(env?: Record, oauthToken?: string): Record; /** * Pick which served model to report on {@link ProviderResult.model} from the * SDK's per-model usage aggregate. An agentic run can report usage under more * than one model key (e.g. a sub-agent on a different model), so rather than * pick an arbitrary enumeration key we choose the model that did the most work — * the one with the largest total token usage (input + output). Ties and absent * counters fall back to enumeration order, and an empty/missing aggregate falls * back to `fallbackModel`. The single-model Haiku path is unaffected (one key). */ export declare function pickServedModel(modelUsage: SDKResultMessage['modelUsage'] | undefined, fallbackModel: string): string; /** * Extract a validated {@link ProviderResult} from the Agent SDK's TERMINAL * result message, or throw {@link AgentProviderError}. * * PURE and OFFLINE so the success / error-subtype / missing-structured-output * branches are unit-testable with synthetic `SDKResultMessage` objects, no * `query()` required: * - `subtype: 'success'` WITH `structured_output` → resolve with that validated * value (the SDK already enforced the schema), plus `total_cost_usd`, model, * raw `result` text, and usage. * - `subtype: 'success'` WITHOUT `structured_output` → throw: a success that * produced no structured object violates our contract. * - any error subtype (`error_max_structured_output_retries`, * `error_during_execution`, `error_max_turns`, `error_max_budget_usd`) → * throw, preserving the subtype and accrued cost. */ export declare function extractResult(result: SDKResultMessage, fallbackModel: string): ProviderResult; /** * The Anthropic Agent SDK / subscription provider. Implements the single * {@link LLMProvider} operation by driving `query()` in JSON-schema output mode * and returning the SDK-validated `structured_output`. */ export declare class AnthropicAgentProvider implements LLMProvider { #private; readonly name = "anthropic-agent-sdk"; constructor(options?: AnthropicAgentProviderOptions); /** * Generate a schema-validated object via the subscription Agent SDK path. * Branches on the constructed `outputMode`: * - `'json_schema'` (default): drives the SDK's structured-output mode and * returns the SDK-validated `structured_output` (multi-turn, robust). * - `'prompt'`: asks for raw JSON in the prompt, then parses + validates the * terminal text locally in one turn (faster, fewer turns). * * Either way it resolves only with a value validated against `request.schema` * and rejects with {@link AgentProviderError} on a terminal SDK error, a * parse/validate failure (`prompt_parse_failed`, prompt mode), missing * structured output (json_schema mode), missing auth, or abort. */ generate(request: ProviderRequest): Promise>; }