UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

46 lines (45 loc) • 3.45 kB
/** * design/374 slice 2 — TYPED input-too-long classification for provider refusals. * * "The request INPUT alone exceeds the model's context limit" is recognizable from prose over the * human-facing `errorMessage`, but such a classifier cannot tell a provider's own diagnostic from * caller text a gateway reflected, and breaks the moment a provider rewords. The classification runs * at the BRAIN boundary, where provenance is decidable, and the verdict rides * `BrainError.inputTooLong` → `AssistantMessage.errorKind: "input_too_long"` (the same typed lane * `degenerate`/`length_empty` already use). * * PROVENANCE DISCIPLINE (mirrors `context-overflow.ts`, the sibling classifier for the * input+max_tokens overflow — a DIFFERENT error: there the input fits and lowering the output cap * self-heals; here the input alone does not fit and only shrinking the input helps): * - The only text source is the provider's diagnostic FIELD: `error.message` of a JSON object * body whose `error` is itself an object (both the Anthropic `{type:"error",error:{…}}` and * the OpenAI `{error:{…}}` envelopes reduce to this). A plain-text body, a string `error`, a * top-level `message` — refused: each is a guess about gateway formatting that would trade a * hypothetical classification for a field a gateway may fill with caller content. * - Prose is matched ANCHORED at the start of that field only, against the conservative * context-limit FAMILY (case-insensitive; the family and its member list live with the rows that * carry them, `provider-dialect.ts`). A gateway that inlines the offending request ("validation * failed; offending prompt: prompt is too long…") therefore cannot classify: caller text must * never steer a retry. * - Structural signals need no prose at all: a provider's own context-limit CODE (OpenAI-family * `context_length_exceeded`; an endpoint's declared code such as GLM's `1261`), and HTTP 413 (the * transport's own "request entity too large"). A code the endpoint declares for something else * outranks every sentence: the provider named the failure, a sentence beside it cannot rename it. * * The verdict is a column of the provider dialect table (`provider-dialect.ts`): a context-limit * refusal is a row whose `inputTooLong` flag is set, read by the same lookup that names the failure's * `providerCondition`. This module is the reader face for a response no endpoint is known for. * * Misclassification cost: inside a PARSED provider envelope a miss is an AUTHORITATIVE negative * that SUPPRESSES the loop's prose fallback — which is why the family must carry every observed * genuine opening; prose-only bodies keep the fallback reach via the "unknown" arm. A FALSE HIT * costs one bounded recovery attempt, and only on a 400/413/422 the request already failed on. */ import { type InputTooLongVerdict } from "./provider-dialect.js"; export { startsWithInputTooLongAnchor, type InputTooLongVerdict } from "./provider-dialect.js"; /** * Classify an HTTP refusal as input-too-long against the generic rows (an endpoint no dialect declares). * `body` is the error-body text, read whole; one that does not parse as a JSON envelope answers `"unknown"` * (413 excepted — the status alone is the provider's statement). */ export declare function classifyInputTooLong(status: number, body: string): InputTooLongVerdict;