{"version":3,"file":"error-body-DKA3lknR.mjs","names":[],"sources":["../node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js"],"sourcesContent":["// Shared normalization for provider HTTP error objects.\n//\n// Endpoints behind a proxy / gateway may return a non-2xx response whose body\n// the provider SDK cannot fold into `error.message`. The SDK error object still\n// carries the HTTP status and the raw/parsed body, but under SDK-specific field\n// names. Provider catch blocks that read only `error.message` therefore drop\n// the body and surface opaque messages like `\"403 status code (no body)\"` or\n// collapse to `\"Unknown: UnknownError\"`.\n//\n// `normalizeProviderError` probes the known SDK field shapes (Mistral,\n// `openai`, `@google/genai`, AWS Bedrock) and returns a struct each provider\n// composes into its display string. The `messageCarriesBody` flag captures the\n// Anthropic / `@google/genai` happy path where the SDK already folded the body\n// into the message, so providers can preserve it without double-printing.\nexport const MAX_PROVIDER_ERROR_BODY_CHARS = 4000;\nexport function normalizeProviderError(error) {\n    if (!(error instanceof Error)) {\n        return { message: safeJsonStringify(error), messageCarriesBody: false };\n    }\n    const sdkError = error;\n    const status = extractStatus(sdkError);\n    const body = extractBody(sdkError);\n    const messageCarriesBody = body === undefined || error.message.includes(body);\n    return {\n        status,\n        body,\n        message: error.message,\n        messageCarriesBody,\n    };\n}\n/**\n * Probe the HTTP status, first numeric hit wins, in SDK-field order:\n * `statusCode` (Mistral) → `status` (`openai`, `@google/genai`) →\n * `$metadata.httpStatusCode` (Bedrock) → `$response.statusCode` (Bedrock).\n */\nfunction extractStatus(error) {\n    if (typeof error.statusCode === \"number\")\n        return error.statusCode;\n    if (typeof error.status === \"number\")\n        return error.status;\n    if (typeof error.$metadata?.httpStatusCode === \"number\")\n        return error.$metadata.httpStatusCode;\n    if (typeof error.$response?.statusCode === \"number\")\n        return error.$response.statusCode;\n    return undefined;\n}\n/**\n * Probe the raw body reason, first usable hit wins, in SDK-field order:\n * `body` string (Mistral) → `error` parsed JSON body object (`openai` SDK's\n * `this.error`) → `$response.body` (Bedrock). Empty objects and unread response\n * streams are treated as no body so they do not surface as `\"{}\"` or serialized\n * stream internals. The chosen body is truncated to the cap.\n */\nfunction extractBody(error) {\n    const bodyText = pickBodyText(error);\n    if (bodyText === undefined)\n        return undefined;\n    const trimmed = bodyText.trim();\n    if (trimmed.length === 0)\n        return undefined;\n    return truncateErrorText(trimmed, MAX_PROVIDER_ERROR_BODY_CHARS);\n}\nfunction pickBodyText(error) {\n    if (typeof error.body === \"string\")\n        return error.body;\n    if (isPlainNonEmptyObject(error.error))\n        return safeJsonStringify(error.error);\n    const responseBody = error.$response?.body;\n    if (typeof responseBody === \"string\")\n        return responseBody;\n    if (isReadableStreamLike(responseBody))\n        return undefined;\n    if (isPlainNonEmptyObject(responseBody))\n        return safeJsonStringify(responseBody);\n    return undefined;\n}\nfunction isReadableStreamLike(value) {\n    return typeof value === \"object\" && value !== null && \"pipe\" in value && typeof value.pipe === \"function\";\n}\n/**\n * Only a PLAIN object counts as an HTTP body. SDK error fields can hold class\n * instances instead of parsed bodies — AWS SDK v3's `$response.body` is an\n * HTTP stream/response wrapper object, and stringifying one produced garbage\n * like `{\"_events\":...}` as the \"body\", which then REPLACED `error.message`\n * in the composed display string. `error.message` is where the SDK puts the\n * real deserialized exception text (\"Input is too long...\", schema validation\n * details, ...), so the one useful string was discarded for noise. A class\n * instance yields no body, `messageCarriesBody` stays true, and the real\n * message survives. Complements the `pipe` sniffing above: web\n * ReadableStreams (pipeTo/pipeThrough, no `pipe`) and non-stream SDK wrapper\n * classes fail the prototype check, while parsed JSON bodies (plain objects\n * by construction) still pass.\n */\nfunction isPlainNonEmptyObject(value) {\n    if (typeof value !== \"object\" || value === null)\n        return false;\n    const proto = Object.getPrototypeOf(value);\n    if (proto !== Object.prototype && proto !== null)\n        return false;\n    return Object.keys(value).length > 0;\n}\n/**\n * Compose a display string from a normalized error. When the message already\n * carries the body (Anthropic / `@google/genai` happy path) or no body/status\n * was extracted, the message is returned unchanged. Otherwise the status and\n * body are surfaced, with an optional provider prefix.\n *\n * - no prefix: `\"<status>: <body>\"`\n * - prefix:    `\"<prefix> (<status>): <body>\"`\n */\nexport function formatProviderError(norm, prefix) {\n    if (norm.messageCarriesBody || norm.status === undefined || norm.body === undefined) {\n        return prefix !== undefined && norm.status !== undefined\n            ? `${prefix} (${norm.status}): ${norm.message}`\n            : norm.message;\n    }\n    return prefix !== undefined ? `${prefix} (${norm.status}): ${norm.body}` : `${norm.status}: ${norm.body}`;\n}\nexport function truncateErrorText(text, maxChars) {\n    if (text.length <= maxChars)\n        return text;\n    return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;\n}\nexport function safeJsonStringify(value) {\n    try {\n        const serialized = JSON.stringify(value);\n        return serialized === undefined ? String(value) : serialized;\n    }\n    catch {\n        return String(value);\n    }\n}\n//# sourceMappingURL=error-body.js.map"],"x_google_ignoreList":[0],"mappings":";;AAcA,MAAa,gCAAgC;AAC7C,SAAgB,uBAAuB,OAAO;CAC1C,IAAI,EAAE,iBAAiB,QACnB,OAAO;EAAE,SAAS,kBAAkB,KAAK;EAAG,oBAAoB;CAAM;CAE1E,MAAM,WAAW;CACjB,MAAM,SAAS,cAAc,QAAQ;CACrC,MAAM,OAAO,YAAY,QAAQ;CACjC,MAAM,qBAAqB,SAAS,KAAA,KAAa,MAAM,QAAQ,SAAS,IAAI;CAC5E,OAAO;EACH;EACA;EACA,SAAS,MAAM;EACf;CACJ;AACJ;;;;;;AAMA,SAAS,cAAc,OAAO;CAC1B,IAAI,OAAO,MAAM,eAAe,UAC5B,OAAO,MAAM;CACjB,IAAI,OAAO,MAAM,WAAW,UACxB,OAAO,MAAM;CACjB,IAAI,OAAO,MAAM,WAAW,mBAAmB,UAC3C,OAAO,MAAM,UAAU;CAC3B,IAAI,OAAO,MAAM,WAAW,eAAe,UACvC,OAAO,MAAM,UAAU;AAE/B;;;;;;;;AAQA,SAAS,YAAY,OAAO;CACxB,MAAM,WAAW,aAAa,KAAK;CACnC,IAAI,aAAa,KAAA,GACb,OAAO,KAAA;CACX,MAAM,UAAU,SAAS,KAAK;CAC9B,IAAI,QAAQ,WAAW,GACnB,OAAO,KAAA;CACX,OAAO,kBAAkB,SAAS,6BAA6B;AACnE;AACA,SAAS,aAAa,OAAO;CACzB,IAAI,OAAO,MAAM,SAAS,UACtB,OAAO,MAAM;CACjB,IAAI,sBAAsB,MAAM,KAAK,GACjC,OAAO,kBAAkB,MAAM,KAAK;CACxC,MAAM,eAAe,MAAM,WAAW;CACtC,IAAI,OAAO,iBAAiB,UACxB,OAAO;CACX,IAAI,qBAAqB,YAAY,GACjC,OAAO,KAAA;CACX,IAAI,sBAAsB,YAAY,GAClC,OAAO,kBAAkB,YAAY;AAE7C;AACA,SAAS,qBAAqB,OAAO;CACjC,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,SAAS,OAAO,MAAM,SAAS;AACnG;;;;;;;;;;;;;;;AAeA,SAAS,sBAAsB,OAAO;CAClC,IAAI,OAAO,UAAU,YAAY,UAAU,MACvC,OAAO;CACX,MAAM,QAAQ,OAAO,eAAe,KAAK;CACzC,IAAI,UAAU,OAAO,aAAa,UAAU,MACxC,OAAO;CACX,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS;AACvC;;;;;;;;;;AAUA,SAAgB,oBAAoB,MAAM,QAAQ;CAC9C,IAAI,KAAK,sBAAsB,KAAK,WAAW,KAAA,KAAa,KAAK,SAAS,KAAA,GACtE,OAAO,WAAW,KAAA,KAAa,KAAK,WAAW,KAAA,IACzC,GAAG,OAAO,IAAI,KAAK,OAAO,KAAK,KAAK,YACpC,KAAK;CAEf,OAAO,WAAW,KAAA,IAAY,GAAG,OAAO,IAAI,KAAK,OAAO,KAAK,KAAK,SAAS,GAAG,KAAK,OAAO,IAAI,KAAK;AACvG;AACA,SAAgB,kBAAkB,MAAM,UAAU;CAC9C,IAAI,KAAK,UAAU,UACf,OAAO;CACX,OAAO,GAAG,KAAK,MAAM,GAAG,QAAQ,EAAE,iBAAiB,KAAK,SAAS,SAAS;AAC9E;AACA,SAAgB,kBAAkB,OAAO;CACrC,IAAI;EACA,MAAM,aAAa,KAAK,UAAU,KAAK;EACvC,OAAO,eAAe,KAAA,IAAY,OAAO,KAAK,IAAI;CACtD,QACM;EACF,OAAO,OAAO,KAAK;CACvB;AACJ"}