UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

78 lines (77 loc) • 4.39 kB
/** * Adaptive `max_tokens` recovery for the ONE provider 400 that is self-healing (CC parity `Fjp` / * `Ijp`, ruled 2026-08-05). * * The failure: the input fits the model's context window, but `input + max_tokens` does not. Nothing * downstream rescues it — the compaction layer's own detectors match "prompt is too long", a * DIFFERENT message meaning the input ALONE overflows, so this 400 is classified `invalid_request`, * is not retried, and terminates the task even though lowering this one request's output cap would * have served it. The provider states every number needed to compute the fix in the error text. * * The recovery is deliberately NARROW: only a 400 whose body carries this exact sentence can trigger * it, and anything the parser cannot read as three integers leaves the original failure untouched. * Two fail-loud guards then bound it — a floor below which lowering the cap stops being useful, and * a no-progress guard so a provider that keeps reporting the same numbers cannot loop the engine. */ /** CC parity (`Ijp`): the smallest output cap worth retrying with. Below this the answer room is so * small that a re-send is not a recovery, so the original 400 is surfaced instead. */ export declare const FLOOR_OUTPUT_TOKENS = 3000; /** The three numbers the provider reported. */ export interface ContextOverflowReport { /** Tokens the provider measured in the request input. */ inputTokens: number; /** The output cap this request carried. */ maxTokens: number; /** The model's total context limit, as the provider counts it. */ contextLimit: number; } /** * Read the three numbers out of a provider 400 body, or `undefined` for every other failure — * including a 400 of any other shape, a body whose provenance is unestablished, a truncated body, and * numbers too large to be exact integers. A caller that gets `undefined` must surface the original * failure unchanged. */ export declare function parseContextOverflow(status: number, body: string): ContextOverflowReport | undefined; /** * What to do about a parsed overflow. `adjust` is the only outcome that re-sends; the other two are * refusals that the caller must report ALONGSIDE the original provider failure, so an operator sees * that a recovery was attempted and why it was declined rather than a bare 400. */ export type OutputCapAdjustment = /** `current` is the cap this adjustment lowers FROM — the smallest one known to be in effect, which * is what a disclosure must name (the provider's echoed number may not be what was sent). */ { outcome: "adjust"; maxOutputTokens: number; current: number; } /** The room left under the context limit is below {@link FLOOR_OUTPUT_TOKENS} — the input itself is * the problem, and no output cap makes this request servable. */ | { outcome: "below_floor"; available: number; } /** The recomputed cap is not STRICTLY below the cap already in effect — the previous adjustment * did not take effect, or the provider re-reported the same numbers, or the numbers would RAISE * the cap. Re-sending cannot help, and in the raising case would be actively worse. */ | { outcome: "no_progress"; available: number; current: number; }; /** * Compute the lowered output cap for a re-send, or the reason not to. * * `otherCapsInEffect` are the caps the CALLER knows about beyond the one the provider echoed — * typically the cap this engine already imposed on an earlier attempt, and the cap the request * actually carried on the wire. The SMALLEST of all of them bounds the adjustment, and a new cap * must be strictly below it. That single rule does three jobs: * - it terminates the loop (every accepted adjustment lowers the cap, and the floor bounds it); * - it makes an adapter that ignored an imposed cap fail loud after one round instead of looping; * - it keeps the recovery from ever RAISING a cap on the strength of a number the provider * reported but the request never carried. * * `report.maxTokens` is always one of the caps considered — the provider says the failing request * carried it, and a value it did not carry can only be smaller in the direction that matters. */ export declare function planOutputCapAdjustment(report: ContextOverflowReport, otherCapsInEffect?: readonly (number | undefined)[]): OutputCapAdjustment;