feat(opencode): tolerate Anthropic thinking block binding (#46653)

This commit is contained in:
Aiden Cline 2026-09-01 14:32:26 -05:00 committed by GitHub
parent dc8753f82a
commit 3f39a329c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 934 additions and 24 deletions

View file

@ -296,7 +296,7 @@
"dependencies": {
"@ai-sdk/alibaba": "1.0.17",
"@ai-sdk/amazon-bedrock": "4.0.166",
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/anthropic": "3.0.111",
"@ai-sdk/azure": "3.0.88",
"@ai-sdk/cerebras": "2.0.41",
"@ai-sdk/cohere": "3.0.27",
@ -571,7 +571,7 @@
"@agentclientprotocol/sdk": "0.21.0",
"@ai-sdk/alibaba": "1.0.17",
"@ai-sdk/amazon-bedrock": "4.0.166",
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/anthropic": "3.0.111",
"@ai-sdk/azure": "3.0.88",
"@ai-sdk/cerebras": "2.0.60",
"@ai-sdk/cohere": "3.0.27",
@ -1066,10 +1066,12 @@
"gcp-metadata@8.1.2": "patches/gcp-metadata@8.1.2.patch",
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch",
"@ai-sdk/anthropic@3.0.111": "patches/@ai-sdk%2Fanthropic@3.0.111.patch",
"@ai-sdk/mistral@3.0.51": "patches/@ai-sdk%2Fmistral@3.0.51.patch",
"@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch",
"@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
"@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
"@ai-sdk/amazon-bedrock@4.0.166": "patches/@ai-sdk%2Famazon-bedrock@4.0.166.patch",
"@ai-sdk/groq@3.0.31": "patches/@ai-sdk%2Fgroq@3.0.31.patch",
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
"pacote@21.5.0": "patches/pacote@21.5.0.patch",
@ -1077,6 +1079,7 @@
"@ai-sdk/openai-compatible@2.0.41": "patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch",
},
"overrides": {
"@ai-sdk/anthropic": "3.0.111",
"@opentui/core": "catalog:",
"@opentui/keymap": "catalog:",
"@opentui/solid": "catalog:",
@ -1170,7 +1173,7 @@
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.166", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.115", "@ai-sdk/openai": "3.0.105", "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.50", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-HzzQb+ks+WmRcnnT9uBdJAxaqSXz3CWgmLSe9hePAkELPzTl/nAIJh2fb2+UsTD0n9OzZfBb25k68CIxraKkoA=="],
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.82", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-WKKou2wbhGGYV8PSALAPyV2YY4nfCqCPkyBzYtJtDA9yCcIFwsbtkTNgg7bqtLCVzeEsY7wwxRoCWy+EMfrw/A=="],
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.111", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.46" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-atgBW8jZPr/KuaKX5FvDIHuXBI8VCol6kVeoD4P0657+VXR73QsLogXQVN/Zt5FHtq9WzpdIZseCJiXPqkgwwA=="],
"@ai-sdk/azure": ["@ai-sdk/azure@3.0.88", "", { "dependencies": { "@ai-sdk/deepseek": "2.0.47", "@ai-sdk/openai": "3.0.84", "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RRjZkB1lYplh8dpBarnvkl1j7sYLHsyXua7erL3oNcMK7fHcl4bPO5C7iQhD1O/DqD/zCceDifnege1s+8yEvw=="],
@ -5626,8 +5629,6 @@
"@ai-sdk/alibaba/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.115", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.50" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-S1oAUCVaB2Fr6LtMDfa9EmVlDVczpRodYc3IKdLD2z4r0s/pX+zwjqlhiwhS1FsCS2jVx8EnSyBtuPuOzF094A=="],
"@ai-sdk/amazon-bedrock/@ai-sdk/openai": ["@ai-sdk/openai@3.0.105", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.50" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-umx95F8gqGuhPdoW+4ofq83fuSN6aMHwISxvY6dZU51Iix5ZKId0FNru+0FQeu+xfFUrVNmf3vYQNc2FLN85xA=="],
"@ai-sdk/amazon-bedrock/@ai-sdk/provider": ["@ai-sdk/provider@3.0.15", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-XeZW1CcDF2GMbH4wejW6xBRI2QCOgnkVYUnxoeDadB1mf85riL2bMUeDoh+6gJ/r4mjNfzUPW8OjLjvwTP0u1Q=="],
@ -5638,9 +5639,9 @@
"@ai-sdk/amazon-bedrock/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
"@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="],
"@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@3.0.15", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-XeZW1CcDF2GMbH4wejW6xBRI2QCOgnkVYUnxoeDadB1mf85riL2bMUeDoh+6gJ/r4mjNfzUPW8OjLjvwTP0u1Q=="],
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.46", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8", "undici": "^6.28.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-tEtld97plCFiYevsJuOkGkeuhQndeMWFBVrJS4AjnbD5AqrNSXRCe0p+BZ3Cju/sxDeeZ9ym3q9YUV8fASA7aQ=="],
"@ai-sdk/azure/@ai-sdk/openai": ["@ai-sdk/openai@3.0.84", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cmgbeJL0bbY0yTJH4/AdmP5E7MjWRL9G8UdhIi0JlV/So03o82ORJofW8OzwCZPTORVQblFbpZXYGDcUd9NdUQ=="],
@ -5676,8 +5677,6 @@
"@ai-sdk/google/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
"@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.110", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.45" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-rNkamQCeAUOUGr5Npg5pXZyYFH4fS1U6Mbdy3dF/NNBEI3D2Chc/ruRrwNegP0gfpX3cllP3O4jSibGBbWPZ7A=="],
"@ai-sdk/google-vertex/@ai-sdk/google": ["@ai-sdk/google@3.0.108", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.45" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kwvYpRNghqt0VRKE7Hx1UWZQCUJJFqUITj24baxy+ApS0Hru0PkBJHD75a36Wc+e6e+wHcKR2MconTeJiBZigA=="],
"@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.67", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.45" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-glcEJC2mBXJKj7joFI0fRhcbdDYKTBgXMPcT6Vcnlym67tTzuNG9pFx3zblxVv8TdOxhojJja5zGG19yeGJxuA=="],
@ -6160,8 +6159,6 @@
"ai-gateway-provider/@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.153", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.110", "@ai-sdk/openai": "3.0.96", "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.45", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iEXrLgWylCHJmznqlKLU3CqRh8UWibv+illrwmsk136FVBBvyXiGnpQrI1pGWCScVLQjBQSFQu7GJDkUEomf/A=="],
"ai-gateway-provider/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.110", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.45" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-rNkamQCeAUOUGr5Npg5pXZyYFH4fS1U6Mbdy3dF/NNBEI3D2Chc/ruRrwNegP0gfpX3cllP3O4jSibGBbWPZ7A=="],
"ai-gateway-provider/@ai-sdk/cerebras": ["@ai-sdk/cerebras@2.0.60", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.54", "@ai-sdk/provider": "3.0.12", "@ai-sdk/provider-utils": "4.0.33" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Rnok3cThg6awBwaDSyiZpgRpbV7pqxGYrA89LODCo5cuEHeP2h0AM0lLHP7zIkclAdXfOm4wldKi/S2T/DGCOw=="],
"ai-gateway-provider/@ai-sdk/cohere": ["@ai-sdk/cohere@3.0.54", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@ai-sdk/provider-utils": "4.0.45" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cXLjIsSzUriPHe704IH6d+ipJ/OvczTB700p9Zma7DPgQzvxG/diyr8q/2LEsbTRiTopiKhky8dn1PJNQcJToQ=="],
@ -6576,6 +6573,8 @@
"@ai-sdk/anthropic/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@ai-sdk/anthropic/@ai-sdk/provider-utils/undici": ["undici@6.28.0", "", {}, "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA=="],
"@ai-sdk/azure/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@ai-sdk/cerebras/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
@ -6984,10 +6983,6 @@
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@3.0.15", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-XeZW1CcDF2GMbH4wejW6xBRI2QCOgnkVYUnxoeDadB1mf85riL2bMUeDoh+6gJ/r4mjNfzUPW8OjLjvwTP0u1Q=="],
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.45", "", { "dependencies": { "@ai-sdk/provider": "3.0.15", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8", "undici": "^5.29.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7u5B/E2uZmU65SlJhhQGFHZwRCN0xOz4HHtFc4sEGV9PHbX3fGiEiZBpc/SABay1dGeJgK3VD60rvLGoWdWPXA=="],
"ai-gateway-provider/@ai-sdk/cerebras/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.54", "", { "dependencies": { "@ai-sdk/provider": "3.0.12", "@ai-sdk/provider-utils": "4.0.33" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-OyXt0zK8y2/ZIyWlbxTv2r1M7AK227S+Gl4BYOEF42q0wz1n5m4fwR8L4Fy/MQ4Ho6xje47MPsFcRdIqIyP6Rw=="],
"ai-gateway-provider/@ai-sdk/cerebras/@ai-sdk/provider": ["@ai-sdk/provider@3.0.12", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-sj9DWTJ2Ze0WR9qsiOPqoqzNx3OxL6iMxHImbhvoe9qOspekbzxNDMiJ4TIGfYHYh9w4OmBjz3prvqhzTi96+Q=="],
@ -7434,10 +7429,6 @@
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider-utils/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
"ai-gateway-provider/@ai-sdk/cerebras/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"ai-gateway-provider/@ai-sdk/cohere/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],

View file

@ -137,6 +137,7 @@
"electron"
],
"overrides": {
"@ai-sdk/anthropic": "3.0.111",
"@opentui/core": "catalog:",
"@opentui/keymap": "catalog:",
"@opentui/solid": "catalog:",
@ -160,6 +161,8 @@
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch",
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch",
"@ai-sdk/openai-compatible@2.0.41": "patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch",
"@ai-sdk/groq@3.0.31": "patches/@ai-sdk%2Fgroq@3.0.31.patch"
"@ai-sdk/groq@3.0.31": "patches/@ai-sdk%2Fgroq@3.0.31.patch",
"@ai-sdk/anthropic@3.0.111": "patches/@ai-sdk%2Fanthropic@3.0.111.patch",
"@ai-sdk/amazon-bedrock@4.0.166": "patches/@ai-sdk%2Famazon-bedrock@4.0.166.patch"
}
}

