import type { Runner } from "../core/runner/runtask.js"; import type { StrategyStore } from "../core/strategy-store.js"; import type { ModelRef, TaskResult, TaskSpec } from "../core/types.js"; /** * Teacher mode (escalation cascade): a cheap "student" does the work; a strong "teacher" is consulted * only when the student is *detectably* stuck or wrong, then withdraws. * * APPLICABILITY — teacher mode assumes the task has a **decidable verify signal**: escalation only fires * when we can tell the student is failing (Tier 0 same-tool/same-error stuck, Tier 1 rubric verifier on * the final output, or a `blocked`/`failed` terminal). It pays off when "wrong" is observable. * * It does NOT fit **open-ended completeness/quality judgement** — e.g. code-review "find ALL the bugs", * creative quality — because there is no oracle for *completeness*: the verifier can't know how many bugs * the code has or which one was missed, so a student that finds one obvious issue passes the rubric while * silently missing others, and the escalation machinery idles (verified in practice: 0 escalations, the * verifier becomes pure added cost). Such tasks are solved by **breadth + adversarial debate** (a `team` * council), not by **depth escalation** — the two are orthogonal. See design/12 §六 for the full reasoning. */ /** Default teacher (advisor) system prompt — returns ONLY structured JSON guidance. */ export declare const TEACHER_PROMPT = "You are an expert advisor to a less-capable \"student\" agent that got stuck.\nYou receive the task and the student's recent failed attempts. Your job is to help the student RECOVER,\nnot to do the work for it.\n\nReturn ONLY one valid JSON object (no markdown, no prose outside it):\n{\n \"strategy\": \"\",\n \"correction\": \"\",\n \"nextStep\": \"\",\n \"takeover\": ,\n \"confidence\": <0=low .. 3=high, how sure you are this guidance is correct>\n}\n\nBe terse. Do NOT solve the whole task unless takeover=true. If you are unsure, set confidence=0 and takeover=false."; export interface TeacherConfig { /** Teacher model (overrides the `advisor` role). Default: resolve the `advisor` role. */ model?: ModelRef; /** Cheap helper model for the stuck-monitor and verifier. Default: the student's own model. */ helperModel?: ModelRef; /** Max escalations per run. Default 3. */ maxEscalations?: number; /** Stop escalating once cumulative teacher tokens exceed this fraction of student tokens. Default 0.4. */ teacherSpendRatioCap?: number; /** Consecutive same-tool failures before "suspected stuck". Default 3. */ stuckThreshold?: number; /** Cumulative same-tool failures that force escalation regardless of the monitor. Default 5. */ stuckHardOverride?: number; /** Second-guess a suspected stall with a cheap stuck-monitor call. Default true. */ useStuckMonitor?: boolean; /** Run a rubric verifier on a completed student output. Default true. */ verifyOutput?: boolean; /** After this many corrections fail, the teacher takes over instead of correcting again. Default 2. */ takeoverAfter?: number; /** Prompt overrides (instruction text) for the teacher, the rubric verifier, and the stuck-monitor. */ prompts?: { teacher?: string; verifier?: string; monitor?: string; }; /** Per-escalation progress callback. */ onEscalation?: (e: EscalationRecord) => void; /** * Decoupled escalation decision (Intent-monitor pattern, design/15). Called after a trigger fires * and the cost guards pass, but before actually consulting the teacher. Return `false` to **skip** * this escalation (the current — unresolved — result is returned). Default: always escalate. A * throw fails open (escalates), so a broken policy can't strand the student; but a policy that * always vetoes makes *you* responsible for the task ever resolving. (No internal timeout — wrap * your own if the policy may hang.) Use it to plug in a separate monitor (a cheap model or rules) * that decides whether escalating is worth it. */ escalationPolicy?: (info: { trigger: EscalationTrigger; attempt: number; result: TaskResult; recent: string[]; verifyReason?: string; }) => boolean | Promise; /** * Self-consistency for the rubric verifier (design/15). When ≥2, the verifier runs this many times * (cheap helper model) and **majority-votes** pass/fail — less noisy than a single call, so the * verify-fail escalation decision is better-calibrated. Default 1. */ verifierSamples?: number; /** * Optional strategy repository (design/14). When set **with `scope`**, relevant past strategies are * retrieved into the student's objective before the run, and the final escalation's strategy is * stored on success — so similar problems can be solved without re-consulting the teacher. */ strategyStore?: StrategyStore; /** Tenant/isolation scope for `strategyStore` (REQUIRED to enable it — strategies never cross scope). */ scope?: string; /** How many strategies to retrieve. Default 3. */ retrieveK?: number; /** Minimum teacher confidence to store a strategy. Default 2. */ minConfidenceToStore?: number; /** Inject retrieved strategies into the objective. Default true when a store+scope are set. */ injectStrategies?: boolean; } export type EscalationTrigger = "stuck" | "blocked" | "failed" | "verify-fail"; export interface TeacherAdvice { strategy?: string; correction?: string; nextStep?: string; takeover: boolean; confidence: number; /** Raw text when the JSON could not be parsed. */ raw?: string; } export interface EscalationRecord { attempt: number; trigger: EscalationTrigger; teacher: TeacherAdvice; tookOver: boolean; } export interface TeacherRunResult extends TaskResult { /** Escalations that occurred during this run (empty if the student succeeded alone). */ escalations: EscalationRecord[]; /** Usage spent on the teacher (advisor), separate from the student's `stats` (which includes the * cheap helper monitor/verifier calls). `tasks` = teacher runs (escalation asks + any takeover). * `humanReview` = the HITL-gate burden of the teacher's runs (notably a takeover that hit an approval * gate) — kept here, not in the student `stats`, since it is teacher work (mirrors the cost split). */ teacherStats: { tokens: number; tasks: number; costUsd?: number; costMicroUsd?: number; humanReview?: { count: number; totalWaitMs: number; gates: Array<{ kind: string; waitMs: number; decision?: string; }>; }; }; } /** Best-effort parse of the teacher's JSON advice; on failure, keep the raw text as a low-confidence correction. */ export declare function parseTeacherAdvice(text: string): TeacherAdvice; /** * Run a task with a cheap "student" model that escalates to a strong "teacher" (advisor) when it gets * stuck or produces a wrong answer — the escalation cascade / teacher mode (design/13). * * The teacher runs in an isolated session (its dialogue is discarded; only its structured JSON advice * is injected back into the student's session, so the student's prefix cache survives). Triggers: * Tier 0 — repeated same-tool failures (aborts the stuck run early); Tier 1 — a rubric verifier on a * completed output (catches "passes but semantically wrong"). Correction-then-takeover, with hard * cost guards (escalation cap, teacher-spend ratio, bounded teacher turns). */ export declare function runWithTeacher(runner: Runner, studentSpec: TaskSpec, teacher?: TeacherConfig): Promise; //# sourceMappingURL=teacher.d.ts.map