/** * design/130 P1+P2 — wall-clock-aware call capping + graceful-finalize estimation. * * Pure state + math, unit-tested in isolation; the runner owns the wiring: * - prepare-task creates a {@link CallCapRef} and hands the harness a per-call provider closure; * - runtask feeds samples (model-call latency/output, tool durations) and the walltime deadline; * - the loop evaluates the provider right before each provider call (maxTokensPerCall seam). * * Throughput prior is deliberately CONSERVATIVE (codex ④: an optimistic prior yields an oversized * cap and a late finalize — the failure direction is silent). The EWMA takes over from the first * completed call. Cross-run per-model priors (P25/P10 history) are deferred — no history store in * this slice. */ /** Conservative first-call throughput prior (tokens/sec) — err LOW (codex ④). */ export declare const CALL_CAP_PRIOR_TOK_PER_SEC = 15; /** Fraction of the remaining wall-clock a single call may absorb (leave room for tools + next turn). */ export declare const CALL_CAP_SAFETY = 0.5; /** Never cap below this — a starved reply is worse than none (design/130 §2). */ export declare const CALL_CAP_MIN_FLOOR = 1024; /** Anthropic budget-thinking legal minimum (design/119 semantics: below this, thinking is skipped). */ export declare const CALL_CAP_THINKING_MIN = 2048; /** P2b — fixed write-out cushion bounds (design/130: 60–90s band, budget-proportional under it). */ export declare const WRITEOUT_CUSHION_MAX_MS = 75000; export declare const WRITEOUT_CUSHION_MIN_MS = 10000; /** P2b — margin under the hard deadline that the finalize write-out turn itself must respect. */ export declare const FINAL_WRITEOUT_MARGIN_MS = 5000; /** * P2b: the write-out cushion for a given wall-clock budget — 15% of the budget, clamped to the * [10s, 75s] band so tiny budgets aren't swallowed and huge budgets don't over-reserve. */ export declare function writeoutCushionMs(budgetMs: number): number; export interface CallCapState { /** EWMA output-token throughput (tok/sec); undefined until the first completed call. */ emaTokPerSec?: number; /** EWMA model-call wall latency (ms). */ emaCallMs?: number; /** EWMA tool-execution duration (ms). */ emaToolMs?: number; /** P2b: decaying max of model-call wall latency (ms) — tail-aware companion to `emaCallMs`. */ peakCallMs?: number; /** P2b: decaying max of tool-execution duration (ms) — tail-aware companion to `emaToolMs`. */ peakToolMs?: number; /** Diagnostics for the NEXT brain.call trace row (set by the provider, consumed by the tracer). */ last?: { cap: number; remainingMs: number; tokPerSec: number; thinkingSkipped: boolean; }; } /** * Shared mutable ref between prepare-task (creates + closes the provider over it) and runtask * (feeds samples + the deadline + finalize mode). */ export interface CallCapRef { state: CallCapState; /** Absolute walltime deadline (ms epoch); set by runtask once the task clock starts. */ deadlineMs?: number; /** P2: finalize was injected — raise the P1 floor so the write-out turn isn't starved. */ finalizeMode?: boolean; /** * The static ceiling the shrink respects (spec.limits.maxOutputTokens ?? current model's * maxTokens). MUTABLE (codex delta ②): a mid-run degrade switch to a smaller model must * TIGHTEN it (runtask's degrade site), or the dynamic cap could exceed the served model's * real limit. Only ever lowered, never raised. */ staticCapTokens?: number; /** TB telemetry B2 (service [397]): count of calls whose max_tokens was actually shrunk * (computeCallCap returned a cap). Incremented by the prepare-task provider closure; * folded into `stats.mechanisms.capShrinks` at result assembly. */ shrinks?: number; /** * P2b: the write-out cushion (ms) — set by runtask alongside `deadlineMs` iff graceful finalize * is on. Presence ARMS the soft execution deadline ({@link softExecDeadlineMs}: brain call cutoff * + foreground tool-timeout clamp) and widens the finalize boundary condition * (`remaining < est + cushion`). Absent ⇒ P2b execution hardening is inert. */ cushionMs?: number; /** P2b telemetry: count of foreground shell timeouts clamped to the soft tool deadline * (incremented by the hands-toolkit clamp notifier; folded into `stats.mechanisms.toolClamps`). */ toolClamps?: number; /** * service [405] P0 — the run has OBSERVED self-directed reasoning output (an assistant message * carrying a thinking block). P1's cap math (`walltime × visible-output-throughput × safety`) * is structurally WRONG for such models: reasoning tokens bill against max_tokens but produce * no visible output, so a hard cap decapitates the reasoning mid-thought (TB full-89: 14 calls * with completionTokens == callCap, two solved tasks lost). Once observed, the P1 shrink is OFF * for the rest of the run. The first call is protected by `Model.reasoning` metadata instead — * this runtime flag is the safety net for deployments whose metadata is wrong (TB's deepseek * spec said `reasoning:false`; the model reasons anyway). */ reasoningObserved?: boolean; } /** * P2b: the ABSOLUTE soft execution deadline (ms epoch) for the next call/tool, or undefined when * inert (deadline not armed / graceful finalize off). While working: `deadline − cushion`, so a * long call/tool is cut/clamped with the write-out window intact. Once the finalize write-out turn * is in flight (`finalizeMode`): `deadline − a small margin`, so the final turn may use the cushion * it was reserved. */ export declare function softExecDeadlineMs(ref: CallCapRef): number | undefined; export declare function createCallCapRef(): CallCapRef; /** * Feed one completed model call (output tokens + wall latency) into the EWMAs. * Zero-output calls are DISCARDED entirely (codex delta ④): a degenerate / aborted / * usage-missing call returns fast with no work — folding its latency into `emaCallMs` would pull * the finalize estimate optimistic exactly when the provider is misbehaving. */ export declare function recordCallSample(state: CallCapState, outputTokens: number, latencyMs: number): void; /** Feed one completed tool execution into the tool-duration EWMA. */ export declare function recordToolSample(state: CallCapState, durationMs: number): void; /** * P1: compute the per-call output cap from the remaining wall-clock. * Returns undefined when no shrink applies (no deadline yet / already past it — the hard-abort * path owns that — or the derived cap would not shrink below the static ceiling). * * @param thinkingActive whether this run requests budget-thinking (the [1024,2047] contract only * matters then). */ export declare function computeCallCap(ref: CallCapRef, nowMs: number, thinkingActive: boolean): number | undefined; /** * P2: estimate one more full model-call + tool cycle (ms), with headroom. Conservative by * construction: EWMA samples from THIS run, a fat prior before any samples. P2b: TAIL-AWARE — the * per-leg base is `max(EWMA, decayed peak)`, not the mean alone (a run of small tail calls used to * pull the mean low right before one more heavy call crossed the deadline; the decayed peak keeps * the heavy sample in the estimate for several rounds). Only ever raises the estimate, i.e. only * ever finalizes EARLIER — the safe direction. */ export declare function estimateCycleMs(state: CallCapState): number; //# sourceMappingURL=call-cap.d.ts.map