Skip to content

feat: support Claude models on the Bedrock Mantle endpoint - #43231

Open
ktoulgaridis wants to merge 10 commits into
anomalyco:devfrom
ktoulgaridis:bedrock-mantle-messages
Open

feat: support Claude models on the Bedrock Mantle endpoint#43231
ktoulgaridis wants to merge 10 commits into
anomalyco:devfrom
ktoulgaridis:bedrock-mantle-messages

Conversation

@ktoulgaridis

@ktoulgaridisktoulgaridis commented Aug 18, 2026

Copy link
Copy Markdown

Issue for this PR

Closes#43230

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Lets Claude models be used on the bedrock-mantle endpoint.

Mantle serves Claude only through the Anthropic Messages API at /anthropic/v1/messages, and nothing bundled reaches that:

  • @ai-sdk/amazon-bedrock/mantle is OpenAI-compatible only, and Mantle rejects Anthropic IDs there — The model 'anthropic.claude-opus-4-8' does not support the '/openai/v1/responses' API
  • @ai-sdk/amazon-bedrock/anthropic speaks Messages, but hardcodes buildRequestUrl to the bedrock-runtime/model/{id}/invoke path and moves the model ID into an anthropic_version body field
  • @ai-sdk/anthropic speaks Messages and takes a baseURL, but authenticates only with a key, so profile/SSO users would need a Bedrock API key refreshed every 12h

So this adds @ai-sdk/amazon-bedrock/mantle-anthropic: AnthropicMessagesLanguageModel pointed at the Mantle base URL, with a fetch that SigV4-signs the request (service bedrock-mantle) using the credential provider the bedrock loader already builds from region/profile. Signing in fetch is the only request-time auth hook the AI SDK offers; it wraps the fetch opencode already puts in options, so the existing timeout and SSE-abort handling still runs. Bearer tokens (AWS_BEARER_TOKEN_BEDROCK or options.apiKey) keep their current precedence and skip signing.

Two fields the SDK sends by default are rejected by Mantle, both verified live:

  • output_config.format → 400 Extra inputs are not permitted, which broke every generateObject call (e.g. agent create). supportsNativeStructuredOutput: false routes structured output through the SDK's JSON tool instead.
  • a tool-level strict field → 400 tools.0.custom.strict: Extra inputs are not permitted, so supportsStrictTools: false is set too.

Both are model-config-only settings, so the model is built from the declared @ai-sdk/anthropic/internal subpath rather than createAnthropic — the same way @ai-sdk/google-vertex/anthropic builds its model. One visible consequence: requests no longer carry the ai-sdk/anthropic/<version> User-Agent suffix (@ai-sdk/google-vertex/anthropic drops it too). provider.tools and the embedding/image model stubs go with it; nothing here uses them.

The key also has to be threaded through the Anthropic paths in the transform layer, alongside @ai-sdk/google-vertex/anthropicsdkKey (otherwise per-model providerOptions are silently dropped), the empty-content guard, usesAnthropicAutomaticCaching, variants/reasoningEffort/reasoningBudget (otherwise reasoning is silently off), supportsMediaInToolResult, and the v1 config lowerers. The Responses-API-only lists correctly exclude it.

