langchain 1.2.24 → 1.2.25

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 (325) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/_virtual/{rolldown_runtime.cjs → _rolldown/runtime.cjs} +24 -13
  3. package/dist/_virtual/_rolldown/runtime.js +36 -0
  4. package/dist/agents/ReactAgent.cjs +52 -65
  5. package/dist/agents/ReactAgent.cjs.map +1 -1
  6. package/dist/agents/ReactAgent.d.cts.map +1 -1
  7. package/dist/agents/ReactAgent.d.ts.map +1 -1
  8. package/dist/agents/ReactAgent.js +11 -24
  9. package/dist/agents/ReactAgent.js.map +1 -1
  10. package/dist/agents/RunnableCallable.cjs +7 -7
  11. package/dist/agents/RunnableCallable.cjs.map +1 -1
  12. package/dist/agents/RunnableCallable.js.map +1 -1
  13. package/dist/agents/annotation.cjs +41 -37
  14. package/dist/agents/annotation.cjs.map +1 -1
  15. package/dist/agents/annotation.js +21 -17
  16. package/dist/agents/annotation.js.map +1 -1
  17. package/dist/agents/constants.d.cts.map +1 -1
  18. package/dist/agents/constants.d.ts.map +1 -1
  19. package/dist/agents/errors.cjs +3 -3
  20. package/dist/agents/errors.cjs.map +1 -1
  21. package/dist/agents/errors.d.cts.map +1 -1
  22. package/dist/agents/errors.d.ts.map +1 -1
  23. package/dist/agents/errors.js.map +1 -1
  24. package/dist/agents/index.cjs.map +1 -1
  25. package/dist/agents/index.d.cts +2 -2
  26. package/dist/agents/index.d.cts.map +1 -1
  27. package/dist/agents/index.d.ts +2 -2
  28. package/dist/agents/index.d.ts.map +1 -1
  29. package/dist/agents/index.js.map +1 -1
  30. package/dist/agents/middleware/constants.cjs +2 -2
  31. package/dist/agents/middleware/constants.cjs.map +1 -1
  32. package/dist/agents/middleware/constants.js.map +1 -1
  33. package/dist/agents/middleware/contextEditing.cjs +14 -27
  34. package/dist/agents/middleware/contextEditing.cjs.map +1 -1
  35. package/dist/agents/middleware/contextEditing.d.cts +2 -3
  36. package/dist/agents/middleware/contextEditing.d.cts.map +1 -1
  37. package/dist/agents/middleware/contextEditing.d.ts +2 -3
  38. package/dist/agents/middleware/contextEditing.d.ts.map +1 -1
  39. package/dist/agents/middleware/contextEditing.js +5 -18
  40. package/dist/agents/middleware/contextEditing.js.map +1 -1
  41. package/dist/agents/middleware/dynamicSystemPrompt.cjs +3 -4
  42. package/dist/agents/middleware/dynamicSystemPrompt.cjs.map +1 -1
  43. package/dist/agents/middleware/dynamicSystemPrompt.d.cts +2 -2
  44. package/dist/agents/middleware/dynamicSystemPrompt.d.cts.map +1 -1
  45. package/dist/agents/middleware/dynamicSystemPrompt.d.ts +2 -2
  46. package/dist/agents/middleware/dynamicSystemPrompt.d.ts.map +1 -1
  47. package/dist/agents/middleware/dynamicSystemPrompt.js +1 -2
  48. package/dist/agents/middleware/dynamicSystemPrompt.js.map +1 -1
  49. package/dist/agents/middleware/error.cjs +2 -2
  50. package/dist/agents/middleware/error.cjs.map +1 -1
  51. package/dist/agents/middleware/error.js.map +1 -1
  52. package/dist/agents/middleware/hitl.cjs +16 -26
  53. package/dist/agents/middleware/hitl.cjs.map +1 -1
  54. package/dist/agents/middleware/hitl.d.cts.map +1 -1
  55. package/dist/agents/middleware/hitl.d.ts.map +1 -1
  56. package/dist/agents/middleware/hitl.js +8 -18
  57. package/dist/agents/middleware/hitl.js.map +1 -1
  58. package/dist/agents/middleware/index.js +2 -0
  59. package/dist/agents/middleware/llmToolSelector.cjs +9 -10
  60. package/dist/agents/middleware/llmToolSelector.cjs.map +1 -1
  61. package/dist/agents/middleware/llmToolSelector.d.cts +4 -4
  62. package/dist/agents/middleware/llmToolSelector.d.cts.map +1 -1
  63. package/dist/agents/middleware/llmToolSelector.d.ts +4 -4
  64. package/dist/agents/middleware/llmToolSelector.d.ts.map +1 -1
  65. package/dist/agents/middleware/llmToolSelector.js +3 -4
  66. package/dist/agents/middleware/llmToolSelector.js.map +1 -1
  67. package/dist/agents/middleware/modelCallLimit.cjs +5 -5
  68. package/dist/agents/middleware/modelCallLimit.cjs.map +1 -1
  69. package/dist/agents/middleware/modelCallLimit.d.cts +2 -2
  70. package/dist/agents/middleware/modelCallLimit.d.cts.map +1 -1
  71. package/dist/agents/middleware/modelCallLimit.d.ts +2 -2
  72. package/dist/agents/middleware/modelCallLimit.d.ts.map +1 -1
  73. package/dist/agents/middleware/modelCallLimit.js.map +1 -1
  74. package/dist/agents/middleware/modelFallback.cjs.map +1 -1
  75. package/dist/agents/middleware/modelFallback.d.cts +0 -1
  76. package/dist/agents/middleware/modelFallback.d.cts.map +1 -1
  77. package/dist/agents/middleware/modelFallback.d.ts +0 -1
  78. package/dist/agents/middleware/modelFallback.d.ts.map +1 -1
  79. package/dist/agents/middleware/modelFallback.js.map +1 -1
  80. package/dist/agents/middleware/modelRetry.cjs +19 -17
  81. package/dist/agents/middleware/modelRetry.cjs.map +1 -1
  82. package/dist/agents/middleware/modelRetry.d.cts +0 -1
  83. package/dist/agents/middleware/modelRetry.d.cts.map +1 -1
  84. package/dist/agents/middleware/modelRetry.d.ts +0 -1
  85. package/dist/agents/middleware/modelRetry.d.ts.map +1 -1
  86. package/dist/agents/middleware/modelRetry.js +15 -13
  87. package/dist/agents/middleware/modelRetry.js.map +1 -1
  88. package/dist/agents/middleware/pii.cjs +21 -32
  89. package/dist/agents/middleware/pii.cjs.map +1 -1
  90. package/dist/agents/middleware/pii.d.cts +0 -1
  91. package/dist/agents/middleware/pii.d.cts.map +1 -1
  92. package/dist/agents/middleware/pii.d.ts +0 -1
  93. package/dist/agents/middleware/pii.d.ts.map +1 -1
  94. package/dist/agents/middleware/pii.js +10 -21
  95. package/dist/agents/middleware/pii.js.map +1 -1
  96. package/dist/agents/middleware/piiRedaction.cjs +22 -28
  97. package/dist/agents/middleware/piiRedaction.cjs.map +1 -1
  98. package/dist/agents/middleware/piiRedaction.d.cts +0 -1
  99. package/dist/agents/middleware/piiRedaction.d.cts.map +1 -1
  100. package/dist/agents/middleware/piiRedaction.d.ts +0 -1
  101. package/dist/agents/middleware/piiRedaction.d.ts.map +1 -1
  102. package/dist/agents/middleware/piiRedaction.js +8 -14
  103. package/dist/agents/middleware/piiRedaction.js.map +1 -1
  104. package/dist/agents/middleware/provider/anthropic/promptCaching.cjs +5 -8
  105. package/dist/agents/middleware/provider/anthropic/promptCaching.cjs.map +1 -1
  106. package/dist/agents/middleware/provider/anthropic/promptCaching.d.cts +2 -2
  107. package/dist/agents/middleware/provider/anthropic/promptCaching.d.cts.map +1 -1
  108. package/dist/agents/middleware/provider/anthropic/promptCaching.d.ts +2 -2
  109. package/dist/agents/middleware/provider/anthropic/promptCaching.d.ts.map +1 -1
  110. package/dist/agents/middleware/provider/anthropic/promptCaching.js +3 -6
  111. package/dist/agents/middleware/provider/anthropic/promptCaching.js.map +1 -1
  112. package/dist/agents/middleware/provider/openai/moderation.cjs +17 -22
  113. package/dist/agents/middleware/provider/openai/moderation.cjs.map +1 -1
  114. package/dist/agents/middleware/provider/openai/moderation.d.cts +0 -2
  115. package/dist/agents/middleware/provider/openai/moderation.d.cts.map +1 -1
  116. package/dist/agents/middleware/provider/openai/moderation.d.ts +0 -2
  117. package/dist/agents/middleware/provider/openai/moderation.d.ts.map +1 -1
  118. package/dist/agents/middleware/provider/openai/moderation.js +10 -15
  119. package/dist/agents/middleware/provider/openai/moderation.js.map +1 -1
  120. package/dist/agents/middleware/summarization.cjs +39 -62
  121. package/dist/agents/middleware/summarization.cjs.map +1 -1
  122. package/dist/agents/middleware/summarization.d.cts +2 -2
  123. package/dist/agents/middleware/summarization.d.cts.map +1 -1
  124. package/dist/agents/middleware/summarization.d.ts +2 -2
  125. package/dist/agents/middleware/summarization.d.ts.map +1 -1
  126. package/dist/agents/middleware/summarization.js +17 -40
  127. package/dist/agents/middleware/summarization.js.map +1 -1
  128. package/dist/agents/middleware/todoListMiddleware.cjs +21 -27
  129. package/dist/agents/middleware/todoListMiddleware.cjs.map +1 -1
  130. package/dist/agents/middleware/todoListMiddleware.d.cts +4 -4
  131. package/dist/agents/middleware/todoListMiddleware.d.cts.map +1 -1
  132. package/dist/agents/middleware/todoListMiddleware.d.ts +4 -4
  133. package/dist/agents/middleware/todoListMiddleware.d.ts.map +1 -1
  134. package/dist/agents/middleware/todoListMiddleware.js +12 -18
  135. package/dist/agents/middleware/todoListMiddleware.js.map +1 -1
  136. package/dist/agents/middleware/toolCallLimit.cjs +24 -46
  137. package/dist/agents/middleware/toolCallLimit.cjs.map +1 -1
  138. package/dist/agents/middleware/toolCallLimit.d.cts +2 -3
  139. package/dist/agents/middleware/toolCallLimit.d.cts.map +1 -1
  140. package/dist/agents/middleware/toolCallLimit.d.ts +2 -3
  141. package/dist/agents/middleware/toolCallLimit.d.ts.map +1 -1
  142. package/dist/agents/middleware/toolCallLimit.js +17 -39
  143. package/dist/agents/middleware/toolCallLimit.js.map +1 -1
  144. package/dist/agents/middleware/toolEmulator.cjs +8 -13
  145. package/dist/agents/middleware/toolEmulator.cjs.map +1 -1
  146. package/dist/agents/middleware/toolEmulator.d.cts +0 -1
  147. package/dist/agents/middleware/toolEmulator.d.cts.map +1 -1
  148. package/dist/agents/middleware/toolEmulator.d.ts +0 -1
  149. package/dist/agents/middleware/toolEmulator.d.ts.map +1 -1
  150. package/dist/agents/middleware/toolEmulator.js +5 -10
  151. package/dist/agents/middleware/toolEmulator.js.map +1 -1
  152. package/dist/agents/middleware/toolRetry.cjs +19 -17
  153. package/dist/agents/middleware/toolRetry.cjs.map +1 -1
  154. package/dist/agents/middleware/toolRetry.d.cts +0 -1
  155. package/dist/agents/middleware/toolRetry.d.cts.map +1 -1
  156. package/dist/agents/middleware/toolRetry.d.ts +0 -1
  157. package/dist/agents/middleware/toolRetry.d.ts.map +1 -1
  158. package/dist/agents/middleware/toolRetry.js +15 -13
  159. package/dist/agents/middleware/toolRetry.js.map +1 -1
  160. package/dist/agents/middleware/types.cjs.map +1 -1
  161. package/dist/agents/middleware/types.d.cts +33 -33
  162. package/dist/agents/middleware/types.d.cts.map +1 -1
  163. package/dist/agents/middleware/types.d.ts +33 -33
  164. package/dist/agents/middleware/types.d.ts.map +1 -1
  165. package/dist/agents/middleware/types.js.map +1 -1
  166. package/dist/agents/middleware/utils.cjs +8 -8
  167. package/dist/agents/middleware/utils.cjs.map +1 -1
  168. package/dist/agents/middleware/utils.d.cts +0 -1
  169. package/dist/agents/middleware/utils.d.cts.map +1 -1
  170. package/dist/agents/middleware/utils.d.ts +0 -1
  171. package/dist/agents/middleware/utils.d.ts.map +1 -1
  172. package/dist/agents/middleware/utils.js +3 -3
  173. package/dist/agents/middleware/utils.js.map +1 -1
  174. package/dist/agents/middleware.cjs +1 -2
  175. package/dist/agents/middleware.cjs.map +1 -1
  176. package/dist/agents/middleware.d.cts +0 -1
  177. package/dist/agents/middleware.d.cts.map +1 -1
  178. package/dist/agents/middleware.d.ts +0 -1
  179. package/dist/agents/middleware.d.ts.map +1 -1
  180. package/dist/agents/middleware.js +1 -2
  181. package/dist/agents/middleware.js.map +1 -1
  182. package/dist/agents/model.cjs.map +1 -1
  183. package/dist/agents/model.js.map +1 -1
  184. package/dist/agents/nodes/AfterAgentNode.cjs +1 -2
  185. package/dist/agents/nodes/AfterAgentNode.cjs.map +1 -1
  186. package/dist/agents/nodes/AfterAgentNode.js +1 -2
  187. package/dist/agents/nodes/AfterAgentNode.js.map +1 -1
  188. package/dist/agents/nodes/AfterModelNode.cjs +1 -2
  189. package/dist/agents/nodes/AfterModelNode.cjs.map +1 -1
  190. package/dist/agents/nodes/AfterModelNode.js +1 -2
  191. package/dist/agents/nodes/AfterModelNode.js.map +1 -1
  192. package/dist/agents/nodes/AgentNode.cjs +46 -58
  193. package/dist/agents/nodes/AgentNode.cjs.map +1 -1
  194. package/dist/agents/nodes/AgentNode.js +16 -28
  195. package/dist/agents/nodes/AgentNode.js.map +1 -1
  196. package/dist/agents/nodes/BeforeAgentNode.cjs +1 -2
  197. package/dist/agents/nodes/BeforeAgentNode.cjs.map +1 -1
  198. package/dist/agents/nodes/BeforeAgentNode.js +1 -2
  199. package/dist/agents/nodes/BeforeAgentNode.js.map +1 -1
  200. package/dist/agents/nodes/BeforeModelNode.cjs +1 -2
  201. package/dist/agents/nodes/BeforeModelNode.cjs.map +1 -1
  202. package/dist/agents/nodes/BeforeModelNode.js +1 -2
  203. package/dist/agents/nodes/BeforeModelNode.js.map +1 -1
  204. package/dist/agents/nodes/ToolNode.cjs +25 -25
  205. package/dist/agents/nodes/ToolNode.cjs.map +1 -1
  206. package/dist/agents/nodes/ToolNode.js +6 -6
  207. package/dist/agents/nodes/ToolNode.js.map +1 -1
  208. package/dist/agents/nodes/middleware.cjs +3 -3
  209. package/dist/agents/nodes/middleware.cjs.map +1 -1
  210. package/dist/agents/nodes/middleware.js.map +1 -1
  211. package/dist/agents/nodes/types.d.cts +0 -1
  212. package/dist/agents/nodes/types.d.cts.map +1 -1
  213. package/dist/agents/nodes/types.d.ts +0 -1
  214. package/dist/agents/nodes/types.d.ts.map +1 -1
  215. package/dist/agents/nodes/utils.cjs +16 -17
  216. package/dist/agents/nodes/utils.cjs.map +1 -1
  217. package/dist/agents/nodes/utils.js +2 -3
  218. package/dist/agents/nodes/utils.js.map +1 -1
  219. package/dist/agents/responses.cjs +20 -30
  220. package/dist/agents/responses.cjs.map +1 -1
  221. package/dist/agents/responses.d.cts +0 -1
  222. package/dist/agents/responses.d.cts.map +1 -1
  223. package/dist/agents/responses.d.ts +0 -1
  224. package/dist/agents/responses.d.ts.map +1 -1
  225. package/dist/agents/responses.js +12 -22
  226. package/dist/agents/responses.js.map +1 -1
  227. package/dist/agents/runtime.d.cts +0 -1
  228. package/dist/agents/runtime.d.cts.map +1 -1
  229. package/dist/agents/runtime.d.ts +0 -1
  230. package/dist/agents/runtime.d.ts.map +1 -1
  231. package/dist/agents/state.cjs +1 -2
  232. package/dist/agents/state.cjs.map +1 -1
  233. package/dist/agents/state.js +1 -2
  234. package/dist/agents/state.js.map +1 -1
  235. package/dist/agents/tests/utils.cjs +21 -26
  236. package/dist/agents/tests/utils.cjs.map +1 -1
  237. package/dist/agents/tests/utils.d.cts +0 -1
  238. package/dist/agents/tests/utils.d.cts.map +1 -1
  239. package/dist/agents/tests/utils.d.ts +0 -1
  240. package/dist/agents/tests/utils.d.ts.map +1 -1
  241. package/dist/agents/tests/utils.js +12 -17
  242. package/dist/agents/tests/utils.js.map +1 -1
  243. package/dist/agents/types.d.cts +4 -5
  244. package/dist/agents/types.d.cts.map +1 -1
  245. package/dist/agents/types.d.ts +4 -5
  246. package/dist/agents/types.d.ts.map +1 -1
  247. package/dist/agents/utils.cjs +32 -32
  248. package/dist/agents/utils.cjs.map +1 -1
  249. package/dist/agents/utils.js +6 -6
  250. package/dist/agents/utils.js.map +1 -1
  251. package/dist/agents/withAgentName.cjs +5 -5
  252. package/dist/agents/withAgentName.cjs.map +1 -1
  253. package/dist/agents/withAgentName.js.map +1 -1
  254. package/dist/chat_models/universal.cjs +34 -41
  255. package/dist/chat_models/universal.cjs.map +1 -1
  256. package/dist/chat_models/universal.d.cts.map +1 -1
  257. package/dist/chat_models/universal.d.ts.map +1 -1
  258. package/dist/chat_models/universal.js +21 -29
  259. package/dist/chat_models/universal.js.map +1 -1
  260. package/dist/hub/base.cjs +3 -4
  261. package/dist/hub/base.cjs.map +1 -1
  262. package/dist/hub/base.d.cts +0 -1
  263. package/dist/hub/base.d.cts.map +1 -1
  264. package/dist/hub/base.d.ts +0 -1
  265. package/dist/hub/base.d.ts.map +1 -1
  266. package/dist/hub/base.js +1 -2
  267. package/dist/hub/base.js.map +1 -1
  268. package/dist/hub/index.cjs +2 -2
  269. package/dist/hub/index.cjs.map +1 -1
  270. package/dist/hub/index.d.cts +0 -1
  271. package/dist/hub/index.d.cts.map +1 -1
  272. package/dist/hub/index.d.ts +0 -1
  273. package/dist/hub/index.d.ts.map +1 -1
  274. package/dist/hub/index.js +1 -2
  275. package/dist/hub/index.js.map +1 -1
  276. package/dist/hub/node.cjs +7 -13
  277. package/dist/hub/node.cjs.map +1 -1
  278. package/dist/hub/node.d.cts +0 -1
  279. package/dist/hub/node.d.cts.map +1 -1
  280. package/dist/hub/node.d.ts +0 -1
  281. package/dist/hub/node.d.ts.map +1 -1
  282. package/dist/hub/node.js +6 -13
  283. package/dist/hub/node.js.map +1 -1
  284. package/dist/index.cjs +48 -48
  285. package/dist/index.d.cts +2 -1
  286. package/dist/index.d.ts +2 -1
  287. package/dist/index.js +2 -3
  288. package/dist/load/import_constants.cjs.map +1 -1
  289. package/dist/load/import_constants.js.map +1 -1
  290. package/dist/load/import_map.cjs +46 -47
  291. package/dist/load/import_map.cjs.map +1 -1
  292. package/dist/load/import_map.js +2 -3
  293. package/dist/load/import_map.js.map +1 -1
  294. package/dist/load/import_type.d.cts.map +1 -1
  295. package/dist/load/import_type.d.ts.map +1 -1
  296. package/dist/load/index.cjs +13 -3
  297. package/dist/load/index.cjs.map +1 -1
  298. package/dist/load/index.d.cts +9 -1
  299. package/dist/load/index.d.cts.map +1 -1
  300. package/dist/load/index.d.ts +9 -1
  301. package/dist/load/index.d.ts.map +1 -1
  302. package/dist/load/index.js +9 -0
  303. package/dist/load/index.js.map +1 -1
  304. package/dist/load/serializable.cjs +7 -6
  305. package/dist/load/serializable.js +4 -4
  306. package/dist/storage/encoder_backed.cjs +9 -10
  307. package/dist/storage/encoder_backed.cjs.map +1 -1
  308. package/dist/storage/encoder_backed.d.cts +0 -1
  309. package/dist/storage/encoder_backed.d.cts.map +1 -1
  310. package/dist/storage/encoder_backed.d.ts +0 -1
  311. package/dist/storage/encoder_backed.d.ts.map +1 -1
  312. package/dist/storage/encoder_backed.js +4 -6
  313. package/dist/storage/encoder_backed.js.map +1 -1
  314. package/dist/storage/file_system.cjs +12 -11
  315. package/dist/storage/file_system.cjs.map +1 -1
  316. package/dist/storage/file_system.d.cts +0 -1
  317. package/dist/storage/file_system.d.cts.map +1 -1
  318. package/dist/storage/file_system.d.ts +0 -1
  319. package/dist/storage/file_system.d.ts.map +1 -1
  320. package/dist/storage/file_system.js +5 -7
  321. package/dist/storage/file_system.js.map +1 -1
  322. package/dist/storage/in_memory.cjs +5 -5
  323. package/dist/storage/in_memory.js +2 -3
  324. package/package.json +6 -6
  325. package/dist/_virtual/rolldown_runtime.js +0 -25
