langchain 1.0.2 → 1.0.4

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 (132) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/agents/ReactAgent.cjs +21 -41
  3. package/dist/agents/ReactAgent.cjs.map +1 -1
  4. package/dist/agents/ReactAgent.js +21 -41
  5. package/dist/agents/ReactAgent.js.map +1 -1
  6. package/dist/agents/annotation.cjs +7 -4
  7. package/dist/agents/annotation.cjs.map +1 -1
  8. package/dist/agents/annotation.js +8 -5
  9. package/dist/agents/annotation.js.map +1 -1
  10. package/dist/agents/middleware/contextEditing.d.cts.map +1 -1
  11. package/dist/agents/middleware/contextEditing.d.ts.map +1 -1
  12. package/dist/agents/middleware/dynamicSystemPrompt.d.cts.map +1 -1
  13. package/dist/agents/middleware/dynamicSystemPrompt.d.ts.map +1 -1
  14. package/dist/agents/middleware/hitl.cjs +7 -2
  15. package/dist/agents/middleware/hitl.cjs.map +1 -1
  16. package/dist/agents/middleware/hitl.d.cts.map +1 -1
  17. package/dist/agents/middleware/hitl.d.ts.map +1 -1
  18. package/dist/agents/middleware/hitl.js +7 -2
  19. package/dist/agents/middleware/hitl.js.map +1 -1
  20. package/dist/agents/middleware/index.cjs +2 -1
  21. package/dist/agents/middleware/index.js +2 -1
  22. package/dist/agents/middleware/llmToolSelector.d.cts +4 -4
  23. package/dist/agents/middleware/llmToolSelector.d.cts.map +1 -1
  24. package/dist/agents/middleware/{callLimit.cjs → modelCallLimit.cjs} +22 -7
  25. package/dist/agents/middleware/modelCallLimit.cjs.map +1 -0
  26. package/dist/agents/middleware/{callLimit.d.cts → modelCallLimit.d.cts} +12 -3
  27. package/dist/agents/middleware/modelCallLimit.d.cts.map +1 -0
  28. package/dist/agents/middleware/{callLimit.d.ts → modelCallLimit.d.ts} +12 -3
  29. package/dist/agents/middleware/modelCallLimit.d.ts.map +1 -0
  30. package/dist/agents/middleware/{callLimit.js → modelCallLimit.js} +22 -7
  31. package/dist/agents/middleware/modelCallLimit.js.map +1 -0
  32. package/dist/agents/middleware/promptCaching.d.cts.map +1 -1
  33. package/dist/agents/middleware/promptCaching.d.ts.map +1 -1
  34. package/dist/agents/middleware/summarization.cjs +274 -52
  35. package/dist/agents/middleware/summarization.cjs.map +1 -1
  36. package/dist/agents/middleware/summarization.d.cts +326 -30
  37. package/dist/agents/middleware/summarization.d.cts.map +1 -1
  38. package/dist/agents/middleware/summarization.d.ts +325 -29
  39. package/dist/agents/middleware/summarization.d.ts.map +1 -1
  40. package/dist/agents/middleware/summarization.js +276 -54
  41. package/dist/agents/middleware/summarization.js.map +1 -1
  42. package/dist/agents/middleware/todoListMiddleware.d.cts.map +1 -1
  43. package/dist/agents/middleware/todoListMiddleware.d.ts.map +1 -1
  44. package/dist/agents/middleware/toolCallLimit.cjs +215 -93
  45. package/dist/agents/middleware/toolCallLimit.cjs.map +1 -1
  46. package/dist/agents/middleware/toolCallLimit.d.cts +48 -37
  47. package/dist/agents/middleware/toolCallLimit.d.cts.map +1 -1
  48. package/dist/agents/middleware/toolCallLimit.d.ts +48 -37
  49. package/dist/agents/middleware/toolCallLimit.d.ts.map +1 -1
  50. package/dist/agents/middleware/toolCallLimit.js +216 -94
  51. package/dist/agents/middleware/toolCallLimit.js.map +1 -1
  52. package/dist/agents/middleware/toolRetry.cjs +224 -0
  53. package/dist/agents/middleware/toolRetry.cjs.map +1 -0
  54. package/dist/agents/middleware/toolRetry.d.cts +179 -0
  55. package/dist/agents/middleware/toolRetry.d.cts.map +1 -0
  56. package/dist/agents/middleware/toolRetry.d.ts +179 -0
  57. package/dist/agents/middleware/toolRetry.d.ts.map +1 -0
  58. package/dist/agents/middleware/toolRetry.js +223 -0
  59. package/dist/agents/middleware/toolRetry.js.map +1 -0
  60. package/dist/agents/middleware/types.d.cts +21 -19
  61. package/dist/agents/middleware/types.d.cts.map +1 -1
  62. package/dist/agents/middleware/types.d.ts +21 -19
  63. package/dist/agents/middleware/types.d.ts.map +1 -1
  64. package/dist/agents/middleware/utils.cjs +7 -0
  65. package/dist/agents/middleware/utils.cjs.map +1 -1
  66. package/dist/agents/middleware/utils.d.cts.map +1 -1
  67. package/dist/agents/middleware/utils.d.ts.map +1 -1
  68. package/dist/agents/middleware/utils.js +7 -1
  69. package/dist/agents/middleware/utils.js.map +1 -1
  70. package/dist/agents/middleware.cjs.map +1 -1
  71. package/dist/agents/middleware.d.cts +4 -4
  72. package/dist/agents/middleware.d.cts.map +1 -1
  73. package/dist/agents/middleware.d.ts +4 -4
  74. package/dist/agents/middleware.d.ts.map +1 -1
  75. package/dist/agents/middleware.js.map +1 -1
  76. package/dist/agents/nodes/AgentNode.cjs +21 -51
  77. package/dist/agents/nodes/AgentNode.cjs.map +1 -1
  78. package/dist/agents/nodes/AgentNode.js +23 -53
  79. package/dist/agents/nodes/AgentNode.js.map +1 -1
  80. package/dist/agents/nodes/ToolNode.cjs +12 -18
  81. package/dist/agents/nodes/ToolNode.cjs.map +1 -1
  82. package/dist/agents/nodes/ToolNode.js +12 -18
  83. package/dist/agents/nodes/ToolNode.js.map +1 -1
  84. package/dist/agents/nodes/middleware.cjs +9 -7
  85. package/dist/agents/nodes/middleware.cjs.map +1 -1
  86. package/dist/agents/nodes/middleware.js +10 -8
  87. package/dist/agents/nodes/middleware.js.map +1 -1
  88. package/dist/agents/nodes/types.d.cts +1 -1
  89. package/dist/agents/nodes/types.d.cts.map +1 -1
  90. package/dist/agents/nodes/types.d.ts +1 -1
  91. package/dist/agents/nodes/types.d.ts.map +1 -1
  92. package/dist/agents/nodes/utils.cjs +5 -1
  93. package/dist/agents/nodes/utils.cjs.map +1 -1
  94. package/dist/agents/nodes/utils.js +5 -1
  95. package/dist/agents/nodes/utils.js.map +1 -1
  96. package/dist/agents/responses.cjs +0 -1
  97. package/dist/agents/responses.js +1 -1
  98. package/dist/agents/runtime.d.cts +11 -27
  99. package/dist/agents/runtime.d.cts.map +1 -1
  100. package/dist/agents/runtime.d.ts +11 -27
  101. package/dist/agents/runtime.d.ts.map +1 -1
  102. package/dist/agents/state.cjs +45 -0
  103. package/dist/agents/state.cjs.map +1 -0
  104. package/dist/agents/state.js +44 -0
  105. package/dist/agents/state.js.map +1 -0
  106. package/dist/agents/types.d.cts +1 -1
  107. package/dist/agents/types.d.cts.map +1 -1
  108. package/dist/agents/types.d.ts +1 -1
  109. package/dist/agents/types.d.ts.map +1 -1
  110. package/dist/agents/utils.cjs +10 -2
  111. package/dist/agents/utils.cjs.map +1 -1
  112. package/dist/agents/utils.js +10 -2
  113. package/dist/agents/utils.js.map +1 -1
  114. package/dist/chat_models/universal.cjs +2 -2
  115. package/dist/chat_models/universal.cjs.map +1 -1
  116. package/dist/chat_models/universal.js +2 -2
  117. package/dist/chat_models/universal.js.map +1 -1
  118. package/dist/index.cjs +6 -18
  119. package/dist/index.cjs.map +1 -1
  120. package/dist/index.d.cts +4 -4
  121. package/dist/index.d.ts +4 -4
  122. package/dist/index.js +4 -5
  123. package/dist/index.js.map +1 -1
  124. package/package.json +7 -7
  125. package/dist/agents/middleware/callLimit.cjs.map +0 -1
  126. package/dist/agents/middleware/callLimit.d.cts.map +0 -1
  127. package/dist/agents/middleware/callLimit.d.ts.map +0 -1
  128. package/dist/agents/middleware/callLimit.js.map +0 -1
  129. package/dist/agents/tools.d.cts +0 -9
  130. package/dist/agents/tools.d.cts.map +0 -1
  131. package/dist/agents/tools.d.ts +0 -9
  132. package/dist/agents/tools.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"toolCallLimit.d.cts","names":["z","InferInteropZodInput","ToolCallLimitExceededError","Error","ToolCallLimitOptionsSchema","ZodString","ZodOptional","ZodNumber","ZodEnum","ZodDefault","ZodTypeAny","ZodObject","ToolCallLimitConfig","toolCallLimitMiddleware","__types_js2","AgentMiddleware"],"sources":["../../../src/agents/middleware/toolCallLimit.d.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport declare class ToolCallLimitExceededError extends Error {\n /**\n * Current thread tool call count.\n */\n threadCount: number;\n /**\n * Current run tool call count.\n */\n runCount: number;\n /**\n * Thread tool call limit (if set).\n */\n threadLimit: number | undefined;\n /**\n * Run tool call limit (if set).\n */\n runLimit: number | undefined;\n /**\n * Tool name being limited (if specific tool), or undefined for all tools.\n */\n toolName: string | undefined;\n constructor(threadCount: number, runCount: number, threadLimit: number | undefined, runLimit: number | undefined, toolName?: string | undefined);\n}\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport declare const ToolCallLimitOptionsSchema: z.ZodObject<{\n /**\n * Name of the specific tool to limit. If undefined, limits apply to all tools.\n */\n toolName: z.ZodOptional<z.ZodString>;\n /**\n * Maximum number of tool calls allowed per thread.\n * undefined means no limit.\n */\n threadLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * Maximum number of tool calls allowed per run.\n * undefined means no limit.\n */\n runLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * What to do when limits are exceeded.\n * - \"end\": Jump to the end of the agent execution and inject an artificial\n * AI message indicating that the limit was exceeded.\n * - \"error\": throws a ToolCallLimitExceededError\n */\n exitBehavior: z.ZodDefault<z.ZodEnum<[\"end\", \"error\"]>>;\n}, \"strip\", z.ZodTypeAny, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior: \"end\" | \"error\";\n}, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior?: \"end\" | \"error\" | undefined;\n}>;\nexport type ToolCallLimitConfig = InferInteropZodInput<typeof ToolCallLimitOptionsSchema>;\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n * - \"end\": Jump to the end of the agent execution and inject an artificial AI message indicating that the limit was exceeded.\n * - \"error\": throws a ToolCallLimitExceededError\n *\n * @throws {Error} If both limits are undefined or if exitBehavior is invalid.\n *\n * @example Limit all tool calls globally\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * const globalLimiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [globalLimiter]\n * });\n * ```\n *\n * @example Limit a specific tool\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * const searchLimiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * runLimit: 3,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [searchLimiter]\n * });\n * ```\n *\n * @example Use both in the same agent\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * const globalLimiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"end\"\n * });\n *\n * const searchLimiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * runLimit: 3,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [globalLimiter, searchLimiter]\n * });\n * ```\n */\nexport declare function toolCallLimitMiddleware(options: ToolCallLimitConfig): import(\"./types.js\").AgentMiddleware<undefined, undefined, any>;\n"],"mappings":";;;;;;;;;AAQA;AA0BA;;AAI4BA,cA9BPE,0BAAAA,SAAmCC,KAAK,CA8B/BE;EAAS;;;EAKT,WAKAE,EAAAA,MAAAA;EAAS;;;EAOT,QAChBG,EAAAA,MAAAA;EAAU;AAtBoC;AAiC5D;EAA+B,WAAA,EAAA,MAAA,GAAA,SAAA;EAAA;;AAAuB;EAmF9BG,QAAAA,EAAAA,MAAAA,GAAAA,SAAuB;EAAA;;;EAAoE,QAAA,EAAA,MAAA,GAAA,SAAA;;;;;;cApH9FT,4BAA4BJ,CAAAA,CAAEW;;;;YAIrCX,CAAAA,CAAEM,YAAYN,CAAAA,CAAEK;;;;;eAKbL,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;YAKnBP,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;;;gBAOZP,CAAAA,CAAES,WAAWT,CAAAA,CAAEQ;YACrBR,CAAAA,CAAEU;;;;;;;;;;;KAWFE,mBAAAA,GAAsBX,4BAA4BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmFtCS,uBAAAA,UAAiCD,sBAAmB"}
