@librechat/agents 2.4.322 → 3.0.0-rc1

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 (258) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +218 -0
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -0
  3. package/dist/cjs/common/enum.cjs +14 -5
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/events.cjs +10 -6
  6. package/dist/cjs/events.cjs.map +1 -1
  7. package/dist/cjs/graphs/Graph.cjs +309 -212
  8. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  9. package/dist/cjs/graphs/MultiAgentGraph.cjs +322 -0
  10. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -0
  11. package/dist/cjs/llm/anthropic/index.cjs +54 -9
  12. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  13. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  14. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +52 -6
  15. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  16. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +22 -2
  17. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  18. package/dist/cjs/llm/anthropic/utils/tools.cjs +29 -0
  19. package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -0
  20. package/dist/cjs/llm/google/index.cjs +144 -0
  21. package/dist/cjs/llm/google/index.cjs.map +1 -0
  22. package/dist/cjs/llm/google/utils/common.cjs +477 -0
  23. package/dist/cjs/llm/google/utils/common.cjs.map +1 -0
  24. package/dist/cjs/llm/ollama/index.cjs +67 -0
  25. package/dist/cjs/llm/ollama/index.cjs.map +1 -0
  26. package/dist/cjs/llm/ollama/utils.cjs +158 -0
  27. package/dist/cjs/llm/ollama/utils.cjs.map +1 -0
  28. package/dist/cjs/llm/openai/index.cjs +389 -3
  29. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  30. package/dist/cjs/llm/openai/utils/index.cjs +672 -0
  31. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -0
  32. package/dist/cjs/llm/providers.cjs +15 -15
  33. package/dist/cjs/llm/providers.cjs.map +1 -1
  34. package/dist/cjs/llm/text.cjs +14 -3
  35. package/dist/cjs/llm/text.cjs.map +1 -1
  36. package/dist/cjs/llm/vertexai/index.cjs +330 -0
  37. package/dist/cjs/llm/vertexai/index.cjs.map +1 -0
  38. package/dist/cjs/main.cjs +11 -0
  39. package/dist/cjs/main.cjs.map +1 -1
  40. package/dist/cjs/run.cjs +120 -81
  41. package/dist/cjs/run.cjs.map +1 -1
  42. package/dist/cjs/stream.cjs +85 -51
  43. package/dist/cjs/stream.cjs.map +1 -1
  44. package/dist/cjs/tools/ToolNode.cjs +10 -4
  45. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  46. package/dist/cjs/tools/handlers.cjs +119 -13
  47. package/dist/cjs/tools/handlers.cjs.map +1 -1
  48. package/dist/cjs/tools/search/anthropic.cjs +40 -0
  49. package/dist/cjs/tools/search/anthropic.cjs.map +1 -0
  50. package/dist/cjs/tools/search/firecrawl.cjs +55 -9
  51. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  52. package/dist/cjs/tools/search/format.cjs +6 -6
  53. package/dist/cjs/tools/search/format.cjs.map +1 -1
  54. package/dist/cjs/tools/search/rerankers.cjs +7 -29
  55. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  56. package/dist/cjs/tools/search/search.cjs +86 -16
  57. package/dist/cjs/tools/search/search.cjs.map +1 -1
  58. package/dist/cjs/tools/search/tool.cjs +4 -2
  59. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  60. package/dist/cjs/tools/search/utils.cjs +1 -1
  61. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  62. package/dist/cjs/utils/events.cjs +31 -0
  63. package/dist/cjs/utils/events.cjs.map +1 -0
  64. package/dist/cjs/utils/title.cjs +57 -21
  65. package/dist/cjs/utils/title.cjs.map +1 -1
  66. package/dist/cjs/utils/tokens.cjs +54 -7
  67. package/dist/cjs/utils/tokens.cjs.map +1 -1
  68. package/dist/esm/agents/AgentContext.mjs +216 -0
  69. package/dist/esm/agents/AgentContext.mjs.map +1 -0
  70. package/dist/esm/common/enum.mjs +15 -6
  71. package/dist/esm/common/enum.mjs.map +1 -1
  72. package/dist/esm/events.mjs +10 -6
  73. package/dist/esm/events.mjs.map +1 -1
  74. package/dist/esm/graphs/Graph.mjs +311 -214
  75. package/dist/esm/graphs/Graph.mjs.map +1 -1
  76. package/dist/esm/graphs/MultiAgentGraph.mjs +320 -0
  77. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -0
  78. package/dist/esm/llm/anthropic/index.mjs +54 -9
  79. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  80. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  81. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +52 -6
  82. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  83. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +22 -2
  84. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  85. package/dist/esm/llm/anthropic/utils/tools.mjs +27 -0
  86. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -0
  87. package/dist/esm/llm/google/index.mjs +142 -0
  88. package/dist/esm/llm/google/index.mjs.map +1 -0
  89. package/dist/esm/llm/google/utils/common.mjs +471 -0
  90. package/dist/esm/llm/google/utils/common.mjs.map +1 -0
  91. package/dist/esm/llm/ollama/index.mjs +65 -0
  92. package/dist/esm/llm/ollama/index.mjs.map +1 -0
  93. package/dist/esm/llm/ollama/utils.mjs +155 -0
  94. package/dist/esm/llm/ollama/utils.mjs.map +1 -0
  95. package/dist/esm/llm/openai/index.mjs +388 -4
  96. package/dist/esm/llm/openai/index.mjs.map +1 -1
  97. package/dist/esm/llm/openai/utils/index.mjs +666 -0
  98. package/dist/esm/llm/openai/utils/index.mjs.map +1 -0
  99. package/dist/esm/llm/providers.mjs +5 -5
  100. package/dist/esm/llm/providers.mjs.map +1 -1
  101. package/dist/esm/llm/text.mjs +14 -3
  102. package/dist/esm/llm/text.mjs.map +1 -1
  103. package/dist/esm/llm/vertexai/index.mjs +328 -0
  104. package/dist/esm/llm/vertexai/index.mjs.map +1 -0
  105. package/dist/esm/main.mjs +6 -5
  106. package/dist/esm/main.mjs.map +1 -1
  107. package/dist/esm/run.mjs +121 -83
  108. package/dist/esm/run.mjs.map +1 -1
  109. package/dist/esm/stream.mjs +87 -54
  110. package/dist/esm/stream.mjs.map +1 -1
  111. package/dist/esm/tools/ToolNode.mjs +10 -4
  112. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  113. package/dist/esm/tools/handlers.mjs +119 -15
  114. package/dist/esm/tools/handlers.mjs.map +1 -1
  115. package/dist/esm/tools/search/anthropic.mjs +37 -0
  116. package/dist/esm/tools/search/anthropic.mjs.map +1 -0
  117. package/dist/esm/tools/search/firecrawl.mjs +55 -9
  118. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  119. package/dist/esm/tools/search/format.mjs +7 -7
  120. package/dist/esm/tools/search/format.mjs.map +1 -1
  121. package/dist/esm/tools/search/rerankers.mjs +7 -29
  122. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  123. package/dist/esm/tools/search/search.mjs +86 -16
  124. package/dist/esm/tools/search/search.mjs.map +1 -1
  125. package/dist/esm/tools/search/tool.mjs +4 -2
  126. package/dist/esm/tools/search/tool.mjs.map +1 -1
  127. package/dist/esm/tools/search/utils.mjs +1 -1
  128. package/dist/esm/tools/search/utils.mjs.map +1 -1
  129. package/dist/esm/utils/events.mjs +29 -0
  130. package/dist/esm/utils/events.mjs.map +1 -0
  131. package/dist/esm/utils/title.mjs +57 -22
  132. package/dist/esm/utils/title.mjs.map +1 -1
  133. package/dist/esm/utils/tokens.mjs +54 -8
  134. package/dist/esm/utils/tokens.mjs.map +1 -1
  135. package/dist/types/agents/AgentContext.d.ts +91 -0
  136. package/dist/types/common/enum.d.ts +15 -6
  137. package/dist/types/events.d.ts +5 -4
  138. package/dist/types/graphs/Graph.d.ts +64 -67
  139. package/dist/types/graphs/MultiAgentGraph.d.ts +37 -0
  140. package/dist/types/graphs/index.d.ts +1 -0
  141. package/dist/types/llm/anthropic/index.d.ts +11 -0
  142. package/dist/types/llm/anthropic/types.d.ts +9 -3
  143. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
  144. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +4 -4
  145. package/dist/types/llm/anthropic/utils/tools.d.ts +3 -0
  146. package/dist/types/llm/google/index.d.ts +13 -0
  147. package/dist/types/llm/google/types.d.ts +32 -0
  148. package/dist/types/llm/google/utils/common.d.ts +19 -0
  149. package/dist/types/llm/google/utils/tools.d.ts +10 -0
  150. package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +14 -0
  151. package/dist/types/llm/ollama/index.d.ts +7 -0
  152. package/dist/types/llm/ollama/utils.d.ts +7 -0
  153. package/dist/types/llm/openai/index.d.ts +72 -3
  154. package/dist/types/llm/openai/types.d.ts +10 -0
  155. package/dist/types/llm/openai/utils/index.d.ts +20 -0
  156. package/dist/types/llm/text.d.ts +1 -1
  157. package/dist/types/llm/vertexai/index.d.ts +293 -0
  158. package/dist/types/messages/reducer.d.ts +9 -0
  159. package/dist/types/run.d.ts +19 -12
  160. package/dist/types/scripts/ant_web_search.d.ts +1 -0
  161. package/dist/types/scripts/args.d.ts +2 -1
  162. package/dist/types/scripts/handoff-test.d.ts +1 -0
  163. package/dist/types/scripts/multi-agent-conditional.d.ts +1 -0
  164. package/dist/types/scripts/multi-agent-parallel.d.ts +1 -0
  165. package/dist/types/scripts/multi-agent-sequence.d.ts +1 -0
  166. package/dist/types/scripts/multi-agent-test.d.ts +1 -0
  167. package/dist/types/stream.d.ts +10 -3
  168. package/dist/types/tools/CodeExecutor.d.ts +2 -2
  169. package/dist/types/tools/ToolNode.d.ts +1 -1
  170. package/dist/types/tools/handlers.d.ts +17 -4
  171. package/dist/types/tools/search/anthropic.d.ts +16 -0
  172. package/dist/types/tools/search/firecrawl.d.ts +15 -0
  173. package/dist/types/tools/search/rerankers.d.ts +0 -1
  174. package/dist/types/tools/search/types.d.ts +30 -9
  175. package/dist/types/types/graph.d.ts +95 -15
  176. package/dist/types/types/llm.d.ts +24 -10
  177. package/dist/types/types/run.d.ts +46 -8
  178. package/dist/types/types/stream.d.ts +16 -2
  179. package/dist/types/types/tools.d.ts +1 -1
  180. package/dist/types/utils/events.d.ts +6 -0
  181. package/dist/types/utils/title.d.ts +2 -1
  182. package/dist/types/utils/tokens.d.ts +24 -0
  183. package/package.json +33 -17
  184. package/src/agents/AgentContext.ts +315 -0
  185. package/src/common/enum.ts +14 -5
  186. package/src/events.ts +24 -13
  187. package/src/graphs/Graph.ts +495 -312
  188. package/src/graphs/MultiAgentGraph.ts +381 -0
  189. package/src/graphs/index.ts +2 -1
  190. package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
  191. package/src/llm/anthropic/index.ts +78 -13
  192. package/src/llm/anthropic/llm.spec.ts +491 -115
  193. package/src/llm/anthropic/types.ts +39 -3
  194. package/src/llm/anthropic/utils/message_inputs.ts +67 -11
  195. package/src/llm/anthropic/utils/message_outputs.ts +21 -2
  196. package/src/llm/anthropic/utils/output_parsers.ts +25 -6
  197. package/src/llm/anthropic/utils/tools.ts +29 -0
  198. package/src/llm/google/index.ts +218 -0
  199. package/src/llm/google/types.ts +43 -0
  200. package/src/llm/google/utils/common.ts +646 -0
  201. package/src/llm/google/utils/tools.ts +160 -0
  202. package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
  203. package/src/llm/ollama/index.ts +89 -0
  204. package/src/llm/ollama/utils.ts +193 -0
  205. package/src/llm/openai/index.ts +600 -14
  206. package/src/llm/openai/types.ts +24 -0
  207. package/src/llm/openai/utils/index.ts +912 -0
  208. package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
  209. package/src/llm/providers.ts +10 -9
  210. package/src/llm/text.ts +26 -7
  211. package/src/llm/vertexai/index.ts +360 -0
  212. package/src/messages/reducer.ts +80 -0
  213. package/src/run.ts +181 -112
  214. package/src/scripts/ant_web_search.ts +158 -0
  215. package/src/scripts/args.ts +12 -8
  216. package/src/scripts/cli4.ts +29 -21
  217. package/src/scripts/cli5.ts +29 -21
  218. package/src/scripts/code_exec.ts +54 -23
  219. package/src/scripts/code_exec_files.ts +48 -17
  220. package/src/scripts/code_exec_simple.ts +46 -27
  221. package/src/scripts/handoff-test.ts +135 -0
  222. package/src/scripts/image.ts +52 -20
  223. package/src/scripts/multi-agent-conditional.ts +220 -0
  224. package/src/scripts/multi-agent-example-output.md +110 -0
  225. package/src/scripts/multi-agent-parallel.ts +337 -0
  226. package/src/scripts/multi-agent-sequence.ts +212 -0
  227. package/src/scripts/multi-agent-test.ts +186 -0
  228. package/src/scripts/search.ts +1 -9
  229. package/src/scripts/simple.ts +25 -10
  230. package/src/scripts/tools.ts +48 -18
  231. package/src/specs/anthropic.simple.test.ts +150 -34
  232. package/src/specs/azure.simple.test.ts +325 -0
  233. package/src/specs/openai.simple.test.ts +140 -33
  234. package/src/specs/openrouter.simple.test.ts +107 -0
  235. package/src/specs/prune.test.ts +4 -9
  236. package/src/specs/reasoning.test.ts +80 -44
  237. package/src/specs/token-memoization.test.ts +39 -0
  238. package/src/stream.test.ts +94 -0
  239. package/src/stream.ts +139 -60
  240. package/src/tools/ToolNode.ts +21 -7
  241. package/src/tools/handlers.ts +192 -18
  242. package/src/tools/search/anthropic.ts +51 -0
  243. package/src/tools/search/firecrawl.ts +69 -20
  244. package/src/tools/search/format.ts +6 -8
  245. package/src/tools/search/rerankers.ts +7 -40
  246. package/src/tools/search/search.ts +97 -16
  247. package/src/tools/search/tool.ts +5 -2
  248. package/src/tools/search/types.ts +30 -10
  249. package/src/tools/search/utils.ts +1 -1
  250. package/src/types/graph.ts +272 -103
  251. package/src/types/llm.ts +25 -12
  252. package/src/types/run.ts +51 -13
  253. package/src/types/stream.ts +22 -1
  254. package/src/types/tools.ts +16 -10
  255. package/src/utils/events.ts +32 -0
  256. package/src/utils/llmConfig.ts +19 -7
  257. package/src/utils/title.ts +104 -30
  258. package/src/utils/tokens.ts +69 -10