View file

@ -63,7 +63,7 @@
"dependencies": {
"@ai-sdk/alibaba": "1.0.17",
"@ai-sdk/amazon-bedrock": "4.0.166",
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/anthropic": "3.0.111",
"@ai-sdk/azure": "3.0.88",
"@ai-sdk/cerebras": "2.0.41",
"@ai-sdk/cohere": "3.0.27",

View file

@ -57,7 +57,7 @@
"@agentclientprotocol/sdk": "0.21.0",
"@ai-sdk/alibaba": "1.0.17",
"@ai-sdk/amazon-bedrock": "4.0.166",
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/anthropic": "3.0.111",
"@ai-sdk/azure": "3.0.88",
"@ai-sdk/cerebras": "2.0.60",
"@ai-sdk/cohere": "3.0.27",

View file

@ -684,6 +684,41 @@ function anthropicOmitsThinking(apiId: string) {
return anthropicUsesModernAdaptiveThinking(apiId)
}
// Opus 5, Sonnet 5, Fable 5.x, and Mythos 5.x think without a `thinking` parameter.
function anthropicThinksByDefault(apiId: string) {
const version = /claude-(?:[a-z]+-)?(\d+)(?:[.-](\d{1,2}))?(?:[.@-]|$)/i.exec(apiId)
if (!version) return false
return Number(version[1]) >= 5
}
// Fable 5.1 binds each thinking signature to the system prompt, tool list, and
// messages above it, and rejects the request when any of that changes. opencode
// re-renders parts of that prefix between turns (system prompt, tools, compaction),
// so ask the API to drop the affected blocks instead of failing the request.
// Models that do not run the check accept the field, so it is safe on every Claude.
// The patched AI SDK adds the thinking-binding-controls beta whenever it is set.
const ANTHROPIC_BLOCK_BINDING = { prefixMismatchBehavior: "drop_block" }
function anthropicBlockBinding(model: Provider.Model, options: { [x: string]: any }) {
if (!model.api.id.toLowerCase().includes("claude")) return options
const byDefault = anthropicThinksByDefault(model.api.id)
switch (model.api.npm) {
case "@ai-sdk/anthropic":
case "@ai-sdk/google-vertex/anthropic": {
const thinking = options.thinking ?? (byDefault ? { type: "adaptive" } : undefined)
if (!thinking || (thinking.type !== "adaptive" && thinking.type !== "enabled")) return options
return { ...options, thinking: { ...thinking, blockBinding: ANTHROPIC_BLOCK_BINDING } }
}
case "@ai-sdk/amazon-bedrock": {
const reasoningConfig = options.reasoningConfig ?? (byDefault ? { type: "adaptive" } : undefined)
if (!reasoningConfig || (reasoningConfig.type !== "adaptive" && reasoningConfig.type !== "enabled"))
return options
return { ...options, reasoningConfig: { ...reasoningConfig, blockBinding: ANTHROPIC_BLOCK_BINDING } }
}
}
return options
}
function googleThinkingLevelEfforts(apiId: string) {
const id = apiId.toLowerCase()
if (!id.includes("gemini-3")) return ["low", "high"]
@ -1363,7 +1398,7 @@ export function providerOptions(model: Provider.Model, options: { [x: string]: a
usesOpenAIReasoningGate &&
(model.capabilities.reasoning || options.reasoningEffort !== undefined || options.reasoningSummary !== undefined)
? { ...options, forceReasoning: true }
: options
: anthropicBlockBinding(model, options)
if (model.api.npm === "@ai-sdk/gateway") {
// Gateway providerOptions are split across two namespaces:

View file

@ -435,6 +435,20 @@ const layer = Layer.effect(
case "step-finish": {
const completedSnapshot = yield* snapshot.track()
yield* Effect.forEach(Object.keys(ctx.reasoningMap), finishReasoning)
// Anthropic reports thinking blocks it removed before the model saw the
// prompt. Prefix mismatches mean opencode changed history behind a signed
// block; log them so the churn can be tracked down.
const dropped = isRecord(value.providerMetadata?.anthropic)
? value.providerMetadata.anthropic.inputTransformations
: undefined
if (Array.isArray(dropped) && dropped.length > 0) {
yield* Effect.logWarning("thinking blocks dropped by provider", {
sessionID: ctx.sessionID,
messageID: ctx.assistantMessage.id,
model: ctx.model.id,
transformations: JSON.stringify(dropped),
})
}
const usage = Session.getUsage({
model: ctx.model,
usage: value.usage ?? new Usage({}),

View file

@ -7,6 +7,8 @@ import { ModelV2 } from "@opencode-ai/core/model"
import { ModelsDev } from "@opencode-ai/core/models-dev"
import { generateText, jsonSchema, type ModelMessage } from "ai"
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock"
import { createAnthropic } from "@ai-sdk/anthropic"
import { createVertexAnthropic } from "@ai-sdk/google-vertex/anthropic"
describe("ProviderTransform.options - setCacheKey", () => {
const sessionID = "test-session-123"
@ -845,6 +847,199 @@ describe("ProviderTransform.providerOptions", () => {
})
})
describe("anthropic thinking block binding", () => {
const binding = { prefixMismatchBehavior: "drop_block" }
const claude = (npm: string, id: string) =>
createModel({ providerID: "custom", api: { id, url: "https://example.com", npm } })
test("adds blockBinding to explicit adaptive thinking on @ai-sdk/anthropic", () => {
const model = claude("@ai-sdk/anthropic", "claude-opus-4-7")
expect(ProviderTransform.providerOptions(model, { thinking: { type: "adaptive" }, effort: "high" })).toEqual({
anthropic: { thinking: { type: "adaptive", blockBinding: binding }, effort: "high" },
})
})
test("adds blockBinding to explicit enabled thinking", () => {
const model = claude("@ai-sdk/anthropic", "claude-sonnet-4-5")
expect(ProviderTransform.providerOptions(model, { thinking: { type: "enabled", budgetTokens: 4000 } })).toEqual({
anthropic: { thinking: { type: "enabled", budgetTokens: 4000, blockBinding: binding } },
})
})
test("injects adaptive thinking for models that think by default when no variant is set", () => {
for (const id of ["claude-fable-5-1", "claude-mythos-5-1", "claude-opus-5", "claude-sonnet-5"]) {
const model = claude("@ai-sdk/anthropic", id)
expect(ProviderTransform.providerOptions(model, {})).toEqual({
anthropic: { thinking: { type: "adaptive", blockBinding: binding } },
})
}
})
test("does not inject thinking for models that are off by default", () => {
for (const id of ["claude-opus-4-7", "claude-opus-4-5", "claude-sonnet-4-6", "claude-haiku-4-5"]) {
const model = claude("@ai-sdk/anthropic", id)
expect(ProviderTransform.providerOptions(model, {})).toEqual({ anthropic: {} })
}
})
test("leaves disabled thinking alone", () => {
const model = claude("@ai-sdk/anthropic", "claude-sonnet-5")
expect(ProviderTransform.providerOptions(model, { thinking: { type: "disabled" } })).toEqual({
anthropic: { thinking: { type: "disabled" } },
})
})
test("applies to vertex anthropic", () => {
const model = claude("@ai-sdk/google-vertex/anthropic", "claude-fable-5-1")
expect(ProviderTransform.providerOptions(model, { thinking: { type: "adaptive" }, effort: "max" })).toEqual({
anthropic: { thinking: { type: "adaptive", blockBinding: binding }, effort: "max" },
})
})
test("applies to bedrock reasoningConfig", () => {
const model = claude("@ai-sdk/amazon-bedrock", "us.anthropic.claude-fable-5-1-v1:0")
expect(
ProviderTransform.providerOptions(model, { reasoningConfig: { type: "adaptive", maxReasoningEffort: "high" } }),
).toEqual({
bedrock: { reasoningConfig: { type: "adaptive", maxReasoningEffort: "high", blockBinding: binding } },
})
expect(ProviderTransform.providerOptions(model, {})).toEqual({
bedrock: { reasoningConfig: { type: "adaptive", blockBinding: binding } },
})
})
test("does not touch bedrock non-anthropic models", () => {
const model = claude("@ai-sdk/amazon-bedrock", "amazon.nova-pro-v1:0")
expect(ProviderTransform.providerOptions(model, { reasoningConfig: { type: "enabled" } })).toEqual({
bedrock: { reasoningConfig: { type: "enabled" } },
})
})
test("does not touch non-claude models on anthropic-compatible transports", () => {
const model = claude("@ai-sdk/anthropic", "kimi-k2-thinking")
expect(ProviderTransform.providerOptions(model, { thinking: { type: "adaptive" } })).toEqual({
anthropic: { thinking: { type: "adaptive" } },
})
})
test("reaches the anthropic wire as block_binding plus beta header", async () => {
const model = claude("@ai-sdk/anthropic", "claude-fable-5-1")
let sent: { headers: Headers; body: any } | undefined
const provider = createAnthropic({
apiKey: "test-key",
fetch: Object.assign(
async (...args: Parameters<typeof fetch>) => {
sent = { headers: new Headers(args[1]?.headers), body: JSON.parse(String(args[1]?.body)) }
return Response.json({
type: "message",
id: "msg_1",
model: "claude-fable-5-1",
role: "assistant",
content: [{ type: "text", text: "ok" }],
stop_reason: "end_turn",
usage: { input_tokens: 1, output_tokens: 1 },
input_transformations: [
{ type: "thinking_dropped", path: "messages.1.content.0", reason: "prefix_binding_mismatch" },
],
})
},
{ preconnect: () => undefined },
),
})
const result = await generateText({
model: provider("claude-fable-5-1"),
prompt: "hi",
providerOptions: ProviderTransform.providerOptions(model, {}),
})
expect(sent?.body.thinking).toEqual({
type: "adaptive",
block_binding: { prefix_mismatch_behavior: "drop_block" },
})
expect(sent?.headers.get("anthropic-beta")?.split(",")).toContain("thinking-binding-controls-2026-08-01")
expect(result.providerMetadata?.anthropic?.inputTransformations).toEqual([
{ type: "thinking_dropped", path: "messages.1.content.0", reason: "prefix_binding_mismatch" },
])
})
test("reaches the vertex anthropic wire as block_binding plus beta header", async () => {
const model = claude("@ai-sdk/google-vertex/anthropic", "claude-fable-5-1")
let sent: { url: string; headers: Headers; body: any } | undefined
const provider = createVertexAnthropic({
project: "test-project",
location: "global",
generateAuthToken: async () => "test-token",
fetch: Object.assign(
async (...args: Parameters<typeof fetch>) => {
sent = {
url: String(args[0]),
headers: new Headers(args[1]?.headers),
body: JSON.parse(String(args[1]?.body)),
}
return Response.json({
type: "message",
id: "msg_1",
model: "claude-fable-5-1",
role: "assistant",
content: [{ type: "text", text: "ok" }],
stop_reason: "end_turn",
usage: { input_tokens: 1, output_tokens: 1 },
})
},
{ preconnect: () => undefined },
),
})
await generateText({
model: provider("claude-fable-5-1"),
prompt: "hi",
providerOptions: ProviderTransform.providerOptions(model, {}),
})
// Same wire shape Anthropic's own Vertex SDK produces: rawPredict URL, model moved
// out of the body, anthropic_version added, betas carried in the anthropic-beta header.
expect(sent?.url).toBe(
"https://aiplatform.googleapis.com/v1/projects/test-project/locations/global/publishers/anthropic/models/claude-fable-5-1:rawPredict",
)
expect(sent?.body.model).toBeUndefined()
expect(sent?.body.anthropic_version).toBe("vertex-2023-10-16")
expect(sent?.body.thinking).toEqual({
type: "adaptive",
block_binding: { prefix_mismatch_behavior: "drop_block" },
})
expect(sent?.headers.get("anthropic-beta")?.split(",")).toContain("thinking-binding-controls-2026-08-01")
})
test("reaches the bedrock wire as additionalModelRequestFields", async () => {
const model = claude("@ai-sdk/amazon-bedrock", "us.anthropic.claude-fable-5-1-v1:0")
let body: any
const provider = createAmazonBedrock({
apiKey: "test-key",
region: "us-east-1",
fetch: Object.assign(
async (...args: Parameters<typeof fetch>) => {
body = JSON.parse(String(args[1]?.body))
return Response.json({
output: { message: { role: "assistant", content: [{ text: "ok" }] } },
stopReason: "end_turn",
usage: { inputTokens: 1, outputTokens: 1, totalTokens: 2 },
})
},
{ preconnect: () => undefined },
),
})
await generateText({
model: provider("us.anthropic.claude-fable-5-1-v1:0"),
prompt: "hi",
providerOptions: ProviderTransform.providerOptions(model, {
reasoningConfig: { type: "adaptive", maxReasoningEffort: "high" },
}),
})
expect(body.additionalModelRequestFields.thinking).toEqual({
type: "adaptive",
block_binding: { prefix_mismatch_behavior: "drop_block" },
})
expect(body.additionalModelRequestFields.anthropic_beta).toContain("thinking-binding-controls-2026-08-01")
})
})
test("forces reasoning for explicit effort even when model is not marked reasoning-capable", () => {
const model = createModel({
capabilities: {

View file

@ -0,0 +1,144 @@
diff --git a/dist/index.d.mts b/dist/index.d.mts
index d194ae227fd1223ba44c8c5157b1bb72b1bab273..2e046db0a365c27659ffcec08782c7c26845c1fa 100644
--- a/dist/index.d.mts
+++ b/dist/index.d.mts
@@ -61,6 +61,12 @@ declare const amazonBedrockLanguageModelOptions: z.ZodObject<{
omitted: "omitted";
summarized: "summarized";
}>>;
+ blockBinding: z.ZodOptional<z.ZodObject<{
+ prefixMismatchBehavior: z.ZodEnum<{
+ error: "error";
+ drop_block: "drop_block";
+ }>;
+ }, z.core.$strip>>;
}, z.core.$strip>>;
anthropicBeta: z.ZodOptional<z.ZodArray<z.ZodString>>;
serviceTier: z.ZodOptional<z.ZodEnum<{
diff --git a/dist/index.d.ts b/dist/index.d.ts
index d194ae227fd1223ba44c8c5157b1bb72b1bab273..2e046db0a365c27659ffcec08782c7c26845c1fa 100644
--- a/dist/index.d.ts
+++ b/dist/index.d.ts
@@ -61,6 +61,12 @@ declare const amazonBedrockLanguageModelOptions: z.ZodObject<{
omitted: "omitted";
summarized: "summarized";
}>>;
+ blockBinding: z.ZodOptional<z.ZodObject<{
+ prefixMismatchBehavior: z.ZodEnum<{
+ error: "error";
+ drop_block: "drop_block";
+ }>;
+ }, z.core.$strip>>;
}, z.core.$strip>>;
anthropicBeta: z.ZodOptional<z.ZodArray<z.ZodString>>;
serviceTier: z.ZodOptional<z.ZodEnum<{
diff --git a/dist/index.js b/dist/index.js
index 2047c91971c23f72dd3cd0c069614f37a30e45f3..9e9ccc26b711eb9ad2722bf1dd4b2e931e528776 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -95,7 +95,10 @@ var amazonBedrockLanguageModelOptions = import_v4.z.object({
]).optional(),
budgetTokens: import_v4.z.number().optional(),
maxReasoningEffort: import_v4.z.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
- display: import_v4.z.enum(["omitted", "summarized"]).optional()
+ display: import_v4.z.enum(["omitted", "summarized"]).optional(),
+ blockBinding: import_v4.z.object({
+ prefixMismatchBehavior: import_v4.z.enum(["error", "drop_block"])
+ }).optional()
}).optional(),
/**
* Anthropic beta features to enable
@@ -1020,6 +1023,10 @@ var BedrockChatLanguageModel = class {
...additionalTools
};
}
+ const thinkingBlockBinding = isAnthropicModel && isThinkingEnabled ? (bedrockOptions.reasoningConfig == null ? void 0 : bedrockOptions.reasoningConfig.blockBinding) : void 0;
+ if (thinkingBlockBinding != null) {
+ betas.add("thinking-binding-controls-2026-08-01");
+ }
if (betas.size > 0 || bedrockOptions.anthropicBeta) {
const existingBetas = (_g = bedrockOptions.anthropicBeta) != null ? _g : [];
const mergedBetas = betas.size > 0 ? [...existingBetas, ...Array.from(betas)] : existingBetas;
@@ -1050,7 +1057,12 @@ var BedrockChatLanguageModel = class {
...bedrockOptions.additionalModelRequestFields,
thinking: {
type: "enabled",
- budget_tokens: thinkingBudget
+ budget_tokens: thinkingBudget,
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
};
} else if (thinkingType === "adaptive") {
@@ -1058,7 +1070,12 @@ var BedrockChatLanguageModel = class {
...bedrockOptions.additionalModelRequestFields,
thinking: {
type: "adaptive",
- ...thinkingDisplay != null && { display: thinkingDisplay }
+ ...thinkingDisplay != null && { display: thinkingDisplay },
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
};
}
diff --git a/dist/index.mjs b/dist/index.mjs
index 5a669504cb3b21f20788956bc9c22529c1498c35..000114dfe76cba25ddfe693f042232810026c229 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -84,7 +84,10 @@ var amazonBedrockLanguageModelOptions = z.object({
]).optional(),
budgetTokens: z.number().optional(),
maxReasoningEffort: z.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
- display: z.enum(["omitted", "summarized"]).optional()
+ display: z.enum(["omitted", "summarized"]).optional(),
+ blockBinding: z.object({
+ prefixMismatchBehavior: z.enum(["error", "drop_block"])
+ }).optional()
}).optional(),
/**
* Anthropic beta features to enable
@@ -1024,6 +1027,10 @@ var BedrockChatLanguageModel = class {
...additionalTools
};
}
+ const thinkingBlockBinding = isAnthropicModel && isThinkingEnabled ? (bedrockOptions.reasoningConfig == null ? void 0 : bedrockOptions.reasoningConfig.blockBinding) : void 0;
+ if (thinkingBlockBinding != null) {
+ betas.add("thinking-binding-controls-2026-08-01");
+ }
if (betas.size > 0 || bedrockOptions.anthropicBeta) {
const existingBetas = (_g = bedrockOptions.anthropicBeta) != null ? _g : [];
const mergedBetas = betas.size > 0 ? [...existingBetas, ...Array.from(betas)] : existingBetas;
@@ -1054,7 +1061,12 @@ var BedrockChatLanguageModel = class {
...bedrockOptions.additionalModelRequestFields,
thinking: {
type: "enabled",
- budget_tokens: thinkingBudget
+ budget_tokens: thinkingBudget,
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
};
} else if (thinkingType === "adaptive") {
@@ -1062,7 +1074,12 @@ var BedrockChatLanguageModel = class {
...bedrockOptions.additionalModelRequestFields,
thinking: {
type: "adaptive",
- ...thinkingDisplay != null && { display: thinkingDisplay }
+ ...thinkingDisplay != null && { display: thinkingDisplay },
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
};
}

View file

@ -0,0 +1,528 @@
diff --git a/dist/index.d.mts b/dist/index.d.mts
index a66d061f466c89a57efec33f37b7daabaaba2892..15f1b2aca0c0b43e5e1f8baddd2669c074912d18 100644
--- a/dist/index.d.mts
+++ b/dist/index.d.mts
@@ -211,9 +211,21 @@ declare const anthropicLanguageModelOptions: z.ZodObject<{
omitted: "omitted";
summarized: "summarized";
}>>;
+ blockBinding: z.ZodOptional<z.ZodObject<{
+ prefixMismatchBehavior: z.ZodEnum<{
+ error: "error";
+ drop_block: "drop_block";
+ }>;
+ }, z.core.$strip>>;
}, z.core.$strip>, z.ZodObject<{
type: z.ZodLiteral<"enabled">;
budgetTokens: z.ZodOptional<z.ZodNumber>;
+ blockBinding: z.ZodOptional<z.ZodObject<{
+ prefixMismatchBehavior: z.ZodEnum<{
+ error: "error";
+ drop_block: "drop_block";
+ }>;
+ }, z.core.$strip>>;
}, z.core.$strip>, z.ZodObject<{
type: z.ZodLiteral<"disabled">;
}, z.core.$strip>]>>;
diff --git a/dist/index.d.ts b/dist/index.d.ts
index a66d061f466c89a57efec33f37b7daabaaba2892..15f1b2aca0c0b43e5e1f8baddd2669c074912d18 100644
--- a/dist/index.d.ts
+++ b/dist/index.d.ts
@@ -211,9 +211,21 @@ declare const anthropicLanguageModelOptions: z.ZodObject<{
omitted: "omitted";
summarized: "summarized";
}>>;
+ blockBinding: z.ZodOptional<z.ZodObject<{
+ prefixMismatchBehavior: z.ZodEnum<{
+ error: "error";
+ drop_block: "drop_block";
+ }>;
+ }, z.core.$strip>>;
}, z.core.$strip>, z.ZodObject<{
type: z.ZodLiteral<"enabled">;
budgetTokens: z.ZodOptional<z.ZodNumber>;
+ blockBinding: z.ZodOptional<z.ZodObject<{
+ prefixMismatchBehavior: z.ZodEnum<{
+ error: "error";
+ drop_block: "drop_block";
+ }>;
+ }, z.core.$strip>>;
}, z.core.$strip>, z.ZodObject<{
type: z.ZodLiteral<"disabled">;
}, z.core.$strip>]>>;
diff --git a/dist/index.js b/dist/index.js
index 88c1aa865339baa320cf80ec543bed865825bc61..5006e82b0edd9676d1650cc94ecb573a2810acce 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -85,6 +85,13 @@ var anthropicMessagesResponseSchema = (0, import_provider_utils2.lazySchema)(
type: import_v42.z.literal("message"),
id: import_v42.z.string().nullish(),
model: import_v42.z.string().nullish(),
+ input_transformations: import_v42.z.array(
+ import_v42.z.looseObject({
+ type: import_v42.z.string(),
+ path: import_v42.z.string().nullish(),
+ reason: import_v42.z.string().nullish()
+ })
+ ).nullish(),
content: import_v42.z.array(
import_v42.z.discriminatedUnion("type", [
import_v42.z.object({
@@ -424,6 +431,13 @@ var anthropicMessagesChunkSchema = (0, import_provider_utils2.lazySchema)(
id: import_v42.z.string().nullish(),
model: import_v42.z.string().nullish(),
role: import_v42.z.string().nullish(),
+ input_transformations: import_v42.z.array(
+ import_v42.z.looseObject({
+ type: import_v42.z.string(),
+ path: import_v42.z.string().nullish(),
+ reason: import_v42.z.string().nullish()
+ })
+ ).nullish(),
usage: import_v42.z.looseObject({
input_tokens: import_v42.z.number(),
cache_creation_input_tokens: import_v42.z.number().nullish(),
@@ -923,12 +937,18 @@ var anthropicLanguageModelOptions = import_v43.z.object({
* - `"omitted"`: Thinking blocks are present but text is empty (default for Opus 4.7+).
* - `"summarized"`: Thinking content is returned. Required to see reasoning output.
*/
- display: import_v43.z.enum(["omitted", "summarized"]).optional()
+ display: import_v43.z.enum(["omitted", "summarized"]).optional(),
+ blockBinding: import_v43.z.object({
+ prefixMismatchBehavior: import_v43.z.enum(["error", "drop_block"])
+ }).optional()
}),
import_v43.z.object({
/** for models before Opus 4.6, except Sonnet 4.6 still supports it */
type: import_v43.z.literal("enabled"),
- budgetTokens: import_v43.z.number().optional()
+ budgetTokens: import_v43.z.number().optional(),
+ blockBinding: import_v43.z.object({
+ prefixMismatchBehavior: import_v43.z.enum(["error", "drop_block"])
+ }).optional()
}),
import_v43.z.object({
type: import_v43.z.literal("disabled")
@@ -3568,6 +3588,7 @@ var AnthropicMessagesLanguageModel = class {
const sendThinking = isThinking || thinkingType === "disabled";
let thinkingBudget = thinkingType === "enabled" ? (_g = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _g.budgetTokens : void 0;
const thinkingDisplay = thinkingType === "adaptive" ? (_h = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _h.display : void 0;
+ const thinkingBlockBinding = isThinking ? (anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : anthropicOptions.thinking.blockBinding : void 0;
const maxTokens = maxOutputTokens != null ? maxOutputTokens : maxOutputTokensForModel;
const baseArgs = {
// model id:
@@ -3583,7 +3604,12 @@ var AnthropicMessagesLanguageModel = class {
thinking: {
type: thinkingType,
...thinkingBudget != null && { budget_tokens: thinkingBudget },
- ...thinkingDisplay != null && { display: thinkingDisplay }
+ ...thinkingDisplay != null && { display: thinkingDisplay },
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
},
...((anthropicOptions == null ? void 0 : anthropicOptions.effort) || (anthropicOptions == null ? void 0 : anthropicOptions.taskBudget) || useStructuredOutput && (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null) && {
@@ -3798,6 +3824,9 @@ var AnthropicMessagesLanguageModel = class {
} else if ((anthropicOptions == null ? void 0 : anthropicOptions.fallbacks) && anthropicOptions.fallbacks.length > 0) {
betas.add("server-side-fallback-2026-06-01");
}
+ if (thinkingBlockBinding != null) {
+ betas.add("thinking-binding-controls-2026-08-01");
+ }
const defaultEagerInputStreaming = stream && ((_j = anthropicOptions == null ? void 0 : anthropicOptions.toolStreaming) != null ? _j : true);
const {
tools: anthropicTools2,
@@ -4364,6 +4393,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens: (_a2 = response.usage.cache_creation_input_tokens) != null ? _a2 : null,
stopSequence: (_b2 = response.stop_sequence) != null ? _b2 : null,
...stopDetails != null ? { stopDetails } : {},
+ ...response.input_transformations != null ? { inputTransformations: response.input_transformations } : {},
iterations: response.usage.iterations ? response.usage.iterations.map(
(iter) => ({
type: iter.type,
@@ -4453,6 +4483,7 @@ var AnthropicMessagesLanguageModel = class {
let cacheCreationInputTokens = null;
let stopSequence = null;
let stopDetails = void 0;
+ let inputTransformations = void 0;
let container = null;
let isJsonResponseFromTool = false;
let isMessageOpen = false;
@@ -5111,6 +5142,9 @@ var AnthropicMessagesLanguageModel = class {
isMessageOpen = true;
activeMessageId = value.message.id;
usage.input_tokens = value.message.usage.input_tokens;
+ if (value.message.input_transformations != null) {
+ inputTransformations = value.message.input_transformations;
+ }
usage.cache_read_input_tokens = (_e = value.message.usage.cache_read_input_tokens) != null ? _e : 0;
usage.cache_creation_input_tokens = (_f = value.message.usage.cache_creation_input_tokens) != null ? _f : 0;
rawUsage = {
@@ -5231,6 +5265,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens,
stopSequence,
...stopDetails != null ? { stopDetails } : {},
+ ...inputTransformations != null ? { inputTransformations } : {},
iterations: usage.iterations ? usage.iterations.map(
(iter) => ({
type: iter.type,
diff --git a/dist/index.mjs b/dist/index.mjs
index 593b030c7f2adbe0cd38556b7a74f5ede6a5435e..1fa36ccb119715df3cd00976e479c679c66d2261 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -85,6 +85,13 @@ var anthropicMessagesResponseSchema = lazySchema2(
type: z2.literal("message"),
id: z2.string().nullish(),
model: z2.string().nullish(),
+ input_transformations: z2.array(
+ z2.looseObject({
+ type: z2.string(),
+ path: z2.string().nullish(),
+ reason: z2.string().nullish()
+ })
+ ).nullish(),
content: z2.array(
z2.discriminatedUnion("type", [
z2.object({
@@ -424,6 +431,13 @@ var anthropicMessagesChunkSchema = lazySchema2(
id: z2.string().nullish(),
model: z2.string().nullish(),
role: z2.string().nullish(),
+ input_transformations: z2.array(
+ z2.looseObject({
+ type: z2.string(),
+ path: z2.string().nullish(),
+ reason: z2.string().nullish()
+ })
+ ).nullish(),
usage: z2.looseObject({
input_tokens: z2.number(),
cache_creation_input_tokens: z2.number().nullish(),
@@ -923,12 +937,18 @@ var anthropicLanguageModelOptions = z3.object({
* - `"omitted"`: Thinking blocks are present but text is empty (default for Opus 4.7+).
* - `"summarized"`: Thinking content is returned. Required to see reasoning output.
*/
- display: z3.enum(["omitted", "summarized"]).optional()
+ display: z3.enum(["omitted", "summarized"]).optional(),
+ blockBinding: z3.object({
+ prefixMismatchBehavior: z3.enum(["error", "drop_block"])
+ }).optional()
}),
z3.object({
/** for models before Opus 4.6, except Sonnet 4.6 still supports it */
type: z3.literal("enabled"),
- budgetTokens: z3.number().optional()
+ budgetTokens: z3.number().optional(),
+ blockBinding: z3.object({
+ prefixMismatchBehavior: z3.enum(["error", "drop_block"])
+ }).optional()
}),
z3.object({
type: z3.literal("disabled")
@@ -3620,6 +3640,7 @@ var AnthropicMessagesLanguageModel = class {
const sendThinking = isThinking || thinkingType === "disabled";
let thinkingBudget = thinkingType === "enabled" ? (_g = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _g.budgetTokens : void 0;
const thinkingDisplay = thinkingType === "adaptive" ? (_h = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _h.display : void 0;
+ const thinkingBlockBinding = isThinking ? (anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : anthropicOptions.thinking.blockBinding : void 0;
const maxTokens = maxOutputTokens != null ? maxOutputTokens : maxOutputTokensForModel;
const baseArgs = {
// model id:
@@ -3635,7 +3656,12 @@ var AnthropicMessagesLanguageModel = class {
thinking: {
type: thinkingType,
...thinkingBudget != null && { budget_tokens: thinkingBudget },
- ...thinkingDisplay != null && { display: thinkingDisplay }
+ ...thinkingDisplay != null && { display: thinkingDisplay },
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
},
...((anthropicOptions == null ? void 0 : anthropicOptions.effort) || (anthropicOptions == null ? void 0 : anthropicOptions.taskBudget) || useStructuredOutput && (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null) && {
@@ -3850,6 +3876,9 @@ var AnthropicMessagesLanguageModel = class {
} else if ((anthropicOptions == null ? void 0 : anthropicOptions.fallbacks) && anthropicOptions.fallbacks.length > 0) {
betas.add("server-side-fallback-2026-06-01");
}
+ if (thinkingBlockBinding != null) {
+ betas.add("thinking-binding-controls-2026-08-01");
+ }
const defaultEagerInputStreaming = stream && ((_j = anthropicOptions == null ? void 0 : anthropicOptions.toolStreaming) != null ? _j : true);
const {
tools: anthropicTools2,
@@ -4416,6 +4445,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens: (_a2 = response.usage.cache_creation_input_tokens) != null ? _a2 : null,
stopSequence: (_b2 = response.stop_sequence) != null ? _b2 : null,
...stopDetails != null ? { stopDetails } : {},
+ ...response.input_transformations != null ? { inputTransformations: response.input_transformations } : {},
iterations: response.usage.iterations ? response.usage.iterations.map(
(iter) => ({
type: iter.type,
@@ -4505,6 +4535,7 @@ var AnthropicMessagesLanguageModel = class {
let cacheCreationInputTokens = null;
let stopSequence = null;
let stopDetails = void 0;
+ let inputTransformations = void 0;
let container = null;
let isJsonResponseFromTool = false;
let isMessageOpen = false;
@@ -5163,6 +5194,9 @@ var AnthropicMessagesLanguageModel = class {
isMessageOpen = true;
activeMessageId = value.message.id;
usage.input_tokens = value.message.usage.input_tokens;
+ if (value.message.input_transformations != null) {
+ inputTransformations = value.message.input_transformations;
+ }
usage.cache_read_input_tokens = (_e = value.message.usage.cache_read_input_tokens) != null ? _e : 0;
usage.cache_creation_input_tokens = (_f = value.message.usage.cache_creation_input_tokens) != null ? _f : 0;
rawUsage = {
@@ -5283,6 +5317,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens,
stopSequence,
...stopDetails != null ? { stopDetails } : {},
+ ...inputTransformations != null ? { inputTransformations } : {},
iterations: usage.iterations ? usage.iterations.map(
(iter) => ({
type: iter.type,
diff --git a/dist/internal/index.js b/dist/internal/index.js
index 701ca5a333d83d384f682667b9976b7f72b0de37..ce53d0c9fe5c00a092b0347b45d61d8ce9c3a79a 100644
--- a/dist/internal/index.js
+++ b/dist/internal/index.js
@@ -79,6 +79,13 @@ var anthropicMessagesResponseSchema = (0, import_provider_utils2.lazySchema)(
type: import_v42.z.literal("message"),
id: import_v42.z.string().nullish(),
model: import_v42.z.string().nullish(),
+ input_transformations: import_v42.z.array(
+ import_v42.z.looseObject({
+ type: import_v42.z.string(),
+ path: import_v42.z.string().nullish(),
+ reason: import_v42.z.string().nullish()
+ })
+ ).nullish(),
content: import_v42.z.array(
import_v42.z.discriminatedUnion("type", [
import_v42.z.object({
@@ -418,6 +425,13 @@ var anthropicMessagesChunkSchema = (0, import_provider_utils2.lazySchema)(
id: import_v42.z.string().nullish(),
model: import_v42.z.string().nullish(),
role: import_v42.z.string().nullish(),
+ input_transformations: import_v42.z.array(
+ import_v42.z.looseObject({
+ type: import_v42.z.string(),
+ path: import_v42.z.string().nullish(),
+ reason: import_v42.z.string().nullish()
+ })
+ ).nullish(),
usage: import_v42.z.looseObject({
input_tokens: import_v42.z.number(),
cache_creation_input_tokens: import_v42.z.number().nullish(),
@@ -917,12 +931,18 @@ var anthropicLanguageModelOptions = import_v43.z.object({
* - `"omitted"`: Thinking blocks are present but text is empty (default for Opus 4.7+).
* - `"summarized"`: Thinking content is returned. Required to see reasoning output.
*/
- display: import_v43.z.enum(["omitted", "summarized"]).optional()
+ display: import_v43.z.enum(["omitted", "summarized"]).optional(),
+ blockBinding: import_v43.z.object({
+ prefixMismatchBehavior: import_v43.z.enum(["error", "drop_block"])
+ }).optional()
}),
import_v43.z.object({
/** for models before Opus 4.6, except Sonnet 4.6 still supports it */
type: import_v43.z.literal("enabled"),
- budgetTokens: import_v43.z.number().optional()
+ budgetTokens: import_v43.z.number().optional(),
+ blockBinding: import_v43.z.object({
+ prefixMismatchBehavior: import_v43.z.enum(["error", "drop_block"])
+ }).optional()
}),
import_v43.z.object({
type: import_v43.z.literal("disabled")
@@ -3562,6 +3582,7 @@ var AnthropicMessagesLanguageModel = class {
const sendThinking = isThinking || thinkingType === "disabled";
let thinkingBudget = thinkingType === "enabled" ? (_g = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _g.budgetTokens : void 0;
const thinkingDisplay = thinkingType === "adaptive" ? (_h = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _h.display : void 0;
+ const thinkingBlockBinding = isThinking ? (anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : anthropicOptions.thinking.blockBinding : void 0;
const maxTokens = maxOutputTokens != null ? maxOutputTokens : maxOutputTokensForModel;
const baseArgs = {
// model id:
@@ -3577,7 +3598,12 @@ var AnthropicMessagesLanguageModel = class {
thinking: {
type: thinkingType,
...thinkingBudget != null && { budget_tokens: thinkingBudget },
- ...thinkingDisplay != null && { display: thinkingDisplay }
+ ...thinkingDisplay != null && { display: thinkingDisplay },
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
},
...((anthropicOptions == null ? void 0 : anthropicOptions.effort) || (anthropicOptions == null ? void 0 : anthropicOptions.taskBudget) || useStructuredOutput && (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null) && {
@@ -3792,6 +3818,9 @@ var AnthropicMessagesLanguageModel = class {
} else if ((anthropicOptions == null ? void 0 : anthropicOptions.fallbacks) && anthropicOptions.fallbacks.length > 0) {
betas.add("server-side-fallback-2026-06-01");
}
+ if (thinkingBlockBinding != null) {
+ betas.add("thinking-binding-controls-2026-08-01");
+ }
const defaultEagerInputStreaming = stream && ((_j = anthropicOptions == null ? void 0 : anthropicOptions.toolStreaming) != null ? _j : true);
const {
tools: anthropicTools2,
@@ -4358,6 +4387,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens: (_a2 = response.usage.cache_creation_input_tokens) != null ? _a2 : null,
stopSequence: (_b2 = response.stop_sequence) != null ? _b2 : null,
...stopDetails != null ? { stopDetails } : {},
+ ...response.input_transformations != null ? { inputTransformations: response.input_transformations } : {},
iterations: response.usage.iterations ? response.usage.iterations.map(
(iter) => ({
type: iter.type,
@@ -4447,6 +4477,7 @@ var AnthropicMessagesLanguageModel = class {
let cacheCreationInputTokens = null;
let stopSequence = null;
let stopDetails = void 0;
+ let inputTransformations = void 0;
let container = null;
let isJsonResponseFromTool = false;
let isMessageOpen = false;
@@ -5105,6 +5136,9 @@ var AnthropicMessagesLanguageModel = class {
isMessageOpen = true;
activeMessageId = value.message.id;
usage.input_tokens = value.message.usage.input_tokens;
+ if (value.message.input_transformations != null) {
+ inputTransformations = value.message.input_transformations;
+ }
usage.cache_read_input_tokens = (_e = value.message.usage.cache_read_input_tokens) != null ? _e : 0;
usage.cache_creation_input_tokens = (_f = value.message.usage.cache_creation_input_tokens) != null ? _f : 0;
rawUsage = {
@@ -5225,6 +5259,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens,
stopSequence,
...stopDetails != null ? { stopDetails } : {},
+ ...inputTransformations != null ? { inputTransformations } : {},
iterations: usage.iterations ? usage.iterations.map(
(iter) => ({
type: iter.type,
diff --git a/dist/internal/index.mjs b/dist/internal/index.mjs
index c11f29fa42a9ce6a5681d43c609020f1f4a616da..df7f7a01992a56826eb809e6cdfb1e50a87a1b90 100644
--- a/dist/internal/index.mjs
+++ b/dist/internal/index.mjs
@@ -69,6 +69,13 @@ var anthropicMessagesResponseSchema = lazySchema2(
type: z2.literal("message"),
id: z2.string().nullish(),
model: z2.string().nullish(),
+ input_transformations: z2.array(
+ z2.looseObject({
+ type: z2.string(),
+ path: z2.string().nullish(),
+ reason: z2.string().nullish()
+ })
+ ).nullish(),
content: z2.array(
z2.discriminatedUnion("type", [
z2.object({
@@ -408,6 +415,13 @@ var anthropicMessagesChunkSchema = lazySchema2(
id: z2.string().nullish(),
model: z2.string().nullish(),
role: z2.string().nullish(),
+ input_transformations: z2.array(
+ z2.looseObject({
+ type: z2.string(),
+ path: z2.string().nullish(),
+ reason: z2.string().nullish()
+ })
+ ).nullish(),
usage: z2.looseObject({
input_tokens: z2.number(),
cache_creation_input_tokens: z2.number().nullish(),
@@ -907,12 +921,18 @@ var anthropicLanguageModelOptions = z3.object({
* - `"omitted"`: Thinking blocks are present but text is empty (default for Opus 4.7+).
* - `"summarized"`: Thinking content is returned. Required to see reasoning output.
*/
- display: z3.enum(["omitted", "summarized"]).optional()
+ display: z3.enum(["omitted", "summarized"]).optional(),
+ blockBinding: z3.object({
+ prefixMismatchBehavior: z3.enum(["error", "drop_block"])
+ }).optional()
}),
z3.object({
/** for models before Opus 4.6, except Sonnet 4.6 still supports it */
type: z3.literal("enabled"),
- budgetTokens: z3.number().optional()
+ budgetTokens: z3.number().optional(),
+ blockBinding: z3.object({
+ prefixMismatchBehavior: z3.enum(["error", "drop_block"])
+ }).optional()
}),
z3.object({
type: z3.literal("disabled")
@@ -3604,6 +3624,7 @@ var AnthropicMessagesLanguageModel = class {
const sendThinking = isThinking || thinkingType === "disabled";
let thinkingBudget = thinkingType === "enabled" ? (_g = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _g.budgetTokens : void 0;
const thinkingDisplay = thinkingType === "adaptive" ? (_h = anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : _h.display : void 0;
+ const thinkingBlockBinding = isThinking ? (anthropicOptions == null ? void 0 : anthropicOptions.thinking) == null ? void 0 : anthropicOptions.thinking.blockBinding : void 0;
const maxTokens = maxOutputTokens != null ? maxOutputTokens : maxOutputTokensForModel;
const baseArgs = {
// model id:
@@ -3619,7 +3640,12 @@ var AnthropicMessagesLanguageModel = class {
thinking: {
type: thinkingType,
...thinkingBudget != null && { budget_tokens: thinkingBudget },
- ...thinkingDisplay != null && { display: thinkingDisplay }
+ ...thinkingDisplay != null && { display: thinkingDisplay },
+ ...thinkingBlockBinding != null && {
+ block_binding: {
+ prefix_mismatch_behavior: thinkingBlockBinding.prefixMismatchBehavior
+ }
+ }
}
},
...((anthropicOptions == null ? void 0 : anthropicOptions.effort) || (anthropicOptions == null ? void 0 : anthropicOptions.taskBudget) || useStructuredOutput && (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null) && {
@@ -3834,6 +3860,9 @@ var AnthropicMessagesLanguageModel = class {
} else if ((anthropicOptions == null ? void 0 : anthropicOptions.fallbacks) && anthropicOptions.fallbacks.length > 0) {
betas.add("server-side-fallback-2026-06-01");
}
+ if (thinkingBlockBinding != null) {
+ betas.add("thinking-binding-controls-2026-08-01");
+ }
const defaultEagerInputStreaming = stream && ((_j = anthropicOptions == null ? void 0 : anthropicOptions.toolStreaming) != null ? _j : true);
const {
tools: anthropicTools2,
@@ -4400,6 +4429,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens: (_a2 = response.usage.cache_creation_input_tokens) != null ? _a2 : null,
stopSequence: (_b2 = response.stop_sequence) != null ? _b2 : null,
...stopDetails != null ? { stopDetails } : {},
+ ...response.input_transformations != null ? { inputTransformations: response.input_transformations } : {},
iterations: response.usage.iterations ? response.usage.iterations.map(
(iter) => ({
type: iter.type,
@@ -4489,6 +4519,7 @@ var AnthropicMessagesLanguageModel = class {
let cacheCreationInputTokens = null;
let stopSequence = null;
let stopDetails = void 0;
+ let inputTransformations = void 0;
let container = null;
let isJsonResponseFromTool = false;
let isMessageOpen = false;
@@ -5147,6 +5178,9 @@ var AnthropicMessagesLanguageModel = class {
isMessageOpen = true;
activeMessageId = value.message.id;
usage.input_tokens = value.message.usage.input_tokens;
+ if (value.message.input_transformations != null) {
+ inputTransformations = value.message.input_transformations;
+ }
usage.cache_read_input_tokens = (_e = value.message.usage.cache_read_input_tokens) != null ? _e : 0;
usage.cache_creation_input_tokens = (_f = value.message.usage.cache_creation_input_tokens) != null ? _f : 0;
rawUsage = {
@@ -5267,6 +5301,7 @@ var AnthropicMessagesLanguageModel = class {
cacheCreationInputTokens,
stopSequence,
...stopDetails != null ? { stopDetails } : {},
+ ...inputTransformations != null ? { inputTransformations } : {},
iterations: usage.iterations ? usage.iterations.map(
(iter) => ({
type: iter.type,