@langchain/anthropic 0.2.3 → 0.2.5
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 +274 -121
- package/dist/chat_models.d.ts +10 -13
- package/dist/chat_models.js +274 -121
- package/dist/output_parsers.cjs +6 -1
- package/dist/output_parsers.js +6 -1
- package/dist/utils.cjs +28 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +24 -0
- package/package.json +2 -2
package/dist/chat_models.cjs
CHANGED
|
@@ -10,7 +10,12 @@ const base_1 = require("@langchain/core/language_models/base");
|
|
|
10
10
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
11
11
|
const runnables_1 = require("@langchain/core/runnables");
|
|
12
12
|
const types_1 = require("@langchain/core/utils/types");
|
|
13
|
+
const stream_1 = require("@langchain/core/utils/stream");
|
|
13
14
|
const output_parsers_js_1 = require("./output_parsers.cjs");
|
|
15
|
+
const utils_js_1 = require("./utils.cjs");
|
|
16
|
+
function _toolsInParams(params) {
|
|
17
|
+
return !!(params.tools && params.tools.length > 0);
|
|
18
|
+
}
|
|
14
19
|
function _formatImage(imageUrl) {
|
|
15
20
|
const regex = /^data:(image\/.+);base64,(.+)$/;
|
|
16
21
|
const match = imageUrl.match(regex);
|
|
@@ -44,6 +49,8 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
|
|
|
44
49
|
content: messages[0].text,
|
|
45
50
|
additional_kwargs: additionalKwargs,
|
|
46
51
|
usage_metadata: usageMetadata,
|
|
52
|
+
response_metadata: additionalKwargs,
|
|
53
|
+
id: additionalKwargs.id,
|
|
47
54
|
}),
|
|
48
55
|
},
|
|
49
56
|
];
|
|
@@ -59,6 +66,8 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
|
|
|
59
66
|
additional_kwargs: additionalKwargs,
|
|
60
67
|
tool_calls: toolCalls,
|
|
61
68
|
usage_metadata: usageMetadata,
|
|
69
|
+
response_metadata: additionalKwargs,
|
|
70
|
+
id: additionalKwargs.id,
|
|
62
71
|
}),
|
|
63
72
|
},
|
|
64
73
|
];
|
|
@@ -69,6 +78,117 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
|
|
|
69
78
|
function isAnthropicTool(tool) {
|
|
70
79
|
return "input_schema" in tool;
|
|
71
80
|
}
|
|
81
|
+
function _makeMessageChunkFromAnthropicEvent(data, fields) {
|
|
82
|
+
let usageDataCopy = { ...fields.usageData };
|
|
83
|
+
if (data.type === "message_start") {
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
85
|
+
const { content, usage, ...additionalKwargs } = data.message;
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
+
const filteredAdditionalKwargs = {};
|
|
88
|
+
for (const [key, value] of Object.entries(additionalKwargs)) {
|
|
89
|
+
if (value !== undefined && value !== null) {
|
|
90
|
+
filteredAdditionalKwargs[key] = value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
usageDataCopy = usage;
|
|
94
|
+
let usageMetadata;
|
|
95
|
+
if (fields.streamUsage) {
|
|
96
|
+
usageMetadata = {
|
|
97
|
+
input_tokens: usage.input_tokens,
|
|
98
|
+
output_tokens: usage.output_tokens,
|
|
99
|
+
total_tokens: usage.input_tokens + usage.output_tokens,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
console.log("data.message", data.message);
|
|
103
|
+
return {
|
|
104
|
+
chunk: new messages_1.AIMessageChunk({
|
|
105
|
+
content: fields.coerceContentToString ? "" : [],
|
|
106
|
+
additional_kwargs: filteredAdditionalKwargs,
|
|
107
|
+
usage_metadata: usageMetadata,
|
|
108
|
+
id: data.message.id,
|
|
109
|
+
}),
|
|
110
|
+
usageData: usageDataCopy,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
else if (data.type === "message_delta") {
|
|
114
|
+
let usageMetadata;
|
|
115
|
+
if (fields.streamUsage) {
|
|
116
|
+
usageMetadata = {
|
|
117
|
+
input_tokens: data.usage.output_tokens,
|
|
118
|
+
output_tokens: 0,
|
|
119
|
+
total_tokens: data.usage.output_tokens,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (data?.usage !== undefined) {
|
|
123
|
+
usageDataCopy.output_tokens += data.usage.output_tokens;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
chunk: new messages_1.AIMessageChunk({
|
|
127
|
+
content: fields.coerceContentToString ? "" : [],
|
|
128
|
+
additional_kwargs: { ...data.delta },
|
|
129
|
+
usage_metadata: usageMetadata,
|
|
130
|
+
}),
|
|
131
|
+
usageData: usageDataCopy,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
else if (data.type === "content_block_start" &&
|
|
135
|
+
data.content_block.type === "tool_use") {
|
|
136
|
+
return {
|
|
137
|
+
chunk: new messages_1.AIMessageChunk({
|
|
138
|
+
content: fields.coerceContentToString
|
|
139
|
+
? ""
|
|
140
|
+
: [
|
|
141
|
+
{
|
|
142
|
+
index: data.index,
|
|
143
|
+
...data.content_block,
|
|
144
|
+
input: "",
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
additional_kwargs: {},
|
|
148
|
+
}),
|
|
149
|
+
usageData: usageDataCopy,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
else if (data.type === "content_block_delta" &&
|
|
153
|
+
data.delta.type === "text_delta") {
|
|
154
|
+
const content = data.delta?.text;
|
|
155
|
+
if (content !== undefined) {
|
|
156
|
+
return {
|
|
157
|
+
chunk: new messages_1.AIMessageChunk({
|
|
158
|
+
content: fields.coerceContentToString
|
|
159
|
+
? content
|
|
160
|
+
: [
|
|
161
|
+
{
|
|
162
|
+
index: data.index,
|
|
163
|
+
...data.delta,
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
additional_kwargs: {},
|
|
167
|
+
}),
|
|
168
|
+
usageData: usageDataCopy,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else if (data.type === "content_block_delta" &&
|
|
173
|
+
data.delta.type === "input_json_delta") {
|
|
174
|
+
return {
|
|
175
|
+
chunk: new messages_1.AIMessageChunk({
|
|
176
|
+
content: fields.coerceContentToString
|
|
177
|
+
? ""
|
|
178
|
+
: [
|
|
179
|
+
{
|
|
180
|
+
index: data.index,
|
|
181
|
+
input: data.delta.partial_json,
|
|
182
|
+
type: data.delta.type,
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
additional_kwargs: {},
|
|
186
|
+
}),
|
|
187
|
+
usageData: usageDataCopy,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
72
192
|
function _mergeMessages(messages) {
|
|
73
193
|
// Merge runs of human/tool messages into single human messages with content blocks.
|
|
74
194
|
const merged = [];
|
|
@@ -243,6 +363,90 @@ function _formatMessagesForAnthropic(messages) {
|
|
|
243
363
|
system,
|
|
244
364
|
};
|
|
245
365
|
}
|
|
366
|
+
function extractToolCallChunk(chunk) {
|
|
367
|
+
let newToolCallChunk;
|
|
368
|
+
// Initial chunk for tool calls from anthropic contains identifying information like ID and name.
|
|
369
|
+
// This chunk does not contain any input JSON.
|
|
370
|
+
const toolUseChunks = Array.isArray(chunk.content)
|
|
371
|
+
? chunk.content.find((c) => c.type === "tool_use")
|
|
372
|
+
: undefined;
|
|
373
|
+
if (toolUseChunks &&
|
|
374
|
+
"index" in toolUseChunks &&
|
|
375
|
+
"name" in toolUseChunks &&
|
|
376
|
+
"id" in toolUseChunks) {
|
|
377
|
+
newToolCallChunk = {
|
|
378
|
+
args: "",
|
|
379
|
+
id: toolUseChunks.id,
|
|
380
|
+
name: toolUseChunks.name,
|
|
381
|
+
index: toolUseChunks.index,
|
|
382
|
+
type: "tool_call_chunk",
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
// Chunks after the initial chunk only contain the index and partial JSON.
|
|
386
|
+
const inputJsonDeltaChunks = Array.isArray(chunk.content)
|
|
387
|
+
? chunk.content.find((c) => c.type === "input_json_delta")
|
|
388
|
+
: undefined;
|
|
389
|
+
if (inputJsonDeltaChunks &&
|
|
390
|
+
"index" in inputJsonDeltaChunks &&
|
|
391
|
+
"input" in inputJsonDeltaChunks) {
|
|
392
|
+
if (typeof inputJsonDeltaChunks.input === "string") {
|
|
393
|
+
newToolCallChunk = {
|
|
394
|
+
args: inputJsonDeltaChunks.input,
|
|
395
|
+
index: inputJsonDeltaChunks.index,
|
|
396
|
+
type: "tool_call_chunk",
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
newToolCallChunk = {
|
|
401
|
+
args: JSON.stringify(inputJsonDeltaChunks.input, null, 2),
|
|
402
|
+
index: inputJsonDeltaChunks.index,
|
|
403
|
+
type: "tool_call_chunk",
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return newToolCallChunk;
|
|
408
|
+
}
|
|
409
|
+
function extractToken(chunk) {
|
|
410
|
+
return typeof chunk.content === "string" && chunk.content !== ""
|
|
411
|
+
? chunk.content
|
|
412
|
+
: undefined;
|
|
413
|
+
}
|
|
414
|
+
function extractToolUseContent(chunk, concatenatedChunks) {
|
|
415
|
+
let newConcatenatedChunks = concatenatedChunks;
|
|
416
|
+
// Remove `tool_use` content types until the last chunk.
|
|
417
|
+
let toolUseContent;
|
|
418
|
+
if (!newConcatenatedChunks) {
|
|
419
|
+
newConcatenatedChunks = chunk;
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
newConcatenatedChunks = (0, stream_1.concat)(newConcatenatedChunks, chunk);
|
|
423
|
+
}
|
|
424
|
+
if (Array.isArray(newConcatenatedChunks.content) &&
|
|
425
|
+
newConcatenatedChunks.content.find((c) => c.type === "tool_use")) {
|
|
426
|
+
try {
|
|
427
|
+
const toolUseMsg = newConcatenatedChunks.content.find((c) => c.type === "tool_use");
|
|
428
|
+
if (!toolUseMsg ||
|
|
429
|
+
!("input" in toolUseMsg || "name" in toolUseMsg || "id" in toolUseMsg))
|
|
430
|
+
return;
|
|
431
|
+
const parsedArgs = JSON.parse(toolUseMsg.input);
|
|
432
|
+
if (parsedArgs) {
|
|
433
|
+
toolUseContent = {
|
|
434
|
+
type: "tool_use",
|
|
435
|
+
id: toolUseMsg.id,
|
|
436
|
+
name: toolUseMsg.name,
|
|
437
|
+
input: parsedArgs,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
catch (_) {
|
|
442
|
+
// no-op
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
toolUseContent,
|
|
447
|
+
concatenatedChunks: newConcatenatedChunks,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
246
450
|
/**
|
|
247
451
|
* Wrapper around Anthropic large language models.
|
|
248
452
|
*
|
|
@@ -468,22 +672,7 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
468
672
|
* Get the parameters used to invoke the model
|
|
469
673
|
*/
|
|
470
674
|
invocationParams(options) {
|
|
471
|
-
|
|
472
|
-
if (options?.tool_choice) {
|
|
473
|
-
if (options?.tool_choice === "any") {
|
|
474
|
-
tool_choice = {
|
|
475
|
-
type: "any",
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
else if (options?.tool_choice === "auto") {
|
|
479
|
-
tool_choice = {
|
|
480
|
-
type: "auto",
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
tool_choice = options?.tool_choice;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
675
|
+
const tool_choice = (0, utils_js_1.handleToolChoice)(options?.tool_choice);
|
|
487
676
|
return {
|
|
488
677
|
model: this.model,
|
|
489
678
|
temperature: this.temperature,
|
|
@@ -516,119 +705,83 @@ class ChatAnthropicMessages extends chat_models_1.BaseChatModel {
|
|
|
516
705
|
async *_streamResponseChunks(messages, options, runManager) {
|
|
517
706
|
const params = this.invocationParams(options);
|
|
518
707
|
const formattedMessages = _formatMessagesForAnthropic(messages);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const stream = await this.createStreamWithRetry({
|
|
541
|
-
...params,
|
|
542
|
-
...formattedMessages,
|
|
543
|
-
stream: true,
|
|
708
|
+
const coerceContentToString = !_toolsInParams({
|
|
709
|
+
...params,
|
|
710
|
+
...formattedMessages,
|
|
711
|
+
stream: false,
|
|
712
|
+
});
|
|
713
|
+
const stream = await this.createStreamWithRetry({
|
|
714
|
+
...params,
|
|
715
|
+
...formattedMessages,
|
|
716
|
+
stream: true,
|
|
717
|
+
});
|
|
718
|
+
let usageData = { input_tokens: 0, output_tokens: 0 };
|
|
719
|
+
let concatenatedChunks;
|
|
720
|
+
for await (const data of stream) {
|
|
721
|
+
if (options.signal?.aborted) {
|
|
722
|
+
stream.controller.abort();
|
|
723
|
+
throw new Error("AbortError: User aborted the request.");
|
|
724
|
+
}
|
|
725
|
+
const result = _makeMessageChunkFromAnthropicEvent(data, {
|
|
726
|
+
streamUsage: !!(this.streamUsage || options.streamUsage),
|
|
727
|
+
coerceContentToString,
|
|
728
|
+
usageData,
|
|
544
729
|
});
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
usageData = usage;
|
|
562
|
-
let usageMetadata;
|
|
563
|
-
if (this.streamUsage || options.streamUsage) {
|
|
564
|
-
usageMetadata = {
|
|
565
|
-
input_tokens: usage.input_tokens,
|
|
566
|
-
output_tokens: usage.output_tokens,
|
|
567
|
-
total_tokens: usage.input_tokens + usage.output_tokens,
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
yield new outputs_1.ChatGenerationChunk({
|
|
571
|
-
message: new messages_1.AIMessageChunk({
|
|
572
|
-
content: "",
|
|
573
|
-
additional_kwargs: filteredAdditionalKwargs,
|
|
574
|
-
usage_metadata: usageMetadata,
|
|
575
|
-
}),
|
|
576
|
-
text: "",
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
else if (data.type === "message_delta") {
|
|
580
|
-
let usageMetadata;
|
|
581
|
-
if (this.streamUsage || options.streamUsage) {
|
|
582
|
-
usageMetadata = {
|
|
583
|
-
input_tokens: data.usage.output_tokens,
|
|
584
|
-
output_tokens: 0,
|
|
585
|
-
total_tokens: data.usage.output_tokens,
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
yield new outputs_1.ChatGenerationChunk({
|
|
589
|
-
message: new messages_1.AIMessageChunk({
|
|
590
|
-
content: "",
|
|
591
|
-
additional_kwargs: { ...data.delta },
|
|
592
|
-
usage_metadata: usageMetadata,
|
|
593
|
-
}),
|
|
594
|
-
text: "",
|
|
595
|
-
});
|
|
596
|
-
if (data?.usage !== undefined) {
|
|
597
|
-
usageData.output_tokens += data.usage.output_tokens;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
else if (data.type === "content_block_delta" &&
|
|
601
|
-
data.delta.type === "text_delta") {
|
|
602
|
-
const content = data.delta?.text;
|
|
603
|
-
if (content !== undefined) {
|
|
604
|
-
yield new outputs_1.ChatGenerationChunk({
|
|
605
|
-
message: new messages_1.AIMessageChunk({
|
|
606
|
-
content,
|
|
607
|
-
additional_kwargs: {},
|
|
608
|
-
}),
|
|
609
|
-
text: content,
|
|
610
|
-
});
|
|
611
|
-
await runManager?.handleLLMNewToken(content);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
730
|
+
if (!result)
|
|
731
|
+
continue;
|
|
732
|
+
const { chunk, usageData: updatedUsageData } = result;
|
|
733
|
+
usageData = updatedUsageData;
|
|
734
|
+
const newToolCallChunk = extractToolCallChunk(chunk);
|
|
735
|
+
// Maintain concatenatedChunks for accessing the complete `tool_use` content block.
|
|
736
|
+
concatenatedChunks = concatenatedChunks
|
|
737
|
+
? (0, stream_1.concat)(concatenatedChunks, chunk)
|
|
738
|
+
: chunk;
|
|
739
|
+
let toolUseContent;
|
|
740
|
+
const extractedContent = extractToolUseContent(chunk, concatenatedChunks);
|
|
741
|
+
if (extractedContent) {
|
|
742
|
+
toolUseContent = extractedContent.toolUseContent;
|
|
743
|
+
concatenatedChunks = extractedContent.concatenatedChunks;
|
|
614
744
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
};
|
|
745
|
+
// Filter partial `tool_use` content, and only add `tool_use` chunks if complete JSON available.
|
|
746
|
+
const chunkContent = Array.isArray(chunk.content)
|
|
747
|
+
? chunk.content.filter((c) => c.type !== "tool_use")
|
|
748
|
+
: chunk.content;
|
|
749
|
+
if (Array.isArray(chunkContent) && toolUseContent) {
|
|
750
|
+
chunkContent.push(toolUseContent);
|
|
622
751
|
}
|
|
752
|
+
// Extract the text content token for text field and runManager.
|
|
753
|
+
const token = extractToken(chunk);
|
|
623
754
|
yield new outputs_1.ChatGenerationChunk({
|
|
624
755
|
message: new messages_1.AIMessageChunk({
|
|
625
|
-
content:
|
|
626
|
-
additional_kwargs:
|
|
627
|
-
|
|
756
|
+
content: chunkContent,
|
|
757
|
+
additional_kwargs: chunk.additional_kwargs,
|
|
758
|
+
tool_call_chunks: newToolCallChunk ? [newToolCallChunk] : undefined,
|
|
759
|
+
usage_metadata: chunk.usage_metadata,
|
|
760
|
+
response_metadata: chunk.response_metadata,
|
|
761
|
+
id: chunk.id,
|
|
628
762
|
}),
|
|
629
|
-
text: "",
|
|
763
|
+
text: token ?? "",
|
|
630
764
|
});
|
|
765
|
+
if (token) {
|
|
766
|
+
await runManager?.handleLLMNewToken(token);
|
|
767
|
+
}
|
|
631
768
|
}
|
|
769
|
+
let usageMetadata;
|
|
770
|
+
if (this.streamUsage || options.streamUsage) {
|
|
771
|
+
usageMetadata = {
|
|
772
|
+
input_tokens: usageData.input_tokens,
|
|
773
|
+
output_tokens: usageData.output_tokens,
|
|
774
|
+
total_tokens: usageData.input_tokens + usageData.output_tokens,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
yield new outputs_1.ChatGenerationChunk({
|
|
778
|
+
message: new messages_1.AIMessageChunk({
|
|
779
|
+
content: coerceContentToString ? "" : [],
|
|
780
|
+
additional_kwargs: { usage: usageData },
|
|
781
|
+
usage_metadata: usageMetadata,
|
|
782
|
+
}),
|
|
783
|
+
text: "",
|
|
784
|
+
});
|
|
632
785
|
}
|
|
633
786
|
/** @ignore */
|
|
634
787
|
async _generateNonStreaming(messages, params, requestOptions) {
|
package/dist/chat_models.d.ts
CHANGED
|
@@ -3,24 +3,21 @@ import type { Stream } from "@anthropic-ai/sdk/streaming";
|
|
|
3
3
|
import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
|
|
4
4
|
import { AIMessageChunk, type BaseMessage } from "@langchain/core/messages";
|
|
5
5
|
import { ChatGeneration, ChatGenerationChunk, type ChatResult } from "@langchain/core/outputs";
|
|
6
|
-
import { BaseChatModel, LangSmithParams, type BaseChatModelParams } from "@langchain/core/language_models/chat_models";
|
|
7
|
-
import { type StructuredOutputMethodOptions, type
|
|
6
|
+
import { BaseChatModel, BaseChatModelCallOptions, LangSmithParams, type BaseChatModelParams } from "@langchain/core/language_models/chat_models";
|
|
7
|
+
import { type StructuredOutputMethodOptions, type BaseLanguageModelInput, type ToolDefinition } from "@langchain/core/language_models/base";
|
|
8
8
|
import { StructuredToolInterface } from "@langchain/core/tools";
|
|
9
|
-
import { Runnable } from "@langchain/core/runnables";
|
|
9
|
+
import { Runnable, RunnableToolLike } from "@langchain/core/runnables";
|
|
10
10
|
import { ToolCall } from "@langchain/core/messages/tool";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import type { Tool as AnthropicTool } from "@anthropic-ai/sdk/resources/index.mjs";
|
|
13
13
|
import { AnthropicToolResponse } from "./types.js";
|
|
14
|
+
import { AnthropicToolChoice, AnthropicToolTypes } from "./utils.js";
|
|
14
15
|
type AnthropicMessageCreateParams = Anthropic.MessageCreateParamsNonStreaming;
|
|
15
16
|
type AnthropicStreamingMessageCreateParams = Anthropic.MessageCreateParamsStreaming;
|
|
16
17
|
type AnthropicMessageStreamEvent = Anthropic.MessageStreamEvent;
|
|
17
18
|
type AnthropicRequestOptions = Anthropic.RequestOptions;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
name: string;
|
|
21
|
-
} | "any" | "auto";
|
|
22
|
-
export interface ChatAnthropicCallOptions extends BaseLanguageModelCallOptions, Pick<AnthropicInput, "streamUsage"> {
|
|
23
|
-
tools?: (StructuredToolInterface | AnthropicTool | Record<string, unknown> | ToolDefinition)[];
|
|
19
|
+
export interface ChatAnthropicCallOptions extends BaseChatModelCallOptions, Pick<AnthropicInput, "streamUsage"> {
|
|
20
|
+
tools?: AnthropicToolTypes[];
|
|
24
21
|
/**
|
|
25
22
|
* Whether or not to specify what tool the model should use
|
|
26
23
|
* @default "auto"
|
|
@@ -150,7 +147,7 @@ export declare class ChatAnthropicMessages<CallOptions extends ChatAnthropicCall
|
|
|
150
147
|
* @throws {Error} If a mix of AnthropicTools and StructuredTools are passed.
|
|
151
148
|
*/
|
|
152
149
|
formatStructuredToolToAnthropic(tools: ChatAnthropicCallOptions["tools"]): AnthropicTool[] | undefined;
|
|
153
|
-
bindTools(tools: (AnthropicTool | Record<string, unknown> | StructuredToolInterface | ToolDefinition)[], kwargs?: Partial<CallOptions>): Runnable<BaseLanguageModelInput, AIMessageChunk, CallOptions>;
|
|
150
|
+
bindTools(tools: (AnthropicTool | Record<string, unknown> | StructuredToolInterface | ToolDefinition | RunnableToolLike)[], kwargs?: Partial<CallOptions>): Runnable<BaseLanguageModelInput, AIMessageChunk, CallOptions>;
|
|
154
151
|
/**
|
|
155
152
|
* Get the parameters used to invoke the model
|
|
156
153
|
*/
|
|
@@ -163,8 +160,8 @@ export declare class ChatAnthropicMessages<CallOptions extends ChatAnthropicCall
|
|
|
163
160
|
temperature?: number | undefined;
|
|
164
161
|
model: "claude-2.1" | (string & {}) | "claude-3-opus-20240229" | "claude-3-sonnet-20240229" | "claude-3-haiku-20240307" | "claude-2.0" | "claude-instant-1.2";
|
|
165
162
|
system?: string | undefined;
|
|
166
|
-
stream?: boolean | undefined;
|
|
167
163
|
max_tokens: number;
|
|
164
|
+
stream?: boolean | undefined;
|
|
168
165
|
stop_sequences?: string[] | undefined;
|
|
169
166
|
top_k?: number | undefined;
|
|
170
167
|
top_p?: number | undefined;
|
|
@@ -180,8 +177,8 @@ export declare class ChatAnthropicMessages<CallOptions extends ChatAnthropicCall
|
|
|
180
177
|
temperature?: number | undefined;
|
|
181
178
|
model: "claude-2.1" | (string & {}) | "claude-3-opus-20240229" | "claude-3-sonnet-20240229" | "claude-3-haiku-20240307" | "claude-2.0" | "claude-instant-1.2";
|
|
182
179
|
system?: string | undefined;
|
|
183
|
-
stream?: boolean | undefined;
|
|
184
180
|
max_tokens: number;
|
|
181
|
+
stream?: boolean | undefined;
|
|
185
182
|
stop_sequences?: string[] | undefined;
|
|
186
183
|
top_k?: number | undefined;
|
|
187
184
|
top_p?: number | undefined;
|
|
@@ -194,7 +191,7 @@ export declare class ChatAnthropicMessages<CallOptions extends ChatAnthropicCall
|
|
|
194
191
|
llmOutput: {
|
|
195
192
|
id: string;
|
|
196
193
|
model: string;
|
|
197
|
-
stop_reason: "tool_use" | "
|
|
194
|
+
stop_reason: "tool_use" | "stop_sequence" | "end_turn" | "max_tokens" | null;
|
|
198
195
|
stop_sequence: string | null;
|
|
199
196
|
usage: Anthropic.Messages.Usage;
|
|
200
197
|
};
|
package/dist/chat_models.js
CHANGED
|
@@ -7,7 +7,12 @@ import { isOpenAITool, } from "@langchain/core/language_models/base";
|
|
|
7
7
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
8
8
|
import { RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnables";
|
|
9
9
|
import { isZodSchema } from "@langchain/core/utils/types";
|
|
10
|
+
import { concat } from "@langchain/core/utils/stream";
|
|
10
11
|
import { AnthropicToolsOutputParser, extractToolCalls, } from "./output_parsers.js";
|
|
12
|
+
import { handleToolChoice, } from "./utils.js";
|
|
13
|
+
function _toolsInParams(params) {
|
|
14
|
+
return !!(params.tools && params.tools.length > 0);
|
|
15
|
+
}
|
|
11
16
|
function _formatImage(imageUrl) {
|
|
12
17
|
const regex = /^data:(image\/.+);base64,(.+)$/;
|
|
13
18
|
const match = imageUrl.match(regex);
|
|
@@ -41,6 +46,8 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
|
|
|
41
46
|
content: messages[0].text,
|
|
42
47
|
additional_kwargs: additionalKwargs,
|
|
43
48
|
usage_metadata: usageMetadata,
|
|
49
|
+
response_metadata: additionalKwargs,
|
|
50
|
+
id: additionalKwargs.id,
|
|
44
51
|
}),
|
|
45
52
|
},
|
|
46
53
|
];
|
|
@@ -56,6 +63,8 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
|
|
|
56
63
|
additional_kwargs: additionalKwargs,
|
|
57
64
|
tool_calls: toolCalls,
|
|
58
65
|
usage_metadata: usageMetadata,
|
|
66
|
+
response_metadata: additionalKwargs,
|
|
67
|
+
id: additionalKwargs.id,
|
|
59
68
|
}),
|
|
60
69
|
},
|
|
61
70
|
];
|
|
@@ -66,6 +75,117 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
|
|
|
66
75
|
function isAnthropicTool(tool) {
|
|
67
76
|
return "input_schema" in tool;
|
|
68
77
|
}
|
|
78
|
+
function _makeMessageChunkFromAnthropicEvent(data, fields) {
|
|
79
|
+
let usageDataCopy = { ...fields.usageData };
|
|
80
|
+
if (data.type === "message_start") {
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
82
|
+
const { content, usage, ...additionalKwargs } = data.message;
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
+
const filteredAdditionalKwargs = {};
|
|
85
|
+
for (const [key, value] of Object.entries(additionalKwargs)) {
|
|
86
|
+
if (value !== undefined && value !== null) {
|
|
87
|
+
filteredAdditionalKwargs[key] = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
usageDataCopy = usage;
|
|
91
|
+
let usageMetadata;
|
|
92
|
+
if (fields.streamUsage) {
|
|
93
|
+
usageMetadata = {
|
|
94
|
+
input_tokens: usage.input_tokens,
|
|
95
|
+
output_tokens: usage.output_tokens,
|
|
96
|
+
total_tokens: usage.input_tokens + usage.output_tokens,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
console.log("data.message", data.message);
|
|
100
|
+
return {
|
|
101
|
+
chunk: new AIMessageChunk({
|
|
102
|
+
content: fields.coerceContentToString ? "" : [],
|
|
103
|
+
additional_kwargs: filteredAdditionalKwargs,
|
|
104
|
+
usage_metadata: usageMetadata,
|
|
105
|
+
id: data.message.id,
|
|
106
|
+
}),
|
|
107
|
+
usageData: usageDataCopy,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
else if (data.type === "message_delta") {
|
|
111
|
+
let usageMetadata;
|
|
112
|
+
if (fields.streamUsage) {
|
|
113
|
+
usageMetadata = {
|
|
114
|
+
input_tokens: data.usage.output_tokens,
|
|
115
|
+
output_tokens: 0,
|
|
116
|
+
total_tokens: data.usage.output_tokens,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (data?.usage !== undefined) {
|
|
120
|
+
usageDataCopy.output_tokens += data.usage.output_tokens;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
chunk: new AIMessageChunk({
|
|
124
|
+
content: fields.coerceContentToString ? "" : [],
|
|
125
|
+
additional_kwargs: { ...data.delta },
|
|
126
|
+
usage_metadata: usageMetadata,
|
|
127
|
+
}),
|
|
128
|
+
usageData: usageDataCopy,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
else if (data.type === "content_block_start" &&
|
|
132
|
+
data.content_block.type === "tool_use") {
|
|
133
|
+
return {
|
|
134
|
+
chunk: new AIMessageChunk({
|
|
135
|
+
content: fields.coerceContentToString
|
|
136
|
+
? ""
|
|
137
|
+
: [
|
|
138
|
+
{
|
|
139
|
+
index: data.index,
|
|
140
|
+
...data.content_block,
|
|
141
|
+
input: "",
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
additional_kwargs: {},
|
|
145
|
+
}),
|
|
146
|
+
usageData: usageDataCopy,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
else if (data.type === "content_block_delta" &&
|
|
150
|
+
data.delta.type === "text_delta") {
|
|
151
|
+
const content = data.delta?.text;
|
|
152
|
+
if (content !== undefined) {
|
|
153
|
+
return {
|
|
154
|
+
chunk: new AIMessageChunk({
|
|
155
|
+
content: fields.coerceContentToString
|
|
156
|
+
? content
|
|
157
|
+
: [
|
|
158
|
+
{
|
|
159
|
+
index: data.index,
|
|
160
|
+
...data.delta,
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
additional_kwargs: {},
|
|
164
|
+
}),
|
|
165
|
+
usageData: usageDataCopy,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (data.type === "content_block_delta" &&
|
|
170
|
+
data.delta.type === "input_json_delta") {
|
|
171
|
+
return {
|
|
172
|
+
chunk: new AIMessageChunk({
|
|
173
|
+
content: fields.coerceContentToString
|
|
174
|
+
? ""
|
|
175
|
+
: [
|
|
176
|
+
{
|
|
177
|
+
index: data.index,
|
|
178
|
+
input: data.delta.partial_json,
|
|
179
|
+
type: data.delta.type,
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
additional_kwargs: {},
|
|
183
|
+
}),
|
|
184
|
+
usageData: usageDataCopy,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
69
189
|
function _mergeMessages(messages) {
|
|
70
190
|
// Merge runs of human/tool messages into single human messages with content blocks.
|
|
71
191
|
const merged = [];
|
|
@@ -239,6 +359,90 @@ function _formatMessagesForAnthropic(messages) {
|
|
|
239
359
|
system,
|
|
240
360
|
};
|
|
241
361
|
}
|
|
362
|
+
function extractToolCallChunk(chunk) {
|
|
363
|
+
let newToolCallChunk;
|
|
364
|
+
// Initial chunk for tool calls from anthropic contains identifying information like ID and name.
|
|
365
|
+
// This chunk does not contain any input JSON.
|
|
366
|
+
const toolUseChunks = Array.isArray(chunk.content)
|
|
367
|
+
? chunk.content.find((c) => c.type === "tool_use")
|
|
368
|
+
: undefined;
|
|
369
|
+
if (toolUseChunks &&
|
|
370
|
+
"index" in toolUseChunks &&
|
|
371
|
+
"name" in toolUseChunks &&
|
|
372
|
+
"id" in toolUseChunks) {
|
|
373
|
+
newToolCallChunk = {
|
|
374
|
+
args: "",
|
|
375
|
+
id: toolUseChunks.id,
|
|
376
|
+
name: toolUseChunks.name,
|
|
377
|
+
index: toolUseChunks.index,
|
|
378
|
+
type: "tool_call_chunk",
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
// Chunks after the initial chunk only contain the index and partial JSON.
|
|
382
|
+
const inputJsonDeltaChunks = Array.isArray(chunk.content)
|
|
383
|
+
? chunk.content.find((c) => c.type === "input_json_delta")
|
|
384
|
+
: undefined;
|
|
385
|
+
if (inputJsonDeltaChunks &&
|
|
386
|
+
"index" in inputJsonDeltaChunks &&
|
|
387
|
+
"input" in inputJsonDeltaChunks) {
|
|
388
|
+
if (typeof inputJsonDeltaChunks.input === "string") {
|
|
389
|
+
newToolCallChunk = {
|
|
390
|
+
args: inputJsonDeltaChunks.input,
|
|
391
|
+
index: inputJsonDeltaChunks.index,
|
|
392
|
+
type: "tool_call_chunk",
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
newToolCallChunk = {
|
|
397
|
+
args: JSON.stringify(inputJsonDeltaChunks.input, null, 2),
|
|
398
|
+
index: inputJsonDeltaChunks.index,
|
|
399
|
+
type: "tool_call_chunk",
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return newToolCallChunk;
|
|
404
|
+
}
|
|
405
|
+
function extractToken(chunk) {
|
|
406
|
+
return typeof chunk.content === "string" && chunk.content !== ""
|
|
407
|
+
? chunk.content
|
|
408
|
+
: undefined;
|
|
409
|
+
}
|
|
410
|
+
function extractToolUseContent(chunk, concatenatedChunks) {
|
|
411
|
+
let newConcatenatedChunks = concatenatedChunks;
|
|
412
|
+
// Remove `tool_use` content types until the last chunk.
|
|
413
|
+
let toolUseContent;
|
|
414
|
+
if (!newConcatenatedChunks) {
|
|
415
|
+
newConcatenatedChunks = chunk;
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
newConcatenatedChunks = concat(newConcatenatedChunks, chunk);
|
|
419
|
+
}
|
|
420
|
+
if (Array.isArray(newConcatenatedChunks.content) &&
|
|
421
|
+
newConcatenatedChunks.content.find((c) => c.type === "tool_use")) {
|
|
422
|
+
try {
|
|
423
|
+
const toolUseMsg = newConcatenatedChunks.content.find((c) => c.type === "tool_use");
|
|
424
|
+
if (!toolUseMsg ||
|
|
425
|
+
!("input" in toolUseMsg || "name" in toolUseMsg || "id" in toolUseMsg))
|
|
426
|
+
return;
|
|
427
|
+
const parsedArgs = JSON.parse(toolUseMsg.input);
|
|
428
|
+
if (parsedArgs) {
|
|
429
|
+
toolUseContent = {
|
|
430
|
+
type: "tool_use",
|
|
431
|
+
id: toolUseMsg.id,
|
|
432
|
+
name: toolUseMsg.name,
|
|
433
|
+
input: parsedArgs,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch (_) {
|
|
438
|
+
// no-op
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return {
|
|
442
|
+
toolUseContent,
|
|
443
|
+
concatenatedChunks: newConcatenatedChunks,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
242
446
|
/**
|
|
243
447
|
* Wrapper around Anthropic large language models.
|
|
244
448
|
*
|
|
@@ -464,22 +668,7 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
464
668
|
* Get the parameters used to invoke the model
|
|
465
669
|
*/
|
|
466
670
|
invocationParams(options) {
|
|
467
|
-
|
|
468
|
-
if (options?.tool_choice) {
|
|
469
|
-
if (options?.tool_choice === "any") {
|
|
470
|
-
tool_choice = {
|
|
471
|
-
type: "any",
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
else if (options?.tool_choice === "auto") {
|
|
475
|
-
tool_choice = {
|
|
476
|
-
type: "auto",
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
tool_choice = options?.tool_choice;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
671
|
+
const tool_choice = handleToolChoice(options?.tool_choice);
|
|
483
672
|
return {
|
|
484
673
|
model: this.model,
|
|
485
674
|
temperature: this.temperature,
|
|
@@ -512,119 +701,83 @@ export class ChatAnthropicMessages extends BaseChatModel {
|
|
|
512
701
|
async *_streamResponseChunks(messages, options, runManager) {
|
|
513
702
|
const params = this.invocationParams(options);
|
|
514
703
|
const formattedMessages = _formatMessagesForAnthropic(messages);
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
const stream = await this.createStreamWithRetry({
|
|
537
|
-
...params,
|
|
538
|
-
...formattedMessages,
|
|
539
|
-
stream: true,
|
|
704
|
+
const coerceContentToString = !_toolsInParams({
|
|
705
|
+
...params,
|
|
706
|
+
...formattedMessages,
|
|
707
|
+
stream: false,
|
|
708
|
+
});
|
|
709
|
+
const stream = await this.createStreamWithRetry({
|
|
710
|
+
...params,
|
|
711
|
+
...formattedMessages,
|
|
712
|
+
stream: true,
|
|
713
|
+
});
|
|
714
|
+
let usageData = { input_tokens: 0, output_tokens: 0 };
|
|
715
|
+
let concatenatedChunks;
|
|
716
|
+
for await (const data of stream) {
|
|
717
|
+
if (options.signal?.aborted) {
|
|
718
|
+
stream.controller.abort();
|
|
719
|
+
throw new Error("AbortError: User aborted the request.");
|
|
720
|
+
}
|
|
721
|
+
const result = _makeMessageChunkFromAnthropicEvent(data, {
|
|
722
|
+
streamUsage: !!(this.streamUsage || options.streamUsage),
|
|
723
|
+
coerceContentToString,
|
|
724
|
+
usageData,
|
|
540
725
|
});
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
usageData = usage;
|
|
558
|
-
let usageMetadata;
|
|
559
|
-
if (this.streamUsage || options.streamUsage) {
|
|
560
|
-
usageMetadata = {
|
|
561
|
-
input_tokens: usage.input_tokens,
|
|
562
|
-
output_tokens: usage.output_tokens,
|
|
563
|
-
total_tokens: usage.input_tokens + usage.output_tokens,
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
yield new ChatGenerationChunk({
|
|
567
|
-
message: new AIMessageChunk({
|
|
568
|
-
content: "",
|
|
569
|
-
additional_kwargs: filteredAdditionalKwargs,
|
|
570
|
-
usage_metadata: usageMetadata,
|
|
571
|
-
}),
|
|
572
|
-
text: "",
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
else if (data.type === "message_delta") {
|
|
576
|
-
let usageMetadata;
|
|
577
|
-
if (this.streamUsage || options.streamUsage) {
|
|
578
|
-
usageMetadata = {
|
|
579
|
-
input_tokens: data.usage.output_tokens,
|
|
580
|
-
output_tokens: 0,
|
|
581
|
-
total_tokens: data.usage.output_tokens,
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
yield new ChatGenerationChunk({
|
|
585
|
-
message: new AIMessageChunk({
|
|
586
|
-
content: "",
|
|
587
|
-
additional_kwargs: { ...data.delta },
|
|
588
|
-
usage_metadata: usageMetadata,
|
|
589
|
-
}),
|
|
590
|
-
text: "",
|
|
591
|
-
});
|
|
592
|
-
if (data?.usage !== undefined) {
|
|
593
|
-
usageData.output_tokens += data.usage.output_tokens;
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
else if (data.type === "content_block_delta" &&
|
|
597
|
-
data.delta.type === "text_delta") {
|
|
598
|
-
const content = data.delta?.text;
|
|
599
|
-
if (content !== undefined) {
|
|
600
|
-
yield new ChatGenerationChunk({
|
|
601
|
-
message: new AIMessageChunk({
|
|
602
|
-
content,
|
|
603
|
-
additional_kwargs: {},
|
|
604
|
-
}),
|
|
605
|
-
text: content,
|
|
606
|
-
});
|
|
607
|
-
await runManager?.handleLLMNewToken(content);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
726
|
+
if (!result)
|
|
727
|
+
continue;
|
|
728
|
+
const { chunk, usageData: updatedUsageData } = result;
|
|
729
|
+
usageData = updatedUsageData;
|
|
730
|
+
const newToolCallChunk = extractToolCallChunk(chunk);
|
|
731
|
+
// Maintain concatenatedChunks for accessing the complete `tool_use` content block.
|
|
732
|
+
concatenatedChunks = concatenatedChunks
|
|
733
|
+
? concat(concatenatedChunks, chunk)
|
|
734
|
+
: chunk;
|
|
735
|
+
let toolUseContent;
|
|
736
|
+
const extractedContent = extractToolUseContent(chunk, concatenatedChunks);
|
|
737
|
+
if (extractedContent) {
|
|
738
|
+
toolUseContent = extractedContent.toolUseContent;
|
|
739
|
+
concatenatedChunks = extractedContent.concatenatedChunks;
|
|
610
740
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
};
|
|
741
|
+
// Filter partial `tool_use` content, and only add `tool_use` chunks if complete JSON available.
|
|
742
|
+
const chunkContent = Array.isArray(chunk.content)
|
|
743
|
+
? chunk.content.filter((c) => c.type !== "tool_use")
|
|
744
|
+
: chunk.content;
|
|
745
|
+
if (Array.isArray(chunkContent) && toolUseContent) {
|
|
746
|
+
chunkContent.push(toolUseContent);
|
|
618
747
|
}
|
|
748
|
+
// Extract the text content token for text field and runManager.
|
|
749
|
+
const token = extractToken(chunk);
|
|
619
750
|
yield new ChatGenerationChunk({
|
|
620
751
|
message: new AIMessageChunk({
|
|
621
|
-
content:
|
|
622
|
-
additional_kwargs:
|
|
623
|
-
|
|
752
|
+
content: chunkContent,
|
|
753
|
+
additional_kwargs: chunk.additional_kwargs,
|
|
754
|
+
tool_call_chunks: newToolCallChunk ? [newToolCallChunk] : undefined,
|
|
755
|
+
usage_metadata: chunk.usage_metadata,
|
|
756
|
+
response_metadata: chunk.response_metadata,
|
|
757
|
+
id: chunk.id,
|
|
624
758
|
}),
|
|
625
|
-
text: "",
|
|
759
|
+
text: token ?? "",
|
|
626
760
|
});
|
|
761
|
+
if (token) {
|
|
762
|
+
await runManager?.handleLLMNewToken(token);
|
|
763
|
+
}
|
|
627
764
|
}
|
|
765
|
+
let usageMetadata;
|
|
766
|
+
if (this.streamUsage || options.streamUsage) {
|
|
767
|
+
usageMetadata = {
|
|
768
|
+
input_tokens: usageData.input_tokens,
|
|
769
|
+
output_tokens: usageData.output_tokens,
|
|
770
|
+
total_tokens: usageData.input_tokens + usageData.output_tokens,
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
yield new ChatGenerationChunk({
|
|
774
|
+
message: new AIMessageChunk({
|
|
775
|
+
content: coerceContentToString ? "" : [],
|
|
776
|
+
additional_kwargs: { usage: usageData },
|
|
777
|
+
usage_metadata: usageMetadata,
|
|
778
|
+
}),
|
|
779
|
+
text: "",
|
|
780
|
+
});
|
|
628
781
|
}
|
|
629
782
|
/** @ignore */
|
|
630
783
|
async _generateNonStreaming(messages, params, requestOptions) {
|
package/dist/output_parsers.cjs
CHANGED
|
@@ -79,7 +79,12 @@ function extractToolCalls(content) {
|
|
|
79
79
|
const toolCalls = [];
|
|
80
80
|
for (const block of content) {
|
|
81
81
|
if (block.type === "tool_use") {
|
|
82
|
-
toolCalls.push({
|
|
82
|
+
toolCalls.push({
|
|
83
|
+
name: block.name,
|
|
84
|
+
args: block.input,
|
|
85
|
+
id: block.id,
|
|
86
|
+
type: "tool_call",
|
|
87
|
+
});
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
90
|
return toolCalls;
|
package/dist/output_parsers.js
CHANGED
|
@@ -75,7 +75,12 @@ export function extractToolCalls(content) {
|
|
|
75
75
|
const toolCalls = [];
|
|
76
76
|
for (const block of content) {
|
|
77
77
|
if (block.type === "tool_use") {
|
|
78
|
-
toolCalls.push({
|
|
78
|
+
toolCalls.push({
|
|
79
|
+
name: block.name,
|
|
80
|
+
args: block.input,
|
|
81
|
+
id: block.id,
|
|
82
|
+
type: "tool_call",
|
|
83
|
+
});
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
return toolCalls;
|
package/dist/utils.cjs
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleToolChoice = void 0;
|
|
4
|
+
function handleToolChoice(toolChoice) {
|
|
5
|
+
if (!toolChoice) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
else if (toolChoice === "any") {
|
|
9
|
+
return {
|
|
10
|
+
type: "any",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
else if (toolChoice === "auto") {
|
|
14
|
+
return {
|
|
15
|
+
type: "auto",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
else if (typeof toolChoice === "string") {
|
|
19
|
+
return {
|
|
20
|
+
type: "tool",
|
|
21
|
+
name: toolChoice,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return toolChoice;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.handleToolChoice = handleToolChoice;
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MessageCreateParams, Tool as AnthropicTool } from "@anthropic-ai/sdk/resources/index.mjs";
|
|
2
|
+
import { ToolDefinition } from "@langchain/core/language_models/base";
|
|
3
|
+
import { RunnableToolLike } from "@langchain/core/runnables";
|
|
4
|
+
import { StructuredToolInterface } from "@langchain/core/tools";
|
|
5
|
+
export type AnthropicToolChoice = {
|
|
6
|
+
type: "tool";
|
|
7
|
+
name: string;
|
|
8
|
+
} | "any" | "auto" | "none" | string;
|
|
9
|
+
export type AnthropicToolTypes = StructuredToolInterface | AnthropicTool | Record<string, unknown> | ToolDefinition | RunnableToolLike;
|
|
10
|
+
export declare function handleToolChoice(toolChoice?: AnthropicToolChoice): MessageCreateParams.ToolChoiceAuto | MessageCreateParams.ToolChoiceAny | MessageCreateParams.ToolChoiceTool | undefined;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function handleToolChoice(toolChoice) {
|
|
2
|
+
if (!toolChoice) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
else if (toolChoice === "any") {
|
|
6
|
+
return {
|
|
7
|
+
type: "any",
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
else if (toolChoice === "auto") {
|
|
11
|
+
return {
|
|
12
|
+
type: "auto",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
else if (typeof toolChoice === "string") {
|
|
16
|
+
return {
|
|
17
|
+
type: "tool",
|
|
18
|
+
name: toolChoice,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return toolChoice;
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/anthropic",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Anthropic integrations for LangChain.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@anthropic-ai/sdk": "^0.22.0",
|
|
39
|
-
"@langchain/core": ">=0.2.
|
|
39
|
+
"@langchain/core": ">=0.2.16 <0.3.0",
|
|
40
40
|
"fast-xml-parser": "^4.3.5",
|
|
41
41
|
"zod": "^3.22.4",
|
|
42
42
|
"zod-to-json-schema": "^3.22.4"
|