@librechat/agents 2.4.21 → 2.4.30

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 (42) hide show
  1. package/dist/cjs/llm/anthropic/index.cjs +1 -1
  2. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  3. package/dist/cjs/llm/anthropic/types.cjs +50 -0
  4. package/dist/cjs/llm/anthropic/types.cjs.map +1 -0
  5. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +227 -21
  6. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  7. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +1 -0
  8. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  9. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  10. package/dist/cjs/messages/core.cjs +91 -51
  11. package/dist/cjs/messages/core.cjs.map +1 -1
  12. package/dist/cjs/run.cjs.map +1 -1
  13. package/dist/esm/llm/anthropic/index.mjs +1 -1
  14. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  15. package/dist/esm/llm/anthropic/types.mjs +48 -0
  16. package/dist/esm/llm/anthropic/types.mjs.map +1 -0
  17. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +228 -22
  18. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  19. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +1 -0
  20. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  21. package/dist/esm/llm/openai/index.mjs.map +1 -1
  22. package/dist/esm/messages/core.mjs +91 -51
  23. package/dist/esm/messages/core.mjs.map +1 -1
  24. package/dist/esm/run.mjs.map +1 -1
  25. package/dist/types/llm/anthropic/index.d.ts +3 -4
  26. package/dist/types/llm/anthropic/types.d.ts +4 -35
  27. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +2 -2
  28. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -3
  29. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +22 -0
  30. package/dist/types/llm/openai/index.d.ts +3 -2
  31. package/dist/types/messages/core.d.ts +1 -1
  32. package/dist/types/tools/example.d.ts +21 -3
  33. package/package.json +9 -9
  34. package/src/llm/anthropic/index.ts +6 -5
  35. package/src/llm/anthropic/llm.spec.ts +176 -179
  36. package/src/llm/anthropic/types.ts +64 -39
  37. package/src/llm/anthropic/utils/message_inputs.ts +275 -37
  38. package/src/llm/anthropic/utils/message_outputs.ts +4 -21
  39. package/src/llm/anthropic/utils/output_parsers.ts +114 -0
  40. package/src/llm/openai/index.ts +7 -6
  41. package/src/messages/core.ts +197 -96
  42. package/src/run.ts +1 -1
@@ -1,77 +1,74 @@
1
- /* eslint-disable no-process-env */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
-
4
- import { expect, test } from "@jest/globals";
5
- import * as fs from "fs/promises";
1
+ import { expect, test } from '@jest/globals';
2
+ import * as fs from 'fs/promises';
6
3
  import {
7
4
  AIMessageChunk,
8
5
  BaseMessage,
9
6
  HumanMessage,
10
7
  SystemMessage,
11
- } from "@langchain/core/messages";
12
- import { ChatPromptValue } from "@langchain/core/prompt_values";
8
+ } from '@langchain/core/messages';
9
+ import { ChatPromptValue } from '@langchain/core/prompt_values';
13
10
  import {
14
11
  PromptTemplate,
15
12
  ChatPromptTemplate,
16
13
  AIMessagePromptTemplate,
17
14
  HumanMessagePromptTemplate,
18
15
  SystemMessagePromptTemplate,
19
- } from "@langchain/core/prompts";
20
- import { CallbackManager } from "@langchain/core/callbacks/manager";
21
- import { concat } from "@langchain/core/utils/stream";
22
- import { CustomAnthropic as ChatAnthropic } from "./llm";
23
- import { AnthropicMessageResponse } from "./types";
16
+ } from '@langchain/core/prompts';
17
+ import { CallbackManager } from '@langchain/core/callbacks/manager';
18
+ import { concat } from '@langchain/core/utils/stream';
19
+ import { CustomAnthropic as ChatAnthropic } from './index';
20
+ import { AnthropicMessageResponse } from './types';
24
21
  jest.setTimeout(120000);
25
22
 
