@librechat/agents 3.8.0 → 3.8.2

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 (248) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +13 -3
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +176 -55
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +16 -6
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/hitl/approvalReview.cjs +89 -0
  8. package/dist/cjs/hitl/approvalReview.cjs.map +1 -0
  9. package/dist/cjs/langfuse.cjs +42 -0
  10. package/dist/cjs/langfuse.cjs.map +1 -1
  11. package/dist/cjs/langfuseToolOutputTracing.cjs +42 -0
  12. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  13. package/dist/cjs/langfuseTraceShaping.cjs +7 -1
  14. package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
  15. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +6 -10
  16. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  17. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +2 -7
  18. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  19. package/dist/cjs/llm/contextPressureMeter.cjs +51 -10
  20. package/dist/cjs/llm/contextPressureMeter.cjs.map +1 -1
  21. package/dist/cjs/llm/init.cjs +1 -1
  22. package/dist/cjs/llm/invoke.cjs +2 -2
  23. package/dist/cjs/llm/openai/index.cjs +4 -3
  24. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  25. package/dist/cjs/llm/openai/utils/index.cjs +5 -4
  26. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  27. package/dist/cjs/llm/preempt.cjs +3 -2
  28. package/dist/cjs/llm/preempt.cjs.map +1 -1
  29. package/dist/cjs/llm/prepareProviderRequest.cjs +9 -7
  30. package/dist/cjs/llm/prepareProviderRequest.cjs.map +1 -1
  31. package/dist/cjs/llm/providers.cjs +1 -1
  32. package/dist/cjs/main.cjs +14 -8
  33. package/dist/cjs/messages/alternation.cjs +1 -5
  34. package/dist/cjs/messages/alternation.cjs.map +1 -1
  35. package/dist/cjs/messages/budget.cjs +206 -7
  36. package/dist/cjs/messages/budget.cjs.map +1 -1
  37. package/dist/cjs/messages/cache.cjs +3 -9
  38. package/dist/cjs/messages/cache.cjs.map +1 -1
  39. package/dist/cjs/messages/core.cjs +26 -38
  40. package/dist/cjs/messages/core.cjs.map +1 -1
  41. package/dist/cjs/messages/format.cjs +132 -43
  42. package/dist/cjs/messages/format.cjs.map +1 -1
  43. package/dist/cjs/messages/index.cjs +2 -0
  44. package/dist/cjs/messages/prune.cjs +14 -9
  45. package/dist/cjs/messages/prune.cjs.map +1 -1
  46. package/dist/cjs/messages/reasoningTypes.cjs +21 -0
  47. package/dist/cjs/messages/reasoningTypes.cjs.map +1 -0
  48. package/dist/cjs/messages/recency.cjs +15 -94
  49. package/dist/cjs/messages/recency.cjs.map +1 -1
  50. package/dist/cjs/messages/toolHistoryProjection.cjs +243 -0
  51. package/dist/cjs/messages/toolHistoryProjection.cjs.map +1 -0
  52. package/dist/cjs/messages/toolResultTypes.cjs +145 -4
  53. package/dist/cjs/messages/toolResultTypes.cjs.map +1 -1
  54. package/dist/cjs/run.cjs +22 -10
  55. package/dist/cjs/run.cjs.map +1 -1
  56. package/dist/cjs/session/AgentSession.cjs +7 -5
  57. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  58. package/dist/cjs/session/JsonlSessionStore.cjs +3 -0
  59. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  60. package/dist/cjs/session/index.cjs +1 -1
  61. package/dist/cjs/session/sessionProjection.cjs +75 -0
  62. package/dist/cjs/session/sessionProjection.cjs.map +1 -0
  63. package/dist/cjs/stream.cjs +20 -19
  64. package/dist/cjs/stream.cjs.map +1 -1
  65. package/dist/cjs/summarization/index.cjs.map +1 -1
  66. package/dist/cjs/summarization/node.cjs +19 -9
  67. package/dist/cjs/summarization/node.cjs.map +1 -1
  68. package/dist/cjs/summarization/shared.cjs +9 -0
  69. package/dist/cjs/summarization/shared.cjs.map +1 -1
  70. package/dist/cjs/tools/ToolNode.cjs +256 -84
  71. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  72. package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
  73. package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
  74. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +24 -9
  75. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  76. package/dist/cjs/tools/subagent/SubagentReplay.cjs +2 -0
  77. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
  78. package/dist/cjs/tools/toolBatchReplay.cjs +187 -0
  79. package/dist/cjs/tools/toolBatchReplay.cjs.map +1 -0
  80. package/dist/cjs/tools/toolOutputReferences.cjs +12 -0
  81. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  82. package/dist/cjs/types/hitl.cjs +4 -0
  83. package/dist/cjs/types/hitl.cjs.map +1 -1
  84. package/dist/cjs/utils/events.cjs +13 -0
  85. package/dist/cjs/utils/events.cjs.map +1 -1
  86. package/dist/cjs/utils/tokens.cjs +105 -0
  87. package/dist/cjs/utils/tokens.cjs.map +1 -1
  88. package/dist/esm/agents/AgentContext.mjs +13 -3
  89. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  90. package/dist/esm/graphs/Graph.mjs +178 -57
  91. package/dist/esm/graphs/Graph.mjs.map +1 -1
  92. package/dist/esm/graphs/MultiAgentGraph.mjs +16 -6
  93. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  94. package/dist/esm/hitl/approvalReview.mjs +83 -0
  95. package/dist/esm/hitl/approvalReview.mjs.map +1 -0
  96. package/dist/esm/langfuse.mjs +43 -2
  97. package/dist/esm/langfuse.mjs.map +1 -1
  98. package/dist/esm/langfuseToolOutputTracing.mjs +41 -1
  99. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  100. package/dist/esm/langfuseTraceShaping.mjs +7 -1
  101. package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
  102. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +6 -10
  103. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  104. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +2 -7
  105. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  106. package/dist/esm/llm/contextPressureMeter.mjs +52 -11
  107. package/dist/esm/llm/contextPressureMeter.mjs.map +1 -1
  108. package/dist/esm/llm/init.mjs +1 -1
  109. package/dist/esm/llm/invoke.mjs +2 -2
  110. package/dist/esm/llm/openai/index.mjs +2 -1
  111. package/dist/esm/llm/openai/index.mjs.map +1 -1
  112. package/dist/esm/llm/openai/utils/index.mjs +5 -4
  113. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  114. package/dist/esm/llm/preempt.mjs +2 -1
  115. package/dist/esm/llm/preempt.mjs.map +1 -1
  116. package/dist/esm/llm/prepareProviderRequest.mjs +9 -7
  117. package/dist/esm/llm/prepareProviderRequest.mjs.map +1 -1
  118. package/dist/esm/llm/providers.mjs +1 -1
  119. package/dist/esm/main.mjs +13 -10
  120. package/dist/esm/messages/alternation.mjs +2 -6
  121. package/dist/esm/messages/alternation.mjs.map +1 -1
  122. package/dist/esm/messages/budget.mjs +206 -8
  123. package/dist/esm/messages/budget.mjs.map +1 -1
  124. package/dist/esm/messages/cache.mjs +3 -9
  125. package/dist/esm/messages/cache.mjs.map +1 -1
  126. package/dist/esm/messages/core.mjs +24 -34
  127. package/dist/esm/messages/core.mjs.map +1 -1
  128. package/dist/esm/messages/format.mjs +133 -44
  129. package/dist/esm/messages/format.mjs.map +1 -1
  130. package/dist/esm/messages/index.mjs +2 -0
  131. package/dist/esm/messages/prune.mjs +14 -9
  132. package/dist/esm/messages/prune.mjs.map +1 -1
  133. package/dist/esm/messages/reasoningTypes.mjs +20 -0
  134. package/dist/esm/messages/reasoningTypes.mjs.map +1 -0
  135. package/dist/esm/messages/recency.mjs +16 -95
  136. package/dist/esm/messages/recency.mjs.map +1 -1
  137. package/dist/esm/messages/toolHistoryProjection.mjs +237 -0
  138. package/dist/esm/messages/toolHistoryProjection.mjs.map +1 -0
  139. package/dist/esm/messages/toolResultTypes.mjs +141 -4
  140. package/dist/esm/messages/toolResultTypes.mjs.map +1 -1
  141. package/dist/esm/run.mjs +23 -11
  142. package/dist/esm/run.mjs.map +1 -1
  143. package/dist/esm/session/AgentSession.mjs +7 -5
  144. package/dist/esm/session/AgentSession.mjs.map +1 -1
  145. package/dist/esm/session/JsonlSessionStore.mjs +3 -0
  146. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  147. package/dist/esm/session/index.mjs +1 -1
  148. package/dist/esm/session/sessionProjection.mjs +72 -0
  149. package/dist/esm/session/sessionProjection.mjs.map +1 -0
  150. package/dist/esm/stream.mjs +17 -16
  151. package/dist/esm/stream.mjs.map +1 -1
  152. package/dist/esm/summarization/index.mjs.map +1 -1
  153. package/dist/esm/summarization/node.mjs +20 -10
  154. package/dist/esm/summarization/node.mjs.map +1 -1
  155. package/dist/esm/summarization/shared.mjs +9 -1
  156. package/dist/esm/summarization/shared.mjs.map +1 -1
  157. package/dist/esm/tools/ToolNode.mjs +256 -84
  158. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  159. package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
  160. package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
  161. package/dist/esm/tools/subagent/SubagentExecutor.mjs +24 -9
  162. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  163. package/dist/esm/tools/subagent/SubagentReplay.mjs +1 -1
  164. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
  165. package/dist/esm/tools/toolBatchReplay.mjs +176 -0
  166. package/dist/esm/tools/toolBatchReplay.mjs.map +1 -0
  167. package/dist/esm/tools/toolOutputReferences.mjs +12 -0
  168. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  169. package/dist/esm/types/hitl.mjs +4 -1
  170. package/dist/esm/types/hitl.mjs.map +1 -1
  171. package/dist/esm/utils/events.mjs +13 -0
  172. package/dist/esm/utils/events.mjs.map +1 -1
  173. package/dist/esm/utils/tokens.mjs +105 -1
  174. package/dist/esm/utils/tokens.mjs.map +1 -1
  175. package/dist/types/agents/AgentContext.d.ts +13 -1
  176. package/dist/types/graphs/Graph.d.ts +27 -0
  177. package/dist/types/hitl/approvalReview.d.ts +32 -0
  178. package/dist/types/hooks/types.d.ts +4 -2
  179. package/dist/types/index.d.ts +1 -0
  180. package/dist/types/langfuse.d.ts +5 -0
  181. package/dist/types/langfuseToolOutputTracing.d.ts +2 -0
  182. package/dist/types/llm/contextPressureMeter.d.ts +2 -1
  183. package/dist/types/llm/prepareProviderRequest.d.ts +7 -1
  184. package/dist/types/messages/budget.d.ts +15 -10
  185. package/dist/types/messages/core.d.ts +8 -17
  186. package/dist/types/messages/format.d.ts +3 -2
  187. package/dist/types/messages/index.d.ts +1 -1
  188. package/dist/types/messages/prune.d.ts +1 -1
  189. package/dist/types/messages/reasoningTypes.d.ts +7 -0
  190. package/dist/types/messages/recency.d.ts +3 -0
  191. package/dist/types/messages/toolHistoryProjection.d.ts +65 -0
  192. package/dist/types/messages/toolResultTypes.d.ts +31 -1
  193. package/dist/types/session/sessionProjection.d.ts +10 -0
  194. package/dist/types/summarization/index.d.ts +2 -1
  195. package/dist/types/summarization/node.d.ts +1 -0
  196. package/dist/types/summarization/shared.d.ts +12 -0
  197. package/dist/types/tools/ToolNode.d.ts +12 -6
  198. package/dist/types/tools/subagent/SubagentReplay.d.ts +2 -0
  199. package/dist/types/tools/toolBatchReplay.d.ts +54 -0
  200. package/dist/types/tools/toolOutputReferences.d.ts +2 -0
  201. package/dist/types/types/graph.d.ts +20 -0
  202. package/dist/types/types/run.d.ts +4 -0
  203. package/dist/types/types/summarize.d.ts +4 -1
  204. package/dist/types/utils/tokens.d.ts +2 -1
  205. package/package.json +1 -1
  206. package/src/agents/AgentContext.ts +34 -3
  207. package/src/graphs/Graph.ts +465 -147
  208. package/src/graphs/MultiAgentGraph.ts +28 -6
  209. package/src/hitl/approvalReview.ts +209 -0
  210. package/src/hooks/types.ts +4 -1
  211. package/src/index.ts +1 -0
  212. package/src/langfuse.ts +67 -9
  213. package/src/langfuseToolOutputTracing.ts +91 -0
  214. package/src/langfuseTraceShaping.ts +17 -4
  215. package/src/llm/anthropic/utils/message_inputs.ts +5 -10
  216. package/src/llm/bedrock/utils/message_inputs.ts +2 -8
  217. package/src/llm/contextPressureMeter.ts +80 -12
  218. package/src/llm/openai/utils/index.ts +5 -4
  219. package/src/llm/prepareProviderRequest.ts +21 -16
  220. package/src/messages/alternation.ts +2 -15
  221. package/src/messages/budget.ts +439 -23
  222. package/src/messages/cache.ts +8 -9
  223. package/src/messages/core.ts +65 -95
  224. package/src/messages/format.ts +262 -78
  225. package/src/messages/index.ts +1 -1
  226. package/src/messages/prune.ts +31 -12
  227. package/src/messages/reasoningTypes.ts +23 -0
  228. package/src/messages/recency.ts +35 -179
  229. package/src/messages/toolHistoryProjection.ts +460 -0
  230. package/src/messages/toolResultTypes.ts +331 -100
  231. package/src/run.ts +44 -22
  232. package/src/session/AgentSession.ts +33 -16
  233. package/src/session/JsonlSessionStore.ts +6 -0
  234. package/src/session/sessionProjection.ts +126 -0
  235. package/src/stream.ts +14 -19
  236. package/src/summarization/index.ts +2 -0
  237. package/src/summarization/node.ts +62 -13
  238. package/src/summarization/shared.ts +23 -0
  239. package/src/tools/ToolNode.ts +518 -184
  240. package/src/tools/subagent/SubagentExecutor.ts +35 -6
  241. package/src/tools/subagent/SubagentReplay.ts +2 -2
  242. package/src/tools/toolBatchReplay.ts +395 -0
  243. package/src/tools/toolOutputReferences.ts +16 -0
  244. package/src/types/graph.ts +20 -0
  245. package/src/types/run.ts +4 -0
  246. package/src/types/summarize.ts +4 -1
  247. package/src/utils/events.ts +19 -0
  248. package/src/utils/tokens.ts +183 -0
