@langchain/anthropic 0.1.6 → 0.1.7

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.
@@ -262,3 +262,17 @@ test("Test ChatAnthropic withStructuredOutput on a single array item", async ()
262
262
  tone: "positive",
263
263
  });
264
264
  });
265
+ test("Test ChatAnthropicTools", async () => {
266
+ const chat = new ChatAnthropicTools({
267
+ modelName: "claude-3-sonnet-20240229",
268
+ maxRetries: 0,
269
+ });
270
+ const structured = chat.withStructuredOutput(z.object({
271
+ nested: z.array(z.number()),
272
+ }), { force: false });
273
+ const res = await structured.invoke("What are the first five natural numbers?");
274
+ console.log(res);
275
+ expect(res).toEqual({
276
+ nested: [1, 2, 3, 4, 5],
277
+ });
278
+ });
@@ -18,6 +18,9 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
18
18
  return "ChatAnthropicTools";
19
19
  }
20
20
  constructor(fields) {
21
+ if (fields?.cache !== undefined) {
22
+ throw new Error("Caching is not supported for this model.");
23
+ }
21
24
  super(fields ?? {});
22
25
  Object.defineProperty(this, "llm", {
23
26
  enumerable: true,
@@ -59,7 +62,7 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
59
62
  async *_streamResponseChunks(messages, options, runManager) {
60
63
  yield* this.llm._streamResponseChunks(messages, options, runManager);
61
64
  }
62
- async _prepareAndParseToolCall({ messages, options, runManager, systemPromptTemplate = tool_calling_js_1.DEFAULT_TOOL_SYSTEM_PROMPT, stopSequences, }) {
65
+ async _prepareAndParseToolCall({ messages, options, systemPromptTemplate = tool_calling_js_1.DEFAULT_TOOL_SYSTEM_PROMPT, stopSequences, }) {
63
66
  let promptMessages = messages;
64
67
  let forced = false;
65
68
  let toolCall;
@@ -105,8 +108,10 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
105
108
  else if (options.tool_choice !== undefined) {
106
109
  throw new Error(`If "tool_choice" is provided, "tools" must also be.`);
107
110
  }
108
- const chatResult = await this.llm._generate(promptMessages, options, runManager);
109
- const chatGenerationContent = chatResult.generations[0].message.content;
111
+ const chatResult = await this.llm
112
+ .withConfig({ runName: "ChatAnthropicTools" })
113
+ .invoke(promptMessages, options);
114
+ const chatGenerationContent = chatResult.content;
110
115
  if (typeof chatGenerationContent !== "string") {
111
116
  throw new Error("AnthropicFunctions does not support non-string output.");
112
117
  }
@@ -171,15 +176,25 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
171
176
  generations: [{ message: responseMessageWithFunctions, text: "" }],
172
177
  };
173
178
  }
174
- return chatResult;
179
+ return { generations: [{ message: chatResult, text: "" }] };
175
180
  }
176
- async _generate(messages, options, _runManager) {
177
- return this._prepareAndParseToolCall({
178
- messages,
179
- options,
181
+ async generate(messages, parsedOptions, callbacks) {
182
+ const baseMessages = messages.map((messageList) => messageList.map(messages_1.coerceMessageLikeToMessage));
183
+ // generate results
184
+ const chatResults = await Promise.all(baseMessages.map((messageList) => this._prepareAndParseToolCall({
185
+ messages: messageList,
186
+ options: { callbacks, ...parsedOptions },
180
187
  systemPromptTemplate: this.systemPromptTemplate,
181
188
  stopSequences: this.stopSequences ?? [],
182
- });
189
+ })));
190
+ // create combined output
191
+ const output = {
192
+ generations: chatResults.map((chatResult) => chatResult.generations),
193
+ };
194
+ return output;
195
+ }
196
+ async _generate(_messages, _options, _runManager) {
197
+ throw new Error("Unused.");
183
198
  }
184
199
  _llmType() {
185
200
  return "anthropic_tool_calling";
@@ -190,6 +205,7 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
190
205
  let name;
191
206
  let method;
192
207
  let includeRaw;
208
+ let force;
193
209
  if (isStructuredOutputMethodParams(outputSchema)) {
194
210
  schema = outputSchema.schema;
195
211
  name = outputSchema.name;
@@ -201,6 +217,7 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
201
217
  name = config?.name;
202
218
  method = config?.method;
203
219
  includeRaw = config?.includeRaw;
220
+ force = config?.force ?? true;
204
221
  }
205
222
  if (method === "jsonMode") {
206
223
  throw new Error(`Anthropic only supports "functionCalling" as a method.`);
@@ -244,12 +261,14 @@ class ChatAnthropicTools extends chat_models_1.BaseChatModel {
244
261
  }
245
262
  const llm = this.bind({
246
263
  tools,
247
- tool_choice: {
248
- type: "function",
249
- function: {
250
- name: functionName,
251
- },
252
- },
264
+ tool_choice: force
265
+ ? {
266
+ type: "function",
267
+ function: {
268
+ name: functionName,
269
+ },
270
+ }
271
+ : "auto",
253
272
  });
254
273
  if (!includeRaw) {
255
274
  return llm.pipe(outputParser).withConfig({
@@ -1,7 +1,7 @@
1
- import { BaseMessage } from "@langchain/core/messages";
2
- import { ChatGenerationChunk, ChatResult } from "@langchain/core/outputs";
1
+ import { BaseMessage, BaseMessageLike } from "@langchain/core/messages";
2
+ import type { ChatGenerationChunk, ChatResult, LLMResult } from "@langchain/core/outputs";
3
3
  import { BaseChatModel, BaseChatModelParams } from "@langchain/core/language_models/chat_models";
4
- import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
4
+ import { CallbackManagerForLLMRun, Callbacks } from "@langchain/core/callbacks/manager";
5
5
  import { BasePromptTemplate } from "@langchain/core/prompts";
6
6
  import { BaseLanguageModelCallOptions, BaseLanguageModelInput, StructuredOutputMethodParams, StructuredOutputMethodOptions, ToolDefinition } from "@langchain/core/language_models/base";
7
7
  import { Runnable } from "@langchain/core/runnables";
@@ -35,17 +35,21 @@ export declare class ChatAnthropicTools extends BaseChatModel<ChatAnthropicTools
35
35
  /** @ignore */
36
36
  _identifyingParams(): Record<string, any>;
37
37
  _streamResponseChunks(messages: BaseMessage[], options: this["ParsedCallOptions"], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
38
- _prepareAndParseToolCall({ messages, options, runManager, systemPromptTemplate, stopSequences, }: {
38
+ _prepareAndParseToolCall({ messages, options, systemPromptTemplate, stopSequences, }: {
39
39
  messages: BaseMessage[];
40
40
  options: ChatAnthropicToolsCallOptions;
41
- runManager?: CallbackManagerForLLMRun;
42
41
  systemPromptTemplate?: BasePromptTemplate;
43
42
  stopSequences: string[];
44
43
  }): Promise<ChatResult>;
45
- _generate(messages: BaseMessage[], options: this["ParsedCallOptions"], _runManager?: CallbackManagerForLLMRun | undefined): Promise<ChatResult>;
44
+ generate(messages: BaseMessageLike[][], parsedOptions?: ChatAnthropicToolsCallOptions, callbacks?: Callbacks): Promise<LLMResult>;
45
+ _generate(_messages: BaseMessage[], _options: this["ParsedCallOptions"], _runManager?: CallbackManagerForLLMRun | undefined): Promise<ChatResult>;
46
46
  _llmType(): string;
47
- withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: StructuredOutputMethodParams<RunOutput, false> | z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<false>): Runnable<BaseLanguageModelInput, RunOutput>;
48
- withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: StructuredOutputMethodParams<RunOutput, true> | z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<true>): Runnable<BaseLanguageModelInput, {
47
+ withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: StructuredOutputMethodParams<RunOutput, false> | z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<false> & {
48
+ force?: boolean;
49
+ }): Runnable<BaseLanguageModelInput, RunOutput>;
50
+ withStructuredOutput<RunOutput extends Record<string, any> = Record<string, any>>(outputSchema: StructuredOutputMethodParams<RunOutput, true> | z.ZodType<RunOutput> | Record<string, any>, config?: StructuredOutputMethodOptions<true> & {
51
+ force?: boolean;
52
+ }): Runnable<BaseLanguageModelInput, {
49
53
  raw: BaseMessage;
50
54
  parsed: RunOutput;
51
55
  }>;
@@ -1,5 +1,5 @@
1
1
  import { XMLParser } from "fast-xml-parser";
2
- import { AIMessage, SystemMessage, } from "@langchain/core/messages";
2
+ import { AIMessage, SystemMessage, coerceMessageLikeToMessage, } from "@langchain/core/messages";
3
3
  import { BaseChatModel, } from "@langchain/core/language_models/chat_models";
4
4
  import { RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnables";
5
5
  import { JsonOutputKeyToolsParser } from "@langchain/core/output_parsers/openai_tools";
@@ -15,6 +15,9 @@ export class ChatAnthropicTools extends BaseChatModel {
15
15
  return "ChatAnthropicTools";
16
16
  }
17
17
  constructor(fields) {
18
+ if (fields?.cache !== undefined) {
19
+ throw new Error("Caching is not supported for this model.");
20
+ }
18
21
  super(fields ?? {});
19
22
  Object.defineProperty(this, "llm", {
20
23
  enumerable: true,
@@ -56,7 +59,7 @@ export class ChatAnthropicTools extends BaseChatModel {
56
59
  async *_streamResponseChunks(messages, options, runManager) {
57
60
  yield* this.llm._streamResponseChunks(messages, options, runManager);
58
61
  }
59
- async _prepareAndParseToolCall({ messages, options, runManager, systemPromptTemplate = DEFAULT_TOOL_SYSTEM_PROMPT, stopSequences, }) {
62
+ async _prepareAndParseToolCall({ messages, options, systemPromptTemplate = DEFAULT_TOOL_SYSTEM_PROMPT, stopSequences, }) {
60
63
  let promptMessages = messages;
61
64
  let forced = false;
62
65
  let toolCall;
@@ -102,8 +105,10 @@ export class ChatAnthropicTools extends BaseChatModel {
102
105
  else if (options.tool_choice !== undefined) {
103
106
  throw new Error(`If "tool_choice" is provided, "tools" must also be.`);
104
107
  }
105
- const chatResult = await this.llm._generate(promptMessages, options, runManager);
106
- const chatGenerationContent = chatResult.generations[0].message.content;
108
+ const chatResult = await this.llm
109
+ .withConfig({ runName: "ChatAnthropicTools" })
110
+ .invoke(promptMessages, options);
111
+ const chatGenerationContent = chatResult.content;
107
112
  if (typeof chatGenerationContent !== "string") {
108
113
  throw new Error("AnthropicFunctions does not support non-string output.");
109
114
  }
@@ -168,15 +173,25 @@ export class ChatAnthropicTools extends BaseChatModel {
168
173
  generations: [{ message: responseMessageWithFunctions, text: "" }],
169
174
  };
170
175
  }
171
- return chatResult;
176
+ return { generations: [{ message: chatResult, text: "" }] };
172
177
  }
173
- async _generate(messages, options, _runManager) {
174
- return this._prepareAndParseToolCall({
175
- messages,
176
- options,
178
+ async generate(messages, parsedOptions, callbacks) {
179
+ const baseMessages = messages.map((messageList) => messageList.map(coerceMessageLikeToMessage));
180
+ // generate results
181
+ const chatResults = await Promise.all(baseMessages.map((messageList) => this._prepareAndParseToolCall({
182
+ messages: messageList,
183
+ options: { callbacks, ...parsedOptions },
177
184
  systemPromptTemplate: this.systemPromptTemplate,
178
185
  stopSequences: this.stopSequences ?? [],
179
- });
186
+ })));
187
+ // create combined output
188
+ const output = {
189
+ generations: chatResults.map((chatResult) => chatResult.generations),
190
+ };
191
+ return output;
192
+ }
193
+ async _generate(_messages, _options, _runManager) {
194
+ throw new Error("Unused.");
180
195
  }
181
196
  _llmType() {
182
197
  return "anthropic_tool_calling";
@@ -187,6 +202,7 @@ export class ChatAnthropicTools extends BaseChatModel {
187
202
  let name;
188
203
  let method;
189
204
  let includeRaw;
205
+ let force;
190
206
  if (isStructuredOutputMethodParams(outputSchema)) {
191
207
  schema = outputSchema.schema;
192
208
  name = outputSchema.name;
@@ -198,6 +214,7 @@ export class ChatAnthropicTools extends BaseChatModel {
198
214
  name = config?.name;
199
215
  method = config?.method;
200
216
  includeRaw = config?.includeRaw;
217
+ force = config?.force ?? true;
201
218
  }
202
219
  if (method === "jsonMode") {
203
220
  throw new Error(`Anthropic only supports "functionCalling" as a method.`);
@@ -241,12 +258,14 @@ export class ChatAnthropicTools extends BaseChatModel {
241
258
  }
242
259
  const llm = this.bind({
243
260
  tools,
244
- tool_choice: {
245
- type: "function",
246
- function: {
247
- name: functionName,
248
- },
249
- },
261
+ tool_choice: force
262
+ ? {
263
+ type: "function",
264
+ function: {
265
+ name: functionName,
266
+ },
267
+ }
268
+ : "auto",
250
269
  });
251
270
  if (!includeRaw) {
252
271
  return llm.pipe(outputParser).withConfig({
@@ -62,9 +62,21 @@ xmlParameters
62
62
  const schemaType = schema.properties[key].type;
63
63
  // Crawl for lists indistinguishable from single items
64
64
  if (schema.properties && schema.properties[key] && schemaType === "array") {
65
- fixedParameters[key] = Array.isArray(xmlParameters[key])
66
- ? xmlParameters[key]
67
- : [xmlParameters[key]];
65
+ const value = xmlParameters[key];
66
+ if (Array.isArray(value)) {
67
+ fixedParameters[key] = value;
68
+ }
69
+ else if (typeof value === "string") {
70
+ if (value.startsWith("[") && value.endsWith("]")) {
71
+ fixedParameters[key] = JSON.parse(value);
72
+ }
73
+ else {
74
+ fixedParameters[key] = value.split(",");
75
+ }
76
+ }
77
+ else {
78
+ fixedParameters[key] = [value];
79
+ }
68
80
  // Crawl for objects like {"item": "my string"} that should really just be "my string"
69
81
  if (schemaType !== "object" &&
70
82
  typeof xmlParameters[key] === "object" &&
@@ -58,9 +58,21 @@ xmlParameters
58
58
  const schemaType = schema.properties[key].type;
59
59
  // Crawl for lists indistinguishable from single items
60
60
  if (schema.properties && schema.properties[key] && schemaType === "array") {
61
- fixedParameters[key] = Array.isArray(xmlParameters[key])
62
- ? xmlParameters[key]
63
- : [xmlParameters[key]];
61
+ const value = xmlParameters[key];
62
+ if (Array.isArray(value)) {
63
+ fixedParameters[key] = value;
64
+ }
65
+ else if (typeof value === "string") {
66
+ if (value.startsWith("[") && value.endsWith("]")) {
67
+ fixedParameters[key] = JSON.parse(value);
68
+ }
69
+ else {
70
+ fixedParameters[key] = value.split(",");
71
+ }
72
+ }
73
+ else {
74
+ fixedParameters[key] = [value];
75
+ }
64
76
  // Crawl for objects like {"item": "my string"} that should really just be "my string"
65
77
  if (schemaType !== "object" &&
66
78
  typeof xmlParameters[key] === "object" &&
@@ -95,7 +95,7 @@ test("Test ChatAnthropic in streaming mode", async () => {
95
95
  }),
96
96
  });
97
97
  const message = new HumanMessage("Hello!");
98
- const res = await model.call([message]);
98
+ const res = await model.invoke([message]);
99
99
  console.log({ res });
100
100
  expect(nrNewTokens > 0).toBe(true);
101
101
  expect(res.content).toBe(streamedCompletion);
@@ -117,7 +117,7 @@ test("Test ChatAnthropic in streaming mode with a signal", async () => {
117
117
  const controller = new AbortController();
118
118
  const message = new HumanMessage("Hello! Give me an extremely verbose response");
119
119
  await expect(() => {
120
- const res = model.call([message], {
120
+ const res = model.invoke([message], {
121
121
  signal: controller.signal,
122
122
  });
123
123
  setTimeout(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/anthropic",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Anthropic integrations for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {