@librechat/agents 3.1.75 → 3.1.77-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/dist/cjs/graphs/Graph.cjs +22 -3
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/hitl/askUserQuestion.cjs +67 -0
  4. package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -0
  5. package/dist/cjs/hooks/HookRegistry.cjs +54 -0
  6. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  7. package/dist/cjs/hooks/createToolPolicyHook.cjs +115 -0
  8. package/dist/cjs/hooks/createToolPolicyHook.cjs.map +1 -0
  9. package/dist/cjs/hooks/executeHooks.cjs +40 -1
  10. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  11. package/dist/cjs/hooks/types.cjs +1 -0
  12. package/dist/cjs/hooks/types.cjs.map +1 -1
  13. package/dist/cjs/langchain/google-common.cjs +3 -0
  14. package/dist/cjs/langchain/google-common.cjs.map +1 -0
  15. package/dist/cjs/langchain/index.cjs +86 -0
  16. package/dist/cjs/langchain/index.cjs.map +1 -0
  17. package/dist/cjs/langchain/language_models/chat_models.cjs +3 -0
  18. package/dist/cjs/langchain/language_models/chat_models.cjs.map +1 -0
  19. package/dist/cjs/langchain/messages/tool.cjs +3 -0
  20. package/dist/cjs/langchain/messages/tool.cjs.map +1 -0
  21. package/dist/cjs/langchain/messages.cjs +51 -0
  22. package/dist/cjs/langchain/messages.cjs.map +1 -0
  23. package/dist/cjs/langchain/openai.cjs +3 -0
  24. package/dist/cjs/langchain/openai.cjs.map +1 -0
  25. package/dist/cjs/langchain/prompts.cjs +11 -0
  26. package/dist/cjs/langchain/prompts.cjs.map +1 -0
  27. package/dist/cjs/langchain/runnables.cjs +19 -0
  28. package/dist/cjs/langchain/runnables.cjs.map +1 -0
  29. package/dist/cjs/langchain/tools.cjs +23 -0
  30. package/dist/cjs/langchain/tools.cjs.map +1 -0
  31. package/dist/cjs/langchain/utils/env.cjs +11 -0
  32. package/dist/cjs/langchain/utils/env.cjs.map +1 -0
  33. package/dist/cjs/llm/anthropic/index.cjs +145 -52
  34. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  35. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  36. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +21 -14
  37. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  38. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +84 -70
  39. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  40. package/dist/cjs/llm/bedrock/index.cjs +1 -1
  41. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  42. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +213 -3
  43. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  44. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +2 -1
  45. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  46. package/dist/cjs/llm/google/utils/common.cjs +5 -4
  47. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  48. package/dist/cjs/llm/openai/index.cjs +519 -655
  49. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  50. package/dist/cjs/llm/openai/utils/index.cjs +20 -458
  51. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  52. package/dist/cjs/llm/openrouter/index.cjs +57 -175
  53. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  54. package/dist/cjs/llm/vertexai/index.cjs +5 -3
  55. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  56. package/dist/cjs/main.cjs +112 -3
  57. package/dist/cjs/main.cjs.map +1 -1
  58. package/dist/cjs/messages/cache.cjs +2 -1
  59. package/dist/cjs/messages/cache.cjs.map +1 -1
  60. package/dist/cjs/messages/core.cjs +7 -6
  61. package/dist/cjs/messages/core.cjs.map +1 -1
  62. package/dist/cjs/messages/format.cjs +73 -15
  63. package/dist/cjs/messages/format.cjs.map +1 -1
  64. package/dist/cjs/messages/langchain.cjs +26 -0
  65. package/dist/cjs/messages/langchain.cjs.map +1 -0
  66. package/dist/cjs/messages/prune.cjs +7 -6
  67. package/dist/cjs/messages/prune.cjs.map +1 -1
  68. package/dist/cjs/run.cjs +400 -42
  69. package/dist/cjs/run.cjs.map +1 -1
  70. package/dist/cjs/tools/ToolNode.cjs +556 -56
  71. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  72. package/dist/cjs/tools/search/search.cjs +55 -66
  73. package/dist/cjs/tools/search/search.cjs.map +1 -1
  74. package/dist/cjs/tools/search/tavily-scraper.cjs +189 -0
  75. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -0
  76. package/dist/cjs/tools/search/tavily-search.cjs +372 -0
  77. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -0
  78. package/dist/cjs/tools/search/tool.cjs +26 -4
  79. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  80. package/dist/cjs/tools/search/utils.cjs +10 -3
  81. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  82. package/dist/esm/graphs/Graph.mjs +22 -3
  83. package/dist/esm/graphs/Graph.mjs.map +1 -1
  84. package/dist/esm/hitl/askUserQuestion.mjs +65 -0
  85. package/dist/esm/hitl/askUserQuestion.mjs.map +1 -0
  86. package/dist/esm/hooks/HookRegistry.mjs +54 -0
  87. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  88. package/dist/esm/hooks/createToolPolicyHook.mjs +113 -0
  89. package/dist/esm/hooks/createToolPolicyHook.mjs.map +1 -0
  90. package/dist/esm/hooks/executeHooks.mjs +40 -1
  91. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  92. package/dist/esm/hooks/types.mjs +1 -0
  93. package/dist/esm/hooks/types.mjs.map +1 -1
  94. package/dist/esm/langchain/google-common.mjs +2 -0
  95. package/dist/esm/langchain/google-common.mjs.map +1 -0
  96. package/dist/esm/langchain/index.mjs +5 -0
  97. package/dist/esm/langchain/index.mjs.map +1 -0
  98. package/dist/esm/langchain/language_models/chat_models.mjs +2 -0
  99. package/dist/esm/langchain/language_models/chat_models.mjs.map +1 -0
  100. package/dist/esm/langchain/messages/tool.mjs +2 -0
  101. package/dist/esm/langchain/messages/tool.mjs.map +1 -0
  102. package/dist/esm/langchain/messages.mjs +2 -0
  103. package/dist/esm/langchain/messages.mjs.map +1 -0
  104. package/dist/esm/langchain/openai.mjs +2 -0
  105. package/dist/esm/langchain/openai.mjs.map +1 -0
  106. package/dist/esm/langchain/prompts.mjs +2 -0
  107. package/dist/esm/langchain/prompts.mjs.map +1 -0
  108. package/dist/esm/langchain/runnables.mjs +2 -0
  109. package/dist/esm/langchain/runnables.mjs.map +1 -0
  110. package/dist/esm/langchain/tools.mjs +2 -0
  111. package/dist/esm/langchain/tools.mjs.map +1 -0
  112. package/dist/esm/langchain/utils/env.mjs +2 -0
  113. package/dist/esm/langchain/utils/env.mjs.map +1 -0
  114. package/dist/esm/llm/anthropic/index.mjs +146 -54
  115. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  116. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  117. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +21 -14
  118. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  119. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +84 -71
  120. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  121. package/dist/esm/llm/bedrock/index.mjs +1 -1
  122. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  123. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +214 -4
  124. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  125. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +2 -1
  126. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  127. package/dist/esm/llm/google/utils/common.mjs +5 -4
  128. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  129. package/dist/esm/llm/openai/index.mjs +520 -656
  130. package/dist/esm/llm/openai/index.mjs.map +1 -1
  131. package/dist/esm/llm/openai/utils/index.mjs +23 -459
  132. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  133. package/dist/esm/llm/openrouter/index.mjs +57 -175
  134. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  135. package/dist/esm/llm/vertexai/index.mjs +5 -3
  136. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  137. package/dist/esm/main.mjs +7 -0
  138. package/dist/esm/main.mjs.map +1 -1
  139. package/dist/esm/messages/cache.mjs +2 -1
  140. package/dist/esm/messages/cache.mjs.map +1 -1
  141. package/dist/esm/messages/core.mjs +7 -6
  142. package/dist/esm/messages/core.mjs.map +1 -1
  143. package/dist/esm/messages/format.mjs +73 -15
  144. package/dist/esm/messages/format.mjs.map +1 -1
  145. package/dist/esm/messages/langchain.mjs +23 -0
  146. package/dist/esm/messages/langchain.mjs.map +1 -0
  147. package/dist/esm/messages/prune.mjs +7 -6
  148. package/dist/esm/messages/prune.mjs.map +1 -1
  149. package/dist/esm/run.mjs +400 -42
  150. package/dist/esm/run.mjs.map +1 -1
  151. package/dist/esm/tools/ToolNode.mjs +557 -57
  152. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  153. package/dist/esm/tools/search/search.mjs +55 -66
  154. package/dist/esm/tools/search/search.mjs.map +1 -1
  155. package/dist/esm/tools/search/tavily-scraper.mjs +186 -0
  156. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -0
  157. package/dist/esm/tools/search/tavily-search.mjs +370 -0
  158. package/dist/esm/tools/search/tavily-search.mjs.map +1 -0
  159. package/dist/esm/tools/search/tool.mjs +26 -4
  160. package/dist/esm/tools/search/tool.mjs.map +1 -1
  161. package/dist/esm/tools/search/utils.mjs +10 -3
  162. package/dist/esm/tools/search/utils.mjs.map +1 -1
  163. package/dist/types/graphs/Graph.d.ts +7 -0
  164. package/dist/types/hitl/askUserQuestion.d.ts +55 -0
  165. package/dist/types/hitl/index.d.ts +6 -0
  166. package/dist/types/hooks/HookRegistry.d.ts +58 -0
  167. package/dist/types/hooks/createToolPolicyHook.d.ts +87 -0
  168. package/dist/types/hooks/index.d.ts +4 -1
  169. package/dist/types/hooks/types.d.ts +109 -3
  170. package/dist/types/index.d.ts +10 -0
  171. package/dist/types/langchain/google-common.d.ts +1 -0
  172. package/dist/types/langchain/index.d.ts +8 -0
  173. package/dist/types/langchain/language_models/chat_models.d.ts +1 -0
  174. package/dist/types/langchain/messages/tool.d.ts +1 -0
  175. package/dist/types/langchain/messages.d.ts +2 -0
  176. package/dist/types/langchain/openai.d.ts +1 -0
  177. package/dist/types/langchain/prompts.d.ts +1 -0
  178. package/dist/types/langchain/runnables.d.ts +2 -0
  179. package/dist/types/langchain/tools.d.ts +2 -0
  180. package/dist/types/langchain/utils/env.d.ts +1 -0
  181. package/dist/types/llm/anthropic/index.d.ts +22 -9
  182. package/dist/types/llm/anthropic/types.d.ts +5 -1
  183. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +13 -6
  184. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +1 -1
  185. package/dist/types/llm/openai/index.d.ts +21 -24
  186. package/dist/types/llm/openrouter/index.d.ts +11 -9
  187. package/dist/types/llm/vertexai/index.d.ts +1 -0
  188. package/dist/types/messages/cache.d.ts +4 -1
  189. package/dist/types/messages/format.d.ts +4 -1
  190. package/dist/types/messages/langchain.d.ts +27 -0
  191. package/dist/types/run.d.ts +117 -1
  192. package/dist/types/tools/ToolNode.d.ts +26 -1
  193. package/dist/types/tools/search/tavily-scraper.d.ts +19 -0
  194. package/dist/types/tools/search/tavily-search.d.ts +4 -0
  195. package/dist/types/tools/search/types.d.ts +99 -5
  196. package/dist/types/tools/search/utils.d.ts +2 -2
  197. package/dist/types/types/graph.d.ts +23 -37
  198. package/dist/types/types/hitl.d.ts +272 -0
  199. package/dist/types/types/index.d.ts +1 -0
  200. package/dist/types/types/llm.d.ts +3 -3
  201. package/dist/types/types/run.d.ts +33 -0
  202. package/dist/types/types/stream.d.ts +1 -1
  203. package/dist/types/types/tools.d.ts +19 -0
  204. package/package.json +80 -17
  205. package/src/graphs/Graph.ts +33 -4
  206. package/src/graphs/__tests__/composition.smoke.test.ts +188 -0
  207. package/src/hitl/askUserQuestion.ts +72 -0
  208. package/src/hitl/index.ts +7 -0
  209. package/src/hooks/HookRegistry.ts +71 -0
  210. package/src/hooks/__tests__/createToolPolicyHook.test.ts +259 -0
  211. package/src/hooks/createToolPolicyHook.ts +184 -0
  212. package/src/hooks/executeHooks.ts +50 -1
  213. package/src/hooks/index.ts +6 -0
  214. package/src/hooks/types.ts +112 -0
  215. package/src/index.ts +22 -0
  216. package/src/langchain/google-common.ts +1 -0
  217. package/src/langchain/index.ts +8 -0
  218. package/src/langchain/language_models/chat_models.ts +1 -0
  219. package/src/langchain/messages/tool.ts +5 -0
  220. package/src/langchain/messages.ts +21 -0
  221. package/src/langchain/openai.ts +1 -0
  222. package/src/langchain/prompts.ts +1 -0
  223. package/src/langchain/runnables.ts +7 -0
  224. package/src/langchain/tools.ts +8 -0
  225. package/src/langchain/utils/env.ts +1 -0
  226. package/src/llm/anthropic/index.ts +252 -84
  227. package/src/llm/anthropic/llm.spec.ts +751 -102
  228. package/src/llm/anthropic/types.ts +9 -1
  229. package/src/llm/anthropic/utils/message_inputs.ts +37 -19
  230. package/src/llm/anthropic/utils/message_outputs.ts +119 -101
  231. package/src/llm/bedrock/index.ts +2 -2
  232. package/src/llm/bedrock/llm.spec.ts +341 -0
  233. package/src/llm/bedrock/utils/message_inputs.ts +303 -4
  234. package/src/llm/bedrock/utils/message_outputs.ts +2 -1
  235. package/src/llm/custom-chat-models.smoke.test.ts +836 -0
  236. package/src/llm/google/llm.spec.ts +339 -57
  237. package/src/llm/google/utils/common.ts +53 -48
  238. package/src/llm/openai/contentBlocks.test.ts +346 -0
  239. package/src/llm/openai/index.ts +856 -833
  240. package/src/llm/openai/utils/index.ts +107 -78
  241. package/src/llm/openai/utils/messages.test.ts +159 -0
  242. package/src/llm/openrouter/index.ts +124 -247
  243. package/src/llm/openrouter/reasoning.test.ts +8 -1
  244. package/src/llm/vertexai/index.ts +11 -5
  245. package/src/llm/vertexai/llm.spec.ts +28 -1
  246. package/src/messages/cache.test.ts +4 -3
  247. package/src/messages/cache.ts +3 -2
  248. package/src/messages/core.ts +16 -9
  249. package/src/messages/format.ts +96 -16
  250. package/src/messages/formatAgentMessages.test.ts +166 -1
  251. package/src/messages/langchain.ts +39 -0
  252. package/src/messages/prune.ts +12 -8
  253. package/src/run.ts +456 -47
  254. package/src/scripts/caching.ts +2 -3
  255. package/src/specs/summarization.test.ts +51 -58
  256. package/src/tools/ToolNode.ts +706 -63
  257. package/src/tools/__tests__/hitl.test.ts +3593 -0
  258. package/src/tools/search/search.ts +83 -73
  259. package/src/tools/search/tavily-scraper.ts +235 -0
  260. package/src/tools/search/tavily-search.ts +424 -0
  261. package/src/tools/search/tavily.test.ts +965 -0
  262. package/src/tools/search/tool.ts +36 -26
  263. package/src/tools/search/types.ts +133 -8
  264. package/src/tools/search/utils.ts +13 -5
  265. package/src/types/graph.ts +32 -87
  266. package/src/types/hitl.ts +303 -0
  267. package/src/types/index.ts +1 -0
  268. package/src/types/llm.ts +3 -3
  269. package/src/types/run.ts +33 -0
  270. package/src/types/stream.ts +1 -1
  271. package/src/types/tools.ts +19 -0
  272. package/src/utils/llmConfig.ts +1 -6
