@ai-sdk/anthropic 4.0.93 → 4.0.95
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 +19 -0
- package/dist/index.js +240 -24
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +12 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +240 -24
- package/dist/internal/index.js.map +1 -1
- package/docs/05-anthropic.mdx +19 -2
- package/package.json +2 -2
- package/src/anthropic-language-model.ts +138 -22
- package/src/convert-to-anthropic-prompt.ts +17 -1
- package/src/has-circular-schema-reference.ts +115 -0
- package/src/internal/index.ts +1 -0
- package/src/sanitize-json-schema.ts +27 -24
- package/src/supports-native-structured-output-schema.ts +138 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @ai-sdk/anthropic
|
|
2
2
|
|
|
3
|
+
## 4.0.95
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2cd0a97: Enable native structured output and strict tools for supported Claude 5 models on Bedrock. In automatic mode, Bedrock and Anthropic now fall back for schemas that native structured output cannot represent: recursive references, open objects, or more than ten optional properties. Anthropic uses the JSON response tool; Bedrock Converse uses the JSON tool or JSON instructions for models that reject forced tool use. The JSON-tool fallback excludes disabled and unselected application tools. Explicit `outputFormat` selection remains unchanged.
|
|
8
|
+
- 4ae6986: fix(anthropic): parse valid JSON string tool input and safely serialize BigInt and cycles in tool results
|
|
9
|
+
- Updated dependencies [51ca5b7]
|
|
10
|
+
- Updated dependencies [dc6f1c3]
|
|
11
|
+
- Updated dependencies [4ae6986]
|
|
12
|
+
- @ai-sdk/provider-utils@5.0.73
|
|
13
|
+
|
|
14
|
+
## 4.0.94
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- f4c5f1e: fix(anthropic): use native structured outputs for Claude models that reject forced tool use (Sonnet 5.5, Opus 5.5, Fable 5.1) even when the provider disables them by default, as Amazon Bedrock and Google Vertex do. Self-referencing schemas keep the JSON response tool. Also keep `definitions` and `$defs` next to a top-level `$ref` when sanitizing structured output schemas, so the reference still resolves.
|
|
19
|
+
- e10aebb: fix(anthropic): when the JSON response tool is in use but the model answers in text without calling it (for example with manual thinking, where the forced tool choice is downgraded to `auto`), return the final answer text instead of dropping it. Text before a tool call, result, or message continuation is still dropped.
|
|
20
|
+
- b0d51fe: fix(anthropic): keep the JSON response tool for schemas that native structured outputs cannot represent when upgrading models that reject forced tool use. Schemas with open objects (maps, free-form objects) would otherwise come back as `{}`, and schemas with more than 10 optional properties can be rejected as too complex.
|
|
21
|
+
|
|
3
22
|
## 4.0.93
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { APICallError, InvalidArgumentError, InvalidResponseDataError, NoSuchModelError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
|
|
2
|
-
import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertInlineFileDataToUint8Array, convertToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonLinesResponseHandler, createJsonResponseHandler, createProviderDefinedToolFactory, createProviderExecutedToolFactory, createProviderStreamError, createToolNameMapping, encodePathSegment, experimental_toolCaller, generateId, getFromApi, getTopLevelMediaType, isCustomReasoning, isNonNullable, isProviderStreamError, isRecord, lazySchema, loadApiKey, loadOptionalSetting, mapReasoningToProviderBudget, mapReasoningToProviderEffort, normalizeBatchRequestCounts, normalizeHeaders, parseProviderOptions, postFormDataToApi, postJsonToApi, resolve, resolveFullMediaType, resolveProviderReference, safeValidateTypes, secureJsonParse, serializeModelOptions, validateBaseURL, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
|
|
2
|
+
import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertInlineFileDataToUint8Array, convertToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonLinesResponseHandler, createJsonResponseHandler, createProviderDefinedToolFactory, createProviderExecutedToolFactory, createProviderStreamError, createToolNameMapping, encodePathSegment, experimental_toolCaller, generateId, getFromApi, getTopLevelMediaType, isCustomReasoning, isNonNullable, isProviderStreamError, isRecord, lazySchema, loadApiKey, loadOptionalSetting, mapReasoningToProviderBudget, mapReasoningToProviderEffort, normalizeBatchRequestCounts, normalizeHeaders, parseProviderOptions, postFormDataToApi, postJsonToApi, resolve, resolveFullMediaType, resolveProviderReference, safeValidateTypes, secureJsonParse, serializeModelOptions, stringifyWithBigIntAndCycles, validateBaseURL, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema } from "@ai-sdk/provider-utils";
|
|
3
3
|
import { Experimental_DecisionLanguageModel } from "@ai-sdk/provider-utils/experimental-decision";
|
|
4
4
|
import { z } from "zod/v4";
|
|
5
5
|
//#region src/anthropic-error.ts
|
|
@@ -2963,7 +2963,7 @@ async function convertToAnthropicPrompt({ prompt, sendReasoning, warnings, cache
|
|
|
2963
2963
|
case "execution-denied":
|
|
2964
2964
|
contentValue = output.reason ?? "Tool call execution denied.";
|
|
2965
2965
|
break;
|
|
2966
|
-
default: contentValue =
|
|
2966
|
+
default: contentValue = stringifyWithBigIntAndCycles(output.value);
|
|
2967
2967
|
}
|
|
2968
2968
|
const toolsetName = getAnthropicToolsetName({
|
|
2969
2969
|
toolName: part.toolName,
|
|
@@ -3634,6 +3634,10 @@ function getAnthropicCaller(providerOptions) {
|
|
|
3634
3634
|
return caller?.type === "direct" ? { type: "direct" } : void 0;
|
|
3635
3635
|
}
|
|
3636
3636
|
function toAnthropicToolInput(input) {
|
|
3637
|
+
if (typeof input === "string") try {
|
|
3638
|
+
const parsed = secureJsonParse(input);
|
|
3639
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
3640
|
+
} catch {}
|
|
3637
3641
|
return typeof input === "object" && input !== null && !Array.isArray(input) ? input : { rawInvalidInput: input };
|
|
3638
3642
|
}
|
|
3639
3643
|
//#endregion
|
|
@@ -3700,8 +3704,10 @@ function sanitizeDefinition(definition) {
|
|
|
3700
3704
|
}
|
|
3701
3705
|
function sanitizeSchema(schema) {
|
|
3702
3706
|
const result = {};
|
|
3703
|
-
|
|
3704
|
-
|
|
3707
|
+
if (schema.$ref != null) return {
|
|
3708
|
+
$ref: schema.$ref,
|
|
3709
|
+
...sanitizeSchemaDefinitions(schema)
|
|
3710
|
+
};
|
|
3705
3711
|
if (schema.$schema != null) result.$schema = schema.$schema;
|
|
3706
3712
|
if (schema.$id != null) result.$id = schema.$id;
|
|
3707
3713
|
if (schema.title != null) result.title = schema.title;
|
|
@@ -3713,11 +3719,7 @@ function sanitizeSchema(schema) {
|
|
|
3713
3719
|
if (schema.anyOf != null) result.anyOf = schema.anyOf.map(sanitizeDefinition);
|
|
3714
3720
|
else if (schema.oneOf != null) result.anyOf = schema.oneOf.map(sanitizeDefinition);
|
|
3715
3721
|
if (schema.allOf != null) result.allOf = schema.allOf.map(sanitizeDefinition);
|
|
3716
|
-
|
|
3717
|
-
if (schemaWithDefs.$defs != null) {
|
|
3718
|
-
const resultWithDefs = result;
|
|
3719
|
-
resultWithDefs.$defs = Object.fromEntries(Object.entries(schemaWithDefs.$defs).map(([name, definition]) => [name, sanitizeDefinition(definition)]));
|
|
3720
|
-
}
|
|
3722
|
+
Object.assign(result, sanitizeSchemaDefinitions(schema));
|
|
3721
3723
|
if (schema.type === "object" || schema.properties != null) {
|
|
3722
3724
|
if (schema.properties != null) result.properties = Object.fromEntries(Object.entries(schema.properties).map(([name, definition]) => [name, sanitizeDefinition(definition)]));
|
|
3723
3725
|
result.additionalProperties = false;
|
|
@@ -3729,6 +3731,14 @@ function sanitizeSchema(schema) {
|
|
|
3729
3731
|
if (constraintDescription != null) result.description = result.description == null ? constraintDescription : `${result.description}\n${constraintDescription}`;
|
|
3730
3732
|
return result;
|
|
3731
3733
|
}
|
|
3734
|
+
function sanitizeSchemaDefinitions(schema) {
|
|
3735
|
+
const { $defs } = schema;
|
|
3736
|
+
const sanitizeAll = (definitions) => Object.fromEntries(Object.entries(definitions).map(([name, definition]) => [name, sanitizeDefinition(definition)]));
|
|
3737
|
+
return {
|
|
3738
|
+
...schema.definitions != null && { definitions: sanitizeAll(schema.definitions) },
|
|
3739
|
+
...$defs != null && { $defs: sanitizeAll($defs) }
|
|
3740
|
+
};
|
|
3741
|
+
}
|
|
3732
3742
|
function getConstraintDescription(schema) {
|
|
3733
3743
|
const descriptions = DESCRIPTION_CONSTRAINT_KEYS.flatMap((key) => {
|
|
3734
3744
|
const value = schema[key];
|
|
@@ -3746,6 +3756,155 @@ function formatConstraintValue(value) {
|
|
|
3746
3756
|
return JSON.stringify(value);
|
|
3747
3757
|
}
|
|
3748
3758
|
//#endregion
|
|
3759
|
+
//#region src/has-circular-schema-reference.ts
|
|
3760
|
+
const SCHEMA_MAP_KEYWORDS = /* @__PURE__ */ new Set([
|
|
3761
|
+
"dependentSchemas",
|
|
3762
|
+
"patternProperties",
|
|
3763
|
+
"properties"
|
|
3764
|
+
]);
|
|
3765
|
+
const DATA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
3766
|
+
"const",
|
|
3767
|
+
"default",
|
|
3768
|
+
"enum",
|
|
3769
|
+
"examples"
|
|
3770
|
+
]);
|
|
3771
|
+
/**
|
|
3772
|
+
* Whether a JSON schema contains a cycle of local `$ref`s, e.g. a tree node
|
|
3773
|
+
* whose children reference the node itself.
|
|
3774
|
+
*
|
|
3775
|
+
* Anthropic's native structured outputs reject such schemas, while the JSON
|
|
3776
|
+
* response tool accepts them.
|
|
3777
|
+
*/
|
|
3778
|
+
function hasCircularSchemaReference(schema) {
|
|
3779
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
3780
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3781
|
+
const visit = (pointer) => {
|
|
3782
|
+
if (visiting.has(pointer)) return true;
|
|
3783
|
+
if (visited.has(pointer)) return false;
|
|
3784
|
+
const target = resolveSchemaPointer(schema, pointer);
|
|
3785
|
+
if (target === void 0) return false;
|
|
3786
|
+
visiting.add(pointer);
|
|
3787
|
+
const isCircular = collectLocalRefs(target).some(visit);
|
|
3788
|
+
visiting.delete(pointer);
|
|
3789
|
+
visited.add(pointer);
|
|
3790
|
+
return isCircular;
|
|
3791
|
+
};
|
|
3792
|
+
return visit("#");
|
|
3793
|
+
}
|
|
3794
|
+
function collectLocalRefs(node, refs = []) {
|
|
3795
|
+
if (Array.isArray(node)) {
|
|
3796
|
+
for (const item of node) collectLocalRefs(item, refs);
|
|
3797
|
+
return refs;
|
|
3798
|
+
}
|
|
3799
|
+
if (!isRecord(node)) return refs;
|
|
3800
|
+
for (const [key, value] of Object.entries(node)) if (key === "$ref") {
|
|
3801
|
+
if (typeof value === "string" && value.startsWith("#")) refs.push(value);
|
|
3802
|
+
} else if (SCHEMA_MAP_KEYWORDS.has(key) && isRecord(value)) for (const subschema of Object.values(value)) collectLocalRefs(subschema, refs);
|
|
3803
|
+
else if (key !== "$defs" && key !== "definitions" && !DATA_KEYWORDS.has(key)) collectLocalRefs(value, refs);
|
|
3804
|
+
return refs;
|
|
3805
|
+
}
|
|
3806
|
+
function resolveSchemaPointer(schema, pointer) {
|
|
3807
|
+
if (pointer === "#") return schema;
|
|
3808
|
+
if (!pointer.startsWith("#/")) return;
|
|
3809
|
+
let decodedPointer;
|
|
3810
|
+
try {
|
|
3811
|
+
decodedPointer = decodeURIComponent(pointer.slice(2));
|
|
3812
|
+
} catch {
|
|
3813
|
+
return;
|
|
3814
|
+
}
|
|
3815
|
+
let current = schema;
|
|
3816
|
+
for (const rawSegment of decodedPointer.split("/")) {
|
|
3817
|
+
const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
3818
|
+
if (Array.isArray(current)) current = current[Number(segment)];
|
|
3819
|
+
else if (isRecord(current)) current = current[segment];
|
|
3820
|
+
else return;
|
|
3821
|
+
}
|
|
3822
|
+
return current;
|
|
3823
|
+
}
|
|
3824
|
+
//#endregion
|
|
3825
|
+
//#region src/supports-native-structured-output-schema.ts
|
|
3826
|
+
const MAX_OPTIONAL_PROPERTIES = 10;
|
|
3827
|
+
const SUBSCHEMA_KEYWORDS = [
|
|
3828
|
+
"additionalProperties",
|
|
3829
|
+
"contains",
|
|
3830
|
+
"else",
|
|
3831
|
+
"if",
|
|
3832
|
+
"items",
|
|
3833
|
+
"not",
|
|
3834
|
+
"then"
|
|
3835
|
+
];
|
|
3836
|
+
const SUBSCHEMA_LIST_KEYWORDS = [
|
|
3837
|
+
"allOf",
|
|
3838
|
+
"anyOf",
|
|
3839
|
+
"oneOf",
|
|
3840
|
+
"prefixItems"
|
|
3841
|
+
];
|
|
3842
|
+
const SUBSCHEMA_MAP_KEYWORDS = [
|
|
3843
|
+
"dependentSchemas",
|
|
3844
|
+
"patternProperties",
|
|
3845
|
+
"properties"
|
|
3846
|
+
];
|
|
3847
|
+
/**
|
|
3848
|
+
* Whether Anthropic's native structured outputs (`output_config.format`) can
|
|
3849
|
+
* represent a schema without rejecting it or losing data.
|
|
3850
|
+
*
|
|
3851
|
+
* Rejected: self-referencing schemas, and schemas with too many optional
|
|
3852
|
+
* properties. Lossy: open objects (maps, free-form objects), which native
|
|
3853
|
+
* structured outputs close with `additionalProperties: false`, so the model
|
|
3854
|
+
* can only return `{}` for them.
|
|
3855
|
+
*/
|
|
3856
|
+
function supportsNativeStructuredOutputSchema(schema) {
|
|
3857
|
+
if (hasCircularSchemaReference(schema)) return false;
|
|
3858
|
+
const { optionalProperties, hasOpenObject } = getSchemaStats(schema, schema, /* @__PURE__ */ new Map());
|
|
3859
|
+
return !hasOpenObject && optionalProperties <= MAX_OPTIONAL_PROPERTIES;
|
|
3860
|
+
}
|
|
3861
|
+
function getSchemaStats(node, root, refStats) {
|
|
3862
|
+
const stats = {
|
|
3863
|
+
optionalProperties: 0,
|
|
3864
|
+
hasOpenObject: false
|
|
3865
|
+
};
|
|
3866
|
+
if (!isRecord(node)) return stats;
|
|
3867
|
+
const add = (child) => {
|
|
3868
|
+
const childStats = getSchemaStats(child, root, refStats);
|
|
3869
|
+
stats.optionalProperties += childStats.optionalProperties;
|
|
3870
|
+
stats.hasOpenObject ||= childStats.hasOpenObject;
|
|
3871
|
+
};
|
|
3872
|
+
if (typeof node.$ref === "string" && node.$ref.startsWith("#")) {
|
|
3873
|
+
let resolved = refStats.get(node.$ref);
|
|
3874
|
+
if (resolved == null) {
|
|
3875
|
+
resolved = getSchemaStats(resolveSchemaPointer(root, node.$ref), root, refStats);
|
|
3876
|
+
refStats.set(node.$ref, resolved);
|
|
3877
|
+
}
|
|
3878
|
+
stats.optionalProperties += resolved.optionalProperties;
|
|
3879
|
+
stats.hasOpenObject ||= resolved.hasOpenObject;
|
|
3880
|
+
}
|
|
3881
|
+
if (isOpenObject(node)) stats.hasOpenObject = true;
|
|
3882
|
+
if (isRecord(node.properties)) {
|
|
3883
|
+
const required = new Set(Array.isArray(node.required) ? node.required : []);
|
|
3884
|
+
stats.optionalProperties += Object.keys(node.properties).filter((name) => !required.has(name)).length;
|
|
3885
|
+
}
|
|
3886
|
+
for (const keyword of SUBSCHEMA_KEYWORDS) {
|
|
3887
|
+
const value = node[keyword];
|
|
3888
|
+
if (Array.isArray(value)) value.forEach(add);
|
|
3889
|
+
else add(value);
|
|
3890
|
+
}
|
|
3891
|
+
for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
|
|
3892
|
+
const value = node[keyword];
|
|
3893
|
+
if (Array.isArray(value)) value.forEach(add);
|
|
3894
|
+
}
|
|
3895
|
+
for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
|
|
3896
|
+
const value = node[keyword];
|
|
3897
|
+
if (isRecord(value)) Object.values(value).forEach(add);
|
|
3898
|
+
}
|
|
3899
|
+
return stats;
|
|
3900
|
+
}
|
|
3901
|
+
function isOpenObject(node) {
|
|
3902
|
+
const { additionalProperties, patternProperties, properties, type } = node;
|
|
3903
|
+
if (additionalProperties === true || isRecord(additionalProperties)) return true;
|
|
3904
|
+
if (isRecord(patternProperties) && Object.keys(patternProperties).length > 0) return true;
|
|
3905
|
+
return (type === "object" || Array.isArray(type) && type.includes("object")) && properties == null && additionalProperties !== false;
|
|
3906
|
+
}
|
|
3907
|
+
//#endregion
|
|
3749
3908
|
//#region src/anthropic-language-model.ts
|
|
3750
3909
|
function createAnthropicStreamError(error) {
|
|
3751
3910
|
const inferredMetadata = getAnthropicStreamErrorMetadata(error.type);
|
|
@@ -3864,6 +4023,28 @@ function getProviderOptionsName(provider) {
|
|
|
3864
4023
|
const dotIndex = provider.indexOf(".");
|
|
3865
4024
|
return dotIndex === -1 ? provider : provider.substring(0, dotIndex);
|
|
3866
4025
|
}
|
|
4026
|
+
const TEXT_OR_THINKING_BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
4027
|
+
"redacted_thinking",
|
|
4028
|
+
"text",
|
|
4029
|
+
"thinking"
|
|
4030
|
+
]);
|
|
4031
|
+
function isContinuationStopReason(stopReason) {
|
|
4032
|
+
return stopReason === "pause_turn" || stopReason === "tool_use";
|
|
4033
|
+
}
|
|
4034
|
+
/**
|
|
4035
|
+
* Text parts to return when the JSON response tool is in use: the text after
|
|
4036
|
+
* the last tool call or result, and only if the tool was never called.
|
|
4037
|
+
*/
|
|
4038
|
+
function getJsonResponseToolFallbackText(content, stopReason) {
|
|
4039
|
+
const text = /* @__PURE__ */ new Set();
|
|
4040
|
+
if (isContinuationStopReason(stopReason)) return text;
|
|
4041
|
+
for (const part of content) {
|
|
4042
|
+
if (part.type === "tool_use" && part.name === "json") return /* @__PURE__ */ new Set();
|
|
4043
|
+
if (part.type === "text") text.add(part);
|
|
4044
|
+
else if (!TEXT_OR_THINKING_BLOCK_TYPES.has(part.type)) text.clear();
|
|
4045
|
+
}
|
|
4046
|
+
return text;
|
|
4047
|
+
}
|
|
3867
4048
|
var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
3868
4049
|
static [WORKFLOW_SERIALIZE](model) {
|
|
3869
4050
|
return serializeModelOptions({
|
|
@@ -3974,10 +4155,11 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
3974
4155
|
}
|
|
3975
4156
|
const isAnthropicModel = isKnownModel || modelId.includes("claude-");
|
|
3976
4157
|
const supportsStructuredOutput = (config.supportsNativeStructuredOutput ?? true) && modelSupportsStructuredOutput;
|
|
4158
|
+
const supportsResponseSchema = responseFormat?.type !== "json" || responseFormat.schema == null || supportsNativeStructuredOutputSchema(responseFormat.schema);
|
|
3977
4159
|
const supportsStrictTools = (config.supportsStrictTools ?? true) && modelSupportsStructuredOutput;
|
|
3978
4160
|
const structureOutputMode = anthropicOptions?.structuredOutputMode ?? "auto";
|
|
3979
|
-
let useStructuredOutput = structureOutputMode === "outputFormat" || structureOutputMode === "auto" && supportsStructuredOutput;
|
|
3980
|
-
if (!useStructuredOutput && rejectsForcedToolUse &&
|
|
4161
|
+
let useStructuredOutput = structureOutputMode === "outputFormat" || structureOutputMode === "auto" && supportsStructuredOutput && supportsResponseSchema;
|
|
4162
|
+
if (!useStructuredOutput && rejectsForcedToolUse && modelSupportsStructuredOutput && responseFormat?.type === "json" && responseFormat.schema != null && supportsNativeStructuredOutputSchema(responseFormat.schema)) {
|
|
3981
4163
|
warnings.push({
|
|
3982
4164
|
type: "unsupported",
|
|
3983
4165
|
feature: "providerOptions.anthropic.structuredOutputMode",
|
|
@@ -4276,7 +4458,7 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
4276
4458
|
else if (anthropicOptions?.fallbacks && anthropicOptions.fallbacks.length > 0) betas.add("server-side-fallback-2026-06-01");
|
|
4277
4459
|
const defaultEagerInputStreaming = stream && (anthropicOptions?.toolStreaming ?? true);
|
|
4278
4460
|
const { tools: anthropicTools, toolChoice: anthropicToolChoice, toolWarnings, betas: toolsBetas } = await prepareTools(jsonResponseTool != null ? {
|
|
4279
|
-
tools: [...tools ?? [], jsonResponseTool],
|
|
4461
|
+
tools: [...(tools ?? []).filter((tool) => toolChoice?.type !== "none" && (toolChoice?.type !== "tool" || tool.name === toolChoice.toolName)), jsonResponseTool],
|
|
4280
4462
|
toolChoice: { type: "required" },
|
|
4281
4463
|
disableParallelToolUse: true,
|
|
4282
4464
|
cacheControlValidator,
|
|
@@ -4384,9 +4566,10 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
4384
4566
|
const serverToolCalls = {};
|
|
4385
4567
|
let isJsonResponseFromTool = false;
|
|
4386
4568
|
const hasWebSearchResults = response.content.some((part) => part.type === "web_search_tool_result" && Array.isArray(part.content) && part.content.length > 0);
|
|
4569
|
+
const jsonResponseToolFallbackText = usesJsonResponseTool ? getJsonResponseToolFallbackText(response.content, response.stop_reason) : void 0;
|
|
4387
4570
|
for (const part of response.content) switch (part.type) {
|
|
4388
4571
|
case "text":
|
|
4389
|
-
if (
|
|
4572
|
+
if (jsonResponseToolFallbackText == null || jsonResponseToolFallbackText.has(part)) {
|
|
4390
4573
|
const citations = part.citations ?? [];
|
|
4391
4574
|
content.push({
|
|
4392
4575
|
type: "text",
|
|
@@ -4824,6 +5007,16 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
4824
5007
|
let safeguardResults;
|
|
4825
5008
|
let container = null;
|
|
4826
5009
|
let isJsonResponseFromTool = false;
|
|
5010
|
+
const heldBackText = [];
|
|
5011
|
+
const heldBackTextByIndex = /* @__PURE__ */ new Map();
|
|
5012
|
+
const createTextEnd = (id, citations) => ({
|
|
5013
|
+
type: "text-end",
|
|
5014
|
+
id,
|
|
5015
|
+
...citations.length > 0 && {
|
|
5016
|
+
citations: citations.map((citation) => mapAnthropicCitation(citation, citationDocuments)),
|
|
5017
|
+
providerMetadata: { anthropic: { citations } }
|
|
5018
|
+
}
|
|
5019
|
+
});
|
|
4827
5020
|
let hasWebSearchResults = false;
|
|
4828
5021
|
const fallbackWebCitations = [];
|
|
4829
5022
|
let isMessageOpen = false;
|
|
@@ -4870,9 +5063,19 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
4870
5063
|
return;
|
|
4871
5064
|
}
|
|
4872
5065
|
blockType = contentBlockType;
|
|
5066
|
+
if (!TEXT_OR_THINKING_BLOCK_TYPES.has(contentBlockType)) heldBackText.length = 0;
|
|
4873
5067
|
switch (contentBlockType) {
|
|
4874
5068
|
case "text":
|
|
4875
|
-
if (usesJsonResponseTool)
|
|
5069
|
+
if (usesJsonResponseTool) {
|
|
5070
|
+
const entry = {
|
|
5071
|
+
id: String(value.index),
|
|
5072
|
+
text: "",
|
|
5073
|
+
citations: []
|
|
5074
|
+
};
|
|
5075
|
+
heldBackText.push(entry);
|
|
5076
|
+
heldBackTextByIndex.set(value.index, entry);
|
|
5077
|
+
return;
|
|
5078
|
+
}
|
|
4876
5079
|
contentBlocks[value.index] = {
|
|
4877
5080
|
type: "text",
|
|
4878
5081
|
citations: []
|
|
@@ -5258,14 +5461,7 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
5258
5461
|
const contentBlock = contentBlocks[value.index];
|
|
5259
5462
|
switch (contentBlock.type) {
|
|
5260
5463
|
case "text":
|
|
5261
|
-
controller.enqueue(
|
|
5262
|
-
type: "text-end",
|
|
5263
|
-
id: String(value.index),
|
|
5264
|
-
...contentBlock.citations.length > 0 && {
|
|
5265
|
-
citations: contentBlock.citations.map((citation) => mapAnthropicCitation(citation, citationDocuments)),
|
|
5266
|
-
providerMetadata: { anthropic: { citations: contentBlock.citations } }
|
|
5267
|
-
}
|
|
5268
|
-
});
|
|
5464
|
+
controller.enqueue(createTextEnd(String(value.index), contentBlock.citations));
|
|
5269
5465
|
break;
|
|
5270
5466
|
case "reasoning":
|
|
5271
5467
|
controller.enqueue({
|
|
@@ -5325,7 +5521,11 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
5325
5521
|
const deltaType = value.delta.type;
|
|
5326
5522
|
switch (deltaType) {
|
|
5327
5523
|
case "text_delta":
|
|
5328
|
-
if (usesJsonResponseTool)
|
|
5524
|
+
if (usesJsonResponseTool) {
|
|
5525
|
+
const entry = heldBackTextByIndex.get(value.index);
|
|
5526
|
+
if (entry != null) entry.text += value.delta.text;
|
|
5527
|
+
return;
|
|
5528
|
+
}
|
|
5329
5529
|
controller.enqueue({
|
|
5330
5530
|
type: "text-delta",
|
|
5331
5531
|
id: String(value.index),
|
|
@@ -5386,6 +5586,7 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
5386
5586
|
const citation = value.delta.citation;
|
|
5387
5587
|
const contentBlock = contentBlocks[value.index];
|
|
5388
5588
|
if (contentBlock?.type === "text") contentBlock.citations.push(citation);
|
|
5589
|
+
heldBackTextByIndex.get(value.index)?.citations.push(citation);
|
|
5389
5590
|
if (citation.type === "web_search_result_location") fallbackWebCitations.push(citation);
|
|
5390
5591
|
else {
|
|
5391
5592
|
const source = createCitationSource(citation, citationDocuments, generateId);
|
|
@@ -5411,6 +5612,7 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
5411
5612
|
}
|
|
5412
5613
|
isMessageOpen = true;
|
|
5413
5614
|
activeMessageId = value.message.id;
|
|
5615
|
+
heldBackTextByIndex.clear();
|
|
5414
5616
|
usage.input_tokens = value.message.usage.input_tokens;
|
|
5415
5617
|
usage.cache_read_input_tokens = value.message.usage.cache_read_input_tokens ?? 0;
|
|
5416
5618
|
usage.cache_creation_input_tokens = value.message.usage.cache_creation_input_tokens ?? 0;
|
|
@@ -5531,6 +5733,20 @@ var AnthropicLanguageModel = class AnthropicLanguageModel {
|
|
|
5531
5733
|
if (source) controller.enqueue(source);
|
|
5532
5734
|
}
|
|
5533
5735
|
fallbackWebCitations.length = 0;
|
|
5736
|
+
if (!isJsonResponseFromTool && !isContinuationStopReason(finishReason.raw)) for (const { id, text, citations } of heldBackText) {
|
|
5737
|
+
if (text.length === 0) continue;
|
|
5738
|
+
controller.enqueue({
|
|
5739
|
+
type: "text-start",
|
|
5740
|
+
id
|
|
5741
|
+
});
|
|
5742
|
+
controller.enqueue({
|
|
5743
|
+
type: "text-delta",
|
|
5744
|
+
id,
|
|
5745
|
+
delta: text
|
|
5746
|
+
});
|
|
5747
|
+
controller.enqueue(createTextEnd(id, citations));
|
|
5748
|
+
}
|
|
5749
|
+
heldBackText.length = 0;
|
|
5534
5750
|
controller.enqueue({
|
|
5535
5751
|
type: "finish",
|
|
5536
5752
|
finishReason,
|
|
@@ -7133,7 +7349,7 @@ var AnthropicSkills = class {
|
|
|
7133
7349
|
};
|
|
7134
7350
|
//#endregion
|
|
7135
7351
|
//#region src/version.ts
|
|
7136
|
-
const VERSION = "4.0.
|
|
7352
|
+
const VERSION = "4.0.95";
|
|
7137
7353
|
//#endregion
|
|
7138
7354
|
//#region src/anthropic-provider.ts
|
|
7139
7355
|
const ANTHROPIC_API_URL = "https://api.anthropic.com";
|