import type { ToolCallRequest } from "./tool-policy.js"; /** The classifier's verdict over one pending `ask`. */ export type AutoModeVerdict = { kind: "allow"; } /** `category` is the matched BLOCK rule name (207 output contract); `reason` starts with `[Rule Name]`. */ | { kind: "block"; category: string; reason: string; } /** The classifier could not run: model error/timeout, or the session breaker is open. NOT a decision. */ | { kind: "unavailable"; cause: "error" | "timeout" | "breaker_open"; } /** The model responded but not in the `…` contract shape. NOT a decision. */ | { kind: "parse_error"; raw: string; }; /** * Parse the 207 classifier output contract: * blocked: `yesRule Name[Rule Name] …` * allowed: `no` * The contract says the ENTIRE response must begin with `` — we strip `` blocks * first (CC-anchored: the 206 body's `dJi` removes closed thinking blocks AND a dangling unclosed * tail before its own block-scan — a reasoning model's scratch space is not part of the verdict), * then tolerate leading whitespace (models routinely emit a leading newline) but nothing else: any * other preamble is a `parse_error` (fail-closed; 207 vocabulary: `automode-parsing-error`). * * Declared STRICTER than the CC parser (`iJi`: first `` ANYWHERE in the response, closing tag * optional): a free-scan lets a prompt-injected preamble seed the verdict; our contract-anchored * parse costs only a fallback to the original human chain on the mismatch, never a silent allow. * * Strictness is polarity-asymmetric (codex review, confirmed HIGH): * - an ALLOW must be UNAMBIGUOUS: `no` followed by anything but whitespace — * a second conflicting `yes`, trailing prose, any tail at all — violates the * contract and maps to `parse_error` (the ask flows the original human chain, never a silent * allow on a malformed response); * - a stated BLOCK tolerates a tail (that is where ``/`` live, and extra * content after a block verdict can only ever be judged in the blocking direction) — a * `yes` with MISSING/empty ``/`` still maps to `block` * (with "" placeholders): the block intent is unambiguous, and downgrading a stated block * to parse_error (⇒ the ask may later auto-deny OR a human may approve) would weaken the * classifier's explicit verdict on the exact calls it flagged. */ export declare function parseAutoModeResponse(text: string): AutoModeVerdict; /** What the decider hands the deployment's `classify` hook (the assembled prompt is the hook's job * when it owns assembly; when using {@link buildAutoModePrompt} the decider passes its output). */ export interface AutoModeClassifyInput { /** The pending tool call — FINAL post-hook/post-rewrite args (the same args the gate adjudicated). */ req: ToolCallRequest; /** The human-readable text of the ask being decided (policy/safety message), when present. */ askMessage?: string; } /** The pluggable model leg: given the classify input, return the model's raw text response. * Deployment-injected (roster cheap tier per [672]③); MAY throw / reject — the decider fail-closes. */ export type AutoModeClassifyFn = (input: AutoModeClassifyInput, signal?: AbortSignal) => Promise; export interface AutoModeDeciderOptions { classify: AutoModeClassifyFn; /** Hard cap on one classification round-trip. Default 15_000 ms (sema 裁量 — CC's constant is not * established; a permission gate must not stall the whole run on a slow classifier). */ timeoutMs?: number; /** Consecutive-failure threshold that opens the session breaker (default 3, [672]② "连续 N 失败"). * Failures = unavailable(error|timeout) + parse_error. A successful round (allow/block) resets it. */ failureThreshold?: number; /** Fired ONCE when the breaker opens ([672]②: "本 session 退回非 auto + 一次性告警"). */ onBreakerOpen?: (info: { consecutiveFailures: number; lastCause: string; }) => void; } export interface AutoModeDecider { /** Never rejects. Any internal failure surfaces as `unavailable`/`parse_error` (fail-closed). */ decide(input: AutoModeClassifyInput, signal?: AbortSignal): Promise; /** True once the session breaker has opened (it never half-opens: [672]② is a SESSION fallback * to non-auto, not a retry window — a flapping classifier must not oscillate the permission mode). */ breakerOpen(): boolean; } /** * Session-scoped decider: timeout + fail-closed error mapping + a one-way circuit breaker. * One instance per run/session — the breaker state is the session's "退回非 auto" latch. */ export declare function createAutoModeDecider(opts: AutoModeDeciderOptions): AutoModeDecider; //# sourceMappingURL=auto-mode.d.ts.map