agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
112 lines • 5.22 kB
TypeScript
/**
* ContextWindowExceededError — "the request did not fit" as a typed error
* that names the fixes (9.6.0).
*
* Every vendor refuses an over-long request in its own words, and until now
* every one of them reached the caller as an opaque provider error:
*
* [openai] 400 Input tokens exceed the configured limit of 272000 tokens.
* Your messages resulted in 879073 tokens.
*
* That is the message a production field deployment spent a day on. It is a
* true sentence and a useless one: it does not say which of the framework's
* dials moves that number, and it looks exactly like a transient 400 — so the
* natural next move is to retry, which re-sends the same oversized history and
* fails identically, forever.
*
* So the adapters translate it, ONCE, into an error whose message contains the
* three fixes in the order they are worth trying, and which carries the two
* numbers (limit, actual) when the vendor stated them.
*
* **Detection is deliberately conservative.** Only unmistakable phrases and
* vendor codes translate; everything else passes through untouched as the
* provider error it always was. In particular a RATE limit ("rate limit
* reached … tokens per min") is a different failure with a different fix and
* must never land here — which is why no pattern matches on "too many tokens".
*
* @see ../core/runCheckpoint.ts where this class makes `resumeOnError`
* stop advertising a resume that cannot work
*/
/** Discriminator carried on the error — stable across releases. */
export declare const ERR_CONTEXT_WINDOW_EXCEEDED: "ERR_CONTEXT_WINDOW_EXCEEDED";
/**
* Thrown by an LLM adapter when the provider refused the request because the
* prompt did not fit the model's context window.
*
* A refusal, not a failure of the model: nothing was generated and nothing was
* charged for output. Retrying the identical request is deterministic — it
* fails the same way — so this is one of the classes
* {@link canResume} reports as not resumable.
*
* @example
* ```ts
* import { ContextWindowExceededError } from 'agentfootprint';
*
* try {
* await agent.run({ message: 'summarise the fabric inventory' });
* } catch (err) {
* if (err instanceof ContextWindowExceededError) {
* console.error(`sent ${err.actualTokens} against ${err.limitTokens}`);
* // …cap the tool result, or add .window(slidingWindow({ keepRecentTurns: 2 }))
* }
* }
* ```
*/
export declare class ContextWindowExceededError extends Error {
readonly code: "ERR_CONTEXT_WINDOW_EXCEEDED";
/** Which adapter refused — `'openai'`, `'anthropic'`, `'bedrock'`, … */
readonly provider: string;
/** The model's (or gateway's) ceiling in tokens, when the vendor said it. */
readonly limitTokens?: number;
/** What the request actually came to in tokens, when the vendor said it. */
readonly actualTokens?: number;
/** HTTP status, when there was one. Kept so retry policies still see a 4xx. */
readonly status?: number;
/** The provider's own error, unchanged. */
readonly cause?: Error;
constructor(args: {
provider: string;
providerMessage: string;
limitTokens?: number;
actualTokens?: number;
status?: number;
cause?: Error;
});
}
/** `true` for the typed error, including across a `structuredClone`-free
* boundary where `instanceof` still holds. Kept as a function so callers do
* not have to import the class to ask the question. */
export declare function isContextWindowExceeded(err: unknown): err is ContextWindowExceededError;
export interface ContextWindowTranslation {
/** Which adapter is asking — appears in the message prefix. */
readonly provider: string;
/**
* Extra text to search — the HTTP body, for adapters that read the response
* themselves instead of going through a vendor SDK.
*/
readonly bodyText?: string;
/** Status the adapter already knows (browser adapters read it off `Response`). */
readonly status?: number;
}
/**
* Does this error SAY it is a context overflow, whoever produced it?
*
* The same conservative phrase test the adapters translate on, asked without
* building anything — for code that has to classify an error it did not
* catch at an adapter boundary. A custom `LLMProvider`, a gateway wrapper or
* a proxy in front of a vendor produces the vendor's sentence without ever
* passing through `wrapError`, and a caller reading that error deserves the
* same answer an adapter would have given.
*
* @see ../core/runCheckpoint.ts — the caller this exists for
*/
export declare function looksLikeContextWindowExceeded(err: unknown, bodyText?: string): boolean;
/**
* Translate a provider error into {@link ContextWindowExceededError} — or
* return `undefined`, which means "not this failure, leave it alone".
*
* Already-translated errors are returned as they are, so an adapter that
* wraps another adapter cannot double-wrap.
*/
export declare function asContextWindowExceeded(err: unknown, options: ContextWindowTranslation): ContextWindowExceededError | undefined;
//# sourceMappingURL=contextWindow.d.ts.map