langchain 1.4.5-dev-1781048185730 → 1.4.6-dev-1781485641139

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 (166) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/agents/ReactAgent.cjs +5 -2
  3. package/dist/agents/ReactAgent.cjs.map +1 -1
  4. package/dist/agents/ReactAgent.d.cts +1 -1
  5. package/dist/agents/ReactAgent.d.cts.map +1 -1
  6. package/dist/agents/ReactAgent.d.ts +1 -1
  7. package/dist/agents/ReactAgent.d.ts.map +1 -1
  8. package/dist/agents/ReactAgent.js +4 -1
  9. package/dist/agents/ReactAgent.js.map +1 -1
  10. package/dist/agents/index.cjs +3 -1
  11. package/dist/agents/index.cjs.map +1 -1
  12. package/dist/agents/index.d.cts +3 -1
  13. package/dist/agents/index.d.cts.map +1 -1
  14. package/dist/agents/index.d.ts +3 -1
  15. package/dist/agents/index.d.ts.map +1 -1
  16. package/dist/agents/index.js +3 -1
  17. package/dist/agents/index.js.map +1 -1
  18. package/dist/agents/middleware/constants.cjs +25 -0
  19. package/dist/agents/middleware/constants.cjs.map +1 -1
  20. package/dist/agents/middleware/constants.js +25 -0
  21. package/dist/agents/middleware/constants.js.map +1 -1
  22. package/dist/agents/middleware/contextEditing.cjs.map +1 -1
  23. package/dist/agents/middleware/contextEditing.d.cts.map +1 -1
  24. package/dist/agents/middleware/contextEditing.d.ts.map +1 -1
  25. package/dist/agents/middleware/contextEditing.js.map +1 -1
  26. package/dist/agents/middleware/hitl.cjs +68 -29
  27. package/dist/agents/middleware/hitl.cjs.map +1 -1
  28. package/dist/agents/middleware/hitl.d.cts +2 -105
  29. package/dist/agents/middleware/hitl.d.cts.map +1 -1
  30. package/dist/agents/middleware/hitl.d.ts +2 -105
  31. package/dist/agents/middleware/hitl.d.ts.map +1 -1
  32. package/dist/agents/middleware/hitl.js +68 -29
  33. package/dist/agents/middleware/hitl.js.map +1 -1
  34. package/dist/agents/middleware/index.cjs +1 -0
  35. package/dist/agents/middleware/index.d.cts +2 -1
  36. package/dist/agents/middleware/index.d.ts +2 -1
  37. package/dist/agents/middleware/index.js +1 -0
  38. package/dist/agents/middleware/llmToolSelector.cjs +14 -0
  39. package/dist/agents/middleware/llmToolSelector.cjs.map +1 -1
  40. package/dist/agents/middleware/llmToolSelector.js +14 -0
  41. package/dist/agents/middleware/llmToolSelector.js.map +1 -1
  42. package/dist/agents/middleware/modelCallLimit.cjs +12 -0
  43. package/dist/agents/middleware/modelCallLimit.cjs.map +1 -1
  44. package/dist/agents/middleware/modelCallLimit.js +12 -0
  45. package/dist/agents/middleware/modelCallLimit.js.map +1 -1
  46. package/dist/agents/middleware/modelRetry.cjs +10 -1
  47. package/dist/agents/middleware/modelRetry.cjs.map +1 -1
  48. package/dist/agents/middleware/modelRetry.js +10 -1
  49. package/dist/agents/middleware/modelRetry.js.map +1 -1
  50. package/dist/agents/middleware/pii.cjs +9 -0
  51. package/dist/agents/middleware/pii.cjs.map +1 -1
  52. package/dist/agents/middleware/pii.js +9 -0
  53. package/dist/agents/middleware/pii.js.map +1 -1
  54. package/dist/agents/middleware/piiRedaction.cjs +6 -1
  55. package/dist/agents/middleware/piiRedaction.cjs.map +1 -1
  56. package/dist/agents/middleware/piiRedaction.js +6 -1
  57. package/dist/agents/middleware/piiRedaction.js.map +1 -1
  58. package/dist/agents/middleware/provider/anthropic/promptCaching.cjs +19 -0
  59. package/dist/agents/middleware/provider/anthropic/promptCaching.cjs.map +1 -1
  60. package/dist/agents/middleware/provider/anthropic/promptCaching.js +19 -0
  61. package/dist/agents/middleware/provider/anthropic/promptCaching.js.map +1 -1
  62. package/dist/agents/middleware/provider/openai/moderation.cjs.map +1 -1
  63. package/dist/agents/middleware/provider/openai/moderation.js.map +1 -1
  64. package/dist/agents/middleware/providerToolSearch.cjs +130 -0
  65. package/dist/agents/middleware/providerToolSearch.cjs.map +1 -0
  66. package/dist/agents/middleware/providerToolSearch.d.cts +75 -0
  67. package/dist/agents/middleware/providerToolSearch.d.cts.map +1 -0
  68. package/dist/agents/middleware/providerToolSearch.d.ts +75 -0
  69. package/dist/agents/middleware/providerToolSearch.d.ts.map +1 -0
  70. package/dist/agents/middleware/providerToolSearch.js +129 -0
  71. package/dist/agents/middleware/providerToolSearch.js.map +1 -0
  72. package/dist/agents/middleware/summarization.cjs +62 -1
  73. package/dist/agents/middleware/summarization.cjs.map +1 -1
  74. package/dist/agents/middleware/summarization.js +62 -1
  75. package/dist/agents/middleware/summarization.js.map +1 -1
  76. package/dist/agents/middleware/todoListMiddleware.cjs.map +1 -1
  77. package/dist/agents/middleware/todoListMiddleware.js.map +1 -1
  78. package/dist/agents/middleware/toolCallLimit.cjs +24 -0
  79. package/dist/agents/middleware/toolCallLimit.cjs.map +1 -1
  80. package/dist/agents/middleware/toolCallLimit.js +24 -0
  81. package/dist/agents/middleware/toolCallLimit.js.map +1 -1
  82. package/dist/agents/middleware/toolEmulator.cjs.map +1 -1
  83. package/dist/agents/middleware/toolEmulator.js.map +1 -1
  84. package/dist/agents/middleware/toolRetry.cjs +17 -0
  85. package/dist/agents/middleware/toolRetry.cjs.map +1 -1
  86. package/dist/agents/middleware/toolRetry.js +17 -0
  87. package/dist/agents/middleware/toolRetry.js.map +1 -1
  88. package/dist/agents/middleware.cjs.map +1 -1
  89. package/dist/agents/middleware.js.map +1 -1
  90. package/dist/agents/nodes/AfterAgentNode.cjs.map +1 -1
  91. package/dist/agents/nodes/AfterAgentNode.js.map +1 -1
  92. package/dist/agents/nodes/AfterModelNode.cjs.map +1 -1
  93. package/dist/agents/nodes/AfterModelNode.js.map +1 -1
  94. package/dist/agents/nodes/AgentNode.cjs +17 -0
  95. package/dist/agents/nodes/AgentNode.cjs.map +1 -1
  96. package/dist/agents/nodes/AgentNode.js +17 -0
  97. package/dist/agents/nodes/AgentNode.js.map +1 -1
  98. package/dist/agents/nodes/BeforeAgentNode.cjs.map +1 -1
  99. package/dist/agents/nodes/BeforeAgentNode.js.map +1 -1
  100. package/dist/agents/nodes/BeforeModelNode.cjs.map +1 -1
  101. package/dist/agents/nodes/BeforeModelNode.js.map +1 -1
  102. package/dist/agents/nodes/ToolNode.cjs +3 -0
  103. package/dist/agents/nodes/ToolNode.cjs.map +1 -1
  104. package/dist/agents/nodes/ToolNode.js +3 -0
  105. package/dist/agents/nodes/ToolNode.js.map +1 -1
  106. package/dist/agents/nodes/middleware.cjs +3 -0
  107. package/dist/agents/nodes/middleware.cjs.map +1 -1
  108. package/dist/agents/nodes/middleware.js +3 -0
  109. package/dist/agents/nodes/middleware.js.map +1 -1
  110. package/dist/agents/nodes/utils.cjs.map +1 -1
  111. package/dist/agents/nodes/utils.js.map +1 -1
  112. package/dist/agents/responses.cjs.map +1 -1
  113. package/dist/agents/responses.js.map +1 -1
  114. package/dist/agents/tests/utils.cjs.map +1 -1
  115. package/dist/agents/tests/utils.js.map +1 -1
  116. package/dist/agents/transformers/index.cjs +2 -0
  117. package/dist/agents/transformers/index.d.cts +3 -0
  118. package/dist/agents/transformers/index.d.ts +3 -0
  119. package/dist/agents/transformers/index.js +3 -0
  120. package/dist/agents/transformers/subagent.cjs +205 -0
  121. package/dist/agents/transformers/subagent.cjs.map +1 -0
  122. package/dist/agents/transformers/subagent.d.cts +34 -0
  123. package/dist/agents/transformers/subagent.d.cts.map +1 -0
  124. package/dist/agents/transformers/subagent.d.ts +34 -0
  125. package/dist/agents/transformers/subagent.d.ts.map +1 -0
  126. package/dist/agents/transformers/subagent.js +204 -0
  127. package/dist/agents/transformers/subagent.js.map +1 -0
  128. package/dist/agents/{stream.cjs → transformers/tool-call.cjs} +3 -15
  129. package/dist/agents/transformers/tool-call.cjs.map +1 -0
  130. package/dist/agents/transformers/tool-call.d.cts +17 -0
  131. package/dist/agents/transformers/tool-call.d.cts.map +1 -0
  132. package/dist/agents/transformers/tool-call.d.ts +17 -0
  133. package/dist/agents/transformers/tool-call.d.ts.map +1 -0
  134. package/dist/agents/{stream.js → transformers/tool-call.js} +2 -14
  135. package/dist/agents/transformers/tool-call.js.map +1 -0
  136. package/dist/agents/{stream.d.cts → transformers/types.d.cts} +50 -20
  137. package/dist/agents/transformers/types.d.cts.map +1 -0
  138. package/dist/agents/{stream.d.ts → transformers/types.d.ts} +50 -20
  139. package/dist/agents/transformers/types.d.ts.map +1 -0
  140. package/dist/agents/utils.cjs +3 -0
  141. package/dist/agents/utils.cjs.map +1 -1
  142. package/dist/agents/utils.js +3 -0
  143. package/dist/agents/utils.js.map +1 -1
  144. package/dist/browser.cjs +9 -3
  145. package/dist/browser.d.cts +6 -3
  146. package/dist/browser.d.ts +6 -3
  147. package/dist/browser.js +6 -2
  148. package/dist/chat_models/universal.cjs.map +1 -1
  149. package/dist/chat_models/universal.js.map +1 -1
  150. package/dist/hub/index.cjs.map +1 -1
  151. package/dist/hub/index.js.map +1 -1
  152. package/dist/hub/node.cjs.map +1 -1
  153. package/dist/hub/node.js.map +1 -1
  154. package/dist/index.cjs +9 -3
  155. package/dist/index.d.cts +6 -3
  156. package/dist/index.d.ts +6 -3
  157. package/dist/index.js +6 -2
  158. package/dist/storage/encoder_backed.cjs.map +1 -1
  159. package/dist/storage/encoder_backed.js.map +1 -1
  160. package/dist/storage/file_system.cjs.map +1 -1
  161. package/dist/storage/file_system.js.map +1 -1
  162. package/package.json +13 -13
  163. package/dist/agents/stream.cjs.map +0 -1
  164. package/dist/agents/stream.d.cts.map +0 -1
  165. package/dist/agents/stream.d.ts.map +0 -1
  166. package/dist/agents/stream.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/agents/index.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\nimport type {\n InteropZodObject,\n InteropZodType,\n} from \"@langchain/core/utils/types\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\nimport type {\n StateDefinitionInit,\n StreamTransformer,\n} from \"@langchain/langgraph\";\n\nimport type { ResponseFormatUndefined } from \"./responses.js\";\nimport type {\n CreateAgentParams,\n AgentTypeConfig,\n CombineTools,\n CombineStreamTransformers,\n} from \"./types.js\";\nimport type {\n AnyAgentMiddleware,\n AnyAnnotationRoot,\n} from \"./middleware/types.js\";\nimport type { ExtractZodArrayTypes } from \"./types.js\";\nimport type { SerializableSchema } from \"@langchain/core/utils/standard_schema\";\nimport type {\n ToolStrategy,\n TypedToolStrategy,\n ProviderStrategy,\n ResponseFormat,\n JsonSchemaFormat,\n} from \"./responses.js\";\nimport { ReactAgent } from \"./ReactAgent.js\";\n\n/**\n * Creates a production-ready ReAct (Reasoning + Acting) agent that combines language models with tools\n * and middleware to create systems that can reason about tasks, decide which tools to use, and iteratively\n * work towards solutions.\n *\n * The agent follows the ReAct pattern, interleaving reasoning steps with tool calls to iteratively\n * work towards solutions. It can handle multiple tool calls in sequence or parallel, maintain state\n * across interactions, and provide auditable decision processes.\n *\n * ## Core Components\n *\n * ### Model\n * The reasoning engine can be specified as:\n * - **String identifier**: `\"openai:gpt-4o\"` for simple setup\n * - **Model instance**: Configured model object for full control\n * - **Dynamic function**: Select models at runtime based on state\n *\n * ### Tools\n * Tools give agents the ability to take actions:\n * - Pass an array of tools created with the `tool` function\n * - Or provide a configured `ToolNode` for custom error handling\n *\n * ### Prompt\n * Shape how your agent approaches tasks:\n * - String for simple instructions\n * - SystemMessage for structured prompts\n * - Function for dynamic prompts based on state\n *\n * ### Middleware\n * Middleware allows you to extend the agent's behavior:\n * - Add pre/post-model processing for context injection or validation\n * - Add dynamic control flows, e.g. terminate invocation or retries\n * - Add human-in-the-loop capabilities\n * - Add tool calls to the agent\n * - Add tool results to the agent\n *\n * ## Advanced Features\n *\n * - **Structured Output**: Use `responseFormat` with a Zod schema to get typed responses\n * - **Memory**: Extend the state schema to remember information across interactions\n * - **Streaming**: Get real-time updates as the agent processes\n *\n * @param options - Configuration options for the agent\n * @param options.llm - The language model as an instance of a chat model\n * @param options.model - The language model as a string identifier, see more in {@link https://docs.langchain.com/oss/javascript/langchain/models#basic-usage | Models}.\n * @param options.tools - Array of tools or configured ToolNode\n * @param options.prompt - System instructions (string, SystemMessage, or function)\n * @param options.responseFormat - Zod schema for structured output\n * @param options.stateSchema - Custom state schema for memory\n * @param options.middleware - Array of middleware for extending agent behavior, see more in {@link https://docs.langchain.com/oss/javascript/langchain/middleware | Middleware}.\n *\n * @returns A ReactAgent instance with `invoke` and `stream` methods\n *\n * @example Basic agent with tools\n * ```ts\n * import { createAgent, tool } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const search = tool(\n * ({ query }) => `Results for: ${query}`,\n * {\n * name: \"search\",\n * description: \"Search for information\",\n * schema: z.object({\n * query: z.string().describe(\"The search query\"),\n * })\n * }\n * );\n *\n * const agent = createAgent({\n * llm: \"openai:gpt-4o\",\n * tools: [search],\n * });\n *\n * const result = await agent.invoke({\n * messages: [{ role: \"user\", content: \"Search for ReAct agents\" }],\n * });\n * ```\n *\n * @example Structured output\n * ```ts\n * import { createAgent } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const ContactInfo = z.object({\n * name: z.string(),\n * email: z.string(),\n * phone: z.string(),\n * });\n *\n * const agent = createAgent({\n * llm: \"openai:gpt-4o\",\n * tools: [],\n * responseFormat: ContactInfo,\n * });\n *\n * const result = await agent.invoke({\n * messages: [{\n * role: \"user\",\n * content: \"Extract: John Doe, john@example.com, (555) 123-4567\"\n * }],\n * });\n *\n * console.log(result.structuredResponse);\n * // { name: 'John Doe', email: 'john@example.com', phone: '(555) 123-4567' }\n * ```\n *\n * @example Streaming responses\n * ```ts\n * const stream = await agent.stream(\n * { messages: [{ role: \"user\", content: \"What's the weather?\" }] },\n * { streamMode: \"values\" }\n * );\n *\n * for await (const chunk of stream) {\n * // ...\n * }\n * ```\n *\n * @example With StateSchema\n * ```ts\n * import { createAgent } from \"langchain\";\n * import { StateSchema, ReducedValue } from \"@langchain/langgraph\";\n * import { z } from \"zod\";\n *\n * const AgentState = new StateSchema({\n * userId: z.string(),\n * count: z.number().default(0),\n * history: new ReducedValue(\n * z.array(z.string()).default(() => []),\n * { inputSchema: z.string(), reducer: (c, n) => [...c, n] }\n * ),\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * stateSchema: AgentState,\n * });\n * ```\n */\n// Overload 1: With responseFormat as single InteropZodType\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n InteropZodType<StructuredResponseFormat>\n > & {\n responseFormat: InteropZodType<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 2: With responseFormat as array of InteropZodTypes (infers union type)\nexport function createAgent<\n StructuredResponseFormat extends readonly InteropZodType<any>[],\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n ExtractZodArrayTypes<StructuredResponseFormat> extends Record<string, any>\n ? ExtractZodArrayTypes<StructuredResponseFormat>\n : Record<string, any>,\n TStateSchema,\n ContextSchema,\n StructuredResponseFormat\n > & {\n responseFormat: StructuredResponseFormat;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n ExtractZodArrayTypes<StructuredResponseFormat> extends Record<string, any>\n ? ExtractZodArrayTypes<StructuredResponseFormat>\n : Record<string, any>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 3: With responseFormat as JsonSchemaFormat (JSON schema object)\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n JsonSchemaFormat\n > & {\n responseFormat: JsonSchemaFormat;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 4: With responseFormat as array of JsonSchemaFormat (JSON schema objects)\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n JsonSchemaFormat[]\n > & {\n responseFormat: JsonSchemaFormat[];\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 5: With responseFormat as union of JsonSchemaFormat | JsonSchemaFormat[]\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n JsonSchemaFormat | JsonSchemaFormat[]\n > & {\n responseFormat: JsonSchemaFormat | JsonSchemaFormat[];\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 6: With responseFormat as single SerializableSchema\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n SerializableSchema\n > & {\n responseFormat: SerializableSchema;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 7: With responseFormat as array of SerializableSchema\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n SerializableSchema[]\n > & {\n responseFormat: SerializableSchema[];\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 8: With responseFormat as TypedToolStrategy (for union types from toolStrategy)\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TypedToolStrategy<StructuredResponseFormat>\n > & {\n responseFormat: TypedToolStrategy<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 9: With responseFormat as single ToolStrategy instance\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n ToolStrategy<StructuredResponseFormat>\n > & {\n responseFormat: ToolStrategy<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 10: With responseFormat as ProviderStrategy\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n ProviderStrategy<StructuredResponseFormat>\n > & {\n responseFormat: ProviderStrategy<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 11: Without responseFormat property at all - with proper middleware state typing\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: Omit<\n CreateAgentParams<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n never\n >,\n \"responseFormat\"\n > & {\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 12: With responseFormat explicitly undefined\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: Omit<\n CreateAgentParams<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n never\n >,\n \"responseFormat\"\n > & {\n responseFormat?: undefined;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 13: For other ResponseFormat values (failsafe)\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n ResponseFormat\n > & {\n responseFormat: ResponseFormat;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Implementation\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any>,\n TStateSchema extends StateDefinitionInit,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject,\n TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n TStreamTransformers extends ReadonlyArray<() => StreamTransformer<any>> =\n readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n any\n >\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n> {\n return new ReactAgent(params);\n}\n\n// Re-export types and utilities\nexport * from \"./types.js\";\nexport * from \"./errors.js\";\nexport * from \"./nodes/types.js\";\nexport type { JumpToTarget } from \"./constants.js\";\nexport type { Runtime } from \"./runtime.js\";\nexport {\n toolStrategy,\n providerStrategy,\n ToolStrategy,\n ProviderStrategy,\n type TypedToolStrategy,\n type ResponseFormat,\n type ResponseFormatUndefined,\n} from \"./responses.js\";\nexport { createMiddleware } from \"./middleware.js\";\nexport { MIDDLEWARE_BRAND } from \"./middleware/types.js\";\nexport type * from \"./middleware/types.js\";\nexport { FakeToolCallingModel } from \"./tests/utils.js\";\nexport type { ReactAgent } from \"./ReactAgent.js\";\nexport { createToolCallTransformer } from \"./stream.js\";\nexport type { AgentRunStream, ToolCallStreamUnion } from \"./stream.js\";\n"],"mappings":";;;;;;;;AA+pBA,SAAgB,YAad,QAeA;AACA,QAAO,IAAI,WAAW,OAAO"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/agents/index.ts"],"sourcesContent":["/* oxlint-disable @typescript-eslint/no-explicit-any */\nimport type {\n InteropZodObject,\n InteropZodType,\n} from \"@langchain/core/utils/types\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\nimport type {\n StateDefinitionInit,\n StreamTransformer,\n} from \"@langchain/langgraph\";\n\nimport type { ResponseFormatUndefined } from \"./responses.js\";\nimport type {\n CreateAgentParams,\n AgentTypeConfig,\n CombineTools,\n CombineStreamTransformers,\n} from \"./types.js\";\nimport type {\n AnyAgentMiddleware,\n AnyAnnotationRoot,\n} from \"./middleware/types.js\";\nimport type { ExtractZodArrayTypes } from \"./types.js\";\nimport type { SerializableSchema } from \"@langchain/core/utils/standard_schema\";\nimport type {\n ToolStrategy,\n TypedToolStrategy,\n ProviderStrategy,\n ResponseFormat,\n JsonSchemaFormat,\n} from \"./responses.js\";\nimport { ReactAgent } from \"./ReactAgent.js\";\n\n/**\n * Creates a production-ready ReAct (Reasoning + Acting) agent that combines language models with tools\n * and middleware to create systems that can reason about tasks, decide which tools to use, and iteratively\n * work towards solutions.\n *\n * The agent follows the ReAct pattern, interleaving reasoning steps with tool calls to iteratively\n * work towards solutions. It can handle multiple tool calls in sequence or parallel, maintain state\n * across interactions, and provide auditable decision processes.\n *\n * ## Core Components\n *\n * ### Model\n * The reasoning engine can be specified as:\n * - **String identifier**: `\"openai:gpt-4o\"` for simple setup\n * - **Model instance**: Configured model object for full control\n * - **Dynamic function**: Select models at runtime based on state\n *\n * ### Tools\n * Tools give agents the ability to take actions:\n * - Pass an array of tools created with the `tool` function\n * - Or provide a configured `ToolNode` for custom error handling\n *\n * ### Prompt\n * Shape how your agent approaches tasks:\n * - String for simple instructions\n * - SystemMessage for structured prompts\n * - Function for dynamic prompts based on state\n *\n * ### Middleware\n * Middleware allows you to extend the agent's behavior:\n * - Add pre/post-model processing for context injection or validation\n * - Add dynamic control flows, e.g. terminate invocation or retries\n * - Add human-in-the-loop capabilities\n * - Add tool calls to the agent\n * - Add tool results to the agent\n *\n * ## Advanced Features\n *\n * - **Structured Output**: Use `responseFormat` with a Zod schema to get typed responses\n * - **Memory**: Extend the state schema to remember information across interactions\n * - **Streaming**: Get real-time updates as the agent processes\n *\n * @param options - Configuration options for the agent\n * @param options.llm - The language model as an instance of a chat model\n * @param options.model - The language model as a string identifier, see more in {@link https://docs.langchain.com/oss/javascript/langchain/models#basic-usage | Models}.\n * @param options.tools - Array of tools or configured ToolNode\n * @param options.prompt - System instructions (string, SystemMessage, or function)\n * @param options.responseFormat - Zod schema for structured output\n * @param options.stateSchema - Custom state schema for memory\n * @param options.middleware - Array of middleware for extending agent behavior, see more in {@link https://docs.langchain.com/oss/javascript/langchain/middleware | Middleware}.\n *\n * @returns A ReactAgent instance with `invoke` and `stream` methods\n *\n * @example Basic agent with tools\n * ```ts\n * import { createAgent, tool } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const search = tool(\n * ({ query }) => `Results for: ${query}`,\n * {\n * name: \"search\",\n * description: \"Search for information\",\n * schema: z.object({\n * query: z.string().describe(\"The search query\"),\n * })\n * }\n * );\n *\n * const agent = createAgent({\n * llm: \"openai:gpt-4o\",\n * tools: [search],\n * });\n *\n * const result = await agent.invoke({\n * messages: [{ role: \"user\", content: \"Search for ReAct agents\" }],\n * });\n * ```\n *\n * @example Structured output\n * ```ts\n * import { createAgent } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const ContactInfo = z.object({\n * name: z.string(),\n * email: z.string(),\n * phone: z.string(),\n * });\n *\n * const agent = createAgent({\n * llm: \"openai:gpt-4o\",\n * tools: [],\n * responseFormat: ContactInfo,\n * });\n *\n * const result = await agent.invoke({\n * messages: [{\n * role: \"user\",\n * content: \"Extract: John Doe, john@example.com, (555) 123-4567\"\n * }],\n * });\n *\n * console.log(result.structuredResponse);\n * // { name: 'John Doe', email: 'john@example.com', phone: '(555) 123-4567' }\n * ```\n *\n * @example Streaming responses\n * ```ts\n * const stream = await agent.stream(\n * { messages: [{ role: \"user\", content: \"What's the weather?\" }] },\n * { streamMode: \"values\" }\n * );\n *\n * for await (const chunk of stream) {\n * // ...\n * }\n * ```\n *\n * @example With StateSchema\n * ```ts\n * import { createAgent } from \"langchain\";\n * import { StateSchema, ReducedValue } from \"@langchain/langgraph\";\n * import { z } from \"zod\";\n *\n * const AgentState = new StateSchema({\n * userId: z.string(),\n * count: z.number().default(0),\n * history: new ReducedValue(\n * z.array(z.string()).default(() => []),\n * { inputSchema: z.string(), reducer: (c, n) => [...c, n] }\n * ),\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [searchTool],\n * stateSchema: AgentState,\n * });\n * ```\n */\n// Overload 1: With responseFormat as single InteropZodType\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n InteropZodType<StructuredResponseFormat>\n > & {\n responseFormat: InteropZodType<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 2: With responseFormat as array of InteropZodTypes (infers union type)\nexport function createAgent<\n StructuredResponseFormat extends readonly InteropZodType<any>[],\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n ExtractZodArrayTypes<StructuredResponseFormat> extends Record<string, any>\n ? ExtractZodArrayTypes<StructuredResponseFormat>\n : Record<string, any>,\n TStateSchema,\n ContextSchema,\n StructuredResponseFormat\n > & {\n responseFormat: StructuredResponseFormat;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n ExtractZodArrayTypes<StructuredResponseFormat> extends Record<string, any>\n ? ExtractZodArrayTypes<StructuredResponseFormat>\n : Record<string, any>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 3: With responseFormat as JsonSchemaFormat (JSON schema object)\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n JsonSchemaFormat\n > & {\n responseFormat: JsonSchemaFormat;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 4: With responseFormat as array of JsonSchemaFormat (JSON schema objects)\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n JsonSchemaFormat[]\n > & {\n responseFormat: JsonSchemaFormat[];\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 5: With responseFormat as union of JsonSchemaFormat | JsonSchemaFormat[]\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n JsonSchemaFormat | JsonSchemaFormat[]\n > & {\n responseFormat: JsonSchemaFormat | JsonSchemaFormat[];\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 6: With responseFormat as single SerializableSchema\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n SerializableSchema\n > & {\n responseFormat: SerializableSchema;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 7: With responseFormat as array of SerializableSchema\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n SerializableSchema[]\n > & {\n responseFormat: SerializableSchema[];\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n Record<string, unknown>,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 8: With responseFormat as TypedToolStrategy (for union types from toolStrategy)\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TypedToolStrategy<StructuredResponseFormat>\n > & {\n responseFormat: TypedToolStrategy<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 9: With responseFormat as single ToolStrategy instance\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n ToolStrategy<StructuredResponseFormat>\n > & {\n responseFormat: ToolStrategy<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 10: With responseFormat as ProviderStrategy\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n ProviderStrategy<StructuredResponseFormat>\n > & {\n responseFormat: ProviderStrategy<StructuredResponseFormat>;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 11: Without responseFormat property at all - with proper middleware state typing\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: Omit<\n CreateAgentParams<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n never\n >,\n \"responseFormat\"\n > & {\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 12: With responseFormat explicitly undefined\nexport function createAgent<\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: Omit<\n CreateAgentParams<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n never\n >,\n \"responseFormat\"\n > & {\n responseFormat?: undefined;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n ResponseFormatUndefined,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Overload 13: For other ResponseFormat values (failsafe)\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any> = Record<string, any>,\n TStateSchema extends StateDefinitionInit | undefined = undefined,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject =\n AnyAnnotationRoot,\n const TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n ResponseFormat\n > & {\n responseFormat: ResponseFormat;\n middleware?: TMiddleware;\n tools?: TTools;\n streamTransformers?: TStreamTransformers;\n }\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n>;\n\n// Implementation\nexport function createAgent<\n StructuredResponseFormat extends Record<string, any>,\n TStateSchema extends StateDefinitionInit,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject,\n TMiddleware extends readonly AnyAgentMiddleware[] =\n readonly AnyAgentMiddleware[],\n TTools extends readonly (ClientTool | ServerTool)[] = readonly (\n | ClientTool\n | ServerTool\n )[],\n TStreamTransformers extends ReadonlyArray<() => StreamTransformer<any>> =\n readonly [],\n>(\n params: CreateAgentParams<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n any\n >\n): ReactAgent<\n AgentTypeConfig<\n StructuredResponseFormat,\n TStateSchema,\n ContextSchema,\n TMiddleware,\n CombineTools<TTools, TMiddleware>,\n CombineStreamTransformers<TStreamTransformers, TMiddleware>\n >\n> {\n return new ReactAgent(params);\n}\n\n// Re-export types and utilities\nexport * from \"./types.js\";\nexport * from \"./errors.js\";\nexport * from \"./nodes/types.js\";\nexport type { JumpToTarget } from \"./constants.js\";\nexport type { Runtime } from \"./runtime.js\";\nexport {\n toolStrategy,\n providerStrategy,\n ToolStrategy,\n ProviderStrategy,\n type TypedToolStrategy,\n type ResponseFormat,\n type ResponseFormatUndefined,\n} from \"./responses.js\";\nexport { createMiddleware } from \"./middleware.js\";\nexport { MIDDLEWARE_BRAND } from \"./middleware/types.js\";\nexport type * from \"./middleware/types.js\";\nexport { FakeToolCallingModel } from \"./tests/utils.js\";\nexport type { ReactAgent } from \"./ReactAgent.js\";\nexport {\n createToolCallTransformer,\n createSubagentTransformer,\n type AgentRunStream,\n type ToolCallStreamUnion,\n type SubagentRunStream,\n} from \"./transformers/index.js\";\n"],"mappings":";;;;;;;;;;AA+pBA,SAAgB,YAad,QAeA;AACA,QAAO,IAAI,WAAW,OAAO"}