1
+ {"version":3,"file":"toolCallLimit.d.cts","names":["z","InferInteropZodInput","ToolCallLimitExceededError","Error","ToolCallLimitOptionsSchema","ZodString","ZodOptional","ZodNumber","ZodEnum","ZodDefault","ZodTypeAny","ZodObject","ToolCallLimitConfig","toolCallLimitMiddleware","ZodRecord","Record","__types_js13","AgentMiddleware"],"sources":["../../../src/agents/middleware/toolCallLimit.d.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport declare class ToolCallLimitExceededError extends Error {\n /**\n * Current thread tool call count.\n */\n threadCount: number;\n /**\n * Current run tool call count.\n */\n runCount: number;\n /**\n * Thread tool call limit (if set).\n */\n threadLimit: number | undefined;\n /**\n * Run tool call limit (if set).\n */\n runLimit: number | undefined;\n /**\n * Tool name being limited (if specific tool), or undefined for all tools.\n */\n toolName: string | undefined;\n constructor(threadCount: number, runCount: number, threadLimit: number | undefined, runLimit: number | undefined, toolName?: string | undefined);\n}\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport declare const ToolCallLimitOptionsSchema: z.ZodObject<{\n /**\n * Name of the specific tool to limit. If undefined, limits apply to all tools.\n */\n toolName: z.ZodOptional<z.ZodString>;\n /**\n * Maximum number of tool calls allowed per thread.\n * undefined means no limit.\n */\n threadLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * Maximum number of tool calls allowed per run.\n * undefined means no limit.\n */\n runLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately, injecting a ToolMessage and an AI message\n * for the single tool call that exceeded the limit. Raises NotImplementedError\n * if there are multiple tool calls.\n *\n * @default \"continue\"\n */\n exitBehavior: z.ZodDefault<z.ZodEnum<[\"continue\", \"error\", \"end\"]>>;\n}, \"strip\", z.ZodTypeAny, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior: \"continue\" | \"end\" | \"error\";\n}, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior?: \"continue\" | \"end\" | \"error\" | undefined;\n}>;\nexport type ToolCallLimitConfig = InferInteropZodInput<typeof ToolCallLimitOptionsSchema>;\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.\n *\n * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.\n * @throws {NotImplementedError} If exitBehavior is \"end\" and there are multiple tool calls.\n *\n * @example Continue execution with blocked tools (default)\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * // Block exceeded tools but let other tools and model continue\n * const limiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"continue\", // default\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Stop immediately when limit exceeded\n * ```ts\n * // End execution immediately with an AI message\n * const limiter = toolCallLimitMiddleware({\n * runLimit: 5,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Raise exception on limit\n * ```ts\n * // Strict limit with exception handling\n * const limiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * exitBehavior: \"error\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n *\n * try {\n * const result = await agent.invoke({ messages: [new HumanMessage(\"Task\")] });\n * } catch (error) {\n * if (error instanceof ToolCallLimitExceededError) {\n * console.log(`Search limit exceeded: ${error}`);\n * }\n * }\n * ```\n */\nexport declare function toolCallLimitMiddleware(options: ToolCallLimitConfig): import(\"./types.js\").AgentMiddleware<z.ZodObject<{\n threadToolCallCount: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;\n runToolCallCount: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;\n}, \"strip\", z.ZodTypeAny, {\n threadToolCallCount: Record<string, number>;\n runToolCallCount: Record<string, number>;\n}, {\n threadToolCallCount?: Record<string, number> | undefined;\n runToolCallCount?: Record<string, number> | undefined;\n}>, undefined, any>;\n"],"mappings":";;;;;;;;;AAQA;AA0BA;;AAI4BA,cA9BPE,0BAAAA,SAAmCC,KAAK,CA8B/BE;EAAS;;;EAKT,WAKAE,EAAAA,MAAAA;EAAS;;;EAWT,QAChBG,EAAAA,MAAAA;EAAU;AA1BoC;AAqC5D;EAA+B,WAAA,EAAA,MAAA,GAAA,SAAA;EAAA;;AAAuB;EAiF9BG,QAAAA,EAAAA,MAAAA,GAAAA,SAAuB;EAAA;;;EACc,QAAIN,EAAAA,MAAAA,GAAAA,SAAAA;EAAS,WAAlCO,CAAAA,WAAAA,EAAAA,MAAAA,EAAAA,QAAAA,EAAAA,MAAAA,EAAAA,WAAAA,EAAAA,MAAAA,GAAAA,SAAAA,EAAAA,QAAAA,EAAAA,MAAAA,GAAAA,SAAAA,EAAAA,QAAAA,CAAAA,EAAAA,MAAAA,GAAAA,SAAAA;;;;;AAClBd,cAxHDI,0BAwHGK,EAxHyBT,CAAAA,CAAEW,SAwH3BF,CAAAA;EAAU;;;EAGN,QAEFM,EAzHZf,CAAAA,CAAEM,WAyHUS,CAzHEf,CAAAA,CAAEK,SAyHJU,CAAAA;EAAM;;;AAPmF;eA7GlGf,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;YAKnBP,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;;;;;;;gBAWZP,CAAAA,CAAES,WAAWT,CAAAA,CAAEQ;YACrBR,CAAAA,CAAEU;;;;;;;;;;;KAWFE,mBAAAA,GAAsBX,4BAA4BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiFtCS,uBAAAA,UAAiCD,sBAAsE,gBAAXZ,CAAAA,CAAEW;uBAC7FX,CAAAA,CAAES,WAAWT,CAAAA,CAAEc,UAAUd,CAAAA,CAAEK,WAAWL,CAAAA,CAAEO;oBAC3CP,CAAAA,CAAES,WAAWT,CAAAA,CAAEc,UAAUd,CAAAA,CAAEK,WAAWL,CAAAA,CAAEO;YAClDP,CAAAA,CAAEU;uBACWK;oBACHA;;wBAEIA;qBACHA"}
@@ -53,21 +53,25 @@ declare const ToolCallLimitOptionsSchema: z.ZodObject<{
53
53
  runLimit: z.ZodOptional<z.ZodNumber>;
54
54
  /**
55
55
  * What to do when limits are exceeded.
56
- * - "end": Jump to the end of the agent execution and inject an artificial
57
- * AI message indicating that the limit was exceeded.
58
- * - "error": throws a ToolCallLimitExceededError
56
+ * - "continue": Block exceeded tools with error messages, let other tools continue (default)
57
+ * - "error": Raise a ToolCallLimitExceededError exception
58
+ * - "end": Stop execution immediately, injecting a ToolMessage and an AI message
59
+ * for the single tool call that exceeded the limit. Raises NotImplementedError
60
+ * if there are multiple tool calls.
61
+ *
62
+ * @default "continue"
59
63
  */
60
- exitBehavior: z.ZodDefault<z.ZodEnum<["end", "error"]>>;
64
+ exitBehavior: z.ZodDefault<z.ZodEnum<["continue", "error", "end"]>>;
61
65
  }, "strip", z.ZodTypeAny, {
62
66
  toolName?: string | undefined;
63
67
  threadLimit?: number | undefined;
64
68
  runLimit?: number | undefined;
65
- exitBehavior: "end" | "error";
69
+ exitBehavior: "continue" | "end" | "error";
66
70
  }, {
67
71
  toolName?: string | undefined;
68
72
  threadLimit?: number | undefined;
69
73
  runLimit?: number | undefined;
70
- exitBehavior?: "end" | "error" | undefined;
74
+ exitBehavior?: "continue" | "end" | "error" | undefined;
71
75
  }>;
