hotfix: disable native structured output for AiHubMix/NewAPI Anthropic models (#14376)

<!-- Template from
https://github.com/kubevirt/kubevirt/blob/main/.github/PULL_REQUEST_TEMPLATE.md?-->
<!--  Thanks for sending a pull request!  Here are some tips for you:
1. Consider creating this PR as draft:
https://github.com/CherryHQ/cherry-studio/blob/main/CONTRIBUTING.md
-->

<!--

🚨 Branch Strategy Change (Effective April 3, 2026) 🚨

The `main` branch is now under CODE FREEZE.

- main branch: Only accepts critical bug fixes via `hotfix/*` branches.
Fix PRs must be minimal in scope and must not include any refactoring
code.
- v2 branch: All new features, refactoring, and optimizations should be
submitted to the `v2` branch.

If you are submitting a bug fix to main, please ensure your PR is from a
`hotfix/*` branch.

-->

### What this PR does

Before this PR: sending any request with tools (MCP or otherwise)
through the AiHubMix or NewAPI provider using Claude Opus 4.6 / Sonnet
4.6 / Opus 4.5 / Sonnet 4.5 / Haiku 4.5 / Opus 4.1 fails immediately
with `invalid_request_error: Unexpected value(s)
'structured-outputs-2025-11-13' for the 'anthropic-beta' header` when
the proxy routes the model to a Vertex AI or Bedrock backend.

After this PR: `supportsNativeStructuredOutput: false` is passed to
`AnthropicMessagesLanguageModel` inside both proxy providers, so
`@ai-sdk/anthropic` no longer emits the `structured-outputs-2025-11-13`
beta and falls back to function-tool-based structured outputs, which
every downstream backend accepts. MCP and plain tool calls work again.

Fixes #14375

### Why we need it and why it was done in this way

`@ai-sdk/anthropic` (currently `3.0.64`, same behavior through `3.0.71`
and `4.0.0-beta.37`) marks `claude-opus-4-6` / `claude-sonnet-4-6` /
`claude-*-4-5` / `claude-opus-4-1` as `supportsStructuredOutput: true`
in `getModelCapabilities()`, and unconditionally adds `anthropic-beta:
structured-outputs-2025-11-13` whenever tools are attached. That beta is
only accepted on the direct Anthropic API. Vertex AI and Bedrock reject
it — the issue's `req_vrtx_` request ID confirms the user's AiHubMix
account routed the request to Vertex.

The SDK only exposes this knob at provider construction time via
`supportsNativeStructuredOutput`, not per request. Since AiHubMix and
NewAPI are multi-backend proxies — a single Claude model ID can land on
Anthropic direct, Vertex, or Bedrock depending on the account — Cherry
has no reliable way to pick the right value at call time. Defaulting to
`false` unblocks the failing request at the cost of native structured
output for `generateObject` / `streamObject`; function-tool fallback is
already the legacy path and remains correct.

The following tradeoffs were made:
- Users of AiHubMix/NewAPI who relied on `generateObject`/`streamObject`
native mode will now go through function-tool fallback. MCP tool use
(the reported breakage) is unaffected.
- Direct Anthropic / Vertex Anthropic / Bedrock providers are untouched.

The following alternatives were considered:
- Upgrade `@ai-sdk/anthropic`: does not help — `3.0.71` and
`4.0.0-beta.37` contain identical logic.
- Request-time `providerOptions.anthropic.structuredOutputMode =
'functionTool'`: does not suppress the beta header;
`supportsStructuredOutput` and the `structureOutputMode` option are
independent code paths in the SDK.
- Add a per-provider "backend" config field: correct long-term fix but
requires new UI/schema, which is out of scope for a `main`-branch hotfix
under code freeze. Tracked as a v2 follow-up issue.

Links to places where the discussion took place: #14375

### Breaking changes

None for end users. AiHubMix/NewAPI users invoking
`generateObject`/`streamObject` will silently switch to function-tool
fallback; outputs remain JSON-schema-valid.

### Special notes for your reviewer

The comment in each provider file names the affected model IDs
explicitly so future readers understand why the knob is set. The change
is confined to two lines of behavior in two files — no refactoring.

### Checklist

This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [x] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others

### Release note

<!--  Write your release note:
1. Enter your extended release note in the below block. If the PR
requires additional action from users switching to the new release,
include the string "action required".
2. If no release note is required, just write "NONE".
3. Only include user-facing changes (new features, bug fixes visible to
users, UI changes, behavior changes). For CI, maintenance, internal
refactoring, build tooling, or other non-user-facing work, write "NONE".
-->

```release-note
Fix invalid_request_error when calling Claude Opus 4.6 / Sonnet 4.6 / 4.5 series / Opus 4.1 with tools (including MCP) through AiHubMix or NewAPI: the `structured-outputs-2025-11-13` beta header is no longer sent, so requests routed to Vertex AI / Bedrock backends succeed.
```

Signed-off-by: suyao <sy20010504@gmail.com>
This commit is contained in:
SuYao
2026-04-22 17:35:14 +08:00
committed by GitHub
parent 3f463e178b
commit 01caaf06f7
2 changed files with 14 additions and 2 deletions

View File

@@ -61,7 +61,13 @@ export function createAihubmix(options: AihubmixProviderSettings = {}): Aihubmix
baseURL,
headers: () => ({ ...headers, 'x-api-key': resolveApiKey() }),
fetch: customFetch,
supportedUrls: () => ({ 'image/*': [/^https?:\/\/.*$/] })
supportedUrls: () => ({ 'image/*': [/^https?:\/\/.*$/] }),
// AiHubMix may route Claude models to Vertex/Bedrock backends, which reject the
// `structured-outputs-2025-11-13` beta header added by @ai-sdk/anthropic for
// claude-opus-4-6 / claude-sonnet-4-6 / claude-*-4-5 / claude-opus-4-1. Falling
// back to function-tool-based structured outputs keeps tool use (incl. MCP) working
// across all downstream backends. See issue #14375.
supportsNativeStructuredOutput: false
})
}

View File

@@ -68,7 +68,13 @@ export function createNewApi(options: NewApiProviderSettings = {}): NewApiProvid
baseURL,
headers: () => ({ ...headers, 'x-api-key': resolveApiKey() }),
fetch: customFetch,
supportedUrls: () => ({ 'image/*': [/^https?:\/\/.*$/] })
supportedUrls: () => ({ 'image/*': [/^https?:\/\/.*$/] }),
// NewAPI may route Claude models to Vertex/Bedrock backends, which reject the
// `structured-outputs-2025-11-13` beta header added by @ai-sdk/anthropic for
// claude-opus-4-6 / claude-sonnet-4-6 / claude-*-4-5 / claude-opus-4-1. Falling
// back to function-tool-based structured outputs keeps tool use (incl. MCP) working
// across all downstream backends. See issue #14375.
supportsNativeStructuredOutput: false
})
}