@@ -2,11 +2,36 @@ require("../../_virtual/_rolldown/runtime.cjs");
2
2
  let zod_v3 = require("zod/v3");
3
3
  //#region src/agents/middleware/constants.ts
4
4
  const RetrySchema = zod_v3.z.object({
5
+ /**
6
+ * Maximum number of retry attempts after the initial call.
7
+ * Default is 2 retries (3 total attempts). Must be >= 0.
8
+ */
5
9
  maxRetries: zod_v3.z.number().min(0).default(2),
10
+ /**
11
+ * Either an array of error constructors to retry on, or a function
12
+ * that takes an error and returns `true` if it should be retried.
13
+ * Default is to retry on all errors.
14
+ */
6
15
  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),
16
+ /**
17
+ * Multiplier for exponential backoff. Each retry waits
18
+ * `initialDelayMs * (backoffFactor ** retryNumber)` milliseconds.
19
+ * Set to 0.0 for constant delay. Default is 2.0.
20
+ */
7
21
  backoffFactor: zod_v3.z.number().min(0).default(2),
22
+ /**
23
+ * Initial delay in milliseconds before first retry. Default is 1000 (1 second).
24
+ */
8
25
  initialDelayMs: zod_v3.z.number().min(0).default(1e3),
26
+ /**
27
+ * Maximum delay in milliseconds between retries. Caps exponential
28
+ * backoff growth. Default is 60000 (60 seconds).
29
+ */
9
30
  maxDelayMs: zod_v3.z.number().min(0).default(6e4),
31
+ /**
32
+ * Whether to add random jitter (±25%) to delay to avoid thundering herd.
33
+ * Default is `true`.
34
+ */
10
35
  jitter: zod_v3.z.boolean().default(true)
11
36
  });