72
76
  type ToolCallLimitConfig = InferInteropZodInput<typeof ToolCallLimitOptionsSchema>;
73
77
  /**
@@ -88,71 +92,78 @@ type ToolCallLimitConfig = InferInteropZodInput<typeof ToolCallLimitOptionsSchem
88
92
  * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.
89
93
  * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.
90
94
  * @param options.exitBehavior - What to do when limits are exceeded.
91
- * - "end": Jump to the end of the agent execution and inject an artificial AI message indicating that the limit was exceeded.
92
- * - "error": throws a ToolCallLimitExceededError
95
+ * - "continue": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)
96
+ * - "error": Raise a ToolCallLimitExceededError exception
97
+ * - "end": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.
93
98
  *
94
- * @throws {Error} If both limits are undefined or if exitBehavior is invalid.
99
+ * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.
100
+ * @throws {NotImplementedError} If exitBehavior is "end" and there are multiple tool calls.
95
101
  *
96
- * @example Limit all tool calls globally
102
+ * @example Continue execution with blocked tools (default)
97
103
  * ```ts
98
104
  * import { toolCallLimitMiddleware } from "@langchain/langchain/agents/middleware";
99
105
  * import { createAgent } from "@langchain/langchain/agents";
100
106
  *
101
- * const globalLimiter = toolCallLimitMiddleware({
107
+ * // Block exceeded tools but let other tools and model continue
108
+ * const limiter = toolCallLimitMiddleware({
102
109
  * threadLimit: 20,
103
110
  * runLimit: 10,
104
- * exitBehavior: "end"
111
+ * exitBehavior: "continue", // default
105
112
  * });
106
113
  *
107
114
  * const agent = createAgent({
108
115
  * model: "openai:gpt-4o",
109
- * middleware: [globalLimiter]
116
+ * middleware: [limiter]
110
117
  * });
111
118
  * ```
112
119
  *
113
- * @example Limit a specific tool
120
+ * @example Stop immediately when limit exceeded
114
121
  * ```ts
115
- * import { toolCallLimitMiddleware } from "@langchain/langchain/agents/middleware";
116
- * import { createAgent } from "@langchain/langchain/agents";
117
- *
118
- * const searchLimiter = toolCallLimitMiddleware({
119
- * toolName: "search",
120
- * threadLimit: 5,
121
- * runLimit: 3,
122
+ * // End execution immediately with an AI message
123
+ * const limiter = toolCallLimitMiddleware({
124
+ * runLimit: 5,
122
125
  * exitBehavior: "end"
123
126
  * });
124
127
  *
125
128
  * const agent = createAgent({
126
129
  * model: "openai:gpt-4o",
127
- * middleware: [searchLimiter]
130
+ * middleware: [limiter]
128
131
  * });
129
132
  * ```
130
133
  *
131
- * @example Use both in the same agent
134
+ * @example Raise exception on limit
132
135
  * ```ts
133
- * import { toolCallLimitMiddleware } from "@langchain/langchain/agents/middleware";
134
- * import { createAgent } from "@langchain/langchain/agents";
135
- *
136
- * const globalLimiter = toolCallLimitMiddleware({
137
- * threadLimit: 20,
138
- * runLimit: 10,
139
- * exitBehavior: "end"
140
- * });
141
- *
142
- * const searchLimiter = toolCallLimitMiddleware({
136
+ * // Strict limit with exception handling
137
+ * const limiter = toolCallLimitMiddleware({
143
138
  * toolName: "search",
144
139
  * threadLimit: 5,
145
- * runLimit: 3,
146
- * exitBehavior: "end"
140
+ * exitBehavior: "error"
147
141
  * });
148
142
  *
149
143
  * const agent = createAgent({
150
144
  * model: "openai:gpt-4o",
151
- * middleware: [globalLimiter, searchLimiter]
145
+ * middleware: [limiter]
152
146
  * });
147
+ *
148
+ * try {
149
+ * const result = await agent.invoke({ messages: [new HumanMessage("Task")] });
150
+ * } catch (error) {
151
+ * if (error instanceof ToolCallLimitExceededError) {
152
+ * console.log(`Search limit exceeded: ${error}`);
153
+ * }
154
+ * }
153
155
  * ```
154
156
  */
