@langchain/anthropic 0.1.1 → 0.1.3
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.
- package/dist/chat_models.cjs +46 -12
- package/dist/chat_models.d.ts +0 -2
- package/dist/chat_models.js +46 -12
- package/dist/experimental/index.cjs +17 -0
- package/dist/experimental/index.d.ts +1 -0
- package/dist/experimental/index.js +1 -0
- package/dist/experimental/tests/tool_calling.int.test.d.ts +1 -0
- package/dist/experimental/tests/tool_calling.int.test.js +268 -0
- package/dist/experimental/tool_calling.cjs +260 -0
- package/dist/experimental/tool_calling.d.ts +51 -0
- package/dist/experimental/tool_calling.js +256 -0
- package/dist/experimental/utils/tool_calling.cjs +87 -0
- package/dist/experimental/utils/tool_calling.d.ts +10 -0
- package/dist/experimental/utils/tool_calling.js +82 -0
- package/dist/tests/chat_models.int.test.js +26 -6
- package/experimental.cjs +1 -0
- package/experimental.d.cts +1 -0
- package/experimental.d.ts +1 -0
- package/experimental.js +1 -0
- package/package.json +20 -3
package/dist/chat_models.cjs
CHANGED
|
@@ -6,6 +6,22 @@ const messages_1 = require("@langchain/core/messages");
|
|
|
6
6
|
const outputs_1 = require("@langchain/core/outputs");
|
|
7
7
|
const env_1 = require("@langchain/core/utils/env");
|
|
8
8
|
const chat_models_1 = require("@langchain/core/language_models/chat_models");
|
|
9
|
+
function _formatImage(imageUrl) {
|
|
10
|
+
const regex = /^data:(image\/.+);base64,(.+)$/;
|
|
11
|
+
const match = imageUrl.match(regex);
|
|
12
|
+
if (match === null) {
|
|
13
|
+
throw new Error([
|
|
14
|
+
"Anthropic only supports base64-encoded images currently.",
|
|
15
|
+
"Example: data:image/png;base64,/9j/4AAQSk...",
|
|
16
|
+
].join("\n\n"));
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
type: "base64",
|
|
20
|
+
media_type: match[1] ?? "",
|
|
21
|
+
data: match[2] ?? "",
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
};
|
|
24
|
+
}
|
|
9
25
|
/**
|
|
10
26
|
* Wrapper around Anthropic large language models.
|
|
11
27
|
*
|
|
@@ -243,16 +259,13 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
243
259
|
let system;
|
|
244
260
|
if (messages.length > 0 && messages[0]._getType() === "system") {
|
|
245
261
|
if (typeof messages[0].content !== "string") {
|
|
246
|
-
throw new Error("
|
|
262
|
+
throw new Error("System message content must be a string.");
|
|
247
263
|
}
|
|
248
264
|
system = messages[0].content;
|
|
249
265
|
}
|
|
250
266
|
const conversationMessages = system !== undefined ? messages.slice(1) : messages;
|
|
251
267
|
const formattedMessages = conversationMessages.map((message) => {
|
|
252
268
|
let role;
|
|
253
|
-
if (typeof message.content !== "string") {
|
|
254
|
-
throw new Error("Currently only string content messages are supported.");
|
|
255
|
-
}
|
|
256
269
|
if (message._getType() === "human") {
|
|
257
270
|
role = "user";
|
|
258
271
|
}
|
|
@@ -265,10 +278,35 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
265
278
|
else {
|
|
266
279
|
throw new Error(`Message type "${message._getType()}" is not supported.`);
|
|
267
280
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
281
|
+
if (typeof message.content === "string") {
|
|
282
|
+
return {
|
|
283
|
+
role,
|
|
284
|
+
content: message.content,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
return {
|
|
289
|
+
role,
|
|
290
|
+
content: message.content.map((contentPart) => {
|
|
291
|
+
if (contentPart.type === "image_url") {
|
|
292
|
+
let source;
|
|
293
|
+
if (typeof contentPart.image_url === "string") {
|
|
294
|
+
source = _formatImage(contentPart.image_url);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
source = _formatImage(contentPart.image_url.url);
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
type: "image",
|
|
301
|
+
source,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
return contentPart;
|
|
306
|
+
}
|
|
307
|
+
}),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
272
310
|
});
|
|
273
311
|
return {
|
|
274
312
|
messages: formattedMessages,
|
|
@@ -374,10 +412,6 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
374
412
|
_llmType() {
|
|
375
413
|
return "anthropic";
|
|
376
414
|
}
|
|
377
|
-
/** @ignore */
|
|
378
|
-
_combineLLMOutput() {
|
|
379
|
-
return [];
|
|
380
|
-
}
|
|
381
415
|
}
|
|
382
416
|
exports.ChatAnthropicMessages = ChatAnthropicMessages;
|
|
383
417
|
class ChatAnthropic extends ChatAnthropicMessages {
|
package/dist/chat_models.d.ts
CHANGED
|
@@ -165,8 +165,6 @@ export declare class ChatAnthropicMessages<CallOptions extends BaseLanguageModel
|
|
|
165
165
|
signal?: AbortSignal;
|
|
166
166
|
}): Promise<Anthropic.Message>;
|
|
167
167
|
_llmType(): string;
|
|
168
|
-
/** @ignore */
|
|
169
|
-
_combineLLMOutput(): never[];
|
|
170
168
|
}
|
|
171
169
|
export declare class ChatAnthropic extends ChatAnthropicMessages {
|
|
172
170
|
}
|
package/dist/chat_models.js
CHANGED
|
@@ -3,6 +3,22 @@ import { AIMessage, AIMessageChunk, } from "@langchain/core/messages";
|
|
|
3
3
|
import { ChatGenerationChunk } from "@langchain/core/outputs";
|
|
4
4
|
import { getEnvironmentVariable } from "@langchain/core/utils/env";
|
|
5
5
|
import { BaseChatModel, } from "@langchain/core/language_models/chat_models";
|
|
6
|
+
function _formatImage(imageUrl) {
|
|
7
|
+
const regex = /^data:(image\/.+);base64,(.+)$/;
|
|
8
|
+
const match = imageUrl.match(regex);
|
|
9
|
+
if (match === null) {
|
|
10
|
+
throw new Error([
|
|
11
|
+
"Anthropic only supports base64-encoded images currently.",
|
|
12
|
+
"Example: data:image/png;base64,/9j/4AAQSk...",
|
|
13
|
+
].join("\n\n"));
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
type: "base64",
|
|
17
|
+
media_type: match[1] ?? "",
|
|
18
|
+
data: match[2] ?? "",
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
};
|
|
21
|
+
}
|
|
6
22
|
/**
|
|
7
23
|
* Wrapper around Anthropic large language models.
|
|
8
24
|
*
|
|
@@ -240,16 +256,13 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
240
256
|
let system;
|
|
241
257
|
if (messages.length > 0 && messages[0]._getType() === "system") {
|
|
242
258
|
if (typeof messages[0].content !== "string") {
|
|
243
|
-
throw new Error("
|
|
259
|
+
throw new Error("System message content must be a string.");
|
|
244
260
|
}
|
|
245
261
|
system = messages[0].content;
|
|
246
262
|
}
|
|
247
263
|
const conversationMessages = system !== undefined ? messages.slice(1) : messages;
|
|
248
264
|
const formattedMessages = conversationMessages.map((message) => {
|
|
249
265
|
let role;
|
|
250
|
-
if (typeof message.content !== "string") {
|
|
251
|
-
throw new Error("Currently only string content messages are supported.");
|
|
252
|
-
}
|
|
253
266
|
if (message._getType() === "human") {
|
|
254
267
|
role = "user";
|
|
255
268
|
}
|
|
@@ -262,10 +275,35 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
262
275
|
else {
|
|
263
276
|
throw new Error(`Message type "${message._getType()}" is not supported.`);
|
|
264
277
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
278
|
+
if (typeof message.content === "string") {
|
|
279
|
+
return {
|
|
280
|
+
role,
|
|
281
|
+
content: message.content,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
return {
|
|
286
|
+
role,
|
|
287
|
+
content: message.content.map((contentPart) => {
|
|
288
|
+
if (contentPart.type === "image_url") {
|
|
289
|
+
let source;
|
|
290
|
+
if (typeof contentPart.image_url === "string") {
|
|
291
|
+
source = _formatImage(contentPart.image_url);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
source = _formatImage(contentPart.image_url.url);
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
type: "image",
|
|
298
|
+
source,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
return contentPart;
|
|
303
|
+
}
|
|
304
|
+
}),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
269
307
|
});
|
|
270
308
|
return {
|
|
271
309
|
messages: formattedMessages,
|
|
@@ -371,10 +409,6 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
371
409
|
_llmType() {
|
|
372
410
|
return "anthropic";
|
|
373
411
|
}
|
|
374
|
-
/** @ignore */
|
|
375
|
-
_combineLLMOutput() {
|
|
376
|
-
return [];
|
|
377
|
-
}
|
|
378
412
|
}
|
|
379
413
|
export class ChatAnthropic extends ChatAnthropicMessages {
|
|
380
414
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./tool_calling.cjs"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./tool_calling.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./tool_calling.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/* eslint-disable no-process-env */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
3
|
+
import { test } from "@jest/globals";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
6
|
+
import { HumanMessage } from "@langchain/core/messages";
|
|
7
|
+
import { ChatPromptTemplate } from "@langchain/core/prompts";
|
|
8
|
+
import { ChatAnthropicTools } from "../tool_calling.js";
|
|
9
|
+
test("Test ChatAnthropicTools", async () => {
|
|
10
|
+
const chat = new ChatAnthropicTools({
|
|
11
|
+
modelName: "claude-3-sonnet-20240229",
|
|
12
|
+
maxRetries: 0,
|
|
13
|
+
});
|
|
14
|
+
const message = new HumanMessage("Hello!");
|
|
15
|
+
const res = await chat.invoke([message]);
|
|
16
|
+
console.log(JSON.stringify(res));
|
|
17
|
+
});
|
|
18
|
+
test("Test ChatAnthropicTools streaming", async () => {
|
|
19
|
+
const chat = new ChatAnthropicTools({
|
|
20
|
+
modelName: "claude-3-sonnet-20240229",
|
|
21
|
+
maxRetries: 0,
|
|
22
|
+
});
|
|
23
|
+
const message = new HumanMessage("Hello!");
|
|
24
|
+
const stream = await chat.stream([message]);
|
|
25
|
+
const chunks = [];
|
|
26
|
+
for await (const chunk of stream) {
|
|
27
|
+
console.log(chunk);
|
|
28
|
+
chunks.push(chunk);
|
|
29
|
+
}
|
|
30
|
+
expect(chunks.length).toBeGreaterThan(1);
|
|
31
|
+
});
|
|
32
|
+
test("Test ChatAnthropicTools with tools", async () => {
|
|
33
|
+
const chat = new ChatAnthropicTools({
|
|
34
|
+
modelName: "claude-3-sonnet-20240229",
|
|
35
|
+
temperature: 0.1,
|
|
36
|
+
maxRetries: 0,
|
|
37
|
+
}).bind({
|
|
38
|
+
tools: [
|
|
39
|
+
{
|
|
40
|
+
type: "function",
|
|
41
|
+
function: {
|
|
42
|
+
name: "get_current_weather",
|
|
43
|
+
description: "Get the current weather in a given location",
|
|
44
|
+
parameters: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
location: {
|
|
48
|
+
type: "string",
|
|
49
|
+
description: "The city and state, e.g. San Francisco, CA",
|
|
50
|
+
},
|
|
51
|
+
unit: {
|
|
52
|
+
type: "string",
|
|
53
|
+
enum: ["celsius", "fahrenheit"],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
required: ["location"],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
const message = new HumanMessage("What is the weather in San Francisco?");
|
|
63
|
+
const res = await chat.invoke([message]);
|
|
64
|
+
console.log(JSON.stringify(res));
|
|
65
|
+
expect(res.additional_kwargs.tool_calls).toBeDefined();
|
|
66
|
+
expect(res.additional_kwargs.tool_calls?.[0].function.name).toEqual("get_current_weather");
|
|
67
|
+
});
|
|
68
|
+
test("Test ChatAnthropicTools with a forced function call", async () => {
|
|
69
|
+
const chat = new ChatAnthropicTools({
|
|
70
|
+
modelName: "claude-3-sonnet-20240229",
|
|
71
|
+
temperature: 0.1,
|
|
72
|
+
maxRetries: 0,
|
|
73
|
+
}).bind({
|
|
74
|
+
tools: [
|
|
75
|
+
{
|
|
76
|
+
type: "function",
|
|
77
|
+
function: {
|
|
78
|
+
name: "extract_data",
|
|
79
|
+
description: "Return information about the input",
|
|
80
|
+
parameters: {
|
|
81
|
+
type: "object",
|
|
82
|
+
properties: {
|
|
83
|
+
sentiment: {
|
|
84
|
+
type: "string",
|
|
85
|
+
description: "The city and state, e.g. San Francisco, CA",
|
|
86
|
+
},
|
|
87
|
+
aggressiveness: {
|
|
88
|
+
type: "integer",
|
|
89
|
+
description: "How aggressive the input is from 1 to 10",
|
|
90
|
+
},
|
|
91
|
+
language: {
|
|
92
|
+
type: "string",
|
|
93
|
+
description: "The language the input is in",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: ["sentiment", "aggressiveness"],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
tool_choice: { type: "function", function: { name: "extract_data" } },
|
|
102
|
+
});
|
|
103
|
+
const message = new HumanMessage("Extract the desired information from the following passage:\n\nthis is really cool");
|
|
104
|
+
const res = await chat.invoke([message]);
|
|
105
|
+
console.log(JSON.stringify(res));
|
|
106
|
+
expect(res.additional_kwargs.tool_calls).toBeDefined();
|
|
107
|
+
expect(res.additional_kwargs.tool_calls?.[0]?.function.name).toEqual("extract_data");
|
|
108
|
+
});
|
|
109
|
+
test("ChatAnthropicTools with Zod schema", async () => {
|
|
110
|
+
const schema = z.object({
|
|
111
|
+
people: z.array(z.object({
|
|
112
|
+
name: z.string().describe("The name of a person"),
|
|
113
|
+
height: z.number().describe("The person's height"),
|
|
114
|
+
hairColor: z.optional(z.string()).describe("The person's hair color"),
|
|
115
|
+
})),
|
|
116
|
+
});
|
|
117
|
+
const chat = new ChatAnthropicTools({
|
|
118
|
+
modelName: "claude-3-sonnet-20240229",
|
|
119
|
+
temperature: 0.1,
|
|
120
|
+
maxRetries: 0,
|
|
121
|
+
}).bind({
|
|
122
|
+
tools: [
|
|
123
|
+
{
|
|
124
|
+
type: "function",
|
|
125
|
+
function: {
|
|
126
|
+
name: "information_extraction",
|
|
127
|
+
description: "Extracts the relevant information from the passage.",
|
|
128
|
+
parameters: zodToJsonSchema(schema),
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
tool_choice: {
|
|
133
|
+
type: "function",
|
|
134
|
+
function: {
|
|
135
|
+
name: "information_extraction",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
const message = new HumanMessage("Alex is 5 feet tall. Claudia is 1 foot taller than Alex and jumps higher than him. Claudia is a brunette and Alex is blonde.");
|
|
140
|
+
const res = await chat.invoke([message]);
|
|
141
|
+
console.log(JSON.stringify(res));
|
|
142
|
+
expect(res.additional_kwargs.tool_calls).toBeDefined();
|
|
143
|
+
expect(res.additional_kwargs.tool_calls?.[0]?.function.name).toEqual("information_extraction");
|
|
144
|
+
expect(JSON.parse(res.additional_kwargs.tool_calls?.[0]?.function.arguments ?? "")).toEqual({
|
|
145
|
+
people: expect.arrayContaining([
|
|
146
|
+
{ name: "Alex", height: 5, hairColor: "blonde" },
|
|
147
|
+
{ name: "Claudia", height: 6, hairColor: "brunette" },
|
|
148
|
+
]),
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
test("ChatAnthropicTools with parallel tool calling", async () => {
|
|
152
|
+
const schema = z.object({
|
|
153
|
+
name: z.string().describe("The name of a person"),
|
|
154
|
+
height: z.number().describe("The person's height"),
|
|
155
|
+
hairColor: z.optional(z.string()).describe("The person's hair color"),
|
|
156
|
+
});
|
|
157
|
+
const chat = new ChatAnthropicTools({
|
|
158
|
+
modelName: "claude-3-sonnet-20240229",
|
|
159
|
+
temperature: 0.1,
|
|
160
|
+
maxRetries: 0,
|
|
161
|
+
}).bind({
|
|
162
|
+
tools: [
|
|
163
|
+
{
|
|
164
|
+
type: "function",
|
|
165
|
+
function: {
|
|
166
|
+
name: "person",
|
|
167
|
+
description: "A person mentioned in the passage.",
|
|
168
|
+
parameters: zodToJsonSchema(schema),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
tool_choice: {
|
|
173
|
+
type: "function",
|
|
174
|
+
function: {
|
|
175
|
+
name: "person",
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
console.log(zodToJsonSchema(schema));
|
|
180
|
+
const message = new HumanMessage("Alex is 5 feet tall. Claudia is 1 foot taller than Alex and jumps higher than him. Claudia is a brunette and Alex is blonde.");
|
|
181
|
+
const res = await chat.invoke([message]);
|
|
182
|
+
console.log(JSON.stringify(res));
|
|
183
|
+
expect(res.additional_kwargs.tool_calls).toBeDefined();
|
|
184
|
+
expect(res.additional_kwargs.tool_calls?.map((toolCall) => JSON.parse(toolCall.function.arguments ?? ""))).toEqual(expect.arrayContaining([
|
|
185
|
+
{ name: "Alex", height: 5, hairColor: "blonde" },
|
|
186
|
+
{ name: "Claudia", height: 6, hairColor: "brunette" },
|
|
187
|
+
]));
|
|
188
|
+
});
|
|
189
|
+
test("Test ChatAnthropic withStructuredOutput", async () => {
|
|
190
|
+
const runnable = new ChatAnthropicTools({
|
|
191
|
+
modelName: "claude-3-sonnet-20240229",
|
|
192
|
+
maxRetries: 0,
|
|
193
|
+
}).withStructuredOutput({
|
|
194
|
+
schema: z.object({
|
|
195
|
+
name: z.string().describe("The name of a person"),
|
|
196
|
+
height: z.number().describe("The person's height"),
|
|
197
|
+
hairColor: z.optional(z.string()).describe("The person's hair color"),
|
|
198
|
+
}),
|
|
199
|
+
name: "person",
|
|
200
|
+
});
|
|
201
|
+
const message = new HumanMessage("Alex is 5 feet tall. Alex is blonde.");
|
|
202
|
+
const res = await runnable.invoke([message]);
|
|
203
|
+
console.log(JSON.stringify(res, null, 2));
|
|
204
|
+
expect(res).toEqual({ name: "Alex", height: 5, hairColor: "blonde" });
|
|
205
|
+
});
|
|
206
|
+
test("Test ChatAnthropic withStructuredOutput on a single array item", async () => {
|
|
207
|
+
const runnable = new ChatAnthropicTools({
|
|
208
|
+
modelName: "claude-3-sonnet-20240229",
|
|
209
|
+
maxRetries: 0,
|
|
210
|
+
}).withStructuredOutput({
|
|
211
|
+
schema: z.object({
|
|
212
|
+
people: z.array(z.object({
|
|
213
|
+
name: z.string().describe("The name of a person"),
|
|
214
|
+
height: z.number().describe("The person's height"),
|
|
215
|
+
hairColor: z.optional(z.string()).describe("The person's hair color"),
|
|
216
|
+
})),
|
|
217
|
+
}),
|
|
218
|
+
});
|
|
219
|
+
const message = new HumanMessage("Alex is 5 feet tall. Alex is blonde.");
|
|
220
|
+
const res = await runnable.invoke([message]);
|
|
221
|
+
console.log(JSON.stringify(res, null, 2));
|
|
222
|
+
expect(res).toEqual({
|
|
223
|
+
people: [{ hairColor: "blonde", height: 5, name: "Alex" }],
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
test("Test ChatAnthropic withStructuredOutput on a single array item", async () => {
|
|
227
|
+
const runnable = new ChatAnthropicTools({
|
|
228
|
+
modelName: "claude-3-sonnet-20240229",
|
|
229
|
+
maxRetries: 0,
|
|
230
|
+
}).withStructuredOutput({
|
|
231
|
+
schema: z.object({
|
|
232
|
+
sender: z
|
|
233
|
+
.optional(z.string())
|
|
234
|
+
.describe("The sender's name, if available"),
|
|
235
|
+
sender_phone_number: z
|
|
236
|
+
.optional(z.string())
|
|
237
|
+
.describe("The sender's phone number, if available"),
|
|
238
|
+
sender_address: z
|
|
239
|
+
.optional(z.string())
|
|
240
|
+
.describe("The sender's address, if available"),
|
|
241
|
+
action_items: z
|
|
242
|
+
.array(z.string())
|
|
243
|
+
.describe("A list of action items requested by the email"),
|
|
244
|
+
topic: z
|
|
245
|
+
.string()
|
|
246
|
+
.describe("High level description of what the email is about"),
|
|
247
|
+
tone: z.enum(["positive", "negative"]).describe("The tone of the email."),
|
|
248
|
+
}),
|
|
249
|
+
name: "Email",
|
|
250
|
+
});
|
|
251
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
252
|
+
[
|
|
253
|
+
"human",
|
|
254
|
+
"What can you tell me about the following email? Make sure to answer in the correct format: {email}",
|
|
255
|
+
],
|
|
256
|
+
]);
|
|
257
|
+
const extractionChain = prompt.pipe(runnable);
|
|
258
|
+
const response = await extractionChain.invoke({
|
|
259
|
+
email: "From: Erick. The email is about the new project. The tone is positive. The action items are to send the report and to schedule a meeting.",
|
|
260
|
+
});
|
|
261
|
+
console.log(JSON.stringify(response, null, 2));
|
|
262
|
+
expect(response).toEqual({
|
|
263
|
+
sender: "Erick",
|
|
264
|
+
action_items: [expect.any(String), expect.any(String)],
|
|
265
|
+
topic: expect.any(String),
|
|
266
|
+
tone: "positive",
|
|
267
|
+
});
|
|
268
|
+
});
|