Skip to content

feat: add AWS Bedrock provider via Anthropic SDK - #9957

Closed
renlon wants to merge 1 commit into
NousResearch:mainfrom
renlon:feature/aws-bedrock-provider
Closed

feat: add AWS Bedrock provider via Anthropic SDK#9957
renlon wants to merge 1 commit into
NousResearch:mainfrom
renlon:feature/aws-bedrock-provider

Conversation

@renlon

@renlon renlon commented Apr 15, 2026

Copy link
Copy Markdown

Summary

Add Amazon Bedrock as an inference provider using the Anthropic SDK's AnthropicBedrock class — not the boto3 Converse API. This preserves Claude-specific features that the Converse API loses: streaming, reasoning/thinking with configurable budgets, and adaptive thinking.

  • Supports bearer token, SigV4 (IAM credentials), AWS_PROFILE, SSO, and boto3 default credential chain (instance roles, IRSA)
  • Compatible with Claude Code env vars (CLAUDE_CODE_USE_BEDROCK, ANTHROPIC_MODEL, etc.)
  • Live model discovery via ListFoundationModels + ListInferenceProfiles (filtered to Anthropic models)
  • Maps common Anthropic/OpenRouter model slugs (including dated variants) to valid Bedrock inference profile IDs
  • boto3 added as optional dependency ([bedrock] extra), not a core requirement
  • 85 unit tests

Comparison with existing Bedrock PRs