@@ -1,10 +1,16 @@
1
+ /* eslint-disable no-process-env */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import { config } from 'dotenv';
4
+ config();
1
5
  import { expect, test } from '@jest/globals';
2
6
  import * as fs from 'fs/promises';
3
7
  import {
8
+ AIMessage,
4
9
  AIMessageChunk,
5
10
  BaseMessage,
6
11
  HumanMessage,
7
12
  SystemMessage,
13
+ ToolMessage,
8
14
  } from '@langchain/core/messages';
9
15
  import { ChatPromptValue } from '@langchain/core/prompt_values';
10
16
  import {
@@ -16,13 +22,53 @@ import {
16
22
  } from '@langchain/core/prompts';
17
23
  import { CallbackManager } from '@langchain/core/callbacks/manager';
18
24
  import { concat } from '@langchain/core/utils/stream';
25
+ import { AnthropicVertex } from '@anthropic-ai/vertex-sdk';
26
+ import { BaseLanguageModelInput } from '@langchain/core/language_models/base';
27
+ import { tool } from '@langchain/core/tools';
28
+ import { z } from 'zod';
19
29
  import { CustomAnthropic as ChatAnthropic } from './index';
20
- import { AnthropicMessageResponse } from './types';
30
+ import { AnthropicMessageResponse, ChatAnthropicContentBlock } from './types';
21
31
  jest.setTimeout(120000);
22
32
 
33
+ async function invoke(
34
+ chat: ChatAnthropic,
35
+ invocationType: string,
36
+ input: BaseLanguageModelInput
37
+ ): Promise<AIMessageChunk | AIMessage> {
38
+ if (invocationType === 'stream') {
39
+ let output: AIMessageChunk | undefined;
40
+
41
+ const stream = await chat.stream(input);
42
+
43
+ for await (const chunk of stream) {
44
+ if (!output) {
45
+ output = chunk;
46
+ } else {
47
+ output = output.concat(chunk);
48
+ }
49
+ }
50
+
51
+ return output!;
52
+ }
53
+
54
+ return chat.invoke(input);
55
+ }
56
+
57
+ // use this for tests involving "extended thinking"
58
+ const extendedThinkingModelName = 'claude-3-7-sonnet-20250219';
59
+
60
+ // use this for tests involving citations
61
+ const citationsModelName = 'claude-3-5-sonnet-20241022';
62
+
63
+ // use this for tests involving PDF documents
64
+ const pdfModelName = 'claude-3-5-haiku-20241022';
65
+
66
+ // Use this model for all other tests
67
+ const modelName = 'claude-3-haiku-20240307';
68
+
23
69
  test('Test ChatAnthropic', async () => {
24
70
  const chat = new ChatAnthropic({
25
- modelName: 'claude-3-sonnet-20240229',
71
+ modelName,
26
72
  maxRetries: 0,
27
73
  });
28
74
  const message = new HumanMessage('Hello!');
@@ -32,7 +78,7 @@ test('Test ChatAnthropic', async () => {
32
78
 
33
79
  test('Test ChatAnthropic with a bad API key throws appropriate error', async () => {
34
80
  const chat = new ChatAnthropic({
35
- modelName: 'claude-3-sonnet-20240229',
81
+ modelName,
36
82
  maxRetries: 0,
37
83
  apiKey: 'bad',
38
84
  });
@@ -65,7 +111,7 @@ test('Test ChatAnthropic with unknown model throws appropriate error', async ()
65
111
 
66
112
  test('Test ChatAnthropic Generate', async () => {
67
113
  const chat = new ChatAnthropic({
68
- modelName: 'claude-3-sonnet-20240229',
114
+ modelName,
69
115
  maxRetries: 0,
70
116
  });
71
117
  const message = new HumanMessage('Hello!');
@@ -73,7 +119,6 @@ test('Test ChatAnthropic Generate', async () => {
73
119
  expect(res.generations.length).toBe(2);
74
120
  for (const generation of res.generations) {
75
121
  expect(generation.length).toBe(1);
76
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
77
122
  for (const message of generation) {
78
123
  // console.log(message.text);
79
124
  }
@@ -83,7 +128,7 @@ test('Test ChatAnthropic Generate', async () => {
83
128
 
84
129
  test.skip('Test ChatAnthropic Generate w/ ClientOptions', async () => {
85
130
  const chat = new ChatAnthropic({
86
- modelName: 'claude-3-sonnet-20240229',
131
+ modelName,
87
132
  maxRetries: 0,
88
133
  clientOptions: {
89
134
  defaultHeaders: {
@@ -96,7 +141,6 @@ test.skip('Test ChatAnthropic Generate w/ ClientOptions', async () => {
96
141
  expect(res.generations.length).toBe(2);
97
142
  for (const generation of res.generations) {
98
143
  expect(generation.length).toBe(1);
99
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
100
144
  for (const message of generation) {
101
145
  // console.log(message.text);
102
146
  }
@@ -106,7 +150,7 @@ test.skip('Test ChatAnthropic Generate w/ ClientOptions', async () => {
106
150
 
107
151
  test('Test ChatAnthropic Generate with a signal in call options', async () => {
108
152
  const chat = new ChatAnthropic({
109
- modelName: 'claude-3-sonnet-20240229',
153
+ modelName,
110
154
  maxRetries: 0,
111
155
  });
112
156
  const controller = new AbortController();
@@ -128,9 +172,8 @@ test('Test ChatAnthropic tokenUsage with a batch', async () => {
128
172
  const model = new ChatAnthropic({
129
173
  temperature: 0,
130
174
  maxRetries: 0,
131
- modelName: 'claude-3-sonnet-20240229',
175
+ modelName,
132
176
  });
133
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
134
177
  const res = await model.generate([
135
178
  [new HumanMessage(`Hello!`)],
136
179
  [new HumanMessage(`Hi!`)],
@@ -143,7 +186,7 @@ test('Test ChatAnthropic in streaming mode', async () => {
143
186
  let streamedCompletion = '';
144
187
 
145
188
  const model = new ChatAnthropic({
146
- modelName: 'claude-3-sonnet-20240229',
189
+ modelName,
147
190
  maxRetries: 0,
148
191
  streaming: true,
149
192
  callbacks: CallbackManager.fromHandlers({
@@ -166,7 +209,7 @@ test('Test ChatAnthropic in streaming mode with a signal', async () => {
166
209
  let streamedCompletion = '';
167
210
 
168
211
  const model = new ChatAnthropic({
169
- modelName: 'claude-3-sonnet-20240229',
212
+ modelName,
170
213
  maxRetries: 0,
171
214
  streaming: true,
172
215
  callbacks: CallbackManager.fromHandlers({
@@ -195,14 +238,13 @@ test('Test ChatAnthropic in streaming mode with a signal', async () => {
195
238
 
196
239
  test.skip('Test ChatAnthropic prompt value', async () => {
197
240
  const chat = new ChatAnthropic({
198
- modelName: 'claude-3-sonnet-20240229',
241
+ modelName,
199
242
  maxRetries: 0,
200
243
  });
201
244
  const message = new HumanMessage('Hello!');
202
245
  const res = await chat.generatePrompt([new ChatPromptValue([message])]);
203
246
  expect(res.generations.length).toBe(1);
204
247
  for (const generation of res.generations) {
205
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
206
248
  for (const g of generation) {
207
249
  // console.log(g.text);
208
250
  }
@@ -212,7 +254,7 @@ test.skip('Test ChatAnthropic prompt value', async () => {
212
254
 
213
255
  test.skip('ChatAnthropic, docs, prompt templates', async () => {
214
256
  const chat = new ChatAnthropic({
215
- modelName: 'claude-3-sonnet-20240229',
257
+ modelName,
216
258
  maxRetries: 0,
217
259
  temperature: 0,
218
260
  });
@@ -226,7 +268,6 @@ test.skip('ChatAnthropic, docs, prompt templates', async () => {
226
268
  HumanMessagePromptTemplate.fromTemplate('{text}'),
227
269
  ]);
228
270
 
229
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
230
271
  const responseA = await chat.generatePrompt([
231
272
  await chatPrompt.formatPromptValue({
232
273
  input_language: 'English',
@@ -240,7 +281,7 @@ test.skip('ChatAnthropic, docs, prompt templates', async () => {
240
281
 
241
282
  test.skip('ChatAnthropic, longer chain of messages', async () => {
242
283
  const chat = new ChatAnthropic({
243
- modelName: 'claude-3-sonnet-20240229',
284
+ modelName,
244
285
  maxRetries: 0,
245
286
  temperature: 0,
246
287
  });
@@ -251,7 +292,6 @@ test.skip('ChatAnthropic, longer chain of messages', async () => {
251
292
  HumanMessagePromptTemplate.fromTemplate('{text}'),
252
293
  ]);
253
294
 
254
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
255
295
  const responseA = await chat.generatePrompt([
256
296
  await chatPrompt.formatPromptValue({
257
297
  text: 'What did I just say my name was?',
@@ -265,12 +305,11 @@ test.skip('ChatAnthropic, Anthropic apiUrl set manually via constructor', async
265
305
  // Pass the default URL through (should use this, and work as normal)
266
306
  const anthropicApiUrl = 'https://api.anthropic.com';
267
307
  const chat = new ChatAnthropic({
268
- modelName: 'claude-3-sonnet-20240229',
308
+ modelName,
269
309
  maxRetries: 0,
270
310
  anthropicApiUrl,
271
311
  });
272
312
  const message = new HumanMessage('Hello!');
273
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
274
313
  const res = await chat.call([message]);
275
314
  // console.log({ res });
276
315
  });
@@ -279,10 +318,10 @@ test('Test ChatAnthropic stream method', async () => {
279
318
  const model = new ChatAnthropic({
280
319
  maxTokens: 50,
281
320
  maxRetries: 0,
282
- modelName: 'claude-3-sonnet-20240229',
321
+ modelName,
283
322
  });
284
323
  const stream = await model.stream('Print hello world.');
285
- const chunks: any[] = [];
324
+ const chunks: AIMessageChunk[] = [];
286
325
  for await (const chunk of stream) {
287
326
  chunks.push(chunk);
288
327
  }
@@ -294,7 +333,7 @@ test('Test ChatAnthropic stream method with abort', async () => {
294
333
  const model = new ChatAnthropic({
295
334
  maxTokens: 500,
296
335
  maxRetries: 0,
297
- modelName: 'claude-3-sonnet-20240229',
336
+ modelName,
298
337
  });
299
338
  const stream = await model.stream(
300
339
  'How is your day going? Be extremely verbose.',
@@ -302,7 +341,6 @@ test('Test ChatAnthropic stream method with abort', async () => {
302
341
  signal: AbortSignal.timeout(1000),
303
342
  }
304
343
  );
305
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
306
344
  for await (const chunk of stream) {
307
345
  // console.log(chunk);
308
346
  }
@@ -313,13 +351,12 @@ test('Test ChatAnthropic stream method with early break', async () => {
313
351
  const model = new ChatAnthropic({
314
352
  maxTokens: 50,
315
353
  maxRetries: 0,
316
- modelName: 'claude-3-sonnet-20240229',
354
+ modelName,
317
355
  });
318
356
  const stream = await model.stream(
319
357
  'How is your day going? Be extremely verbose.'
320
358
  );
321
359
  let i = 0;
322
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
323
360
  for await (const chunk of stream) {
324
361
  // console.log(chunk);
325
362
  i += 1;
@@ -331,7 +368,7 @@ test('Test ChatAnthropic stream method with early break', async () => {
331
368
 
332
369
  test('Test ChatAnthropic headers passed through', async () => {
333
370
  const chat = new ChatAnthropic({
334
- modelName: 'claude-3-sonnet-20240229',
371
+ modelName,
335
372
  maxRetries: 0,
336
373
  apiKey: 'NOT_REAL',
337
374
  clientOptions: {
@@ -341,36 +378,142 @@ test('Test ChatAnthropic headers passed through', async () => {
341
378
  },
342
379
  });
343
380
  const message = new HumanMessage('Hello!');
344
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
345
381
  const res = await chat.invoke([message]);
346
382
  // console.log({ res });
347
383
  });
348
384
 
349
- test('Test ChatAnthropic multimodal', async () => {
350
- const chat = new ChatAnthropic({
351
- modelName: 'claude-3-sonnet-20240229',
352
- maxRetries: 0,
353
- });
354
- // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
355
- const res = await chat.invoke([
356
- new HumanMessage({
357
- content: [
358
- {
359
- type: 'image_url',
360
- image_url: {
361
- url: 'data:image/jpeg;base64,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',
362
- },
363
- },
364
- { type: 'text', text: 'What is this a logo for?' },
365
- ],
366
- }),
367
- ]);
368
- // console.log(res);
385
+ describe('ChatAnthropic image inputs', () => {
386
+ test.each(['invoke', 'stream'])(
387
+ 'Test ChatAnthropic image_url, %s',
388
+ async (invocationType: string) => {
389
+ const chat = new ChatAnthropic({
390
+ modelName,
391
+ maxRetries: 0,
392
+ });
393
+
394
+ const dataUrlRes = invoke(chat, invocationType, [
395
+ new HumanMessage({
396
+ content: [
397
+ {
398
+ type: 'image_url',
399
+ image_url: {
400
+ url: 'data:image/jpeg;base64,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',
401
+ },
402
+ },
403
+ { type: 'text', text: 'Describe this image.' },
404
+ ],
405
+ }),
406
+ ]);
407
+
408
+ await expect(dataUrlRes).resolves.toBeDefined();
409
+
410
+ const urlRes = invoke(chat, invocationType, [
411
+ new HumanMessage({
412
+ content: [
413
+ {
414
+ type: 'image_url',
415
+ image_url:
416
+ 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/RedDisc.svg/24px-RedDisc.svg.png',
417
+ },
418
+ { type: 'text', text: 'Describe this image.' },
419
+ ],
420
+ }),
421
+ ]);
422
+
423
+ await expect(urlRes).resolves.toBeDefined();
424
+
425
+ const invalidSchemeRes = invoke(chat, invocationType, [
426
+ new HumanMessage({
427
+ content: [
428
+ {
429
+ type: 'image_url',
430
+ image_url: 'file:///path/to/image.png',
431
+ },
432
+ { type: 'text', text: 'Describe this image.' },
433
+ ],
434
+ }),
435
+ ]);
436
+
437
+ await expect(invalidSchemeRes).rejects.toThrow(
438
+ [
439
+ 'Invalid image URL protocol: "file:". Anthropic only supports images as http, https, or base64-encoded data URLs on \'image_url\' content blocks.',
440
+ 'Example: data:image/png;base64,/9j/4AAQSk...',
441
+ 'Example: https://example.com/image.jpg',
442
+ ].join('\n\n')
443
+ );
444
+
445
+ const invalidUrlRes = invoke(chat, invocationType, [
446
+ new HumanMessage({
447
+ content: [
448
+ {
449
+ type: 'image_url',
450
+ image_url: "this isn't a valid URL",
451
+ },
452
+ { type: 'text', text: 'Describe this image.' },
453
+ ],
454
+ }),
455
+ ]);
456
+
457
+ await expect(invalidUrlRes).rejects.toThrow(
458
+ [
459
+ `Malformed image URL: "this isn't a valid URL". Content blocks of type 'image_url' must be a valid http, https, or base64-encoded data URL.`,
460
+ 'Example: data:image/png;base64,/9j/4AAQSk...',
461
+ 'Example: https://example.com/image.jpg',
462
+ ].join('\n\n')
463
+ );
464
+ }
465
+ );
466
+
467
+ test.each(['invoke', 'stream'])(
468
+ 'Test ChatAnthropic Anthropic Image Block, %s',
469
+ async (invocationType: string) => {
470
+ const chat = new ChatAnthropic({
471
+ modelName,
472
+ maxRetries: 0,
473
+ });
474
+ const base64Res = invoke(chat, invocationType, [
475
+ new HumanMessage({
476
+ content: [
477
+ {
478
+ type: 'image',
479
+ source: {
480
+ type: 'base64',
481
+ media_type: 'image/jpeg',
482
+ data: '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',
483
+ },
484
+ },
485
+ {
486
+ type: 'text',
487
+ text: 'Describe this image',
488
+ },
489
+ ],
490
+ }),
491
+ ]);
492
+
493
+ await expect(base64Res).resolves.toBeDefined();
494
+
495
+ const urlRes = chat.invoke([
496
+ new HumanMessage({
497
+ content: [
498
+ {
499
+ type: 'image',
500
+ source: {
501
+ type: 'url',
502
+ url: 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/RedDisc.svg/24px-RedDisc.svg.png',
503
+ },
504
+ },
505
+ ],
506
+ }),
507
+ ]);
508
+
509
+ await expect(urlRes).resolves.toBeDefined();
510
+ }
511
+ );
369
512
  });
370
513
 
371
514
  test('Stream tokens', async () => {
372
515
  const model = new ChatAnthropic({
373
- model: 'claude-3-haiku-20240307',
516
+ modelName,
374
517
  temperature: 0,
375
518
  maxTokens: 10,
376
519
  });
@@ -397,14 +540,14 @@ test('Stream tokens', async () => {
397
540
  });
398
541
 
399
542
  test('id is supplied when invoking', async () => {
400
- const model = new ChatAnthropic();
543
+ const model = new ChatAnthropic({ modelName });
401
544
  const result = await model.invoke('Hello');
402
545
  expect(result.id).toBeDefined();
403
546
  expect(result.id).not.toEqual('');
404
547
  });
405
548
 
406
549
  test('id is supplied when streaming', async () => {
407
- const model = new ChatAnthropic();
550
+ const model = new ChatAnthropic({ modelName });
408
551
  let finalChunk: AIMessageChunk | undefined;
409
552
  for await (const chunk of await model.stream('Hello')) {
410
553
  finalChunk = !finalChunk ? chunk : concat(finalChunk, chunk);
@@ -678,7 +821,7 @@ The current date is ${new Date().toISOString()}`;
678
821
 
679
822
  test('system prompt caching', async () => {
680
823
  const model = new ChatAnthropic({
681
- model: 'claude-3-haiku-20240307',
824
+ modelName,
682
825
  clientOptions: {
683
826
  defaultHeaders: {
684
827
  'anthropic-beta': 'prompt-caching-2024-07-31',
@@ -724,7 +867,7 @@ test('system prompt caching', async () => {
724
867
  // TODO: Add proper test with long tool content
725
868
  test.skip('tool caching', async () => {
726
869
  const model = new ChatAnthropic({
727
- model: 'claude-3-haiku-20240307',
870
+ modelName,
728
871
  clientOptions: {
729
872
  defaultHeaders: {
730
873
  'anthropic-beta': 'prompt-caching-2024-07-31',
@@ -769,14 +912,22 @@ test.skip('tool caching', async () => {
769
912
  );
770
913
  });
771
914
 
915
+ test.skip('Test ChatAnthropic with custom client', async () => {
916
+ const client = new AnthropicVertex();
917
+ const chat = new ChatAnthropic({
918
+ modelName,
919
+ maxRetries: 0,
920
+ createClient: () => client,
921
+ });
922
+ const message = new HumanMessage('Hello!');
923
+ const res = await chat.invoke([message]);
924
+ // console.log({ res });
925
+ expect(res.usage_metadata?.input_token_details).toBeDefined();
926
+ });
927
+
772
928
  test('human message caching', async () => {
773
929
  const model = new ChatAnthropic({
774
- model: 'claude-3-haiku-20240307',
775
- clientOptions: {
776
- defaultHeaders: {
777
- 'anthropic-beta': 'prompt-caching-2024-07-31',
778
- },
779
- },
930
+ modelName,
780
931
  });
781
932
 
782
933
  const messages = [
@@ -784,7 +935,7 @@ test('human message caching', async () => {
784
935
  content: [
785
936
  {
786
937
  type: 'text',
787
- text: `You are a pirate. Always respond in pirate dialect.\nUse the following as context when answering questions: ${CACHED_TEXT}`,
938
+ text: `You are a scotsman. Always respond in scotsman dialect.\nUse the following as context when answering questions: ${CACHED_TEXT}`,
788
939
  },
789
940
  ],
790
941
  }),
@@ -813,11 +964,10 @@ test('human message caching', async () => {
813
964
 
814
965
  test('Can accept PDF documents', async () => {
815
966
  const model = new ChatAnthropic({
816
- model: 'claude-3-5-sonnet-latest',
967
+ modelName: pdfModelName,
817
968
  });
818
969
 
819
- const pdfPath =
820
- '../langchain-community/src/document_loaders/tests/example_data/Jacob_Lee_Resume_2023.pdf';
970
+ const pdfPath = './src/llm/anthropic/Jacob_Lee_Resume_2023.pdf';
821
971
  const pdfBase64 = await fs.readFile(pdfPath, 'base64');
822
972
 
823
973
  const response = await model.invoke([
@@ -844,70 +994,253 @@ test('Can accept PDF documents', async () => {
844
994
  expect(response.content.length).toBeGreaterThan(10);
845
995
  });
846
996
 
847
- test('Citations', async () => {
848
- const citationsModel = new ChatAnthropic({
849
- model: 'claude-3-5-sonnet-latest',
997
+ describe('Citations', () => {
998
+ test('document blocks', async () => {
999
+ const citationsModel = new ChatAnthropic({
1000
+ model: citationsModelName,
1001
+ });
1002
+ const messages = [
1003
+ {
1004
+ role: 'user',
1005
+ content: [
1006
+ {
1007
+ type: 'document',
1008
+ source: {
1009
+ type: 'text',
1010
+ media_type: 'text/plain',
1011
+ data: "The grass the user is asking about is bluegrass. The sky is orange because it's night.",
1012
+ },
1013
+ title: 'My Document',
1014
+ context: 'This is a trustworthy document.',
1015
+ citations: {
1016
+ enabled: true,
1017
+ },
1018
+ },
1019
+ {
1020
+ type: 'text',
1021
+ text: 'What color is the grass and sky?',
1022
+ },
1023
+ ],
1024
+ },
1025
+ ];
1026
+
1027
+ const response = await citationsModel.invoke(messages);
1028
+
1029
+ expect(response.content.length).toBeGreaterThan(2);
1030
+ expect(Array.isArray(response.content)).toBe(true);
1031
+ const blocksWithCitations = (response.content as any[]).filter(
1032
+ (block) => block.citations !== undefined
1033
+ );
1034
+ expect(blocksWithCitations.length).toEqual(2);
1035
+ expect(typeof blocksWithCitations[0].citations[0]).toEqual('object');
1036
+
1037
+ const stream = await citationsModel.stream(messages);
1038
+ let aggregated;
1039
+ let chunkHasCitation = false;
1040
+ for await (const chunk of stream) {
1041
+ aggregated = aggregated === undefined ? chunk : concat(aggregated, chunk);
1042
+ if (
1043
+ !chunkHasCitation &&
1044
+ Array.isArray(chunk.content) &&
1045
+ chunk.content.some((c: any) => c.citations !== undefined)
1046
+ ) {
1047
+ chunkHasCitation = true;
1048
+ }
1049
+ }
1050
+ expect(chunkHasCitation).toBe(true);
1051
+ expect(Array.isArray(aggregated?.content)).toBe(true);
1052
+ expect(aggregated?.content.length).toBeGreaterThan(2);
1053
+ expect(
1054
+ (aggregated?.content as any[]).some((c) => c.citations !== undefined)
1055
+ ).toBe(true);
850
1056
  });
1057
+ describe('search result blocks', () => {
1058
+ const citationsModel = new ChatAnthropic({
1059
+ model: citationsModelName,
1060
+ clientOptions: {
1061
+ defaultHeaders: {
1062
+ 'anthropic-beta': 'search-results-2025-06-09',
1063
+ },
1064
+ },
1065
+ });
851
1066
 
852
- const messages = [
853
- {
854
- role: 'user',
855
- content: [
856
- {
857
- type: 'document',
858
- source: {
859
- type: 'text',
860
- media_type: 'text/plain',
861
- data: "The grass the user is asking about is bluegrass. The sky is orange because it's night.",
1067
+ const messages = [
1068
+ {
1069
+ role: 'user',
1070
+ content: [
1071
+ {
1072
+ type: 'search_result',
1073
+ title: 'History of France',
1074
+ source: 'https://example.com/france-history',
1075
+ citations: { enabled: true },
1076
+ content: [
1077
+ {
1078
+ type: 'text',
1079
+ text: 'The capital of France is Paris.',
1080
+ },
1081
+ {
1082
+ type: 'text',
1083
+ text: 'The old capital of France was Lyon.',
1084
+ },
1085
+ ],
1086
+ },
1087
+ {
1088
+ type: 'search_result',
1089
+ title: 'Geography of France',
1090
+ source: 'https://example.com/france-geography',
1091
+ citations: { enabled: true },
1092
+ content: [
1093
+ {
1094
+ type: 'text',
1095
+ text: 'France is a country in Europe.',
1096
+ },
1097
+ {
1098
+ type: 'text',
1099
+ text: 'France borders Spain to the south.',
1100
+ },
1101
+ ],
862
1102
  },
863
- title: 'My Document',
864
- context: 'This is a trustworthy document.',
865
- citations: {
866
- enabled: true,
1103
+ {
1104
+ type: 'text',
1105
+ text: 'What is the capital of France and where is it located? You must cite your sources.',
867
1106
  },
1107
+ ],
1108
+ },
1109
+ ];
1110
+
1111
+ test('without streaming', async () => {
1112
+ const response = await citationsModel.invoke(messages);
1113
+
1114
+ expect(Array.isArray(response.content)).toBe(true);
1115
+ expect(response.content.length).toBeGreaterThan(0);
1116
+
1117
+ // Check that we have cited content
1118
+ const blocksWithCitations = (response.content as any[]).filter(
1119
+ (block) => block.citations !== undefined
1120
+ );
1121
+ expect(blocksWithCitations.length).toBeGreaterThan(0);
1122
+
1123
+ // Verify citation structure
1124
+ const citation = blocksWithCitations[0].citations[0];
1125
+ expect(typeof citation).toBe('object');
1126
+ expect(citation.type).toBe('search_result_location');
1127
+ expect(citation.source).toBeDefined();
1128
+ });
1129
+ test('with streaming', async () => {
1130
+ // Test streaming
1131
+ const stream = await citationsModel.stream(messages);
1132
+ let aggregated;
1133
+ let chunkHasCitation = false;
1134
+ for await (const chunk of stream) {
1135
+ aggregated =
1136
+ aggregated === undefined ? chunk : concat(aggregated, chunk);
1137
+ if (
1138
+ !chunkHasCitation &&
1139
+ Array.isArray(chunk.content) &&
1140
+ chunk.content.some((c: any) => c.citations !== undefined)
1141
+ ) {
1142
+ chunkHasCitation = true;
1143
+ }
1144
+ }
1145
+ expect(chunkHasCitation).toBe(true);
1146
+ expect(Array.isArray(aggregated?.content)).toBe(true);
1147
+ expect(
1148
+ (aggregated?.content as any[]).some((c) => c.citations !== undefined)
1149
+ ).toBe(true);
1150
+ });
1151
+ });
1152
+
1153
+ test('search result blocks from tool', async () => {
1154
+ const ragTool = tool(
1155
+ (): ChatAnthropicContentBlock[] => [
1156
+ {
1157
+ type: 'search_result',
1158
+ title: 'History of France',
1159
+ source: 'https://example.com/france-history',
1160
+ citations: { enabled: true },
1161
+ content: [
1162
+ {
1163
+ type: 'text',
1164
+ text: 'The capital of France is Paris.',
1165
+ },
1166
+ {
1167
+ type: 'text',
1168
+ text: 'France was established as a republic in 1792.',
1169
+ },
1170
+ ],
868
1171
  },
869
1172
  {
870
- type: 'text',
871
- text: 'What color is the grass and sky?',
1173
+ type: 'search_result',
1174
+ title: 'Geography of France',
1175
+ source: 'https://example.com/france-geography',
1176
+ citations: { enabled: true },
1177
+ content: [
1178
+ {
1179
+ type: 'text',
1180
+ text: 'France is located in Western Europe.',
1181
+ },
1182
+ {
1183
+ type: 'text',
1184
+ text: 'France has a population of approximately 67 million people.',
1185
+ },
1186
+ ],
872
1187
  },
873
1188
  ],
874
- },
875
- ];
1189
+ {
1190
+ name: 'search_knowledge_base',
1191
+ description: 'Search the knowledge base for information about France',
1192
+ schema: z.object({
1193
+ query: z.string().describe('The search query'),
1194
+ }),
1195
+ }
1196
+ );
876
1197
 
877
- const response = await citationsModel.invoke(messages);
1198
+ const citationsModel = new ChatAnthropic({
1199
+ model: citationsModelName,
1200
+ clientOptions: {
1201
+ defaultHeaders: {
1202
+ 'anthropic-beta': 'search-results-2025-06-09',
1203
+ },
1204
+ },
1205
+ }).bindTools([ragTool]);
878
1206
 
879
- expect(response.content.length).toBeGreaterThan(2);
880
- expect(Array.isArray(response.content)).toBe(true);
881
- const blocksWithCitations = (response.content as any[]).filter(
882
- (block) => block.citations !== undefined
883
- );
884
- expect(blocksWithCitations.length).toEqual(2);
885
- expect(typeof blocksWithCitations[0].citations[0]).toEqual('object');
1207
+ const messages = [
1208
+ new HumanMessage(
1209
+ 'Search for information about France and tell me what you find with proper citations.'
1210
+ ),
1211
+ ];
886
1212
 
887
- const stream = await citationsModel.stream(messages);
888
- let aggregated;
889
- let chunkHasCitation = false;
890
- for await (const chunk of stream) {
891
- aggregated = aggregated === undefined ? chunk : concat(aggregated, chunk);
892
- if (
893
- !chunkHasCitation &&
894
- Array.isArray(chunk.content) &&
895
- chunk.content.some((c: any) => c.citations !== undefined)
896
- ) {
897
- chunkHasCitation = true;
898
- }
899
- }
900
- expect(chunkHasCitation).toBe(true);
901
- expect(Array.isArray(aggregated?.content)).toBe(true);
902
- expect(aggregated?.content.length).toBeGreaterThan(2);
903
- expect(
904
- (aggregated?.content as any[]).some((c) => c.citations !== undefined)
905
- ).toBe(true);
1213
+ const response = await citationsModel.invoke(messages);
1214
+ messages.push(response);
1215
+
1216
+ expect(Array.isArray(response.content)).toBe(true);
1217
+ expect(response.content.length).toBeGreaterThan(0);
1218
+
1219
+ // Check that the model called the tool
1220
+ expect(response.tool_calls?.length).toBeGreaterThan(0);
1221
+ expect(response.tool_calls?.[0].name).toBe('search_knowledge_base');
1222
+
1223
+ const toolResponse = await ragTool.invoke(response.tool_calls![0]);
1224
+ messages.push(toolResponse);
1225
+
1226
+ const response2 = await citationsModel.invoke(messages);
1227
+
1228
+ expect(Array.isArray(response2.content)).toBe(true);
1229
+ expect(response2.content.length).toBeGreaterThan(0);
1230
+ // Make sure that a citation exists somewhere in the content list
1231
+ const citationBlock = (response2.content as any[]).find(
1232
+ (block: any) =>
1233
+ Array.isArray(block.citations) && block.citations.length > 0
1234
+ );
1235
+ expect(citationBlock).toBeDefined();
1236
+ expect(citationBlock.citations[0].type).toBe('search_result_location');
1237
+ expect(citationBlock.citations[0].source).toBeDefined();
1238
+ });
906
1239
  });
907
1240
 
908
1241
  test('Test thinking blocks multiturn invoke', async () => {
909
1242
  const model = new ChatAnthropic({
910
- model: 'claude-3-7-sonnet-latest',
1243
+ model: extendedThinkingModelName,
911
1244
  maxTokens: 5000,
912
1245
  thinking: { type: 'enabled', budget_tokens: 2000 },
913
1246
  });
@@ -945,7 +1278,7 @@ test('Test thinking blocks multiturn invoke', async () => {
945
1278
 
946
1279
  test('Test thinking blocks multiturn streaming', async () => {
947
1280
  const model = new ChatAnthropic({
948
- model: 'claude-3-7-sonnet-latest',
1281
+ model: extendedThinkingModelName,
949
1282
  maxTokens: 5000,
950
1283
  thinking: { type: 'enabled', budget_tokens: 2000 },
951
1284
  });
@@ -986,7 +1319,7 @@ test('Test thinking blocks multiturn streaming', async () => {
986
1319
 
987
1320
  test('Test redacted thinking blocks multiturn invoke', async () => {
988
1321
  const model = new ChatAnthropic({
989
- model: 'claude-3-7-sonnet-latest',
1322
+ model: extendedThinkingModelName,
990
1323
  maxTokens: 5000,
991
1324
  thinking: { type: 'enabled', budget_tokens: 2000 },
992
1325
  });
@@ -1023,7 +1356,7 @@ test('Test redacted thinking blocks multiturn invoke', async () => {
1023
1356
 
1024
1357
  test('Test redacted thinking blocks multiturn streaming', async () => {
1025
1358
  const model = new ChatAnthropic({
1026
- model: 'claude-3-7-sonnet-latest',
1359
+ model: extendedThinkingModelName,
1027
1360
  maxTokens: 5000,
1028
1361
  thinking: { type: 'enabled', budget_tokens: 2000 },
1029
1362
  });
@@ -1064,3 +1397,46 @@ test('Test redacted thinking blocks multiturn streaming', async () => {
1064
1397
  // test a second time to make sure that we've got input translation working correctly
1065
1398
  await doStreaming(streamingMessages);
1066
1399
  });
1400
+
1401
+ test('Can handle google function calling blocks in content', async () => {
1402
+ const chat = new ChatAnthropic({
1403
+ modelName: 'claude-3-7-sonnet-latest',
1404
+ maxRetries: 0,
1405
+ });
1406
+ const toolCallId = 'tool_call_id';
1407
+ const messages = [
1408
+ new SystemMessage("You're a helpful assistant"),
1409
+ new HumanMessage('What is the weather like in San Francisco?'),
1410
+ new AIMessage({
1411
+ content: [
1412
+ {
1413
+ // Pass a content block with the `functionCall` object that Google returns.
1414
+ functionCall: {
1415
+ args: {
1416
+ location: 'san francisco',
1417
+ },
1418
+ name: 'get_weather',
1419
+ },
1420
+ },
1421
+ ],
1422
+ tool_calls: [
1423
+ {
1424
+ id: toolCallId,
1425
+ name: 'get_weather',
1426
+ args: {
1427
+ location: 'san francisco',
1428
+ },
1429
+ },
1430
+ ],
1431
+ }),
1432
+ new ToolMessage({
1433
+ tool_call_id: toolCallId,
1434
+ content: 'The weather is sunny',
1435
+ }),
1436
+ new HumanMessage(
1437
+ 'Give me a one sentence description of what the sky looks like.'
1438
+ ),
1439
+ ];
1440
+ const res = await chat.invoke(messages);
1441
+ expect(res.content.length).toBeGreaterThan(1);
1442
+ });