@langchain/anthropic 1.4.0-dev-1775763803878 → 1.4.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @langchain/anthropic
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#10777](https://github.com/langchain-ai/langchainjs/pull/10777) [`0cfcfc6`](https://github.com/langchain-ai/langchainjs/commit/0cfcfc66897d8fafeb7e7ed90b7299eace9a7c37) Thanks [@jonaslalin](https://github.com/jonaslalin)! - feat(anthropic): support strict tool calling for custom tools
8
+
9
+ ## 1.3.29
10
+
11
+ ### Patch Changes
12
+
13
+ - [#10735](https://github.com/langchain-ai/langchainjs/pull/10735) [`1a2a08a`](https://github.com/langchain-ai/langchainjs/commit/1a2a08a33b7d99ec7348678116cc5d074db137bb) Thanks [@chenzimin](https://github.com/chenzimin)! - feat(anthropic): add automatic prompt caching via top-level cache_control
14
+
15
+ ## 1.3.28
16
+
17
+ ### Patch Changes
18
+
19
+ - [#10776](https://github.com/langchain-ai/langchainjs/pull/10776) [`20a9abe`](https://github.com/langchain-ai/langchainjs/commit/20a9abea23ffacf4ae8dc9a7aeec217143bbdeb6) Thanks [@hntrl](https://github.com/hntrl)! - fix(deps): remediate uuid vulnerability by removing direct uuid usage
20
+
21
+ - Updated dependencies [[`20a9abe`](https://github.com/langchain-ai/langchainjs/commit/20a9abea23ffacf4ae8dc9a7aeec217143bbdeb6)]:
22
+ - @langchain/core@1.1.42
23
+
24
+ ## 1.3.27
25
+
26
+ ### Patch Changes
27
+
28
+ - [#10726](https://github.com/langchain-ai/langchainjs/pull/10726) [`ad153c1`](https://github.com/langchain-ai/langchainjs/commit/ad153c185b6cf813d4b7695740d9a4453d2cb63f) Thanks [@hntrl](https://github.com/hntrl)! - feat(anthropic): add Claude Opus 4.7 compatibility updates
29
+
30
+ - Updated dependencies [[`589f29c`](https://github.com/langchain-ai/langchainjs/commit/589f29ce844eb252c2d5e6b0f8d26de37763a0d7), [`2e9e696`](https://github.com/langchain-ai/langchainjs/commit/2e9e6969e248a53ede0659a41d0ac8dbaf291ab4)]:
31
+ - @langchain/core@1.1.41
32
+
3
33
  ## 1.3.26
4
34
 
5
35
  ### Patch Changes
package/README.md CHANGED
@@ -75,6 +75,91 @@ const response = await model.stream({
75
75
  });
76
76
  ```
77
77
 
78
+ ### Strict Tool Use
79
+
80
+ Anthropic supports [strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use), which uses grammar-constrained sampling to guarantee that Claude's tool inputs match your schema (no missing required fields, no wrong types). Enable it on a per-call, per-binding, or per-tool basis.
81
+
82
+ **Per-call** with `bindTools` (applies to every tool in the binding):
83
+
84
+ ```typescript
85
+ import { ChatAnthropic } from "@langchain/anthropic";
86
+ import { tool } from "langchain";
87
+ import { z } from "zod";
88
+
89
+ const getWeather = tool(async ({ location }) => `Weather in ${location}`, {
90
+ name: "get_weather",
91
+ description: "Get the current weather in a given location",
92
+ schema: z.object({ location: z.string() }),
93
+ });
94
+
95
+ const model = new ChatAnthropic({ model: "claude-opus-4-7" });
96
+
97
+ const response = await model
98
+ .bindTools([getWeather], { strict: true })
99
+ .invoke("What's the weather in San Francisco?");
100
+ ```
101
+
102
+ **Default for a tool-bound model** with `withConfig` (applies to every subsequent call on the bound model):
103
+
104
+ ```typescript
105
+ const strictModelWithTools = model
106
+ .bindTools([getWeather])
107
+ .withConfig({ strict: true });
108
+
109
+ const response = await strictModelWithTools.invoke(
110
+ "What's the weather in San Francisco?"
111
+ );
112
+ ```
113
+
114
+ **Per-tool** with `extras.strict` for mixed strict/non-strict tool sets:
115
+
116
+ ```typescript
117
+ const lookupCustomer = tool(async ({ id }) => `...`, {
118
+ name: "lookup_customer",
119
+ description: "Look up a customer by id",
120
+ schema: z.object({ id: z.string() }),
121
+ // Strict on this critical tool only.
122
+ extras: { strict: true },
123
+ });
124
+
125
+ const searchDocs = tool(async ({ query }) => `...`, {
126
+ name: "search_docs",
127
+ description: "Free-form documentation search",
128
+ schema: z.object({ query: z.string() }),
129
+ });
130
+
131
+ const response = await model
132
+ .bindTools([lookupCustomer, searchDocs])
133
+ .invoke("Find customer 12345 and any onboarding docs");
134
+ ```
135
+
136
+ **With `withStructuredOutput`** to guarantee schema-conforming output:
137
+
138
+ ```typescript
139
+ const Weather = z.object({
140
+ location: z.string(),
141
+ temperature_celsius: z.number(),
142
+ });
143
+
144
+ const structured = model.withStructuredOutput(Weather, {
145
+ method: "functionCalling",
146
+ strict: true,
147
+ });
148
+
149
+ const result = await structured.invoke("What's the weather in San Francisco?");
150
+ ```
151
+
152
+ Precedence when multiple sources are set:
153
+
154
+ 1. Per-call `strict` (e.g. `bindTools(..., { strict })`, `withConfig({ strict })`, or `withStructuredOutput(..., { strict })`)
155
+ 2. Per-tool `strict` (e.g. `extras.strict`, `function.strict` on OpenAI-shaped tools, or `strict` on raw Anthropic-shaped tools)
156
+
157
+ In other words, per-tool acts as a fallback default for tools that opt in; if the call already specifies `strict`, that value wins for every tool in the request.
158
+
159
+ > **Note on `withStructuredOutput` methods:** Anthropic's `strict` is a property of a tool definition, so it only applies when `method: "functionCalling"` (the default), where the structured output is produced by a strict tool call.
160
+ >
161
+ > The other method, `"jsonSchema"`, uses Anthropic's [native structured outputs](https://docs.claude.com/en/docs/build-with-claude/structured-outputs) and does not accept `strict`. Passing `strict` together with `"jsonSchema"` or `"jsonMode"` throws, to avoid silently dropping the option. If you want strict-validated output, stick with the default `functionCalling` method.
162
+
78
163
  ## Tools
79
164
 
80
165
  This package provides LangChain-compatible wrappers for Anthropic's built-in tools. These tools can be bound to `ChatAnthropic` using `bindTools()` or any [`ReactAgent`](https://docs.langchain.com/oss/javascript/langchain/agents).
@@ -2,6 +2,7 @@ require("./_virtual/_rolldown/runtime.cjs");
2
2
  const require_output_parsers = require("./output_parsers.cjs");
3
3
  const require_tools = require("./utils/tools.cjs");
4
4
  const require_message_inputs = require("./utils/message_inputs.cjs");
5
+ const require_params = require("./utils/params.cjs");
5
6
  const require_message_outputs = require("./utils/message_outputs.cjs");
6
7
  const require_errors = require("./utils/errors.cjs");
7
8
  const require_profiles = require("./profiles.cjs");
@@ -20,6 +21,7 @@ let _langchain_core_utils_standard_schema = require("@langchain/core/utils/stand
20
21
  let _langchain_core_language_models_structured_output = require("@langchain/core/language_models/structured_output");
21
22
  //#region src/chat_models.ts
22
23
  const MODEL_DEFAULT_MAX_OUTPUT_TOKENS = {
24
+ "claude-opus-4-7": 16384,
23
25
  "claude-opus-4-6": 16384,
24
26
  "claude-sonnet-4-6": 16384,
25
27
  "claude-opus-4-5": 16384,
@@ -649,7 +651,7 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
649
651
  model: modelOrFields
650
652
  } : modelOrFields ?? {};
651
653
  super(fields ?? {});
652
- this._addVersion("@langchain/anthropic", "1.4.0-dev-1775763803878");
654
+ this._addVersion("@langchain/anthropic", "1.4.0");
653
655
  this.anthropicApiKey = fields?.apiKey ?? fields?.anthropicApiKey ?? (0, _langchain_core_utils_env.getEnvironmentVariable)("ANTHROPIC_API_KEY");
654
656
  if (!this.anthropicApiKey && !fields?.createClient) throw new Error("Anthropic API key not found");
655
657
  this.clientOptions = fields?.clientOptions ?? {};
@@ -689,31 +691,48 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
689
691
  * Formats LangChain StructuredTools to AnthropicTools.
690
692
  *
691
693
  * @param {ChatAnthropicCallOptions["tools"]} tools The tools to format
694
+ * @param fields Optional `strict` flag applied to every formatted custom tool.
692
695
  * @returns {AnthropicTool[] | undefined} The formatted tools, or undefined if none are passed.
693
696
  */
694
- formatStructuredToolToAnthropic(tools) {
697
+ formatStructuredToolToAnthropic(tools, fields) {
695
698
  if (!tools) return;
696
699
  return tools.map((tool) => {
697
700
  if ((0, _langchain_core_utils_function_calling.isLangChainTool)(tool) && tool.extras?.providerToolDefinition) return tool.extras.providerToolDefinition;
698
701
  if (isBuiltinTool(tool)) return tool;
699
- if (isAnthropicTool(tool)) return tool;
700
- if ((0, _langchain_core_language_models_base.isOpenAITool)(tool)) return {
701
- name: tool.function.name,
702
- description: tool.function.description,
703
- input_schema: tool.function.parameters
704
- };
705
- if ((0, _langchain_core_utils_function_calling.isLangChainTool)(tool)) return {
706
- name: tool.name,
707
- description: tool.description,
708
- input_schema: (0, _langchain_core_utils_types.isInteropZodSchema)(tool.schema) ? (0, _langchain_core_utils_json_schema.toJsonSchema)(tool.schema) : tool.schema,
709
- ...tool.extras ? require_tools.AnthropicToolExtrasSchema.parse(tool.extras) : {}
710
- };
702
+ if (isAnthropicTool(tool)) {
703
+ if (fields?.strict !== void 0) return {
704
+ ...tool,
705
+ strict: fields.strict
706
+ };
707
+ return tool;
708
+ }
709
+ if ((0, _langchain_core_language_models_base.isOpenAITool)(tool)) {
710
+ const functionStrict = "strict" in tool.function && typeof tool.function.strict === "boolean" ? tool.function.strict : void 0;
711
+ const strict = fields?.strict ?? functionStrict;
712
+ return {
713
+ name: tool.function.name,
714
+ description: tool.function.description,
715
+ input_schema: tool.function.parameters,
716
+ ...strict !== void 0 ? { strict } : {}
717
+ };
718
+ }
719
+ if ((0, _langchain_core_utils_function_calling.isLangChainTool)(tool)) {
720
+ const { strict: extrasStrict, ...restExtras } = tool.extras ? require_tools.AnthropicToolExtrasSchema.parse(tool.extras) : {};
721
+ const strict = fields?.strict ?? extrasStrict;
722
+ return {
723
+ name: tool.name,
724
+ description: tool.description,
725
+ input_schema: (0, _langchain_core_utils_types.isInteropZodSchema)(tool.schema) ? (0, _langchain_core_utils_json_schema.toJsonSchema)(tool.schema) : tool.schema,
726
+ ...restExtras,
727
+ ...strict !== void 0 ? { strict } : {}
728
+ };
729
+ }
711
730
  throw new Error(`Unknown tool type passed to ChatAnthropic: ${JSON.stringify(tool, null, 2)}`);
712
731
  });
713
732
  }
714
733
  bindTools(tools, kwargs) {
715
734
  return this.withConfig({
716
- tools: this.formatStructuredToolToAnthropic(tools),
735
+ tools: this.formatStructuredToolToAnthropic(tools, { strict: kwargs?.strict }),
717
736
  ...kwargs
718
737
  });
719
738
  }
@@ -738,31 +757,38 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
738
757
  return Object.keys(base).length > 0 ? base : void 0;
739
758
  })();
740
759
  const compactionBetas = this.contextManagement?.edits?.some((e) => e.type === "compact_20260112") ? ["compact-2026-01-12"] : [];
760
+ const taskBudgetBetas = require_params.getTaskBudgetBetas(this.model, mergedOutputConfig);
741
761
  const output = {
742
762
  model: this.model,
743
763
  stop_sequences: options?.stop ?? this.stopSequences,
744
764
  stream: this.streaming,
745
765
  max_tokens: this.maxTokens,
746
- tools: this.formatStructuredToolToAnthropic(options?.tools),
766
+ tools: this.formatStructuredToolToAnthropic(options?.tools, { strict: options?.strict }),
747
767
  tool_choice,
748
768
  thinking: this.thinking,
749
769
  context_management: this.contextManagement,
750
770
  ...this.invocationKwargs,
751
771
  container: options?.container,
752
- betas: _combineBetas(this.betas, options?.betas, toolBetas ?? [], compactionBetas),
772
+ betas: _combineBetas(this.betas, options?.betas, toolBetas ?? [], compactionBetas, taskBudgetBetas),
753
773
  output_config: mergedOutputConfig,
754
774
  inference_geo: options?.inferenceGeo ?? this.inferenceGeo,
755
- mcp_servers: options?.mcp_servers
775
+ mcp_servers: options?.mcp_servers,
776
+ cache_control: options?.cache_control
756
777
  };
757
- if (this.thinking.type === "enabled" || this.thinking.type === "adaptive") {
758
- if (this.topK !== void 0) throw new Error("topK is not supported when thinking is enabled");
759
- if (this.topP !== void 0) throw new Error("topP is not supported when thinking is enabled");
760
- if (this.temperature !== void 0 && this.temperature !== 1) throw new Error("temperature is not supported when thinking is enabled");
761
- } else {
762
- if (this.temperature !== void 0) output.temperature = this.temperature;
763
- if (this.topK !== void 0) output.top_k = this.topK;
764
- if (this.topP !== void 0) output.top_p = this.topP;
765
- }
778
+ require_params.validateInvocationParamCompatibility({
779
+ model: this.model,
780
+ thinking: this.thinking,
781
+ topK: this.topK,
782
+ topP: this.topP,
783
+ temperature: this.temperature
784
+ });
785
+ Object.assign(output, require_params.getSamplingParams({
786
+ model: this.model,
787
+ thinking: this.thinking,
788
+ topK: this.topK,
789
+ topP: this.topP,
790
+ temperature: this.temperature
791
+ }));
766
792
  return output;
767
793
  }
768
794
  /** @ignore */
@@ -783,8 +809,7 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
783
809
  }
784
810
  async *_streamResponseChunks(messages, options, runManager) {
785
811
  const params = this.invocationParams(options);
786
- let formattedMessages = require_message_inputs._convertMessagesToAnthropicPayload(messages);
787
- if (options.cache_control) formattedMessages = require_message_inputs.applyCacheControlToPayload(formattedMessages, options.cache_control);
812
+ const formattedMessages = require_message_inputs._convertMessagesToAnthropicPayload(messages);
788
813
  const payload = {
789
814
  ...params,
790
815
  ...formattedMessages,
@@ -837,8 +862,7 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
837
862
  */
838
863
  async *_streamChatModelEvents(messages, options, _runManager) {
839
864
  const params = this.invocationParams(options);
840
- let formattedMessages = require_message_inputs._convertMessagesToAnthropicPayload(messages);
841
- if (options.cache_control) formattedMessages = require_message_inputs.applyCacheControlToPayload(formattedMessages, options.cache_control);
865
+ const formattedMessages = require_message_inputs._convertMessagesToAnthropicPayload(messages);
842
866
  const payload = {
843
867
  ...params,
844
868
  ...formattedMessages,
@@ -861,9 +885,8 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
861
885
  yield* require_stream_events.convertAnthropicStream(abortableStream(stream, options.signal), { streamUsage: shouldStreamUsage ?? true });
862
886
  }
863
887
  /** @ignore */
864
- async _generateNonStreaming(messages, params, requestOptions, cacheControl) {
865
- let formattedMessages = require_message_inputs._convertMessagesToAnthropicPayload(messages);
866
- if (cacheControl) formattedMessages = require_message_inputs.applyCacheControlToPayload(formattedMessages, cacheControl);
888
+ async _generateNonStreaming(messages, params, requestOptions) {
889
+ const formattedMessages = require_message_inputs._convertMessagesToAnthropicPayload(messages);
867
890
  const { content, ...additionalKwargs } = await this.completionWithRetry({
868
891
  ...params,
869
892
  stream: false,
@@ -894,7 +917,7 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
894
917
  } else return this._generateNonStreaming(messages, params, {
895
918
  signal: options.signal,
896
919
  headers: options.headers
897
- }, options.cache_control);
920
+ });
898
921
  }
899
922
  /**
900
923
  * Creates a streaming request with retry.
@@ -994,6 +1017,7 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
994
1017
  schema: outputSchema
995
1018
  };
996
1019
  let method = config?.method ?? "functionCalling";
1020
+ if (config?.strict !== void 0 && method !== "functionCalling") throw new Error(`Argument \`strict\` is only supported for \`method\` = "functionCalling" on Anthropic models. Got method = "${method}".`);
997
1021
  if (method === "jsonMode") {
998
1022
  console.warn(`"jsonMode" is not supported for Anthropic models. Falling back to "jsonSchema".`);
999
1023
  method = "jsonSchema";
@@ -1040,7 +1064,8 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
1040
1064
  ls_structured_output_format: {
1041
1065
  kwargs: { method: "functionCalling" },
1042
1066
  schema: (0, _langchain_core_utils_json_schema.toJsonSchema)(schema)
1043
- }
1067
+ },
1068
+ ...config?.strict !== void 0 ? { strict: config.strict } : {}
1044
1069
  });
1045
1070
  const raiseIfNoToolCalls = (message) => {
1046
1071
  if (!message.tool_calls || message.tool_calls.length === 0) throw new Error(thinkingAdmonition);
@@ -1057,7 +1082,8 @@ var ChatAnthropicMessages = class extends _langchain_core_language_models_chat_m
1057
1082
  ls_structured_output_format: {
1058
1083
  kwargs: { method: "functionCalling" },
1059
1084
  schema: (0, _langchain_core_utils_json_schema.toJsonSchema)(schema)
1060
- }
1085
+ },
1086
+ ...config?.strict !== void 0 ? { strict: config.strict } : {}
1061
1087
  });
1062
1088
  } else throw new TypeError(`Unrecognized structured output method '${method}'. Expected 'functionCalling' or 'jsonSchema'`);
1063
1089
  return (0, _langchain_core_language_models_structured_output.assembleStructuredOutputPipeline)(llm, outputParser, includeRaw, includeRaw ? "StructuredOutputRunnable" : "ChatAnthropicStructuredOutput");