langchain 1.0.6 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -1
  3. package/chat_models/universal.cjs +1 -0
  4. package/chat_models/universal.d.cts +1 -0
  5. package/chat_models/universal.d.ts +1 -0
  6. package/chat_models/universal.js +1 -0
  7. package/dist/agents/ReactAgent.cjs +1 -1
  8. package/dist/agents/ReactAgent.cjs.map +1 -1
  9. package/dist/agents/ReactAgent.js +2 -2
  10. package/dist/agents/ReactAgent.js.map +1 -1
  11. package/dist/agents/index.d.cts +0 -2
  12. package/dist/agents/index.d.ts +0 -2
  13. package/dist/agents/middleware/constants.cjs +16 -0
  14. package/dist/agents/middleware/constants.cjs.map +1 -0
  15. package/dist/agents/middleware/constants.js +15 -0
  16. package/dist/agents/middleware/constants.js.map +1 -0
  17. package/dist/agents/middleware/contextEditing.cjs.map +1 -1
  18. package/dist/agents/middleware/contextEditing.d.cts +23 -7
  19. package/dist/agents/middleware/contextEditing.d.ts +23 -7
  20. package/dist/agents/middleware/contextEditing.js.map +1 -1
  21. package/dist/agents/middleware/dynamicSystemPrompt.cjs +5 -2
  22. package/dist/agents/middleware/dynamicSystemPrompt.cjs.map +1 -1
  23. package/dist/agents/middleware/dynamicSystemPrompt.d.cts +2 -1
  24. package/dist/agents/middleware/dynamicSystemPrompt.d.ts +2 -1
  25. package/dist/agents/middleware/dynamicSystemPrompt.js +4 -2
  26. package/dist/agents/middleware/dynamicSystemPrompt.js.map +1 -1
  27. package/dist/agents/middleware/error.cjs +20 -0
  28. package/dist/agents/middleware/error.cjs.map +1 -0
  29. package/dist/agents/middleware/error.js +19 -0
  30. package/dist/agents/middleware/error.js.map +1 -0
  31. package/dist/agents/middleware/index.cjs +4 -2
  32. package/dist/agents/middleware/index.d.ts +18 -0
  33. package/dist/agents/middleware/index.js +4 -2
  34. package/dist/agents/middleware/modelRetry.cjs +162 -0
  35. package/dist/agents/middleware/modelRetry.cjs.map +1 -0
  36. package/dist/agents/middleware/modelRetry.d.cts +134 -0
  37. package/dist/agents/middleware/modelRetry.d.ts +134 -0
  38. package/dist/agents/middleware/modelRetry.js +161 -0
  39. package/dist/agents/middleware/modelRetry.js.map +1 -0
  40. package/dist/agents/middleware/{promptCaching.cjs → provider/anthropic/promptCaching.cjs} +3 -3
  41. package/dist/agents/middleware/provider/anthropic/promptCaching.cjs.map +1 -0
  42. package/dist/agents/middleware/{promptCaching.d.cts → provider/anthropic/promptCaching.d.cts} +2 -2
  43. package/dist/agents/middleware/{promptCaching.d.ts → provider/anthropic/promptCaching.d.ts} +2 -2
  44. package/dist/agents/middleware/{promptCaching.js → provider/anthropic/promptCaching.js} +2 -2
  45. package/dist/agents/middleware/provider/anthropic/promptCaching.js.map +1 -0
  46. package/dist/agents/middleware/provider/openai/moderation.cjs +299 -0
  47. package/dist/agents/middleware/provider/openai/moderation.cjs.map +1 -0
  48. package/dist/agents/middleware/provider/openai/moderation.d.cts +133 -0
  49. package/dist/agents/middleware/provider/openai/moderation.d.ts +133 -0
  50. package/dist/agents/middleware/provider/openai/moderation.js +298 -0
  51. package/dist/agents/middleware/provider/openai/moderation.js.map +1 -0
  52. package/dist/agents/middleware/summarization.d.cts +0 -4
  53. package/dist/agents/middleware/summarization.d.ts +0 -4
  54. package/dist/agents/middleware/todoListMiddleware.cjs +1 -1
  55. package/dist/agents/middleware/todoListMiddleware.cjs.map +1 -1
  56. package/dist/agents/middleware/todoListMiddleware.js +1 -1
  57. package/dist/agents/middleware/todoListMiddleware.js.map +1 -1
  58. package/dist/agents/middleware/toolRetry.cjs +32 -44
  59. package/dist/agents/middleware/toolRetry.cjs.map +1 -1
  60. package/dist/agents/middleware/toolRetry.d.cts +16 -36
  61. package/dist/agents/middleware/toolRetry.d.ts +16 -36
  62. package/dist/agents/middleware/toolRetry.js +32 -44
  63. package/dist/agents/middleware/toolRetry.js.map +1 -1
  64. package/dist/agents/middleware/types.d.cts +9 -10
  65. package/dist/agents/middleware/types.d.ts +9 -10
  66. package/dist/agents/middleware/utils.cjs +23 -0
  67. package/dist/agents/middleware/utils.cjs.map +1 -1
  68. package/dist/agents/middleware/utils.d.ts +2 -0
  69. package/dist/agents/middleware/utils.js +23 -1
  70. package/dist/agents/middleware/utils.js.map +1 -1
  71. package/dist/agents/nodes/AgentNode.cjs +50 -22
  72. package/dist/agents/nodes/AgentNode.cjs.map +1 -1
  73. package/dist/agents/nodes/AgentNode.js +52 -24
  74. package/dist/agents/nodes/AgentNode.js.map +1 -1
  75. package/dist/agents/nodes/types.d.cts +39 -3
  76. package/dist/agents/nodes/types.d.ts +39 -3
  77. package/dist/agents/responses.d.cts +0 -19
  78. package/dist/agents/responses.d.ts +0 -19
  79. package/dist/agents/runtime.d.ts +1 -0
  80. package/dist/agents/tests/utils.cjs +10 -1
  81. package/dist/agents/tests/utils.cjs.map +1 -1
  82. package/dist/agents/tests/utils.js +10 -1
  83. package/dist/agents/tests/utils.js.map +1 -1
  84. package/dist/agents/types.d.cts +68 -2
  85. package/dist/agents/types.d.ts +68 -2
  86. package/dist/agents/utils.cjs +15 -12
  87. package/dist/agents/utils.cjs.map +1 -1
  88. package/dist/agents/utils.js +16 -13
  89. package/dist/agents/utils.js.map +1 -1
  90. package/dist/chat_models/universal.cjs +50 -16
  91. package/dist/chat_models/universal.cjs.map +1 -1
  92. package/dist/chat_models/universal.d.cts +19 -1
  93. package/dist/chat_models/universal.d.ts +19 -1
  94. package/dist/chat_models/universal.js +50 -16
  95. package/dist/chat_models/universal.js.map +1 -1
  96. package/dist/index.cjs +8 -2
  97. package/dist/index.d.cts +5 -3
  98. package/dist/index.d.ts +6 -3
  99. package/dist/index.js +7 -3
  100. package/dist/load/import_constants.cjs +2 -1
  101. package/dist/load/import_constants.cjs.map +1 -1
  102. package/dist/load/import_constants.js +2 -1
  103. package/dist/load/import_constants.js.map +1 -1
  104. package/dist/load/import_map.cjs +2 -19
  105. package/dist/load/import_map.cjs.map +1 -1
  106. package/dist/load/import_map.js +2 -19
  107. package/dist/load/import_map.js.map +1 -1
  108. package/hub/node.cjs +1 -0
  109. package/hub/node.d.cts +1 -0
  110. package/hub/node.d.ts +1 -0
  111. package/hub/node.js +1 -0
  112. package/hub.cjs +1 -0
  113. package/hub.d.cts +1 -0
  114. package/hub.d.ts +1 -0
  115. package/hub.js +1 -0
  116. package/load/serializable.cjs +1 -0
  117. package/load/serializable.d.cts +1 -0
  118. package/load/serializable.d.ts +1 -0
  119. package/load/serializable.js +1 -0
  120. package/load.cjs +1 -0
  121. package/load.d.cts +1 -0
  122. package/load.d.ts +1 -0
  123. package/load.js +1 -0
  124. package/package.json +66 -53
  125. package/storage/encoder_backed.cjs +1 -0
  126. package/storage/encoder_backed.d.cts +1 -0
  127. package/storage/encoder_backed.d.ts +1 -0
  128. package/storage/encoder_backed.js +1 -0
  129. package/storage/file_system.cjs +1 -0
  130. package/storage/file_system.d.cts +1 -0
  131. package/storage/file_system.d.ts +1 -0
  132. package/storage/file_system.js +1 -0
  133. package/storage/in_memory.cjs +1 -0
  134. package/storage/in_memory.d.cts +1 -0
  135. package/storage/in_memory.d.ts +1 -0
  136. package/storage/in_memory.js +1 -0
  137. package/dist/agents/ReactAgent.d.cts.map +0 -1
  138. package/dist/agents/ReactAgent.d.ts.map +0 -1
  139. package/dist/agents/constants.cjs +0 -7
  140. package/dist/agents/constants.cjs.map +0 -1
  141. package/dist/agents/constants.d.cts.map +0 -1
  142. package/dist/agents/constants.d.ts.map +0 -1
  143. package/dist/agents/constants.js +0 -6
  144. package/dist/agents/constants.js.map +0 -1
  145. package/dist/agents/errors.d.cts.map +0 -1
  146. package/dist/agents/errors.d.ts.map +0 -1
  147. package/dist/agents/index.d.cts.map +0 -1
  148. package/dist/agents/index.d.ts.map +0 -1
  149. package/dist/agents/middleware/contextEditing.d.cts.map +0 -1
  150. package/dist/agents/middleware/contextEditing.d.ts.map +0 -1
  151. package/dist/agents/middleware/dynamicSystemPrompt.d.cts.map +0 -1
  152. package/dist/agents/middleware/dynamicSystemPrompt.d.ts.map +0 -1
  153. package/dist/agents/middleware/hitl.d.cts.map +0 -1
  154. package/dist/agents/middleware/hitl.d.ts.map +0 -1
  155. package/dist/agents/middleware/llmToolSelector.d.cts.map +0 -1
  156. package/dist/agents/middleware/llmToolSelector.d.ts.map +0 -1
  157. package/dist/agents/middleware/modelCallLimit.d.cts.map +0 -1
  158. package/dist/agents/middleware/modelCallLimit.d.ts.map +0 -1
  159. package/dist/agents/middleware/modelFallback.d.cts.map +0 -1
  160. package/dist/agents/middleware/modelFallback.d.ts.map +0 -1
  161. package/dist/agents/middleware/pii.d.cts.map +0 -1
  162. package/dist/agents/middleware/pii.d.ts.map +0 -1
  163. package/dist/agents/middleware/piiRedaction.d.cts.map +0 -1
  164. package/dist/agents/middleware/piiRedaction.d.ts.map +0 -1
  165. package/dist/agents/middleware/promptCaching.cjs.map +0 -1
  166. package/dist/agents/middleware/promptCaching.d.cts.map +0 -1
  167. package/dist/agents/middleware/promptCaching.d.ts.map +0 -1
  168. package/dist/agents/middleware/promptCaching.js.map +0 -1
  169. package/dist/agents/middleware/summarization.d.cts.map +0 -1
  170. package/dist/agents/middleware/summarization.d.ts.map +0 -1
  171. package/dist/agents/middleware/todoListMiddleware.d.cts.map +0 -1
  172. package/dist/agents/middleware/todoListMiddleware.d.ts.map +0 -1
  173. package/dist/agents/middleware/toolCallLimit.d.cts.map +0 -1
  174. package/dist/agents/middleware/toolCallLimit.d.ts.map +0 -1
  175. package/dist/agents/middleware/toolEmulator.d.cts.map +0 -1
  176. package/dist/agents/middleware/toolEmulator.d.ts.map +0 -1
  177. package/dist/agents/middleware/toolRetry.d.cts.map +0 -1
  178. package/dist/agents/middleware/toolRetry.d.ts.map +0 -1
  179. package/dist/agents/middleware/types.d.cts.map +0 -1
  180. package/dist/agents/middleware/types.d.ts.map +0 -1
  181. package/dist/agents/middleware/utils.d.cts.map +0 -1
  182. package/dist/agents/middleware/utils.d.ts.map +0 -1
  183. package/dist/agents/middleware.d.cts.map +0 -1
  184. package/dist/agents/middleware.d.ts.map +0 -1
  185. package/dist/agents/nodes/types.d.cts.map +0 -1
  186. package/dist/agents/nodes/types.d.ts.map +0 -1
  187. package/dist/agents/responses.d.cts.map +0 -1
  188. package/dist/agents/responses.d.ts.map +0 -1
  189. package/dist/agents/runtime.d.cts.map +0 -1
  190. package/dist/agents/runtime.d.ts.map +0 -1
  191. package/dist/agents/tests/utils.d.cts.map +0 -1
  192. package/dist/agents/tests/utils.d.ts.map +0 -1
  193. package/dist/agents/types.d.cts.map +0 -1
  194. package/dist/agents/types.d.ts.map +0 -1
  195. package/dist/chat_models/universal.d.cts.map +0 -1
  196. package/dist/chat_models/universal.d.ts.map +0 -1
  197. package/dist/hub/base.d.cts.map +0 -1
  198. package/dist/hub/base.d.ts.map +0 -1
  199. package/dist/hub/index.d.cts.map +0 -1
  200. package/dist/hub/index.d.ts.map +0 -1
  201. package/dist/hub/node.d.cts.map +0 -1
  202. package/dist/hub/node.d.ts.map +0 -1
  203. package/dist/load/import_type.d.cts.map +0 -1
  204. package/dist/load/import_type.d.ts.map +0 -1
  205. package/dist/load/index.d.cts.map +0 -1
  206. package/dist/load/index.d.ts.map +0 -1
  207. package/dist/storage/encoder_backed.d.cts.map +0 -1
  208. package/dist/storage/encoder_backed.d.ts.map +0 -1
  209. package/dist/storage/file_system.d.cts.map +0 -1
  210. package/dist/storage/file_system.d.ts.map +0 -1
