{"version":3,"file":"modelRetry.cjs","names":["z","RetrySchema","InvalidRetryConfigError","AIMessage","createMiddleware","calculateRetryDelay","sleep"],"sources":["../../../src/agents/middleware/modelRetry.ts"],"sourcesContent":["/**\n * Model retry middleware for agents.\n */\nimport { z } from \"zod/v3\";\nimport { AIMessage } from \"@langchain/core/messages\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport { sleep, calculateRetryDelay } from \"./utils.js\";\nimport { RetrySchema } from \"./constants.js\";\nimport { InvalidRetryConfigError } from \"./error.js\";\n\n/**\n * Configuration options for the Model Retry Middleware.\n */\nexport const ModelRetryMiddlewareOptionsSchema = z\n  .object({\n    /**\n     * Behavior when all retries are exhausted. Options:\n     * - `\"continue\"` (default): Return an AIMessage with error details, allowing\n     *   the agent to potentially handle the failure gracefully.\n     * - `\"error\"`: Re-raise the exception, stopping agent execution.\n     * - Custom function: Function that takes the exception and returns a string\n     *   for the AIMessage content, allowing custom error formatting.\n     */\n    onFailure: z\n      .union([\n        z.literal(\"error\"),\n        z.literal(\"continue\"),\n        z.function().args(z.instanceof(Error)).returns(z.string()),\n      ])\n      .default(\"continue\"),\n  })\n  .merge(RetrySchema);\n\nexport type ModelRetryMiddlewareConfig = z.input<\n  typeof ModelRetryMiddlewareOptionsSchema\n>;\n\n/**\n * Middleware that automatically retries failed model calls with configurable backoff.\n *\n * Supports retrying on specific exceptions and exponential backoff.\n *\n * @example Basic usage with default settings (2 retries, exponential backoff)\n * ```ts\n * import { createAgent, modelRetryMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n *   model: \"openai:gpt-4o\",\n *   tools: [searchTool],\n *   middleware: [modelRetryMiddleware()],\n * });\n * ```\n *\n * @example Retry specific exceptions only\n * ```ts\n * import { modelRetryMiddleware } from \"langchain\";\n *\n * const retry = modelRetryMiddleware({\n *   maxRetries: 4,\n *   retryOn: [TimeoutError, NetworkError],\n *   backoffFactor: 1.5,\n * });\n * ```\n *\n * @example Custom exception filtering\n * ```ts\n * function shouldRetry(error: Error): boolean {\n *   // Only retry on rate limit errors\n *   if (error.name === \"RateLimitError\") {\n *     return true;\n *   }\n *   // Or check for specific HTTP status codes\n *   if (error.name === \"HTTPError\" && \"statusCode\" in error) {\n *     const statusCode = (error as any).statusCode;\n *     return statusCode === 429 || statusCode === 503;\n *   }\n *   return false;\n * }\n *\n * const retry = modelRetryMiddleware({\n *   maxRetries: 3,\n *   retryOn: shouldRetry,\n * });\n * ```\n *\n * @example Return error message instead of raising\n * ```ts\n * const retry = modelRetryMiddleware({\n *   maxRetries: 4,\n *   onFailure: \"continue\", // Return AIMessage with error instead of throwing\n * });\n * ```\n *\n * @example Custom error message formatting\n * ```ts\n * const formatError = (error: Error) =>\n *   `Model call failed: ${error.message}. Please try again later.`;\n *\n * const retry = modelRetryMiddleware({\n *   maxRetries: 4,\n *   onFailure: formatError,\n * });\n * ```\n *\n * @example Constant backoff (no exponential growth)\n * ```ts\n * const retry = modelRetryMiddleware({\n *   maxRetries: 5,\n *   backoffFactor: 0.0, // No exponential growth\n *   initialDelayMs: 2000, // Always wait 2 seconds\n * });\n * ```\n *\n * @example Raise exception on failure\n * ```ts\n * const retry = modelRetryMiddleware({\n *   maxRetries: 2,\n *   onFailure: \"error\", // Re-raise exception instead of returning message\n * });\n * ```\n *\n * @param config - Configuration options for the retry middleware\n * @returns A middleware instance that handles model failures with retries\n */\nexport function modelRetryMiddleware(config: ModelRetryMiddlewareConfig = {}) {\n  const { success, error, data } =\n    ModelRetryMiddlewareOptionsSchema.safeParse(config);\n  if (!success) {\n    throw new InvalidRetryConfigError(error);\n  }\n  const {\n    maxRetries,\n    retryOn,\n    onFailure,\n    backoffFactor,\n    initialDelayMs,\n    maxDelayMs,\n    jitter,\n  } = data;\n\n  /**\n   * Check if the exception should trigger a retry.\n   */\n  const shouldRetryException = (error: Error): boolean => {\n    if (typeof retryOn === \"function\") {\n      return retryOn(error);\n    }\n    // retryOn is an array of error constructors\n    return retryOn.some(\n      (ErrorConstructor) => error.constructor === ErrorConstructor\n    );\n  };\n\n  // Use the exported calculateRetryDelay function with our config\n  const delayConfig = { backoffFactor, initialDelayMs, maxDelayMs, jitter };\n\n  /**\n   * Format the failure message when retries are exhausted.\n   */\n  const formatFailureMessage = (error: Error, attemptsMade: number): string => {\n    const errorType = error.constructor.name;\n    const attemptWord = attemptsMade === 1 ? \"attempt\" : \"attempts\";\n    return `Model call failed after ${attemptsMade} ${attemptWord} with ${errorType}: ${error.message}`;\n  };\n\n  /**\n   * Handle failure when all retries are exhausted.\n   */\n  const handleFailure = (error: Error, attemptsMade: number): AIMessage => {\n    if (onFailure === \"error\") {\n      throw error;\n    }\n\n    let content: string;\n    if (typeof onFailure === \"function\") {\n      content = onFailure(error);\n    } else {\n      content = formatFailureMessage(error, attemptsMade);\n    }\n\n    return new AIMessage({\n      content,\n    });\n  };\n\n  return createMiddleware({\n    name: \"modelRetryMiddleware\",\n    contextSchema: ModelRetryMiddlewareOptionsSchema,\n    wrapModelCall: async (request, handler) => {\n      // Initial attempt + retries\n      for (let attempt = 0; attempt <= maxRetries; attempt++) {\n        try {\n          return await handler(request);\n        } catch (error) {\n          const attemptsMade = attempt + 1; // attempt is 0-indexed\n\n          // Ensure error is an Error instance\n          const err =\n            error && typeof error === \"object\" && \"message\" in error\n              ? (error as Error)\n              : new Error(String(error));\n\n          // Check if we should retry this exception\n          if (!shouldRetryException(err)) {\n            // Exception is not retryable, handle failure immediately\n            return handleFailure(err, attemptsMade);\n          }\n\n          // Check if we have more retries left\n          if (attempt < maxRetries) {\n            // Calculate and apply backoff delay\n            const delay = calculateRetryDelay(delayConfig, attempt);\n            if (delay > 0) {\n              await sleep(delay);\n            }\n            // Continue to next retry\n          } else {\n            // No more retries, handle failure\n            return handleFailure(err, attemptsMade);\n          }\n        }\n      }\n\n      // Unreachable: loop always returns via handler success or handleFailure\n      throw new Error(\"Unexpected: retry loop completed without returning\");\n    },\n  });\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,MAAa,oCAAoCA,OAAAA,EAC9C,OAAO;;;;;;;;;AASN,WAAWA,OAAAA,EACR,MAAM;CACLA,OAAAA,EAAE,QAAQ,QAAQ;CAClBA,OAAAA,EAAE,QAAQ,WAAW;CACrBA,OAAAA,EAAE,UAAU,CAAC,KAAKA,OAAAA,EAAE,WAAW,MAAM,CAAC,CAAC,QAAQA,OAAAA,EAAE,QAAQ,CAAC;CAC3D,CAAC,CACD,QAAQ,WAAW,EACvB,CAAC,CACD,MAAMC,kBAAAA,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6FrB,SAAgB,qBAAqB,SAAqC,EAAE,EAAE;CAC5E,MAAM,EAAE,SAAS,OAAO,SACtB,kCAAkC,UAAU,OAAO;AACrD,KAAI,CAAC,QACH,OAAM,IAAIC,cAAAA,wBAAwB,MAAM;CAE1C,MAAM,EACJ,YACA,SACA,WACA,eACA,gBACA,YACA,WACE;;;;CAKJ,MAAM,wBAAwB,UAA0B;AACtD,MAAI,OAAO,YAAY,WACrB,QAAO,QAAQ,MAAM;AAGvB,SAAO,QAAQ,MACZ,qBAAqB,MAAM,gBAAgB,iBAC7C;;CAIH,MAAM,cAAc;EAAE;EAAe;EAAgB;EAAY;EAAQ;;;;CAKzE,MAAM,wBAAwB,OAAc,iBAAiC;EAC3E,MAAM,YAAY,MAAM,YAAY;AAEpC,SAAO,2BAA2B,aAAa,GAD3B,iBAAiB,IAAI,YAAY,WACS,QAAQ,UAAU,IAAI,MAAM;;;;;CAM5F,MAAM,iBAAiB,OAAc,iBAAoC;AACvE,MAAI,cAAc,QAChB,OAAM;EAGR,IAAI;AACJ,MAAI,OAAO,cAAc,WACvB,WAAU,UAAU,MAAM;MAE1B,WAAU,qBAAqB,OAAO,aAAa;AAGrD,SAAO,IAAIC,yBAAAA,UAAU,EACnB,SACD,CAAC;;AAGJ,QAAOC,mBAAAA,iBAAiB;EACtB,MAAM;EACN,eAAe;EACf,eAAe,OAAO,SAAS,YAAY;AAEzC,QAAK,IAAI,UAAU,GAAG,WAAW,YAAY,UAC3C,KAAI;AACF,WAAO,MAAM,QAAQ,QAAQ;YACtB,OAAO;IACd,MAAM,eAAe,UAAU;IAG/B,MAAM,MACJ,SAAS,OAAO,UAAU,YAAY,aAAa,QAC9C,QACD,IAAI,MAAM,OAAO,MAAM,CAAC;AAG9B,QAAI,CAAC,qBAAqB,IAAI,CAE5B,QAAO,cAAc,KAAK,aAAa;AAIzC,QAAI,UAAU,YAAY;KAExB,MAAM,QAAQC,cAAAA,oBAAoB,aAAa,QAAQ;AACvD,SAAI,QAAQ,EACV,OAAMC,cAAAA,MAAM,MAAM;UAKpB,QAAO,cAAc,KAAK,aAAa;;AAM7C,SAAM,IAAI,MAAM,qDAAqD;;EAExE,CAAC"}