12
37
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"constants.cjs","names":["z"],"sources":["../../../src/agents/middleware/constants.ts"],"sourcesContent":["import { z } from \"zod/v3\";\n\nexport const RetrySchema = 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 * 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 // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n z.array(z.custom<new (...args: any[]) => Error>()),\n ])\n .default(() => () => true),\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"],"mappings":";;;AAEA,MAAa,cAAcA,OAAAA,EAAE,OAAO;CAKlC,YAAYA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAOxC,SAASA,OAAAA,EACN,MAAM,CACLA,OAAAA,EAAE,UAAU,CAAC,KAAKA,OAAAA,EAAE,WAAW,MAAM,CAAC,CAAC,QAAQA,OAAAA,EAAE,SAAS,CAAC,EAE3DA,OAAAA,EAAE,MAAMA,OAAAA,EAAE,QAAuC,CAAC,CACnD,CAAC,CACD,oBAAoB,KAAK;CAO5B,eAAeA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAI;CAK7C,gBAAgBA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAK;CAM/C,YAAYA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAM;CAM5C,QAAQA,OAAAA,EAAE,SAAS,CAAC,QAAQ,KAAK;CAClC,CAAC"}
1
+ {"version":3,"file":"constants.cjs","names":["z"],"sources":["../../../src/agents/middleware/constants.ts"],"sourcesContent":["import { z } from \"zod/v3\";\n\nexport const RetrySchema = 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 * 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 // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n z.array(z.custom<new (...args: any[]) => Error>()),\n ])\n .default(() => () => true),\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"],"mappings":";;;AAEA,MAAa,cAAcA,OAAAA,EAAE,OAAO;;;;;CAKlC,YAAYA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;;;;;;CAOxC,SAASA,OAAAA,EACN,MAAM,CACLA,OAAAA,EAAE,UAAU,CAAC,KAAKA,OAAAA,EAAE,WAAW,MAAM,CAAC,CAAC,QAAQA,OAAAA,EAAE,SAAS,CAAC,EAE3DA,OAAAA,EAAE,MAAMA,OAAAA,EAAE,QAAuC,CAAC,CACnD,CAAC,CACD,oBAAoB,KAAK;;;;;;CAO5B,eAAeA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAI;;;;CAK7C,gBAAgBA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAK;;;;;CAM/C,YAAYA,OAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAM;;;;;CAM5C,QAAQA,OAAAA,EAAE,SAAS,CAAC,QAAQ,KAAK;CAClC,CAAC"}
@@ -1,11 +1,36 @@
1
1
  import { z } from "zod/v3";
2
2
  //#region src/agents/middleware/constants.ts
3
3
  const RetrySchema = z.object({
4
+ /**
5
+ * Maximum number of retry attempts after the initial call.
6
+ * Default is 2 retries (3 total attempts). Must be >= 0.
7
+ */
4
8
  maxRetries: z.number().min(0).default(2),
9
+ /**
10
+ * Either an array of error constructors to retry on, or a function
11
+ * that takes an error and returns `true` if it should be retried.
12
+ * Default is to retry on all errors.
13
+ */
5
14
  retryOn: z.union([z.function().args(z.instanceof(Error)).returns(z.boolean()), z.array(z.custom())]).default(() => () => true),
15
+ /**
16
+ * Multiplier for exponential backoff. Each retry waits
17
+ * `initialDelayMs * (backoffFactor ** retryNumber)` milliseconds.
18
+ * Set to 0.0 for constant delay. Default is 2.0.
19
+ */
6
20
  backoffFactor: z.number().min(0).default(2),
21
+ /**
22
+ * Initial delay in milliseconds before first retry. Default is 1000 (1 second).
23
+ */
7
24
  initialDelayMs: z.number().min(0).default(1e3),
25
+ /**
26
+ * Maximum delay in milliseconds between retries. Caps exponential
27
+ * backoff growth. Default is 60000 (60 seconds).
28
+ */
8
29
  maxDelayMs: z.number().min(0).default(6e4),
30
+ /**
31
+ * Whether to add random jitter (±25%) to delay to avoid thundering herd.
32
+ * Default is `true`.
33
+ */
9
34
  jitter: z.boolean().default(true)
10
35
  });