155
- declare function toolCallLimitMiddleware(options: ToolCallLimitConfig): AgentMiddleware<undefined, undefined, any>;
157
+ declare function toolCallLimitMiddleware(options: ToolCallLimitConfig): AgentMiddleware<z.ZodObject<{
158
+ threadToolCallCount: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
159
+ runToolCallCount: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
160
+ }, "strip", z.ZodTypeAny, {
161
+ threadToolCallCount: Record<string, number>;
162
+ runToolCallCount: Record<string, number>;
163
+ }, {
164
+ threadToolCallCount?: Record<string, number> | undefined;
165
+ runToolCallCount?: Record<string, number> | undefined;
166
+ }>, undefined, any>;
156
167
  //#endregion
157
168
  export { ToolCallLimitConfig, ToolCallLimitExceededError, toolCallLimitMiddleware };
158
169
  //# sourceMappingURL=toolCallLimit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"toolCallLimit.d.ts","names":["z","InferInteropZodInput","ToolCallLimitExceededError","Error","ToolCallLimitOptionsSchema","ZodString","ZodOptional","ZodNumber","ZodEnum","ZodDefault","ZodTypeAny","ZodObject","ToolCallLimitConfig","toolCallLimitMiddleware","__types_js10","AgentMiddleware"],"sources":["../../../src/agents/middleware/toolCallLimit.d.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport declare class ToolCallLimitExceededError extends Error {\n /**\n * Current thread tool call count.\n */\n threadCount: number;\n /**\n * Current run tool call count.\n */\n runCount: number;\n /**\n * Thread tool call limit (if set).\n */\n threadLimit: number | undefined;\n /**\n * Run tool call limit (if set).\n */\n runLimit: number | undefined;\n /**\n * Tool name being limited (if specific tool), or undefined for all tools.\n */\n toolName: string | undefined;\n constructor(threadCount: number, runCount: number, threadLimit: number | undefined, runLimit: number | undefined, toolName?: string | undefined);\n}\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport declare const ToolCallLimitOptionsSchema: z.ZodObject<{\n /**\n * Name of the specific tool to limit. If undefined, limits apply to all tools.\n */\n toolName: z.ZodOptional<z.ZodString>;\n /**\n * Maximum number of tool calls allowed per thread.\n * undefined means no limit.\n */\n threadLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * Maximum number of tool calls allowed per run.\n * undefined means no limit.\n */\n runLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * What to do when limits are exceeded.\n * - \"end\": Jump to the end of the agent execution and inject an artificial\n * AI message indicating that the limit was exceeded.\n * - \"error\": throws a ToolCallLimitExceededError\n */\n exitBehavior: z.ZodDefault<z.ZodEnum<[\"end\", \"error\"]>>;\n}, \"strip\", z.ZodTypeAny, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior: \"end\" | \"error\";\n}, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior?: \"end\" | \"error\" | undefined;\n}>;\nexport type ToolCallLimitConfig = InferInteropZodInput<typeof ToolCallLimitOptionsSchema>;\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n * - \"end\": Jump to the end of the agent execution and inject an artificial AI message indicating that the limit was exceeded.\n * - \"error\": throws a ToolCallLimitExceededError\n *\n * @throws {Error} If both limits are undefined or if exitBehavior is invalid.\n *\n * @example Limit all tool calls globally\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * const globalLimiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [globalLimiter]\n * });\n * ```\n *\n * @example Limit a specific tool\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * const searchLimiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * runLimit: 3,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [searchLimiter]\n * });\n * ```\n *\n * @example Use both in the same agent\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * const globalLimiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"end\"\n * });\n *\n * const searchLimiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * runLimit: 3,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [globalLimiter, searchLimiter]\n * });\n * ```\n */\nexport declare function toolCallLimitMiddleware(options: ToolCallLimitConfig): import(\"./types.js\").AgentMiddleware<undefined, undefined, any>;\n"],"mappings":";;;;;;;;;AAQA;AA0BA;;AAI4BA,cA9BPE,0BAAAA,SAAmCC,KAAK,CA8B/BE;EAAS;;;EAKT,WAKAE,EAAAA,MAAAA;EAAS;;;EAOT,QAChBG,EAAAA,MAAAA;EAAU;AAtBoC;AAiC5D;EAA+B,WAAA,EAAA,MAAA,GAAA,SAAA;EAAA;;AAAuB;EAmF9BG,QAAAA,EAAAA,MAAAA,GAAAA,SAAuB;EAAA;;;EAAoE,QAAA,EAAA,MAAA,GAAA,SAAA;;;;;;cApH9FT,4BAA4BJ,CAAAA,CAAEW;;;;YAIrCX,CAAAA,CAAEM,YAAYN,CAAAA,CAAEK;;;;;eAKbL,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;YAKnBP,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;;;gBAOZP,CAAAA,CAAES,WAAWT,CAAAA,CAAEQ;YACrBR,CAAAA,CAAEU;;;;;;;;;;;KAWFE,mBAAAA,GAAsBX,4BAA4BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmFtCS,uBAAAA,UAAiCD,sBAAmB"}
