/** * Copyright (c) 2026, Salesforce, Inc., * All rights reserved. * For full license text, see the LICENSE.txt file */ /** * Typed error markers used to classify failures at the MCP tool boundary * (W-22697673). The MCP adapter (`schemas/tool-adapter.ts`) maps these * to category prefixes — `Auth:` / `Schema:` / `UserInput:` — so an agent can * distinguish an infra/auth/schema failure from a user-input mistake without * parsing free text. `MutationContextError` (walker) is also treated as * UserInput; message heuristics remain a secondary fallback for untyped throws. * Everything unmatched falls through to `Internal:`. */ /** * Retryability disposition for a `Schema:` failure (W-23148365). Surfaced to the * MCP host as a closed-set `[retry=...]` token appended to the error text so an * agent can decide whether to retry, back off, or give up: * - `"now"` — retry immediately; the failure involved no live org round-trip * (a priming-lock wait timeout), so an instant retry is likely to * succeed. * - `"backoff"` — the introspection request failed transiently (HTTP 5xx/429/420 * or a network errno) AND the connection layer already exhausted * its one built-in retry, so wait with increasing backoff before * retrying — some org-side conditions (e.g. an API rate limit) may * take longer than a second or two to clear. * - `"no"` — permanent: a 4xx, a malformed/absent `__schema`, GraphQL errors * in the introspection body, or no cached schema. Don't retry — * fix the request, re-authenticate, or (re)prime via `sf_gql_connect`. * `Auth` / `UserInput` / `Internal` errors are uniformly non-retryable and never * carry a token; only `SchemaError` / `SchemaRefreshError` carry `retry`. */ export type RetryHint = "now" | "backoff" | "no"; /** * Classify the underlying cause of a Schema failure into a {@link RetryHint}. * * Defensive by construction: inspects an untyped `cause` (the jsforce / * `@salesforce/core` error that bubbled up from `connection.request`, or a Node * `ErrnoException` from a cache write) without assuming a type. Reads three shapes, * in order: a numeric HTTP `statusCode`, a parsed `errorCode` / `name` (e.g. * `ERROR_HTTP_503`, `REQUEST_LIMIT_EXCEEDED`), then the network/IO `code` errno. * For a real jsforce HTTP failure the `ERROR_HTTP_` regex on `errorCode`/`name` * is the load-bearing path — jsforce-node's `HttpApiError` sets string `name`/ * `errorCode` but NOT a numeric `.statusCode`, so the first branch is a defensive * fallback for other cause shapes (and the contract tests' `statusCode`-bearing * doubles), not the production trigger. Anything unrecognized returns `"no"` — we * never INVENT retryability, and the connection layer has already spent its one * transient retry before the error reaches us, so an unknown failure that survived * that retry is treated as permanent. * * Every property read is wrapped so a `cause` with a throwing accessor cannot * escape (this runs inside `runTool`'s catch, where an escaped throw would drop * the sanitized `: ` envelope and leak a raw SDK error). Real * causes (jsforce/`@salesforce/core`/`fs` errors) carry plain-data fields, so this * is a defensive backstop, not a live path; a throw simply falls back to `"no"`. */ export declare function classifyCause(cause: unknown): RetryHint; /** * Detect whether an introspection/download `cause` is a 401/403-class auth failure * that should surface as `Auth:` (re-authenticate) rather than `Schema:` (W-23335328). * * Mirrors {@link classifyCause}'s defensive shape-reading. A real jsforce / * `@salesforce/core` HTTP failure carries a string `errorCode`/`name` — jsforce-node's * `HttpApiError` sets `ERROR_HTTP_401`/`ERROR_HTTP_403` for a status-only failure, or * the body's code (e.g. `INVALID_SESSION_ID`) for an expired session — but NOT a numeric * `statusCode`; so the `ERROR_HTTP_` regex on `errorCode`/`name` and the * `AUTH_ERROR_CODES` check are the load-bearing paths, and the `statusCode` branch is a * defensive fallback for other cause shapes (and the contract tests' status-bearing * doubles). Every property read is wrapped so a `cause` with a throwing accessor falls * back to `false` (this runs on the priming-failure path; an escaped throw would drop the * classification). Returns false for a null/undefined/non-object cause and for any * non-auth status — we never over-broaden: a 4xx that is not 401/403 stays `Schema:`. * * Note (W-23148365 N3): callers must key the Auth reclassification off THIS cause-shape * inspection, never off retry-token absence or schema-cache survival — a forced refresh * that keeps a usable cache emits no token regardless of the cause, so "no token" is not a * reliable signal that a 401/403 occurred. */ export declare function isAuthError(cause: unknown): boolean; /** Credential/auth resolution failure (e.g. unknown org, expired token). → `Auth:` */ export declare class AuthError extends Error { constructor(message: string, opts?: { cause?: unknown; }); } /** * Agent-supplied input or spec violation that the user can fix: an unknown * type/field/argument named in a request, an invalid navigation, a malformed * command. → `UserInput:`. Carrying this typed marker keeps classification off * the brittle message-shape heuristics for the navigation/validation sites that * throw it. */ export declare class UserInputError extends Error { constructor(message: string, opts?: { cause?: unknown; }); } /** * Schema introspection / priming / build failure. → `Schema:` * * Carries a {@link RetryHint} (`retry`, default `"no"`) stamped at the throw site * from the underlying cause (W-23148365). The MCP adapter reads this field to * append the `[retry=...]` token; throw sites that know the disposition (a * permanent missing-`__schema`, a transient lock timeout) set it explicitly, * and the lazy-prime wrap derives it via {@link classifyCause}. */ export declare class SchemaError extends Error { readonly retry: RetryHint; constructor(message: string, opts?: { cause?: unknown; retry?: RetryHint; }); }