11
36
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","names":[],"sources":["../../../src/agents/middleware/constants.ts"],"sourcesContent":["import { z } from \"zod/v3\";\n\nexport const RetrySchema = 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 * 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 // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n z.array(z.custom<new (...args: any[]) => Error>()),\n ])\n .default(() => () => true),\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"],"mappings":";;AAEA,MAAa,cAAc,EAAE,OAAO;CAKlC,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAOxC,SAAS,EACN,MAAM,CACL,EAAE,UAAU,CAAC,KAAK,EAAE,WAAW,MAAM,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,EAE3D,EAAE,MAAM,EAAE,QAAuC,CAAC,CACnD,CAAC,CACD,oBAAoB,KAAK;CAO5B,eAAe,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAI;CAK7C,gBAAgB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAK;CAM/C,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAM;CAM5C,QAAQ,EAAE,SAAS,CAAC,QAAQ,KAAK;CAClC,CAAC"}
1
+ {"version":3,"file":"constants.js","names":[],"sources":["../../../src/agents/middleware/constants.ts"],"sourcesContent":["import { z } from \"zod/v3\";\n\nexport const RetrySchema = 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 * 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 // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n z.array(z.custom<new (...args: any[]) => Error>()),\n ])\n .default(() => () => true),\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"],"mappings":";;AAEA,MAAa,cAAc,EAAE,OAAO;;;;;CAKlC,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;;;;;;CAOxC,SAAS,EACN,MAAM,CACL,EAAE,UAAU,CAAC,KAAK,EAAE,WAAW,MAAM,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,EAE3D,EAAE,MAAM,EAAE,QAAuC,CAAC,CACnD,CAAC,CACD,oBAAoB,KAAK;;;;;;CAO5B,eAAe,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAI;;;;CAK7C,gBAAgB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAK;;;;;CAM/C,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAM;;;;;CAM5C,QAAQ,EAAE,SAAS,CAAC,QAAQ,KAAK;CAClC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"contextEditing.cjs","names":["#triggerConditions","contextSizeSchema","keepSchema","ToolMessage","#findAIMessageForToolCall","#shouldEdit","#determineKeepCount","#buildClearedToolInputMessage","getProfileLimits","AIMessage","createMiddleware","SystemMessage","countTokensApproximately"],"sources":["../../../src/agents/middleware/contextEditing.ts"],"sourcesContent":["/**\n * Context editing middleware.\n *\n * This middleware mirrors Anthropic's context editing capabilities by clearing\n * older tool results once the conversation grows beyond a configurable token\n * threshold. The implementation is intentionally model-agnostic so it can be used\n * with any LangChain chat model.\n */\n\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport {\n AIMessage,\n ToolMessage,\n SystemMessage,\n} from \"@langchain/core/messages\";\n\nimport { countTokensApproximately } from \"./utils.js\";\nimport { createMiddleware } from \"../middleware.js\";\nimport {\n getProfileLimits,\n contextSizeSchema,\n keepSchema,\n type ContextSize,\n type KeepSize,\n type TokenCounter,\n} from \"./summarization.js\";\n\nconst DEFAULT_TOOL_PLACEHOLDER = \"[cleared]\";\nconst DEFAULT_TRIGGER_TOKENS = 100_000;\nconst DEFAULT_KEEP = 3;\n\n/**\n * Protocol describing a context editing strategy.\n *\n * Implement this interface to create custom strategies for managing\n * conversation context size. The `apply` method should modify the\n * messages array in-place and return the updated token count.\n *\n * @example\n * ```ts\n * import { HumanMessage, type ContextEdit, type BaseMessage } from \"langchain\";\n *\n * class RemoveOldHumanMessages implements ContextEdit {\n * constructor(private keepRecent: number = 10) {}\n *\n * async apply({ messages, countTokens }) {\n * // Check current token count\n * const tokens = await countTokens(messages);\n *\n * // Remove old human messages if over limit, keeping the most recent ones\n * if (tokens > 50000) {\n * const humanMessages: number[] = [];\n *\n * // Find all human message indices\n * for (let i = 0; i < messages.length; i++) {\n * if (HumanMessage.isInstance(messages[i])) {\n * humanMessages.push(i);\n * }\n * }\n *\n * // Remove old human messages (keep only the most recent N)\n * const toRemove = humanMessages.slice(0, -this.keepRecent);\n * for (let i = toRemove.length - 1; i >= 0; i--) {\n * messages.splice(toRemove[i]!, 1);\n * }\n * }\n * }\n * }\n * ```\n */\nexport interface ContextEdit {\n /**\n * Apply an edit to the message list, returning the new token count.\n *\n * This method should:\n * 1. Check if editing is needed based on `tokens` parameter\n * 2. Modify the `messages` array in-place (if needed)\n * 3. Return the new token count after modifications\n *\n * @param params - Parameters for the editing operation\n * @returns The updated token count after applying edits\n */\n apply(params: {\n /**\n * Array of messages to potentially edit (modify in-place)\n */\n messages: BaseMessage[];\n /**\n * Function to count tokens in a message array\n */\n countTokens: TokenCounter;\n /**\n * Optional model instance for model profile information\n */\n model?: BaseLanguageModel;\n }): void | Promise<void>;\n}\n\n/**\n * Configuration for clearing tool outputs when token limits are exceeded.\n */\nexport interface ClearToolUsesEditConfig {\n /**\n * Trigger conditions for context editing.\n * Can be a single condition object (all properties must be met) or an array of conditions (any condition must be met).\n *\n * @example\n * ```ts\n * // Single condition: trigger if tokens >= 100000 AND messages >= 50\n * trigger: { tokens: 100000, messages: 50 }\n *\n * // Multiple conditions: trigger if (tokens >= 100000 AND messages >= 50) OR (tokens >= 50000 AND messages >= 100)\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ]\n *\n * // Fractional trigger: trigger at 80% of model's max input tokens\n * trigger: { fraction: 0.8 }\n * ```\n */\n trigger?: ContextSize | ContextSize[];\n\n /**\n * Context retention policy applied after editing.\n * Specify how many tool results to preserve using messages, tokens, or fraction.\n *\n * @example\n * ```ts\n * // Keep 3 most recent tool results\n * keep: { messages: 3 }\n *\n * // Keep tool results that fit within 1000 tokens\n * keep: { tokens: 1000 }\n *\n * // Keep tool results that fit within 30% of model's max input tokens\n * keep: { fraction: 0.3 }\n * ```\n */\n keep?: KeepSize;\n\n /**\n * Whether to clear the originating tool call parameters on the AI message.\n * @default false\n */\n clearToolInputs?: boolean;\n\n /**\n * List of tool names to exclude from clearing.\n * @default []\n */\n excludeTools?: string[];\n\n /**\n * Placeholder text inserted for cleared tool outputs.\n * @default \"[cleared]\"\n */\n placeholder?: string;\n\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n triggerTokens?: number;\n\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n keepMessages?: number;\n\n /**\n * @deprecated This property is deprecated and will be removed in a future version.\n * Use `keep: { tokens: value }` or `keep: { messages: value }` instead to control retention.\n */\n clearAtLeast?: number;\n}\n\n/**\n * Strategy for clearing tool outputs when token limits are exceeded.\n *\n * This strategy mirrors Anthropic's `clear_tool_uses_20250919` behavior by\n * replacing older tool results with a placeholder text when the conversation\n * grows too large. It preserves the most recent tool results and can exclude\n * specific tools from being cleared.\n *\n * @example\n * ```ts\n * import { ClearToolUsesEdit } from \"langchain\";\n *\n * const edit = new ClearToolUsesEdit({\n * trigger: { tokens: 100000 }, // Start clearing at 100K tokens\n * keep: { messages: 3 }, // Keep 3 most recent tool results\n * excludeTools: [\"important\"], // Never clear \"important\" tool\n * clearToolInputs: false, // Keep tool call arguments\n * placeholder: \"[cleared]\", // Replacement text\n * });\n *\n * // Multiple trigger conditions\n * const edit2 = new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ],\n * keep: { messages: 3 },\n * });\n *\n * // Fractional trigger with model profile\n * const edit3 = new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * });\n * ```\n */\nexport class ClearToolUsesEdit implements ContextEdit {\n #triggerConditions: ContextSize[];\n\n trigger: ContextSize | ContextSize[];\n keep: KeepSize;\n clearToolInputs: boolean;\n excludeTools: Set<string>;\n placeholder: string;\n model: BaseLanguageModel;\n clearAtLeast: number;\n\n constructor(config: ClearToolUsesEditConfig = {}) {\n // Handle deprecated parameters\n let trigger: ContextSize | ContextSize[] | undefined = config.trigger;\n if (config.triggerTokens !== undefined) {\n console.warn(\n \"triggerTokens is deprecated. Use `trigger: { tokens: value }` instead.\"\n );\n if (trigger === undefined) {\n trigger = { tokens: config.triggerTokens };\n }\n }\n\n let keep: KeepSize | undefined = config.keep;\n if (config.keepMessages !== undefined) {\n console.warn(\n \"keepMessages is deprecated. Use `keep: { messages: value }` instead.\"\n );\n if (keep === undefined) {\n keep = { messages: config.keepMessages };\n }\n }\n\n // Set defaults\n if (trigger === undefined) {\n trigger = { tokens: DEFAULT_TRIGGER_TOKENS };\n }\n if (keep === undefined) {\n keep = { messages: DEFAULT_KEEP };\n }\n\n // Validate trigger conditions\n if (Array.isArray(trigger)) {\n this.#triggerConditions = trigger.map((t) => contextSizeSchema.parse(t));\n this.trigger = this.#triggerConditions;\n } else {\n const validated = contextSizeSchema.parse(trigger);\n this.#triggerConditions = [validated];\n this.trigger = validated;\n }\n\n // Validate keep\n const validatedKeep = keepSchema.parse(keep);\n this.keep = validatedKeep;\n\n // Handle deprecated clearAtLeast\n if (config.clearAtLeast !== undefined) {\n console.warn(\n \"clearAtLeast is deprecated and will be removed in a future version. \" +\n \"It conflicts with the `keep` property. Use `keep: { tokens: value }` or \" +\n \"`keep: { messages: value }` instead to control retention.\"\n );\n }\n this.clearAtLeast = config.clearAtLeast ?? 0;\n\n this.clearToolInputs = config.clearToolInputs ?? false;\n this.excludeTools = new Set(config.excludeTools ?? []);\n this.placeholder = config.placeholder ?? DEFAULT_TOOL_PLACEHOLDER;\n }\n\n async apply(params: {\n messages: BaseMessage[];\n model: BaseLanguageModel;\n countTokens: TokenCounter;\n }): Promise<void> {\n const { messages, model, countTokens } = params;\n const tokens = await countTokens(messages);\n\n /**\n * Always remove orphaned tool messages (those without corresponding AI messages)\n * regardless of whether editing is triggered\n */\n const orphanedIndices: number[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n // Check if this tool message has a corresponding AI message\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, i),\n msg.tool_call_id\n );\n\n if (!aiMessage) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n } else {\n // Check if the AI message actually has this tool call\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === msg.tool_call_id\n );\n if (!toolCall) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n }\n }\n }\n }\n\n /**\n * Remove orphaned tool messages in reverse order to maintain indices\n */\n for (let i = orphanedIndices.length - 1; i >= 0; i--) {\n messages.splice(orphanedIndices[i]!, 1);\n }\n\n /**\n * Recalculate tokens after removing orphaned messages\n */\n let currentTokens = tokens;\n if (orphanedIndices.length > 0) {\n currentTokens = await countTokens(messages);\n }\n\n /**\n * Check if editing should be triggered\n */\n if (!this.#shouldEdit(messages, currentTokens, model)) {\n return;\n }\n\n /**\n * Find all tool message candidates with their actual indices in the messages array\n */\n const candidates: { idx: number; msg: ToolMessage }[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n candidates.push({ idx: i, msg });\n }\n }\n\n if (candidates.length === 0) {\n return;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n const keepCount = await this.#determineKeepCount(\n candidates,\n countTokens,\n model\n );\n\n /**\n * Keep the most recent tool messages based on keep policy\n */\n const candidatesToClear =\n keepCount >= candidates.length\n ? []\n : keepCount > 0\n ? candidates.slice(0, -keepCount)\n : candidates;\n\n /**\n * If clearAtLeast is set, we may need to clear more messages to meet the token requirement\n * This is a deprecated feature that conflicts with keep, but we support it for backwards compatibility\n */\n let clearedTokens = 0;\n const initialCandidatesToClear = [...candidatesToClear];\n\n for (const { idx, msg: toolMessage } of initialCandidatesToClear) {\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata?.context_editing as\n | { cleared?: boolean }\n | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n\n /**\n * If clearAtLeast is set and we haven't cleared enough tokens,\n * continue clearing more messages (going backwards from keepCount)\n * This is deprecated behavior but maintained for backwards compatibility\n */\n if (this.clearAtLeast > 0 && clearedTokens < this.clearAtLeast) {\n /**\n * Find remaining candidates that weren't cleared yet (those that were kept)\n */\n const remainingCandidates =\n keepCount > 0 && keepCount < candidates.length\n ? candidates.slice(-keepCount)\n : [];\n\n /**\n * Clear additional messages until we've cleared at least clearAtLeast tokens\n * Go backwards through the kept messages\n */\n for (let i = remainingCandidates.length - 1; i >= 0; i--) {\n if (clearedTokens >= this.clearAtLeast) {\n break;\n }\n\n const { idx, msg: toolMessage } = remainingCandidates[i]!;\n\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata?.context_editing as\n | { cleared?: boolean }\n | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n }\n }\n\n /**\n * Determine whether editing should run for the current token usage\n */\n #shouldEdit(\n messages: BaseMessage[],\n totalTokens: number,\n model: BaseLanguageModel\n ): boolean {\n /**\n * Check each condition (OR logic between conditions)\n */\n for (const trigger of this.#triggerConditions) {\n /**\n * Within a single condition, all specified properties must be satisfied (AND logic)\n */\n let conditionMet = true;\n let hasAnyProperty = false;\n\n if (trigger.messages !== undefined) {\n hasAnyProperty = true;\n if (messages.length < trigger.messages) {\n conditionMet = false;\n }\n }\n\n if (trigger.tokens !== undefined) {\n hasAnyProperty = true;\n if (totalTokens < trigger.tokens) {\n conditionMet = false;\n }\n }\n\n if (trigger.fraction !== undefined) {\n hasAnyProperty = true;\n if (!model) {\n continue;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const threshold = Math.floor(maxInputTokens * trigger.fraction);\n if (threshold <= 0) {\n continue;\n }\n if (totalTokens < threshold) {\n conditionMet = false;\n }\n } else {\n /**\n * If fraction is specified but we can't get model limits, skip this condition\n */\n continue;\n }\n }\n\n /**\n * If condition has at least one property and all properties are satisfied, trigger editing\n */\n if (hasAnyProperty && conditionMet) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n async #determineKeepCount(\n candidates: Array<{ idx: number; msg: ToolMessage }>,\n countTokens: TokenCounter,\n model: BaseLanguageModel\n ): Promise<number> {\n if (\"messages\" in this.keep && this.keep.messages !== undefined) {\n return this.keep.messages;\n }\n\n if (\"tokens\" in this.keep && this.keep.tokens !== undefined) {\n /**\n * For token-based keep, count backwards from the end until we exceed the token limit\n * This is a simplified implementation - keeping N most recent tool messages\n * A more sophisticated implementation would count actual tokens\n */\n const targetTokens = this.keep.tokens;\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n /**\n * Estimate tokens for this tool message (simplified - could be improved)\n */\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n\n if (\"fraction\" in this.keep && this.keep.fraction !== undefined) {\n if (!model) {\n return DEFAULT_KEEP;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const targetTokens = Math.floor(maxInputTokens * this.keep.fraction);\n if (targetTokens <= 0) {\n return DEFAULT_KEEP;\n }\n /**\n * Use token-based logic with fractional target\n */\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n }\n\n return DEFAULT_KEEP;\n }\n\n #findAIMessageForToolCall(\n previousMessages: BaseMessage[],\n toolCallId: string\n ): AIMessage | null {\n // Search backwards through previous messages\n for (let i = previousMessages.length - 1; i >= 0; i--) {\n const msg = previousMessages[i];\n if (AIMessage.isInstance(msg)) {\n const hasToolCall = msg.tool_calls?.some(\n (call) => call.id === toolCallId\n );\n if (hasToolCall) {\n return msg;\n }\n }\n }\n return null;\n }\n\n #buildClearedToolInputMessage(\n message: AIMessage,\n toolCallId: string\n ): AIMessage {\n const updatedToolCalls = message.tool_calls?.map((toolCall) => {\n if (toolCall.id === toolCallId) {\n return { ...toolCall, args: {} };\n }\n return toolCall;\n });\n\n const metadata = { ...message.response_metadata };\n const contextEntry = {\n ...(metadata.context_editing as Record<string, unknown>),\n };\n\n const clearedIds = new Set<string>(\n contextEntry.cleared_tool_inputs as string[] | undefined\n );\n clearedIds.add(toolCallId);\n contextEntry.cleared_tool_inputs = Array.from(clearedIds).sort();\n metadata.context_editing = contextEntry;\n\n return new AIMessage({\n content: message.content,\n tool_calls: updatedToolCalls,\n response_metadata: metadata,\n id: message.id,\n name: message.name,\n additional_kwargs: message.additional_kwargs,\n });\n }\n}\n\n/**\n * Configuration for the Context Editing Middleware.\n */\nexport interface ContextEditingMiddlewareConfig {\n /**\n * Sequence of edit strategies to apply. Defaults to a single\n * ClearToolUsesEdit mirroring Anthropic defaults.\n */\n edits?: ContextEdit[];\n\n /**\n * Whether to use approximate token counting (faster, less accurate)\n * or exact counting implemented by the chat model (potentially slower, more accurate).\n * Currently only OpenAI models support exact counting.\n * @default \"approx\"\n */\n tokenCountMethod?: \"approx\" | \"model\";\n}\n\n/**\n * Middleware that automatically prunes tool results to manage context size.\n *\n * This middleware applies a sequence of edits when the total input token count\n * exceeds configured thresholds. By default, it uses the `ClearToolUsesEdit` strategy\n * which mirrors Anthropic's `clear_tool_uses_20250919` behaviour by clearing older\n * tool results once the conversation exceeds 100,000 tokens.\n *\n * ## Basic Usage\n *\n * Use the middleware with default settings to automatically manage context:\n *\n * @example Basic usage with defaults\n * ```ts\n * import { contextEditingMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware(),\n * ],\n * });\n * ```\n *\n * The default configuration:\n * - Triggers when context exceeds **100,000 tokens**\n * - Keeps the **3 most recent** tool results\n * - Uses **approximate token counting** (fast)\n * - Does not clear tool call arguments\n *\n * ## Custom Configuration\n *\n * Customize the clearing behavior with `ClearToolUsesEdit`:\n *\n * @example Custom ClearToolUsesEdit configuration\n * ```ts\n * import { contextEditingMiddleware, ClearToolUsesEdit } from \"langchain\";\n *\n * // Single condition: trigger if tokens >= 50000 AND messages >= 20\n * const agent1 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { tokens: 50000, messages: 20 },\n * keep: { messages: 5 },\n * excludeTools: [\"search\"],\n * clearToolInputs: true,\n * }),\n * ],\n * tokenCountMethod: \"approx\",\n * }),\n * ],\n * });\n *\n * // Multiple conditions: trigger if (tokens >= 50000 AND messages >= 20) OR (tokens >= 30000 AND messages >= 50)\n * const agent2 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 50000, messages: 20 },\n * { tokens: 30000, messages: 50 },\n * ],\n * keep: { messages: 5 },\n * }),\n * ],\n * }),\n * ],\n * });\n *\n * // Fractional trigger with model profile\n * const agent3 = createAgent({\n * model: chatModel,\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * model: chatModel,\n * }),\n * ],\n * }),\n * ],\n * });\n * ```\n *\n * ## Custom Editing Strategies\n *\n * Implement your own context editing strategy by creating a class that\n * implements the `ContextEdit` interface:\n *\n * @example Custom editing strategy\n * ```ts\n * import { contextEditingMiddleware, type ContextEdit, type TokenCounter } from \"langchain\";\n * import type { BaseMessage } from \"@langchain/core/messages\";\n *\n * class CustomEdit implements ContextEdit {\n * async apply(params: {\n * tokens: number;\n * messages: BaseMessage[];\n * countTokens: TokenCounter;\n * }): Promise<number> {\n * // Implement your custom editing logic here\n * // and apply it to the messages array, then\n * // return the new token count after edits\n * return countTokens(messages);\n * }\n * }\n * ```\n *\n * @param config - Configuration options for the middleware\n * @returns A middleware instance that can be used with `createAgent`\n */\nexport function contextEditingMiddleware(\n config: ContextEditingMiddlewareConfig = {}\n) {\n const edits = config.edits ?? [new ClearToolUsesEdit()];\n const tokenCountMethod = config.tokenCountMethod ?? \"approx\";\n\n return createMiddleware({\n name: \"ContextEditingMiddleware\",\n wrapModelCall: async (request, handler) => {\n if (!request.messages || request.messages.length === 0) {\n return handler(request);\n }\n\n /**\n * Use model's token counting method\n */\n const systemMsg = request.systemPrompt\n ? [new SystemMessage(request.systemPrompt)]\n : [];\n\n const countTokens: TokenCounter =\n tokenCountMethod === \"approx\"\n ? countTokensApproximately\n : async (messages: BaseMessage[]): Promise<number> => {\n const allMessages = [...systemMsg, ...messages];\n\n /**\n * Check if model has getNumTokensFromMessages method\n * currently only OpenAI models have this method\n */\n if (\"getNumTokensFromMessages\" in request.model) {\n return (\n request.model as BaseLanguageModel & {\n getNumTokensFromMessages: (\n messages: BaseMessage[]\n ) => Promise<{\n totalCount: number;\n countPerMessage: number[];\n }>;\n }\n )\n .getNumTokensFromMessages(allMessages)\n .then(({ totalCount }) => totalCount);\n }\n\n throw new Error(\n `Model \"${request.model.getName()}\" does not support token counting`\n );\n };\n\n /**\n * Apply each edit in sequence\n */\n for (const edit of edits) {\n await edit.apply({\n messages: request.messages,\n model: request.model as BaseLanguageModel,\n countTokens,\n });\n }\n\n return handler(request);\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contextEditing.cjs","names":["#triggerConditions","contextSizeSchema","keepSchema","ToolMessage","#findAIMessageForToolCall","#shouldEdit","#determineKeepCount","#buildClearedToolInputMessage","getProfileLimits","AIMessage","createMiddleware","SystemMessage","countTokensApproximately"],"sources":["../../../src/agents/middleware/contextEditing.ts"],"sourcesContent":["/**\n * Context editing middleware.\n *\n * This middleware mirrors Anthropic's context editing capabilities by clearing\n * older tool results once the conversation grows beyond a configurable token\n * threshold. The implementation is intentionally model-agnostic so it can be used\n * with any LangChain chat model.\n */\n\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport {\n AIMessage,\n ToolMessage,\n SystemMessage,\n} from \"@langchain/core/messages\";\n\nimport { countTokensApproximately } from \"./utils.js\";\nimport { createMiddleware } from \"../middleware.js\";\nimport {\n getProfileLimits,\n contextSizeSchema,\n keepSchema,\n type ContextSize,\n type KeepSize,\n type TokenCounter,\n} from \"./summarization.js\";\n\nconst DEFAULT_TOOL_PLACEHOLDER = \"[cleared]\";\nconst DEFAULT_TRIGGER_TOKENS = 100_000;\nconst DEFAULT_KEEP = 3;\n\n/**\n * Protocol describing a context editing strategy.\n *\n * Implement this interface to create custom strategies for managing\n * conversation context size. The `apply` method should modify the\n * messages array in-place and return the updated token count.\n *\n * @example\n * ```ts\n * import { HumanMessage, type ContextEdit, type BaseMessage } from \"langchain\";\n *\n * class RemoveOldHumanMessages implements ContextEdit {\n * constructor(private keepRecent: number = 10) {}\n *\n * async apply({ messages, countTokens }) {\n * // Check current token count\n * const tokens = await countTokens(messages);\n *\n * // Remove old human messages if over limit, keeping the most recent ones\n * if (tokens > 50000) {\n * const humanMessages: number[] = [];\n *\n * // Find all human message indices\n * for (let i = 0; i < messages.length; i++) {\n * if (HumanMessage.isInstance(messages[i])) {\n * humanMessages.push(i);\n * }\n * }\n *\n * // Remove old human messages (keep only the most recent N)\n * const toRemove = humanMessages.slice(0, -this.keepRecent);\n * for (let i = toRemove.length - 1; i >= 0; i--) {\n * messages.splice(toRemove[i]!, 1);\n * }\n * }\n * }\n * }\n * ```\n */\nexport interface ContextEdit {\n /**\n * Apply an edit to the message list, returning the new token count.\n *\n * This method should:\n * 1. Check if editing is needed based on `tokens` parameter\n * 2. Modify the `messages` array in-place (if needed)\n * 3. Return the new token count after modifications\n *\n * @param params - Parameters for the editing operation\n * @returns The updated token count after applying edits\n */\n apply(params: {\n /**\n * Array of messages to potentially edit (modify in-place)\n */\n messages: BaseMessage[];\n /**\n * Function to count tokens in a message array\n */\n countTokens: TokenCounter;\n /**\n * Optional model instance for model profile information\n */\n model?: BaseLanguageModel;\n }): void | Promise<void>;\n}\n\n/**\n * Configuration for clearing tool outputs when token limits are exceeded.\n */\nexport interface ClearToolUsesEditConfig {\n /**\n * Trigger conditions for context editing.\n * Can be a single condition object (all properties must be met) or an array of conditions (any condition must be met).\n *\n * @example\n * ```ts\n * // Single condition: trigger if tokens >= 100000 AND messages >= 50\n * trigger: { tokens: 100000, messages: 50 }\n *\n * // Multiple conditions: trigger if (tokens >= 100000 AND messages >= 50) OR (tokens >= 50000 AND messages >= 100)\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ]\n *\n * // Fractional trigger: trigger at 80% of model's max input tokens\n * trigger: { fraction: 0.8 }\n * ```\n */\n trigger?: ContextSize | ContextSize[];\n\n /**\n * Context retention policy applied after editing.\n * Specify how many tool results to preserve using messages, tokens, or fraction.\n *\n * @example\n * ```ts\n * // Keep 3 most recent tool results\n * keep: { messages: 3 }\n *\n * // Keep tool results that fit within 1000 tokens\n * keep: { tokens: 1000 }\n *\n * // Keep tool results that fit within 30% of model's max input tokens\n * keep: { fraction: 0.3 }\n * ```\n */\n keep?: KeepSize;\n\n /**\n * Whether to clear the originating tool call parameters on the AI message.\n * @default false\n */\n clearToolInputs?: boolean;\n\n /**\n * List of tool names to exclude from clearing.\n * @default []\n */\n excludeTools?: string[];\n\n /**\n * Placeholder text inserted for cleared tool outputs.\n * @default \"[cleared]\"\n */\n placeholder?: string;\n\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n triggerTokens?: number;\n\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n keepMessages?: number;\n\n /**\n * @deprecated This property is deprecated and will be removed in a future version.\n * Use `keep: { tokens: value }` or `keep: { messages: value }` instead to control retention.\n */\n clearAtLeast?: number;\n}\n\n/**\n * Strategy for clearing tool outputs when token limits are exceeded.\n *\n * This strategy mirrors Anthropic's `clear_tool_uses_20250919` behavior by\n * replacing older tool results with a placeholder text when the conversation\n * grows too large. It preserves the most recent tool results and can exclude\n * specific tools from being cleared.\n *\n * @example\n * ```ts\n * import { ClearToolUsesEdit } from \"langchain\";\n *\n * const edit = new ClearToolUsesEdit({\n * trigger: { tokens: 100000 }, // Start clearing at 100K tokens\n * keep: { messages: 3 }, // Keep 3 most recent tool results\n * excludeTools: [\"important\"], // Never clear \"important\" tool\n * clearToolInputs: false, // Keep tool call arguments\n * placeholder: \"[cleared]\", // Replacement text\n * });\n *\n * // Multiple trigger conditions\n * const edit2 = new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ],\n * keep: { messages: 3 },\n * });\n *\n * // Fractional trigger with model profile\n * const edit3 = new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * });\n * ```\n */\nexport class ClearToolUsesEdit implements ContextEdit {\n #triggerConditions: ContextSize[];\n\n trigger: ContextSize | ContextSize[];\n keep: KeepSize;\n clearToolInputs: boolean;\n excludeTools: Set<string>;\n placeholder: string;\n model: BaseLanguageModel;\n clearAtLeast: number;\n\n constructor(config: ClearToolUsesEditConfig = {}) {\n // Handle deprecated parameters\n let trigger: ContextSize | ContextSize[] | undefined = config.trigger;\n if (config.triggerTokens !== undefined) {\n console.warn(\n \"triggerTokens is deprecated. Use `trigger: { tokens: value }` instead.\"\n );\n if (trigger === undefined) {\n trigger = { tokens: config.triggerTokens };\n }\n }\n\n let keep: KeepSize | undefined = config.keep;\n if (config.keepMessages !== undefined) {\n console.warn(\n \"keepMessages is deprecated. Use `keep: { messages: value }` instead.\"\n );\n if (keep === undefined) {\n keep = { messages: config.keepMessages };\n }\n }\n\n // Set defaults\n if (trigger === undefined) {\n trigger = { tokens: DEFAULT_TRIGGER_TOKENS };\n }\n if (keep === undefined) {\n keep = { messages: DEFAULT_KEEP };\n }\n\n // Validate trigger conditions\n if (Array.isArray(trigger)) {\n this.#triggerConditions = trigger.map((t) => contextSizeSchema.parse(t));\n this.trigger = this.#triggerConditions;\n } else {\n const validated = contextSizeSchema.parse(trigger);\n this.#triggerConditions = [validated];\n this.trigger = validated;\n }\n\n // Validate keep\n const validatedKeep = keepSchema.parse(keep);\n this.keep = validatedKeep;\n\n // Handle deprecated clearAtLeast\n if (config.clearAtLeast !== undefined) {\n console.warn(\n \"clearAtLeast is deprecated and will be removed in a future version. \" +\n \"It conflicts with the `keep` property. Use `keep: { tokens: value }` or \" +\n \"`keep: { messages: value }` instead to control retention.\"\n );\n }\n this.clearAtLeast = config.clearAtLeast ?? 0;\n\n this.clearToolInputs = config.clearToolInputs ?? false;\n this.excludeTools = new Set(config.excludeTools ?? []);\n this.placeholder = config.placeholder ?? DEFAULT_TOOL_PLACEHOLDER;\n }\n\n async apply(params: {\n messages: BaseMessage[];\n model: BaseLanguageModel;\n countTokens: TokenCounter;\n }): Promise<void> {\n const { messages, model, countTokens } = params;\n const tokens = await countTokens(messages);\n\n /**\n * Always remove orphaned tool messages (those without corresponding AI messages)\n * regardless of whether editing is triggered\n */\n const orphanedIndices: number[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n // Check if this tool message has a corresponding AI message\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, i),\n msg.tool_call_id\n );\n\n if (!aiMessage) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n } else {\n // Check if the AI message actually has this tool call\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === msg.tool_call_id\n );\n if (!toolCall) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n }\n }\n }\n }\n\n /**\n * Remove orphaned tool messages in reverse order to maintain indices\n */\n for (let i = orphanedIndices.length - 1; i >= 0; i--) {\n messages.splice(orphanedIndices[i]!, 1);\n }\n\n /**\n * Recalculate tokens after removing orphaned messages\n */\n let currentTokens = tokens;\n if (orphanedIndices.length > 0) {\n currentTokens = await countTokens(messages);\n }\n\n /**\n * Check if editing should be triggered\n */\n if (!this.#shouldEdit(messages, currentTokens, model)) {\n return;\n }\n\n /**\n * Find all tool message candidates with their actual indices in the messages array\n */\n const candidates: { idx: number; msg: ToolMessage }[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n candidates.push({ idx: i, msg });\n }\n }\n\n if (candidates.length === 0) {\n return;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n const keepCount = await this.#determineKeepCount(\n candidates,\n countTokens,\n model\n );\n\n /**\n * Keep the most recent tool messages based on keep policy\n */\n const candidatesToClear =\n keepCount >= candidates.length\n ? []\n : keepCount > 0\n ? candidates.slice(0, -keepCount)\n : candidates;\n\n /**\n * If clearAtLeast is set, we may need to clear more messages to meet the token requirement\n * This is a deprecated feature that conflicts with keep, but we support it for backwards compatibility\n */\n let clearedTokens = 0;\n const initialCandidatesToClear = [...candidatesToClear];\n\n for (const { idx, msg: toolMessage } of initialCandidatesToClear) {\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata?.context_editing as\n | { cleared?: boolean }\n | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n\n /**\n * If clearAtLeast is set and we haven't cleared enough tokens,\n * continue clearing more messages (going backwards from keepCount)\n * This is deprecated behavior but maintained for backwards compatibility\n */\n if (this.clearAtLeast > 0 && clearedTokens < this.clearAtLeast) {\n /**\n * Find remaining candidates that weren't cleared yet (those that were kept)\n */\n const remainingCandidates =\n keepCount > 0 && keepCount < candidates.length\n ? candidates.slice(-keepCount)\n : [];\n\n /**\n * Clear additional messages until we've cleared at least clearAtLeast tokens\n * Go backwards through the kept messages\n */\n for (let i = remainingCandidates.length - 1; i >= 0; i--) {\n if (clearedTokens >= this.clearAtLeast) {\n break;\n }\n\n const { idx, msg: toolMessage } = remainingCandidates[i]!;\n\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata\n ?.context_editing as { cleared?: boolean } | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n }\n }\n\n /**\n * Determine whether editing should run for the current token usage\n */\n #shouldEdit(\n messages: BaseMessage[],\n totalTokens: number,\n model: BaseLanguageModel\n ): boolean {\n /**\n * Check each condition (OR logic between conditions)\n */\n for (const trigger of this.#triggerConditions) {\n /**\n * Within a single condition, all specified properties must be satisfied (AND logic)\n */\n let conditionMet = true;\n let hasAnyProperty = false;\n\n if (trigger.messages !== undefined) {\n hasAnyProperty = true;\n if (messages.length < trigger.messages) {\n conditionMet = false;\n }\n }\n\n if (trigger.tokens !== undefined) {\n hasAnyProperty = true;\n if (totalTokens < trigger.tokens) {\n conditionMet = false;\n }\n }\n\n if (trigger.fraction !== undefined) {\n hasAnyProperty = true;\n if (!model) {\n continue;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const threshold = Math.floor(maxInputTokens * trigger.fraction);\n if (threshold <= 0) {\n continue;\n }\n if (totalTokens < threshold) {\n conditionMet = false;\n }\n } else {\n /**\n * If fraction is specified but we can't get model limits, skip this condition\n */\n continue;\n }\n }\n\n /**\n * If condition has at least one property and all properties are satisfied, trigger editing\n */\n if (hasAnyProperty && conditionMet) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n async #determineKeepCount(\n candidates: Array<{ idx: number; msg: ToolMessage }>,\n countTokens: TokenCounter,\n model: BaseLanguageModel\n ): Promise<number> {\n if (\"messages\" in this.keep && this.keep.messages !== undefined) {\n return this.keep.messages;\n }\n\n if (\"tokens\" in this.keep && this.keep.tokens !== undefined) {\n /**\n * For token-based keep, count backwards from the end until we exceed the token limit\n * This is a simplified implementation - keeping N most recent tool messages\n * A more sophisticated implementation would count actual tokens\n */\n const targetTokens = this.keep.tokens;\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n /**\n * Estimate tokens for this tool message (simplified - could be improved)\n */\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n\n if (\"fraction\" in this.keep && this.keep.fraction !== undefined) {\n if (!model) {\n return DEFAULT_KEEP;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const targetTokens = Math.floor(maxInputTokens * this.keep.fraction);\n if (targetTokens <= 0) {\n return DEFAULT_KEEP;\n }\n /**\n * Use token-based logic with fractional target\n */\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n }\n\n return DEFAULT_KEEP;\n }\n\n #findAIMessageForToolCall(\n previousMessages: BaseMessage[],\n toolCallId: string\n ): AIMessage | null {\n // Search backwards through previous messages\n for (let i = previousMessages.length - 1; i >= 0; i--) {\n const msg = previousMessages[i];\n if (AIMessage.isInstance(msg)) {\n const hasToolCall = msg.tool_calls?.some(\n (call) => call.id === toolCallId\n );\n if (hasToolCall) {\n return msg;\n }\n }\n }\n return null;\n }\n\n #buildClearedToolInputMessage(\n message: AIMessage,\n toolCallId: string\n ): AIMessage {\n const updatedToolCalls = message.tool_calls?.map((toolCall) => {\n if (toolCall.id === toolCallId) {\n return { ...toolCall, args: {} };\n }\n return toolCall;\n });\n\n const metadata = { ...message.response_metadata };\n const contextEntry = {\n ...(metadata.context_editing as Record<string, unknown>),\n };\n\n const clearedIds = new Set<string>(\n contextEntry.cleared_tool_inputs as string[] | undefined\n );\n clearedIds.add(toolCallId);\n contextEntry.cleared_tool_inputs = Array.from(clearedIds).sort();\n metadata.context_editing = contextEntry;\n\n return new AIMessage({\n content: message.content,\n tool_calls: updatedToolCalls,\n response_metadata: metadata,\n id: message.id,\n name: message.name,\n additional_kwargs: message.additional_kwargs,\n });\n }\n}\n\n/**\n * Configuration for the Context Editing Middleware.\n */\nexport interface ContextEditingMiddlewareConfig {\n /**\n * Sequence of edit strategies to apply. Defaults to a single\n * ClearToolUsesEdit mirroring Anthropic defaults.\n */\n edits?: ContextEdit[];\n\n /**\n * Whether to use approximate token counting (faster, less accurate)\n * or exact counting implemented by the chat model (potentially slower, more accurate).\n * Currently only OpenAI models support exact counting.\n * @default \"approx\"\n */\n tokenCountMethod?: \"approx\" | \"model\";\n}\n\n/**\n * Middleware that automatically prunes tool results to manage context size.\n *\n * This middleware applies a sequence of edits when the total input token count\n * exceeds configured thresholds. By default, it uses the `ClearToolUsesEdit` strategy\n * which mirrors Anthropic's `clear_tool_uses_20250919` behaviour by clearing older\n * tool results once the conversation exceeds 100,000 tokens.\n *\n * ## Basic Usage\n *\n * Use the middleware with default settings to automatically manage context:\n *\n * @example Basic usage with defaults\n * ```ts\n * import { contextEditingMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware(),\n * ],\n * });\n * ```\n *\n * The default configuration:\n * - Triggers when context exceeds **100,000 tokens**\n * - Keeps the **3 most recent** tool results\n * - Uses **approximate token counting** (fast)\n * - Does not clear tool call arguments\n *\n * ## Custom Configuration\n *\n * Customize the clearing behavior with `ClearToolUsesEdit`:\n *\n * @example Custom ClearToolUsesEdit configuration\n * ```ts\n * import { contextEditingMiddleware, ClearToolUsesEdit } from \"langchain\";\n *\n * // Single condition: trigger if tokens >= 50000 AND messages >= 20\n * const agent1 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { tokens: 50000, messages: 20 },\n * keep: { messages: 5 },\n * excludeTools: [\"search\"],\n * clearToolInputs: true,\n * }),\n * ],\n * tokenCountMethod: \"approx\",\n * }),\n * ],\n * });\n *\n * // Multiple conditions: trigger if (tokens >= 50000 AND messages >= 20) OR (tokens >= 30000 AND messages >= 50)\n * const agent2 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 50000, messages: 20 },\n * { tokens: 30000, messages: 50 },\n * ],\n * keep: { messages: 5 },\n * }),\n * ],\n * }),\n * ],\n * });\n *\n * // Fractional trigger with model profile\n * const agent3 = createAgent({\n * model: chatModel,\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * model: chatModel,\n * }),\n * ],\n * }),\n * ],\n * });\n * ```\n *\n * ## Custom Editing Strategies\n *\n * Implement your own context editing strategy by creating a class that\n * implements the `ContextEdit` interface:\n *\n * @example Custom editing strategy\n * ```ts\n * import { contextEditingMiddleware, type ContextEdit, type TokenCounter } from \"langchain\";\n * import type { BaseMessage } from \"@langchain/core/messages\";\n *\n * class CustomEdit implements ContextEdit {\n * async apply(params: {\n * tokens: number;\n * messages: BaseMessage[];\n * countTokens: TokenCounter;\n * }): Promise<number> {\n * // Implement your custom editing logic here\n * // and apply it to the messages array, then\n * // return the new token count after edits\n * return countTokens(messages);\n * }\n * }\n * ```\n *\n * @param config - Configuration options for the middleware\n * @returns A middleware instance that can be used with `createAgent`\n */\nexport function contextEditingMiddleware(\n config: ContextEditingMiddlewareConfig = {}\n) {\n const edits = config.edits ?? [new ClearToolUsesEdit()];\n const tokenCountMethod = config.tokenCountMethod ?? \"approx\";\n\n return createMiddleware({\n name: \"ContextEditingMiddleware\",\n wrapModelCall: async (request, handler) => {\n if (!request.messages || request.messages.length === 0) {\n return handler(request);\n }\n\n /**\n * Use model's token counting method\n */\n const systemMsg = request.systemPrompt\n ? [new SystemMessage(request.systemPrompt)]\n : [];\n\n const countTokens: TokenCounter =\n tokenCountMethod === \"approx\"\n ? countTokensApproximately\n : async (messages: BaseMessage[]): Promise<number> => {\n const allMessages = [...systemMsg, ...messages];\n\n /**\n * Check if model has getNumTokensFromMessages method\n * currently only OpenAI models have this method\n */\n if (\"getNumTokensFromMessages\" in request.model) {\n return (\n request.model as BaseLanguageModel & {\n getNumTokensFromMessages: (\n messages: BaseMessage[]\n ) => Promise<{\n totalCount: number;\n countPerMessage: number[];\n }>;\n }\n )\n .getNumTokensFromMessages(allMessages)\n .then(({ totalCount }) => totalCount);\n }\n\n throw new Error(\n `Model \"${request.model.getName()}\" does not support token counting`\n );\n };\n\n /**\n * Apply each edit in sequence\n */\n for (const edit of edits) {\n await edit.apply({\n messages: request.messages,\n model: request.model as BaseLanguageModel,\n countTokens,\n });\n }\n\n return handler(request);\n },\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"contextEditing.d.cts","names":[],"sources":["../../../src/agents/middleware/contextEditing.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsGA;;;;;;;;;;;;;;;;;;;;;AA+GA;;UA9IiB,WAAA;EAiJN;;;;;;;;;;;EArIT,KAAA,CAAM,MAAA;IAkI6C;;;IA9HjD,QAAA,EAAU,WAAA;IAiIH;;;IA7HP,WAAA,EAAa,YAAA;IA+Hf;;;IA3HE,KAAA,GAAQ,iBAAA;EAAA,WACC,OAAA;AAAA;;;;UAMI,uBAAA;EAqLT;;;;;;;;;;;AA+dR;;;;;;;;EAhoBE,OAAA,GAAU,WAAA,GAAc,WAAA;EA2wBV;;;;;;;;;;;;;;;;EAzvBd,IAAA,GAAO,QAAA;;;;;EAMP,eAAA;;;;;EAMA,YAAA;;;;;EAMA,WAAA;;;;EAKA,aAAA;;;;EAKA,YAAA;;;;;EAMA,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuCW,iBAAA,YAA6B,WAAA;EAAA;EAGxC,OAAA,EAAS,WAAA,GAAc,WAAA;EACvB,IAAA,EAAM,QAAA;EACN,eAAA;EACA,YAAA,EAAc,GAAA;EACd,WAAA;EACA,KAAA,EAAO,iBAAA;EACP,YAAA;EAEA,WAAA,CAAY,MAAA,GAAQ,uBAAA;EA2Dd,KAAA,CAAM,MAAA;IACV,QAAA,EAAU,WAAA;IACV,KAAA,EAAO,iBAAA;IACP,WAAA,EAAa,YAAA;EAAA,IACX,OAAA;AAAA;;;;UA2dW,8BAAA;;;;;EAKf,KAAA,GAAQ,WAAA;;;;;;;EAQR,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8Hc,wBAAA,CACd,MAAA,GAAQ,8BAAA,GAAmC,eAAA,0CAAA,wBAAA,CAAA,UAAA,GAAA,wBAAA,CAAA,UAAA"}
1
+ {"version":3,"file":"contextEditing.d.cts","names":[],"sources":["../../../src/agents/middleware/contextEditing.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsGA;;;;;;;;;;;;;;;;;;;;;AA+GA;;UA9IiB,WAAA;EAiJN;;;;;;;;;;;EArIT,KAAA,CAAM,MAAA;IAkI6C;;;IA9HjD,QAAA,EAAU,WAAA;IAiIH;;;IA7HP,WAAA,EAAa,YAAA;IA+Hf;;;IA3HE,KAAA,GAAQ,iBAAA;EAAA,WACC,OAAA;AAAA;;;;UAMI,uBAAA;EAqLT;;;;;;;;;;;AA8dR;;;;;;;;EA/nBE,OAAA,GAAU,WAAA,GAAc,WAAA;EA0wBV;;;;;;;;;;;;;;;;EAxvBd,IAAA,GAAO,QAAA;;;;;EAMP,eAAA;;;;;EAMA,YAAA;;;;;EAMA,WAAA;;;;EAKA,aAAA;;;;EAKA,YAAA;;;;;EAMA,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuCW,iBAAA,YAA6B,WAAA;EAAA;EAGxC,OAAA,EAAS,WAAA,GAAc,WAAA;EACvB,IAAA,EAAM,QAAA;EACN,eAAA;EACA,YAAA,EAAc,GAAA;EACd,WAAA;EACA,KAAA,EAAO,iBAAA;EACP,YAAA;EAEA,WAAA,CAAY,MAAA,GAAQ,uBAAA;EA2Dd,KAAA,CAAM,MAAA;IACV,QAAA,EAAU,WAAA;IACV,KAAA,EAAO,iBAAA;IACP,WAAA,EAAa,YAAA;EAAA,IACX,OAAA;AAAA;;;;UA0dW,8BAAA;;;;;EAKf,KAAA,GAAQ,WAAA;;;;;;;EAQR,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8Hc,wBAAA,CACd,MAAA,GAAQ,8BAAA,GAAmC,eAAA,0CAAA,wBAAA,CAAA,UAAA,GAAA,wBAAA,CAAA,UAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"contextEditing.d.ts","names":[],"sources":["../../../src/agents/middleware/contextEditing.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsGA;;;;;;;;;;;;;;;;;;;;;AA+GA;;UA9IiB,WAAA;EAiJN;;;;;;;;;;;EArIT,KAAA,CAAM,MAAA;IAkI6C;;;IA9HjD,QAAA,EAAU,WAAA;IAiIH;;;IA7HP,WAAA,EAAa,YAAA;IA+Hf;;;IA3HE,KAAA,GAAQ,iBAAA;EAAA,WACC,OAAA;AAAA;;;;UAMI,uBAAA;EAqLT;;;;;;;;;;;AA+dR;;;;;;;;EAhoBE,OAAA,GAAU,WAAA,GAAc,WAAA;EA2wBV;;;;;;;;;;;;;;;;EAzvBd,IAAA,GAAO,QAAA;;;;;EAMP,eAAA;;;;;EAMA,YAAA;;;;;EAMA,WAAA;;;;EAKA,aAAA;;;;EAKA,YAAA;;;;;EAMA,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuCW,iBAAA,YAA6B,WAAA;EAAA;EAGxC,OAAA,EAAS,WAAA,GAAc,WAAA;EACvB,IAAA,EAAM,QAAA;EACN,eAAA;EACA,YAAA,EAAc,GAAA;EACd,WAAA;EACA,KAAA,EAAO,iBAAA;EACP,YAAA;EAEA,WAAA,CAAY,MAAA,GAAQ,uBAAA;EA2Dd,KAAA,CAAM,MAAA;IACV,QAAA,EAAU,WAAA;IACV,KAAA,EAAO,iBAAA;IACP,WAAA,EAAa,YAAA;EAAA,IACX,OAAA;AAAA;;;;UA2dW,8BAAA;;;;;EAKf,KAAA,GAAQ,WAAA;;;;;;;EAQR,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8Hc,wBAAA,CACd,MAAA,GAAQ,8BAAA,GAAmC,eAAA,0CAAA,wBAAA,CAAA,UAAA,GAAA,wBAAA,CAAA,UAAA"}
1
+ {"version":3,"file":"contextEditing.d.ts","names":[],"sources":["../../../src/agents/middleware/contextEditing.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsGA;;;;;;;;;;;;;;;;;;;;;AA+GA;;UA9IiB,WAAA;EAiJN;;;;;;;;;;;EArIT,KAAA,CAAM,MAAA;IAkI6C;;;IA9HjD,QAAA,EAAU,WAAA;IAiIH;;;IA7HP,WAAA,EAAa,YAAA;IA+Hf;;;IA3HE,KAAA,GAAQ,iBAAA;EAAA,WACC,OAAA;AAAA;;;;UAMI,uBAAA;EAqLT;;;;;;;;;;;AA8dR;;;;;;;;EA/nBE,OAAA,GAAU,WAAA,GAAc,WAAA;EA0wBV;;;;;;;;;;;;;;;;EAxvBd,IAAA,GAAO,QAAA;;;;;EAMP,eAAA;;;;;EAMA,YAAA;;;;;EAMA,WAAA;;;;EAKA,aAAA;;;;EAKA,YAAA;;;;;EAMA,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuCW,iBAAA,YAA6B,WAAA;EAAA;EAGxC,OAAA,EAAS,WAAA,GAAc,WAAA;EACvB,IAAA,EAAM,QAAA;EACN,eAAA;EACA,YAAA,EAAc,GAAA;EACd,WAAA;EACA,KAAA,EAAO,iBAAA;EACP,YAAA;EAEA,WAAA,CAAY,MAAA,GAAQ,uBAAA;EA2Dd,KAAA,CAAM,MAAA;IACV,QAAA,EAAU,WAAA;IACV,KAAA,EAAO,iBAAA;IACP,WAAA,EAAa,YAAA;EAAA,IACX,OAAA;AAAA;;;;UA0dW,8BAAA;;;;;EAKf,KAAA,GAAQ,WAAA;;;;;;;EAQR,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8Hc,wBAAA,CACd,MAAA,GAAQ,8BAAA,GAAmC,eAAA,0CAAA,wBAAA,CAAA,UAAA,GAAA,wBAAA,CAAA,UAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"contextEditing.js","names":["#triggerConditions","#findAIMessageForToolCall","#shouldEdit","#determineKeepCount","#buildClearedToolInputMessage"],"sources":["../../../src/agents/middleware/contextEditing.ts"],"sourcesContent":["/**\n * Context editing middleware.\n *\n * This middleware mirrors Anthropic's context editing capabilities by clearing\n * older tool results once the conversation grows beyond a configurable token\n * threshold. The implementation is intentionally model-agnostic so it can be used\n * with any LangChain chat model.\n */\n\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport {\n AIMessage,\n ToolMessage,\n SystemMessage,\n} from \"@langchain/core/messages\";\n\nimport { countTokensApproximately } from \"./utils.js\";\nimport { createMiddleware } from \"../middleware.js\";\nimport {\n getProfileLimits,\n contextSizeSchema,\n keepSchema,\n type ContextSize,\n type KeepSize,\n type TokenCounter,\n} from \"./summarization.js\";\n\nconst DEFAULT_TOOL_PLACEHOLDER = \"[cleared]\";\nconst DEFAULT_TRIGGER_TOKENS = 100_000;\nconst DEFAULT_KEEP = 3;\n\n/**\n * Protocol describing a context editing strategy.\n *\n * Implement this interface to create custom strategies for managing\n * conversation context size. The `apply` method should modify the\n * messages array in-place and return the updated token count.\n *\n * @example\n * ```ts\n * import { HumanMessage, type ContextEdit, type BaseMessage } from \"langchain\";\n *\n * class RemoveOldHumanMessages implements ContextEdit {\n * constructor(private keepRecent: number = 10) {}\n *\n * async apply({ messages, countTokens }) {\n * // Check current token count\n * const tokens = await countTokens(messages);\n *\n * // Remove old human messages if over limit, keeping the most recent ones\n * if (tokens > 50000) {\n * const humanMessages: number[] = [];\n *\n * // Find all human message indices\n * for (let i = 0; i < messages.length; i++) {\n * if (HumanMessage.isInstance(messages[i])) {\n * humanMessages.push(i);\n * }\n * }\n *\n * // Remove old human messages (keep only the most recent N)\n * const toRemove = humanMessages.slice(0, -this.keepRecent);\n * for (let i = toRemove.length - 1; i >= 0; i--) {\n * messages.splice(toRemove[i]!, 1);\n * }\n * }\n * }\n * }\n * ```\n */\nexport interface ContextEdit {\n /**\n * Apply an edit to the message list, returning the new token count.\n *\n * This method should:\n * 1. Check if editing is needed based on `tokens` parameter\n * 2. Modify the `messages` array in-place (if needed)\n * 3. Return the new token count after modifications\n *\n * @param params - Parameters for the editing operation\n * @returns The updated token count after applying edits\n */\n apply(params: {\n /**\n * Array of messages to potentially edit (modify in-place)\n */\n messages: BaseMessage[];\n /**\n * Function to count tokens in a message array\n */\n countTokens: TokenCounter;\n /**\n * Optional model instance for model profile information\n */\n model?: BaseLanguageModel;\n }): void | Promise<void>;\n}\n\n/**\n * Configuration for clearing tool outputs when token limits are exceeded.\n */\nexport interface ClearToolUsesEditConfig {\n /**\n * Trigger conditions for context editing.\n * Can be a single condition object (all properties must be met) or an array of conditions (any condition must be met).\n *\n * @example\n * ```ts\n * // Single condition: trigger if tokens >= 100000 AND messages >= 50\n * trigger: { tokens: 100000, messages: 50 }\n *\n * // Multiple conditions: trigger if (tokens >= 100000 AND messages >= 50) OR (tokens >= 50000 AND messages >= 100)\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ]\n *\n * // Fractional trigger: trigger at 80% of model's max input tokens\n * trigger: { fraction: 0.8 }\n * ```\n */\n trigger?: ContextSize | ContextSize[];\n\n /**\n * Context retention policy applied after editing.\n * Specify how many tool results to preserve using messages, tokens, or fraction.\n *\n * @example\n * ```ts\n * // Keep 3 most recent tool results\n * keep: { messages: 3 }\n *\n * // Keep tool results that fit within 1000 tokens\n * keep: { tokens: 1000 }\n *\n * // Keep tool results that fit within 30% of model's max input tokens\n * keep: { fraction: 0.3 }\n * ```\n */\n keep?: KeepSize;\n\n /**\n * Whether to clear the originating tool call parameters on the AI message.\n * @default false\n */\n clearToolInputs?: boolean;\n\n /**\n * List of tool names to exclude from clearing.\n * @default []\n */\n excludeTools?: string[];\n\n /**\n * Placeholder text inserted for cleared tool outputs.\n * @default \"[cleared]\"\n */\n placeholder?: string;\n\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n triggerTokens?: number;\n\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n keepMessages?: number;\n\n /**\n * @deprecated This property is deprecated and will be removed in a future version.\n * Use `keep: { tokens: value }` or `keep: { messages: value }` instead to control retention.\n */\n clearAtLeast?: number;\n}\n\n/**\n * Strategy for clearing tool outputs when token limits are exceeded.\n *\n * This strategy mirrors Anthropic's `clear_tool_uses_20250919` behavior by\n * replacing older tool results with a placeholder text when the conversation\n * grows too large. It preserves the most recent tool results and can exclude\n * specific tools from being cleared.\n *\n * @example\n * ```ts\n * import { ClearToolUsesEdit } from \"langchain\";\n *\n * const edit = new ClearToolUsesEdit({\n * trigger: { tokens: 100000 }, // Start clearing at 100K tokens\n * keep: { messages: 3 }, // Keep 3 most recent tool results\n * excludeTools: [\"important\"], // Never clear \"important\" tool\n * clearToolInputs: false, // Keep tool call arguments\n * placeholder: \"[cleared]\", // Replacement text\n * });\n *\n * // Multiple trigger conditions\n * const edit2 = new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ],\n * keep: { messages: 3 },\n * });\n *\n * // Fractional trigger with model profile\n * const edit3 = new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * });\n * ```\n */\nexport class ClearToolUsesEdit implements ContextEdit {\n #triggerConditions: ContextSize[];\n\n trigger: ContextSize | ContextSize[];\n keep: KeepSize;\n clearToolInputs: boolean;\n excludeTools: Set<string>;\n placeholder: string;\n model: BaseLanguageModel;\n clearAtLeast: number;\n\n constructor(config: ClearToolUsesEditConfig = {}) {\n // Handle deprecated parameters\n let trigger: ContextSize | ContextSize[] | undefined = config.trigger;\n if (config.triggerTokens !== undefined) {\n console.warn(\n \"triggerTokens is deprecated. Use `trigger: { tokens: value }` instead.\"\n );\n if (trigger === undefined) {\n trigger = { tokens: config.triggerTokens };\n }\n }\n\n let keep: KeepSize | undefined = config.keep;\n if (config.keepMessages !== undefined) {\n console.warn(\n \"keepMessages is deprecated. Use `keep: { messages: value }` instead.\"\n );\n if (keep === undefined) {\n keep = { messages: config.keepMessages };\n }\n }\n\n // Set defaults\n if (trigger === undefined) {\n trigger = { tokens: DEFAULT_TRIGGER_TOKENS };\n }\n if (keep === undefined) {\n keep = { messages: DEFAULT_KEEP };\n }\n\n // Validate trigger conditions\n if (Array.isArray(trigger)) {\n this.#triggerConditions = trigger.map((t) => contextSizeSchema.parse(t));\n this.trigger = this.#triggerConditions;\n } else {\n const validated = contextSizeSchema.parse(trigger);\n this.#triggerConditions = [validated];\n this.trigger = validated;\n }\n\n // Validate keep\n const validatedKeep = keepSchema.parse(keep);\n this.keep = validatedKeep;\n\n // Handle deprecated clearAtLeast\n if (config.clearAtLeast !== undefined) {\n console.warn(\n \"clearAtLeast is deprecated and will be removed in a future version. \" +\n \"It conflicts with the `keep` property. Use `keep: { tokens: value }` or \" +\n \"`keep: { messages: value }` instead to control retention.\"\n );\n }\n this.clearAtLeast = config.clearAtLeast ?? 0;\n\n this.clearToolInputs = config.clearToolInputs ?? false;\n this.excludeTools = new Set(config.excludeTools ?? []);\n this.placeholder = config.placeholder ?? DEFAULT_TOOL_PLACEHOLDER;\n }\n\n async apply(params: {\n messages: BaseMessage[];\n model: BaseLanguageModel;\n countTokens: TokenCounter;\n }): Promise<void> {\n const { messages, model, countTokens } = params;\n const tokens = await countTokens(messages);\n\n /**\n * Always remove orphaned tool messages (those without corresponding AI messages)\n * regardless of whether editing is triggered\n */\n const orphanedIndices: number[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n // Check if this tool message has a corresponding AI message\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, i),\n msg.tool_call_id\n );\n\n if (!aiMessage) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n } else {\n // Check if the AI message actually has this tool call\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === msg.tool_call_id\n );\n if (!toolCall) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n }\n }\n }\n }\n\n /**\n * Remove orphaned tool messages in reverse order to maintain indices\n */\n for (let i = orphanedIndices.length - 1; i >= 0; i--) {\n messages.splice(orphanedIndices[i]!, 1);\n }\n\n /**\n * Recalculate tokens after removing orphaned messages\n */\n let currentTokens = tokens;\n if (orphanedIndices.length > 0) {\n currentTokens = await countTokens(messages);\n }\n\n /**\n * Check if editing should be triggered\n */\n if (!this.#shouldEdit(messages, currentTokens, model)) {\n return;\n }\n\n /**\n * Find all tool message candidates with their actual indices in the messages array\n */\n const candidates: { idx: number; msg: ToolMessage }[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n candidates.push({ idx: i, msg });\n }\n }\n\n if (candidates.length === 0) {\n return;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n const keepCount = await this.#determineKeepCount(\n candidates,\n countTokens,\n model\n );\n\n /**\n * Keep the most recent tool messages based on keep policy\n */\n const candidatesToClear =\n keepCount >= candidates.length\n ? []\n : keepCount > 0\n ? candidates.slice(0, -keepCount)\n : candidates;\n\n /**\n * If clearAtLeast is set, we may need to clear more messages to meet the token requirement\n * This is a deprecated feature that conflicts with keep, but we support it for backwards compatibility\n */\n let clearedTokens = 0;\n const initialCandidatesToClear = [...candidatesToClear];\n\n for (const { idx, msg: toolMessage } of initialCandidatesToClear) {\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata?.context_editing as\n | { cleared?: boolean }\n | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n\n /**\n * If clearAtLeast is set and we haven't cleared enough tokens,\n * continue clearing more messages (going backwards from keepCount)\n * This is deprecated behavior but maintained for backwards compatibility\n */\n if (this.clearAtLeast > 0 && clearedTokens < this.clearAtLeast) {\n /**\n * Find remaining candidates that weren't cleared yet (those that were kept)\n */\n const remainingCandidates =\n keepCount > 0 && keepCount < candidates.length\n ? candidates.slice(-keepCount)\n : [];\n\n /**\n * Clear additional messages until we've cleared at least clearAtLeast tokens\n * Go backwards through the kept messages\n */\n for (let i = remainingCandidates.length - 1; i >= 0; i--) {\n if (clearedTokens >= this.clearAtLeast) {\n break;\n }\n\n const { idx, msg: toolMessage } = remainingCandidates[i]!;\n\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata?.context_editing as\n | { cleared?: boolean }\n | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n }\n }\n\n /**\n * Determine whether editing should run for the current token usage\n */\n #shouldEdit(\n messages: BaseMessage[],\n totalTokens: number,\n model: BaseLanguageModel\n ): boolean {\n /**\n * Check each condition (OR logic between conditions)\n */\n for (const trigger of this.#triggerConditions) {\n /**\n * Within a single condition, all specified properties must be satisfied (AND logic)\n */\n let conditionMet = true;\n let hasAnyProperty = false;\n\n if (trigger.messages !== undefined) {\n hasAnyProperty = true;\n if (messages.length < trigger.messages) {\n conditionMet = false;\n }\n }\n\n if (trigger.tokens !== undefined) {\n hasAnyProperty = true;\n if (totalTokens < trigger.tokens) {\n conditionMet = false;\n }\n }\n\n if (trigger.fraction !== undefined) {\n hasAnyProperty = true;\n if (!model) {\n continue;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const threshold = Math.floor(maxInputTokens * trigger.fraction);\n if (threshold <= 0) {\n continue;\n }\n if (totalTokens < threshold) {\n conditionMet = false;\n }\n } else {\n /**\n * If fraction is specified but we can't get model limits, skip this condition\n */\n continue;\n }\n }\n\n /**\n * If condition has at least one property and all properties are satisfied, trigger editing\n */\n if (hasAnyProperty && conditionMet) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n async #determineKeepCount(\n candidates: Array<{ idx: number; msg: ToolMessage }>,\n countTokens: TokenCounter,\n model: BaseLanguageModel\n ): Promise<number> {\n if (\"messages\" in this.keep && this.keep.messages !== undefined) {\n return this.keep.messages;\n }\n\n if (\"tokens\" in this.keep && this.keep.tokens !== undefined) {\n /**\n * For token-based keep, count backwards from the end until we exceed the token limit\n * This is a simplified implementation - keeping N most recent tool messages\n * A more sophisticated implementation would count actual tokens\n */\n const targetTokens = this.keep.tokens;\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n /**\n * Estimate tokens for this tool message (simplified - could be improved)\n */\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n\n if (\"fraction\" in this.keep && this.keep.fraction !== undefined) {\n if (!model) {\n return DEFAULT_KEEP;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const targetTokens = Math.floor(maxInputTokens * this.keep.fraction);\n if (targetTokens <= 0) {\n return DEFAULT_KEEP;\n }\n /**\n * Use token-based logic with fractional target\n */\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n }\n\n return DEFAULT_KEEP;\n }\n\n #findAIMessageForToolCall(\n previousMessages: BaseMessage[],\n toolCallId: string\n ): AIMessage | null {\n // Search backwards through previous messages\n for (let i = previousMessages.length - 1; i >= 0; i--) {\n const msg = previousMessages[i];\n if (AIMessage.isInstance(msg)) {\n const hasToolCall = msg.tool_calls?.some(\n (call) => call.id === toolCallId\n );\n if (hasToolCall) {\n return msg;\n }\n }\n }\n return null;\n }\n\n #buildClearedToolInputMessage(\n message: AIMessage,\n toolCallId: string\n ): AIMessage {\n const updatedToolCalls = message.tool_calls?.map((toolCall) => {\n if (toolCall.id === toolCallId) {\n return { ...toolCall, args: {} };\n }\n return toolCall;\n });\n\n const metadata = { ...message.response_metadata };\n const contextEntry = {\n ...(metadata.context_editing as Record<string, unknown>),\n };\n\n const clearedIds = new Set<string>(\n contextEntry.cleared_tool_inputs as string[] | undefined\n );\n clearedIds.add(toolCallId);\n contextEntry.cleared_tool_inputs = Array.from(clearedIds).sort();\n metadata.context_editing = contextEntry;\n\n return new AIMessage({\n content: message.content,\n tool_calls: updatedToolCalls,\n response_metadata: metadata,\n id: message.id,\n name: message.name,\n additional_kwargs: message.additional_kwargs,\n });\n }\n}\n\n/**\n * Configuration for the Context Editing Middleware.\n */\nexport interface ContextEditingMiddlewareConfig {\n /**\n * Sequence of edit strategies to apply. Defaults to a single\n * ClearToolUsesEdit mirroring Anthropic defaults.\n */\n edits?: ContextEdit[];\n\n /**\n * Whether to use approximate token counting (faster, less accurate)\n * or exact counting implemented by the chat model (potentially slower, more accurate).\n * Currently only OpenAI models support exact counting.\n * @default \"approx\"\n */\n tokenCountMethod?: \"approx\" | \"model\";\n}\n\n/**\n * Middleware that automatically prunes tool results to manage context size.\n *\n * This middleware applies a sequence of edits when the total input token count\n * exceeds configured thresholds. By default, it uses the `ClearToolUsesEdit` strategy\n * which mirrors Anthropic's `clear_tool_uses_20250919` behaviour by clearing older\n * tool results once the conversation exceeds 100,000 tokens.\n *\n * ## Basic Usage\n *\n * Use the middleware with default settings to automatically manage context:\n *\n * @example Basic usage with defaults\n * ```ts\n * import { contextEditingMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware(),\n * ],\n * });\n * ```\n *\n * The default configuration:\n * - Triggers when context exceeds **100,000 tokens**\n * - Keeps the **3 most recent** tool results\n * - Uses **approximate token counting** (fast)\n * - Does not clear tool call arguments\n *\n * ## Custom Configuration\n *\n * Customize the clearing behavior with `ClearToolUsesEdit`:\n *\n * @example Custom ClearToolUsesEdit configuration\n * ```ts\n * import { contextEditingMiddleware, ClearToolUsesEdit } from \"langchain\";\n *\n * // Single condition: trigger if tokens >= 50000 AND messages >= 20\n * const agent1 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { tokens: 50000, messages: 20 },\n * keep: { messages: 5 },\n * excludeTools: [\"search\"],\n * clearToolInputs: true,\n * }),\n * ],\n * tokenCountMethod: \"approx\",\n * }),\n * ],\n * });\n *\n * // Multiple conditions: trigger if (tokens >= 50000 AND messages >= 20) OR (tokens >= 30000 AND messages >= 50)\n * const agent2 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 50000, messages: 20 },\n * { tokens: 30000, messages: 50 },\n * ],\n * keep: { messages: 5 },\n * }),\n * ],\n * }),\n * ],\n * });\n *\n * // Fractional trigger with model profile\n * const agent3 = createAgent({\n * model: chatModel,\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * model: chatModel,\n * }),\n * ],\n * }),\n * ],\n * });\n * ```\n *\n * ## Custom Editing Strategies\n *\n * Implement your own context editing strategy by creating a class that\n * implements the `ContextEdit` interface:\n *\n * @example Custom editing strategy\n * ```ts\n * import { contextEditingMiddleware, type ContextEdit, type TokenCounter } from \"langchain\";\n * import type { BaseMessage } from \"@langchain/core/messages\";\n *\n * class CustomEdit implements ContextEdit {\n * async apply(params: {\n * tokens: number;\n * messages: BaseMessage[];\n * countTokens: TokenCounter;\n * }): Promise<number> {\n * // Implement your custom editing logic here\n * // and apply it to the messages array, then\n * // return the new token count after edits\n * return countTokens(messages);\n * }\n * }\n * ```\n *\n * @param config - Configuration options for the middleware\n * @returns A middleware instance that can be used with `createAgent`\n */\nexport function contextEditingMiddleware(\n config: ContextEditingMiddlewareConfig = {}\n) {\n const edits = config.edits ?? [new ClearToolUsesEdit()];\n const tokenCountMethod = config.tokenCountMethod ?? \"approx\";\n\n return createMiddleware({\n name: \"ContextEditingMiddleware\",\n wrapModelCall: async (request, handler) => {\n if (!request.messages || request.messages.length === 0) {\n return handler(request);\n }\n\n /**\n * Use model's token counting method\n */\n const systemMsg = request.systemPrompt\n ? [new SystemMessage(request.systemPrompt)]\n : [];\n\n const countTokens: TokenCounter =\n tokenCountMethod === \"approx\"\n ? countTokensApproximately\n : async (messages: BaseMessage[]): Promise<number> => {\n const allMessages = [...systemMsg, ...messages];\n\n /**\n * Check if model has getNumTokensFromMessages method\n * currently only OpenAI models have this method\n */\n if (\"getNumTokensFromMessages\" in request.model) {\n return (\n request.model as BaseLanguageModel & {\n getNumTokensFromMessages: (\n messages: BaseMessage[]\n ) => Promise<{\n totalCount: number;\n countPerMessage: number[];\n }>;\n }\n )\n .getNumTokensFromMessages(allMessages)\n .then(({ totalCount }) => totalCount);\n }\n\n throw new Error(\n `Model \"${request.model.getName()}\" does not support token counting`\n );\n };\n\n /**\n * Apply each edit in sequence\n */\n for (const edit of edits) {\n await edit.apply({\n messages: request.messages,\n model: request.model as BaseLanguageModel,\n countTokens,\n });\n }\n\n return handler(request);\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contextEditing.js","names":["#triggerConditions","#findAIMessageForToolCall","#shouldEdit","#determineKeepCount","#buildClearedToolInputMessage"],"sources":["../../../src/agents/middleware/contextEditing.ts"],"sourcesContent":["/**\n * Context editing middleware.\n *\n * This middleware mirrors Anthropic's context editing capabilities by clearing\n * older tool results once the conversation grows beyond a configurable token\n * threshold. The implementation is intentionally model-agnostic so it can be used\n * with any LangChain chat model.\n */\n\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport {\n AIMessage,\n ToolMessage,\n SystemMessage,\n} from \"@langchain/core/messages\";\n\nimport { countTokensApproximately } from \"./utils.js\";\nimport { createMiddleware } from \"../middleware.js\";\nimport {\n getProfileLimits,\n contextSizeSchema,\n keepSchema,\n type ContextSize,\n type KeepSize,\n type TokenCounter,\n} from \"./summarization.js\";\n\nconst DEFAULT_TOOL_PLACEHOLDER = \"[cleared]\";\nconst DEFAULT_TRIGGER_TOKENS = 100_000;\nconst DEFAULT_KEEP = 3;\n\n/**\n * Protocol describing a context editing strategy.\n *\n * Implement this interface to create custom strategies for managing\n * conversation context size. The `apply` method should modify the\n * messages array in-place and return the updated token count.\n *\n * @example\n * ```ts\n * import { HumanMessage, type ContextEdit, type BaseMessage } from \"langchain\";\n *\n * class RemoveOldHumanMessages implements ContextEdit {\n * constructor(private keepRecent: number = 10) {}\n *\n * async apply({ messages, countTokens }) {\n * // Check current token count\n * const tokens = await countTokens(messages);\n *\n * // Remove old human messages if over limit, keeping the most recent ones\n * if (tokens > 50000) {\n * const humanMessages: number[] = [];\n *\n * // Find all human message indices\n * for (let i = 0; i < messages.length; i++) {\n * if (HumanMessage.isInstance(messages[i])) {\n * humanMessages.push(i);\n * }\n * }\n *\n * // Remove old human messages (keep only the most recent N)\n * const toRemove = humanMessages.slice(0, -this.keepRecent);\n * for (let i = toRemove.length - 1; i >= 0; i--) {\n * messages.splice(toRemove[i]!, 1);\n * }\n * }\n * }\n * }\n * ```\n */\nexport interface ContextEdit {\n /**\n * Apply an edit to the message list, returning the new token count.\n *\n * This method should:\n * 1. Check if editing is needed based on `tokens` parameter\n * 2. Modify the `messages` array in-place (if needed)\n * 3. Return the new token count after modifications\n *\n * @param params - Parameters for the editing operation\n * @returns The updated token count after applying edits\n */\n apply(params: {\n /**\n * Array of messages to potentially edit (modify in-place)\n */\n messages: BaseMessage[];\n /**\n * Function to count tokens in a message array\n */\n countTokens: TokenCounter;\n /**\n * Optional model instance for model profile information\n */\n model?: BaseLanguageModel;\n }): void | Promise<void>;\n}\n\n/**\n * Configuration for clearing tool outputs when token limits are exceeded.\n */\nexport interface ClearToolUsesEditConfig {\n /**\n * Trigger conditions for context editing.\n * Can be a single condition object (all properties must be met) or an array of conditions (any condition must be met).\n *\n * @example\n * ```ts\n * // Single condition: trigger if tokens >= 100000 AND messages >= 50\n * trigger: { tokens: 100000, messages: 50 }\n *\n * // Multiple conditions: trigger if (tokens >= 100000 AND messages >= 50) OR (tokens >= 50000 AND messages >= 100)\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ]\n *\n * // Fractional trigger: trigger at 80% of model's max input tokens\n * trigger: { fraction: 0.8 }\n * ```\n */\n trigger?: ContextSize | ContextSize[];\n\n /**\n * Context retention policy applied after editing.\n * Specify how many tool results to preserve using messages, tokens, or fraction.\n *\n * @example\n * ```ts\n * // Keep 3 most recent tool results\n * keep: { messages: 3 }\n *\n * // Keep tool results that fit within 1000 tokens\n * keep: { tokens: 1000 }\n *\n * // Keep tool results that fit within 30% of model's max input tokens\n * keep: { fraction: 0.3 }\n * ```\n */\n keep?: KeepSize;\n\n /**\n * Whether to clear the originating tool call parameters on the AI message.\n * @default false\n */\n clearToolInputs?: boolean;\n\n /**\n * List of tool names to exclude from clearing.\n * @default []\n */\n excludeTools?: string[];\n\n /**\n * Placeholder text inserted for cleared tool outputs.\n * @default \"[cleared]\"\n */\n placeholder?: string;\n\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n triggerTokens?: number;\n\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n keepMessages?: number;\n\n /**\n * @deprecated This property is deprecated and will be removed in a future version.\n * Use `keep: { tokens: value }` or `keep: { messages: value }` instead to control retention.\n */\n clearAtLeast?: number;\n}\n\n/**\n * Strategy for clearing tool outputs when token limits are exceeded.\n *\n * This strategy mirrors Anthropic's `clear_tool_uses_20250919` behavior by\n * replacing older tool results with a placeholder text when the conversation\n * grows too large. It preserves the most recent tool results and can exclude\n * specific tools from being cleared.\n *\n * @example\n * ```ts\n * import { ClearToolUsesEdit } from \"langchain\";\n *\n * const edit = new ClearToolUsesEdit({\n * trigger: { tokens: 100000 }, // Start clearing at 100K tokens\n * keep: { messages: 3 }, // Keep 3 most recent tool results\n * excludeTools: [\"important\"], // Never clear \"important\" tool\n * clearToolInputs: false, // Keep tool call arguments\n * placeholder: \"[cleared]\", // Replacement text\n * });\n *\n * // Multiple trigger conditions\n * const edit2 = new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 100000, messages: 50 },\n * { tokens: 50000, messages: 100 }\n * ],\n * keep: { messages: 3 },\n * });\n *\n * // Fractional trigger with model profile\n * const edit3 = new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * });\n * ```\n */\nexport class ClearToolUsesEdit implements ContextEdit {\n #triggerConditions: ContextSize[];\n\n trigger: ContextSize | ContextSize[];\n keep: KeepSize;\n clearToolInputs: boolean;\n excludeTools: Set<string>;\n placeholder: string;\n model: BaseLanguageModel;\n clearAtLeast: number;\n\n constructor(config: ClearToolUsesEditConfig = {}) {\n // Handle deprecated parameters\n let trigger: ContextSize | ContextSize[] | undefined = config.trigger;\n if (config.triggerTokens !== undefined) {\n console.warn(\n \"triggerTokens is deprecated. Use `trigger: { tokens: value }` instead.\"\n );\n if (trigger === undefined) {\n trigger = { tokens: config.triggerTokens };\n }\n }\n\n let keep: KeepSize | undefined = config.keep;\n if (config.keepMessages !== undefined) {\n console.warn(\n \"keepMessages is deprecated. Use `keep: { messages: value }` instead.\"\n );\n if (keep === undefined) {\n keep = { messages: config.keepMessages };\n }\n }\n\n // Set defaults\n if (trigger === undefined) {\n trigger = { tokens: DEFAULT_TRIGGER_TOKENS };\n }\n if (keep === undefined) {\n keep = { messages: DEFAULT_KEEP };\n }\n\n // Validate trigger conditions\n if (Array.isArray(trigger)) {\n this.#triggerConditions = trigger.map((t) => contextSizeSchema.parse(t));\n this.trigger = this.#triggerConditions;\n } else {\n const validated = contextSizeSchema.parse(trigger);\n this.#triggerConditions = [validated];\n this.trigger = validated;\n }\n\n // Validate keep\n const validatedKeep = keepSchema.parse(keep);\n this.keep = validatedKeep;\n\n // Handle deprecated clearAtLeast\n if (config.clearAtLeast !== undefined) {\n console.warn(\n \"clearAtLeast is deprecated and will be removed in a future version. \" +\n \"It conflicts with the `keep` property. Use `keep: { tokens: value }` or \" +\n \"`keep: { messages: value }` instead to control retention.\"\n );\n }\n this.clearAtLeast = config.clearAtLeast ?? 0;\n\n this.clearToolInputs = config.clearToolInputs ?? false;\n this.excludeTools = new Set(config.excludeTools ?? []);\n this.placeholder = config.placeholder ?? DEFAULT_TOOL_PLACEHOLDER;\n }\n\n async apply(params: {\n messages: BaseMessage[];\n model: BaseLanguageModel;\n countTokens: TokenCounter;\n }): Promise<void> {\n const { messages, model, countTokens } = params;\n const tokens = await countTokens(messages);\n\n /**\n * Always remove orphaned tool messages (those without corresponding AI messages)\n * regardless of whether editing is triggered\n */\n const orphanedIndices: number[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n // Check if this tool message has a corresponding AI message\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, i),\n msg.tool_call_id\n );\n\n if (!aiMessage) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n } else {\n // Check if the AI message actually has this tool call\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === msg.tool_call_id\n );\n if (!toolCall) {\n // Orphaned tool message - mark for removal\n orphanedIndices.push(i);\n }\n }\n }\n }\n\n /**\n * Remove orphaned tool messages in reverse order to maintain indices\n */\n for (let i = orphanedIndices.length - 1; i >= 0; i--) {\n messages.splice(orphanedIndices[i]!, 1);\n }\n\n /**\n * Recalculate tokens after removing orphaned messages\n */\n let currentTokens = tokens;\n if (orphanedIndices.length > 0) {\n currentTokens = await countTokens(messages);\n }\n\n /**\n * Check if editing should be triggered\n */\n if (!this.#shouldEdit(messages, currentTokens, model)) {\n return;\n }\n\n /**\n * Find all tool message candidates with their actual indices in the messages array\n */\n const candidates: { idx: number; msg: ToolMessage }[] = [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n candidates.push({ idx: i, msg });\n }\n }\n\n if (candidates.length === 0) {\n return;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n const keepCount = await this.#determineKeepCount(\n candidates,\n countTokens,\n model\n );\n\n /**\n * Keep the most recent tool messages based on keep policy\n */\n const candidatesToClear =\n keepCount >= candidates.length\n ? []\n : keepCount > 0\n ? candidates.slice(0, -keepCount)\n : candidates;\n\n /**\n * If clearAtLeast is set, we may need to clear more messages to meet the token requirement\n * This is a deprecated feature that conflicts with keep, but we support it for backwards compatibility\n */\n let clearedTokens = 0;\n const initialCandidatesToClear = [...candidatesToClear];\n\n for (const { idx, msg: toolMessage } of initialCandidatesToClear) {\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata?.context_editing as\n | { cleared?: boolean }\n | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n\n /**\n * If clearAtLeast is set and we haven't cleared enough tokens,\n * continue clearing more messages (going backwards from keepCount)\n * This is deprecated behavior but maintained for backwards compatibility\n */\n if (this.clearAtLeast > 0 && clearedTokens < this.clearAtLeast) {\n /**\n * Find remaining candidates that weren't cleared yet (those that were kept)\n */\n const remainingCandidates =\n keepCount > 0 && keepCount < candidates.length\n ? candidates.slice(-keepCount)\n : [];\n\n /**\n * Clear additional messages until we've cleared at least clearAtLeast tokens\n * Go backwards through the kept messages\n */\n for (let i = remainingCandidates.length - 1; i >= 0; i--) {\n if (clearedTokens >= this.clearAtLeast) {\n break;\n }\n\n const { idx, msg: toolMessage } = remainingCandidates[i]!;\n\n /**\n * Skip if already cleared\n */\n const contextEditing = toolMessage.response_metadata\n ?.context_editing as { cleared?: boolean } | undefined;\n if (contextEditing?.cleared) {\n continue;\n }\n\n /**\n * Find the corresponding AI message\n */\n const aiMessage = this.#findAIMessageForToolCall(\n messages.slice(0, idx),\n toolMessage.tool_call_id\n );\n\n if (!aiMessage) {\n continue;\n }\n\n /**\n * Find the corresponding tool call\n */\n const toolCall = aiMessage.tool_calls?.find(\n (call) => call.id === toolMessage.tool_call_id\n );\n\n if (!toolCall) {\n continue;\n }\n\n /**\n * Skip if tool is excluded\n */\n const toolName = toolMessage.name || toolCall.name;\n if (this.excludeTools.has(toolName)) {\n continue;\n }\n\n /**\n * Clear the tool message\n */\n messages[idx] = new ToolMessage({\n tool_call_id: toolMessage.tool_call_id,\n content: this.placeholder,\n name: toolMessage.name,\n artifact: undefined,\n response_metadata: {\n ...toolMessage.response_metadata,\n context_editing: {\n cleared: true,\n strategy: \"clear_tool_uses\",\n },\n },\n });\n\n /**\n * Optionally clear the tool inputs\n */\n if (this.clearToolInputs) {\n const aiMsgIdx = messages.indexOf(aiMessage);\n if (aiMsgIdx >= 0) {\n messages[aiMsgIdx] = this.#buildClearedToolInputMessage(\n aiMessage,\n toolMessage.tool_call_id\n );\n }\n }\n\n /**\n * Recalculate tokens\n */\n const newTokenCount = await countTokens(messages);\n clearedTokens = Math.max(0, currentTokens - newTokenCount);\n }\n }\n }\n\n /**\n * Determine whether editing should run for the current token usage\n */\n #shouldEdit(\n messages: BaseMessage[],\n totalTokens: number,\n model: BaseLanguageModel\n ): boolean {\n /**\n * Check each condition (OR logic between conditions)\n */\n for (const trigger of this.#triggerConditions) {\n /**\n * Within a single condition, all specified properties must be satisfied (AND logic)\n */\n let conditionMet = true;\n let hasAnyProperty = false;\n\n if (trigger.messages !== undefined) {\n hasAnyProperty = true;\n if (messages.length < trigger.messages) {\n conditionMet = false;\n }\n }\n\n if (trigger.tokens !== undefined) {\n hasAnyProperty = true;\n if (totalTokens < trigger.tokens) {\n conditionMet = false;\n }\n }\n\n if (trigger.fraction !== undefined) {\n hasAnyProperty = true;\n if (!model) {\n continue;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const threshold = Math.floor(maxInputTokens * trigger.fraction);\n if (threshold <= 0) {\n continue;\n }\n if (totalTokens < threshold) {\n conditionMet = false;\n }\n } else {\n /**\n * If fraction is specified but we can't get model limits, skip this condition\n */\n continue;\n }\n }\n\n /**\n * If condition has at least one property and all properties are satisfied, trigger editing\n */\n if (hasAnyProperty && conditionMet) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Determine how many tool results to keep based on keep policy\n */\n async #determineKeepCount(\n candidates: Array<{ idx: number; msg: ToolMessage }>,\n countTokens: TokenCounter,\n model: BaseLanguageModel\n ): Promise<number> {\n if (\"messages\" in this.keep && this.keep.messages !== undefined) {\n return this.keep.messages;\n }\n\n if (\"tokens\" in this.keep && this.keep.tokens !== undefined) {\n /**\n * For token-based keep, count backwards from the end until we exceed the token limit\n * This is a simplified implementation - keeping N most recent tool messages\n * A more sophisticated implementation would count actual tokens\n */\n const targetTokens = this.keep.tokens;\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n /**\n * Estimate tokens for this tool message (simplified - could be improved)\n */\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n\n if (\"fraction\" in this.keep && this.keep.fraction !== undefined) {\n if (!model) {\n return DEFAULT_KEEP;\n }\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const targetTokens = Math.floor(maxInputTokens * this.keep.fraction);\n if (targetTokens <= 0) {\n return DEFAULT_KEEP;\n }\n /**\n * Use token-based logic with fractional target\n */\n let tokenCount = 0;\n let keepCount = 0;\n\n for (let i = candidates.length - 1; i >= 0; i--) {\n const candidate = candidates[i];\n const msgTokens = await countTokens([candidate.msg]);\n if (tokenCount + msgTokens <= targetTokens) {\n tokenCount += msgTokens;\n keepCount++;\n } else {\n break;\n }\n }\n\n return keepCount;\n }\n }\n\n return DEFAULT_KEEP;\n }\n\n #findAIMessageForToolCall(\n previousMessages: BaseMessage[],\n toolCallId: string\n ): AIMessage | null {\n // Search backwards through previous messages\n for (let i = previousMessages.length - 1; i >= 0; i--) {\n const msg = previousMessages[i];\n if (AIMessage.isInstance(msg)) {\n const hasToolCall = msg.tool_calls?.some(\n (call) => call.id === toolCallId\n );\n if (hasToolCall) {\n return msg;\n }\n }\n }\n return null;\n }\n\n #buildClearedToolInputMessage(\n message: AIMessage,\n toolCallId: string\n ): AIMessage {\n const updatedToolCalls = message.tool_calls?.map((toolCall) => {\n if (toolCall.id === toolCallId) {\n return { ...toolCall, args: {} };\n }\n return toolCall;\n });\n\n const metadata = { ...message.response_metadata };\n const contextEntry = {\n ...(metadata.context_editing as Record<string, unknown>),\n };\n\n const clearedIds = new Set<string>(\n contextEntry.cleared_tool_inputs as string[] | undefined\n );\n clearedIds.add(toolCallId);\n contextEntry.cleared_tool_inputs = Array.from(clearedIds).sort();\n metadata.context_editing = contextEntry;\n\n return new AIMessage({\n content: message.content,\n tool_calls: updatedToolCalls,\n response_metadata: metadata,\n id: message.id,\n name: message.name,\n additional_kwargs: message.additional_kwargs,\n });\n }\n}\n\n/**\n * Configuration for the Context Editing Middleware.\n */\nexport interface ContextEditingMiddlewareConfig {\n /**\n * Sequence of edit strategies to apply. Defaults to a single\n * ClearToolUsesEdit mirroring Anthropic defaults.\n */\n edits?: ContextEdit[];\n\n /**\n * Whether to use approximate token counting (faster, less accurate)\n * or exact counting implemented by the chat model (potentially slower, more accurate).\n * Currently only OpenAI models support exact counting.\n * @default \"approx\"\n */\n tokenCountMethod?: \"approx\" | \"model\";\n}\n\n/**\n * Middleware that automatically prunes tool results to manage context size.\n *\n * This middleware applies a sequence of edits when the total input token count\n * exceeds configured thresholds. By default, it uses the `ClearToolUsesEdit` strategy\n * which mirrors Anthropic's `clear_tool_uses_20250919` behaviour by clearing older\n * tool results once the conversation exceeds 100,000 tokens.\n *\n * ## Basic Usage\n *\n * Use the middleware with default settings to automatically manage context:\n *\n * @example Basic usage with defaults\n * ```ts\n * import { contextEditingMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware(),\n * ],\n * });\n * ```\n *\n * The default configuration:\n * - Triggers when context exceeds **100,000 tokens**\n * - Keeps the **3 most recent** tool results\n * - Uses **approximate token counting** (fast)\n * - Does not clear tool call arguments\n *\n * ## Custom Configuration\n *\n * Customize the clearing behavior with `ClearToolUsesEdit`:\n *\n * @example Custom ClearToolUsesEdit configuration\n * ```ts\n * import { contextEditingMiddleware, ClearToolUsesEdit } from \"langchain\";\n *\n * // Single condition: trigger if tokens >= 50000 AND messages >= 20\n * const agent1 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { tokens: 50000, messages: 20 },\n * keep: { messages: 5 },\n * excludeTools: [\"search\"],\n * clearToolInputs: true,\n * }),\n * ],\n * tokenCountMethod: \"approx\",\n * }),\n * ],\n * });\n *\n * // Multiple conditions: trigger if (tokens >= 50000 AND messages >= 20) OR (tokens >= 30000 AND messages >= 50)\n * const agent2 = createAgent({\n * model: \"anthropic:claude-sonnet-4-5\",\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: [\n * { tokens: 50000, messages: 20 },\n * { tokens: 30000, messages: 50 },\n * ],\n * keep: { messages: 5 },\n * }),\n * ],\n * }),\n * ],\n * });\n *\n * // Fractional trigger with model profile\n * const agent3 = createAgent({\n * model: chatModel,\n * tools: [searchTool, calculatorTool],\n * middleware: [\n * contextEditingMiddleware({\n * edits: [\n * new ClearToolUsesEdit({\n * trigger: { fraction: 0.8 }, // Trigger at 80% of model's max tokens\n * keep: { fraction: 0.3 }, // Keep 30% of model's max tokens\n * model: chatModel,\n * }),\n * ],\n * }),\n * ],\n * });\n * ```\n *\n * ## Custom Editing Strategies\n *\n * Implement your own context editing strategy by creating a class that\n * implements the `ContextEdit` interface:\n *\n * @example Custom editing strategy\n * ```ts\n * import { contextEditingMiddleware, type ContextEdit, type TokenCounter } from \"langchain\";\n * import type { BaseMessage } from \"@langchain/core/messages\";\n *\n * class CustomEdit implements ContextEdit {\n * async apply(params: {\n * tokens: number;\n * messages: BaseMessage[];\n * countTokens: TokenCounter;\n * }): Promise<number> {\n * // Implement your custom editing logic here\n * // and apply it to the messages array, then\n * // return the new token count after edits\n * return countTokens(messages);\n * }\n * }\n * ```\n *\n * @param config - Configuration options for the middleware\n * @returns A middleware instance that can be used with `createAgent`\n */\nexport function contextEditingMiddleware(\n config: ContextEditingMiddlewareConfig = {}\n) {\n const edits = config.edits ?? [new ClearToolUsesEdit()];\n const tokenCountMethod = config.tokenCountMethod ?? \"approx\";\n\n return createMiddleware({\n name: \"ContextEditingMiddleware\",\n wrapModelCall: async (request, handler) => {\n if (!request.messages || request.messages.length === 0) {\n return handler(request);\n }\n\n /**\n * Use model's token counting method\n */\n const systemMsg = request.systemPrompt\n ? [new SystemMessage(request.systemPrompt)]\n : [];\n\n const countTokens: TokenCounter =\n tokenCountMethod === \"approx\"\n ? countTokensApproximately\n : async (messages: BaseMessage[]): Promise<number> => {\n const allMessages = [...systemMsg, ...messages];\n\n /**\n * Check if model has getNumTokensFromMessages method\n * currently only OpenAI models have this method\n */\n if (\"getNumTokensFromMessages\" in request.model) {\n return (\n request.model as BaseLanguageModel & {\n getNumTokensFromMessages: (\n messages: BaseMessage[]\n ) => Promise<{\n totalCount: number;\n countPerMessage: number[];\n }>;\n }\n )\n .getNumTokensFromMessages(allMessages)\n .then(({ totalCount }) => totalCount);\n }\n\n throw new Error(\n `Model \"${request.model.getName()}\" does not support token counting`\n );\n };\n\n /**\n * Apply each edit in sequence\n */\n for (const edit of edits) {\n await edit.apply({\n messages: request.messages,\n model: request.model as BaseLanguageModel,\n countTokens,\n });\n }\n\n return handler(request);\n },\n });\n}\n"],"mappings":"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"}