| /** | |
| * Defines shared errors for AI operations. | |
| * | |
| * `AiError` records where a failure happened and stores the detailed reason in a | |
| * `reason` field. Those reasons cover transport problems, provider responses, | |
| * rate limits, authentication, content policy failures, invalid requests, | |
| * invalid output, unsupported schemas, tool failures, invalid user input, and | |
| * unknown failures. This module also includes metadata schemas, guards, | |
| * constructors, and helpers for converting HTTP response information into AI | |
| * error reasons. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| import * as Duration from "../../Duration.js"; | |
| import * as Effect from "../../Effect.js"; | |
| import * as Option from "../../Option.js"; | |
| import * as Predicate from "../../Predicate.js"; | |
| import { redact } from "../../Redactable.js"; | |
| import * as Redacted from "../../Redacted.js"; | |
| import * as Schema from "../../Schema.js"; | |
| import { HttpRequestDetails, HttpResponseDetails } from "./Response.js"; | |
| const ReasonTypeId = "~effect/unstable/ai/AiError/Reason"; | |
| const providerMetadataWithDefaults = () => ProviderMetadata.pipe(Schema.withConstructorDefault(Effect.succeed({})), Schema.withDecodingDefault(Effect.succeed({}))); | |
| const redactHeaders = headers => { | |
| const redacted = redact(headers); | |
| const result = {}; | |
| for (const key in redacted) { | |
| const value = redacted[key]; | |
| result[key] = Redacted.isRedacted(value) ? value.toString() : value; | |
| } | |
| return result; | |
| }; | |
| // ============================================================================= | |
| // Http Request Error | |
| // ============================================================================= | |
| /** | |
| * Error indicating a network-level failure before receiving a response. | |
| * | |
| * **Details** | |
| * | |
| * This error is raised when issues arise before receiving an HTTP response, | |
| * such as network connectivity problems, request encoding issues, or invalid | |
| * URLs. | |
| * | |
| * **Example** (Creating a network error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.NetworkError({ | |
| * reason: "TransportError", | |
| * request: { | |
| * method: "POST", | |
| * url: "https://api.openai.com/v1/completions", | |
| * urlParams: [], | |
| * hash: undefined, | |
| * headers: { "Content-Type": "application/json" } | |
| * }, | |
| * description: "Connection timeout after 30 seconds" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // true | |
| * console.log(error.message) | |
| * // "Transport: Connection timeout after 30 seconds (POST https://api.openai.com/v1/completions)" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class NetworkError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/NetworkError")({ | |
| _tag: /*#__PURE__*/Schema.tag("NetworkError"), | |
| reason: /*#__PURE__*/Schema.Literals(["TransportError", "EncodeError", "InvalidUrlError"]), | |
| request: HttpRequestDetails, | |
| description: /*#__PURE__*/Schema.optional(Schema.String) | |
| }) { | |
| /** | |
| * Marks `NetworkError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Transport errors are retryable; encoding and URL errors are not. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return this.reason === "TransportError"; | |
| } | |
| /** | |
| * Creates a NetworkError from a platform HttpClientError.RequestError. | |
| * | |
| * **Example** (Creating a network error from a request error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * import type { HttpClientError } from "effect/unstable/http" | |
| * | |
| * declare const platformError: HttpClientError.RequestError | |
| * | |
| * const aiError = AiError.NetworkError.fromRequestError(platformError) | |
| * ``` | |
| * | |
| * @since 4.0.0 | |
| */ | |
| static fromRequestError(error) { | |
| return new NetworkError({ | |
| description: error.description, | |
| reason: error._tag, | |
| request: { | |
| hash: Option.getOrUndefined(error.request.hash), | |
| headers: redactHeaders(error.request.headers), | |
| method: error.request.method, | |
| url: error.request.url, | |
| urlParams: Array.from(error.request.urlParams) | |
| } | |
| }); | |
| } | |
| get message() { | |
| const methodAndUrl = `${this.request.method} ${this.request.url}`; | |
| let baseMessage = this.description ? `${this.reason}: ${this.description}` : `${this.reason}: A network error occurred.`; | |
| baseMessage += ` (${methodAndUrl})`; | |
| let suggestion = ""; | |
| switch (this.reason) { | |
| case "EncodeError": | |
| { | |
| suggestion += "Check that the request body data is properly formatted and matches the expected content type."; | |
| break; | |
| } | |
| case "InvalidUrlError": | |
| { | |
| suggestion += "Verify that the URL format is correct and that all required parameters have been provided."; | |
| suggestion += " Check for any special characters that may need encoding."; | |
| break; | |
| } | |
| case "TransportError": | |
| { | |
| suggestion += "Check your network connection and verify that the requested URL is accessible."; | |
| break; | |
| } | |
| } | |
| baseMessage += `\n\n${suggestion}`; | |
| return baseMessage; | |
| } | |
| } | |
| // ============================================================================= | |
| // Http Response Error | |
| // ============================================================================= | |
| // ============================================================================= | |
| // Supporting Schemas | |
| // ============================================================================= | |
| /** | |
| * Schema for provider-specific metadata which can be attached to error reasons. | |
| * | |
| * **Details** | |
| * | |
| * Provider-specific metadata is namespaced by provider name. Each provider | |
| * value can contain arbitrary mutable JSON metadata or `null`. | |
| * | |
| * **Example** (Metadata shape) | |
| * | |
| * ```ts | |
| * const metadata = { | |
| * openai: { | |
| * errorCode: "rate_limit_exceeded", | |
| * requestId: "req_123" | |
| * }, | |
| * anthropic: null | |
| * } | |
| * ``` | |
| * | |
| * @category schemas | |
| * @since 4.0.0 | |
| */ | |
| export const ProviderMetadata = /*#__PURE__*/Schema.Record(Schema.String, /*#__PURE__*/Schema.NullOr(Schema.MutableJson)); | |
| /** | |
| * Schema for token usage information from AI operations. | |
| * | |
| * **Details** | |
| * | |
| * Schema for optional provider-reported token counts for prompt tokens, | |
| * completion tokens, and total tokens. | |
| * | |
| * @category schemas | |
| * @since 4.0.0 | |
| */ | |
| export const UsageInfo = /*#__PURE__*/Schema.Struct({ | |
| promptTokens: Schema.optional(Schema.Number), | |
| completionTokens: Schema.optional(Schema.Number), | |
| totalTokens: Schema.optional(Schema.Number) | |
| }).annotate({ | |
| identifier: "UsageInfo" | |
| }); | |
| /** | |
| * Schema for the combined HTTP context used in error reporting. | |
| * | |
| * **When to use** | |
| * | |
| * Use to attach request details, optional response details, and optional body | |
| * text to AI provider errors. | |
| * | |
| * **Details** | |
| * | |
| * Includes the required request details plus optional response details and raw | |
| * response body. | |
| * | |
| * @see {@link HttpRequestDetails} for captured request details | |
| * @see {@link HttpResponseDetails} for captured response details | |
| * | |
| * @category schemas | |
| * @since 4.0.0 | |
| */ | |
| export const HttpContext = /*#__PURE__*/Schema.Struct({ | |
| request: HttpRequestDetails, | |
| response: Schema.optional(HttpResponseDetails), | |
| body: Schema.optional(Schema.String) | |
| }).annotate({ | |
| identifier: "HttpContext" | |
| }); | |
| // ============================================================================= | |
| // Reason Classes | |
| // ============================================================================= | |
| /** | |
| * Error indicating the request was rate limited. | |
| * | |
| * **Details** | |
| * | |
| * Rate limit errors are always retryable. When `retryAfter` is provided, | |
| * callers should wait that duration before retrying. | |
| * | |
| * **Example** (Creating a rate limit error) | |
| * | |
| * ```ts | |
| * import { Duration } from "effect" | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const rateLimitError = new AiError.RateLimitError({ | |
| * retryAfter: Duration.seconds(60) | |
| * }) | |
| * | |
| * console.log(rateLimitError.isRetryable) // true | |
| * console.log(rateLimitError.message) // "Rate limit exceeded. Retry after 1 minute" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class RateLimitError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/RateLimitError")({ | |
| _tag: /*#__PURE__*/Schema.tag("RateLimitError"), | |
| retryAfter: /*#__PURE__*/Schema.optional(Schema.Duration), | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| http: /*#__PURE__*/Schema.optional(HttpContext) | |
| }) { | |
| /** | |
| * Marks `RateLimitError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Rate limit errors are always retryable. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return true; | |
| } | |
| get message() { | |
| let msg = "Rate limit exceeded"; | |
| if (this.retryAfter) msg += `. Retry after ${Duration.format(this.retryAfter)}`; | |
| return msg; | |
| } | |
| } | |
| /** | |
| * Error indicating account or billing limits have been reached. | |
| * | |
| * **Details** | |
| * | |
| * Quota exhausted errors are not retryable without user action. | |
| * | |
| * **Example** (Creating a quota exhausted error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const quotaError = new AiError.QuotaExhaustedError({}) | |
| * | |
| * console.log(quotaError.isRetryable) // false | |
| * console.log(quotaError.message) | |
| * // "Quota exhausted. Check your account billing and usage limits." | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class QuotaExhaustedError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/QuotaExhaustedError")({ | |
| _tag: /*#__PURE__*/Schema.tag("QuotaExhaustedError"), | |
| resetAt: /*#__PURE__*/Schema.optional(Schema.DateTimeUtc), | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| http: /*#__PURE__*/Schema.optional(HttpContext) | |
| }) { | |
| /** | |
| * Marks `QuotaExhaustedError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Quota exhausted errors require user action and are not retryable. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| let msg = "Quota exhausted"; | |
| if (this.resetAt) msg += `. Resets at ${this.resetAt}`; | |
| return `${msg}. Check your account billing and usage limits.`; | |
| } | |
| } | |
| /** | |
| * Error indicating authentication or authorization failure. | |
| * | |
| * **Details** | |
| * | |
| * Authentication errors are never retryable without credential changes. | |
| * | |
| * **Example** (Creating an authentication error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const authError = new AiError.AuthenticationError({ | |
| * kind: "InvalidKey" | |
| * }) | |
| * | |
| * console.log(authError.isRetryable) // false | |
| * console.log(authError.message) | |
| * // "InvalidKey: Verify your API key is correct" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class AuthenticationError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/AuthenticationError")({ | |
| _tag: /*#__PURE__*/Schema.tag("AuthenticationError"), | |
| kind: /*#__PURE__*/Schema.Literals(["InvalidKey", "ExpiredKey", "MissingKey", "InsufficientPermissions", "Unknown"]), | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| http: /*#__PURE__*/Schema.optional(HttpContext) | |
| }) { | |
| /** | |
| * Marks `AuthenticationError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Authentication errors require credential changes and are not retryable. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| const suggestions = { | |
| InvalidKey: "Verify your API key is correct", | |
| ExpiredKey: "Your API key has expired. Generate a new one", | |
| MissingKey: "No API key provided. Set the appropriate environment variable", | |
| InsufficientPermissions: "Your API key lacks required permissions", | |
| Unknown: "Authentication failed. Check your credentials" | |
| }; | |
| return `${this.kind}: ${suggestions[this.kind]}`; | |
| } | |
| } | |
| /** | |
| * Error indicating content policy violation. | |
| * | |
| * **Details** | |
| * | |
| * Content policy errors are never retryable without content changes. | |
| * | |
| * **Example** (Creating a content policy error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const policyError = new AiError.ContentPolicyError({ | |
| * description: "Input contains prohibited content" | |
| * }) | |
| * | |
| * console.log(policyError.isRetryable) // false | |
| * console.log(policyError.message) | |
| * // "Content policy violation: Input contains prohibited content" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class ContentPolicyError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/ContentPolicyError")({ | |
| _tag: /*#__PURE__*/Schema.tag("ContentPolicyError"), | |
| description: Schema.String, | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| http: /*#__PURE__*/Schema.optional(HttpContext) | |
| }) { | |
| /** | |
| * Marks `ContentPolicyError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Content policy errors require content changes and are not retryable. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| return `Content policy violation: ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating the request had invalid or malformed parameters. | |
| * | |
| * **Details** | |
| * | |
| * Invalid request errors require fixing the request and are not retryable. | |
| * | |
| * **Example** (Creating an invalid request error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const invalidRequestError = new AiError.InvalidRequestError({ | |
| * parameter: "temperature", | |
| * constraint: "must be between 0 and 2", | |
| * description: "Temperature value 5 is out of range" | |
| * }) | |
| * | |
| * console.log(invalidRequestError.isRetryable) // false | |
| * console.log(invalidRequestError.message) | |
| * // "Invalid request: parameter 'temperature' must be between 0 and 2. Temperature value 5 is out of range" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class InvalidRequestError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/InvalidRequestError")({ | |
| _tag: /*#__PURE__*/Schema.tag("InvalidRequestError"), | |
| parameter: /*#__PURE__*/Schema.optional(Schema.String), | |
| constraint: /*#__PURE__*/Schema.optional(Schema.String), | |
| description: /*#__PURE__*/Schema.optional(Schema.String), | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| http: /*#__PURE__*/Schema.optional(HttpContext) | |
| }) { | |
| /** | |
| * Marks `InvalidRequestError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Invalid request errors require fixing the request and are not retryable. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| let msg = "Invalid request"; | |
| if (this.parameter) msg += `: parameter '${this.parameter}'`; | |
| if (this.constraint) msg += ` ${this.constraint}`; | |
| if (this.description) msg += `. ${this.description}`; | |
| return msg; | |
| } | |
| } | |
| /** | |
| * Error indicating the AI provider experienced an internal error. | |
| * | |
| * **Details** | |
| * | |
| * Internal provider errors are typically transient and are retryable. | |
| * | |
| * **Example** (Creating an internal provider error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const providerError = new AiError.InternalProviderError({ | |
| * description: "Server encountered an unexpected error" | |
| * }) | |
| * | |
| * console.log(providerError.isRetryable) // true | |
| * console.log(providerError.message) | |
| * // "Internal provider error: Server encountered an unexpected error" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class InternalProviderError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/InternalProviderError")({ | |
| _tag: /*#__PURE__*/Schema.tag("InternalProviderError"), | |
| description: Schema.String, | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| http: /*#__PURE__*/Schema.optional(HttpContext) | |
| }) { | |
| /** | |
| * Marks `InternalProviderError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Internal provider errors are typically transient and are retryable. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return true; | |
| } | |
| get message() { | |
| return `Internal provider error: ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating failure to parse or validate LLM output. | |
| * | |
| * **Details** | |
| * | |
| * Invalid output errors are retryable since LLM outputs are non-deterministic. | |
| * | |
| * **Example** (Creating an invalid output error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const parseError = new AiError.InvalidOutputError({ | |
| * description: "Expected a string but received a number" | |
| * }) | |
| * | |
| * console.log(parseError.isRetryable) // true | |
| * console.log(parseError.message) | |
| * // "Invalid output: Expected a string but received a number" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class InvalidOutputError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/InvalidOutputError")({ | |
| _tag: /*#__PURE__*/Schema.tag("InvalidOutputError"), | |
| description: Schema.String, | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| usage: /*#__PURE__*/Schema.optional(UsageInfo) | |
| }) { | |
| /** | |
| * Marks `InvalidOutputError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Invalid output errors are retryable since LLM outputs are non-deterministic. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return true; | |
| } | |
| /** | |
| * Creates an InvalidOutputError from a Schema error. | |
| * | |
| * **Example** (Creating an invalid output error from a schema error) | |
| * | |
| * ```ts | |
| * import { Schema } from "effect" | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * declare const schemaError: Schema.SchemaError | |
| * | |
| * const parseError = AiError.InvalidOutputError.fromSchemaError(schemaError) | |
| * ``` | |
| * | |
| * @since 4.0.0 | |
| */ | |
| static fromSchemaError(error) { | |
| return new InvalidOutputError({ | |
| description: error.message | |
| }); | |
| } | |
| get message() { | |
| return `Invalid output: ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating the LLM generated text that does not conform to the | |
| * requested structured output schema. | |
| * | |
| * **Details** | |
| * | |
| * Structured output errors are retryable since LLM outputs are non-deterministic. | |
| * | |
| * **Example** (Creating a structured output error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.StructuredOutputError({ | |
| * description: "Expected a valid JSON object", | |
| * responseText: "{\"foo\":}" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // true | |
| * console.log(error.message) | |
| * // "Structured output validation failed: Expected a valid JSON object" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class StructuredOutputError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/StructuredOutputError")({ | |
| _tag: /*#__PURE__*/Schema.tag("StructuredOutputError"), | |
| description: Schema.String, | |
| responseText: Schema.String, | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| usage: /*#__PURE__*/Schema.optional(UsageInfo) | |
| }) { | |
| /** | |
| * Marks `StructuredOutputError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Structured output errors are retryable since LLM outputs are non-deterministic. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return true; | |
| } | |
| /** | |
| * Creates a StructuredOutputError from a Schema error. | |
| * | |
| * **Example** (Creating a structured output error from a schema error) | |
| * | |
| * ```ts | |
| * import { Schema } from "effect" | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * declare const schemaError: Schema.SchemaError | |
| * declare const rawText: string | |
| * | |
| * const parseError = AiError.StructuredOutputError.fromSchemaError(schemaError, rawText) | |
| * ``` | |
| * | |
| * @since 4.0.0 | |
| */ | |
| static fromSchemaError(error, responseText) { | |
| return new StructuredOutputError({ | |
| description: error.message, | |
| responseText | |
| }); | |
| } | |
| get message() { | |
| return `Structured output validation failed: ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating a codec transformer rejected a schema because it contains | |
| * unsupported constructs. | |
| * | |
| * **Details** | |
| * | |
| * Unsupported schema errors are not retryable because they indicate a | |
| * programmer error where the schema is incompatible with the provider. | |
| * | |
| * **Example** (Creating an unsupported schema error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.UnsupportedSchemaError({ | |
| * description: "Unions are not supported in Anthropic structured output" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // false | |
| * console.log(error.message) | |
| * // "Unsupported schema: Unions are not supported in Anthropic structured output" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class UnsupportedSchemaError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/UnsupportedSchemaError")({ | |
| _tag: /*#__PURE__*/Schema.tag("UnsupportedSchemaError"), | |
| description: Schema.String, | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults() | |
| }) { | |
| /** | |
| * Marks `UnsupportedSchemaError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Unsupported schema errors are not retryable because they indicate a programmer error. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| return `Unsupported schema: ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error data for unknown or unexpected AI failures. | |
| * | |
| * **Details** | |
| * | |
| * Unknown errors are not retryable by default since the cause is unknown. | |
| * | |
| * **Example** (Creating an unknown error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const unknownError = new AiError.UnknownError({ | |
| * description: "An unexpected error occurred" | |
| * }) | |
| * | |
| * console.log(unknownError.isRetryable) // false | |
| * console.log(unknownError.message) | |
| * // "An unexpected error occurred" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class UnknownError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/UnknownError")({ | |
| _tag: /*#__PURE__*/Schema.tag("UnknownError"), | |
| description: /*#__PURE__*/Schema.optional(Schema.String), | |
| metadata: /*#__PURE__*/providerMetadataWithDefaults(), | |
| http: /*#__PURE__*/Schema.optional(HttpContext) | |
| }) { | |
| /** | |
| * Marks `UnknownError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Unknown errors are not retryable by default. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| return this.description ?? "Unknown error"; | |
| } | |
| } | |
| // ============================================================================= | |
| // Tool Call Error Types | |
| // ============================================================================= | |
| /** | |
| * Error indicating the model requested a tool that doesn't exist in the toolkit. | |
| * | |
| * **Details** | |
| * | |
| * This error is retryable because the model may self-correct when provided | |
| * with the list of available tools. | |
| * | |
| * **Example** (Creating a tool not found error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.ToolNotFoundError({ | |
| * toolName: "unknownTool", | |
| * availableTools: ["GetWeather", "GetTime"] | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // true | |
| * console.log(error.message) | |
| * // "Tool 'unknownTool' not found. Available tools: GetWeather, GetTime" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class ToolNotFoundError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/ToolNotFoundError")({ | |
| _tag: /*#__PURE__*/Schema.tag("ToolNotFoundError"), | |
| toolName: Schema.String, | |
| availableTools: /*#__PURE__*/Schema.Array(Schema.String) | |
| }) { | |
| /** | |
| * Marks `ToolNotFoundError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Tool not found errors are retryable because the model may self-correct. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return true; | |
| } | |
| get message() { | |
| const availableTools = this.availableTools.length > 0 ? this.availableTools.join(", ") : "none"; | |
| return `Tool '${this.toolName}' not found. Available tools: ${availableTools}`; | |
| } | |
| } | |
| /** | |
| * Error indicating the model's tool call parameters failed schema validation. | |
| * | |
| * **Details** | |
| * | |
| * This error is retryable because the model may correct its parameters | |
| * on subsequent attempts. | |
| * | |
| * **Example** (Creating a tool parameter validation error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.ToolParameterValidationError({ | |
| * toolName: "GetWeather", | |
| * toolParams: { location: 123 }, | |
| * description: "Expected string, got number" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // true | |
| * console.log(error.message) | |
| * // "Invalid parameters for tool 'GetWeather': Expected string, got number" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class ToolParameterValidationError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/ToolParameterValidationError")({ | |
| _tag: /*#__PURE__*/Schema.tag("ToolParameterValidationError"), | |
| toolName: Schema.String, | |
| toolParams: Schema.Json, | |
| description: Schema.String | |
| }) { | |
| /** | |
| * Marks `ToolParameterValidationError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Parameter validation errors are retryable because the model may correct parameters. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return true; | |
| } | |
| get message() { | |
| return `Invalid parameters for tool '${this.toolName}': ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating the tool handler returned an invalid result that does not | |
| * match the tool's schema. | |
| * | |
| * **Details** | |
| * | |
| * This error is not retryable because invalid results indicate a bug in the | |
| * tool handler implementation. | |
| * | |
| * **Example** (Creating an invalid tool result error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.InvalidToolResultError({ | |
| * toolName: "GetWeather", | |
| * description: "Tool handler returned invalid result: missing 'temperature' field" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // false | |
| * console.log(error.message) | |
| * // "Tool 'GetWeather' returned invalid result: missing 'temperature' field" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class InvalidToolResultError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/InvalidToolResultError")({ | |
| _tag: /*#__PURE__*/Schema.tag("InvalidToolResultError"), | |
| toolName: Schema.String, | |
| description: Schema.String | |
| }) { | |
| /** | |
| * Marks `InvalidToolResultError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Invalid tool result errors are not retryable because they indicate a bug in the handler. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| return `Tool '${this.toolName}' returned invalid result: ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating the tool result cannot be encoded for sending back to the model. | |
| * | |
| * **Details** | |
| * | |
| * This error is not retryable because encoding failures indicate a bug in the | |
| * tool schema definitions. | |
| * | |
| * **Example** (Creating a tool result encoding error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.ToolResultEncodingError({ | |
| * toolName: "GetWeather", | |
| * toolResult: { temperature: 72n }, | |
| * description: "Cannot encode bigint values as JSON" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // false | |
| * console.log(error.message) | |
| * // "Failed to encode result for tool 'GetWeather': Cannot encode bigint values as JSON" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class ToolResultEncodingError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/ToolResultEncodingError")({ | |
| _tag: /*#__PURE__*/Schema.tag("ToolResultEncodingError"), | |
| toolName: Schema.String, | |
| toolResult: Schema.Unknown, | |
| description: Schema.String | |
| }) { | |
| /** | |
| * Marks `ToolResultEncodingError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Encoding errors are not retryable because they indicate a code bug. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| return `Failed to encode result for tool '${this.toolName}': ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating a provider-defined tool was configured with invalid arguments. | |
| * | |
| * **Details** | |
| * | |
| * This error is not retryable because it indicates a programming error in the | |
| * tool configuration that must be fixed in code. | |
| * | |
| * **Example** (Creating a tool configuration error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.ToolConfigurationError({ | |
| * toolName: "OpenAiCodeInterpreter", | |
| * description: "Invalid container ID format" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // false | |
| * console.log(error.message) | |
| * // "Invalid configuration for tool 'OpenAiCodeInterpreter': Invalid container ID format" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class ToolConfigurationError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/ToolConfigurationError")({ | |
| _tag: /*#__PURE__*/Schema.tag("ToolConfigurationError"), | |
| toolName: Schema.String, | |
| description: Schema.String | |
| }) { | |
| /** | |
| * Marks `ToolConfigurationError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Configuration errors are not retryable because they indicate a code bug. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| return `Invalid configuration for tool '${this.toolName}': ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Error indicating an operation requires a toolkit but none was provided. | |
| * | |
| * **Details** | |
| * | |
| * This error occurs when tool approval responses are present in the prompt | |
| * but no toolkit was provided to resolve them. | |
| * | |
| * **Example** (Creating a toolkit required error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.ToolkitRequiredError({ | |
| * pendingApprovals: ["GetWeather", "SendEmail"] | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // false | |
| * console.log(error.message) | |
| * // "Toolkit required to resolve pending tool approvals: GetWeather, SendEmail" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class ToolkitRequiredError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/ToolkitRequiredError")({ | |
| _tag: /*#__PURE__*/Schema.tag("ToolkitRequiredError"), | |
| pendingApprovals: /*#__PURE__*/Schema.Array(Schema.String), | |
| description: /*#__PURE__*/Schema.optional(Schema.String) | |
| }) { | |
| /** | |
| * Marks `ToolkitRequiredError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Toolkit required errors are not retryable without providing a toolkit. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| const tools = this.pendingApprovals.join(", "); | |
| return `Toolkit required to resolve pending tool approvals: ${tools}`; | |
| } | |
| } | |
| /** | |
| * Error indicating the user provided invalid input in their prompt. | |
| * | |
| * **Details** | |
| * | |
| * This error is raised when the prompt contains content that is structurally | |
| * valid but not supported by the provider (e.g., unsupported media types, | |
| * unsupported file formats, etc.). | |
| * | |
| * **Example** (Creating an invalid user input error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = new AiError.InvalidUserInputError({ | |
| * description: "Unsupported media type 'video/mp4'. Supported types include images, application/pdf, text/plain" | |
| * }) | |
| * | |
| * console.log(error.isRetryable) // false | |
| * console.log(error.message) | |
| * // "Invalid user input: Unsupported media type 'video/mp4'. Supported types include images, application/pdf, text/plain" | |
| * ``` | |
| * | |
| * @category reason | |
| * @since 4.0.0 | |
| */ | |
| export class InvalidUserInputError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/InvalidUserInputError")({ | |
| _tag: /*#__PURE__*/Schema.tag("InvalidUserInputError"), | |
| description: Schema.String | |
| }) { | |
| /** | |
| * Marks `InvalidUserInputError` as a semantic AI error reason for runtime guards. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| [ReasonTypeId] = ReasonTypeId; | |
| /** | |
| * Invalid user input errors require fixing the input and are not retryable. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return false; | |
| } | |
| get message() { | |
| return `Invalid user input: ${this.description}`; | |
| } | |
| } | |
| /** | |
| * Schema for validating and parsing AI error reasons. | |
| * | |
| * **When to use** | |
| * | |
| * Use when decoding or validating unknown AI error reason values with Schema. | |
| * | |
| * **Details** | |
| * | |
| * This runtime schema is the union of the concrete AI error reason classes. | |
| * | |
| * @see {@link isAiErrorReason} for checking an existing value without Schema decoding | |
| * | |
| * @category schemas | |
| * @since 4.0.0 | |
| */ | |
| export const AiErrorReason = /*#__PURE__*/Schema.Union([RateLimitError, QuotaExhaustedError, AuthenticationError, ContentPolicyError, InvalidRequestError, InternalProviderError, NetworkError, InvalidOutputError, StructuredOutputError, UnsupportedSchemaError, UnknownError, ToolNotFoundError, ToolParameterValidationError, InvalidToolResultError, ToolResultEncodingError, ToolConfigurationError, ToolkitRequiredError, InvalidUserInputError]); | |
| // ============================================================================= | |
| // Top-Level AiError | |
| // ============================================================================= | |
| const TypeId = "~effect/unstable/ai/AiError/AiError"; | |
| /** | |
| * Schema for the top-level AI error wrapper using the `reason` pattern. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need AI errors that can be handled by semantic reason with | |
| * `Effect.catchReason`. | |
| * | |
| * **Details** | |
| * | |
| * This error stores `module` and `method` context, the semantic `reason`, and | |
| * delegates `isRetryable` and `retryAfter` to the underlying reason. | |
| * | |
| * **Example** (Handling an AI error by tag) | |
| * | |
| * ```ts | |
| * import { Effect } from "effect" | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * declare const aiOperation: Effect.Effect<string, AiError.AiError> | |
| * | |
| * // Handle specific reason types | |
| * const handled = aiOperation.pipe( | |
| * Effect.catchTag("AiError", (error) => { | |
| * if (error.reason._tag === "RateLimitError") { | |
| * return Effect.succeed(`Retry after ${error.retryAfter}`) | |
| * } | |
| * return Effect.fail(error) | |
| * }) | |
| * ) | |
| * ``` | |
| * | |
| * @category schemas | |
| * @since 4.0.0 | |
| */ | |
| export class AiError extends /*#__PURE__*/Schema.ErrorClass("effect/ai/AiError/AiError")({ | |
| _tag: /*#__PURE__*/Schema.tag("AiError"), | |
| module: Schema.String, | |
| method: Schema.String, | |
| reason: AiErrorReason | |
| }) { | |
| [TypeId] = TypeId; | |
| cause = this.reason; | |
| /** | |
| * Delegates to the underlying reason's `isRetryable` getter. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get isRetryable() { | |
| return this.reason.isRetryable; | |
| } | |
| /** | |
| * Delegates to the underlying reason's `retryAfter` if present. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| get retryAfter() { | |
| return "retryAfter" in this.reason ? this.reason.retryAfter : undefined; | |
| } | |
| get message() { | |
| return `${this.module}.${this.method}: ${this.reason.message}`; | |
| } | |
| } | |
| /** | |
| * Type guard to check if a value is an `AiError`. | |
| * | |
| * **Example** (Checking for an AI error) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const someError = new Error("generic error") | |
| * const aiError = AiError.make({ | |
| * module: "Test", | |
| * method: "example", | |
| * reason: new AiError.RateLimitError({}) | |
| * }) | |
| * | |
| * console.log(AiError.isAiError(someError)) // false | |
| * console.log(AiError.isAiError(aiError)) // true | |
| * ``` | |
| * | |
| * @category guards | |
| * @since 4.0.0 | |
| */ | |
| export const isAiError = u => Predicate.hasProperty(u, TypeId); | |
| /** | |
| * Type guard to check if a value is an `AiErrorReason`. | |
| * | |
| * **Example** (Checking for an AI error reason) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const rateLimitError = new AiError.RateLimitError({}) | |
| * const genericError = new Error("generic error") | |
| * | |
| * console.log(AiError.isAiErrorReason(rateLimitError)) // true | |
| * console.log(AiError.isAiErrorReason(genericError)) // false | |
| * ``` | |
| * | |
| * @category guards | |
| * @since 4.0.0 | |
| */ | |
| export const isAiErrorReason = u => Predicate.hasProperty(u, ReasonTypeId); | |
| /** | |
| * Creates an `AiError` with the given reason. | |
| * | |
| * **Example** (Creating an AI error) | |
| * | |
| * ```ts | |
| * import { Duration } from "effect" | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const error = AiError.make({ | |
| * module: "OpenAI", | |
| * method: "completion", | |
| * reason: new AiError.RateLimitError({ | |
| * retryAfter: Duration.seconds(60) | |
| * }) | |
| * }) | |
| * | |
| * console.log(error.message) | |
| * // "OpenAI.completion: Rate limit exceeded. Retry after 1 minute" | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const make = params => new AiError(params); | |
| /** | |
| * Maps HTTP status codes to semantic error reasons. | |
| * | |
| * **When to use** | |
| * | |
| * Use as the base mapping when provider packages translate HTTP status codes into | |
| * provider-specific error reasons. | |
| * | |
| * **Example** (Mapping an HTTP status to a reason) | |
| * | |
| * ```ts | |
| * import { AiError } from "effect/unstable/ai" | |
| * | |
| * const reason = AiError.reasonFromHttpStatus({ | |
| * status: 429, | |
| * body: { error: "Rate limit exceeded" } | |
| * }) | |
| * | |
| * console.log(reason._tag) // "RateLimitError" | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const reasonFromHttpStatus = params => { | |
| const { | |
| status, | |
| http, | |
| metadata, | |
| description | |
| } = params; | |
| const common = { | |
| http, | |
| ...(metadata ? { | |
| metadata | |
| } : undefined), | |
| ...(description ? { | |
| description | |
| } : undefined) | |
| }; | |
| switch (status) { | |
| case 400: | |
| return new InvalidRequestError(common); | |
| case 401: | |
| return new AuthenticationError({ | |
| kind: "InvalidKey", | |
| ...common | |
| }); | |
| case 403: | |
| return new AuthenticationError({ | |
| kind: "InsufficientPermissions", | |
| ...common | |
| }); | |
| case 429: | |
| return new RateLimitError(common); | |
| default: | |
| if (status >= 500) { | |
| return new InternalProviderError({ | |
| description: "Server error", | |
| ...common | |
| }); | |
| } | |
| return new UnknownError(common); | |
| } | |
| }; | |
| //# sourceMappingURL=AiError.js.map |
Xet Storage Details
- Size:
- 38.8 kB
- Xet hash:
- 2f01c000c3e7bf6f22eecf6a41c4c10c7158a02d2d546581ad1edd13808ff07f
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.