@@ -1,53 +1,29 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
2
  const require_utils = require('./utils.cjs');
3
3
  const require_middleware = require('../middleware.cjs');
4
+ const require_constants = require('./constants.cjs');
5
+ const require_error = require('./error.cjs');
4
6
  const __langchain_core_messages = require_rolldown_runtime.__toESM(require("@langchain/core/messages"));
5
7
  const zod_v3 = require_rolldown_runtime.__toESM(require("zod/v3"));
6
8
 
7
9
  //#region src/agents/middleware/toolRetry.ts
8
10
  /**
9
- * Calculate delay for a retry attempt with exponential backoff and jitter.
10
- *
11
- * @param retryNumber - The retry attempt number (0-indexed)
12
- * @param config - Configuration for backoff calculation
13
- * @returns Delay in milliseconds before next retry
14
- *
15
- * @internal Exported for testing purposes
16
- */
17
- function calculateRetryDelay(config, retryNumber) {
18
- const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;
19
- let delay;
20
- if (backoffFactor === 0) delay = initialDelayMs;
21
- else delay = initialDelayMs * backoffFactor ** retryNumber;
22
- delay = Math.min(delay, maxDelayMs);
23
- if (jitter && delay > 0) {
24
- const jitterAmount = delay * .25;
25
- delay = delay + (Math.random() * 2 - 1) * jitterAmount;
26
- delay = Math.max(0, delay);
27
- }
28
- return delay;
29
- }
30
- /**
31
11
  * Configuration options for the Tool Retry Middleware.
32
12
  */
33
13
  const ToolRetryMiddlewareOptionsSchema = zod_v3.z.object({
34
- maxRetries: zod_v3.z.number().min(0).default(2),
35
14
  tools: zod_v3.z.array(zod_v3.z.union([
36
15
  zod_v3.z.custom(),
37
16
  zod_v3.z.custom(),
38
17
  zod_v3.z.string()
39
18
  ])).optional(),
40
- retryOn: zod_v3.z.union([zod_v3.z.function().args(zod_v3.z.instanceof(Error)).returns(zod_v3.z.boolean()), zod_v3.z.array(zod_v3.z.custom())]).default(() => () => true),
41
19
  onFailure: zod_v3.z.union([
20
+ zod_v3.z.literal("error"),
21
+ zod_v3.z.literal("continue"),
42
22
  zod_v3.z.literal("raise"),
43
23
  zod_v3.z.literal("return_message"),
44
24
  zod_v3.z.function().args(zod_v3.z.instanceof(Error)).returns(zod_v3.z.string())
45
- ]).default("return_message"),
46
- backoffFactor: zod_v3.z.number().min(0).default(2),
47
- initialDelayMs: zod_v3.z.number().min(0).default(1e3),
48
- maxDelayMs: zod_v3.z.number().min(0).default(6e4),
49
- jitter: zod_v3.z.boolean().default(true)
50
- });
25
+ ]).default("continue")
26
+ }).merge(require_constants.RetrySchema);
51
27
  /**
52
28
  * Middleware that automatically retries failed tool calls with configurable backoff.
53
29
  *
@@ -148,7 +124,17 @@ const ToolRetryMiddlewareOptionsSchema = zod_v3.z.object({
148
124
  * @returns A middleware instance that handles tool failures with retries
149
125
  */
