Skip to content

feat: add AWS Bedrock API support#260

Closed
devin-ai-integration[bot] wants to merge 10 commits into
mainfrom
feat/add-aws-bedrock-api-support
Closed

feat: add AWS Bedrock API support#260
devin-ai-integration[bot] wants to merge 10 commits into
mainfrom
feat/add-aws-bedrock-api-support

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Add initial AWS Bedrock API support to BenchFlow. Rebased clean version of #247.

This PR introduces a host-side Bedrock proxy and wires aws-bedrock/... models into the existing provider/agent flow so BenchFlow can route supported ACP agents through Bedrock instead of direct Anthropic endpoints. Current focus is the Sonnet 4.5 Claude path.

What Changed

Provider and Agent Plumbing

  • Add aws-bedrock as a registered provider with auth_type=\"aws\"
  • Extend provider auth handling for Bedrock bearer-token auth
  • Update agent/provider env resolution for Bedrock-specific runtime setup
  • Keep Bedrock routing inside the existing BENCHFLOW_PROVIDER_* flow

Host-Side Bedrock Proxy

  • Add host-side Bedrock proxy with Anthropic/OpenAI → Bedrock Converse translation
  • Support Claude Bedrock gateway routes (invoke, invoke-with-response-stream, count-tokens)
  • Add Bedrock runtime startup/cleanup wiring in the trial lifecycle

Trial Integration

  • Start proxy automatically for aws-bedrock/ models; stop during cleanup
  • Rewrite provider base URLs to host-side proxy

Fixes during merge with main

  • Restored check_subscription_auth() fallback that was inadvertently dropped — standard Claude/Codex/Gemini subscription auth works again
  • Added # ty: ignore[unresolved-import] for optional boto3 import to pass ty check
  • Fixed ruff format issues

Tests — 8 new/updated test files covering provider registry, env resolution, ACP model selection, Bedrock proxy HTTP behavior, runtime startup, and trial-side proxy integration.

Review & Testing Checklist for Human

  • Verify Bedrock proxy translates Anthropic messages and OpenAI responses correctly end-to-end with a real aws-bedrock/us.anthropic.claude-sonnet-4-5 model
  • Confirm AWS_BEARER_TOKEN_BEDROCK and AWS_REGION are properly validated and propagated
  • Verify subscription auth still works for standard Claude models (no API key, but host .claude/.credentials.json present)
  • Check that the boto3 optional dependency installs correctly with uv sync --extra bedrock

Notes

  • Rebased from feat/add aws-bedrock-api support #247 (original by AmyTao) — cleaned up merge history to a single commit on top of main
  • The ty check failure from the original PR is fixed with an inline suppression for the optional boto3 import
  • All 860 tests pass locally, lint/format/typecheck clean
  • Co-authored with AmyTao

Link to Devin session: https://app.devin.ai/sessions/35319f5359ec4bb3851a8ce65dcc7620
Requested by: @xdotli


Open in Devin Review

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

agent_env = dict(agent_env or {})
explicit_agent_env_keys = set(agent_env)
auto_inherit_env(agent_env)
auto_inherit_env(agent_env, source_env=load_dotenv_env())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 resolve_agent_env no longer inherits API keys from os.environ, only from .env file

The call auto_inherit_env(agent_env, source_env=load_dotenv_env()) at src/benchflow/_agent_env.py:281 replaces the prior auto_inherit_env(agent_env) which read from os.environ. When no .env file exists, load_dotenv_env() returns {} (an empty dict), which is not None. Inside auto_inherit_env, the guard source = source_env if source_env is not None else os.environ (src/benchflow/_agent_env.py:101) therefore uses the empty dict instead of falling back to os.environ. This means API keys set via shell environment variables (e.g. export ANTHROPIC_API_KEY=sk-test) are silently ignored — breaking the established workflow for all users who don't have a .env file. The CLI passes only explicit --agent-env flags as agent_env (src/benchflow/cli/main.py:129-135), so there is no other path that compensates. The existing auto_inherit_env unit tests (tests/test_resolve_env_helpers.py:37-41) call the function without source_env, so they exercise the os.environ fallback that production code no longer uses.

Prompt for agents
The problem is in resolve_agent_env at src/benchflow/_agent_env.py:281. The call auto_inherit_env(agent_env, source_env=load_dotenv_env()) passes the .env file contents as source_env, completely replacing os.environ. When no .env file exists, load_dotenv_env() returns {} (empty dict, not None), so the os.environ fallback in auto_inherit_env never activates.