@@ -1,4 +1,11 @@
1
1
  import { isProxy } from 'node:util/types';
2
+ import type {
3
+ BaseMessage,
4
+ ChatMessage,
5
+ ToolMessage,
6
+ } from '@langchain/core/messages';
7
+ import type { ProviderName } from '@/types/llm';
8
+ import { getProviderFamily } from '@/llm/providers';
2
9
 
3
10
  export type ProviderToolCallKind =
4
11
  | 'tool'
@@ -26,7 +33,7 @@ export interface ProviderToolResultPartDescriptor {
26
33
 
27
34
  export interface ProviderToolCallIndexEntry {
28
35
  readonly descriptor: ProviderToolCallPartDescriptor;
29
- secondarySourceType?: string;
36
+ secondarySourceTypes?: Set<string>;
30
37
  }
31
38
 
32
39
  export type ProviderToolCallIndex = Map<
@@ -323,10 +330,7 @@ function isCacheControl(value: unknown): boolean {
323
330
  }
324
331
  const ttl = readDataProperty(record, 'ttl');
325
332
  return (
326
- !ttl.found ||
327
- ttl.value === null ||
328
- ttl.value === '5m' ||
329
- ttl.value === '1h'
333
+ !ttl.found || ttl.value === null || ttl.value === '5m' || ttl.value === '1h'
330
334
  );
331
335
  }