@@ -1,8 +1,8 @@
1
- const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
1
+ const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
2
2
  const require_utils = require('./utils.cjs');
3
3
  const require_middleware = require('../middleware.cjs');
4
4
  const require_summarization = require('./summarization.cjs');
5
- const __langchain_core_messages = require_rolldown_runtime.__toESM(require("@langchain/core/messages"));
5
+ let _langchain_core_messages = require("@langchain/core/messages");
6
6
 
7
7
  //#region src/agents/middleware/contextEditing.ts
8
8
  const DEFAULT_TOOL_PLACEHOLDER = "[cleared]";
@@ -74,8 +74,7 @@ var ClearToolUsesEdit = class {
74
74
  this.#triggerConditions = [validated];
75
75
  this.trigger = validated;
76
76
  }
77
- const validatedKeep = require_summarization.keepSchema.parse(keep);
78
- this.keep = validatedKeep;
77
+ this.keep = require_summarization.keepSchema.parse(keep);
79
78
  if (config.clearAtLeast !== void 0) console.warn("clearAtLeast is deprecated and will be removed in a future version. It conflicts with the `keep` property. Use `keep: { tokens: value }` or `keep: { messages: value }` instead to control retention.");
80
79
  this.clearAtLeast = config.clearAtLeast ?? 0;