1
+ {"version":3,"file":"toolCallLimit.d.ts","names":["z","InferInteropZodInput","ToolCallLimitExceededError","Error","ToolCallLimitOptionsSchema","ZodString","ZodOptional","ZodNumber","ZodEnum","ZodDefault","ZodTypeAny","ZodObject","ToolCallLimitConfig","toolCallLimitMiddleware","ZodRecord","Record","__types_js4","AgentMiddleware"],"sources":["../../../src/agents/middleware/toolCallLimit.d.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport declare class ToolCallLimitExceededError extends Error {\n /**\n * Current thread tool call count.\n */\n threadCount: number;\n /**\n * Current run tool call count.\n */\n runCount: number;\n /**\n * Thread tool call limit (if set).\n */\n threadLimit: number | undefined;\n /**\n * Run tool call limit (if set).\n */\n runLimit: number | undefined;\n /**\n * Tool name being limited (if specific tool), or undefined for all tools.\n */\n toolName: string | undefined;\n constructor(threadCount: number, runCount: number, threadLimit: number | undefined, runLimit: number | undefined, toolName?: string | undefined);\n}\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport declare const ToolCallLimitOptionsSchema: z.ZodObject<{\n /**\n * Name of the specific tool to limit. If undefined, limits apply to all tools.\n */\n toolName: z.ZodOptional<z.ZodString>;\n /**\n * Maximum number of tool calls allowed per thread.\n * undefined means no limit.\n */\n threadLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * Maximum number of tool calls allowed per run.\n * undefined means no limit.\n */\n runLimit: z.ZodOptional<z.ZodNumber>;\n /**\n * What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately, injecting a ToolMessage and an AI message\n * for the single tool call that exceeded the limit. Raises NotImplementedError\n * if there are multiple tool calls.\n *\n * @default \"continue\"\n */\n exitBehavior: z.ZodDefault<z.ZodEnum<[\"continue\", \"error\", \"end\"]>>;\n}, \"strip\", z.ZodTypeAny, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior: \"continue\" | \"end\" | \"error\";\n}, {\n toolName?: string | undefined;\n threadLimit?: number | undefined;\n runLimit?: number | undefined;\n exitBehavior?: \"continue\" | \"end\" | \"error\" | undefined;\n}>;\nexport type ToolCallLimitConfig = InferInteropZodInput<typeof ToolCallLimitOptionsSchema>;\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.\n *\n * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.\n * @throws {NotImplementedError} If exitBehavior is \"end\" and there are multiple tool calls.\n *\n * @example Continue execution with blocked tools (default)\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * // Block exceeded tools but let other tools and model continue\n * const limiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"continue\", // default\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Stop immediately when limit exceeded\n * ```ts\n * // End execution immediately with an AI message\n * const limiter = toolCallLimitMiddleware({\n * runLimit: 5,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Raise exception on limit\n * ```ts\n * // Strict limit with exception handling\n * const limiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * exitBehavior: \"error\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n *\n * try {\n * const result = await agent.invoke({ messages: [new HumanMessage(\"Task\")] });\n * } catch (error) {\n * if (error instanceof ToolCallLimitExceededError) {\n * console.log(`Search limit exceeded: ${error}`);\n * }\n * }\n * ```\n */\nexport declare function toolCallLimitMiddleware(options: ToolCallLimitConfig): import(\"./types.js\").AgentMiddleware<z.ZodObject<{\n threadToolCallCount: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;\n runToolCallCount: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;\n}, \"strip\", z.ZodTypeAny, {\n threadToolCallCount: Record<string, number>;\n runToolCallCount: Record<string, number>;\n}, {\n threadToolCallCount?: Record<string, number> | undefined;\n runToolCallCount?: Record<string, number> | undefined;\n}>, undefined, any>;\n"],"mappings":";;;;;;;;;AAQA;AA0BA;;AAI4BA,cA9BPE,0BAAAA,SAAmCC,KAAK,CA8B/BE;EAAS;;;EAKT,WAKAE,EAAAA,MAAAA;EAAS;;;EAWT,QAChBG,EAAAA,MAAAA;EAAU;AA1BoC;AAqC5D;EAA+B,WAAA,EAAA,MAAA,GAAA,SAAA;EAAA;;AAAuB;EAiF9BG,QAAAA,EAAAA,MAAAA,GAAAA,SAAuB;EAAA;;;EACc,QAAIN,EAAAA,MAAAA,GAAAA,SAAAA;EAAS,WAAlCO,CAAAA,WAAAA,EAAAA,MAAAA,EAAAA,QAAAA,EAAAA,MAAAA,EAAAA,WAAAA,EAAAA,MAAAA,GAAAA,SAAAA,EAAAA,QAAAA,EAAAA,MAAAA,GAAAA,SAAAA,EAAAA,QAAAA,CAAAA,EAAAA,MAAAA,GAAAA,SAAAA;;;;;AAClBd,cAxHDI,0BAwHGK,EAxHyBT,CAAAA,CAAEW,SAwH3BF,CAAAA;EAAU;;;EAGN,QAEFM,EAzHZf,CAAAA,CAAEM,WAyHUS,CAzHEf,CAAAA,CAAEK,SAyHJU,CAAAA;EAAM;;;AAPmF;eA7GlGf,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;YAKnBP,CAAAA,CAAEM,YAAYN,CAAAA,CAAEO;;;;;;;;;;;gBAWZP,CAAAA,CAAES,WAAWT,CAAAA,CAAEQ;YACrBR,CAAAA,CAAEU;;;;;;;;;;;KAWFE,mBAAAA,GAAsBX,4BAA4BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiFtCS,uBAAAA,UAAiCD,sBAAsE,gBAAXZ,CAAAA,CAAEW;uBAC7FX,CAAAA,CAAES,WAAWT,CAAAA,CAAEc,UAAUd,CAAAA,CAAEK,WAAWL,CAAAA,CAAEO;oBAC3CP,CAAAA,CAAES,WAAWT,CAAAA,CAAEc,UAAUd,CAAAA,CAAEK,WAAWL,CAAAA,CAAEO;YAClDP,CAAAA,CAAEU;uBACWK;oBACHA;;wBAEIA;qBACHA"}
@@ -1,64 +1,54 @@
1
1
  import { createMiddleware } from "../middleware.js";