332
336
 
@@ -359,9 +363,7 @@ function hasValidCallerProperty(record: Record<string, unknown>): boolean {
359
363
  return !property.found || isServerToolCaller(property.value);
360
364
  }
361
365
 
362
- function hasValidProviderMetadata(
363
- record: Record<string, unknown>
364
- ): boolean {
366
+ function hasValidProviderMetadata(record: Record<string, unknown>): boolean {
365
367
  const id = readDataProperty(record, 'id');
366
368
  if (id.found && !isBoundedProviderPairingString(id.value)) {
367
369
  return false;
@@ -393,8 +395,7 @@ function hasValidProviderMetadata(
393
395
  }
394
396
  const signature = readDataProperty(record, 'thoughtSignature');
395
397
  return (
396
- !signature.found ||
397
- isBoundedProviderPairingString(signature.value, true)
398
+ !signature.found || isBoundedProviderPairingString(signature.value, true)
398
399
  );
399
400
  }
400
401
 
@@ -486,9 +487,7 @@ export function hasStructurallyValidAnthropicWebSearchResultContent(
486
487
  );
487
488
  }
488
489
 
489
- function isGoogleCodeExecutionResult(
490
- record: Record<string, unknown>
491
- ): boolean {
490
+ function isGoogleCodeExecutionResult(record: Record<string, unknown>): boolean {
492
491
  const nested = readDataProperty(record, 'codeExecutionResult');
493
492
  const result = nested.found ? getRecord(nested.value) : undefined;
494
493
  const outcome = result == null ? undefined : readString(result, 'outcome');
@@ -602,48 +601,42 @@ const LOCAL_RESULT_METADATA_FIELDS = [
602
601
  'agentId',
603
602
  'groupId',
604
603
  ] as const;
605
- const TOOL_RESULT_ENVELOPE_FIELDS: Readonly<
606
- Record<string, readonly string[]>
607
- > = {
608
- advisor_tool_result: ANTHROPIC_RESULT_FIELDS,
609
- bash_code_execution_tool_result: ANTHROPIC_RESULT_FIELDS,
610
- code_execution_tool_result: ANTHROPIC_RESULT_FIELDS,
611
- mcp_tool_result: ANTHROPIC_GENERIC_RESULT_FIELDS,
612
- text_editor_code_execution_tool_result: ANTHROPIC_RESULT_FIELDS,
613
- tool_search_tool_result: ANTHROPIC_RESULT_FIELDS,
614
- tool_result: ANTHROPIC_GENERIC_RESULT_FIELDS,
615
- web_fetch_tool_result: ANTHROPIC_SERVER_RESULT_FIELDS,
616
- web_search_tool_result: ANTHROPIC_SERVER_RESULT_FIELDS,
617
- server_tool_call_result: [
618
- 'type',
619
- 'toolCallId',
620
- 'status',
621
- 'output',
622
- ...LOCAL_RESULT_METADATA_FIELDS,
623
- ],
624
- server_tool_result: [
625
- 'type',
626
- 'tool_call_id',
627
- 'status',
628
- 'output',
629
- ...LOCAL_RESULT_METADATA_FIELDS,
630
- ],
631
- codeExecutionResult: [
632
- 'type',
633
- 'codeExecutionResult',
634
- 'agentId',
635
- 'groupId',
636
- ],
637
- toolResponse: [
638
- 'type',
639
- 'toolResponse',
640
- 'thought',
641
- 'thoughtSignature',
642
- 'agentId',
643
- 'groupId',
644
- ],
645
- toolResult: ['type', 'toolResult', 'agentId', 'groupId'],
646
- };
604
+ const TOOL_RESULT_ENVELOPE_FIELDS: Readonly<Record<string, readonly string[]>> =
605
+ {
606
+ advisor_tool_result: ANTHROPIC_RESULT_FIELDS,
607
+ bash_code_execution_tool_result: ANTHROPIC_RESULT_FIELDS,
608
+ code_execution_tool_result: ANTHROPIC_RESULT_FIELDS,
609
+ mcp_tool_result: ANTHROPIC_GENERIC_RESULT_FIELDS,
610
+ text_editor_code_execution_tool_result: ANTHROPIC_RESULT_FIELDS,
611
+ tool_search_tool_result: ANTHROPIC_RESULT_FIELDS,
612
+ tool_result: ANTHROPIC_GENERIC_RESULT_FIELDS,
613
+ web_fetch_tool_result: ANTHROPIC_SERVER_RESULT_FIELDS,
614
+ web_search_tool_result: ANTHROPIC_SERVER_RESULT_FIELDS,
615
+ server_tool_call_result: [
616
+ 'type',
617
+ 'toolCallId',
618
+ 'status',
619
+ 'output',
620
+ ...LOCAL_RESULT_METADATA_FIELDS,
621
+ ],
622
+ server_tool_result: [
623
+ 'type',
624
+ 'tool_call_id',
625
+ 'status',
626
+ 'output',
627
+ ...LOCAL_RESULT_METADATA_FIELDS,
628
+ ],
629
+ codeExecutionResult: ['type', 'codeExecutionResult', 'agentId', 'groupId'],
630
+ toolResponse: [
631
+ 'type',
632
+ 'toolResponse',
633
+ 'thought',
634
+ 'thoughtSignature',
635
+ 'agentId',
636
+ 'groupId',
637
+ ],
638
+ toolResult: ['type', 'toolResult', 'agentId', 'groupId'],
639
+ };
647
640
 
648
641
  function anthropicDescriptor(
649
642
  record: Record<string, unknown>,
@@ -652,9 +645,7 @@ function anthropicDescriptor(
652
645
  ): ProviderToolResultPartDescriptor | undefined {
653
646
  const toolCallId = readPairingString(record, 'tool_use_id');
654
647
  const content = readDataProperty(record, 'content');
655
- return toolCallId != null &&
656
- content.found &&
657
- getRecord(content.value) != null
648
+ return toolCallId != null && content.found && getRecord(content.value) != null
658
649
  ? {
659
650
  type,
660
651
  toolCallId,
@@ -672,7 +663,8 @@ export function getProviderToolResultPartDescriptor(
672
663
  return undefined;
673
664
  }
674
665
  const type = readString(record, 'type');
675
- const allowedFields = type == null ? undefined : TOOL_RESULT_ENVELOPE_FIELDS[type];
666
+ const allowedFields =
667
+ type == null ? undefined : TOOL_RESULT_ENVELOPE_FIELDS[type];
676
668
  if (
677
669
  type == null ||
678
670
  allowedFields == null ||
@@ -685,19 +677,14 @@ export function getProviderToolResultPartDescriptor(
685
677
  }
686
678
  const structuredToolNames = ANTHROPIC_STRUCTURED_RESULT_TOOL_NAMES[type];
687
679
  if (structuredToolNames != null) {
688
- return anthropicDescriptor(
689
- record,
690
- type,
691
- structuredToolNames
692
- );
680
+ return anthropicDescriptor(record, type, structuredToolNames);
693
681
  }
694
682
  if (type === 'web_search_tool_result') {
695
683
  const toolCallId = readPairingString(record, 'tool_use_id');
696
684
  const content = readDataProperty(record, 'content');
697
685
  return toolCallId != null &&
698
686
  content.found &&
699
- (getRecord(content.value) != null ||
700
- isOpaqueBoundedArray(content.value))
687
+ (getRecord(content.value) != null || isOpaqueBoundedArray(content.value))
701
688
  ? {
702
689
  type,
703
690
  toolCallId,
@@ -766,6 +753,33 @@ export function getProviderToolResultPartDescriptor(
766
753
  return undefined;
767
754
  }
768
755
 
756
+ const PROVIDER_TOOL_CALL_CONTENT_TYPES: ReadonlySet<string> = new Set([
757
+ 'tool_call',
758
+ 'tool_use',
759
+ 'server_tool_use',
760
+ 'mcp_tool_use',
761
+ 'server_tool_call',
762
+ 'toolCall',
763
+ 'toolUse',
764
+ 'executableCode',
765
+ ]);
766
+
767
+ export function isProviderToolCallContentPart(part: unknown): boolean {
768
+ const record = getRecord(part);
769
+ const type = record == null ? undefined : readString(record, 'type');
770
+ return type != null && PROVIDER_TOOL_CALL_CONTENT_TYPES.has(type);
771
+ }
772
+
773
+ export function isProviderToolContentPart(part: unknown): boolean {
774
+ const record = getRecord(part);
775
+ const type = record == null ? undefined : readString(record, 'type');
776
+ return (
777
+ type != null &&
778
+ (PROVIDER_TOOL_CALL_CONTENT_TYPES.has(type) ||
779
+ Object.prototype.hasOwnProperty.call(TOOL_RESULT_ENVELOPE_FIELDS, type))
780
+ );
781
+ }
782
+
769
783
  function optionalName(
770
784
  record: Record<string, unknown>
771
785
  ): { readonly name?: string } | undefined {
@@ -817,10 +831,7 @@ function getAnthropicCallKind(
817
831
  if (type === 'mcp_tool_use') {
818
832
  return 'mcp';
819
833
  }
820
- if (
821
- type === 'server_tool_use' ||
822
- isAnthropicServerToolCall(callId, name)
823
- ) {
834
+ if (type === 'server_tool_use' || isAnthropicServerToolCall(callId, name)) {
824
835
  return 'anthropic-server';
825
836
  }
826
837
  return 'tool';
@@ -880,11 +891,7 @@ export function getProviderAIMessageToolCallDescriptor(
880
891
  const record = getRecord(toolCall);
881
892
  if (
882
893
  record == null ||
883
- !hasExactCallShape(
884
- record,
885
- AI_TOOL_CALL_FIELDS,
886
- ['id', 'name', 'args']
887
- ) ||
894
+ !hasExactCallShape(record, AI_TOOL_CALL_FIELDS, ['id', 'name', 'args']) ||
888
895
  !hasOptionalCallType(record, 'tool_call')
889
896
  ) {
890
897
  return undefined;
@@ -920,18 +927,14 @@ export function getProviderToolCallPartDescriptor(
920
927
  ['type', 'tool_call', 'agentId', 'groupId'],
921
928
  ['tool_call']
922
929
  )
923
- : hasExactCallShape(
924
- record,
925
- STANDARD_CALL_FIELDS,
926
- ['id', 'name', 'args']
927
- );
930
+ : hasExactCallShape(record, STANDARD_CALL_FIELDS, ['id', 'name', 'args']);
928
931
  const callIsValid = nested.found
929
932
  ? call != null &&
930
- hasExactCallShape(
931
- call,
932
- LIBRECHAT_CALL_FIELDS,
933
- ['id', 'name', 'args']
934
- ) &&
933
+ hasExactCallShape(call, LIBRECHAT_CALL_FIELDS, [
934
+ 'id',
935
+ 'name',
936
+ 'args',
937
+ ]) &&
935
938
  hasOptionalCallType(call, 'tool_call')
936
939
  : call != null;
937
940
  if (!outerIsValid || !callIsValid) {
@@ -991,11 +994,7 @@ export function getProviderToolCallPartDescriptor(
991
994
  }
992
995
  if (type === 'server_tool_call') {
993
996
  if (
994
- !hasExactCallShape(
995
- record,
996
- STANDARD_CALL_FIELDS,
997
- ['id', 'name', 'args']
998
- )
997
+ !hasExactCallShape(record, STANDARD_CALL_FIELDS, ['id', 'name', 'args'])
999
998
  ) {
1000
999
  return undefined;
1001
1000
  }
@@ -1099,23 +1098,24 @@ export function appendProviderToolCallDescriptor(
1099
1098
  if (existing === null) {
1100
1099
  return;
1101
1100
  }
1102
- const isDualRepresentation =
1103
- existing.secondarySourceType == null &&
1104
- existing.descriptor.sourceType !== descriptor.sourceType &&
1105
- (existing.descriptor.sourceType === 'ai_tool_calls' ||
1106
- descriptor.sourceType === 'ai_tool_calls');
1107
- if (
1101
+ const sourceTypes =
1102
+ existing.secondarySourceTypes ??
1103
+ new Set<string>([existing.descriptor.sourceType]);
1104
+ const isEquivalentRepresentation =
1108
1105
  existing.descriptor.kind === descriptor.kind &&
1109
1106
  existing.descriptor.name === descriptor.name &&
1110
- isDualRepresentation
1111
- ) {
1112
- existing.secondarySourceType = descriptor.sourceType;
1107
+ !sourceTypes.has(descriptor.sourceType);
1108
+ if (isEquivalentRepresentation) {
1109
+ sourceTypes.add(descriptor.sourceType);
1110
+ existing.secondarySourceTypes = sourceTypes;
1113
1111
  return;
1114
1112
  }
1115
1113
  index.set(descriptor.callId, null);
1116
1114
  }
1117
1115
 
1118
- function isExecutableCodePart(part: unknown): boolean {
1116
+ /** Google's built-in code execution emits an `executableCode` part with no call
1117
+ * id; its `codeExecutionResult` pairs by adjacency instead. */
1118
+ export function isExecutableCodePart(part: unknown): boolean {
1119
1119
  const record = getRecord(part);
1120
1120
  if (
1121
1121
  record == null ||
@@ -1172,3 +1172,234 @@ export function consumeProviderToolResultPair(
1172
1172
  calls.delete(descriptor.toolCallId);
1173
1173
  return true;
1174
1174
  }
1175
+
1176
+ function readOwnString(value: unknown, key: string): string | undefined {
1177
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
1178
+ return undefined;
1179
+ }
1180
+ try {
1181
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1182
+ return descriptor != null &&
1183
+ 'value' in descriptor &&
1184
+ typeof descriptor.value === 'string' &&
1185
+ descriptor.value !== '' &&
1186
+ descriptor.value.length <= PROVIDER_TOOL_PAIRING_MAX_IDENTIFIER_CHARS
1187
+ ? descriptor.value
1188
+ : undefined;
1189
+ } catch {
1190
+ return undefined;
1191
+ }
1192
+ }
1193
+
1194
+ function readOwnValue(value: unknown, key: string): unknown {
1195
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
1196
+ return undefined;
1197
+ }
1198
+ try {
1199
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1200
+ return descriptor != null && 'value' in descriptor
1201
+ ? descriptor.value
1202
+ : undefined;
1203
+ } catch {
1204
+ return undefined;
1205
+ }
1206
+ }
1207
+
1208
+ const LEGACY_FUNCTION_CALL_PREFIX = 'legacy_function:';
1209
+
1210
+ export function getLegacyFunctionCallId(name: string): string | undefined {
1211
+ const callId = `${LEGACY_FUNCTION_CALL_PREFIX}${name}`;
1212
+ return callId.length <= PROVIDER_TOOL_PAIRING_MAX_IDENTIFIER_CHARS
1213
+ ? callId
1214
+ : undefined;
1215
+ }
1216
+
1217
+ export type ProviderMessageRole =
1218
+ | 'assistant'
1219
+ | 'user'
1220
+ | 'system'
1221
+ | 'tool'
1222
+ | 'function';
1223
+
1224
+ /** The OpenAI converter forwards `assistant` / `user` / `system` / `developer`
1225
+ * / `tool` / `function`; the Google converter additionally reads `ai`,
1226
+ * `model` and `supervisor` as the model turn and `human` as the user. */
1227
+ const GENERIC_MESSAGE_ROLES: Readonly<Record<string, ProviderMessageRole>> = {
1228
+ assistant: 'assistant',
1229
+ ai: 'assistant',
1230
+ model: 'assistant',
1231
+ supervisor: 'assistant',
1232
+ user: 'user',
1233
+ human: 'user',
1234
+ system: 'system',
1235
+ developer: 'system',
1236
+ tool: 'tool',
1237
+ function: 'function',
1238
+ };
1239
+
1240
+ /**
1241
+ * Normalizes a message to the role a provider converter would send it as. A
1242
+ * `ChatMessage` reports its type as `generic` and carries the wire role on
1243
+ * `role`, so every classifier that keys on `getType()` alone silently skips
1244
+ * generic assistant, tool and function messages the converters accept.
1245
+ */
1246
+ export function getProviderMessageRole(
1247
+ message: BaseMessage,
1248
+ provider?: ProviderName
1249
+ ): ProviderMessageRole | undefined {
1250
+ const type = message.getType();
1251
+ switch (type) {
1252
+ case 'ai':
1253
+ return 'assistant';
1254
+ case 'human':
1255
+ return 'user';
1256
+ case 'system':
1257
+ return 'system';
1258
+ case 'tool':
1259
+ return 'tool';
1260
+ case 'function':
1261
+ return 'function';
1262
+ case 'generic': {
1263
+ if (provider != null && getProviderFamily(provider) === 'bedrock') {
1264
+ return 'user';
1265
+ }
1266
+ const role = (message as Partial<ChatMessage>).role;
1267
+ return typeof role === 'string' ? GENERIC_MESSAGE_ROLES[role] : undefined;
1268
+ }
1269
+ default:
1270
+ return undefined;
1271
+ }
1272
+ }
1273
+
1274
+ export function getRawToolCallDescriptor(
1275
+ toolCall: unknown
1276
+ ): ProviderToolCallPartDescriptor | undefined {
1277
+ const callId = readOwnString(toolCall, 'id');
1278
+ if (callId == null) {
1279
+ return undefined;
1280
+ }
1281
+ let name: string | undefined;
1282
+ if (toolCall != null && typeof toolCall === 'object') {
1283
+ try {
1284
+ const property = Object.getOwnPropertyDescriptor(toolCall, 'function');
1285
+ name =
1286
+ property != null && 'value' in property
1287
+ ? readOwnString(property.value, 'name')
1288
+ : undefined;
1289
+ } catch {
1290
+ return undefined;
1291
+ }
1292
+ }
1293
+ return {
1294
+ callId,
1295
+ kind: 'tool',
1296
+ sourceType: 'raw_tool_calls',
1297
+ ...(name == null ? {} : { name }),
1298
+ };
1299
+ }
1300
+
1301
+ /**
1302
+ * Appends every tool call an assistant message carries: parsed
1303
+ * `AIMessage.tool_calls`, raw `additional_kwargs.tool_calls` (where OpenAI
1304
+ * keeps calls when the parsed array is empty) and a legacy
1305
+ * `additional_kwargs.function_call`. Content-block calls are the caller's to
1306
+ * append, since only the caller knows whether the block is being replayed.
1307
+ * Returns how many descriptors were recognized, so a caller can tell an
1308
+ * invocation from a plain assistant turn without re-deriving the shapes.
1309
+ */
1310
+ export function appendProviderMessageToolCalls(
1311
+ message: BaseMessage,
1312
+ calls: ProviderToolCallIndex,
1313
+ provider?: ProviderName
1314
+ ): number {
1315
+ if (getProviderMessageRole(message, provider) !== 'assistant') {
1316
+ return 0;
1317
+ }
1318
+ let recognized = 0;
1319
+ const toolCalls = getBoundedProviderPairingArrayProperty(
1320
+ message,
1321
+ 'tool_calls'
1322
+ );
1323
+ if (toolCalls != null) {
1324
+ for (let index = 0; index < toolCalls.length; index++) {
1325
+ const descriptor = getProviderAIMessageToolCallDescriptor(
1326
+ toolCalls[index]
1327
+ );
1328
+ if (descriptor != null) {
1329
+ appendProviderToolCallDescriptor(calls, descriptor);
1330
+ recognized += 1;
1331
+ }
1332
+ }
1333
+ }
1334
+
1335
+ const rawToolCalls = getBoundedProviderPairingArrayProperty(
1336
+ message.additional_kwargs,
1337
+ 'tool_calls'
1338
+ );
1339
+ if (rawToolCalls != null) {
1340
+ for (let index = 0; index < rawToolCalls.length; index++) {
1341
+ const descriptor = getRawToolCallDescriptor(rawToolCalls[index]);
1342
+ if (descriptor != null) {
1343
+ appendProviderToolCallDescriptor(calls, descriptor);
1344
+ recognized += 1;
1345
+ }
1346
+ }
1347
+ }
1348
+
1349
+ const legacyFunctionCall = readOwnValue(
1350
+ message.additional_kwargs,
1351
+ 'function_call'
1352
+ );
1353
+ const legacyFunctionName = readOwnString(legacyFunctionCall, 'name');
1354
+ const legacyFunctionCallId =
1355
+ legacyFunctionName == null
1356
+ ? undefined
1357
+ : getLegacyFunctionCallId(legacyFunctionName);
1358
+ if (legacyFunctionCallId != null) {
1359
+ appendProviderToolCallDescriptor(calls, {
1360
+ callId: legacyFunctionCallId,
1361
+ kind: 'tool',
1362
+ name: legacyFunctionName,
1363
+ sourceType: 'legacy_function_call',
1364
+ });
1365
+ recognized += 1;
1366
+ }
1367
+ return recognized;
1368
+ }
1369
+
1370
+ /** Describes a whole-message tool result: a `ToolMessage`, a `FunctionMessage`,
1371
+ * or a generic message carrying the equivalent wire role. */
1372
+ export function getProviderToolMessageResultDescriptor(
1373
+ message: BaseMessage,
1374
+ provider?: ProviderName
1375
+ ): ProviderToolResultPartDescriptor | undefined {
1376
+ const role = getProviderMessageRole(message, provider);
1377
+ if (role === 'function' && message.name != null) {
1378
+ const toolCallId = getLegacyFunctionCallId(message.name);
1379
+ return toolCallId == null
1380
+ ? undefined
1381
+ : {
1382
+ type: 'function_message',
1383
+ toolCallId,
1384
+ compatibleCallKinds: ['tool'],
1385
+ expectedToolNames: [message.name],
1386
+ };
1387
+ }
1388
+ if (role !== 'tool') {
1389
+ return undefined;
1390
+ }
1391
+ const toolMessage = message as ToolMessage & { toolCallId?: unknown };
1392
+ const toolCallId =
1393
+ typeof toolMessage.tool_call_id === 'string'
1394
+ ? toolMessage.tool_call_id
1395
+ : toolMessage.toolCallId;
1396
+ return typeof toolCallId === 'string' &&
1397
+ toolCallId !== '' &&
1398
+ toolCallId.length <= PROVIDER_TOOL_PAIRING_MAX_IDENTIFIER_CHARS
1399
+ ? {
1400
+ type: 'tool_message',
1401
+ toolCallId,
1402
+ compatibleCallKinds: ['tool'],
1403
+ }
1404
+ : undefined;
1405
+ }