Base URL is derived from region, so no api override is needed — that also keeps it working on v2, where ${AWS_REGION} is not substituted (#40075). Model IDs pass through unprefixed, since Mantle has no cross-region inference profiles.

{
"provider": {
"amazon-bedrock": {
"options": { "region": "us-east-1", "profile": "my-sso-profile" },
"models": {
"anthropic.claude-opus-4-8": {
"provider": { "npm": "@ai-sdk/amazon-bedrock/mantle-anthropic" }
}
}
}
}
}

Related: #36208 (native llm layer design — this is the AI SDK path), #39325 (Mantle selector keyed to the amazon-bedrock provider id).

How did you verify your code works?

  • bun typecheck clean in packages/core and packages/opencode; full suites green (packages/core 1101 pass, packages/opencode 3322 pass)
  • New tests cover SigV4 signing, streaming, the API-key path, static env credentials, the missing-credentials error, JSON-tool routing, and the absence of tool strict; plus the transform-layer edits and both the v1 and v2 wirings. Every production edit was mutation-tested — reverting any one of them fails a test.
  • Live against us-east-1 with an SSO profile, on a binary from ./packages/opencode/script/build.ts --single: anthropic.claude-opus-4-8 and anthropic.claude-opus-5 answer over Mantle, tool calls execute and their real output is used, --variant high --thinking streams reasoning, and agent create (the path that previously 400'd) writes a schema-valid agent file. openai.gpt-5.6-sol still works, so the existing Mantle OpenAI route is unaffected.
  • Capability limits were probed directly against the endpoint and are documented: fixed-budget thinking.type: "enabled" is rejected on Opus 4.8/Opus 5/Sonnet 5 (accepted on Haiku 4.5), while adaptive thinking with output_config.effort is accepted.
  • Reviewer repro: aws sso login --profile <profile>, add the config above, then opencode run -m amazon-bedrock/anthropic.claude-opus-4-8 "hi"

Note: packages/core/test/plugin/provider-amazon-bedrock.test.ts already fails on dev when run as a single file (TDZ on AmazonBedrockPlugin via a circular import); it passes as part of bun test test/plugin. Untouched here.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Mantle serves Claude through the Anthropic Messages API at /anthropic/v1/messages,
which no bundled provider could reach: the mantle export is OpenAI-compatible only,
and the anthropic export builds bedrock-runtime invoke paths. Adds a mantle-anthropic
provider that signs Messages requests with SigV4 so profile/SSO/IRSA credentials work.
@github-actionsgithub-actionsBot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Aug 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference; please use your judgment.

  • packages/core/src/plugin/provider/amazon-bedrock.ts:117 — createBedrockMantleAnthropic(options) receives the user's options (which per the docs include profile), but BedrockMantleAnthropicSettings has no profile handling and no default credential-chain resolution (env vars / SSO / IRSA). Without an explicit credentialProvider, SigV4 mode always throws "requires either an API key or AWS credentials". The docs claim "profiles, SSO, and IRSA work as they do elsewhere in Bedrock" — that looks untrue as implemented. Either resolve credentials from profile/env here or fix the docs.
  • packages/core/src/amazon-bedrock/mantle-anthropic.ts:60 — body: init?.body as string: if the AI SDK ever passes a non-string body (stream/Uint8Array), SigV4 signing will produce an invalid payload hash. Consider asserting/handling non-string bodies explicitly.
  • packages/core/src/amazon-bedrock/mantle-anthropic.ts:33 — placeholder apiKey: "sigv4" is clever but means a leaked-looking dummy key header is constructed on every request before deletion; a comment exists — good. Just make sure no retry path bypasses the wrapping fetch.
  • packages/core/test/amazon-bedrock/mantle-anthropic.test.ts — unit tests cover signing and bearer paths well; consider adding a test asserting the helpful error when neither key nor credentials exist.
  • Docs addition is clear, including the no-inference-profile warning.

ktoulgaridisand others added 2 commits August 21, 2026 14:39
The new npm key was invisible to the transform layer, so Claude on Mantle got
no reasoning variants, providerOptions were never remapped to the anthropic key,
and the empty-content and tool-result-media checks skipped it.
Mantle also rejects two fields the SDK sends by default: output_config.format
(400 on any generateObject call) and a tool-level strict field. Both are model
config settings, so the model is now built from @ai-sdk/anthropic/internal the
same way @ai-sdk/google-vertex/anthropic builds its own.
@ktoulgaridis

Copy link
Copy Markdown
Author

Thanks — 4 is fair, added. On the rest:

1. The credential chain isn't meant to live in mantle-anthropic.ts; the callers inject it, exactly as for @ai-sdk/amazon-bedrock and /mantle. packages/core/src/plugin/provider/amazon-bedrock.ts gates on evt.package, the new package is in that allowlist, and it then sets credentialProvider = fromNodeProviderChain(profile ? { profile } : {}) from options.profile ?? AWS_PROFILE. Same on v1 through the amazon-bedrock loader. Verified live with an SSO profile and no key.

There was a real gap next door, now closed: unlike createAmazonBedrock, this had no fallback to static AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY when nothing is injected. Fixed and tested. The other half — v1 wiring the chain only to the literal id amazon-bedrock — is pre-existing and identical for /mantle; that's #39325.

2. Unreachable today: @ai-sdk/anthropic only calls postJsonToApi, which always stringifies. aws4fetch throws rather than mis-hashing if handed anything else, and an absent body hashes to the correct empty-payload digest. Leaving the cast.

3. Retries re-enter doGenerate/doStream, so each attempt re-signs — required anyway, since SigV4 signatures expire; provider-utils has no retry of its own. The x-api-key header is deleted before signing, which now also covers a caller-supplied one via options.headers.

4. Added.

Your review pointed at the right file, though, and digging there turned up two real 400s I've now fixed:

  • output_config.format was still being sent, so any generateObject call — e.g. agent create — failed with output_config.format: Extra inputs are not permitted. The model config now sets supportsNativeStructuredOutput: false, so structured output takes the SDK's JSON-tool path, the same thing @ai-sdk/google-vertex/anthropic does.
  • A tool-level strict field failed the same way (tools.0.custom.strict), so supportsStrictTools: false is set too.

Reaching those flags means building AnthropicMessagesLanguageModel from @ai-sdk/anthropic/internal rather than createAnthropic, since AnthropicProviderSettings can't express them.

Separately, and bigger than any of the above: the new npm key was invisible to the transform layer, so reasoning/effort variants were never generated, providerOptions weren't remapped to the anthropic key, and the empty-content and tool-result-media checks skipped it. All wired now, with tests, and every edit is mutation-tested.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Bedrock Mantle for both Anthropic and OpenAI models with SigV4/SSO auth

2 participants

@ktoulgaridis@Enough1122