81
80
  this.clearToolInputs = config.clearToolInputs ?? false;
@@ -92,13 +91,10 @@ var ClearToolUsesEdit = class {
92
91
  const orphanedIndices = [];
93
92
  for (let i = 0; i < messages.length; i++) {
94
93
  const msg = messages[i];
95
- if (__langchain_core_messages.ToolMessage.isInstance(msg)) {
94
+ if (_langchain_core_messages.ToolMessage.isInstance(msg)) {
96
95
  const aiMessage = this.#findAIMessageForToolCall(messages.slice(0, i), msg.tool_call_id);
97
96
  if (!aiMessage) orphanedIndices.push(i);
98
- else {
99
- const toolCall = aiMessage.tool_calls?.find((call) => call.id === msg.tool_call_id);
100
- if (!toolCall) orphanedIndices.push(i);
101
- }
97
+ else if (!aiMessage.tool_calls?.find((call) => call.id === msg.tool_call_id)) orphanedIndices.push(i);
102
98
  }
103
99
  }
104
100
  /**
@@ -120,7 +116,7 @@ var ClearToolUsesEdit = class {
120
116
  const candidates = [];
121
117
  for (let i = 0; i < messages.length; i++) {
122
118
  const msg = messages[i];
123
- if (__langchain_core_messages.ToolMessage.isInstance(msg)) candidates.push({
119
+ if (_langchain_core_messages.ToolMessage.isInstance(msg)) candidates.push({
124
120
  idx: i,
125
121
  msg
126
122
  });
@@ -141,11 +137,7 @@ var ClearToolUsesEdit = class {
141
137
  let clearedTokens = 0;
142
138
  const initialCandidatesToClear = [...candidatesToClear];
143
139
  for (const { idx, msg: toolMessage } of initialCandidatesToClear) {
144
- /**
145
- * Skip if already cleared
146
- */
147
- const contextEditing = toolMessage.response_metadata?.context_editing;
148
- if (contextEditing?.cleared) continue;
140
+ if ((toolMessage.response_metadata?.context_editing)?.cleared) continue;
149
141
  /**
150
142
  * Find the corresponding AI message
151
143
  */
@@ -164,7 +156,7 @@ var ClearToolUsesEdit = class {
164
156
  /**
165
157
  * Clear the tool message
166
158
  */
167
- messages[idx] = new __langchain_core_messages.ToolMessage({
159
+ messages[idx] = new _langchain_core_messages.ToolMessage({
168
160
  tool_call_id: toolMessage.tool_call_id,
169
161
  content: this.placeholder,
170
162
  name: toolMessage.name,
@@ -207,11 +199,7 @@ var ClearToolUsesEdit = class {
207
199
  for (let i = remainingCandidates.length - 1; i >= 0; i--) {
208
200
  if (clearedTokens >= this.clearAtLeast) break;
209
201
  const { idx, msg: toolMessage } = remainingCandidates[i];
210
- /**
211
- * Skip if already cleared
212
- */
213
- const contextEditing = toolMessage.response_metadata?.context_editing;
214
- if (contextEditing?.cleared) continue;
202
+ if ((toolMessage.response_metadata?.context_editing)?.cleared) continue;
215
203
  /**
216
204
  * Find the corresponding AI message
217
205
  */
@@ -230,7 +218,7 @@ var ClearToolUsesEdit = class {
230
218
  /**
231
219
  * Clear the tool message
232
220
  */
233
- messages[idx] = new __langchain_core_messages.ToolMessage({
221
+ messages[idx] = new _langchain_core_messages.ToolMessage({
234
222
  tool_call_id: toolMessage.tool_call_id,
235
223
  content: this.placeholder,
236
224
  name: toolMessage.name,
@@ -354,9 +342,8 @@ var ClearToolUsesEdit = class {
354
342
  #findAIMessageForToolCall(previousMessages, toolCallId) {
355
343
  for (let i = previousMessages.length - 1; i >= 0; i--) {
356
344
  const msg = previousMessages[i];
357
- if (__langchain_core_messages.AIMessage.isInstance(msg)) {
358
- const hasToolCall = msg.tool_calls?.some((call) => call.id === toolCallId);
359
- if (hasToolCall) return msg;
345
+ if (_langchain_core_messages.AIMessage.isInstance(msg)) {
346
+ if (msg.tool_calls?.some((call) => call.id === toolCallId)) return msg;
360
347
  }
361
348
  }
362
349
  return null;
@@ -375,7 +362,7 @@ var ClearToolUsesEdit = class {
375
362
  clearedIds.add(toolCallId);
376
363
  contextEntry.cleared_tool_inputs = Array.from(clearedIds).sort();
377
364
  metadata.context_editing = contextEntry;
378
- return new __langchain_core_messages.AIMessage({
365
+ return new _langchain_core_messages.AIMessage({
379
366
  content: message.content,
380
367
  tool_calls: updatedToolCalls,
381
368
  response_metadata: metadata,
@@ -518,7 +505,7 @@ function contextEditingMiddleware(config = {}) {
518
505
  /**
519
506
  * Use model's token counting method
520
507
  */
521
- const systemMsg = request.systemPrompt ? [new __langchain_core_messages.SystemMessage(request.systemPrompt)] : [];
508
+ const systemMsg = request.systemPrompt ? [new _langchain_core_messages.SystemMessage(request.systemPrompt)] : [];
522
509
  const countTokens = tokenCountMethod === "approx" ? require_utils.countTokensApproximately : async (messages) => {
523
510
  const allMessages = [...systemMsg, ...messages];
524
511
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"contextEditing.cjs","names":["config: ClearToolUsesEditConfig","trigger: ContextSize | ContextSize[] | undefined","keep: KeepSize | undefined","#triggerConditions","contextSizeSchema","keepSchema","params: {\n messages: BaseMessage[];\n model: BaseLanguageModel;\n countTokens: TokenCounter;\n }","orphanedIndices: number[]","ToolMessage","#findAIMessageForToolCall","#shouldEdit","candidates: { idx: number; msg: ToolMessage }[]","#determineKeepCount","#buildClearedToolInputMessage","messages: BaseMessage[]","totalTokens: number","model: BaseLanguageModel","getProfileLimits","candidates: Array<{ idx: number; msg: ToolMessage }>","countTokens: TokenCounter","previousMessages: BaseMessage[]","toolCallId: string","AIMessage","message: AIMessage","config: ContextEditingMiddlewareConfig","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
+ {"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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"}
@@ -2,10 +2,9 @@ import { AgentMiddleware } from "./types.cjs";
2
2
  import { ContextSize, KeepSize, TokenCounter } from "./summarization.cjs";
3
3
  import { BaseLanguageModel } from "@langchain/core/language_models/base";
4
4
  import { BaseMessage } from "@langchain/core/messages";
5
- import * as _langchain_core_tools5 from "@langchain/core/tools";
5
+ import * as _langchain_core_tools0 from "@langchain/core/tools";
6
6
 
7
7
  //#region src/agents/middleware/contextEditing.d.ts
8
-
9
8
  /**
10
9
  * Protocol describing a context editing strategy.
11
10
  *
@@ -334,7 +333,7 @@ interface ContextEditingMiddlewareConfig {
334
333
  * @param config - Configuration options for the middleware
335
334
  * @returns A middleware instance that can be used with `createAgent`
336
335
  */
337
- declare function contextEditingMiddleware(config?: ContextEditingMiddlewareConfig): AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools5.ServerTool | _langchain_core_tools5.ClientTool)[]>;
336
+ declare function contextEditingMiddleware(config?: ContextEditingMiddlewareConfig): AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools0.ServerTool | _langchain_core_tools0.ClientTool)[]>;
338
337
  //#endregion
339
338
  export { ClearToolUsesEdit, ClearToolUsesEditConfig, ContextEdit, ContextEditingMiddlewareConfig, contextEditingMiddleware };
340
339
  //# sourceMappingURL=contextEditing.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contextEditing.d.cts","names":["__types_js10","BaseMessage","BaseLanguageModel","ContextSize","KeepSize","TokenCounter","ContextEdit","Promise","ClearToolUsesEditConfig","ClearToolUsesEdit","Set","ContextEditingMiddlewareConfig","contextEditingMiddleware","_langchain_core_tools5","ServerTool","ClientTool","AgentMiddleware"],"sources":["../../../src/agents/middleware/contextEditing.d.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 */\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport { type ContextSize, type KeepSize, type TokenCounter } from \"./summarization.js\";\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 * 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 * 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 * Whether to clear the originating tool call parameters on the AI message.\n * @default false\n */\n clearToolInputs?: boolean;\n /**\n * List of tool names to exclude from clearing.\n * @default []\n */\n excludeTools?: string[];\n /**\n * Placeholder text inserted for cleared tool outputs.\n * @default \"[cleared]\"\n */\n placeholder?: string;\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n triggerTokens?: number;\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n keepMessages?: number;\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 * 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 declare class ClearToolUsesEdit implements ContextEdit {\n #private;\n trigger: ContextSize | ContextSize[];\n keep: KeepSize;\n clearToolInputs: boolean;\n excludeTools: Set<string>;\n placeholder: string;\n model: BaseLanguageModel;\n clearAtLeast: number;\n constructor(config?: ClearToolUsesEditConfig);\n apply(params: {\n messages: BaseMessage[];\n model: BaseLanguageModel;\n countTokens: TokenCounter;\n }): Promise<void>;\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 * 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 * 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 declare function contextEditingMiddleware(config?: ContextEditingMiddlewareConfig): import(\"./types.js\").AgentMiddleware<undefined, undefined, unknown, readonly (import(\"@langchain/core/tools\").ServerTool | import(\"@langchain/core/tools\").ClientTool)[]>;\n//# sourceMappingURL=contextEditing.d.ts.map"],"mappings":";;;;;;;;;AA2EsB;AAKtB;;;;AAqCmB;AAkEnB;;;;;;;;;;;;AAA6D;AAmB7D;AAyIA;;;;;AAA+H;;;;;;;;;;;;;UAjS9GM,WAAAA;;;;;;;;;;;;;;;;cAgBCL;;;;iBAIGI;;;;YAILH;aACDK;;;;;UAKEC,uBAAAA;;;;;;;;;;;;;;;;;;;;YAoBHL,cAAcA;;;;;;;;;;;;;;;;;SAiBjBC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkEUK,iBAAAA,YAA6BH;;WAErCH,cAAcA;QACjBC;;gBAEQM;;SAEPR;;uBAEcM;;cAEPP;WACHC;iBACMG;MACbE;;;;;UAKSI,8BAAAA;;;;;UAKLL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoIYM,wBAAAA,UAAkCD,0FAA8BE,sBAAAA,CAAiHC,UAAAA,GAAUD,sBAAAA,CAAmCE"}
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,sBAAA,CAAA,UAAA,GAAA,sBAAA,CAAA,UAAA"}
@@ -1,11 +1,10 @@
1
1
  import { AgentMiddleware } from "./types.js";
2
2
  import { ContextSize, KeepSize, TokenCounter } from "./summarization.js";
3
3
  import { BaseMessage } from "@langchain/core/messages";
4
- import * as _langchain_core_tools5 from "@langchain/core/tools";
4
+ import * as _langchain_core_tools0 from "@langchain/core/tools";
5
5
  import { BaseLanguageModel } from "@langchain/core/language_models/base";
6
6
 
7
7
  //#region src/agents/middleware/contextEditing.d.ts
8
-
9
8
  /**
10
9
  * Protocol describing a context editing strategy.
11
10
  *
@@ -334,7 +333,7 @@ interface ContextEditingMiddlewareConfig {
334
333
  * @param config - Configuration options for the middleware
335
334
  * @returns A middleware instance that can be used with `createAgent`
336
335
  */
337
- declare function contextEditingMiddleware(config?: ContextEditingMiddlewareConfig): AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools5.ServerTool | _langchain_core_tools5.ClientTool)[]>;
336
+ declare function contextEditingMiddleware(config?: ContextEditingMiddlewareConfig): AgentMiddleware<undefined, undefined, unknown, readonly (_langchain_core_tools0.ServerTool | _langchain_core_tools0.ClientTool)[]>;
338
337
  //#endregion
339
338
  export { ClearToolUsesEdit, ClearToolUsesEditConfig, ContextEdit, ContextEditingMiddlewareConfig, contextEditingMiddleware };
340
339
  //# sourceMappingURL=contextEditing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contextEditing.d.ts","names":["__types_js10","BaseMessage","BaseLanguageModel","ContextSize","KeepSize","TokenCounter","ContextEdit","Promise","ClearToolUsesEditConfig","ClearToolUsesEdit","Set","ContextEditingMiddlewareConfig","contextEditingMiddleware","_langchain_core_tools5","ServerTool","ClientTool","AgentMiddleware"],"sources":["../../../src/agents/middleware/contextEditing.d.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 */\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport { type ContextSize, type KeepSize, type TokenCounter } from \"./summarization.js\";\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 * 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 * 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 * Whether to clear the originating tool call parameters on the AI message.\n * @default false\n */\n clearToolInputs?: boolean;\n /**\n * List of tool names to exclude from clearing.\n * @default []\n */\n excludeTools?: string[];\n /**\n * Placeholder text inserted for cleared tool outputs.\n * @default \"[cleared]\"\n */\n placeholder?: string;\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n triggerTokens?: number;\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n keepMessages?: number;\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 * 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 declare class ClearToolUsesEdit implements ContextEdit {\n #private;\n trigger: ContextSize | ContextSize[];\n keep: KeepSize;\n clearToolInputs: boolean;\n excludeTools: Set<string>;\n placeholder: string;\n model: BaseLanguageModel;\n clearAtLeast: number;\n constructor(config?: ClearToolUsesEditConfig);\n apply(params: {\n messages: BaseMessage[];\n model: BaseLanguageModel;\n countTokens: TokenCounter;\n }): Promise<void>;\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 * 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 * 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 declare function contextEditingMiddleware(config?: ContextEditingMiddlewareConfig): import(\"./types.js\").AgentMiddleware<undefined, undefined, unknown, readonly (import(\"@langchain/core/tools\").ServerTool | import(\"@langchain/core/tools\").ClientTool)[]>;\n//# sourceMappingURL=contextEditing.d.ts.map"],"mappings":";;;;;;;;;AA2EsB;AAKtB;;;;AAqCmB;AAkEnB;;;;;;;;;;;;AAA6D;AAmB7D;AAyIA;;;;;AAA+H;;;;;;;;;;;;;UAjS9GM,WAAAA;;;;;;;;;;;;;;;;cAgBCL;;;;iBAIGI;;;;YAILH;aACDK;;;;;UAKEC,uBAAAA;;;;;;;;;;;;;;;;;;;;YAoBHL,cAAcA;;;;;;;;;;;;;;;;;SAiBjBC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkEUK,iBAAAA,YAA6BH;;WAErCH,cAAcA;QACjBC;;gBAEQM;;SAEPR;;uBAEcM;;cAEPP;WACHC;iBACMG;MACbE;;;;;UAKSI,8BAAAA;;;;;UAKLL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoIYM,wBAAAA,UAAkCD,0FAA8BE,sBAAAA,CAAiHC,UAAAA,GAAUD,sBAAAA,CAAmCE"}
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,sBAAA,CAAA,UAAA,GAAA,sBAAA,CAAA,UAAA"}
@@ -73,8 +73,7 @@ var ClearToolUsesEdit = class {
73
73
  this.#triggerConditions = [validated];
74
74
  this.trigger = validated;
75
75
  }
76
- const validatedKeep = keepSchema.parse(keep);
77
- this.keep = validatedKeep;
76
+ this.keep = keepSchema.parse(keep);
78
77
  if (config.clearAtLeast !== void 0) console.warn("clearAtLeast is deprecated and will be removed in a future version. It conflicts with the `keep` property. Use `keep: { tokens: value }` or `keep: { messages: value }` instead to control retention.");
79
78
  this.clearAtLeast = config.clearAtLeast ?? 0;
80
79
  this.clearToolInputs = config.clearToolInputs ?? false;
@@ -94,10 +93,7 @@ var ClearToolUsesEdit = class {
94
93
  if (ToolMessage.isInstance(msg)) {
95
94
  const aiMessage = this.#findAIMessageForToolCall(messages.slice(0, i), msg.tool_call_id);
96
95
  if (!aiMessage) orphanedIndices.push(i);
97
- else {
98
- const toolCall = aiMessage.tool_calls?.find((call) => call.id === msg.tool_call_id);
99
- if (!toolCall) orphanedIndices.push(i);
100
- }
96
+ else if (!aiMessage.tool_calls?.find((call) => call.id === msg.tool_call_id)) orphanedIndices.push(i);
101
97
  }
102
98
  }
103
99
  /**
@@ -140,11 +136,7 @@ var ClearToolUsesEdit = class {
140
136
  let clearedTokens = 0;
141
137
  const initialCandidatesToClear = [...candidatesToClear];
142
138
  for (const { idx, msg: toolMessage } of initialCandidatesToClear) {
143
- /**
144
- * Skip if already cleared
145
- */
146
- const contextEditing = toolMessage.response_metadata?.context_editing;
147
- if (contextEditing?.cleared) continue;
139
+ if ((toolMessage.response_metadata?.context_editing)?.cleared) continue;
148
140
  /**
149
141
  * Find the corresponding AI message
150
142
  */
@@ -206,11 +198,7 @@ var ClearToolUsesEdit = class {
206
198
  for (let i = remainingCandidates.length - 1; i >= 0; i--) {
207
199
  if (clearedTokens >= this.clearAtLeast) break;
208
200
  const { idx, msg: toolMessage } = remainingCandidates[i];
209
- /**
210
- * Skip if already cleared
211
- */
212
- const contextEditing = toolMessage.response_metadata?.context_editing;
213
- if (contextEditing?.cleared) continue;
201
+ if ((toolMessage.response_metadata?.context_editing)?.cleared) continue;
214
202
  /**
215
203
  * Find the corresponding AI message
216
204
  */
@@ -354,8 +342,7 @@ var ClearToolUsesEdit = class {
354
342
  for (let i = previousMessages.length - 1; i >= 0; i--) {
355
343
  const msg = previousMessages[i];
356
344
  if (AIMessage.isInstance(msg)) {
357
- const hasToolCall = msg.tool_calls?.some((call) => call.id === toolCallId);
358
- if (hasToolCall) return msg;
345
+ if (msg.tool_calls?.some((call) => call.id === toolCallId)) return msg;
359
346
  }
360
347
  }
361
348
  return null;