2
- import { AIMessage, HumanMessage } from "@langchain/core/messages";
2
+ import { AIMessage, ToolMessage } from "@langchain/core/messages";
3
3
  import { z } from "zod/v3";
4
+ import { z as z$1 } from "zod/v4";
4
5
 
5
6
  //#region src/agents/middleware/toolCallLimit.ts
6
7
  /**
7
- * Count tool calls in a list of messages.
8
+ * Build the error message content for ToolMessage when limit is exceeded.
8
9
  *
9
- * @param messages - List of messages to count tool calls in.
10
- * @param toolName - If specified, only count calls to this specific tool.
11
- * If undefined, count all tool calls.
12
- * @returns The total number of tool calls (optionally filtered by toolName).
13
- */
14
- function countToolCallsInMessages(messages, toolName) {
15
- let count = 0;
16
- for (const message of messages) if (AIMessage.isInstance(message) && message.tool_calls) if (toolName === void 0) count += message.tool_calls.length;
17
- else count += message.tool_calls.filter((tc) => tc.name === toolName).length;
18
- return count;
19
- }
20
- /**
21
- * Get messages from the current run (after the last HumanMessage).
10
+ * This message is sent to the model, so it should not reference thread/run concepts
11
+ * that the model has no notion of.
22
12
  *
23
- * @param messages - Full list of messages.
24
- * @returns Messages from the current run (after last HumanMessage).
13
+ * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.
14
+ * @returns A concise message instructing the model not to call the tool again.
25
15
  */