Two other open Bedrock PRs (#8832 and #7920) both use the boto3 Converse API. This PR uses the Anthropic SDK's AnthropicBedrock class, reusing the existing anthropic_messages code path with zero format conversion.

Feature #8832 (Converse) #7920 (Converse) This PR (AnthropicBedrock)
Streaming No Yes Yes
Prompt caching No No Accepted but inactive (see note)
Reasoning/thinking No Partial (read-only) Yes — confirmed (budget controls)
Adaptive thinking No No Yes — confirmed
Fast mode No No Unverified (needs Opus 4.6 test)
Claude Code env vars No No Yes
Live model discovery No Yes (all models) Yes (Anthropic models only)
boto3 default chain No Yes Yes (profiles, SSO, instance roles)
Model slug translation No No Yes (OpenRouter/dated → Bedrock IDs)
New adapter file 432 lines 1,032 lines 0 lines
New api_mode bedrock_converse bedrock_converse None (reuses anthropic_messages)
Unit tests 0 107 85
Multi-model (Nova, Llama) Yes Yes Claude only
Guardrails No Yes No

Note on prompt caching: Bedrock accepts cache_control breakpoints without error and returns cache usage fields, but in testing with bearer token auth both values were 0. The code is ready and will work automatically if/when Bedrock activates caching support for bearer auth.

Note on thinking: Confirmed working on Bedrock with both thinking: {type: enabled, budget_tokens: 4000} (manual) and thinking: {type: adaptive} with output_config: {effort: high}. Thinking blocks are returned correctly.

User Configuration

Option 1: Environment variables (temporary)

export CLAUDE_CODE_USE_BEDROCK=1
export AWS_REGION=us-east-1
export AWS_BEARER_TOKEN_BEDROCK=<token>   # or AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY
export ANTHROPIC_MODEL=us.anthropic.claude-opus-4-6-v1
# Optional:
export ANTHROPIC_SMALL_FAST_MODEL=us.anthropic.claude-sonnet-4-6
export DISABLE_PROMPT_CACHING=0

Option 2: Config file (permanent)

~/.hermes/config.yaml:

model:
  default: "us.anthropic.claude-opus-4-6-v1"
  provider: "bedrock"
  context_length: 1000000

~/.hermes/.env:

AWS_REGION=us-east-1
AWS_BEARER_TOKEN_BEDROCK=<your-token>

Option 3: boto3 default credential chain

Works with AWS_PROFILE, SSO, EC2/ECS/Lambda instance roles, and IRSA:

model:
  default: "us.anthropic.claude-opus-4-6-v1"
  provider: "bedrock"

Model slug translation

Common Anthropic/OpenRouter model names are automatically mapped to Bedrock IDs:

  • anthropic/claude-opus-4.6us.anthropic.claude-opus-4-6-v1
  • claude-opus-4-5-20251101us.anthropic.claude-opus-4-5-20251101-v1:0
  • Native Bedrock IDs pass through unchanged

Install

pip install -e ".[bedrock]"   # or pip install -e ".[all]"

Manual Test Results

Test Method Result
Bearer token auth + streaming E2E (real API) PASS
Config.yaml activation (no env override) E2E (real API) PASS
/status shows correct model and provider E2E (screenshot) PASS
Thinking/reasoning (budget_tokens=4000) E2E (real API) PASS
Adaptive thinking (effort: high) E2E (real API) PASS
Tool calling (search_files + terminal) E2E (real API) PASS
Discord gateway with Bedrock E2E (real bot) PASS
Live model discovery (23 Anthropic models) E2E (real API) PASS
Direct AIAgent() with env-only bearer auth Unit test PASS
Auxiliary client uses runtime bearer token Unit test (real resolver) PASS
SigV4 visible in /model picker Unit test (real function) PASS
AWS_PROFILE validated before reporting configured Unit test (real function) PASS
Model slug translation (coarse + dated + Opus 4.1) Unit test PASS
85 unit tests Unit test ALL PASS

Test Plan

  • Bearer token auth works (E2E)
  • Config.yaml activation works (E2E)
  • ANTHROPIC_MODEL scoped to Bedrock only (unit)
  • Explicit --provider blocks ANTHROPIC_MODEL leak (unit)
  • /status shows correct model (E2E)
  • Streaming works (E2E)
  • Thinking/reasoning with budget controls (E2E)
  • Adaptive thinking confirmed (E2E)
  • Tool calling works (E2E)
  • Discord gateway with Bedrock (E2E)
  • DISABLE_PROMPT_CACHING works (unit)
  • AWS_DEFAULT_REGION honored in all code paths (unit)
  • Region defaults to us-east-1 when unset (unit)
  • Direct AIAgent() with env-only bearer auth uses correct client (unit)
  • Auxiliary client wraps in AnthropicAuxiliaryClient with async (unit)
  • Auxiliary auto-routing preserves runtime bearer token (unit)
  • Prompt caching preserved through switch_model and fallback (unit)
  • SigV4 credentials visible in /model picker and auth status (unit)
  • AWS_PROFILE validated (nonexistent profile → not configured) (unit)
  • boto3 default chain accepted (unit)
  • Live model discovery returns Anthropic models only (E2E)
  • Model slug translation: OpenRouter, dated, Opus 4.1 (unit)
  • hermes model picker, hermes setup, hermes doctor all include Bedrock (unit)
  • 85 unit tests pass
  • SigV4 auth with IAM credentials (end-to-end — needs EC2/ECS)
  • Fast mode on Opus 4.6

@renlon
renlon force-pushed the feature/aws-bedrock-provider branch from b9e26aa to b3754db Compare April 15, 2026 00:38
@renlon

renlon commented Apr 15, 2026

Copy link
Copy Markdown
Author

Manual Test Screenshots

Chat response — Claude Opus 4.6 via AWS Bedrock:
Shows model initialization with us.anthropic.claude-opus-4-6-v1 on Bedrock, provider: bedrock, streaming response working.
Screenshot 2026-04-14 at 17 31 53

/status command:
Shows Model: us.anthropic.claude-opus-4-6-v1 (bedrock) correctly reflected in the CLI status bar.
Screenshot 2026-04-14 at 17 31 42

Tool calling:
image

@renlon
renlon force-pushed the feature/aws-bedrock-provider branch 17 times, most recently from 9e1f1d3 to 3b35991 Compare April 15, 2026 04:33
Add Amazon Bedrock as a first-class provider using the Anthropic SDK's
AnthropicBedrock class. Supports both SigV4 (IAM credentials) and
bearer token (Bedrock API keys) authentication. Preserves all Claude
features: streaming, prompt caching, reasoning, adaptive thinking.

Supports Claude Code-compatible env vars:
  CLAUDE_CODE_USE_BEDROCK=1, AWS_REGION, ANTHROPIC_MODEL,
  ANTHROPIC_SMALL_FAST_MODEL, AWS_BEARER_TOKEN_BEDROCK,
  DISABLE_PROMPT_CACHING

Also supports config.yaml: provider: bedrock (permanent setting).

Changes:
- agent/anthropic_adapter.py — build_bedrock_client(), is_bedrock_model_id(),
  preserve Bedrock ARNs in normalize_model_name()
- hermes_cli/auth.py — ProviderConfig + aliases (bedrock, aws-bedrock, aws)
- hermes_cli/runtime_provider.py — CLAUDE_CODE_USE_BEDROCK activation,
  Bedrock credential resolution (SigV4 + bearer auto-detect)
- run_agent.py — Bedrock client init, switch_model, prompt caching,
  DISABLE_PROMPT_CACHING env var
- agent/auxiliary_client.py — Bedrock aux model default
- hermes_cli/model_normalize.py — pass-through for Bedrock model IDs
- cli.py — skip base_url validation for Bedrock
- pyproject.toml — boto3 as optional [bedrock] dependency, added to [all]
- tests/agent/test_bedrock_provider.py — 48 unit tests
@renlon
renlon force-pushed the feature/aws-bedrock-provider branch from 3b35991 to c0743a6 Compare April 15, 2026 04:47
@JiaDe-Wu

Copy link
Copy Markdown
Contributor

Nice approach @renlon. Using AnthropicBedrock to reuse the existing anthropic_messages path is clean — zero new adapter code, and you get thinking budgets + adaptive thinking for free.

Fair comparison table. A couple of notes from our side (#7920):

  • Multi-model is the main tradeoff. Converse API supports Claude + Nova + DeepSeek + Llama + Mistral through one adapter. AnthropicBedrock is Claude-only by design. For AWS teams using Nova or Llama, that matters.
  • Guardrails — our Converse path threads guardrailConfig through the whole call chain. Not available via the Anthropic SDK.
  • Reasoning — you are right that our implementation is read-only for thinking blocks. Your thinking budget controls are a real advantage for Claude users.
  • We just added non-tool-calling model detection based on @ptlally feedback — strips tools for models like DeepSeek R1 that reject toolConfig.

Honestly these two approaches complement each other well. AnthropicBedrock for Claude-heavy users who want full Anthropic feature parity, Converse API for multi-model users who want one provider for everything.

Would be great if the maintainers could pick one as the base and cherry-pick the best parts from both. Happy to help consolidate.

@renlon

renlon commented Apr 15, 2026

Copy link
Copy Markdown
Author

Thanks for the thoughtful comparison @JiaDe-Wu — and the work you put into #7920. I agree these two approaches are complementary rather than competing.

Happy to coordinate either way: if your updated PR in #7920 already incorporates the AnthropicBedrock path (with prompt caching, thinking budgets, etc.), I'm fine dropping this one. Or we can get this merged first and you rebase #7920 on top to add the Converse API path for non-Claude models. Either way works — up to the repo maintainers to decide the order.

@renlon

renlon commented Apr 16, 2026

Copy link
Copy Markdown
Author

closing out this PR in favor of [#7920]. Thanks again @JiaDe-Wu for the great work.

@renlon renlon closed this Apr 16, 2026
Sign up for free to 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.

2 participants