150
126
  function toolRetryMiddleware(config = {}) {
151
- const { maxRetries, tools, retryOn, onFailure, backoffFactor, initialDelayMs, maxDelayMs, jitter } = ToolRetryMiddlewareOptionsSchema.parse(config);
127
+ const { success, error, data } = ToolRetryMiddlewareOptionsSchema.safeParse(config);
128
+ if (!success) throw new require_error.InvalidRetryConfigError(error);
129
+ const { maxRetries, tools, retryOn, onFailure: onFailureConfig, backoffFactor, initialDelayMs, maxDelayMs, jitter } = data;
130
+ let onFailure = onFailureConfig;
131
+ if (onFailureConfig === "raise") {
132
+ console.warn("⚠️ `onFailure: 'raise'` is deprecated. Use `onFailure: 'error'` instead.");
133
+ onFailure = "error";
134
+ } else if (onFailureConfig === "return_message") {
135
+ console.warn("⚠️ `onFailure: 'return_message'` is deprecated. Use `onFailure: 'continue'` instead.");
136
+ onFailure = "continue";
137
+ }
152
138
  const toolFilter = [];
153
139
  for (const tool of tools ?? []) if (typeof tool === "string") toolFilter.push(tool);
154
140
  else if ("name" in tool && typeof tool.name === "string") toolFilter.push(tool.name);
@@ -163,9 +149,11 @@ function toolRetryMiddleware(config = {}) {
163
149
  /**
164
150
  * Check if the exception should trigger a retry.
165
151
  */
166
- const shouldRetryException = (error) => {
167
- if (typeof retryOn === "function") return retryOn(error);
168
- return retryOn.some((ErrorConstructor) => error.constructor === ErrorConstructor);
152
+ const shouldRetryException = (error$1) => {
153
+ if (typeof retryOn === "function") return retryOn(error$1);
154
+ return retryOn.some((ErrorConstructor) => {
155
+ return error$1 instanceof ErrorConstructor;
156
+ });
169
157
  };
170
158
  const delayConfig = {
171
159
  backoffFactor,
@@ -176,19 +164,19 @@ function toolRetryMiddleware(config = {}) {
176
164
  /**
177
165
  * Format the failure message when retries are exhausted.
178
166
  */
179
- const formatFailureMessage = (toolName, error, attemptsMade) => {
180
- const errorType = error.constructor.name;
167
+ const formatFailureMessage = (toolName, error$1, attemptsMade) => {
168
+ const errorType = error$1.constructor.name;
181
169
  const attemptWord = attemptsMade === 1 ? "attempt" : "attempts";
182
170
  return `Tool '${toolName}' failed after ${attemptsMade} ${attemptWord} with ${errorType}`;
183
171
  };
184
172
  /**
185
173
  * Handle failure when all retries are exhausted.
186
174
  */
187
- const handleFailure = (toolName, toolCallId, error, attemptsMade) => {
188
- if (onFailure === "raise") throw error;
175
+ const handleFailure = (toolName, toolCallId, error$1, attemptsMade) => {
176
+ if (onFailure === "error") throw error$1;
189
177
  let content;
190
- if (typeof onFailure === "function") content = onFailure(error);
191
- else content = formatFailureMessage(toolName, error, attemptsMade);
178
+ if (typeof onFailure === "function") content = onFailure(error$1);
179
+ else content = formatFailureMessage(toolName, error$1, attemptsMade);
192
180
  return new __langchain_core_messages.ToolMessage({
193
181
  content,
194
182
  tool_call_id: toolCallId,
@@ -200,17 +188,17 @@ function toolRetryMiddleware(config = {}) {
200
188
  name: "toolRetryMiddleware",
201
189
  contextSchema: ToolRetryMiddlewareOptionsSchema,
202
190
  wrapToolCall: async (request, handler) => {
203
- const toolName = request.tool.name;
191
+ const toolName = request.tool?.name ?? request.toolCall.name;
204
192
  if (!shouldRetryTool(toolName)) return handler(request);
205
193
  const toolCallId = request.toolCall.id ?? "";
206
194
  for (let attempt = 0; attempt <= maxRetries; attempt++) try {
207
195
  return await handler(request);
208
- } catch (error) {
196
+ } catch (error$1) {
209
197
  const attemptsMade = attempt + 1;
210
- const err = error && typeof error === "object" && "message" in error ? error : new Error(String(error));
198
+ const err = error$1 && typeof error$1 === "object" && "message" in error$1 ? error$1 : new Error(String(error$1));
211
199
  if (!shouldRetryException(err)) return handleFailure(toolName, toolCallId, err, attemptsMade);
212
200
  if (attempt < maxRetries) {
213
- const delay = calculateRetryDelay(delayConfig, attempt);
201
+ const delay = require_utils.calculateRetryDelay(delayConfig, attempt);
214
202
  if (delay > 0) await require_utils.sleep(delay);
215
203
  } else return handleFailure(toolName, toolCallId, err, attemptsMade);
216
204
  }
@@ -1 +1 @@
1
- {"version":3,"file":"toolRetry.cjs","names":["config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n }","retryNumber: number","delay: number","z","config: ToolRetryMiddlewareConfig","toolFilter: string[]","toolName: string","error: Error","attemptsMade: number","toolCallId: string","content: string","ToolMessage","createMiddleware","sleep"],"sources":["../../../src/agents/middleware/toolRetry.ts"],"sourcesContent":["/**\n * Tool retry middleware for agents.\n */\nimport { z } from \"zod/v3\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport type { AgentMiddleware } from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport function calculateRetryDelay(\n config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n },\n retryNumber: number\n): number {\n const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;\n\n let delay: number;\n if (backoffFactor === 0.0) {\n delay = initialDelayMs;\n } else {\n delay = initialDelayMs * backoffFactor ** retryNumber;\n }\n\n // Cap at maxDelayMs\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter && delay > 0) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * 2 - 1) * jitterAmount;\n // Ensure delay is not negative after jitter\n delay = Math.max(0, delay);\n }\n\n return delay;\n}\n\n/**\n * Configuration options for the Tool Retry Middleware.\n */\nexport const ToolRetryMiddlewareOptionsSchema = z.object({\n /**\n * Maximum number of retry attempts after the initial call.\n * Default is 2 retries (3 total attempts). Must be >= 0.\n */\n maxRetries: z.number().min(0).default(2),\n\n /**\n * Optional list of tools or tool names to apply retry logic to.\n * Can be a list of `BaseTool` instances or tool name strings.\n * If `undefined`, applies to all tools. Default is `undefined`.\n */\n tools: z\n .array(\n z.union([z.custom<ClientTool>(), z.custom<ServerTool>(), z.string()])\n )\n .optional(),\n\n /**\n * Either an array of error constructors to retry on, or a function\n * that takes an error and returns `true` if it should be retried.\n * Default is to retry on all errors.\n */\n retryOn: z\n .union([\n z.function().args(z.instanceof(Error)).returns(z.boolean()),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n z.array(z.custom<new (...args: any[]) => Error>()),\n ])\n .default(() => () => true),\n\n /**\n * Behavior when all retries are exhausted. Options:\n * - `\"return_message\"` (default): Return a ToolMessage with error details,\n * allowing the LLM to handle the failure and potentially recover.\n * - `\"raise\"`: Re-raise the exception, stopping agent execution.\n * - Custom function: Function that takes the exception and returns a string\n * for the ToolMessage content, allowing custom error formatting.\n */\n onFailure: z\n .union([\n z.literal(\"raise\"),\n z.literal(\"return_message\"),\n z.function().args(z.instanceof(Error)).returns(z.string()),\n ])\n .default(\"return_message\"),\n\n /**\n * Multiplier for exponential backoff. Each retry waits\n * `initialDelayMs * (backoffFactor ** retryNumber)` milliseconds.\n * Set to 0.0 for constant delay. Default is 2.0.\n */\n backoffFactor: z.number().min(0).default(2.0),\n\n /**\n * Initial delay in milliseconds before first retry. Default is 1000 (1 second).\n */\n initialDelayMs: z.number().min(0).default(1000),\n\n /**\n * Maximum delay in milliseconds between retries. Caps exponential\n * backoff growth. Default is 60000 (60 seconds).\n */\n maxDelayMs: z.number().min(0).default(60000),\n\n /**\n * Whether to add random jitter (±25%) to delay to avoid thundering herd.\n * Default is `true`.\n */\n jitter: z.boolean().default(true),\n});\n\nexport type ToolRetryMiddlewareConfig = z.input<\n typeof ToolRetryMiddlewareOptionsSchema\n>;\n\n/**\n * Middleware that automatically retries failed tool 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, toolRetryMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * middleware: [toolRetryMiddleware()],\n * });\n * ```\n *\n * @example Retry specific exceptions only\n * ```ts\n * import { toolRetryMiddleware } from \"langchain\";\n *\n * const retry = toolRetryMiddleware({\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 5xx errors\n * if (error.name === \"HTTPError\" && \"statusCode\" in error) {\n * const statusCode = (error as any).statusCode;\n * return 500 <= statusCode && statusCode < 600;\n * }\n * return false;\n * }\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 3,\n * retryOn: shouldRetry,\n * });\n * ```\n *\n * @example Apply to specific tools with custom error handling\n * ```ts\n * const formatError = (error: Error) =>\n * \"Database temporarily unavailable. Please try again later.\";\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [\"search_database\"],\n * onFailure: formatError,\n * });\n * ```\n *\n * @example Apply to specific tools using BaseTool instances\n * ```ts\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const searchDatabase = tool(\n * async ({ query }) => {\n * // Search implementation\n * return results;\n * },\n * {\n * name: \"search_database\",\n * description: \"Search the database\",\n * schema: z.object({ query: z.string() }),\n * }\n * );\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [searchDatabase], // Pass BaseTool instance\n * });\n * ```\n *\n * @example Constant backoff (no exponential growth)\n * ```ts\n * const retry = toolRetryMiddleware({\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 = toolRetryMiddleware({\n * maxRetries: 2,\n * onFailure: \"raise\", // 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 tool failures with retries\n */\nexport function toolRetryMiddleware(\n config: ToolRetryMiddlewareConfig = {}\n): AgentMiddleware {\n const {\n maxRetries,\n tools,\n retryOn,\n onFailure,\n backoffFactor,\n initialDelayMs,\n maxDelayMs,\n jitter,\n } = ToolRetryMiddlewareOptionsSchema.parse(config);\n\n // Extract tool names from BaseTool instances or strings\n const toolFilter: string[] = [];\n for (const tool of tools ?? []) {\n if (typeof tool === \"string\") {\n toolFilter.push(tool);\n } else if (\"name\" in tool && typeof tool.name === \"string\") {\n toolFilter.push(tool.name);\n } else {\n throw new TypeError(\n \"Expected a tool name string or tool instance to be passed to toolRetryMiddleware\"\n );\n }\n }\n\n /**\n * Check if retry logic should apply to this tool.\n */\n const shouldRetryTool = (toolName: string): boolean => {\n if (toolFilter.length === 0) {\n return true;\n }\n return toolFilter.includes(toolName);\n };\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 = (\n toolName: string,\n error: Error,\n attemptsMade: number\n ): string => {\n const errorType = error.constructor.name;\n const attemptWord = attemptsMade === 1 ? \"attempt\" : \"attempts\";\n return `Tool '${toolName}' failed after ${attemptsMade} ${attemptWord} with ${errorType}`;\n };\n\n /**\n * Handle failure when all retries are exhausted.\n */\n const handleFailure = (\n toolName: string,\n toolCallId: string,\n error: Error,\n attemptsMade: number\n ): ToolMessage => {\n if (onFailure === \"raise\") {\n throw error;\n }\n\n let content: string;\n if (typeof onFailure === \"function\") {\n content = onFailure(error);\n } else {\n content = formatFailureMessage(toolName, error, attemptsMade);\n }\n\n return new ToolMessage({\n content,\n tool_call_id: toolCallId,\n name: toolName,\n status: \"error\",\n });\n };\n\n return createMiddleware({\n name: \"toolRetryMiddleware\",\n contextSchema: ToolRetryMiddlewareOptionsSchema,\n wrapToolCall: async (request, handler) => {\n const toolName = request.tool.name as string;\n\n // Check if retry should apply to this tool\n if (!shouldRetryTool(toolName)) {\n return handler(request);\n }\n\n const toolCallId = request.toolCall.id ?? \"\";\n\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(toolName, toolCallId, 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(toolName, toolCallId, 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":"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"}
1
+ {"version":3,"file":"toolRetry.cjs","names":["z","RetrySchema","config: ToolRetryMiddlewareConfig","InvalidRetryConfigError","toolFilter: string[]","toolName: string","error: Error","error","attemptsMade: number","toolCallId: string","content: string","ToolMessage","createMiddleware","calculateRetryDelay","sleep"],"sources":["../../../src/agents/middleware/toolRetry.ts"],"sourcesContent":["/**\n * Tool retry middleware for agents.\n */\nimport { z } from \"zod/v3\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport type { AgentMiddleware } from \"./types.js\";\nimport { sleep, calculateRetryDelay } from \"./utils.js\";\nimport { RetrySchema } from \"./constants.js\";\nimport { InvalidRetryConfigError } from \"./error.js\";\n\n/**\n * Configuration options for the Tool Retry Middleware.\n */\nexport const ToolRetryMiddlewareOptionsSchema = z\n .object({\n /**\n * Optional list of tools or tool names to apply retry logic to.\n * Can be a list of `BaseTool` instances or tool name strings.\n * If `undefined`, applies to all tools. Default is `undefined`.\n */\n tools: z\n .array(\n z.union([z.custom<ClientTool>(), z.custom<ServerTool>(), z.string()])\n )\n .optional(),\n\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 * Deprecated values:\n * - `\"raise\"`: use `\"error\"` instead.\n * - `\"return_message\"`: use `\"continue\"` instead.\n */\n onFailure: z\n .union([\n z.literal(\"error\"),\n z.literal(\"continue\"),\n /**\n * @deprecated Use `\"error\"` instead.\n */\n z.literal(\"raise\"),\n /**\n * @deprecated Use `\"continue\"` instead.\n */\n z.literal(\"return_message\"),\n z.function().args(z.instanceof(Error)).returns(z.string()),\n ])\n .default(\"continue\"),\n })\n .merge(RetrySchema);\n\nexport type ToolRetryMiddlewareConfig = z.input<\n typeof ToolRetryMiddlewareOptionsSchema\n>;\n\n/**\n * Middleware that automatically retries failed tool 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, toolRetryMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * middleware: [toolRetryMiddleware()],\n * });\n * ```\n *\n * @example Retry specific exceptions only\n * ```ts\n * import { toolRetryMiddleware } from \"langchain\";\n *\n * const retry = toolRetryMiddleware({\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 5xx errors\n * if (error.name === \"HTTPError\" && \"statusCode\" in error) {\n * const statusCode = (error as any).statusCode;\n * return 500 <= statusCode && statusCode < 600;\n * }\n * return false;\n * }\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 3,\n * retryOn: shouldRetry,\n * });\n * ```\n *\n * @example Apply to specific tools with custom error handling\n * ```ts\n * const formatError = (error: Error) =>\n * \"Database temporarily unavailable. Please try again later.\";\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [\"search_database\"],\n * onFailure: formatError,\n * });\n * ```\n *\n * @example Apply to specific tools using BaseTool instances\n * ```ts\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const searchDatabase = tool(\n * async ({ query }) => {\n * // Search implementation\n * return results;\n * },\n * {\n * name: \"search_database\",\n * description: \"Search the database\",\n * schema: z.object({ query: z.string() }),\n * }\n * );\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [searchDatabase], // Pass BaseTool instance\n * });\n * ```\n *\n * @example Constant backoff (no exponential growth)\n * ```ts\n * const retry = toolRetryMiddleware({\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 = toolRetryMiddleware({\n * maxRetries: 2,\n * onFailure: \"raise\", // 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 tool failures with retries\n */\nexport function toolRetryMiddleware(\n config: ToolRetryMiddlewareConfig = {}\n): AgentMiddleware {\n const { success, error, data } =\n ToolRetryMiddlewareOptionsSchema.safeParse(config);\n if (!success) {\n throw new InvalidRetryConfigError(error);\n }\n const {\n maxRetries,\n tools,\n retryOn,\n onFailure: onFailureConfig,\n backoffFactor,\n initialDelayMs,\n maxDelayMs,\n jitter,\n } = data;\n\n let onFailure = onFailureConfig;\n if (onFailureConfig === \"raise\") {\n console.warn(\n \"⚠️ `onFailure: 'raise'` is deprecated. Use `onFailure: 'error'` instead.\"\n );\n onFailure = \"error\";\n } else if (onFailureConfig === \"return_message\") {\n console.warn(\n \"⚠️ `onFailure: 'return_message'` is deprecated. Use `onFailure: 'continue'` instead.\"\n );\n onFailure = \"continue\";\n }\n\n // Extract tool names from BaseTool instances or strings\n const toolFilter: string[] = [];\n for (const tool of tools ?? []) {\n if (typeof tool === \"string\") {\n toolFilter.push(tool);\n } else if (\"name\" in tool && typeof tool.name === \"string\") {\n toolFilter.push(tool.name);\n } else {\n throw new TypeError(\n \"Expected a tool name string or tool instance to be passed to toolRetryMiddleware\"\n );\n }\n }\n\n /**\n * Check if retry logic should apply to this tool.\n */\n const shouldRetryTool = (toolName: string): boolean => {\n if (toolFilter.length === 0) {\n return true;\n }\n return toolFilter.includes(toolName);\n };\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((ErrorConstructor) => {\n // eslint-disable-next-line no-instanceof/no-instanceof\n return error instanceof 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 = (\n toolName: string,\n error: Error,\n attemptsMade: number\n ): string => {\n const errorType = error.constructor.name;\n const attemptWord = attemptsMade === 1 ? \"attempt\" : \"attempts\";\n return `Tool '${toolName}' failed after ${attemptsMade} ${attemptWord} with ${errorType}`;\n };\n\n /**\n * Handle failure when all retries are exhausted.\n */\n const handleFailure = (\n toolName: string,\n toolCallId: string,\n error: Error,\n attemptsMade: number\n ): ToolMessage => {\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(toolName, error, attemptsMade);\n }\n\n return new ToolMessage({\n content,\n tool_call_id: toolCallId,\n name: toolName,\n status: \"error\",\n });\n };\n\n return createMiddleware({\n name: \"toolRetryMiddleware\",\n contextSchema: ToolRetryMiddlewareOptionsSchema,\n wrapToolCall: async (request, handler) => {\n const toolName = (request.tool?.name ?? request.toolCall.name) as string;\n\n // Check if retry should apply to this tool\n if (!shouldRetryTool(toolName)) {\n return handler(request);\n }\n\n const toolCallId = request.toolCall.id ?? \"\";\n\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(toolName, toolCallId, 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(toolName, toolCallId, 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":"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"}
@@ -8,70 +8,50 @@ import { z } from "zod/v3";
8
8
  * Configuration options for the Tool Retry Middleware.
9
9
  */
10
10
  declare const ToolRetryMiddlewareOptionsSchema: z.ZodObject<{
11
- /**
12
- * Maximum number of retry attempts after the initial call.
13
- * Default is 2 retries (3 total attempts). Must be >= 0.
14
- */
15
- maxRetries: z.ZodDefault<z.ZodNumber>;
16
11
  /**
17
12
  * Optional list of tools or tool names to apply retry logic to.
18
13
  * Can be a list of `BaseTool` instances or tool name strings.
19
14
  * If `undefined`, applies to all tools. Default is `undefined`.
20
15
  */
21
16
  tools: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodType<ClientTool, z.ZodTypeDef, ClientTool>, z.ZodType<ServerTool, z.ZodTypeDef, ServerTool>, z.ZodString]>, "many">>;
22
- /**
23
- * Either an array of error constructors to retry on, or a function
24
- * that takes an error and returns `true` if it should be retried.
25
- * Default is to retry on all errors.
26
- */
27
- retryOn: z.ZodDefault<z.ZodUnion<[z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodBoolean>, z.ZodArray<z.ZodType<new (...args: any[]) => Error, z.ZodTypeDef, new (...args: any[]) => Error>, "many">]>>;
28
17
  /**
29
18
  * Behavior when all retries are exhausted. Options:
30
- * - `"return_message"` (default): Return a ToolMessage with error details,
31
- * allowing the LLM to handle the failure and potentially recover.
32
- * - `"raise"`: Re-raise the exception, stopping agent execution.
19
+ * - `"continue"` (default): Return an AIMessage with error details, allowing
20
+ * the agent to potentially handle the failure gracefully.
21
+ * - `"error"`: Re-raise the exception, stopping agent execution.
33
22
  * - Custom function: Function that takes the exception and returns a string
34
- * for the ToolMessage content, allowing custom error formatting.
35
- */
36
- onFailure: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"raise">, z.ZodLiteral<"return_message">, z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodString>]>>;
37
- /**
38
- * Multiplier for exponential backoff. Each retry waits
39
- * `initialDelayMs * (backoffFactor ** retryNumber)` milliseconds.
40
- * Set to 0.0 for constant delay. Default is 2.0.
23
+ * for the AIMessage content, allowing custom error formatting.
24
+ *
25
+ * Deprecated values:
26
+ * - `"raise"`: use `"error"` instead.
27
+ * - `"return_message"`: use `"continue"` instead.
41
28
  */
29
+ onFailure: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"error">, z.ZodLiteral<"continue">, z.ZodLiteral<"raise">, z.ZodLiteral<"return_message">, z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodString>]>>;
30
+ } & {
31
+ maxRetries: z.ZodDefault<z.ZodNumber>;
32
+ retryOn: z.ZodDefault<z.ZodUnion<[z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodBoolean>, z.ZodArray<z.ZodType<new (...args: any[]) => Error, z.ZodTypeDef, new (...args: any[]) => Error>, "many">]>>;
42
33
  backoffFactor: z.ZodDefault<z.ZodNumber>;
43
- /**
44
- * Initial delay in milliseconds before first retry. Default is 1000 (1 second).
45
- */
46
34
  initialDelayMs: z.ZodDefault<z.ZodNumber>;
47
- /**
48
- * Maximum delay in milliseconds between retries. Caps exponential
49
- * backoff growth. Default is 60000 (60 seconds).
50
- */
51
35
  maxDelayMs: z.ZodDefault<z.ZodNumber>;
52
- /**
53
- * Whether to add random jitter (±25%) to delay to avoid thundering herd.
54
- * Default is `true`.
55
- */
56
36
  jitter: z.ZodDefault<z.ZodBoolean>;
57
37
  }, "strip", z.ZodTypeAny, {
58
38
  maxRetries: number;
59
- tools?: (string | ServerTool | ClientTool)[] | undefined;
60
39
  retryOn: (new (...args: any[]) => Error)[] | ((args_0: Error, ...args: unknown[]) => boolean);
61
- onFailure: "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string);
62
40
  backoffFactor: number;
63
41
  initialDelayMs: number;
64
42
  maxDelayMs: number;
65
43
  jitter: boolean;
44
+ tools?: (string | ServerTool | ClientTool)[] | undefined;
45
+ onFailure: "continue" | "error" | "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string);
66
46
  }, {
67
47
  maxRetries?: number | undefined;
68
- tools?: (string | ServerTool | ClientTool)[] | undefined;
69
48
  retryOn?: (new (...args: any[]) => Error)[] | ((args_0: Error, ...args: unknown[]) => boolean) | undefined;
70
- onFailure?: "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string) | undefined;
71
49
  backoffFactor?: number | undefined;
72
50
  initialDelayMs?: number | undefined;
73
51
  maxDelayMs?: number | undefined;
74
52
  jitter?: boolean | undefined;
53
+ tools?: (string | ServerTool | ClientTool)[] | undefined;
54
+ onFailure?: "continue" | "error" | "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string) | undefined;
75
55
  }>;
76
56
  type ToolRetryMiddlewareConfig = z.input<typeof ToolRetryMiddlewareOptionsSchema>;
77
57
  /**
@@ -8,70 +8,50 @@ import { z } from "zod/v3";
8
8
  * Configuration options for the Tool Retry Middleware.
9
9
  */
10
10
  declare const ToolRetryMiddlewareOptionsSchema: z.ZodObject<{
11
- /**
12
- * Maximum number of retry attempts after the initial call.
13
- * Default is 2 retries (3 total attempts). Must be >= 0.
14
- */
15
- maxRetries: z.ZodDefault<z.ZodNumber>;
16
11
  /**
17
12
  * Optional list of tools or tool names to apply retry logic to.
18
13
  * Can be a list of `BaseTool` instances or tool name strings.
19
14
  * If `undefined`, applies to all tools. Default is `undefined`.
20
15
  */
21
16
  tools: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodType<ClientTool, z.ZodTypeDef, ClientTool>, z.ZodType<ServerTool, z.ZodTypeDef, ServerTool>, z.ZodString]>, "many">>;
22
- /**
23
- * Either an array of error constructors to retry on, or a function
24
- * that takes an error and returns `true` if it should be retried.
25
- * Default is to retry on all errors.
26
- */
27
- retryOn: z.ZodDefault<z.ZodUnion<[z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodBoolean>, z.ZodArray<z.ZodType<new (...args: any[]) => Error, z.ZodTypeDef, new (...args: any[]) => Error>, "many">]>>;
28
17
  /**
29
18
  * Behavior when all retries are exhausted. Options:
30
- * - `"return_message"` (default): Return a ToolMessage with error details,
31
- * allowing the LLM to handle the failure and potentially recover.
32
- * - `"raise"`: Re-raise the exception, stopping agent execution.
19
+ * - `"continue"` (default): Return an AIMessage with error details, allowing
20
+ * the agent to potentially handle the failure gracefully.
21
+ * - `"error"`: Re-raise the exception, stopping agent execution.
33
22
  * - Custom function: Function that takes the exception and returns a string
34
- * for the ToolMessage content, allowing custom error formatting.
35
- */
36
- onFailure: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"raise">, z.ZodLiteral<"return_message">, z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodString>]>>;
37
- /**
38
- * Multiplier for exponential backoff. Each retry waits
39
- * `initialDelayMs * (backoffFactor ** retryNumber)` milliseconds.
40
- * Set to 0.0 for constant delay. Default is 2.0.
23
+ * for the AIMessage content, allowing custom error formatting.
24
+ *
25
+ * Deprecated values:
26
+ * - `"raise"`: use `"error"` instead.
27
+ * - `"return_message"`: use `"continue"` instead.
41
28
  */
29
+ onFailure: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"error">, z.ZodLiteral<"continue">, z.ZodLiteral<"raise">, z.ZodLiteral<"return_message">, z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodString>]>>;
30
+ } & {
31
+ maxRetries: z.ZodDefault<z.ZodNumber>;
32
+ retryOn: z.ZodDefault<z.ZodUnion<[z.ZodFunction<z.ZodTuple<[z.ZodType<Error, z.ZodTypeDef, Error>], z.ZodUnknown>, z.ZodBoolean>, z.ZodArray<z.ZodType<new (...args: any[]) => Error, z.ZodTypeDef, new (...args: any[]) => Error>, "many">]>>;
42
33
  backoffFactor: z.ZodDefault<z.ZodNumber>;
43
- /**
44
- * Initial delay in milliseconds before first retry. Default is 1000 (1 second).
45
- */
46
34
  initialDelayMs: z.ZodDefault<z.ZodNumber>;
47
- /**
48
- * Maximum delay in milliseconds between retries. Caps exponential
49
- * backoff growth. Default is 60000 (60 seconds).
50
- */
51
35
  maxDelayMs: z.ZodDefault<z.ZodNumber>;
52
- /**
53
- * Whether to add random jitter (±25%) to delay to avoid thundering herd.
54
- * Default is `true`.
55
- */
56
36
  jitter: z.ZodDefault<z.ZodBoolean>;
57
37
  }, "strip", z.ZodTypeAny, {
58
38
  maxRetries: number;
59
- tools?: (string | ServerTool | ClientTool)[] | undefined;
60
39
  retryOn: (new (...args: any[]) => Error)[] | ((args_0: Error, ...args: unknown[]) => boolean);
61
- onFailure: "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string);
62
40
  backoffFactor: number;
63
41
  initialDelayMs: number;
64
42
  maxDelayMs: number;
65
43
  jitter: boolean;
44
+ tools?: (string | ServerTool | ClientTool)[] | undefined;
45
+ onFailure: "continue" | "error" | "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string);
66
46
  }, {
67
47
  maxRetries?: number | undefined;
68
- tools?: (string | ServerTool | ClientTool)[] | undefined;
69
48
  retryOn?: (new (...args: any[]) => Error)[] | ((args_0: Error, ...args: unknown[]) => boolean) | undefined;
70
- onFailure?: "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string) | undefined;
71
49
  backoffFactor?: number | undefined;
72
50
  initialDelayMs?: number | undefined;
73
51
  maxDelayMs?: number | undefined;
74
52
  jitter?: boolean | undefined;
53
+ tools?: (string | ServerTool | ClientTool)[] | undefined;
54
+ onFailure?: "continue" | "error" | "raise" | "return_message" | ((args_0: Error, ...args: unknown[]) => string) | undefined;
75
55
  }>;
76
56
  type ToolRetryMiddlewareConfig = z.input<typeof ToolRetryMiddlewareOptionsSchema>;
77
57
  /**
@@ -1,52 +1,28 @@
1
- import { sleep } from "./utils.js";
1
+ import { calculateRetryDelay, sleep } from "./utils.js";
2
2
  import { createMiddleware } from "../middleware.js";
3
+ import { RetrySchema } from "./constants.js";
4
+ import { InvalidRetryConfigError } from "./error.js";
3
5
  import { ToolMessage } from "@langchain/core/messages";
4
6
  import { z } from "zod/v3";
5
7
 
6
8
  //#region src/agents/middleware/toolRetry.ts
7
9
  /**
8
- * Calculate delay for a retry attempt with exponential backoff and jitter.
9
- *
10
- * @param retryNumber - The retry attempt number (0-indexed)
11
- * @param config - Configuration for backoff calculation
12
- * @returns Delay in milliseconds before next retry
13
- *
14
- * @internal Exported for testing purposes
15
- */
16
- function calculateRetryDelay(config, retryNumber) {
17
- const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;
18
- let delay;
19
- if (backoffFactor === 0) delay = initialDelayMs;
20
- else delay = initialDelayMs * backoffFactor ** retryNumber;
21
- delay = Math.min(delay, maxDelayMs);
22
- if (jitter && delay > 0) {
23
- const jitterAmount = delay * .25;
24
- delay = delay + (Math.random() * 2 - 1) * jitterAmount;
25
- delay = Math.max(0, delay);
26
- }
27
- return delay;
28
- }
29
- /**
30
10
  * Configuration options for the Tool Retry Middleware.
31
11
  */
32
12
  const ToolRetryMiddlewareOptionsSchema = z.object({
33
- maxRetries: z.number().min(0).default(2),
34
13
  tools: z.array(z.union([
35
14
  z.custom(),
36
15
  z.custom(),
37
16
  z.string()
38
17
  ])).optional(),
39
- retryOn: z.union([z.function().args(z.instanceof(Error)).returns(z.boolean()), z.array(z.custom())]).default(() => () => true),
40
18
  onFailure: z.union([
19
+ z.literal("error"),
20
+ z.literal("continue"),
41
21
  z.literal("raise"),
42
22
  z.literal("return_message"),
43
23
  z.function().args(z.instanceof(Error)).returns(z.string())
44
- ]).default("return_message"),
45
- backoffFactor: z.number().min(0).default(2),
46
- initialDelayMs: z.number().min(0).default(1e3),
47
- maxDelayMs: z.number().min(0).default(6e4),
48
- jitter: z.boolean().default(true)
49
- });
24
+ ]).default("continue")
25
+ }).merge(RetrySchema);
50
26
  /**
51
27
  * Middleware that automatically retries failed tool calls with configurable backoff.
52
28
  *
@@ -147,7 +123,17 @@ const ToolRetryMiddlewareOptionsSchema = z.object({
147
123
  * @returns A middleware instance that handles tool failures with retries
148
124
  */
149
125
  function toolRetryMiddleware(config = {}) {
150
- const { maxRetries, tools, retryOn, onFailure, backoffFactor, initialDelayMs, maxDelayMs, jitter } = ToolRetryMiddlewareOptionsSchema.parse(config);
126
+ const { success, error, data } = ToolRetryMiddlewareOptionsSchema.safeParse(config);
127
+ if (!success) throw new InvalidRetryConfigError(error);
128
+ const { maxRetries, tools, retryOn, onFailure: onFailureConfig, backoffFactor, initialDelayMs, maxDelayMs, jitter } = data;
129
+ let onFailure = onFailureConfig;
130
+ if (onFailureConfig === "raise") {
131
+ console.warn("⚠️ `onFailure: 'raise'` is deprecated. Use `onFailure: 'error'` instead.");
132
+ onFailure = "error";
133
+ } else if (onFailureConfig === "return_message") {
134
+ console.warn("⚠️ `onFailure: 'return_message'` is deprecated. Use `onFailure: 'continue'` instead.");
135
+ onFailure = "continue";
136
+ }
151
137
  const toolFilter = [];
152
138
  for (const tool of tools ?? []) if (typeof tool === "string") toolFilter.push(tool);
153
139
  else if ("name" in tool && typeof tool.name === "string") toolFilter.push(tool.name);
@@ -162,9 +148,11 @@ function toolRetryMiddleware(config = {}) {
162
148
  /**
163
149
  * Check if the exception should trigger a retry.
164
150
  */
165
- const shouldRetryException = (error) => {
166
- if (typeof retryOn === "function") return retryOn(error);
167
- return retryOn.some((ErrorConstructor) => error.constructor === ErrorConstructor);
151
+ const shouldRetryException = (error$1) => {
152
+ if (typeof retryOn === "function") return retryOn(error$1);
153
+ return retryOn.some((ErrorConstructor) => {
154
+ return error$1 instanceof ErrorConstructor;
155
+ });
168
156
  };
169
157
  const delayConfig = {
170
158
  backoffFactor,
@@ -175,19 +163,19 @@ function toolRetryMiddleware(config = {}) {
175
163
  /**
176
164
  * Format the failure message when retries are exhausted.
177
165
  */
178
- const formatFailureMessage = (toolName, error, attemptsMade) => {
179
- const errorType = error.constructor.name;
166
+ const formatFailureMessage = (toolName, error$1, attemptsMade) => {
167
+ const errorType = error$1.constructor.name;
180
168
  const attemptWord = attemptsMade === 1 ? "attempt" : "attempts";
181
169
  return `Tool '${toolName}' failed after ${attemptsMade} ${attemptWord} with ${errorType}`;
182
170
  };
183
171
  /**
184
172
  * Handle failure when all retries are exhausted.
185
173
  */
186
- const handleFailure = (toolName, toolCallId, error, attemptsMade) => {
187
- if (onFailure === "raise") throw error;
174
+ const handleFailure = (toolName, toolCallId, error$1, attemptsMade) => {
175
+ if (onFailure === "error") throw error$1;
188
176
  let content;
189
- if (typeof onFailure === "function") content = onFailure(error);
190
- else content = formatFailureMessage(toolName, error, attemptsMade);
177
+ if (typeof onFailure === "function") content = onFailure(error$1);
178
+ else content = formatFailureMessage(toolName, error$1, attemptsMade);
191
179
  return new ToolMessage({
192
180
  content,
193
181
  tool_call_id: toolCallId,
@@ -199,14 +187,14 @@ function toolRetryMiddleware(config = {}) {
199
187
  name: "toolRetryMiddleware",
200
188
  contextSchema: ToolRetryMiddlewareOptionsSchema,
201
189
  wrapToolCall: async (request, handler) => {
202
- const toolName = request.tool.name;
190
+ const toolName = request.tool?.name ?? request.toolCall.name;
203
191
  if (!shouldRetryTool(toolName)) return handler(request);
204
192
  const toolCallId = request.toolCall.id ?? "";
205
193
  for (let attempt = 0; attempt <= maxRetries; attempt++) try {
206
194
  return await handler(request);
207
- } catch (error) {
195
+ } catch (error$1) {
208
196
  const attemptsMade = attempt + 1;
209
- const err = error && typeof error === "object" && "message" in error ? error : new Error(String(error));
197
+ const err = error$1 && typeof error$1 === "object" && "message" in error$1 ? error$1 : new Error(String(error$1));
210
198
  if (!shouldRetryException(err)) return handleFailure(toolName, toolCallId, err, attemptsMade);
211
199
  if (attempt < maxRetries) {
212
200
  const delay = calculateRetryDelay(delayConfig, attempt);
@@ -1 +1 @@
1
- {"version":3,"file":"toolRetry.js","names":["config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n }","retryNumber: number","delay: number","config: ToolRetryMiddlewareConfig","toolFilter: string[]","toolName: string","error: Error","attemptsMade: number","toolCallId: string","content: string"],"sources":["../../../src/agents/middleware/toolRetry.ts"],"sourcesContent":["/**\n * Tool retry middleware for agents.\n */\nimport { z } from \"zod/v3\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport type { AgentMiddleware } from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport function calculateRetryDelay(\n config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n },\n retryNumber: number\n): number {\n const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;\n\n let delay: number;\n if (backoffFactor === 0.0) {\n delay = initialDelayMs;\n } else {\n delay = initialDelayMs * backoffFactor ** retryNumber;\n }\n\n // Cap at maxDelayMs\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter && delay > 0) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * 2 - 1) * jitterAmount;\n // Ensure delay is not negative after jitter\n delay = Math.max(0, delay);\n }\n\n return delay;\n}\n\n/**\n * Configuration options for the Tool Retry Middleware.\n */\nexport const ToolRetryMiddlewareOptionsSchema = z.object({\n /**\n * Maximum number of retry attempts after the initial call.\n * Default is 2 retries (3 total attempts). Must be >= 0.\n */\n maxRetries: z.number().min(0).default(2),\n\n /**\n * Optional list of tools or tool names to apply retry logic to.\n * Can be a list of `BaseTool` instances or tool name strings.\n * If `undefined`, applies to all tools. Default is `undefined`.\n */\n tools: z\n .array(\n z.union([z.custom<ClientTool>(), z.custom<ServerTool>(), z.string()])\n )\n .optional(),\n\n /**\n * Either an array of error constructors to retry on, or a function\n * that takes an error and returns `true` if it should be retried.\n * Default is to retry on all errors.\n */\n retryOn: z\n .union([\n z.function().args(z.instanceof(Error)).returns(z.boolean()),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n z.array(z.custom<new (...args: any[]) => Error>()),\n ])\n .default(() => () => true),\n\n /**\n * Behavior when all retries are exhausted. Options:\n * - `\"return_message\"` (default): Return a ToolMessage with error details,\n * allowing the LLM to handle the failure and potentially recover.\n * - `\"raise\"`: Re-raise the exception, stopping agent execution.\n * - Custom function: Function that takes the exception and returns a string\n * for the ToolMessage content, allowing custom error formatting.\n */\n onFailure: z\n .union([\n z.literal(\"raise\"),\n z.literal(\"return_message\"),\n z.function().args(z.instanceof(Error)).returns(z.string()),\n ])\n .default(\"return_message\"),\n\n /**\n * Multiplier for exponential backoff. Each retry waits\n * `initialDelayMs * (backoffFactor ** retryNumber)` milliseconds.\n * Set to 0.0 for constant delay. Default is 2.0.\n */\n backoffFactor: z.number().min(0).default(2.0),\n\n /**\n * Initial delay in milliseconds before first retry. Default is 1000 (1 second).\n */\n initialDelayMs: z.number().min(0).default(1000),\n\n /**\n * Maximum delay in milliseconds between retries. Caps exponential\n * backoff growth. Default is 60000 (60 seconds).\n */\n maxDelayMs: z.number().min(0).default(60000),\n\n /**\n * Whether to add random jitter (±25%) to delay to avoid thundering herd.\n * Default is `true`.\n */\n jitter: z.boolean().default(true),\n});\n\nexport type ToolRetryMiddlewareConfig = z.input<\n typeof ToolRetryMiddlewareOptionsSchema\n>;\n\n/**\n * Middleware that automatically retries failed tool 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, toolRetryMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * middleware: [toolRetryMiddleware()],\n * });\n * ```\n *\n * @example Retry specific exceptions only\n * ```ts\n * import { toolRetryMiddleware } from \"langchain\";\n *\n * const retry = toolRetryMiddleware({\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 5xx errors\n * if (error.name === \"HTTPError\" && \"statusCode\" in error) {\n * const statusCode = (error as any).statusCode;\n * return 500 <= statusCode && statusCode < 600;\n * }\n * return false;\n * }\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 3,\n * retryOn: shouldRetry,\n * });\n * ```\n *\n * @example Apply to specific tools with custom error handling\n * ```ts\n * const formatError = (error: Error) =>\n * \"Database temporarily unavailable. Please try again later.\";\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [\"search_database\"],\n * onFailure: formatError,\n * });\n * ```\n *\n * @example Apply to specific tools using BaseTool instances\n * ```ts\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const searchDatabase = tool(\n * async ({ query }) => {\n * // Search implementation\n * return results;\n * },\n * {\n * name: \"search_database\",\n * description: \"Search the database\",\n * schema: z.object({ query: z.string() }),\n * }\n * );\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [searchDatabase], // Pass BaseTool instance\n * });\n * ```\n *\n * @example Constant backoff (no exponential growth)\n * ```ts\n * const retry = toolRetryMiddleware({\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 = toolRetryMiddleware({\n * maxRetries: 2,\n * onFailure: \"raise\", // 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 tool failures with retries\n */\nexport function toolRetryMiddleware(\n config: ToolRetryMiddlewareConfig = {}\n): AgentMiddleware {\n const {\n maxRetries,\n tools,\n retryOn,\n onFailure,\n backoffFactor,\n initialDelayMs,\n maxDelayMs,\n jitter,\n } = ToolRetryMiddlewareOptionsSchema.parse(config);\n\n // Extract tool names from BaseTool instances or strings\n const toolFilter: string[] = [];\n for (const tool of tools ?? []) {\n if (typeof tool === \"string\") {\n toolFilter.push(tool);\n } else if (\"name\" in tool && typeof tool.name === \"string\") {\n toolFilter.push(tool.name);\n } else {\n throw new TypeError(\n \"Expected a tool name string or tool instance to be passed to toolRetryMiddleware\"\n );\n }\n }\n\n /**\n * Check if retry logic should apply to this tool.\n */\n const shouldRetryTool = (toolName: string): boolean => {\n if (toolFilter.length === 0) {\n return true;\n }\n return toolFilter.includes(toolName);\n };\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 = (\n toolName: string,\n error: Error,\n attemptsMade: number\n ): string => {\n const errorType = error.constructor.name;\n const attemptWord = attemptsMade === 1 ? \"attempt\" : \"attempts\";\n return `Tool '${toolName}' failed after ${attemptsMade} ${attemptWord} with ${errorType}`;\n };\n\n /**\n * Handle failure when all retries are exhausted.\n */\n const handleFailure = (\n toolName: string,\n toolCallId: string,\n error: Error,\n attemptsMade: number\n ): ToolMessage => {\n if (onFailure === \"raise\") {\n throw error;\n }\n\n let content: string;\n if (typeof onFailure === \"function\") {\n content = onFailure(error);\n } else {\n content = formatFailureMessage(toolName, error, attemptsMade);\n }\n\n return new ToolMessage({\n content,\n tool_call_id: toolCallId,\n name: toolName,\n status: \"error\",\n });\n };\n\n return createMiddleware({\n name: \"toolRetryMiddleware\",\n contextSchema: ToolRetryMiddlewareOptionsSchema,\n wrapToolCall: async (request, handler) => {\n const toolName = request.tool.name as string;\n\n // Check if retry should apply to this tool\n if (!shouldRetryTool(toolName)) {\n return handler(request);\n }\n\n const toolCallId = request.toolCall.id ?? \"\";\n\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(toolName, toolCallId, 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(toolName, toolCallId, 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":"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"}
1
+ {"version":3,"file":"toolRetry.js","names":["config: ToolRetryMiddlewareConfig","toolFilter: string[]","toolName: string","error: Error","error","attemptsMade: number","toolCallId: string","content: string"],"sources":["../../../src/agents/middleware/toolRetry.ts"],"sourcesContent":["/**\n * Tool retry middleware for agents.\n */\nimport { z } from \"zod/v3\";\nimport { ToolMessage } from \"@langchain/core/messages\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\n\nimport { createMiddleware } from \"../middleware.js\";\nimport type { AgentMiddleware } from \"./types.js\";\nimport { sleep, calculateRetryDelay } from \"./utils.js\";\nimport { RetrySchema } from \"./constants.js\";\nimport { InvalidRetryConfigError } from \"./error.js\";\n\n/**\n * Configuration options for the Tool Retry Middleware.\n */\nexport const ToolRetryMiddlewareOptionsSchema = z\n .object({\n /**\n * Optional list of tools or tool names to apply retry logic to.\n * Can be a list of `BaseTool` instances or tool name strings.\n * If `undefined`, applies to all tools. Default is `undefined`.\n */\n tools: z\n .array(\n z.union([z.custom<ClientTool>(), z.custom<ServerTool>(), z.string()])\n )\n .optional(),\n\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 * Deprecated values:\n * - `\"raise\"`: use `\"error\"` instead.\n * - `\"return_message\"`: use `\"continue\"` instead.\n */\n onFailure: z\n .union([\n z.literal(\"error\"),\n z.literal(\"continue\"),\n /**\n * @deprecated Use `\"error\"` instead.\n */\n z.literal(\"raise\"),\n /**\n * @deprecated Use `\"continue\"` instead.\n */\n z.literal(\"return_message\"),\n z.function().args(z.instanceof(Error)).returns(z.string()),\n ])\n .default(\"continue\"),\n })\n .merge(RetrySchema);\n\nexport type ToolRetryMiddlewareConfig = z.input<\n typeof ToolRetryMiddlewareOptionsSchema\n>;\n\n/**\n * Middleware that automatically retries failed tool 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, toolRetryMiddleware } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * middleware: [toolRetryMiddleware()],\n * });\n * ```\n *\n * @example Retry specific exceptions only\n * ```ts\n * import { toolRetryMiddleware } from \"langchain\";\n *\n * const retry = toolRetryMiddleware({\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 5xx errors\n * if (error.name === \"HTTPError\" && \"statusCode\" in error) {\n * const statusCode = (error as any).statusCode;\n * return 500 <= statusCode && statusCode < 600;\n * }\n * return false;\n * }\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 3,\n * retryOn: shouldRetry,\n * });\n * ```\n *\n * @example Apply to specific tools with custom error handling\n * ```ts\n * const formatError = (error: Error) =>\n * \"Database temporarily unavailable. Please try again later.\";\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [\"search_database\"],\n * onFailure: formatError,\n * });\n * ```\n *\n * @example Apply to specific tools using BaseTool instances\n * ```ts\n * import { tool } from \"@langchain/core/tools\";\n * import { z } from \"zod\";\n *\n * const searchDatabase = tool(\n * async ({ query }) => {\n * // Search implementation\n * return results;\n * },\n * {\n * name: \"search_database\",\n * description: \"Search the database\",\n * schema: z.object({ query: z.string() }),\n * }\n * );\n *\n * const retry = toolRetryMiddleware({\n * maxRetries: 4,\n * tools: [searchDatabase], // Pass BaseTool instance\n * });\n * ```\n *\n * @example Constant backoff (no exponential growth)\n * ```ts\n * const retry = toolRetryMiddleware({\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 = toolRetryMiddleware({\n * maxRetries: 2,\n * onFailure: \"raise\", // 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 tool failures with retries\n */\nexport function toolRetryMiddleware(\n config: ToolRetryMiddlewareConfig = {}\n): AgentMiddleware {\n const { success, error, data } =\n ToolRetryMiddlewareOptionsSchema.safeParse(config);\n if (!success) {\n throw new InvalidRetryConfigError(error);\n }\n const {\n maxRetries,\n tools,\n retryOn,\n onFailure: onFailureConfig,\n backoffFactor,\n initialDelayMs,\n maxDelayMs,\n jitter,\n } = data;\n\n let onFailure = onFailureConfig;\n if (onFailureConfig === \"raise\") {\n console.warn(\n \"⚠️ `onFailure: 'raise'` is deprecated. Use `onFailure: 'error'` instead.\"\n );\n onFailure = \"error\";\n } else if (onFailureConfig === \"return_message\") {\n console.warn(\n \"⚠️ `onFailure: 'return_message'` is deprecated. Use `onFailure: 'continue'` instead.\"\n );\n onFailure = \"continue\";\n }\n\n // Extract tool names from BaseTool instances or strings\n const toolFilter: string[] = [];\n for (const tool of tools ?? []) {\n if (typeof tool === \"string\") {\n toolFilter.push(tool);\n } else if (\"name\" in tool && typeof tool.name === \"string\") {\n toolFilter.push(tool.name);\n } else {\n throw new TypeError(\n \"Expected a tool name string or tool instance to be passed to toolRetryMiddleware\"\n );\n }\n }\n\n /**\n * Check if retry logic should apply to this tool.\n */\n const shouldRetryTool = (toolName: string): boolean => {\n if (toolFilter.length === 0) {\n return true;\n }\n return toolFilter.includes(toolName);\n };\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((ErrorConstructor) => {\n // eslint-disable-next-line no-instanceof/no-instanceof\n return error instanceof 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 = (\n toolName: string,\n error: Error,\n attemptsMade: number\n ): string => {\n const errorType = error.constructor.name;\n const attemptWord = attemptsMade === 1 ? \"attempt\" : \"attempts\";\n return `Tool '${toolName}' failed after ${attemptsMade} ${attemptWord} with ${errorType}`;\n };\n\n /**\n * Handle failure when all retries are exhausted.\n */\n const handleFailure = (\n toolName: string,\n toolCallId: string,\n error: Error,\n attemptsMade: number\n ): ToolMessage => {\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(toolName, error, attemptsMade);\n }\n\n return new ToolMessage({\n content,\n tool_call_id: toolCallId,\n name: toolName,\n status: \"error\",\n });\n };\n\n return createMiddleware({\n name: \"toolRetryMiddleware\",\n contextSchema: ToolRetryMiddlewareOptionsSchema,\n wrapToolCall: async (request, handler) => {\n const toolName = (request.tool?.name ?? request.toolCall.name) as string;\n\n // Check if retry should apply to this tool\n if (!shouldRetryTool(toolName)) {\n return handler(request);\n }\n\n const toolCallId = request.toolCall.id ?? \"\";\n\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(toolName, toolCallId, 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(toolName, toolCallId, 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":"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"}
@@ -1,7 +1,7 @@
1
1
  import { JumpToTarget } from "../constants.cjs";
2
2
  import { AgentBuiltInState, Runtime } from "../runtime.cjs";
3
3
  import { ModelRequest } from "../nodes/types.cjs";
4
- import { AIMessage, ToolMessage } from "@langchain/core/messages";
4
+ import { AIMessage, SystemMessage, ToolMessage } from "@langchain/core/messages";
5
5
  import { ClientTool, ServerTool } from "@langchain/core/tools";
6
6
  import { InferInteropZodInput, InferInteropZodOutput, InteropZodDefault, InteropZodObject, InteropZodOptional } from "@langchain/core/utils/types";
7
7
  import { ToolCall as ToolCall$1 } from "@langchain/core/messages/tool";
@@ -58,7 +58,14 @@ type WrapToolCallHook<TSchema extends InteropZodObject | undefined = undefined,
58
58
  * @param request - The model request containing model, messages, systemPrompt, tools, state, and runtime
59
59
  * @returns The AI message response from the model
60
60
  */
61
- type WrapModelCallHandler<TSchema extends InteropZodObject | undefined = undefined, TContext = unknown> = (request: ModelRequest<NormalizedSchemaInput<TSchema>, TContext>) => PromiseOrValue<AIMessage>;
61
+ type WrapModelCallHandler<TSchema extends InteropZodObject | undefined = undefined, TContext = unknown> = (request: Omit<ModelRequest<NormalizedSchemaInput<TSchema>, TContext>,
62
+ /**
63
+ * allow to reset the system prompt or system message
64
+ */
65
+ "systemPrompt" | "systemMessage"> & {
66
+ systemPrompt?: string;
67
+ systemMessage?: SystemMessage;
68
+ }) => PromiseOrValue<AIMessage>;
62
69
  /**
63
70
  * Wrapper function type for the wrapModelCall hook.
64
71
  * Allows middleware to intercept and modify model execution.
@@ -325,18 +332,10 @@ type InferMiddlewareStates<T = AgentMiddleware[]> = T extends readonly [] ? {} :
325
332
  * Helper type to infer merged input state from an array of middleware (with optional defaults)
326
333
  */
327
334
  type InferMiddlewareInputStates<T extends readonly AgentMiddleware[]> = T extends readonly [] ? {} : T extends readonly [infer First, ...infer Rest] ? First extends AgentMiddleware ? Rest extends readonly AgentMiddleware[] ? InferMiddlewareInputState<First> & InferMiddlewareInputStates<Rest> : InferMiddlewareInputState<First> : {} : {};
328
- /**
329
- * Helper type to infer merged state from an array of middleware (includes built-in state)
330
- */
331
-
332
335
  /**
333
336
  * Helper type to infer the input context schema type from a middleware (with optional defaults)
334
337
  */
335
338
  type InferMiddlewareContextInput<T extends AgentMiddleware> = T extends AgentMiddleware<any, infer C, any> ? C extends InteropZodOptional<infer Inner> ? InferInteropZodInput<Inner> | undefined : C extends InteropZodObject ? InferInteropZodInput<C> : {} : {};
336
- /**
337
- * Helper type to infer merged context from an array of middleware
338
- */
339
-
340
339
  /**
341
340
  * Helper to merge two context types, preserving undefined unions
342
341
  */