26
- test("Test ChatAnthropic", async () => {
23
+ test('Test ChatAnthropic', async () => {
27
24
  const chat = new ChatAnthropic({
28
- modelName: "claude-3-sonnet-20240229",
25
+ modelName: 'claude-3-sonnet-20240229',
29
26
  maxRetries: 0,
30
27
  });
31
- const message = new HumanMessage("Hello!");
28
+ const message = new HumanMessage('Hello!');
32
29
  const res = await chat.invoke([message]);
33
30
  expect(res.response_metadata.usage).toBeDefined();
34
31
  });
35
32
 
36
- test("Test ChatAnthropic with a bad API key throws appropriate error", async () => {
33
+ test('Test ChatAnthropic with a bad API key throws appropriate error', async () => {
37
34
  const chat = new ChatAnthropic({
38
- modelName: "claude-3-sonnet-20240229",
35
+ modelName: 'claude-3-sonnet-20240229',
39
36
  maxRetries: 0,
40
- apiKey: "bad",
37
+ apiKey: 'bad',
41
38
  });
42
39
  let error;
43
40
  try {
44
- const message = new HumanMessage("Hello!");
41
+ const message = new HumanMessage('Hello!');
45
42
  await chat.invoke([message]);
46
43
  } catch (e) {
47
44
  error = e;
48
45
  }
49
46
  expect(error).toBeDefined();
50
- expect((error as any).lc_error_code).toEqual("MODEL_AUTHENTICATION");
47
+ expect((error as any).lc_error_code).toEqual('MODEL_AUTHENTICATION');
51
48
  });
52
49
 
53
- test("Test ChatAnthropic with unknown model throws appropriate error", async () => {
50
+ test('Test ChatAnthropic with unknown model throws appropriate error', async () => {
54
51
  const chat = new ChatAnthropic({
55
- modelName: "badbad",
52
+ modelName: 'badbad',
56
53
  maxRetries: 0,
57
54
  });
58
55
  let error;
59
56
  try {
60
- const message = new HumanMessage("Hello!");
57
+ const message = new HumanMessage('Hello!');
61
58
  await chat.invoke([message]);
62
59
  } catch (e) {
63
60
  error = e;
64
61
  }
65
62
  expect(error).toBeDefined();
66
- expect((error as any).lc_error_code).toEqual("MODEL_NOT_FOUND");
63
+ expect((error as any).lc_error_code).toEqual('MODEL_NOT_FOUND');
67
64
  });
68
65
 
69
- test("Test ChatAnthropic Generate", async () => {
66
+ test('Test ChatAnthropic Generate', async () => {
70
67
  const chat = new ChatAnthropic({
71
- modelName: "claude-3-sonnet-20240229",
68
+ modelName: 'claude-3-sonnet-20240229',
72
69
  maxRetries: 0,
73
70
  });
74
- const message = new HumanMessage("Hello!");
71
+ const message = new HumanMessage('Hello!');
75
72
  const res = await chat.generate([[message], [message]]);
76
73
  expect(res.generations.length).toBe(2);
77
74
  for (const generation of res.generations) {
@@ -84,17 +81,17 @@ test("Test ChatAnthropic Generate", async () => {
84
81
  // console.log({ res });
85
82
  });
86
83
 
87
- test.skip("Test ChatAnthropic Generate w/ ClientOptions", async () => {
84
+ test.skip('Test ChatAnthropic Generate w/ ClientOptions', async () => {
88
85
  const chat = new ChatAnthropic({
89
- modelName: "claude-3-sonnet-20240229",
86
+ modelName: 'claude-3-sonnet-20240229',
90
87
  maxRetries: 0,
91
88
  clientOptions: {
92
89
  defaultHeaders: {
93
- "Helicone-Auth": "HELICONE_API_KEY",
90
+ 'Helicone-Auth': 'HELICONE_API_KEY',
94
91
  },
95
92
  },
96
93
  });
97
- const message = new HumanMessage("Hello!");
94
+ const message = new HumanMessage('Hello!');
98
95
  const res = await chat.generate([[message], [message]]);
99
96
  expect(res.generations.length).toBe(2);
100
97
  for (const generation of res.generations) {
@@ -107,14 +104,14 @@ test.skip("Test ChatAnthropic Generate w/ ClientOptions", async () => {
107
104
  // console.log({ res });
108
105
  });
109
106
 
110
- test("Test ChatAnthropic Generate with a signal in call options", async () => {
107
+ test('Test ChatAnthropic Generate with a signal in call options', async () => {
111
108
  const chat = new ChatAnthropic({
112
- modelName: "claude-3-sonnet-20240229",
109
+ modelName: 'claude-3-sonnet-20240229',
113
110
  maxRetries: 0,
114
111
  });
115
112
  const controller = new AbortController();
116
113
  const message = new HumanMessage(
117
- "How is your day going? Be extremely verbose!"
114
+ 'How is your day going? Be extremely verbose!'
118
115
  );
119
116
  await expect(() => {
120
117
  const res = chat.generate([[message], [message]], {
@@ -127,11 +124,11 @@ test("Test ChatAnthropic Generate with a signal in call options", async () => {
127
124
  }).rejects.toThrow();
128
125
  }, 10000);
129
126
 
130
- test("Test ChatAnthropic tokenUsage with a batch", async () => {
127
+ test('Test ChatAnthropic tokenUsage with a batch', async () => {
131
128
  const model = new ChatAnthropic({
132
129
  temperature: 0,
133
130
  maxRetries: 0,
134
- modelName: "claude-3-sonnet-20240229",
131
+ modelName: 'claude-3-sonnet-20240229',
135
132
  });
136
133
  // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
137
134
  const res = await model.generate([
@@ -141,12 +138,12 @@ test("Test ChatAnthropic tokenUsage with a batch", async () => {
141
138
  // console.log({ res });
142
139
  });
143
140
 
144
- test("Test ChatAnthropic in streaming mode", async () => {
141
+ test('Test ChatAnthropic in streaming mode', async () => {
145
142
  let nrNewTokens = 0;
146
- let streamedCompletion = "";
143
+ let streamedCompletion = '';
147
144
 
148
145
  const model = new ChatAnthropic({
149
- modelName: "claude-3-sonnet-20240229",
146
+ modelName: 'claude-3-sonnet-20240229',
150
147
  maxRetries: 0,
151
148
  streaming: true,
152
149
  callbacks: CallbackManager.fromHandlers({
@@ -156,7 +153,7 @@ test("Test ChatAnthropic in streaming mode", async () => {
156
153
  },
157
154
  }),
158
155
  });
159
- const message = new HumanMessage("Hello!");
156
+ const message = new HumanMessage('Hello!');
160
157
  const res = await model.invoke([message]);
161
158
  // console.log({ res });
162
159
 
@@ -164,12 +161,12 @@ test("Test ChatAnthropic in streaming mode", async () => {
164
161
  expect(res.content).toBe(streamedCompletion);
165
162
  });
166
163
 
167
- test("Test ChatAnthropic in streaming mode with a signal", async () => {
164
+ test('Test ChatAnthropic in streaming mode with a signal', async () => {
168
165
  let nrNewTokens = 0;
169
- let streamedCompletion = "";
166
+ let streamedCompletion = '';
170
167
 
171
168
  const model = new ChatAnthropic({
172
- modelName: "claude-3-sonnet-20240229",
169
+ modelName: 'claude-3-sonnet-20240229',
173
170
  maxRetries: 0,
174
171
  streaming: true,
175
172
  callbacks: CallbackManager.fromHandlers({
@@ -181,7 +178,7 @@ test("Test ChatAnthropic in streaming mode with a signal", async () => {
181
178
  });
182
179
  const controller = new AbortController();
183
180
  const message = new HumanMessage(
184
- "Hello! Give me an extremely verbose response"
181
+ 'Hello! Give me an extremely verbose response'
185
182
  );
186
183
  await expect(() => {
187
184
  const res = model.invoke([message], {
@@ -196,12 +193,12 @@ test("Test ChatAnthropic in streaming mode with a signal", async () => {
196
193
  // console.log({ nrNewTokens, streamedCompletion });
197
194
  }, 5000);
198
195
 
199
- test.skip("Test ChatAnthropic prompt value", async () => {
196
+ test.skip('Test ChatAnthropic prompt value', async () => {
200
197
  const chat = new ChatAnthropic({
201
- modelName: "claude-3-sonnet-20240229",
198
+ modelName: 'claude-3-sonnet-20240229',
202
199
  maxRetries: 0,
203
200
  });
204
- const message = new HumanMessage("Hello!");
201
+ const message = new HumanMessage('Hello!');
205
202
  const res = await chat.generatePrompt([new ChatPromptValue([message])]);
206
203
  expect(res.generations.length).toBe(1);
207
204
  for (const generation of res.generations) {
@@ -213,37 +210,37 @@ test.skip("Test ChatAnthropic prompt value", async () => {
213
210
  // console.log({ res });
214
211
  });
215
212
 
216
- test.skip("ChatAnthropic, docs, prompt templates", async () => {
213
+ test.skip('ChatAnthropic, docs, prompt templates', async () => {
217
214
  const chat = new ChatAnthropic({
218
- modelName: "claude-3-sonnet-20240229",
215
+ modelName: 'claude-3-sonnet-20240229',
219
216
  maxRetries: 0,
220
217
  temperature: 0,
221
218
  });
222
219
 
223
220
  const systemPrompt = PromptTemplate.fromTemplate(
224
- "You are a helpful assistant that translates {input_language} to {output_language}."
221
+ 'You are a helpful assistant that translates {input_language} to {output_language}.'
225
222
  );
226
223
 
227
224
  const chatPrompt = ChatPromptTemplate.fromMessages([
228
225
  new SystemMessagePromptTemplate(systemPrompt),
229
- HumanMessagePromptTemplate.fromTemplate("{text}"),
226
+ HumanMessagePromptTemplate.fromTemplate('{text}'),
230
227
  ]);
231
228
 
232
229
  // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
233
230
  const responseA = await chat.generatePrompt([
234
231
  await chatPrompt.formatPromptValue({
235
- input_language: "English",
236
- output_language: "French",
237
- text: "I love programming.",
232
+ input_language: 'English',
233
+ output_language: 'French',
234
+ text: 'I love programming.',
238
235
  }),
239
236
  ]);
240
237
 
241
238
  // console.log(responseA.generations);
242
239
  });
243
240
 
244
- test.skip("ChatAnthropic, longer chain of messages", async () => {
241
+ test.skip('ChatAnthropic, longer chain of messages', async () => {
245
242
  const chat = new ChatAnthropic({
246
- modelName: "claude-3-sonnet-20240229",
243
+ modelName: 'claude-3-sonnet-20240229',
247
244
  maxRetries: 0,
248
245
  temperature: 0,
249
246
  });
@@ -251,40 +248,40 @@ test.skip("ChatAnthropic, longer chain of messages", async () => {
251
248
  const chatPrompt = ChatPromptTemplate.fromMessages([
252
249
  HumanMessagePromptTemplate.fromTemplate(`Hi, my name is Joe!`),
253
250
  AIMessagePromptTemplate.fromTemplate(`Nice to meet you, Joe!`),
254
- HumanMessagePromptTemplate.fromTemplate("{text}"),
251
+ HumanMessagePromptTemplate.fromTemplate('{text}'),
255
252
  ]);
256
253
 
257
254
  // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
258
255
  const responseA = await chat.generatePrompt([
259
256
  await chatPrompt.formatPromptValue({
260
- text: "What did I just say my name was?",
257
+ text: 'What did I just say my name was?',
261
258
  }),
262
259
  ]);
263
260
 
264
261
  // console.log(responseA.generations);
265
262
  });
266
263
 
267
- test.skip("ChatAnthropic, Anthropic apiUrl set manually via constructor", async () => {
264
+ test.skip('ChatAnthropic, Anthropic apiUrl set manually via constructor', async () => {
268
265
  // Pass the default URL through (should use this, and work as normal)
269
- const anthropicApiUrl = "https://api.anthropic.com";
266
+ const anthropicApiUrl = 'https://api.anthropic.com';
270
267
  const chat = new ChatAnthropic({
271
- modelName: "claude-3-sonnet-20240229",
268
+ modelName: 'claude-3-sonnet-20240229',
272
269
  maxRetries: 0,
273
270
  anthropicApiUrl,
274
271
  });
275
- const message = new HumanMessage("Hello!");
272
+ const message = new HumanMessage('Hello!');
276
273
  // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
277
274
  const res = await chat.call([message]);
278
275
  // console.log({ res });
279
276
  });
280
277
 
281
- test("Test ChatAnthropic stream method", async () => {
278
+ test('Test ChatAnthropic stream method', async () => {
282
279
  const model = new ChatAnthropic({
283
280
  maxTokens: 50,
284
281
  maxRetries: 0,
285
- modelName: "claude-3-sonnet-20240229",
282
+ modelName: 'claude-3-sonnet-20240229',
286
283
  });
287
- const stream = await model.stream("Print hello world.");
284
+ const stream = await model.stream('Print hello world.');
288
285
  const chunks: any[] = [];
289
286
  for await (const chunk of stream) {
290
287
  chunks.push(chunk);
@@ -292,15 +289,15 @@ test("Test ChatAnthropic stream method", async () => {
292
289
  expect(chunks.length).toBeGreaterThan(1);
293
290
  });
294
291
 
295
- test("Test ChatAnthropic stream method with abort", async () => {
292
+ test('Test ChatAnthropic stream method with abort', async () => {
296
293
  await expect(async () => {
297
294
  const model = new ChatAnthropic({
298
295
  maxTokens: 500,
299
296
  maxRetries: 0,
300
- modelName: "claude-3-sonnet-20240229",
297
+ modelName: 'claude-3-sonnet-20240229',
301
298
  });
302
299
  const stream = await model.stream(
303
- "How is your day going? Be extremely verbose.",
300
+ 'How is your day going? Be extremely verbose.',
304
301
  {
305
302
  signal: AbortSignal.timeout(1000),
306
303
  }
@@ -312,14 +309,14 @@ test("Test ChatAnthropic stream method with abort", async () => {
312
309
  }).rejects.toThrow();
313
310
  });
314
311
 
315
- test("Test ChatAnthropic stream method with early break", async () => {
312
+ test('Test ChatAnthropic stream method with early break', async () => {
316
313
  const model = new ChatAnthropic({
317
314
  maxTokens: 50,
318
315
  maxRetries: 0,
319
- modelName: "claude-3-sonnet-20240229",
316
+ modelName: 'claude-3-sonnet-20240229',
320
317
  });
321
318
  const stream = await model.stream(
322
- "How is your day going? Be extremely verbose."
319
+ 'How is your day going? Be extremely verbose.'
323
320
  );
324
321
  let i = 0;
325
322
  // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
@@ -332,26 +329,26 @@ test("Test ChatAnthropic stream method with early break", async () => {
332
329
  }
333
330
  });
334
331
 
335
- test("Test ChatAnthropic headers passed through", async () => {
332
+ test('Test ChatAnthropic headers passed through', async () => {
336
333
  const chat = new ChatAnthropic({
337
- modelName: "claude-3-sonnet-20240229",
334
+ modelName: 'claude-3-sonnet-20240229',
338
335
  maxRetries: 0,
339
- apiKey: "NOT_REAL",
336
+ apiKey: 'NOT_REAL',
340
337
  clientOptions: {
341
338
  defaultHeaders: {
342
- "X-Api-Key": process.env.ANTHROPIC_API_KEY,
339
+ 'X-Api-Key': process.env.ANTHROPIC_API_KEY,
343
340
  },
344
341
  },
345
342
  });
346
- const message = new HumanMessage("Hello!");
343
+ const message = new HumanMessage('Hello!');
347
344
  // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
348
345
  const res = await chat.invoke([message]);
349
346
  // console.log({ res });
350
347
  });
351
348
 
352
- test("Test ChatAnthropic multimodal", async () => {
349
+ test('Test ChatAnthropic multimodal', async () => {
353
350
  const chat = new ChatAnthropic({
354
- modelName: "claude-3-sonnet-20240229",
351
+ modelName: 'claude-3-sonnet-20240229',
355
352
  maxRetries: 0,
356
353
  });
357
354
  // @eslint-disable-next-line/@typescript-eslint/ban-ts-comment
@@ -359,27 +356,27 @@ test("Test ChatAnthropic multimodal", async () => {
359
356
  new HumanMessage({
360
357
  content: [
361
358
  {
362
- type: "image_url",
359
+ type: 'image_url',
363
360
  image_url: {
364
- url: "data:image/jpeg;base64,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",
361
+ url: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAggHCQgGCQgICAcICAgICAgICAYICAgHDAgHCAgICAgIBggICAgICAgICBYICAgICwkKCAgNDQoIDggICQgBAwQEBgUGCgYGCBALCg0QCg0NEA0KCg8LDQoKCgoLDgoQDQoLDQoKCg4NDQ0NDgsQDw0OCg4NDQ4NDQoJDg8OCP/AABEIALAAsAMBEQACEQEDEQH/xAAdAAEAAgEFAQAAAAAAAAAAAAAABwgJAQIEBQYD/8QANBAAAgIBAwIDBwQCAgIDAAAAAQIAAwQFERIIEwYhMQcUFyJVldQjQVGBcZEJMzJiFRYk/8QAGwEBAAMAAwEAAAAAAAAAAAAAAAQFBgEDBwL/xAA5EQACAQIDBQQJBAIBBQAAAAAAAQIDEQQhMQVBUWGREhRxgRMVIjJSU8HR8CNyobFCguEGJGKi4v/aAAwDAQACEQMRAD8ApfJplBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBAEAQBANl16qOTEKB6kkAD+z5Tkcj0On+z7Ub1FlOmanejeavj6dqV6kfsQ1OK4IP8AIM6pVYR1kuqJdLCV6qvCnJ/6v66nL+Ems/RNc+y63+BOvvFL411O/wBW4r5T6D4Saz9E1z7Lrf4Ed4pfGuo9W4r5T6D4Saz9E1z7Lrf4Ed4pfGuo9W4r5T6D4Saz9E1z7Lrf4Ed4pfGuo9W4r5T6D4Saz9E1z7Lrf4Ed4pfGuo9W4r5T6D4Saz9E1z7Lrf4Ed4pfGuo9W4r5T6D4Saz9E1z7Lrf4Ed4pfGuo9W4r5T6D4Saz9E1z7Lrf4Ed4pfGuo9W4r5T6HE1D2e6lQpsu0zU6EXzZ8jTtSoUD9yWuxUAA/kmdkasJaSXVHRVwlekrzpyX+r+mh56m9WHJSGU+hUgg/wBjynaRORvnAEAQBAEAQBAEAQCbennpVzfER95LHE0tX4tlsnJr2B2srw6yQLCpBQ3Me1W+4/VZLKlh4jFRo5ay4cPH7f0XWA2XUxft37MONs34ffRcy/Xsu6bdG0UK2Nh1tkAbHMyAt+Wx2HIi11/SDcQe3jrTXv6IJRVcRUqe88uC0Nxhdn0MMv0458XnJ+e7wVlyJPJkYsTSAIAgCAIAgCAIBqDAIx9qHTbo2tBmycOtcgjYZmOBRlqdjxJtQDuhdye3ette/qhkmliKlP3XlwehXYrZ9DEr9SOfFZS6rXwd1yKCdQ3Srm+HT7yGOXpbPxXLVOLUMTtXXmVgkVliQgvU9qx9h+kz11Ne4fFRrZaS4cfD7f2YfH7LqYT279qHHevH76PlvhKTClEAQBAEAQBAJp6WOn0+I80i7mumYnF8x1LIbSSe3iV2DYq13ElnQ8q6gdijWUuIeKxHoY5e89PuXWy8D3qp7S9iOvN/D9+XiZRNN06uiuvHqrSqmpFrqqrVUrrrUBUREUBVVVAAUAAATNNtu7PR4xUUoxVkskloktxyCZwfRj26jetHPtzrMXSM4Uabj7Vrfj10O2ZdsDbb3bqrCKEYmpeyED8Hs53LZVwvsPg4qN6kbt+OS8t5hdobYqOo44edorK6SzfmtFpz14H16f8Arkz6cmrD1e9crBvsFZy3ropvxC2yo7NTXXXbjhtuXcTmisz91hX2yr4KLjemrNbuPXeMDtuoqihiGnF/5ZJx55ZNceF76GQSUJuhAEAQBAEAhb239WWl+H391s7mXnbAnExu2WqUjdWyLHda6Qw2IXdrCCGFZX5pMo4WdXNZLiyoxm1KOFfZl7UuCtdeN2kvzcRB4d/5JMV7OOVpWRRSWAFmPk1ZTKN9uT1PRi+QHnsj2H12DHYGXLZzS9mV3zVvuVFL/qGDlapSaXFST6qyfS/3tb4M8a4up49WoYlyZGLcCUsTf1B2ZGVgHrsRgVNbqrIwIYAjaVc4Sg+zJWZqaVWFWCnB3T0/PodnqOnV312Y9taW02o1dtViq9dlbAq6OjAqyspIKkEEGfKbTuj7lFSTjJXTyaejXAxd9U/T6fDmYBTzbTMvm+G7FnNRBHcxLLDuWankCrueVlRG5dq7nOlwuI9NHP3lr9zzjamA7rU9n3Jacn8P25eBC0mFKIAgCAIBtdwASfQDc/4nIbsZXulr2ZDR9HwsYpxybqxmZe4Xl71cquyMR69hO3jg+fy0r5n1OWxNX0lRvdovBflz1DZuG7vh4xtZtXl+55vpp5EsyKWZ5X2seH783TdRwsZgmVk4OVRQzMUUXPRYle7gEoCxA5gEqDvsdp2U5KM03omv7I+Ig6lKUIuzaaXmigPtb6HNQ0bEytTGXjZeLiKlhWuu6rINPMLbY1bFqkXHQ908b7CyK+wUqFe+pY2FSSjZpvnl+MwmJ2JVw9OVTtqUYq+Sadt+WaVtd9+W+uLLv5HzB8j/AIlgZ8yRdGfUXXq2JXpGTZtquFUE+cnfMxU2Wu9CzEvaicEsG+/MdzYLbsmexmHdOXaS9l/w+H2PQ9kY9V6apyftxVtdUtJc3x58iykrjQCAIAgFdurzqbPh+lMHFKHVspC6FuLLh427Icp0O4d2ZWREb5WZLGbktJrssMJhvSu8vdX8vh9zP7X2i8LBRp27b46Rj8Vt73JebyVnCfSz0jNqh/8AsGsrZZRcxuoxrms7ua7HmcvLYkOaXJ5Ctjvkb8n/AE+K3TcVi+x+nS6rdyX33eJTbL2S636+JTaeaTveTf8AlLlwjv35ZFmfHnSnoWo47Yo0/FxLOBWnJw8ejHuobb5GVqkUOqnY9qwOjDyI9CKyGKqwd+03ybdjS19mYarHs+jSe5pJNdP6KudBPiTIwNYz/D1jA1WJk91AWKLqGJctDWVg+QFlfdQtsGcVY+//AFgSzx0VKmqi5dJK/wCeZm9iVJ0sRPDye6WWdu1BpXWeV78M8uGd/wCURuCJuqX2YjWNHzMYJyyaKzmYm3Hl71SrOqKW8h307mOT5fLc3mPUSsNV9HUT3aPwf5crNpYbvGHlG2azj+5Zrrp5mKFHBAI9CNx/iak8vTubpwBAEAQDtPCekLk5WHiON0yczFx3H8pbkVVMP7VyJ8zfZi3wTfRHdRh26kI8ZRXk5IzREf6mPPXTSAIB1/iPQa8yjIwrVD05NFuPYrAFWrsrat1YHyIKsRsf2nMXZpo+ZR7UXF77rqYW2xHrJqsHG2smu1T6rapKWKf8OCP6mxvfNHj1nH2XqsnfW6yOVpGr241teVRY9ORS4sqtrPF67B6Mp/2NiCGBIIYMQeGlJWaujsp1JU5KcHZrQyZdK/U3X4ipONdwq1fGQNkVL5JkVbhfe8cE/wDgWKq1e5NFjKD8ttLPm8ThnSd17r0+35qej7N2hHFQs8prVfVcv6J4kIuBAKtdWnV8uj89I090fVeP/wCi8hXq05CvIcg26PmMpDCpgVqUrZaCGqrussLhPSe3P3f7/wCOf4s9tTaXd16On77/APXn48EU58OYl+RremrrRyHbJzdPbI9+LvZZjW21vUlgs5FMe4OqmshVrrscca9jtcSaVKXotydrcVr58zH04znioLFXd3G/a17L08E3u5vJEveGeobX/Cuq2YmttbbjX3NflUu7ZC1VW2OTlaZZuzDHrIbbGXZOFbV9qmwfLElh6Venelqsl4rc+fP6FtT2hicHiHDEu8W7u+ii8lKObtHL3fH/AC1tn1AdReJ4exVvJW/MyEJwcVWG9x2G1zkb8MVNwTbt83kqhmYCVVDDyqytot7/ADeanG46GFh2nm37q4/8c/qVr/4/fZ9k5Obm+J7+Xa430V2soVcrNuuW3LtT+RQUNZKjj3L2QHlRYqWOPqJRVJcvJJWRnth4epKpLE1FqnZ8XJ3b8MuG/LQvdKQ2ZqB/qAYXfFmkLjZWZiINkxszKx0H8JVkW1KP6VAJsIPtRT4pPqjyKtDsVJx4SkvJSdjq59HSIAgCAdp4T1dcbKw8tzsmNmYuQ5/hKsiq1j/SoTPma7UWuKa6o7qM+xUhLhKL8lJXM0RP+pjz100gCAIBjA6x/Y9ZpGq35KofcdSssy8ewA8Vvcl8rHJ3OzrazXAeQNVq8d+3Zx0mDrKpTS3rLy3P6HnG18I6FdzS9mWa/c9V9fPkQTJxRnf+AfHeRpOXj6pjHa/GsDhd+K2p6W0WHY/p31lqidiVDchsyqR8VIKpFxlo/wAv5EjD15UKiqw1X8revMy++DfFtOo4uNqNDcsfKprvrJ8iFZQeLD1Dod0KnzVlI/aZKcXCTi9UerUqkasFOLumk14M8T1L+0uzRdHzdRp8skKlGO2wPC+6xKUt2PkezzN3E7g8NtjvO7D01UqKL03+CzIe0MQ8Ph5VI66Lxbsv7Ks9D3ThTqG/iXOBvSvJsGHTae4L8lWDXZ2QzMzXMt7MoWzzNyW2PzPaYWeNxDj+nDLLPw4dPsZ7Y+CVb/ua3tO7tfitZPzyS5XJS6zOlu3XAmrYSh9Rpq7N2OzKozMYF3RUZyEXIqZ325lVtVyrMOFUjYPEql7MtP6f2J+1tmvE2qU/fWWusfo1/P8AVWfbjruoWabpFGrl/wD5Wq/UOyMhO3mV6QFxaU98BCuzW5dNxW2wcraqeZawku1pQjFVJOn7uWmna1y8uhmMdUqOhSjiPfTlr73o0rXfi1k96V7nq/YP0n6lr99OdqgysfS6qqKw2QbK8rKx6kWrHxcdG2toxlrUA3lU+Q71c3ta+rpr4qFJONOzlnpom9/N8vpkTMBsyriZKeITUEla+rSyUbapLyvzeZkT0fR6saqvFprSmilFrqqrUJXXWo2VEUABVUDbYSgbbd3qbyMVFWSskcucH0ag/wCoBhd8WauuTlZmWh3TIzMrIQ/yluRbap/tXBmwguzFLgkuiPIq0+3UnLjKT8nJ2Orn0dIgCAIBtdAQQfQjY/4nIauZXulr2nDWNHw8kvyyaKxh5e/Hl71SqozsF8h307eQB5fLcvkPQZbE0vR1Gt2q8H+WPUNm4nvGHjK92spfuWT66+ZLMilmIAgHm/aL4ExtVxL9PyaVvptRtkb1WwA9uyths1dqNsRYhDKf39Z905uElKLszor0YVoOE1dP86mH7R/DORdi5OeKz2sI4iZZIKtU+Q11dPJSvl+rS1ZBIKsyDY7krrXJKSjxvbyzPKY0ZuMprSNlLim21p4rPh1t6fA9ieq34Ka1RhW5OA7XKbMcC6ypq7DU/doT9cLyBPNK7ECglmT0nW60FLsN2fPnnroSI4KvKl6aMLxz0zeTavbW3hfy3Wq/4+fbVQKbPDd9wW7vWZGnK2wW2l17l9FTehsS0W5PA/M62uV5CqzhV4+i7+kS5Px4/T8z02wcXHsvDyed24+DzaXg7u3PLLSderP2f3arombi0KXyEFWVVWBu1jU2pc1SD93sqWxAP3dlkHC1FCqm9NOuRd7ToOvhpwjrk14xadv4K7dEPU5gYOI2iZ+RXiql1l2Hk2fJjtVae5ZVbaSUrsW42WB7O2jpYqg8k+exxuGnKXbgr8eOWXmUGxtpUqdP0FV9m12m9Gm72/8AFp8dfEmb22dZmlaXjv7nk42pag4K0U49q3U1t5fqZV1LFErTfl2g4st/8VCjnZXDo4Oc37ScVvv9L/iLXG7Xo0IfpyU57kndeLa0X8vRcq59OnsAzPFWY3iTVmezBa3uMbQOWo2qdhSibcUwa+IrPEBSq9pB/wBjV2GIrxoR9HT1/r/6M/s7A1MbU7ziHeN75/5tbuUF/Oml28h0oDfCAIBE/VL7TRo+j5uSr8cm6s4eJtx5e9XKyK6hvJuwncyCPP5aW8j6GVhqXpKiW7V+C/LFZtLE93w8pXzeUf3PJdNfIxQIgAAHoBsP8TUnl6VjdOAIAgCAIBNPSx1BHw5mE3c20zL4JmIoZjUQT28uusblmp5EMiDlZUTsHaulDDxWH9NHL3lp9i62Xj+61Pa9yWvJ/F9+XgZRNN1Ku+uvIqsS2m1FsqtrZXrsrYBkdHUlWVlIIYEggzNNNOzPR4yUkpRd081bRp7zkTg+jUQCH9Q8FeJjnNdVrmImmPx/QfTKXuqAVOXa2ZeTO5tAe29hWq1bpeS8lKdLs2cH2v3Zfn5kVjpYr0t1VXY4djNaaZ+OumWpGh9j2vaVi6pp+NVpep4+ouxQXY9ZzMnKybbGy8rVbNsHENdKMdiot2Raa0pbtjud/pac5RlK6a4PJJaJasivD4inCcIdmSle11m3JttyeStn/RJ/sG8A6no2LgaTaultiY+MwuuxmzUyDlFue4rek1XGxmd3yWspLvuwoTnskevONSTkr58bafm7dxJuDpVaNONOXZsln2b6+evjv4I6jVejTRLMp9TqTLw8xrRkV24eVZT7vkcuZtorKvUjM25KMj1+Z2RdzOxYuoo9l2a5rVcOJGnsnDubqxTjLVOMmrPilnG/k1yJxrXYAbkkADkdtyf5OwA3Pr5AD+APSQi5K7e1zod0nVrnzanu07KtZnuOMK3x7rWO7WPjuNlsY7sWoenmzMzB2YtLCljZ012XmuevUoMVsWhXk5puEnra1m+Nnl0tffmeY8Df8dum49iXZmZkZ4Q79gImJjv/AALQj23Mv/qt6BvRuQJU9lTaE5K0Vb+X9iNQ2BRg71JOfKyUemb/AJ/gtXhYSVIlNaLXVWqpXWiqqIigBURVACqoAAUAAASrbvmzTpJKy0PtByIBx9R1KuiuzItsSqmpGsttsZUrrrUFnd3YhVVVBJYkAATlJt2R8ykopyk7JZtvRJbzF31T9QR8R5gNPNdMxOSYaMGQ2kkdzLsrOxVruICo45V1AbhGsuQaXC4f0Mc/eev2PONqY7vVT2fcjpzfxfbl4kLSYUogCAIAgCAIBNvTz1VZvh0+7FTl6Wz8mxGfi1DE72WYdhBFZYkuaGHasfc/os9lrQ8RhY1s9JcePj9/7LrAbUnhPYt2ocN68Pto+W+/fsv6ktG1oKuNmVrkEbnDyCKMtTsOQFTkd0LuB3KGtr39HMoquHqU/eWXFaG4wu0KGJX6cs+DykvJ6+KuuZJxEjFiaQBAEAQBAEAQBANQIBGHtR6ktG0UMuTmVtkAbjDxyt+Wx2PEGpG/SDcSO5kNTXv6uJJpYepV91ZcXoV2K2hQwy/UlnwWcn5bvF2XMoL1DdVWb4iPuwU4mlq/JcRX5NewO9dmZYABYVIDilR2q32P6rJXat7h8LGjnrLjw8Pv/Rh8ftSpi/Yt2YcL5vx+2i5kJSYUogCAIAgCAIAgCAbLqFYcWAZT6hgCD/R8pyOZ6HT/AGg6lQorp1PU6EXyVMfUdSoUD9gFpykAA/gCdUqUJaxXREuli69JWhUkv9n9Tl/FvWfreufetb/PnX3el8C6Hf6yxXzX1Hxb1n63rn3rW/z47vS+BdB6yxXzX1Hxb1n63rn3rW/z47vS+BdB6yxXzX1Hxb1n63rn3rW/z47vS+BdB6yxXzX1Hxb1n63rn3rW/wA+O70vgXQessV819R8W9Z+t65961v8+O70vgXQessV819R8W9Z+t65961v8+O70vgXQessV819R8W9Z+t65961v8+O70vgXQessV819Tiah7QdRvU13anqd6N5MmRqOpXqR+4K3ZTgg/wROyNKEdIrojoqYuvVVp1JP/Z/TU89TQqjioCgegAAA/oeU7SJzN84AgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgCAIAgH/9k=',
365
362
  },
366
363
  },
367
- { type: "text", text: "What is this a logo for?" },
364
+ { type: 'text', text: 'What is this a logo for?' },
368
365
  ],
369
366
  }),
370
367
  ]);
371
368
  // console.log(res);
372
369
  });
373
370
 
374
- test("Stream tokens", async () => {
371
+ test('Stream tokens', async () => {
375
372
  const model = new ChatAnthropic({
376
- model: "claude-3-haiku-20240307",
373
+ model: 'claude-3-haiku-20240307',
377
374
  temperature: 0,
378
375
  maxTokens: 10,
379
376
  });
380
377
  let res: AIMessageChunk | null = null;
381
378
  for await (const chunk of await model.stream(
382
- "Why is the sky blue? Be concise."
379
+ 'Why is the sky blue? Be concise.'
383
380
  )) {
384
381
  if (!res) {
385
382
  res = chunk;
@@ -399,23 +396,23 @@ test("Stream tokens", async () => {
399
396
  );
400
397
  });
401
398
 
402
- test("id is supplied when invoking", async () => {
399
+ test('id is supplied when invoking', async () => {
403
400
  const model = new ChatAnthropic();
404
- const result = await model.invoke("Hello");
401
+ const result = await model.invoke('Hello');
405
402
  expect(result.id).toBeDefined();
406
- expect(result.id).not.toEqual("");
403
+ expect(result.id).not.toEqual('');
407
404
  });
408
405
 
409
- test("id is supplied when streaming", async () => {
406
+ test('id is supplied when streaming', async () => {
410
407
  const model = new ChatAnthropic();
411
408
  let finalChunk: AIMessageChunk | undefined;
412
- for await (const chunk of await model.stream("Hello")) {
409
+ for await (const chunk of await model.stream('Hello')) {
413
410
  finalChunk = !finalChunk ? chunk : concat(finalChunk, chunk);
414
411
  }
415
412
  expect(finalChunk).toBeDefined();
416
413
  if (!finalChunk) return;
417
414
  expect(finalChunk.id).toBeDefined();
418
- expect(finalChunk.id).not.toEqual("");
415
+ expect(finalChunk.id).not.toEqual('');
419
416
  });
420
417
 
421
418
  const CACHED_TEXT = `## Components
@@ -679,12 +676,12 @@ LangChain has many different types of output parsers. This is a list of output p
679
676
 
680
677
  The current date is ${new Date().toISOString()}`;
681
678
 
682
- test("system prompt caching", async () => {
679
+ test('system prompt caching', async () => {
683
680
  const model = new ChatAnthropic({
684
- model: "claude-3-haiku-20240307",
681
+ model: 'claude-3-haiku-20240307',
685
682
  clientOptions: {
686
683
  defaultHeaders: {
687
- "anthropic-beta": "prompt-caching-2024-07-31",
684
+ 'anthropic-beta': 'prompt-caching-2024-07-31',
688
685
  },
689
686
  },
690
687
  });
@@ -692,14 +689,14 @@ test("system prompt caching", async () => {
692
689
  new SystemMessage({
693
690
  content: [
694
691
  {
695
- type: "text",
692
+ type: 'text',
696
693
  text: `You are a pirate. Always respond in pirate dialect.\nUse the following as context when answering questions: ${CACHED_TEXT}`,
697
- cache_control: { type: "ephemeral" },
694
+ cache_control: { type: 'ephemeral' },
698
695
  },
699
696
  ],
700
697
  }),
701
698
  new HumanMessage({
702
- content: "What types of messages are supported in LangChain?",
699
+ content: 'What types of messages are supported in LangChain?',
703
700
  }),
704
701
  ];
705
702
  const res = await model.invoke(messages);
@@ -725,38 +722,38 @@ test("system prompt caching", async () => {
725
722
  });
726
723
 
727
724
  // TODO: Add proper test with long tool content
728
- test.skip("tool caching", async () => {
725
+ test.skip('tool caching', async () => {
729
726
  const model = new ChatAnthropic({
730
- model: "claude-3-haiku-20240307",
727
+ model: 'claude-3-haiku-20240307',
731
728
  clientOptions: {
732
729
  defaultHeaders: {
733
- "anthropic-beta": "prompt-caching-2024-07-31",
730
+ 'anthropic-beta': 'prompt-caching-2024-07-31',
734
731
  },
735
732
  },
736
733
  }).bindTools([
737
734
  {
738
- name: "get_weather",
739
- description: "Get the weather for a specific location",
735
+ name: 'get_weather',
736
+ description: 'Get the weather for a specific location',
740
737
  input_schema: {
741
- type: "object",
738
+ type: 'object',
742
739
  properties: {
743
740
  location: {
744
- type: "string",
745
- description: "Location to get the weather for",
741
+ type: 'string',
742
+ description: 'Location to get the weather for',
746
743
  },
747
744
  unit: {
748
- type: "string",
749
- description: "Temperature unit to return",
745
+ type: 'string',
746
+ description: 'Temperature unit to return',
750
747
  },
751
748
  },
752
- required: ["location"],
749
+ required: ['location'],
753
750
  },
754
- cache_control: { type: "ephemeral" },
751
+ cache_control: { type: 'ephemeral' },
755
752
  },
756
753
  ]);
757
754
  const messages = [
758
755
  new HumanMessage({
759
- content: "What is the weather in Regensburg?",
756
+ content: 'What is the weather in Regensburg?',
760
757
  }),
761
758
  ];
762
759
  const res = await model.invoke(messages);
@@ -772,12 +769,12 @@ test.skip("tool caching", async () => {
772
769
  );
773
770
  });
774
771
 
775
- test("human message caching", async () => {
772
+ test('human message caching', async () => {
776
773
  const model = new ChatAnthropic({
777
- model: "claude-3-haiku-20240307",
774
+ model: 'claude-3-haiku-20240307',
778
775
  clientOptions: {
779
776
  defaultHeaders: {
780
- "anthropic-beta": "prompt-caching-2024-07-31",
777
+ 'anthropic-beta': 'prompt-caching-2024-07-31',
781
778
  },
782
779
  },
783
780
  });
@@ -786,7 +783,7 @@ test("human message caching", async () => {
786
783
  new SystemMessage({
787
784
  content: [
788
785
  {
789
- type: "text",
786
+ type: 'text',
790
787
  text: `You are a pirate. Always respond in pirate dialect.\nUse the following as context when answering questions: ${CACHED_TEXT}`,
791
788
  },
792
789
  ],
@@ -794,9 +791,9 @@ test("human message caching", async () => {
794
791
  new HumanMessage({
795
792
  content: [
796
793
  {
797
- type: "text",
798
- text: "What types of messages are supported in LangChain?",
799
- cache_control: { type: "ephemeral" },
794
+ type: 'text',
795
+ text: 'What types of messages are supported in LangChain?',
796
+ cache_control: { type: 'ephemeral' },
800
797
  },
801
798
  ],
802
799
  }),
@@ -814,31 +811,31 @@ test("human message caching", async () => {
814
811
  );
815
812
  });
816
813
 
817
- test("Can accept PDF documents", async () => {
814
+ test('Can accept PDF documents', async () => {
818
815
  const model = new ChatAnthropic({
819
- model: "claude-3-5-sonnet-latest",
816
+ model: 'claude-3-5-sonnet-latest',
820
817
  });
821
818
 
822
819
  const pdfPath =
823
- "../langchain-community/src/document_loaders/tests/example_data/Jacob_Lee_Resume_2023.pdf";
824
- const pdfBase64 = await fs.readFile(pdfPath, "base64");
820
+ '../langchain-community/src/document_loaders/tests/example_data/Jacob_Lee_Resume_2023.pdf';
821
+ const pdfBase64 = await fs.readFile(pdfPath, 'base64');
825
822
 
826
823
  const response = await model.invoke([
827
- ["system", "Use the provided documents to answer the question"],
824
+ ['system', 'Use the provided documents to answer the question'],
828
825
  [
829
- "user",
826
+ 'user',
830
827
  [
831
828
  {
832
- type: "document",
829
+ type: 'document',
833
830
  source: {
834
- type: "base64",
835
- media_type: "application/pdf",
831
+ type: 'base64',
832
+ media_type: 'application/pdf',
836
833
  data: pdfBase64,
837
834
  },
838
835
  },
839
836
  {
840
- type: "text",
841
- text: "Summarize the contents of this PDF",
837
+ type: 'text',
838
+ text: 'Summarize the contents of this PDF',
842
839
  },
843
840
  ],
844
841
  ],
@@ -847,31 +844,31 @@ test("Can accept PDF documents", async () => {
847
844
  expect(response.content.length).toBeGreaterThan(10);
848
845
  });
849
846
 
850
- test("Citations", async () => {
847
+ test('Citations', async () => {
851
848
  const citationsModel = new ChatAnthropic({
852
- model: "claude-3-5-sonnet-latest",
849
+ model: 'claude-3-5-sonnet-latest',
853
850
  });
854
851
 
855
852
  const messages = [
856
853
  {
857
- role: "user",
854
+ role: 'user',
858
855
  content: [
859
856
  {
860
- type: "document",
857
+ type: 'document',
861
858
  source: {
862
- type: "text",
863
- media_type: "text/plain",
859
+ type: 'text',
860
+ media_type: 'text/plain',
864
861
  data: "The grass the user is asking about is bluegrass. The sky is orange because it's night.",
865
862
  },
866
- title: "My Document",
867
- context: "This is a trustworthy document.",
863
+ title: 'My Document',
864
+ context: 'This is a trustworthy document.',
868
865
  citations: {
869
866
  enabled: true,
870
867
  },
871
868
  },
872
869
  {
873
- type: "text",
874
- text: "What color is the grass and sky?",
870
+ type: 'text',
871
+ text: 'What color is the grass and sky?',
875
872
  },
876
873
  ],
877
874
  },
@@ -885,7 +882,7 @@ test("Citations", async () => {
885
882
  (block) => block.citations !== undefined
886
883
  );
887
884
  expect(blocksWithCitations.length).toEqual(2);
888
- expect(typeof blocksWithCitations[0].citations[0]).toEqual("object");
885
+ expect(typeof blocksWithCitations[0].citations[0]).toEqual('object');
889
886
 
890
887
  const stream = await citationsModel.stream(messages);
891
888
  let aggregated;
@@ -908,11 +905,11 @@ test("Citations", async () => {
908
905
  ).toBe(true);
909
906
  });
910
907
 
911
- test("Test thinking blocks multiturn invoke", async () => {
908
+ test('Test thinking blocks multiturn invoke', async () => {
912
909
  const model = new ChatAnthropic({
913
- model: "claude-3-7-sonnet-latest",
910
+ model: 'claude-3-7-sonnet-latest',
914
911
  maxTokens: 5000,
915
- thinking: { type: "enabled", budget_tokens: 2000 },
912
+ thinking: { type: 'enabled', budget_tokens: 2000 },
916
913
  });
917
914
 
918
915
  async function doInvoke(messages: BaseMessage[]) {
@@ -920,37 +917,37 @@ test("Test thinking blocks multiturn invoke", async () => {
920
917
 
921
918
  expect(Array.isArray(response.content)).toBe(true);
922
919
  const content = response.content as AnthropicMessageResponse[];
923
- expect(content.some((block) => "thinking" in (block as any))).toBe(true);
920
+ expect(content.some((block) => 'thinking' in (block as any))).toBe(true);
924
921
 
925
922
  for (const block of response.content) {
926
- expect(typeof block).toBe("object");
927
- if ((block as any).type === "thinking") {
923
+ expect(typeof block).toBe('object');
924
+ if ((block as any).type === 'thinking') {
928
925
  expect(Object.keys(block).sort()).toEqual(
929
- ["type", "thinking", "signature"].sort()
926
+ ['type', 'thinking', 'signature'].sort()
930
927
  );
931
928
  expect((block as any).thinking).toBeTruthy();
932
- expect(typeof (block as any).thinking).toBe("string");
929
+ expect(typeof (block as any).thinking).toBe('string');
933
930
  expect((block as any).signature).toBeTruthy();
934
- expect(typeof (block as any).signature).toBe("string");
931
+ expect(typeof (block as any).signature).toBe('string');
935
932
  }
936
933
  }
937
934
  return response;
938
935
  }
939
936
 
940
- const invokeMessages = [new HumanMessage("Hello")];
937
+ const invokeMessages = [new HumanMessage('Hello')];
941
938
 
942
939
  invokeMessages.push(await doInvoke(invokeMessages));
943
- invokeMessages.push(new HumanMessage("What is 42+7?"));
940
+ invokeMessages.push(new HumanMessage('What is 42+7?'));
944
941
 
945
942
  // test a second time to make sure that we've got input translation working correctly
946
943
  await model.invoke(invokeMessages);
947
944
  });
948
945
 
949
- test("Test thinking blocks multiturn streaming", async () => {
946
+ test('Test thinking blocks multiturn streaming', async () => {
950
947
  const model = new ChatAnthropic({
951
- model: "claude-3-7-sonnet-latest",
948
+ model: 'claude-3-7-sonnet-latest',
952
949
  maxTokens: 5000,
953
- thinking: { type: "enabled", budget_tokens: 2000 },
950
+ thinking: { type: 'enabled', budget_tokens: 2000 },
954
951
  });
955
952
 
956
953
  async function doStreaming(messages: BaseMessage[]) {
@@ -961,37 +958,37 @@ test("Test thinking blocks multiturn streaming", async () => {
961
958
  expect(full).toBeInstanceOf(AIMessageChunk);
962
959
  expect(Array.isArray(full?.content)).toBe(true);
963
960
  const content3 = full?.content as AnthropicMessageResponse[];
964
- expect(content3.some((block) => "thinking" in (block as any))).toBe(true);
961
+ expect(content3.some((block) => 'thinking' in (block as any))).toBe(true);
965
962
 
966
963
  for (const block of full?.content || []) {
967
- expect(typeof block).toBe("object");
968
- if ((block as any).type === "thinking") {
964
+ expect(typeof block).toBe('object');
965
+ if ((block as any).type === 'thinking') {
969
966
  expect(Object.keys(block).sort()).toEqual(
970
- ["type", "thinking", "signature", "index"].sort()
967
+ ['type', 'thinking', 'signature', 'index'].sort()
971
968
  );
972
969
  expect((block as any).thinking).toBeTruthy();
973
- expect(typeof (block as any).thinking).toBe("string");
970
+ expect(typeof (block as any).thinking).toBe('string');
974
971
  expect((block as any).signature).toBeTruthy();
975
- expect(typeof (block as any).signature).toBe("string");
972
+ expect(typeof (block as any).signature).toBe('string');
976
973
  }
977
974
  }
978
975
  return full as AIMessageChunk;
979
976
  }
980
977
 
981
- const streamingMessages = [new HumanMessage("Hello")];
978
+ const streamingMessages = [new HumanMessage('Hello')];
982
979
 
983
980
  streamingMessages.push(await doStreaming(streamingMessages));
984
- streamingMessages.push(new HumanMessage("What is 42+7?"));
981
+ streamingMessages.push(new HumanMessage('What is 42+7?'));
985
982
 
986
983
  // test a second time to make sure that we've got input translation working correctly
987
984
  await doStreaming(streamingMessages);
988
985
  });
989
986
 
990
- test("Test redacted thinking blocks multiturn invoke", async () => {
987
+ test('Test redacted thinking blocks multiturn invoke', async () => {
991
988
  const model = new ChatAnthropic({
992
- model: "claude-3-7-sonnet-latest",
989
+ model: 'claude-3-7-sonnet-latest',
993
990
  maxTokens: 5000,
994
- thinking: { type: "enabled", budget_tokens: 2000 },
991
+ thinking: { type: 'enabled', budget_tokens: 2000 },
995
992
  });
996
993
 
997
994
  async function doInvoke(messages: BaseMessage[]) {
@@ -999,12 +996,12 @@ test("Test redacted thinking blocks multiturn invoke", async () => {
999
996
  let hasReasoning = false;
1000
997
 
1001
998
  for (const block of response.content) {
1002
- expect(typeof block).toBe("object");
1003
- if ((block as any).type === "redacted_thinking") {
999
+ expect(typeof block).toBe('object');
1000
+ if ((block as any).type === 'redacted_thinking') {
1004
1001
  hasReasoning = true;
1005
- expect(Object.keys(block).sort()).toEqual(["type", "data"].sort());
1002
+ expect(Object.keys(block).sort()).toEqual(['type', 'data'].sort());
1006
1003
  expect((block as any).data).toBeTruthy();
1007
- expect(typeof (block as any).data).toBe("string");
1004
+ expect(typeof (block as any).data).toBe('string');
1008
1005
  }
1009
1006
  }
1010
1007
  expect(hasReasoning).toBe(true);
@@ -1013,22 +1010,22 @@ test("Test redacted thinking blocks multiturn invoke", async () => {
1013
1010
 
1014
1011
  const invokeMessages = [
1015
1012
  new HumanMessage(
1016
- "ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB"
1013
+ 'ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB'
1017
1014
  ),
1018
1015
  ];
1019
1016
 
1020
1017
  invokeMessages.push(await doInvoke(invokeMessages));
1021
- invokeMessages.push(new HumanMessage("What is 42+7?"));
1018
+ invokeMessages.push(new HumanMessage('What is 42+7?'));
1022
1019
 
1023
1020
  // test a second time to make sure that we've got input translation working correctly
1024
1021
  await doInvoke(invokeMessages);
1025
1022
  });
1026
1023
 
1027
- test("Test redacted thinking blocks multiturn streaming", async () => {
1024
+ test('Test redacted thinking blocks multiturn streaming', async () => {
1028
1025
  const model = new ChatAnthropic({
1029
- model: "claude-3-7-sonnet-latest",
1026
+ model: 'claude-3-7-sonnet-latest',
1030
1027
  maxTokens: 5000,
1031
- thinking: { type: "enabled", budget_tokens: 2000 },
1028
+ thinking: { type: 'enabled', budget_tokens: 2000 },
1032
1029
  });
1033
1030
 
1034
1031
  async function doStreaming(messages: BaseMessage[]) {
@@ -1041,14 +1038,14 @@ test("Test redacted thinking blocks multiturn streaming", async () => {
1041
1038
  let streamHasReasoning = false;
1042
1039
 
1043
1040
  for (const block of full?.content || []) {
1044
- expect(typeof block).toBe("object");
1045
- if ((block as any).type === "redacted_thinking") {
1041
+ expect(typeof block).toBe('object');
1042
+ if ((block as any).type === 'redacted_thinking') {
1046
1043
  streamHasReasoning = true;
1047
1044
  expect(Object.keys(block).sort()).toEqual(
1048
- ["type", "data", "index"].sort()
1045
+ ['type', 'data', 'index'].sort()
1049
1046
  );
1050
1047
  expect((block as any).data).toBeTruthy();
1051
- expect(typeof (block as any).data).toBe("string");
1048
+ expect(typeof (block as any).data).toBe('string');
1052
1049
  }
1053
1050
  }
1054
1051
  expect(streamHasReasoning).toBe(true);
@@ -1057,13 +1054,13 @@ test("Test redacted thinking blocks multiturn streaming", async () => {
1057
1054
 
1058
1055
  const streamingMessages = [
1059
1056
  new HumanMessage(
1060
- "ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB"
1057
+ 'ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB'
1061
1058
  ),
1062
1059
  ];
1063
1060
 
1064
1061
  streamingMessages.push(await doStreaming(streamingMessages));
1065
- streamingMessages.push(new HumanMessage("What is 42+7?"));
1062
+ streamingMessages.push(new HumanMessage('What is 42+7?'));
1066
1063
 
1067
1064
  // test a second time to make sure that we've got input translation working correctly
1068
1065
  await doStreaming(streamingMessages);
1069
- });
1066
+ });