@@ -16,7 +16,7 @@ import {
16
16
  isAIMessage,
17
17
  type UsageMetadata,
18
18
  type BaseMessageFields,
19
- type MessageContent,
19
+ type MessageContentComplex,
20
20
  type InvalidToolCall,
21
21
  type MessageContentImageUrl,
22
22
  StandardContentBlockConverter,
@@ -37,6 +37,7 @@ import type {
37
37
  OpenAIChatInput,
38
38
  ChatOpenAIReasoningSummary,
39
39
  } from '@langchain/openai';
40
+ import { toLangChainContent } from '@/messages/langchain';
40
41
 
41
42
  export type { OpenAICallOptions, OpenAIChatInput };
42
43
 
@@ -302,6 +303,7 @@ export function _convertMessagesToOpenAIParams(
302
303
  model?: string,
303
304
  options?: ConvertMessagesOptions
304
305
  ): OpenAICompletionParam[] {
306
+ let hasReasoningToolCallContext = false;
305
307
  // TODO: Function messages do not support array content, fix cast
306
308
  return messages.flatMap((message) => {
307
309
  let role = messageToOpenAIRole(message);
@@ -332,6 +334,8 @@ export function _convertMessagesToOpenAIParams(
332
334
  role,
333
335
  content,
334
336
  };
337
+ let messageHasToolCalls = false;
338
+ let messageIsToolResult = false;
335
339
  if (message.name != null) {
336
340
  completionParam.name = message.name;
337
341
  }
@@ -340,17 +344,11 @@ export function _convertMessagesToOpenAIParams(
340
344
  completionParam.content = '';
341
345
  }
342
346
  if (isAIMessage(message) && !!message.tool_calls?.length) {
347
+ messageHasToolCalls = true;
343
348
  completionParam.tool_calls = message.tool_calls.map(
344
349
  convertLangChainToolCallToOpenAI
345
350
  );
346
351
  completionParam.content = hasAnthropicThinkingBlock ? content : '';
347
- if (
348
- options?.includeReasoningContent === true &&
349
- message.additional_kwargs.reasoning_content != null
350
- ) {
351
- completionParam.reasoning_content =
352
- message.additional_kwargs.reasoning_content;
353
- }
354
352
  if (
355
353
  options?.includeReasoningDetails === true &&
356
354
  message.additional_kwargs.reasoning_details != null
@@ -398,14 +396,10 @@ export function _convertMessagesToOpenAIParams(
398
396
  }
399
397
  } else {
400
398
  if (message.additional_kwargs.tool_calls != null) {
399
+ messageHasToolCalls =
400
+ !Array.isArray(message.additional_kwargs.tool_calls) ||
401
+ message.additional_kwargs.tool_calls.length > 0;
401
402
  completionParam.tool_calls = message.additional_kwargs.tool_calls;
402
- if (
403
- options?.includeReasoningContent === true &&
404
- message.additional_kwargs.reasoning_content != null
405
- ) {
406
- completionParam.reasoning_content =
407
- message.additional_kwargs.reasoning_content;
408
- }
409
403
  if (
410
404
  options?.includeReasoningDetails === true &&
411
405
  message.additional_kwargs.reasoning_details != null
@@ -453,10 +447,26 @@ export function _convertMessagesToOpenAIParams(
453
447
  }
454
448
  }
455
449
  if ((message as ToolMessage).tool_call_id != null) {
450
+ messageIsToolResult = true;
456
451
  completionParam.tool_call_id = (message as ToolMessage).tool_call_id;
457
452
  }
458
453
  }
459
454
 
455
+ if (
456
+ options?.includeReasoningContent === true &&
457
+ isAIMessage(message) &&
458
+ (hasReasoningToolCallContext || messageHasToolCalls) &&
459
+ typeof message.additional_kwargs.reasoning_content === 'string' &&
460
+ message.additional_kwargs.reasoning_content !== ''
461
+ ) {
462
+ completionParam.reasoning_content =
463
+ message.additional_kwargs.reasoning_content;
464
+ }
465
+
466
+ if (messageHasToolCalls || messageIsToolResult) {
467
+ hasReasoningToolCallContext = true;
468
+ }
469
+
460
470
  if (
461
471
  message.additional_kwargs.audio &&
462
472
  typeof message.additional_kwargs.audio === 'object' &&
@@ -521,6 +531,9 @@ export function _convertMessagesToOpenAIResponsesParams(
521
531
  type?: string;
522
532
  refusal?: string;
523
533
  };
534
+ const responseMetadata = lcMsg.response_metadata as {
535
+ output?: ResponsesInputItem[];
536
+ };
524
537
 
525
538
  let role = messageToOpenAIRole(lcMsg);
526
539
  if (role === 'system' && isReasoningModel(model)) role = 'developer';
@@ -589,12 +602,12 @@ export function _convertMessagesToOpenAIResponsesParams(
589
602
  // if we have the original response items, just reuse them
590
603
  if (
591
604
  !zdrEnabled &&
592
- lcMsg.response_metadata.output != null &&
593
- Array.isArray(lcMsg.response_metadata.output) &&
594
- lcMsg.response_metadata.output.length > 0 &&
595
- lcMsg.response_metadata.output.every((item) => 'type' in item)
605
+ responseMetadata.output != null &&
606
+ Array.isArray(responseMetadata.output) &&
607
+ responseMetadata.output.length > 0 &&
608
+ responseMetadata.output.every((item) => 'type' in item)
596
609
  ) {
597
- return lcMsg.response_metadata.output;
610
+ return responseMetadata.output;
598
611
  }
599
612
 
600
613
  // otherwise, try to reconstruct the response from what we have
@@ -610,7 +623,13 @@ export function _convertMessagesToOpenAIResponsesParams(
610
623
  }
611
624
 
612
625
  // ai content
613
- let { content } = lcMsg;
626
+ let content = lcMsg.content as
627
+ | string
628
+ | Array<
629
+ | MessageContentComplex
630
+ | OpenAIClient.Responses.ResponseOutputText
631
+ | OpenAIClient.Responses.ResponseOutputRefusal
632
+ >;
614
633
  if (additional_kwargs.refusal) {
615
634
  if (typeof content === 'string') {
616
635
  content = [{ type: 'output_text', text: content, annotations: [] }];
@@ -632,11 +651,13 @@ export function _convertMessagesToOpenAIResponsesParams(
632
651
  ? content
633
652
  : content.flatMap((item) => {
634
653
  if (item.type === 'text') {
654
+ const textItem = item as MessageContentComplex & {
655
+ annotations?: unknown[];
656
+ };
635
657
  return {
636
658
  type: 'output_text',
637
659
  text: item.text,
638
- // @ts-expect-error TODO: add types for `annotations`
639
- annotations: item.annotations ?? [],
660
+ annotations: textItem.annotations ?? [],
640
661
  };
641
662
  }
642
663
 
@@ -646,7 +667,7 @@ export function _convertMessagesToOpenAIResponsesParams(
646
667
 
647
668
  return [];
648
669
  }),
649
- });
670
+ } as ResponsesInputItem);
650
671
 
651
672
  const functionCallIds = additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY];
652
673
 
@@ -677,12 +698,9 @@ export function _convertMessagesToOpenAIResponsesParams(
677
698
  }
678
699
 
679
700
  const toolOutputs =
680
- ((
681
- lcMsg.response_metadata.output as
682
- | Array<ResponsesInputItem>
683
- | undefined
684
- )?.length ?? 0) > 0
685
- ? lcMsg.response_metadata.output
701
+ ((responseMetadata.output as Array<ResponsesInputItem> | undefined)
702
+ ?.length ?? 0) > 0
703
+ ? responseMetadata.output
686
704
  : additional_kwargs.tool_outputs;
687
705
 
688
706
  const fallthroughCallTypes: ResponsesInputItem['type'][] = [
@@ -712,52 +730,63 @@ export function _convertMessagesToOpenAIResponsesParams(
712
730
  }
713
731
 
714
732
  const messages: ResponsesInputItem[] = [];
715
- const content = lcMsg.content.flatMap((item) => {
716
- if (item.type === 'mcp_approval_response') {
717
- messages.push({
718
- // @ts-ignore
719
- type: 'mcp_approval_response',
720
- approval_request_id: item.approval_request_id,
721
- approve: item.approve,
722
- });
723
- }
724
- if (isDataContentBlock(item)) {
725
- return convertToProviderContentBlock(
726
- item,
727
- completionsApiContentBlockConverter
728
- );
729
- }
730
- if (item.type === 'text') {
731
- return {
732
- type: 'input_text',
733
- text: item.text,
734
- };
735
- }
736
- if (item.type === 'image_url') {
737
- return {
738
- type: 'input_image',
739
- image_url:
740
- typeof item.image_url === 'string'
741
- ? item.image_url
742
- : item.image_url.url,
743
- detail:
744
- typeof item.image_url === 'string'
745
- ? 'auto'
746
- : item.image_url.detail,
747
- };
748
- }
749
- if (
750
- item.type === 'input_text' ||
751
- item.type === 'input_image' ||
752
- item.type === 'input_file'
753
- ) {
754
- return item;
733
+ const content = (lcMsg.content as MessageContentComplex[]).flatMap(
734
+ (item) => {
735
+ if (item.type === 'mcp_approval_response') {
736
+ const approvalResponse = item as MessageContentComplex & {
737
+ approval_request_id: string;
738
+ approve: boolean;
739
+ };
740
+ messages.push({
741
+ // @ts-ignore
742
+ type: 'mcp_approval_response',
743
+ approval_request_id: approvalResponse.approval_request_id,
744
+ approve: approvalResponse.approve,
745
+ });
746
+ }
747
+ if (isDataContentBlock(item)) {
748
+ return convertToProviderContentBlock(
749
+ item,
750
+ completionsApiContentBlockConverter
751
+ );
752
+ }
753
+ if (item.type === 'text') {
754
+ return {
755
+ type: 'input_text',
756
+ text: item.text,
757
+ };
758
+ }
759
+ if (item.type === 'image_url') {
760
+ const imageItem = item as MessageContentImageUrl;
761
+ return {
762
+ type: 'input_image',
763
+ image_url:
764
+ typeof imageItem.image_url === 'string'
765
+ ? imageItem.image_url
766
+ : imageItem.image_url.url,
767
+ detail:
768
+ typeof imageItem.image_url === 'string'
769
+ ? 'auto'
770
+ : imageItem.image_url.detail,
771
+ };
772
+ }
773
+ if (
774
+ item.type === 'input_text' ||
775
+ item.type === 'input_image' ||
776
+ item.type === 'input_file'
777
+ ) {
778
+ return item;
779
+ }
780
+ return [];
755
781
  }
756
- return [];
757
- });
782
+ );
758
783
 
759
784
  if (content.length > 0) {
760
- messages.push({ type: 'message', role, content });
785
+ messages.push({
786
+ type: 'message',
787
+ role,
788
+ content,
789
+ } as ResponsesInputItem);
761
790
  }
762
791
  return messages;
763
792
  }
@@ -785,7 +814,7 @@ function _convertOpenAIResponsesMessageToBaseMessage(
785
814
  }
786
815
 
787
816
  let messageId: string | undefined;
788
- const content: MessageContent = [];
817
+ const content: MessageContentComplex[] = [];
789
818
  const tool_calls: ToolCall[] = [];
790
819
  const invalid_tool_calls: InvalidToolCall[] = [];
791
820
  const response_metadata: Record<string, unknown> = {
@@ -871,7 +900,7 @@ function _convertOpenAIResponsesMessageToBaseMessage(
871
900
 
872
901
  return new AIMessage({
873
902
  id: messageId,
874
- content,
903
+ content: toLangChainContent(content),
875
904
  tool_calls,
876
905
  invalid_tool_calls,
877
906
  usage_metadata: response.usage,
@@ -883,7 +912,7 @@ function _convertOpenAIResponsesMessageToBaseMessage(
883
912
  export function _convertOpenAIResponsesDeltaToBaseMessageChunk(
884
913
  chunk: ResponseReturnStreamEvents
885
914
  ) {
886
- const content: Record<string, unknown>[] = [];
915
+ const content: MessageContentComplex[] = [];
887
916
  let generationInfo: Record<string, unknown> = {};
888
917
  let usage_metadata: UsageMetadata | undefined;
889
918
  const tool_call_chunks: ToolCallChunk[] = [];
@@ -1021,10 +1050,10 @@ export function _convertOpenAIResponsesDeltaToBaseMessageChunk(
1021
1050
 
1022
1051
  return new ChatGenerationChunk({
1023
1052
  // Legacy reasons, `onLLMNewToken` should pulls this out
1024
- text: content.map((part) => part.text).join(''),
1053
+ text: content.map((part) => ('text' in part ? part.text : '')).join(''),
1025
1054
  message: new AIMessageChunk({
1026
1055
  id,
1027
- content,
1056
+ content: toLangChainContent(content),
1028
1057
  tool_call_chunks,
1029
1058
  usage_metadata,
1030
1059
  additional_kwargs,
@@ -0,0 +1,159 @@
1
+ import { AIMessage, HumanMessage, ToolMessage } from '@langchain/core/messages';
2
+ import { _convertMessagesToOpenAIParams } from './index';
3
+
4
+ describe('_convertMessagesToOpenAIParams', () => {
5
+ it('includes reasoning_content for assistant messages in tool-call context when requested', () => {
6
+ const messages = [
7
+ new AIMessage({
8
+ content: '',
9
+ tool_calls: [
10
+ {
11
+ id: 'call_1',
12
+ name: 'calculator',
13
+ args: { input: '127 * 453' },
14
+ type: 'tool_call',
15
+ },
16
+ ],
17
+ additional_kwargs: {
18
+ reasoning_content: 'Need calculator.',
19
+ },
20
+ }),
21
+ new ToolMessage({
22
+ content: '57531',
23
+ tool_call_id: 'call_1',
24
+ }),
25
+ new AIMessage({
26
+ content: '127 * 453 = 57531.',
27
+ additional_kwargs: {
28
+ reasoning_content: 'Calculator returned 57531.',
29
+ },
30
+ }),
31
+ ];
32
+
33
+ const params = _convertMessagesToOpenAIParams(messages, 'deepseek-v4-pro', {
34
+ includeReasoningContent: true,
35
+ });
36
+
37
+ expect(params).toHaveLength(3);
38
+ expect(params[0]).toEqual(
39
+ expect.objectContaining({
40
+ role: 'assistant',
41
+ content: '',
42
+ reasoning_content: 'Need calculator.',
43
+ })
44
+ );
45
+ expect(params[2]).toEqual(
46
+ expect.objectContaining({
47
+ role: 'assistant',
48
+ reasoning_content: 'Calculator returned 57531.',
49
+ })
50
+ );
51
+ });
52
+
53
+ it('does not include reasoning_content for no-tool assistant messages', () => {
54
+ const messages = [
55
+ new AIMessage({
56
+ content: '127 * 453 = 57531.',
57
+ additional_kwargs: {
58
+ reasoning_content: 'Mental calculation.',
59
+ },
60
+ }),
61
+ ];
62
+
63
+ const params = _convertMessagesToOpenAIParams(messages, 'deepseek-v4-pro', {
64
+ includeReasoningContent: true,
65
+ });
66
+
67
+ expect(params).toHaveLength(1);
68
+ expect(params[0]).not.toHaveProperty('reasoning_content');
69
+ });
70
+
71
+ it('does not include reasoning_content unless explicitly requested', () => {
72
+ const messages = [
73
+ new AIMessage({
74
+ content: '',
75
+ tool_calls: [
76
+ {
77
+ id: 'call_1',
78
+ name: 'calculator',
79
+ args: { input: '127 * 453' },
80
+ type: 'tool_call',
81
+ },
82
+ ],
83
+ additional_kwargs: {
84
+ reasoning_content: 'Need calculator.',
85
+ },
86
+ }),
87
+ ];
88
+
89
+ const params = _convertMessagesToOpenAIParams(messages, 'deepseek-v4-pro');
90
+
91
+ expect(params).toHaveLength(1);
92
+ expect(params[0]).not.toHaveProperty('reasoning_content');
93
+ });
94
+
95
+ it('keeps reasoning_content latched after tool-call context is established', () => {
96
+ const messages = [
97
+ new AIMessage({
98
+ content: 'No tool was needed.',
99
+ additional_kwargs: {
100
+ reasoning_content: 'Initial no-tool reasoning.',
101
+ },
102
+ }),
103
+ new HumanMessage('Use the calculator.'),
104
+ new AIMessage({
105
+ content: '',
106
+ tool_calls: [
107
+ {
108
+ id: 'call_1',
109
+ name: 'calculator',
110
+ args: { input: '127 * 453' },
111
+ type: 'tool_call',
112
+ },
113
+ ],
114
+ additional_kwargs: {
115
+ reasoning_content: 'Need calculator.',
116
+ },
117
+ }),
118
+ new ToolMessage({
119
+ content: '57531',
120
+ tool_call_id: 'call_1',
121
+ }),
122
+ new AIMessage({
123
+ content: '127 * 453 = 57531.',
124
+ additional_kwargs: {
125
+ reasoning_content: 'Calculator returned 57531.',
126
+ },
127
+ }),
128
+ new HumanMessage('Was that correct?'),
129
+ new AIMessage({
130
+ content: 'Yes.',
131
+ additional_kwargs: {
132
+ reasoning_content: 'The prior calculator result is available.',
133
+ },
134
+ }),
135
+ ];
136
+
137
+ const params = _convertMessagesToOpenAIParams(messages, 'deepseek-v4-pro', {
138
+ includeReasoningContent: true,
139
+ });
140
+
141
+ expect(params).toHaveLength(7);
142
+ expect(params[0]).not.toHaveProperty('reasoning_content');
143
+ expect(params[2]).toEqual(
144
+ expect.objectContaining({
145
+ reasoning_content: 'Need calculator.',
146
+ })
147
+ );
148
+ expect(params[4]).toEqual(
149
+ expect.objectContaining({
150
+ reasoning_content: 'Calculator returned 57531.',
151
+ })
152
+ );
153
+ expect(params[6]).toEqual(
154
+ expect.objectContaining({
155
+ reasoning_content: 'The prior calculator result is available.',
156
+ })
157
+ );
158
+ });
159
+ });