@langchain/anthropic 0.3.19 → 0.3.21
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 +4 -5
- package/dist/chat_models.d.ts +1 -2
- package/dist/chat_models.js +4 -5
- package/dist/experimental/tool_calling.cjs +1 -1
- package/dist/experimental/tool_calling.js +1 -1
- package/dist/types.cjs +47 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +45 -1
- package/dist/utils/message_inputs.cjs +219 -11
- package/dist/utils/message_inputs.d.ts +1 -1
- package/dist/utils/message_inputs.js +220 -12
- package/package.json +2 -2
package/dist/chat_models.cjs
CHANGED
|
@@ -81,9 +81,8 @@ function extractToken(chunk) {
|
|
|
81
81
|
*
|
|
82
82
|
* ```typescript
|
|
83
83
|
* // When calling `.bind`, call options should be passed via the first argument
|
|
84
|
-
* const llmWithArgsBound = llm.
|
|
84
|
+
* const llmWithArgsBound = llm.bindTools([...]).withConfig({
|
|
85
85
|
* stop: ["\n"],
|
|
86
|
-
* tools: [...],
|
|
87
86
|
* });
|
|
88
87
|
*
|
|
89
88
|
* // When calling `.bindTools`, call options should be passed via the second argument
|
|
@@ -651,7 +650,7 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
651
650
|
});
|
|
652
651
|
}
|
|
653
652
|
bindTools(tools, kwargs) {
|
|
654
|
-
return this.
|
|
653
|
+
return this.withConfig({
|
|
655
654
|
tools: this.formatStructuredToolToAnthropic(tools),
|
|
656
655
|
...kwargs,
|
|
657
656
|
});
|
|
@@ -925,7 +924,7 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
925
924
|
"generated. Consider disabling `thinking` or adjust your prompt to ensure " +
|
|
926
925
|
"the tool is called.";
|
|
927
926
|
console.warn(thinkingAdmonition);
|
|
928
|
-
llm = this.
|
|
927
|
+
llm = this.withConfig({
|
|
929
928
|
tools,
|
|
930
929
|
});
|
|
931
930
|
const raiseIfNoToolCalls = (message) => {
|
|
@@ -937,7 +936,7 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
937
936
|
llm = llm.pipe(raiseIfNoToolCalls);
|
|
938
937
|
}
|
|
939
938
|
else {
|
|
940
|
-
llm = this.
|
|
939
|
+
llm = this.withConfig({
|
|
941
940
|
tools,
|
|
942
941
|
tool_choice: {
|
|
943
942
|
type: "tool",
|
package/dist/chat_models.d.ts
CHANGED
|
@@ -117,9 +117,8 @@ type Kwargs = Record<string, any>;
|
|
|
117
117
|
*
|
|
118
118
|
* ```typescript
|
|
119
119
|
* // When calling `.bind`, call options should be passed via the first argument
|
|
120
|
-
* const llmWithArgsBound = llm.
|
|
120
|
+
* const llmWithArgsBound = llm.bindTools([...]).withConfig({
|
|
121
121
|
* stop: ["\n"],
|
|
122
|
-
* tools: [...],
|
|
123
122
|
* });
|
|
124
123
|
*
|
|
125
124
|
* // When calling `.bindTools`, call options should be passed via the second argument
|
package/dist/chat_models.js
CHANGED
|
@@ -78,9 +78,8 @@ function extractToken(chunk) {
|
|
|
78
78
|
*
|
|
79
79
|
* ```typescript
|
|
80
80
|
* // When calling `.bind`, call options should be passed via the first argument
|
|
81
|
-
* const llmWithArgsBound = llm.
|
|
81
|
+
* const llmWithArgsBound = llm.bindTools([...]).withConfig({
|
|
82
82
|
* stop: ["\n"],
|
|
83
|
-
* tools: [...],
|
|
84
83
|
* });
|
|
85
84
|
*
|
|
86
85
|
* // When calling `.bindTools`, call options should be passed via the second argument
|
|
@@ -648,7 +647,7 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
648
647
|
});
|
|
649
648
|
}
|
|
650
649
|
bindTools(tools, kwargs) {
|
|
651
|
-
return this.
|
|
650
|
+
return this.withConfig({
|
|
652
651
|
tools: this.formatStructuredToolToAnthropic(tools),
|
|
653
652
|
...kwargs,
|
|
654
653
|
});
|
|
@@ -922,7 +921,7 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
922
921
|
"generated. Consider disabling `thinking` or adjust your prompt to ensure " +
|
|
923
922
|
"the tool is called.";
|
|
924
923
|
console.warn(thinkingAdmonition);
|
|
925
|
-
llm = this.
|
|
924
|
+
llm = this.withConfig({
|
|
926
925
|
tools,
|
|
927
926
|
});
|
|
928
927
|
const raiseIfNoToolCalls = (message) => {
|
|
@@ -934,7 +933,7 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
934
933
|
llm = llm.pipe(raiseIfNoToolCalls);
|
|
935
934
|
}
|
|
936
935
|
else {
|
|
937
|
-
llm = this.
|
|
936
|
+
llm = this.withConfig({
|
|
938
937
|
tools,
|
|
939
938
|
tool_choice: {
|
|
940
939
|
type: "tool",
|
package/dist/types.cjs
CHANGED
|
@@ -1,2 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isAnthropicImageBlockParam = void 0;
|
|
4
|
+
function isAnthropicImageBlockParam(block) {
|
|
5
|
+
if (block == null) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (typeof block !== "object") {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (!("type" in block) || block.type !== "image") {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (!("source" in block) || typeof block.source !== "object") {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (block.source == null) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (!("type" in block.source)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (block.source.type === "base64") {
|
|
24
|
+
if (!("media_type" in block.source)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (typeof block.source.media_type !== "string") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (!("data" in block.source)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (typeof block.source.data !== "string") {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (block.source.type === "url") {
|
|
39
|
+
if (!("url" in block.source)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (typeof block.source.url !== "string") {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
exports.isAnthropicImageBlockParam = isAnthropicImageBlockParam;
|
package/dist/types.d.ts
CHANGED
|
@@ -25,3 +25,4 @@ export type AnthropicToolResultBlockParam = Anthropic.Messages.ToolResultBlockPa
|
|
|
25
25
|
export type AnthropicDocumentBlockParam = Anthropic.Messages.DocumentBlockParam;
|
|
26
26
|
export type AnthropicThinkingBlockParam = Anthropic.Messages.ThinkingBlockParam;
|
|
27
27
|
export type AnthropicRedactedThinkingBlockParam = Anthropic.Messages.RedactedThinkingBlockParam;
|
|
28
|
+
export declare function isAnthropicImageBlockParam(block: unknown): block is AnthropicImageBlockParam;
|
package/dist/types.js
CHANGED
|
@@ -1 +1,45 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export function isAnthropicImageBlockParam(block) {
|
|
2
|
+
if (block == null) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
if (typeof block !== "object") {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (!("type" in block) || block.type !== "image") {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (!("source" in block) || typeof block.source !== "object") {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (block.source == null) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (!("type" in block.source)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (block.source.type === "base64") {
|
|
21
|
+
if (!("media_type" in block.source)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (typeof block.source.media_type !== "string") {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (!("data" in block.source)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (typeof block.source.data !== "string") {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if (block.source.type === "url") {
|
|
36
|
+
if (!("url" in block.source)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (typeof block.source.url !== "string") {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
@@ -5,21 +5,38 @@ exports._convertMessagesToAnthropicPayload = exports._convertLangChainToolCallTo
|
|
|
5
5
|
* This util file contains functions for converting LangChain messages to Anthropic messages.
|
|
6
6
|
*/
|
|
7
7
|
const messages_1 = require("@langchain/core/messages");
|
|
8
|
+
const types_js_1 = require("../types.cjs");
|
|
8
9
|
function _formatImage(imageUrl) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const parsed = (0, messages_1.parseBase64DataUrl)({ dataUrl: imageUrl });
|
|
11
|
+
if (parsed) {
|
|
12
|
+
return {
|
|
13
|
+
type: "base64",
|
|
14
|
+
media_type: parsed.mime_type,
|
|
15
|
+
data: parsed.data,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
let parsedUrl;
|
|
19
|
+
try {
|
|
20
|
+
parsedUrl = new URL(imageUrl);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
12
23
|
throw new Error([
|
|
13
|
-
|
|
24
|
+
`Malformed image URL: ${JSON.stringify(imageUrl)}. Content blocks of type 'image_url' must be a valid http, https, or base64-encoded data URL.`,
|
|
14
25
|
"Example: data:image/png;base64,/9j/4AAQSk...",
|
|
26
|
+
"Example: https://example.com/image.jpg",
|
|
15
27
|
].join("\n\n"));
|
|
16
28
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
29
|
+
if (parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:") {
|
|
30
|
+
return {
|
|
31
|
+
type: "url",
|
|
32
|
+
url: imageUrl,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
throw new Error([
|
|
36
|
+
`Invalid image URL protocol: ${JSON.stringify(parsedUrl.protocol)}. Anthropic only supports images as http, https, or base64-encoded data URLs on 'image_url' content blocks.`,
|
|
37
|
+
"Example: data:image/png;base64,/9j/4AAQSk...",
|
|
38
|
+
"Example: https://example.com/image.jpg",
|
|
39
|
+
].join("\n\n"));
|
|
23
40
|
}
|
|
24
41
|
function _ensureMessageContents(messages) {
|
|
25
42
|
// Merge runs of human/tool messages into single human messages with content blocks.
|
|
@@ -57,7 +74,10 @@ function _ensureMessageContents(messages) {
|
|
|
57
74
|
content: [
|
|
58
75
|
{
|
|
59
76
|
type: "tool_result",
|
|
60
|
-
|
|
77
|
+
// rare case: message.content could be undefined
|
|
78
|
+
...(message.content != null
|
|
79
|
+
? { content: _formatContent(message.content) }
|
|
80
|
+
: {}),
|
|
61
81
|
tool_use_id: message.tool_call_id,
|
|
62
82
|
},
|
|
63
83
|
],
|
|
@@ -82,6 +102,188 @@ function _convertLangChainToolCallToAnthropic(toolCall) {
|
|
|
82
102
|
};
|
|
83
103
|
}
|
|
84
104
|
exports._convertLangChainToolCallToAnthropic = _convertLangChainToolCallToAnthropic;
|
|
105
|
+
const standardContentBlockConverter = {
|
|
106
|
+
providerName: "anthropic",
|
|
107
|
+
fromStandardTextBlock(block) {
|
|
108
|
+
return {
|
|
109
|
+
type: "text",
|
|
110
|
+
text: block.text,
|
|
111
|
+
...("citations" in (block.metadata ?? {})
|
|
112
|
+
? { citations: block.metadata.citations }
|
|
113
|
+
: {}),
|
|
114
|
+
...("cache_control" in (block.metadata ?? {})
|
|
115
|
+
? { cache_control: block.metadata.cache_control }
|
|
116
|
+
: {}),
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
fromStandardImageBlock(block) {
|
|
120
|
+
if (block.source_type === "url") {
|
|
121
|
+
const data = (0, messages_1.parseBase64DataUrl)({
|
|
122
|
+
dataUrl: block.url,
|
|
123
|
+
asTypedArray: false,
|
|
124
|
+
});
|
|
125
|
+
if (data) {
|
|
126
|
+
return {
|
|
127
|
+
type: "image",
|
|
128
|
+
source: {
|
|
129
|
+
type: "base64",
|
|
130
|
+
data: data.data,
|
|
131
|
+
media_type: data.mime_type,
|
|
132
|
+
},
|
|
133
|
+
...("cache_control" in (block.metadata ?? {})
|
|
134
|
+
? { cache_control: block.metadata.cache_control }
|
|
135
|
+
: {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
return {
|
|
140
|
+
type: "image",
|
|
141
|
+
source: {
|
|
142
|
+
type: "url",
|
|
143
|
+
url: block.url,
|
|
144
|
+
media_type: block.mime_type ?? "",
|
|
145
|
+
},
|
|
146
|
+
...("cache_control" in (block.metadata ?? {})
|
|
147
|
+
? { cache_control: block.metadata.cache_control }
|
|
148
|
+
: {}),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
if (block.source_type === "base64") {
|
|
154
|
+
return {
|
|
155
|
+
type: "image",
|
|
156
|
+
source: {
|
|
157
|
+
type: "base64",
|
|
158
|
+
data: block.data,
|
|
159
|
+
media_type: block.mime_type ?? "",
|
|
160
|
+
},
|
|
161
|
+
...("cache_control" in (block.metadata ?? {})
|
|
162
|
+
? { cache_control: block.metadata.cache_control }
|
|
163
|
+
: {}),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
throw new Error(`Unsupported image source type: ${block.source_type}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
fromStandardFileBlock(block) {
|
|
172
|
+
const mime_type = (block.mime_type ?? "").split(";")[0];
|
|
173
|
+
if (block.source_type === "url") {
|
|
174
|
+
if (mime_type === "application/pdf" || mime_type === "") {
|
|
175
|
+
return {
|
|
176
|
+
type: "document",
|
|
177
|
+
source: {
|
|
178
|
+
type: "url",
|
|
179
|
+
url: block.url,
|
|
180
|
+
media_type: block.mime_type ?? "",
|
|
181
|
+
},
|
|
182
|
+
...("cache_control" in (block.metadata ?? {})
|
|
183
|
+
? { cache_control: block.metadata.cache_control }
|
|
184
|
+
: {}),
|
|
185
|
+
...("citations" in (block.metadata ?? {})
|
|
186
|
+
? { citations: block.metadata.citations }
|
|
187
|
+
: {}),
|
|
188
|
+
...("context" in (block.metadata ?? {})
|
|
189
|
+
? { context: block.metadata.context }
|
|
190
|
+
: {}),
|
|
191
|
+
...("title" in (block.metadata ?? {})
|
|
192
|
+
? { title: block.metadata.title }
|
|
193
|
+
: {}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
throw new Error(`Unsupported file mime type for file url source: ${block.mime_type}`);
|
|
197
|
+
}
|
|
198
|
+
else if (block.source_type === "text") {
|
|
199
|
+
if (mime_type === "text/plain" || mime_type === "") {
|
|
200
|
+
return {
|
|
201
|
+
type: "document",
|
|
202
|
+
source: {
|
|
203
|
+
type: "text",
|
|
204
|
+
data: block.text,
|
|
205
|
+
media_type: block.mime_type ?? "",
|
|
206
|
+
},
|
|
207
|
+
...("cache_control" in (block.metadata ?? {})
|
|
208
|
+
? { cache_control: block.metadata.cache_control }
|
|
209
|
+
: {}),
|
|
210
|
+
...("citations" in (block.metadata ?? {})
|
|
211
|
+
? { citations: block.metadata.citations }
|
|
212
|
+
: {}),
|
|
213
|
+
...("context" in (block.metadata ?? {})
|
|
214
|
+
? { context: block.metadata.context }
|
|
215
|
+
: {}),
|
|
216
|
+
...("title" in (block.metadata ?? {})
|
|
217
|
+
? { title: block.metadata.title }
|
|
218
|
+
: {}),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
throw new Error(`Unsupported file mime type for file text source: ${block.mime_type}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else if (block.source_type === "base64") {
|
|
226
|
+
if (mime_type === "application/pdf" || mime_type === "") {
|
|
227
|
+
return {
|
|
228
|
+
type: "document",
|
|
229
|
+
source: {
|
|
230
|
+
type: "base64",
|
|
231
|
+
data: block.data,
|
|
232
|
+
media_type: "application/pdf",
|
|
233
|
+
},
|
|
234
|
+
...("cache_control" in (block.metadata ?? {})
|
|
235
|
+
? { cache_control: block.metadata.cache_control }
|
|
236
|
+
: {}),
|
|
237
|
+
...("citations" in (block.metadata ?? {})
|
|
238
|
+
? { citations: block.metadata.citations }
|
|
239
|
+
: {}),
|
|
240
|
+
...("context" in (block.metadata ?? {})
|
|
241
|
+
? { context: block.metadata.context }
|
|
242
|
+
: {}),
|
|
243
|
+
...("title" in (block.metadata ?? {})
|
|
244
|
+
? { title: block.metadata.title }
|
|
245
|
+
: {}),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
else if (["image/jpeg", "image/png", "image/gif", "image/webp"].includes(mime_type)) {
|
|
249
|
+
return {
|
|
250
|
+
type: "document",
|
|
251
|
+
source: {
|
|
252
|
+
type: "content",
|
|
253
|
+
content: [
|
|
254
|
+
{
|
|
255
|
+
type: "image",
|
|
256
|
+
source: {
|
|
257
|
+
type: "base64",
|
|
258
|
+
data: block.data,
|
|
259
|
+
media_type: mime_type,
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
...("cache_control" in (block.metadata ?? {})
|
|
265
|
+
? { cache_control: block.metadata.cache_control }
|
|
266
|
+
: {}),
|
|
267
|
+
...("citations" in (block.metadata ?? {})
|
|
268
|
+
? { citations: block.metadata.citations }
|
|
269
|
+
: {}),
|
|
270
|
+
...("context" in (block.metadata ?? {})
|
|
271
|
+
? { context: block.metadata.context }
|
|
272
|
+
: {}),
|
|
273
|
+
...("title" in (block.metadata ?? {})
|
|
274
|
+
? { title: block.metadata.title }
|
|
275
|
+
: {}),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
throw new Error(`Unsupported file mime type for file base64 source: ${block.mime_type}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
throw new Error(`Unsupported file source type: ${block.source_type}`);
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
};
|
|
85
287
|
function _formatContent(content) {
|
|
86
288
|
const toolTypes = ["tool_use", "tool_result", "input_json_delta"];
|
|
87
289
|
const textTypes = ["text", "text_delta"];
|
|
@@ -90,6 +292,9 @@ function _formatContent(content) {
|
|
|
90
292
|
}
|
|
91
293
|
else {
|
|
92
294
|
const contentBlocks = content.map((contentPart) => {
|
|
295
|
+
if ((0, messages_1.isDataContentBlock)(contentPart)) {
|
|
296
|
+
return (0, messages_1.convertToProviderContentBlock)(contentPart, standardContentBlockConverter);
|
|
297
|
+
}
|
|
93
298
|
const cacheControl = "cache_control" in contentPart ? contentPart.cache_control : undefined;
|
|
94
299
|
if (contentPart.type === "image_url") {
|
|
95
300
|
let source;
|
|
@@ -105,6 +310,9 @@ function _formatContent(content) {
|
|
|
105
310
|
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
106
311
|
};
|
|
107
312
|
}
|
|
313
|
+
else if ((0, types_js_1.isAnthropicImageBlockParam)(contentPart)) {
|
|
314
|
+
return contentPart;
|
|
315
|
+
}
|
|
108
316
|
else if (contentPart.type === "document") {
|
|
109
317
|
// PDF
|
|
110
318
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This util file contains functions for converting LangChain messages to Anthropic messages.
|
|
3
3
|
*/
|
|
4
|
-
import { BaseMessage } from "@langchain/core/messages";
|
|
4
|
+
import { type BaseMessage } from "@langchain/core/messages";
|
|
5
5
|
import { ToolCall } from "@langchain/core/messages/tool";
|
|
6
6
|
import { AnthropicMessageCreateParams, AnthropicToolResponse } from "../types.js";
|
|
7
7
|
export declare function _convertLangChainToolCallToAnthropic(toolCall: ToolCall): AnthropicToolResponse;
|
|
@@ -1,22 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This util file contains functions for converting LangChain messages to Anthropic messages.
|
|
3
3
|
*/
|
|
4
|
-
import { HumanMessage, isAIMessage, } from "@langchain/core/messages";
|
|
4
|
+
import { HumanMessage, isAIMessage, isDataContentBlock, convertToProviderContentBlock, parseBase64DataUrl, } from "@langchain/core/messages";
|
|
5
|
+
import { isAnthropicImageBlockParam, } from "../types.js";
|
|
5
6
|
function _formatImage(imageUrl) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const parsed = parseBase64DataUrl({ dataUrl: imageUrl });
|
|
8
|
+
if (parsed) {
|
|
9
|
+
return {
|
|
10
|
+
type: "base64",
|
|
11
|
+
media_type: parsed.mime_type,
|
|
12
|
+
data: parsed.data,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
let parsedUrl;
|
|
16
|
+
try {
|
|
17
|
+
parsedUrl = new URL(imageUrl);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
9
20
|
throw new Error([
|
|
10
|
-
|
|
21
|
+
`Malformed image URL: ${JSON.stringify(imageUrl)}. Content blocks of type 'image_url' must be a valid http, https, or base64-encoded data URL.`,
|
|
11
22
|
"Example: data:image/png;base64,/9j/4AAQSk...",
|
|
23
|
+
"Example: https://example.com/image.jpg",
|
|
12
24
|
].join("\n\n"));
|
|
13
25
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
26
|
+
if (parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:") {
|
|
27
|
+
return {
|
|
28
|
+
type: "url",
|
|
29
|
+
url: imageUrl,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
throw new Error([
|
|
33
|
+
`Invalid image URL protocol: ${JSON.stringify(parsedUrl.protocol)}. Anthropic only supports images as http, https, or base64-encoded data URLs on 'image_url' content blocks.`,
|
|
34
|
+
"Example: data:image/png;base64,/9j/4AAQSk...",
|
|
35
|
+
"Example: https://example.com/image.jpg",
|
|
36
|
+
].join("\n\n"));
|
|
20
37
|
}
|
|
21
38
|
function _ensureMessageContents(messages) {
|
|
22
39
|
// Merge runs of human/tool messages into single human messages with content blocks.
|
|
@@ -54,7 +71,10 @@ function _ensureMessageContents(messages) {
|
|
|
54
71
|
content: [
|
|
55
72
|
{
|
|
56
73
|
type: "tool_result",
|
|
57
|
-
|
|
74
|
+
// rare case: message.content could be undefined
|
|
75
|
+
...(message.content != null
|
|
76
|
+
? { content: _formatContent(message.content) }
|
|
77
|
+
: {}),
|
|
58
78
|
tool_use_id: message.tool_call_id,
|
|
59
79
|
},
|
|
60
80
|
],
|
|
@@ -78,6 +98,188 @@ export function _convertLangChainToolCallToAnthropic(toolCall) {
|
|
|
78
98
|
input: toolCall.args,
|
|
79
99
|
};
|
|
80
100
|
}
|
|
101
|
+
const standardContentBlockConverter = {
|
|
102
|
+
providerName: "anthropic",
|
|
103
|
+
fromStandardTextBlock(block) {
|
|
104
|
+
return {
|
|
105
|
+
type: "text",
|
|
106
|
+
text: block.text,
|
|
107
|
+
...("citations" in (block.metadata ?? {})
|
|
108
|
+
? { citations: block.metadata.citations }
|
|
109
|
+
: {}),
|
|
110
|
+
...("cache_control" in (block.metadata ?? {})
|
|
111
|
+
? { cache_control: block.metadata.cache_control }
|
|
112
|
+
: {}),
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
fromStandardImageBlock(block) {
|
|
116
|
+
if (block.source_type === "url") {
|
|
117
|
+
const data = parseBase64DataUrl({
|
|
118
|
+
dataUrl: block.url,
|
|
119
|
+
asTypedArray: false,
|
|
120
|
+
});
|
|
121
|
+
if (data) {
|
|
122
|
+
return {
|
|
123
|
+
type: "image",
|
|
124
|
+
source: {
|
|
125
|
+
type: "base64",
|
|
126
|
+
data: data.data,
|
|
127
|
+
media_type: data.mime_type,
|
|
128
|
+
},
|
|
129
|
+
...("cache_control" in (block.metadata ?? {})
|
|
130
|
+
? { cache_control: block.metadata.cache_control }
|
|
131
|
+
: {}),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return {
|
|
136
|
+
type: "image",
|
|
137
|
+
source: {
|
|
138
|
+
type: "url",
|
|
139
|
+
url: block.url,
|
|
140
|
+
media_type: block.mime_type ?? "",
|
|
141
|
+
},
|
|
142
|
+
...("cache_control" in (block.metadata ?? {})
|
|
143
|
+
? { cache_control: block.metadata.cache_control }
|
|
144
|
+
: {}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
if (block.source_type === "base64") {
|
|
150
|
+
return {
|
|
151
|
+
type: "image",
|
|
152
|
+
source: {
|
|
153
|
+
type: "base64",
|
|
154
|
+
data: block.data,
|
|
155
|
+
media_type: block.mime_type ?? "",
|
|
156
|
+
},
|
|
157
|
+
...("cache_control" in (block.metadata ?? {})
|
|
158
|
+
? { cache_control: block.metadata.cache_control }
|
|
159
|
+
: {}),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
throw new Error(`Unsupported image source type: ${block.source_type}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
fromStandardFileBlock(block) {
|
|
168
|
+
const mime_type = (block.mime_type ?? "").split(";")[0];
|
|
169
|
+
if (block.source_type === "url") {
|
|
170
|
+
if (mime_type === "application/pdf" || mime_type === "") {
|
|
171
|
+
return {
|
|
172
|
+
type: "document",
|
|
173
|
+
source: {
|
|
174
|
+
type: "url",
|
|
175
|
+
url: block.url,
|
|
176
|
+
media_type: block.mime_type ?? "",
|
|
177
|
+
},
|
|
178
|
+
...("cache_control" in (block.metadata ?? {})
|
|
179
|
+
? { cache_control: block.metadata.cache_control }
|
|
180
|
+
: {}),
|
|
181
|
+
...("citations" in (block.metadata ?? {})
|
|
182
|
+
? { citations: block.metadata.citations }
|
|
183
|
+
: {}),
|
|
184
|
+
...("context" in (block.metadata ?? {})
|
|
185
|
+
? { context: block.metadata.context }
|
|
186
|
+
: {}),
|
|
187
|
+
...("title" in (block.metadata ?? {})
|
|
188
|
+
? { title: block.metadata.title }
|
|
189
|
+
: {}),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
throw new Error(`Unsupported file mime type for file url source: ${block.mime_type}`);
|
|
193
|
+
}
|
|
194
|
+
else if (block.source_type === "text") {
|
|
195
|
+
if (mime_type === "text/plain" || mime_type === "") {
|
|
196
|
+
return {
|
|
197
|
+
type: "document",
|
|
198
|
+
source: {
|
|
199
|
+
type: "text",
|
|
200
|
+
data: block.text,
|
|
201
|
+
media_type: block.mime_type ?? "",
|
|
202
|
+
},
|
|
203
|
+
...("cache_control" in (block.metadata ?? {})
|
|
204
|
+
? { cache_control: block.metadata.cache_control }
|
|
205
|
+
: {}),
|
|
206
|
+
...("citations" in (block.metadata ?? {})
|
|
207
|
+
? { citations: block.metadata.citations }
|
|
208
|
+
: {}),
|
|
209
|
+
...("context" in (block.metadata ?? {})
|
|
210
|
+
? { context: block.metadata.context }
|
|
211
|
+
: {}),
|
|
212
|
+
...("title" in (block.metadata ?? {})
|
|
213
|
+
? { title: block.metadata.title }
|
|
214
|
+
: {}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
throw new Error(`Unsupported file mime type for file text source: ${block.mime_type}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (block.source_type === "base64") {
|
|
222
|
+
if (mime_type === "application/pdf" || mime_type === "") {
|
|
223
|
+
return {
|
|
224
|
+
type: "document",
|
|
225
|
+
source: {
|
|
226
|
+
type: "base64",
|
|
227
|
+
data: block.data,
|
|
228
|
+
media_type: "application/pdf",
|
|
229
|
+
},
|
|
230
|
+
...("cache_control" in (block.metadata ?? {})
|
|
231
|
+
? { cache_control: block.metadata.cache_control }
|
|
232
|
+
: {}),
|
|
233
|
+
...("citations" in (block.metadata ?? {})
|
|
234
|
+
? { citations: block.metadata.citations }
|
|
235
|
+
: {}),
|
|
236
|
+
...("context" in (block.metadata ?? {})
|
|
237
|
+
? { context: block.metadata.context }
|
|
238
|
+
: {}),
|
|
239
|
+
...("title" in (block.metadata ?? {})
|
|
240
|
+
? { title: block.metadata.title }
|
|
241
|
+
: {}),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
else if (["image/jpeg", "image/png", "image/gif", "image/webp"].includes(mime_type)) {
|
|
245
|
+
return {
|
|
246
|
+
type: "document",
|
|
247
|
+
source: {
|
|
248
|
+
type: "content",
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: "image",
|
|
252
|
+
source: {
|
|
253
|
+
type: "base64",
|
|
254
|
+
data: block.data,
|
|
255
|
+
media_type: mime_type,
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
...("cache_control" in (block.metadata ?? {})
|
|
261
|
+
? { cache_control: block.metadata.cache_control }
|
|
262
|
+
: {}),
|
|
263
|
+
...("citations" in (block.metadata ?? {})
|
|
264
|
+
? { citations: block.metadata.citations }
|
|
265
|
+
: {}),
|
|
266
|
+
...("context" in (block.metadata ?? {})
|
|
267
|
+
? { context: block.metadata.context }
|
|
268
|
+
: {}),
|
|
269
|
+
...("title" in (block.metadata ?? {})
|
|
270
|
+
? { title: block.metadata.title }
|
|
271
|
+
: {}),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
throw new Error(`Unsupported file mime type for file base64 source: ${block.mime_type}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
throw new Error(`Unsupported file source type: ${block.source_type}`);
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
};
|
|
81
283
|
function _formatContent(content) {
|
|
82
284
|
const toolTypes = ["tool_use", "tool_result", "input_json_delta"];
|
|
83
285
|
const textTypes = ["text", "text_delta"];
|
|
@@ -86,6 +288,9 @@ function _formatContent(content) {
|
|
|
86
288
|
}
|
|
87
289
|
else {
|
|
88
290
|
const contentBlocks = content.map((contentPart) => {
|
|
291
|
+
if (isDataContentBlock(contentPart)) {
|
|
292
|
+
return convertToProviderContentBlock(contentPart, standardContentBlockConverter);
|
|
293
|
+
}
|
|
89
294
|
const cacheControl = "cache_control" in contentPart ? contentPart.cache_control : undefined;
|
|
90
295
|
if (contentPart.type === "image_url") {
|
|
91
296
|
let source;
|
|
@@ -101,6 +306,9 @@ function _formatContent(content) {
|
|
|
101
306
|
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
102
307
|
};
|
|
103
308
|
}
|
|
309
|
+
else if (isAnthropicImageBlockParam(contentPart)) {
|
|
310
|
+
return contentPart;
|
|
311
|
+
}
|
|
104
312
|
else if (contentPart.type === "document") {
|
|
105
313
|
// PDF
|
|
106
314
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/anthropic",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.21",
|
|
4
4
|
"description": "Anthropic integrations for LangChain.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"author": "LangChain",
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@anthropic-ai/sdk": "^0.
|
|
38
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
39
39
|
"fast-xml-parser": "^4.4.1",
|
|
40
40
|
"zod": "^3.22.4",
|
|
41
41
|
"zod-to-json-schema": "^3.22.4"
|