/** * 0.19.0-alpha.9 — default Anthropic-backed pair-brew NavigatorHook. * * α.4 wired the structural NavigatorHook slot into brew/agent.ts. * α.5 added the proposedTest hard-signal field. α.9 ships the * default implementation: calls Anthropic with NAVIGATOR_SYSTEM + * buildNavigatorPrompt, parses the NavigatorVerdict, adapts it to * NavigatorHookVerdict (the brew-loop interface). * * Wiring path (cli α.10 will add the --with-navigator flag): * ctx.navigatorHook = createPairNavigatorHook({ anthropic, model, ... }); * * Persistent-block escalation (#77 / α.5): when `priorBlockCount >= 2` * for the same root concern, the hook MAY include a proposedTest in * the verdict — written to tests/navigator/ + folded into next iter's * red-set as a HARD signal. Logic is in the prompt; mechanics in * brew/agent.ts. */ import type Anthropic from "@anthropic-ai/sdk"; import { type NavigatorVerdict, type NavigatorPromptArgs } from "@slowcook-ai/llm-anthropic"; import type { NavigatorHook, NavigatorHookInput, NavigatorHookVerdict } from "./agent.js"; /** * Adapt NavigatorVerdict (the prompt-side shape: axes + overall + * rationale) → NavigatorHookVerdict (the brew-loop shape: overall + * concerns + costUsd + proposedTest). * * Mapping rules: * - overall "approve" → "approve" * - overall "warn" → "approve" (warn is informational; brew * only reverts on block) * - overall "block" → "block" * - concerns: each blocking axis becomes one entry ": ". * Warn-severity axes are surfaced too (lower priority). * - costUsd: passed through unchanged. * * Pure: no IO. Tested in isolation. */ export declare function navigatorVerdictToHookVerdict(verdict: NavigatorVerdict, costUsd: number): NavigatorHookVerdict; export interface PairNavigatorOptions { /** Anthropic SDK client to call. */ anthropic: Anthropic; /** Model id (e.g., "claude-sonnet-4-5-20250929"). */ model: string; /** Per-iter token cap for the navigator response. */ maxTokens?: number; /** Per-iter cost ceiling — when the LLM call would exceed this, * the hook abstains (returns null) instead of blocking the iter. */ perIterBudgetUsd?: number; /** Pricing per million tokens for cost computation. Required so * the hook can report costUsd accurately to the budget tracker. */ pricingPerMTokens: { input: number; output: number; }; /** * Loader for the per-call prompt context. Brew/agent.ts doesn't * carry mockFiles / codeMapDigest / storyTestIds / specYaml in * `NavigatorHookInput` — the caller injects a loader that supplies * those from the brew context's filesystem + spec. * * Returning null OR an empty mockFiles array does NOT abort — * the prompt will still be built; navigator just sees less context. */ loadPromptContext: (input: NavigatorHookInput) => Promise<{ mockFiles: NavigatorPromptArgs["mockFiles"]; codeMapDigest: string; storyTestIds: string[]; apiContract?: NavigatorPromptArgs["apiContract"]; crossStoryFiles?: string[]; specYaml?: string; /** * α.55 — list of source-file paths present in the repo at the * time of this iteration. Navigator uses this to ground absence * claims (must NOT assert a path is absent unless it's missing * from this list AND the diff doesn't create it). */ knownSourceFiles?: string[]; priorVerdicts?: NavigatorPromptArgs["priorVerdicts"]; } | null>; } /** * Build a NavigatorHook backed by an Anthropic LLM call. Pure * factory; the returned hook is ready to inject into BrewContext. * * Per-call flow: * 1. Caller-provided loader fills in mockFiles + codeMapDigest + * storyTestIds + spec yaml + cross-story files + prior verdicts. * 2. buildNavigatorPrompt produces the prompt; client.messages.create * runs it with NAVIGATOR_SYSTEM. * 3. Response text is parsed as NavigatorVerdict (JSON; fences * tolerated). * 4. navigatorVerdictToHookVerdict adapts to the brew-loop shape. * 5. Cost is tallied from input/output tokens × pricing. * * On any failure (load error, JSON parse, API error), the hook * returns null — brew treats null as "navigator abstained" + the * iteration proceeds to checkpoint without navigator review. */ export declare function createPairNavigatorHook(options: PairNavigatorOptions): NavigatorHook; /** * Pull the text out of an Anthropic Messages API response. Returns * empty string if the response shape is unexpected (defensive). * Pure: no IO. */ export declare function extractTextFromResponse(response: { content: Array<{ type: string; text?: string; }>; }): string; /** * Parse a NavigatorVerdict from raw LLM text. Tolerates ```json * fences + leading/trailing prose. Throws on malformed JSON or * shape mismatch — caller should catch + treat as abstain. * * Pure: validates shape; doesn't normalize/repair. */ export declare function parseNavigatorVerdict(text: string): NavigatorVerdict; //# sourceMappingURL=pair-navigator.d.ts.map