26
- function getRunMessages(messages) {
27
- /**
28
- * Find the last HumanMessage
29
- */
30
- let lastHumanIndex = -1;
31
- for (let i = messages.length - 1; i >= 0; i--) if (HumanMessage.isInstance(messages[i])) {
32
- lastHumanIndex = i;
33
- break;
34
- }
35
- /**
36
- * If no HumanMessage found, return all messages
37
- */
38
- if (lastHumanIndex === -1) return messages;
39
- /**
40
- * Return messages after the last HumanMessage
41
- */
42
- return messages.slice(lastHumanIndex + 1);
16
+ function buildToolMessageContent(toolName) {
17
+ if (toolName) return `Tool call limit exceeded. Do not call '${toolName}' again.`;
18
+ return "Tool call limit exceeded. Do not make additional tool calls.";
43
19
  }
20
+ const VALID_EXIT_BEHAVIORS = [
21
+ "continue",
22
+ "error",
23
+ "end"
24
+ ];
25
+ const DEFAULT_EXIT_BEHAVIOR = "continue";
44
26
  /**
45
- * Build a message indicating which tool call limits were reached.
27
+ * Build the final AI message content for 'end' behavior.
28
+ *
29
+ * This message is displayed to the user, so it should include detailed information
30
+ * about which limits were exceeded.
46
31
  *
47
32
  * @param threadCount - Current thread tool call count.
48
33
  * @param runCount - Current run tool call count.
49
34
  * @param threadLimit - Thread tool call limit (if set).
50
35
  * @param runLimit - Run tool call limit (if set).
51
36
  * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.
52
- * @returns A formatted message describing which limits were reached.
37
+ * @returns A formatted message describing which limits were exceeded.
53
38
  */
54
- function buildToolLimitExceededMessage(threadCount, runCount, threadLimit, runLimit, toolName) {
55
- const toolDesc = toolName ? `'${toolName}' tool call` : "Tool call";
39
+ function buildFinalAIMessageContent(threadCount, runCount, threadLimit, runLimit, toolName) {
40
+ const toolDesc = toolName ? `'${toolName}' tool` : "Tool";
56
41
  const exceededLimits = [];
57
- if (threadLimit !== void 0 && threadCount >= threadLimit) exceededLimits.push(`thread limit reached (${threadCount}/${threadLimit})`);
58
- if (runLimit !== void 0 && runCount >= runLimit) exceededLimits.push(`run limit reached (${runCount}/${runLimit})`);
59
- return `${toolDesc} limit${exceededLimits.length > 1 ? "s" : ""}: ${exceededLimits.join(", ")}. Stopping to prevent further tool calls.`;
42
+ if (threadLimit !== void 0 && threadCount > threadLimit) exceededLimits.push(`thread limit exceeded (${threadCount}/${threadLimit} calls)`);
43
+ if (runLimit !== void 0 && runCount > runLimit) exceededLimits.push(`run limit exceeded (${runCount}/${runLimit} calls)`);
44
+ const limitsText = exceededLimits.join(" and ");
45
+ return `${toolDesc} call limit reached: ${limitsText}.`;
60
46
  }
61
47
  /**
48
+ * Schema for the exit behavior.
49
+ */
50
+ const exitBehaviorSchema = z.enum(VALID_EXIT_BEHAVIORS).default(DEFAULT_EXIT_BEHAVIOR);
51
+ /**
62
52
  * Exception raised when tool call limits are exceeded.
63
53
  *
64
54
  * This exception is raised when the configured exit behavior is 'error'
@@ -86,7 +76,7 @@ var ToolCallLimitExceededError = class extends Error {
86
76
  */
87
77
  toolName;
88
78
  constructor(threadCount, runCount, threadLimit, runLimit, toolName = void 0) {
89
- const message = buildToolLimitExceededMessage(threadCount, runCount, threadLimit, runLimit, toolName);
79
+ const message = buildFinalAIMessageContent(threadCount, runCount, threadLimit, runLimit, toolName);
90
80
  super(message);
91
81
  this.name = "ToolCallLimitExceededError";
92
82
  this.threadCount = threadCount;
@@ -103,9 +93,17 @@ const ToolCallLimitOptionsSchema = z.object({
103
93
  toolName: z.string().optional(),
104
94
  threadLimit: z.number().optional(),
105
95
  runLimit: z.number().optional(),
106
- exitBehavior: z.enum(["end", "error"]).default("end")
96
+ exitBehavior: exitBehaviorSchema
107
97
  });
108
98
  /**
99
+ * Middleware state schema to track the number of model calls made at the thread and run level.
100
+ */
101
+ const stateSchema = z.object({
102
+ threadToolCallCount: z.record(z.string(), z.number()).default({}),
103
+ runToolCallCount: z.record(z.string(), z.number()).default({})
104
+ });
105
+ const DEFAULT_TOOL_COUNT_KEY = "__all__";
106
+ /**
109
107
  * Middleware that tracks tool call counts and enforces limits.
110
108
  *
111
109
  * This middleware monitors the number of tool calls made during agent execution
@@ -123,68 +121,66 @@ const ToolCallLimitOptionsSchema = z.object({
123
121
  * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.
124
122
  * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.
125
123
  * @param options.exitBehavior - What to do when limits are exceeded.
126
- * - "end": Jump to the end of the agent execution and inject an artificial AI message indicating that the limit was exceeded.
127
- * - "error": throws a ToolCallLimitExceededError
124
+ * - "continue": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)
125
+ * - "error": Raise a ToolCallLimitExceededError exception
126
+ * - "end": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.
128
127
  *
129
- * @throws {Error} If both limits are undefined or if exitBehavior is invalid.
128
+ * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.
129
+ * @throws {NotImplementedError} If exitBehavior is "end" and there are multiple tool calls.
130
130
  *
131
- * @example Limit all tool calls globally
131
+ * @example Continue execution with blocked tools (default)
132
132
  * ```ts
133
133
  * import { toolCallLimitMiddleware } from "@langchain/langchain/agents/middleware";
134
134
  * import { createAgent } from "@langchain/langchain/agents";
135
135
  *
136
- * const globalLimiter = toolCallLimitMiddleware({
136
+ * // Block exceeded tools but let other tools and model continue
137
+ * const limiter = toolCallLimitMiddleware({
137
138
  * threadLimit: 20,
138
139
  * runLimit: 10,
139
- * exitBehavior: "end"
140
+ * exitBehavior: "continue", // default
140
141
  * });
141
142
  *
142
143
  * const agent = createAgent({
143
144
  * model: "openai:gpt-4o",
144
- * middleware: [globalLimiter]
145
+ * middleware: [limiter]
145
146
  * });
146
147
  * ```
147
148
  *
148
- * @example Limit a specific tool
149
+ * @example Stop immediately when limit exceeded
149
150
  * ```ts
150
- * import { toolCallLimitMiddleware } from "@langchain/langchain/agents/middleware";
151
- * import { createAgent } from "@langchain/langchain/agents";
152
- *
153
- * const searchLimiter = toolCallLimitMiddleware({
154
- * toolName: "search",
155
- * threadLimit: 5,
156
- * runLimit: 3,
151
+ * // End execution immediately with an AI message
152
+ * const limiter = toolCallLimitMiddleware({
153
+ * runLimit: 5,
157
154
  * exitBehavior: "end"
158
155
  * });
159
156
  *
160
157
  * const agent = createAgent({
161
158
  * model: "openai:gpt-4o",
162
- * middleware: [searchLimiter]
159
+ * middleware: [limiter]
163
160
  * });
164
161
  * ```
165
162
  *
166
- * @example Use both in the same agent
163
+ * @example Raise exception on limit
167
164
  * ```ts
168
- * import { toolCallLimitMiddleware } from "@langchain/langchain/agents/middleware";
169
- * import { createAgent } from "@langchain/langchain/agents";
170
- *
171
- * const globalLimiter = toolCallLimitMiddleware({
172
- * threadLimit: 20,
173
- * runLimit: 10,
174
- * exitBehavior: "end"
175
- * });
176
- *
177
- * const searchLimiter = toolCallLimitMiddleware({
165
+ * // Strict limit with exception handling
166
+ * const limiter = toolCallLimitMiddleware({
178
167
  * toolName: "search",
179
168
  * threadLimit: 5,
180
- * runLimit: 3,
181
- * exitBehavior: "end"
169
+ * exitBehavior: "error"
182
170
  * });
183
171
  *
184
172
  * const agent = createAgent({
185
173
  * model: "openai:gpt-4o",
186
- * middleware: [globalLimiter, searchLimiter]
174
+ * middleware: [limiter]
187
175
  * });
176
+ *
177
+ * try {
178
+ * const result = await agent.invoke({ messages: [new HumanMessage("Task")] });
179
+ * } catch (error) {
180
+ * if (error instanceof ToolCallLimitExceededError) {
181
+ * console.log(`Search limit exceeded: ${error}`);
182
+ * }
183
+ * }
188
184
  * ```
189
185
  */
190
186
  function toolCallLimitMiddleware(options) {
@@ -193,47 +189,173 @@ function toolCallLimitMiddleware(options) {
193
189
  */
194
190
  if (options.threadLimit === void 0 && options.runLimit === void 0) throw new Error("At least one limit must be specified (threadLimit or runLimit)");
195
191
  /**
196
- * Apply default for exitBehavior and validate
192
+ * Validate exitBehavior (Zod schema already validates, but provide helpful error)
193
+ */
194
+ const exitBehavior = options.exitBehavior ?? DEFAULT_EXIT_BEHAVIOR;
195
+ const parseResult = exitBehaviorSchema.safeParse(exitBehavior);
196
+ if (!parseResult.success) throw new Error(z$1.prettifyError(parseResult.error).slice(2));
197
+ /**
198
+ * Validate that runLimit does not exceed threadLimit
197
199
  */
198
- const exitBehavior = options.exitBehavior ?? "end";
199
- if (exitBehavior !== "end" && exitBehavior !== "error") throw new Error(`Invalid exit behavior: ${exitBehavior}. Must be 'end' or 'error'`);
200
+ if (options.threadLimit !== void 0 && options.runLimit !== void 0 && options.runLimit > options.threadLimit) throw new Error(`runLimit (${options.runLimit}) cannot exceed threadLimit (${options.threadLimit}). The run limit should be less than or equal to the thread limit.`);
200
201
  /**
201
202
  * Generate the middleware name based on the tool name
202
203
  */
203
204
  const middlewareName = options.toolName ? `ToolCallLimitMiddleware[${options.toolName}]` : "ToolCallLimitMiddleware";
204
205
  return createMiddleware({
205
206
  name: middlewareName,
206
- beforeModel: {
207
+ stateSchema,
208
+ afterModel: {
207
209
  canJumpTo: ["end"],
208
210
  hook: (state) => {
209
- const messages = state.messages;
210
211
  /**
211
- * Count tool calls in entire thread
212
+ * Get the last AI message to check for tool calls
213
+ */
214
+ const lastAIMessage = [...state.messages].reverse().find(AIMessage.isInstance);
215
+ if (!lastAIMessage || !lastAIMessage.tool_calls) return void 0;
216
+ /**
217
+ * Helper to check if limit would be exceeded by one more call
218
+ */
219
+ const wouldExceedLimit = (threadCount, runCount) => {
220
+ return options.threadLimit !== void 0 && threadCount + 1 > options.threadLimit || options.runLimit !== void 0 && runCount + 1 > options.runLimit;
221
+ };
222
+ /**
223
+ * Helper to check if a tool call matches our filter
224
+ */
225
+ const matchesToolFilter = (toolCall) => {
226
+ return options.toolName === void 0 || toolCall.name === options.toolName;
227
+ };
228
+ /**
229
+ * Separate tool calls into allowed and blocked based on limits
230
+ */
231
+ const separateToolCalls = (toolCalls, threadCount, runCount) => {
232
+ const allowed$1 = [];
233
+ const blocked$1 = [];
234
+ let tempThreadCount = threadCount;
235
+ let tempRunCount = runCount;
236
+ for (const toolCall of toolCalls) {
237
+ if (!matchesToolFilter(toolCall)) continue;
238
+ if (wouldExceedLimit(tempThreadCount, tempRunCount)) blocked$1.push(toolCall);
239
+ else {
240
+ allowed$1.push(toolCall);
241
+ tempThreadCount += 1;
242
+ tempRunCount += 1;
243
+ }
244
+ }
245
+ return {
246
+ allowed: allowed$1,
247
+ blocked: blocked$1,
248
+ finalThreadCount: tempThreadCount,
249
+ finalRunCount: tempRunCount + blocked$1.length
250
+ };
251
+ };
252
+ /**
253
+ * Get the count key for this middleware instance
254
+ */
255
+ const countKey = options.toolName ?? DEFAULT_TOOL_COUNT_KEY;
256
+ /**
257
+ * Get current counts
258
+ */
259
+ const threadCounts = { ...state.threadToolCallCount ?? {} };
260
+ const runCounts = { ...state.runToolCallCount ?? {} };
261
+ const currentThreadCount = threadCounts[countKey] ?? 0;
262
+ const currentRunCount = runCounts[countKey] ?? 0;
263
+ /**
264
+ * Separate tool calls into allowed and blocked
265
+ */
266
+ const { allowed, blocked, finalThreadCount, finalRunCount } = separateToolCalls(lastAIMessage.tool_calls, currentThreadCount, currentRunCount);
267
+ /**
268
+ * Update counts:
269
+ * - Thread count includes only allowed calls (blocked calls don't count towards thread-level tracking)
270
+ * - Run count includes blocked calls since they were attempted in this run
271
+ */
272
+ threadCounts[countKey] = finalThreadCount;
273
+ runCounts[countKey] = finalRunCount;
274
+ /**
275
+ * If no tool calls are blocked, just update counts
276
+ */
277
+ if (blocked.length === 0) {
278
+ if (allowed.length > 0) return {
279
+ threadToolCallCount: threadCounts,
280
+ runToolCallCount: runCounts
281
+ };
282
+ return void 0;
283
+ }
284
+ /**
285
+ * Handle different exit behaviors
212
286
  */
213
- const threadCount = countToolCallsInMessages(messages, options.toolName);
287
+ if (exitBehavior === "error") {
288
+ const hypotheticalThreadCount = finalThreadCount + blocked.length;
289
+ throw new ToolCallLimitExceededError(hypotheticalThreadCount, finalRunCount, options.threadLimit, options.runLimit, options.toolName);
290
+ }
214
291
  /**
215
- * Count tool calls in current run (after last HumanMessage)
292
+ * Build tool message content (sent to model - no thread/run details)
216
293
  */
217
- const runMessages = getRunMessages(messages);
218
- const runCount = countToolCallsInMessages(runMessages, options.toolName);
294
+ const toolMsgContent = buildToolMessageContent(options.toolName);
219
295
  /**
220
- * Check if any limits are exceeded
296
+ * Inject artificial error ToolMessages for blocked tool calls
221
297
  */
222
- const threadLimitExceeded = options.threadLimit !== void 0 && threadCount >= options.threadLimit;
223
- const runLimitExceeded = options.runLimit !== void 0 && runCount >= options.runLimit;
224
- if (!threadLimitExceeded && !runLimitExceeded) return void 0;
225
- if (exitBehavior === "error") throw new ToolCallLimitExceededError(threadCount, runCount, options.threadLimit, options.runLimit, options.toolName);
298
+ const artificialMessages = blocked.map((toolCall) => new ToolMessage({
299
+ content: toolMsgContent,
300
+ tool_call_id: toolCall.id,
301
+ name: toolCall.name,
302
+ status: "error"
303
+ }));
304
+ if (exitBehavior === "end") {
305
+ /**
306
+ * Check if there are tool calls to other tools that would continue executing
307
+ * For tool-specific limiters: check for calls to other tools
308
+ * For global limiters: check if there are multiple different tool types
309
+ */
310
+ let otherTools = [];
311
+ if (options.toolName !== void 0)
312
+ /**
313
+ * Tool-specific limiter: check for calls to other tools
314
+ */
315
+ otherTools = lastAIMessage.tool_calls.filter((tc) => tc.name !== options.toolName);
316
+ else {
317
+ /**
318
+ * Global limiter: check if there are multiple different tool types
319
+ * If there are allowed calls, those would execute
320
+ * But even if all are blocked, we can't handle multiple tool types with "end"
321
+ */
322
+ const uniqueToolNames = new Set(lastAIMessage.tool_calls.map((tc) => tc.name).filter(Boolean));
323
+ if (uniqueToolNames.size > 1)
324
+ /**
325
+ * Multiple different tool types - use allowed calls to show which ones
326
+ */
327
+ otherTools = allowed.length > 0 ? allowed : lastAIMessage.tool_calls;
328
+ }
329
+ if (otherTools.length > 0) {
330
+ const toolNames = Array.from(new Set(otherTools.map((tc) => tc.name).filter(Boolean))).join(", ");
331
+ throw new Error(`Cannot end execution with other tool calls pending. Found calls to: ${toolNames}. Use 'continue' or 'error' behavior instead.`);
332
+ }
333
+ /**
334
+ * Build final AI message content (displayed to user - includes thread/run details)
335
+ * Use hypothetical thread count (what it would have been if call wasn't blocked)
336
+ * to show which limit was actually exceeded
337
+ */
338
+ const hypotheticalThreadCount = finalThreadCount + blocked.length;
339
+ const finalMsgContent = buildFinalAIMessageContent(hypotheticalThreadCount, finalRunCount, options.threadLimit, options.runLimit, options.toolName);
340
+ artificialMessages.push(new AIMessage(finalMsgContent));
341
+ return {
342
+ threadToolCallCount: threadCounts,
343
+ runToolCallCount: runCounts,
344
+ jumpTo: "end",
345
+ messages: artificialMessages
346
+ };
347
+ }
226
348
  /**
227
- * Create a message indicating the limit was exceeded
349
+ * For exit_behavior="continue", return error messages to block exceeded tools
228
350
  */
229
- const limitMessage = buildToolLimitExceededMessage(threadCount, runCount, options.threadLimit, options.runLimit, options.toolName);
230
- const limitAiMessage = new AIMessage(limitMessage);
231
351
  return {
232
- jumpTo: "end",
233
- messages: [limitAiMessage]
352
+ threadToolCallCount: threadCounts,
353
+ runToolCallCount: runCounts,
354
+ messages: artificialMessages
234
355
  };
235
356
  }
236
- }
357
+ },
358
+ afterAgent: () => ({ runToolCallCount: {} })
237
359
  });
238
360
  }
239
361