/** * hosting/errors — the refusals, authored once so every adapter refuses in the * same words. * * A refusal that varies by adapter is a refusal nobody can write a test or a * runbook against. These six carry a stable `code`, name WHO refused, and say * what the caller should do instead. Adapters map the codes onto whatever their * transport uses to say "no" — that mapping is the adapter's business and lives * in the adapter, never here. * * Note what is NOT here: a run that paused. That is unfinished work rather than * a refusal, and it leaves through `reply.awaiting(...)` — its own terminal — * not through an error dressed up as one. * * `requireCapability` is the last refusal and the only one that is a * programming mistake rather than a runtime condition, so it throws a plain * `Error`: nothing branches on "I forgot to feature-detect", it just needs to * say so loudly and name the adapter it is talking about. */ import type { AgentHost, ConversationHost, HostCapability, PendingAsk } from './types.js'; /** * Thrown when a request arrives at a host that is shutting down or shut down. * * `close()` lets in-flight work finish and refuses everything after it; this is * what "everything after it" receives. */ export declare class HostClosedError extends Error { readonly code: "ERR_HOST_CLOSED"; /** Which adapter refused. */ readonly hostName: string; constructor(hostName: string); } /** * Thrown when a request arrives for a session that already has a run in flight * and the policy is `'reject'`. * * The refusal is about the SESSION, not about load: two turns of one * conversation racing each other would each answer from the state the other is * about to replace. A request for any OTHER session is never refused — it * simply waits. */ export declare class ConcurrentRunError extends Error { readonly code: "ERR_CONCURRENT_RUN"; /** The session that already has a run going. */ readonly sessionId: string; /** The run that is already going, when it has announced itself. */ readonly activeRunId?: string; constructor(sessionId: string, activeRunId?: string); } /** * Raised when a run paused to ask a person something and there is **nowhere to * keep it**. * * **The run did not fail.** A pause is unfinished work: the agent stopped to ask * and is waiting for an answer. Since 7.19 a paused run is stored as * `'flowchart-v1'` and continued by a later request carrying a decision — so the * one case left where a pause genuinely cannot be carried is a request with no * session id. There is no session to store it under, and therefore no later * request that could ever answer it. * * The other half of the old meaning — "the reply cannot carry a pause" — is * gone: {@link HostReply.awaiting} carries it now. An adapter that has not * implemented that terminal still gets its pause STORED (the store is not the * transport's business) and this refusal on the wire, naming the session it can * be answered on. */ export declare class PauseNotCarriedError extends Error { readonly code: "ERR_PAUSE_NOT_CARRIED"; /** The tool that asked, when the run recorded which one it was. */ readonly toolName?: string; /** The session the paused run was stored under, when there was one. */ readonly sessionId?: string; /** Whether the paused run was stored. `false` means it is gone. */ readonly stored: boolean; constructor(toolName?: string, sessionId?: string, stored?: boolean); } /** * Thrown when a new message arrives for a session whose run is waiting on a * person's decision. * * The message is NOT run and the pause is NOT discarded — those are the two ways * this could have gone wrong. Answering the message would step over an * outstanding consent gate; dropping the paused run to make room for the message * would throw away work a person was asked about. So the request is refused, the * pending question is named, and the session sits exactly where it was. * * Answer it by sending the same session a request carrying * {@link HostRequest.decision}. */ export declare class AwaitingDecisionError extends Error { readonly code: "ERR_AWAITING_DECISION"; /** The session that is waiting. */ readonly sessionId: string; /** What it is waiting on — the same payload `reply.awaiting()` delivered. */ readonly pending: PendingAsk; constructor(sessionId: string, pending: PendingAsk); } /** * Thrown when a request carries a decision for a session that is not waiting on * one. * * Usually a duplicate delivery: the run was already continued, or already * answered, and the same decision arrived twice. Running it as an ordinary * message would put a raw approval into the conversation as if the user had * typed it, so it is refused by name instead. */ export declare class NoPendingAskError extends Error { readonly code: "ERR_NO_PENDING_ASK"; /** The session the decision was addressed to. */ readonly sessionId: string; constructor(sessionId: string); } /** * Thrown when something is sent down a conversation that has already ended. * * A closed channel that accepts frames and drops them is the worst of the three * options: the sender believes the far side got it, the far side never did, and * nothing anywhere says so. Refusing by name is the only version of this that * leaves a trace. * * `onClose` is how you avoid meeting this — subscribe, and stop sending. */ export declare class ConversationClosedError extends Error { readonly code: "ERR_CONVERSATION_CLOSED"; /** Which adapter's door this was. */ readonly hostName: string; /** The session the conversation claimed, when it claimed one. */ readonly sessionId?: string; constructor(hostName: string, sessionId?: string); } /** * Thrown when a frame is bigger than the ceiling the adapter DECLARED. * * This is the other half of {@link ConversationLimits} — a declared ceiling * nothing enforces is a number in a doc comment. The port neither chunks nor * truncates, on purpose: how a message is split, numbered and reassembled is * the consumer's protocol question, and answering it inside the adapter would * answer it for every consumer at once. So the ceiling is visible, the refusal * names it, and the splitting happens above the port where the protocol lives. */ export declare class FrameTooLargeError extends Error { readonly code: "ERR_FRAME_TOO_LARGE"; /** Which adapter's door refused. */ readonly hostName: string; /** How big the frame was, in bytes of UTF-8. */ readonly bytes: number; /** The declared ceiling it crossed. */ readonly maxFrameBytes: number; constructor(hostName: string, bytes: number, maxFrameBytes: number); } /** * Thrown when a request body names a wire operation this host does not speak, * or names one and leaves out what it needs (an artifact op without a `ref`). * * The law it enforces: **a body that named an `op` never falls through to a * model turn.** A caller who typo'd `'artifact-head'` and silently got a * conversation turn — with the ref as garbage input — would be told nothing * and billed anyway, which is the accepted-and-silently-wrong failure this * refusal exists to prevent. Adapters answer it as that request's 400: the * request is what is wrong, and the same caller can send the right shape. */ export declare class InvalidWireOpError extends Error { readonly code: "ERR_INVALID_WIRE_OP"; constructor(detail: string); } /** * Thrown when an artifact operation arrives with no session id. * * Artifact resolution is governed by the requesting session's identity — * a ref is redeemed under exactly the scope the run's tools minted it in, and * a request that names no session presents no scope to resolve under. (A run * served without a session scopes its artifacts to its own runId, which no * later request can name — so there is genuinely nothing this request could * ever redeem.) There is deliberately no bare-ref mode: an id alone opens * nothing, ever. */ export declare class ArtifactSessionRequiredError extends Error { readonly code: "ERR_ARTIFACT_SESSION_REQUIRED"; constructor(op: 'head' | 'get'); } /** * Thrown when an artifact operation arrives and the agent serving this * session has no artifact store attached. * * The teaching refusal of the fail-closed capability (`ctx.artifacts` with no * store), spoken at the hosting door: it names the attach rather than * answering "not found" — a deployment gap and a missing ref are different * facts, and only one of them is the operator's to fix. */ export declare class NoArtifactStoreError extends Error { readonly code: "ERR_NO_ARTIFACT_STORE"; constructor(op: 'head' | 'get'); } /** * Thrown when a ref does not resolve for the requesting session — missing, * expired, or minted under a scope this session's identity does not compose. * * **Deliberately one shape for all three.** Distinguishing "never existed" * from "another session's" would let a caller probe scopes it does not own; * the store already answers a wrong scope with "no data" rather than a * cross-tenant error, and this refusal keeps that ambiguity on the wire. * The screen renders a stated absence in place — the `present` result's * description snapshot exists exactly so an expired pane can still say what * is gone. */ export declare class ArtifactNotFoundError extends Error { readonly code: "ERR_ARTIFACT_NOT_FOUND"; /** The ref that did not resolve. */ readonly ref: string; constructor(ref: string); } /** * Raised when an artifact RESOLVED and the reply cannot describe it — a host * without {@link HostReply.artifact}, or an `HttpWire` dialect without an * `artifact` body shape. * * The `PauseNotCarriedError` shape, for the other optional terminal: the * resolution itself succeeded and nothing about the store is wrong — it is * THIS REPLY that has no vocabulary for the answer. Named rather than * improvised, because an adapter inventing a body shape on the spot would be * a body no client was written against. */ export declare class ArtifactNotCarriedError extends Error { readonly code: "ERR_ARTIFACT_NOT_CARRIED"; /** The ref that resolved but could not be delivered. */ readonly ref: string; constructor(ref: string, hostName?: string); } /** * Thrown when a store hands back something that is **present but unreadable** * where a `CheckpointEnvelope` should be. * * The law, in the words of the field report that bought it: * * > *An unreadable stored conversation and an absent one are different facts, * > and only one of them is safe to answer with a fresh start.* * * Absent is ordinary — a new session has no conversation, and answering it * fresh is exactly right. Unreadable is not ordinary: a conversation EXISTS, * somebody is in the middle of it, and starting fresh over the top of it looks * identical to the happy path from the outside. Nobody finds that until a * deployment boundary hands a user a stranger's blank slate. So this refuses, * loudly, naming the session — the one thing a silent `undefined` could never * do. * * It extends `TypeError` because that is what it always was: the refusal gained * a name, a `code` and the session it is about, but a caller who was already * catching a `TypeError` from a reader keeps working. * * `storedPreview` quotes at most 64 characters (`STORED_PREVIEW_LIMIT`, in * `lib/storedPreview` — one cap, shared by every adapter that has to describe * bytes it could not read) — enough to recognise a mangled encoding at a * glance, never the conversation itself. */ export declare class UnreadableEnvelopeError extends TypeError { readonly code: "ERR_UNREADABLE_ENVELOPE"; /** The session those bytes were stored under, when the refuser knows it. */ readonly sessionId?: string; /** A short, deliberately truncated rendering of what the store handed back. */ readonly storedPreview: string; constructor(stored: unknown, sessionId?: string); /** * The same refusal, naming the session — for a reader that knew the bytes * were unreadable but not whose conversation they were. * * Returns a copy rather than mutating: an error already thrown past somebody * is a fact about a moment, and editing it under them is how two stack traces * end up disagreeing about what happened. */ withSession(sessionId: string): UnreadableEnvelopeError; } /** * WHY a presented credential did not identify anybody — the whole vocabulary a * refusal is allowed to say about a token. * * Every value here is a fact about the CHECK, never about the secret. That is * the point of enumerating them at all: an operator needs to act differently on * each one, and `expired` versus `wrong-audience` versus `unverifiable` is the * entire difference between "the client should refresh", "the client is pointed * at the wrong API" and "somebody is presenting something we cannot check" — * none of which requires printing one character of the token. * * - `'no-token'` — no `Authorization: Bearer …` arrived at all. * - `'expired'` — the token's own lifetime is over. * - `'not-yet-valid'` — its `nbf` is in the future (a clock-skew smell). * - `'wrong-audience'` — it was minted for a different API. * - `'wrong-issuer'` — it came from an IdP this door does not accept. * - `'unverifiable'` — the signature did not check out, no key matched, the * algorithm is not allowed, or it is not a token at all. Deliberately ONE * class: distinguishing "bad signature" from "unknown key" tells whoever is * probing which half of a forgery to fix. * - `'claimed-another-user'` — a valid token, and a request that signed * somebody else's name beside it. */ export type IdentityFailureClass = 'no-token' | 'expired' | 'not-yet-valid' | 'wrong-audience' | 'wrong-issuer' | 'unverifiable' | 'claimed-another-user'; /** * The caller could not be identified, and this door was configured to insist. * * **The message never contains the token.** Not truncated, not hashed, not "the * first eight characters". A bearer token in a refusal is a bearer token in the * reply body, in the log line, in the trace and in every sink attached — one * echo and the credential has been published. What travels is * {@link IdentityFailureClass} and the sentence that tells the caller what to * do about it. */ export declare class IdentityNotVerifiedError extends Error { readonly code: "ERR_IDENTITY_NOT_VERIFIED"; /** What went wrong, in the one vocabulary. Never the token. */ readonly failure: IdentityFailureClass; /** Did the request also NAME a user it could not prove? The impersonation * shape, kept as a fact so a sink can count it separately. */ readonly claimedUser: boolean; constructor(failure: IdentityFailureClass, claimedUser: boolean); } /** * The verifier itself could not do its job — its key set was unreachable, its * introspection endpoint timed out. * * A DIFFERENT fact from a token that failed, and the difference is who is at * fault: this is the deployment's outage, not the caller's bad credential, and * answering it with a 401 would send every client off to re-authenticate * against an identity provider that is already down. It maps to 503. */ export declare class VerifierUnavailableError extends Error { readonly code: "ERR_IDENTITY_VERIFIER_UNAVAILABLE"; /** Which verifier could not answer — its name, never its configuration. */ readonly verifier: string; constructor(verifier: string, detail?: string); } /** * An admission policy refused this request before any work started. * * The policy authors the sentence — this class only carries it — because the * limit and its reset are the operator's facts, not the library's. What this * class guarantees is the SHAPE: a refusal that names a limit is a refusal a * client can act on, and one that says "denied" is a support ticket. */ export declare class AdmissionRefusedError extends Error { readonly code: "ERR_ADMISSION_REFUSED"; /** WHO was refused, when the request identified anybody. Never a token. */ readonly userId?: string; constructor(reason: string, userId?: string); } /** * A session-history operation arrived at a door that does not verify identity. * * Listing a person's conversations is answering "which sessions belong to * you?", and a door that reads WHO from an unverified header would answer that * for anyone who guesses a user id — enumeration with a friendly interface. * So the ops are refused outright rather than served under a claimed name. */ export declare class SessionOpNeedsIdentityError extends Error { readonly code: "ERR_SESSION_OP_NEEDS_IDENTITY"; /** The op that was refused. */ readonly op: string; constructor(op: string); } /** * A session-history operation arrived at a session store that keeps no * owner index. * * The two members are OPTIONAL on the port on purpose — most stores are a * key/value map and owe nobody a secondary index — so this refusal names the * store's limitation instead of pretending the answer is "you have no * sessions". An empty list and an unanswerable question are different facts, * and only one of them is safe to render as "nothing here". */ export declare class SessionIndexUnavailableError extends Error { readonly code: "ERR_SESSION_INDEX_UNAVAILABLE"; readonly op: string; constructor(op: string, missing: string); } /** * Retention was asked of a session store that has no answer for it (9.42.0). * * `retention` is OPTIONAL on the port for the same reason the two index * members are — most stores are a key/value map and owe nobody a way to expire * one — so this refusal names the store's limitation rather than doing * nothing quietly. That distinction is the whole point here: an unanswerable * question and a sweep that deleted nothing look identical from a cron job's * exit code, and a deployment can run for a year believing conversations are * being expired because a call returned without complaining. * * It names which stores DO implement it, because the answer to "my store * cannot do this" is usually "then use one that can", and a refusal that makes * somebody go and find that out is a refusal that gets caught and ignored. The * two it names by hand are the two that ship in this folder; the cloud * adapters are pointed at rather than listed, because a hand-maintained list * of them inside a PORT is both a vendor name where none belongs and a list * that goes stale the release after somebody adds one. * * No identity material, like every refusal here: retention is about a store, * and nothing about who was signed in belongs in it. */ export declare class SessionRetentionUnavailableError extends Error { readonly code: "ERR_SESSION_RETENTION_UNAVAILABLE"; /** What was being attempted, in the caller's words. */ readonly purpose: string; constructor(purpose: string); } /** * The ONE answer for a session the caller may not have — read OR continued. * * A session that does not exist, one that belongs to somebody else, and one * whose stored conversation names no owner all end here, byte-identical but * for the id the caller already knew. Told apart, they would be an oracle for * which session ids are real — the same law * {@link ArtifactNotFoundError} follows, for the same reason. * * Raised by BOTH doors that open a session at a verifying host: the two * session-history ops, and an ordinary turn that named somebody else's session * (9.26.0). One refusal, so the answer cannot depend on which door a caller * knocked at — the mistake this class of hole is always made of. */ export declare class SessionNotFoundError extends Error { readonly code: "ERR_SESSION_NOT_FOUND"; /** The id that was asked for — the caller's own string, nothing learned. */ readonly sessionId: string; constructor(sessionId: string); } /** * A `persist` would have left the ownership index naming one person and the * stored conversation naming another (9.36.1). * * ── The split brain this exists to prevent ────────────────────────────────── * The write-once rule protects the INDEX and said nothing about the PAYLOAD. * Two writers signing the same fresh session therefore produced a store where * `ownerOf(session)` answered the FIRST writer and the stored envelope carried * the SECOND writer's whole conversation — and the envelope carries its own * identity. The first writer lists the session, opens it, and reads somebody * else's conversation. That is not a race in one backend: it was reproduced in * a live trial and then found, by inspection, in every store implementing this * contract, because the flaw was in the contract rather than in any of them. * * So the rule gained its missing half: **a different non-empty identity is * refused, and an absent one is allowed.** A leaner turn claims nobody and * cannot contradict anybody — the contract explicitly blesses it — while a * turn signed by somebody else is a contradiction, and a store that stored it * would be a store where ownership is decided by who wrote last. * * ── What this refusal will not tell you ───────────────────────────────────── * Neither name. Not the owner, not the caller, not a line of either * conversation. An error is read by whoever provoked it, and a refusal that * names the person who owns a session is an oracle for who is signed in — the * same law {@link SessionNotFoundError} and {@link ArtifactNotFoundError} * follow. The session id is here because it is the caller's own string, which * is the one thing the message teaches nobody anything by repeating. */ export declare class SessionOwnershipConflictError extends Error { readonly code: "ERR_SESSION_OWNERSHIP_CONFLICT"; /** The id that was written to — the caller's own string, nothing learned. */ readonly sessionId: string; constructor(sessionId: string); } /** * A session-history result resolved and the reply cannot describe it. * * The {@link ArtifactNotCarriedError} shape, for the other new terminal. */ export declare class SessionsNotCarriedError extends Error { readonly code: "ERR_SESSIONS_NOT_CARRIED"; readonly op: string; constructor(op: string, hostName?: string); } /** * Assert that a host can do something, and throw a corrective error naming the * adapter when it cannot. * * This is the feature-detection law with teeth: capabilities are read, never * assumed, and asking for one that is absent tells you which adapter you are * actually holding rather than failing quietly somewhere downstream. * * Takes either port, because both declare the same two facts — who they are and * what they can do — and a caller holding a conversation-only host is entitled * to the same answer as one holding a request host. * * @example * requireCapability(host, 'streaming'); // throws unless this host streams * * // or branch instead of insisting: * if (host.capabilities.includes('streaming')) { ... } */ /** * Thrown when a request body exceeds the ceiling the host was given. * * A body is memory this process pays for while somebody else fills it, so a * host with a ceiling stops reading at it rather than discovering the limit as * an out-of-memory kill. The read is abandoned at the byte that crossed the * line — nothing further is buffered, and the bytes already read are dropped. * * There is no default ceiling: see `HttpHostOptions.maxBodyBytes` for why the * absence is deliberate and what it costs. */ export declare class RequestTooLargeError extends Error { readonly limitBytes: number; readonly code: "ERR_REQUEST_TOO_LARGE"; constructor(limitBytes: number, hostName: string); } /** * A dialect's refusal of THIS request — its own status, its own code. * * `readRequest` is a wire's one chance to look at a body before a turn is paid * for, and some dialects can tell from the shape alone that they cannot serve * it: an input item kind this dialect does not carry, a field whose type is * wrong. Throwing this says so with a status the caller can act on, instead of * a 500 that reads as "the server broke" for a request the caller could fix. * * The distinction it keeps: this is the REQUEST being wrong. A dialect that * throws anything else from `readRequest` still gets that request's 500, which * is the honest answer when the dialect itself is what failed. * * @example A dialect refusing an input kind it does not carry * throw new WireRequestRefusal( * 'unsupported_input', * 'image input is not carried by this dialect', * ); */ export declare class WireRequestRefusal extends Error { readonly code: string; /** HTTP status for this refusal. Default 400 — the request is what is wrong. */ readonly status: number; constructor(code: string, detail: string, /** HTTP status for this refusal. Default 400 — the request is what is wrong. */ status?: number); } export declare function requireCapability(host: AgentHost | ConversationHost, capability: HostCapability): void; //# sourceMappingURL=errors.d.ts.map