import type { LlmProvider, LlmUsage } from './provider-base.js'; export interface CriticInput { /** The user's original prompt for the current turn. Primary objective * for on-track judgment when it is a concrete ask. */ prompt?: string; /** Active Focus title/body — **background context only**. Must not * override a concrete current-turn ask. Used as primary only when the * turn prompt is empty / a bare continuation ("继续"). */ goalTitle?: string; goalBody?: string; /** Compact transcript of the latest tool calls. Capped at the last * ~10 by the caller; the critic prompt re-caps to 300 chars per * preview anyway. */ recentToolCalls: ReadonlyArray<{ name: string; isError: boolean; preview?: string; }>; } export interface CriticVerdict { onTrack: boolean; reason: string; /** When onTrack=false, the critic's one-line suggestion for what to * do differently. May be empty if the critic couldn't think of one. */ redirect?: string; /** Provider/model used for the critic call, for audit. */ modelUsed?: string; /** Token/cost usage from the critic provider call, when reported. */ usage?: LlmUsage; } export interface CompletionCriticInput { goalTitle: string; goalBody?: string; evidence: ReadonlyArray<{ name: string; preview: string; }>; } export interface CompletionCriticVerdict { completed: boolean; reason: string; modelUsed?: string; } /** * Whether the current-turn prompt is a concrete ask that outranks Focus. * Focus stays background; critic must not hard-pull back to Focus. */ export declare function isConcreteTurnAsk(prompt?: string): boolean; export declare const DEFAULT_SYSTEM_PROMPT: string; /** v1.2.99 (CR finding A2): three-valued knob. * - `off` / `0` / `false` → hard kill, never fire critic * - `always` / `on` / `1` / `true` → fire whenever any anchor exists * (prompt OR active goal) * - anything else (incl. unset) → fire ONLY when an active long-task * goal exists. Per-turn prompts alone don't trigger. * * This matches the cost story documented in CHANGELOG: day-to-day * single-turn chats pay nothing; the critic is reserved for * long-horizon work signalled by Focus-backed goal state. */ export type CriticMode = 'off' | 'always' | 'goal-only'; export declare function resolveCriticMode(): CriticMode; /** Pick the critic provider: env-named role → cheap role → null. * Returns null when no usable provider — caller treats that as * "critic disabled this turn" and skips. */ export declare function pickCriticProvider(force?: boolean): { provider: LlmProvider; role: string; } | null; /** Build the user message for the critic. Exported for unit tests. */ export declare function buildCriticUserBlock(input: CriticInput): string; /** * When Focus is only background (concrete current ask), never hard-stop * the turn for an off-track verdict — soft steer at most. Hard Focus * enforcement belongs to Loop, not Focus injection. */ export declare function shouldHardStopOnOffTrack(input: Pick): boolean; /** * Run one goal-critic check. ALWAYS returns a verdict — never throws. * Provider errors / unparseable JSON / no anchor → `onTrack=true` with * a reason explaining why we couldn't judge, so the caller treats them * as "no veto" rather than a misleading break. */ export declare function runGoalCritic(input: CriticInput, opts?: { signal?: AbortSignal; timeoutMs?: number; force?: boolean; }): Promise; /** Hard completion proof review. Evidence and recap are untrusted model/tool * data; malformed output and provider failures fail closed. */ export declare function runGoalCompletionCritic(input: CompletionCriticInput, opts?: { signal?: AbortSignal; timeoutMs?: number; }): Promise; //# sourceMappingURL=goal-critic.d.ts.map