The fix should merge both sources: .env values should act as a fallback layer on top of os.environ (or vice versa, depending on desired precedence). One approach: build a merged source dict that combines os.environ with .env overrides, e.g.:

  dotenv = load_dotenv_env()
  merged_source = {**os.environ, **dotenv}  # .env overrides os.environ
  auto_inherit_env(agent_env, source_env=merged_source)

Alternatively, call auto_inherit_env twice (once with .env, once with os.environ) using setdefault semantics to get the right precedence. The key invariant to preserve: users who export API keys in their shell must still have them inherited into agent_env.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a valid finding. On main, auto_inherit_env(agent_env) reads from os.environ. This PR changes it to auto_inherit_env(agent_env, source_env=load_dotenv_env()) which only reads from the .env file.

This was an intentional change from the original PR author (commit f18f719 — "fix: prefer explicit and .env auth vars over host env for Bedrock runs"), but it does break the established workflow for users who export API keys in their shell without a .env file.

A simple fix would be to merge both sources as suggested:

dotenv = load_dotenv_env()
merged_source = {**os.environ, **dotenv}  # .env overrides os.environ
auto_inherit_env(agent_env, source_env=merged_source)

@xdotli — should I apply this fix, or was the .env-only behavior intentional for Bedrock?

xdotli added 2 commits May 15, 2026 22:11
- Restore check_subscription_auth() fallback in resolve_agent_env
  before raising ValueError (inadvertently removed during Bedrock merge)
- Add ty: ignore[unresolved-import] for optional boto3 import
- Update test_no_auth_file_raises match pattern for new error message
- Fix ruff format issues
@devin-ai-integration
devin-ai-integration Bot force-pushed the feat/add-aws-bedrock-api-support branch from 41bd7f9 to cc2b584 Compare May 15, 2026 22:12
@xdotli xdotli closed this May 15, 2026

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 11 additional findings in Devin Review.

Open in Devin Review


logger = logging.getLogger(__name__)

BEDROCK_PROXY_BIND_HOST = "0.0.0.0"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Bedrock proxy binds to 0.0.0.0 without inbound authentication, exposing AWS credentials to the network

The Bedrock proxy server binds to 0.0.0.0 (all network interfaces) at _provider_runtime.py:15 and the proxy has no authentication on the inbound side (bedrock_proxy.py:170-245). Any device on the same network can send requests to the proxy's port and they will be forwarded to AWS Bedrock using the user's AWS_BEARER_TOKEN_BEDROCK credentials. This is especially concerning because the proxy is started automatically when using an aws-bedrock/ model prefix.

How the proxy is reached without auth

The proxy binds on BEDROCK_PROXY_BIND_HOST = "0.0.0.0" at _provider_runtime.py:111. The _handle_connection method at bedrock_proxy.py:170 processes all inbound requests with no authentication — no token check, no IP allowlist. The routes at /v1/messages, /v1/responses, and /model/*/invoke* all proxy through to AWS Bedrock using the bearer token from _bedrock_auth_headers at bedrock_proxy.py:337-349.

Prompt for agents
The Bedrock proxy server binds to 0.0.0.0 (BEDROCK_PROXY_BIND_HOST at _provider_runtime.py:15), making it accessible from any network interface. This proxy forwards requests to AWS Bedrock using the user's AWS_BEARER_TOKEN_BEDROCK with no inbound authentication.

The bind address should be restricted. For Docker environments, consider binding to the Docker bridge network interface instead of all interfaces. For non-Docker environments, 127.0.0.1 is already used as the URL host but the server still binds on 0.0.0.0.

Possible approaches:
1. Bind to 127.0.0.1 by default. For Docker on Linux where host.docker.internal maps to the bridge gateway (not loopback), bind to the Docker bridge interface IP (e.g. 172.17.0.1) which can be detected at runtime.
2. Add a randomly-generated auth token that is set as a header by the agent and validated by the proxy.
3. At minimum, document the security implications and let users opt into 0.0.0.0 explicitly.

Files involved: src/benchflow/_provider_runtime.py (BEDROCK_PROXY_BIND_HOST constant, ensure_bedrock_proxy_runtime), src/benchflow/providers/bedrock_proxy.py (BedrockProxyServer._handle_connection).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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