feat: add AWS Bedrock LLM provider via native Converse API - #713
Conversation
…tle substring matching
- Safe u32→i32 cast for max_tokens using try_from with clamp - Remove brittle string-based error detection fallback for tool results - Validate BEDROCK_CROSS_REGION against allowed values (us/eu/apac/global) - Validate message list is non-empty before Converse API call - Log when using default us-east-1 region - Update llm_backend doc comment to list all backends - Add tests for build_inference_config and empty message handling
The wizard collected the profile name but only printed a hint to set it manually. Now it saves to settings and writes AWS_PROFILE to the bootstrap .env, consistent with how BEDROCK_REGION and other Bedrock settings are persisted.
The AWS SDK dependencies (aws-config, aws-sdk-bedrockruntime, aws-smithy-types) require cmake and a C compiler to build aws-lc-sys. Gate them behind an opt-in `bedrock` feature flag so default builds are unaffected. Build with: cargo build --features bedrock All config, settings, and wizard code stays unconditional (no AWS deps) so users can configure Bedrock even without the feature compiled — they get a clear error at startup directing them to rebuild.
…rchitecture (takeover #345) - Resolve merge conflicts with main's registry-based provider system - Add missing cache_creation_input_tokens/cache_read_input_tokens fields - Add missing content_parts field in test ChatMessage - Fix string literal type mismatches in wizard env_vars (.to_string()) - Remove non-functional bearer token auth (AWS_BEARER_TOKEN_BEDROCK) from wizard and documentation per reviewer feedback from @zmanian and @serrrfirat - Remove stale BEDROCK_ACCESS_KEY proxy entry from provider table - Update Bedrock provider to use is_bedrock string check (LlmBackend enum removed) - Add bedrock_profile fallback from settings in config resolution [skip-regression-check] Co-Authored-By: cgorski <cgorski@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
There was a problem hiding this comment.
Pull request overview
This PR adds native AWS Bedrock LLM provider support using aws-sdk-bedrockruntime's Converse API, bypassing the OpenAI-compatible layer. It is a continuation/rebase of #345, adapted to work with the current registry-based provider architecture and feature-gated behind --features bedrock.
Changes:
- New
src/llm/bedrock.rsimplementingLlmProviderfor AWS Bedrock via the Converse API, with message conversion, tool support, and error mapping - Config system extended:
BedrockConfigstruct, env var resolution (BEDROCK_REGION,BEDROCK_MODEL,BEDROCK_CROSS_REGION,AWS_PROFILE), and feature-gated provider instantiation - Setup wizard updated with a Bedrock-specific flow (region, auth, cross-region) and documentation updated across
docs/LLM_PROVIDERS.md,FEATURE_PARITY.md,CLAUDE.md, andCHANGELOG.md
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/llm/bedrock.rs |
New 1127-line Bedrock provider with full Converse API implementation and 31 unit tests |
src/llm/mod.rs |
Routes backend == "bedrock" to the new provider; adds bedrock: None to test config |
src/config/llm.rs |
Adds BedrockConfig struct and resolves Bedrock env vars in LlmConfig::resolve() |
src/config/mod.rs |
Exports BedrockConfig; adds vestigial bedrock_api_key → AWS_BEARER_TOKEN_BEDROCK secret injection |
src/settings.rs |
Adds bedrock_region, bedrock_cross_region, bedrock_profile fields to Settings |
src/setup/wizard.rs |
Adds setup_bedrock(), setup_bedrock_cross_region(), and Bedrock model selection in wizard |
src/setup/README.md |
Documents Bedrock in provider table with outdated AWS_BEARER_TOKEN_BEDROCK env var reference |
docs/LLM_PROVIDERS.md |
Adds full Bedrock documentation section |
FEATURE_PARITY.md |
Updates Bedrock row to reflect native API instead of LiteLLM proxy |
CLAUDE.md |
Adds Bedrock env vars to the configuration reference |
CHANGELOG.md |
Adds unreleased entry (with inaccurate mention of bearer token auth) |
Cargo.toml / Cargo.lock |
Adds aws-config, aws-sdk-bedrockruntime, aws-smithy-types as optional dependencies |
Comments suppressed due to low confidence (1)
src/config/llm.rs:320
- In
LlmConfig::resolve(), whenis_bedrockis true,config.backendis set tobackend_lower(line 319), which can be"aws_bedrock"or"aws"— not normalized to"bedrock". However,create_llm_providerinsrc/llm/mod.rsonly checksconfig.backend == "bedrock"(line 69). WhenLLM_BACKEND=aws_bedrockorLLM_BACKEND=awsis used,config.backendwill hold"aws_bedrock"or"aws"respectively,config.providerwill beNone, and the function will returnLlmError::AuthFailedinstead of creating the Bedrock provider. The fix is to normalize the stored backend name to"bedrock"for all three aliases in theOk(Self { backend: ... })expression, or to check all three aliases increate_llm_provider.
Ok(Self {
backend: if is_nearai {
"nearai".to_string()
} else if let Some(ref p) = provider {
p.provider_id.clone()
} else {
backend_lower
},
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| | Ollama | None | - | - | | ||
| | OpenRouter¹ | API key | `llm_compatible_api_key` | `LLM_API_KEY` | | ||
| | OpenAI-compatible¹ | Optional API key | `llm_compatible_api_key` | `LLM_API_KEY` | | ||
| | AWS Bedrock | API key or AWS credentials | `bedrock_api_key` | `AWS_BEARER_TOKEN_BEDROCK` | |
There was a problem hiding this comment.
The README table entry for AWS Bedrock says "Auth Method: API key or AWS credentials" and "Env Var: AWS_BEARER_TOKEN_BEDROCK". However, this PR explicitly removes bearer token auth as non-functional. The bedrock_api_key secret and AWS_BEARER_TOKEN_BEDROCK env var mapping added in src/config/mod.rs is vestigial and misleading — it maps a bedrock_api_key secret to an env var that the new native Bedrock provider never reads. The README and the secret injection mapping in mod.rs should be updated to reflect that the actual auth is through standard AWS credential chain, not a bearer token or API key stored in the secrets system.
| | AWS Bedrock | API key or AWS credentials | `bedrock_api_key` | `AWS_BEARER_TOKEN_BEDROCK` | | |
| | AWS Bedrock | AWS credential chain (no app-managed secret) | - | - | |
There was a problem hiding this comment.
Fixed in 51061e7 — updated README table to remove bearer token/API key references. Bedrock now shows "AWS credentials (IAM, SSO, instance roles)" with no secret name or env var.
| let mut mappings: Vec<(&str, &str)> = vec![ | ||
| ("llm_nearai_api_key", "NEARAI_API_KEY"), | ||
| ("llm_anthropic_oauth_token", "ANTHROPIC_OAUTH_TOKEN"), | ||
| ("bedrock_api_key", "AWS_BEARER_TOKEN_BEDROCK"), |
There was a problem hiding this comment.
The bedrock_api_key → AWS_BEARER_TOKEN_BEDROCK mapping added in inject_llm_keys_from_secrets is a leftover from the removed bearer-token auth approach. The new native Bedrock provider reads only BEDROCK_REGION, BEDROCK_MODEL, BEDROCK_CROSS_REGION, and AWS_PROFILE — it never reads AWS_BEARER_TOKEN_BEDROCK. This mapping will silently load a stale secret and set an env var that has no effect, potentially causing confusion. It should be removed.
| ("bedrock_api_key", "AWS_BEARER_TOKEN_BEDROCK"), |
There was a problem hiding this comment.
Fixed in 51061e7 — removed the dead bedrock_api_key → AWS_BEARER_TOKEN_BEDROCK mapping from inject_llm_keys_from_secrets.
| fn build_inference_config( | ||
| temperature: Option<f32>, | ||
| max_tokens: Option<u32>, | ||
| ) -> Option<InferenceConfiguration> { | ||
| let mut builder = InferenceConfiguration::builder(); | ||
| let mut needs_config = false; | ||
|
|
||
| if let Some(temp) = temperature { | ||
| builder = builder.temperature(temp); | ||
| needs_config = true; | ||
| } | ||
| if let Some(tokens) = max_tokens { | ||
| builder = builder.max_tokens(i32::try_from(tokens).unwrap_or(i32::MAX)); | ||
| needs_config = true; | ||
| } | ||
|
|
||
| if needs_config { | ||
| Some(builder.build()) | ||
| } else { | ||
| None | ||
| } | ||
| } |
There was a problem hiding this comment.
The build_inference_config function only handles temperature and max_tokens, but ignores stop_sequences from both CompletionRequest and ToolCompletionRequest. The AWS Bedrock InferenceConfiguration builder supports .stop_sequences(). If callers pass stop sequences (e.g. the agent loop uses them to detect end-of-turn markers), they will be silently ignored, causing incorrect behavior. The stop_sequences parameter should be passed through to build_inference_config and applied via builder.stop_sequences().
There was a problem hiding this comment.
Fixed in 51061e7 — build_inference_config now accepts stop_sequences: Option<&[String]> and passes them to the Bedrock InferenceConfiguration. Added 2 tests (with sequences + empty sequences).
| ), | ||
| }); | ||
| } | ||
| let profile = optional_env("AWS_PROFILE")?; |
There was a problem hiding this comment.
The PR description claims "Added bedrock_profile fallback from settings in config resolution", but in the actual code (line 302), profile is only resolved from the AWS_PROFILE environment variable — there is no fallback to settings.bedrock_profile. For completeness the resolution should be optional_env("AWS_PROFILE")?.or_else(|| settings.bedrock_profile.clone()). Without this fallback, when AWS_PROFILE is not set as an env var but was saved to settings.bedrock_profile by the wizard, the profile will be silently ignored unless it was also written to the .env file via write_bootstrap_env. While write_bootstrap_env does write AWS_PROFILE, the fallback from settings is still missing for environments where the wizard settings are used directly without loading from .env.
| let profile = optional_env("AWS_PROFILE")?; | |
| let profile = | |
| optional_env("AWS_PROFILE")?.or_else(|| settings.bedrock_profile.clone()); |
There was a problem hiding this comment.
Already fixed in 6009cdb — added .or_else(|| settings.bedrock_profile.clone()) fallback for AWS_PROFILE, consistent with region and cross_region resolution.
|
|
||
| ### Added | ||
|
|
||
| - AWS Bedrock LLM provider via native Converse API with bearer token, IAM, and SSO auth support (feature-gated: `--features bedrock`) |
There was a problem hiding this comment.
The CHANGELOG entry says "with bearer token, IAM, and SSO auth support", but bearer token auth (AWS_BEARER_TOKEN_BEDROCK) was explicitly removed in this PR per reviewer feedback (the PR description states "Removed non-functional bearer token auth"). The entry should instead describe the supported authentication methods: IAM credentials, SSO profiles, and instance roles.
There was a problem hiding this comment.
Fixed in 51061e7 — CHANGELOG entry now says "with IAM and SSO auth support" instead of "with bearer token, IAM, and SSO auth support".
Regenerating Cargo.lock from scratch caused transitive dependency version drift that broke the html_to_markdown fixture test in CI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…file fallback
- Move is_bedrock check before unknown-backend warning to prevent
spurious "unknown backend" log for bedrock users
- Normalize backend aliases ("aws", "aws_bedrock") to "bedrock" so
the provider factory matches correctly
- Add settings.bedrock_profile fallback for AWS_PROFILE, consistent
with region and cross_region resolution
[skip-regression-check]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Self-ReviewBugs Fixed (commits after initial push)
Known Limitations (acceptable for initial PR)
Generated with Claude Code |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // Bedrock is a special case (native AWS SDK, not registry-based) | ||
| options.push( | ||
| "AWS Bedrock - Claude & other models via AWS (API key, IAM, SSO)".to_string(), |
There was a problem hiding this comment.
The wizard menu entry description says "Claude & other models via AWS (API key, IAM, SSO)" but the setup_bedrock() method only offers AWS default credentials (env vars, ~/.aws/credentials, IAM roles) and named profiles. The mention of "API key" is misleading since bearer token auth was removed. It should be updated to match the actual auth options, e.g., "Claude & other models via AWS (IAM, SSO profiles, instance roles)".
| "AWS Bedrock - Claude & other models via AWS (API key, IAM, SSO)".to_string(), | |
| "AWS Bedrock - Claude & other models via AWS (IAM, SSO profiles, instance roles)" | |
| .to_string(), |
There was a problem hiding this comment.
Fixed in 51061e7 — wizard menu now says "Claude & other models via AWS (IAM, SSO)" without "API key".
| if self.settings.llm_backend.as_deref() == Some("bedrock") { | ||
| if let Some(ref model) = self.settings.selected_model { | ||
| env_vars.push(("BEDROCK_MODEL".to_string(), model.clone())); | ||
| } | ||
| if let Some(ref cross) = self.settings.bedrock_cross_region { | ||
| env_vars.push(("BEDROCK_CROSS_REGION".to_string(), cross.clone())); | ||
| } | ||
| if let Some(ref profile) = self.settings.bedrock_profile { | ||
| env_vars.push(("AWS_PROFILE".to_string(), profile.clone())); | ||
| } | ||
| } |
There was a problem hiding this comment.
When the backend is "bedrock", write_bootstrap_env() writes the model to BEDROCK_MODEL here (line 2408) and then later also writes it to LLM_MODEL via registry.model_env_var("bedrock"), which returns "LLM_MODEL" as a fallback for unknown registry providers. This causes the bedrock model ID to be written redundantly to LLM_MODEL. If the user later switches to an OpenAI-compatible provider that uses LLM_MODEL, the stale Bedrock model name would be picked up. The generic model write below should be skipped when backend_str == "bedrock" since BEDROCK_MODEL is already set.
There was a problem hiding this comment.
Fixed in 51061e7 — write_bootstrap_env now skips the LLM_MODEL write when backend is bedrock, since BEDROCK_MODEL is already written above.
…uences, model dedup - Remove stale bearer token refs from setup README and CHANGELOG - Remove dead bedrock_api_key secret injection mapping - Pass stop_sequences through to Bedrock InferenceConfiguration - Remove "API key" from wizard menu description (bearer token removed) - Skip duplicate LLM_MODEL write for bedrock backend in wizard - Fix cargo fmt formatting [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ock-provider # Conflicts: # src/config/llm.rs # src/llm/mod.rs # src/setup/wizard.rs
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 0 => { | ||
| // Default AWS credentials | ||
| print_info( | ||
| "Using default AWS credential chain (env vars, ~/.aws/credentials, IAM roles).", | ||
| ); | ||
| } |
There was a problem hiding this comment.
When auth choice 0 (default AWS credentials) is selected in setup_bedrock(), the existing self.settings.bedrock_profile is not cleared. If the user previously configured a named profile and then re-runs the wizard choosing "default credentials", the stale profile will persist in settings and will be written to .env as AWS_PROFILE (line 2431-2433 in write_bootstrap_env). This means the SDK will continue to use the old profile instead of the default credential chain. The match arm for 0 should explicitly set self.settings.bedrock_profile = None;.
There was a problem hiding this comment.
Fixed in 13f151c — setup_bedrock() now clears self.settings.bedrock_profile = None when auth choice 0 (default credentials) is selected. Added regression test test_bedrock_clears_stale_profile_on_default_creds.
| self.settings.llm_backend = Some("bedrock".to_string()); | ||
| if self.settings.selected_model.is_some() { | ||
| self.settings.selected_model = None; | ||
| } |
There was a problem hiding this comment.
setup_bedrock() unconditionally resets selected_model = None at the start, even when the user was already on bedrock and confirmed "Keep current provider?" in the wizard. All other provider setup functions (e.g. setup_openai_compatible_generic, setup_ollama_generic) only clear the model when switching to a different provider (checked with if self.settings.llm_backend.as_deref() != Some(backend_id)). This means running the wizard again on an already-configured Bedrock install will always clear the previously selected model, forcing re-entry. The guard should be if self.settings.llm_backend.as_deref() != Some("bedrock") before clearing.
| self.settings.llm_backend = Some("bedrock".to_string()); | |
| if self.settings.selected_model.is_some() { | |
| self.settings.selected_model = None; | |
| } | |
| // Clear model only when switching providers (old model may be invalid) | |
| if self.settings.llm_backend.as_deref() != Some("bedrock") { | |
| self.settings.selected_model = None; | |
| } | |
| self.settings.llm_backend = Some("bedrock".to_string()); |
There was a problem hiding this comment.
Fixed in 13f151c — setup_bedrock() now uses the established pattern from #600: if self.settings.llm_backend.as_deref() != Some("bedrock") { self.settings.selected_model = None; }. Model is preserved when re-entering the same provider, cleared when switching. Added regression test test_bedrock_same_provider_preserves_model.
zmanian
left a comment
There was a problem hiding this comment.
Not redundant with #676 -- this is a significant upgrade from proxy-based (LiteLLM) to native Converse API. Eliminates an external dependency, uses standard AWS credential chain, and handles Bedrock-specific features (ToolResult status, GuardrailIntervened, ModelContextWindowExceeded). Well-structured (1153 lines) with 31 unit tests.
Issues to address:
1. Dead `providers.json` entry (must fix). The PR intercepts `bedrock` before the registry lookup, making the existing `providers.json` bedrock entry unreachable dead code. Either remove it or rename to `bedrock_proxy` for users who want the LiteLLM path.
2. CMake build dependency (must document). `aws-lc-sys` (transitive dep via `aws-sdk-bedrockruntime`) requires CMake at build time. This could break CI or user builds. Document this requirement in the Bedrock section of provider docs.
3. `block_in_place` in constructor (should fix). `BedrockProvider::new` uses `tokio::task::block_in_place` + `Handle::current().block_on()` to load AWS config. This panics in `current_thread` runtimes (tests). Consider making `new` async.
4. No streaming support (note for follow-up). The Bedrock Converse API supports `converse_stream()` but this uses `converse()` only. Users see nothing until the full response completes.
…ard fixes - Remove dead LiteLLM-based bedrock entry from providers.json (native Converse API intercepts before registry lookup) - Make BedrockProvider::new() async to avoid block_in_place panic in current_thread runtimes; propagate async to create_llm_provider, build_provider_chain, and init_llm - Document CMake build prerequisite in docs/LLM_PROVIDERS.md - Clear bedrock_profile when user selects "default credentials" in wizard - Fix selected_model clearing to match established pattern (conditional on provider switch, not unconditional) - Add regression tests for bedrock model preservation and profile clearing Addresses review feedback from @zmanian on PR #713. Streaming support tracked in #741. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@zmanian Addressed all review feedback in 13f151c:
All changes include regression tests. CI should be green (2633 unit tests pass; the 2 |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -502,6 +509,8 @@ OBSERVABILITY_BACKEND=none # none/noop (default) or log | |||
|
|
|||
| Backends: `nearai` (default), `openai`, `anthropic`, `ollama`, `openai_compatible`, `tinfoil` — set via `LLM_BACKEND`. See [src/llm/CLAUDE.md](src/llm/CLAUDE.md) for per-provider auth and configuration details. | |||
There was a problem hiding this comment.
Line 510 in CLAUDE.md lists the LLM backends as nearai, openai, anthropic, ollama, openai_compatible, tinfoil — but bedrock is now also a supported backend. The inline list should include bedrock (noting the --features bedrock requirement) so developers know it exists when scanning this quick reference.
| Backends: `nearai` (default), `openai`, `anthropic`, `ollama`, `openai_compatible`, `tinfoil` — set via `LLM_BACKEND`. See [src/llm/CLAUDE.md](src/llm/CLAUDE.md) for per-provider auth and configuration details. | |
| Backends: `nearai` (default), `openai`, `anthropic`, `ollama`, `openai_compatible`, `tinfoil`, `bedrock` (requires `--features bedrock`) — set via `LLM_BACKEND`. See [src/llm/CLAUDE.md](src/llm/CLAUDE.md) for per-provider auth and configuration details. |
There was a problem hiding this comment.
Fixed in 1730bd9 — added bedrock (with --features bedrock note) to the inline backend list in CLAUDE.md.
|
|
||
| if is_known && confirm("Keep current provider?", true).map_err(SetupError::Io)? { | ||
| if current == "bedrock" { | ||
| return self.setup_bedrock().await; |
There was a problem hiding this comment.
When the user confirms "Keep current provider?" for a Bedrock provider at line 833, the code calls self.setup_bedrock().await which unconditionally re-runs the full setup flow: asking for region, auth method, and cross-region prefix. This is inconsistent with the stated intent of "keeping" the current provider — the user is forced to re-configure all settings even when keeping the same provider.
By contrast, the NEAR AI path calls run_provider_setup which has an early-return if the session is still valid (session.has_token().await check), and API key providers offer "Use this key?" confirmation before re-entering.
setup_bedrock() should check if a valid config already exists and offer to skip re-configuration (similar to how setup_nearai checks for an existing session, or how setup_api_key_provider checks for an existing env var with "Use this key?"). Without this, every --provider-only wizard re-run on a Bedrock setup forces the user to re-select region, auth, and cross-region even when nothing has changed.
| return self.setup_bedrock().await; | |
| // For Bedrock, keeping the current provider should not force re-running | |
| // the entire setup flow (region, auth, cross-region prefix). We simply | |
| // keep the existing configuration. | |
| print_info("Keeping existing AWS Bedrock configuration."); | |
| return Ok(()); |
There was a problem hiding this comment.
Fixed in 1730bd9 — when user confirms "Keep current provider?" for Bedrock, we now early-return with "Keeping existing AWS Bedrock configuration" instead of re-running the full setup flow (region, auth, cross-region).
| // Named profile | ||
| let profile = | ||
| input("AWS profile name (from ~/.aws/config)").map_err(SetupError::Io)?; | ||
| if !profile.is_empty() { |
There was a problem hiding this comment.
When auth choice 1 (named profile) is selected but the user enters an empty string, self.settings.bedrock_profile is left unchanged. If a profile was previously configured, it will remain set and be written to .env as AWS_PROFILE by write_bootstrap_env. The user has no way to clear a previously configured profile by pressing Enter here. The empty-profile case should either return an error (requiring a non-empty profile name when "named profile" is selected) or clear the existing profile, consistent with what auth choice 0 does.
| if !profile.is_empty() { | |
| if profile.trim().is_empty() { | |
| // Empty input clears any previously configured profile | |
| self.settings.bedrock_profile = None; | |
| print_info( | |
| "AWS profile cleared; using default AWS credential chain instead.", | |
| ); | |
| } else { |
There was a problem hiding this comment.
Fixed in 1730bd9 — empty profile input now clears bedrock_profile and informs the user ("AWS profile cleared; using default AWS credential chain instead"). Added regression test test_bedrock_empty_profile_clears_existing.
* feat: add AWS Bedrock LLM provider via native Converse API * fix: use JSON parsing for tool result error detection instead of brittle substring matching * refactor: extract duplicated inference config builder into helper function * fix: address review feedback — safe casts, input validation, and tests - Safe u32→i32 cast for max_tokens using try_from with clamp - Remove brittle string-based error detection fallback for tool results - Validate BEDROCK_CROSS_REGION against allowed values (us/eu/apac/global) - Validate message list is non-empty before Converse API call - Log when using default us-east-1 region - Update llm_backend doc comment to list all backends - Add tests for build_inference_config and empty message handling * fix: persist AWS_PROFILE for Bedrock named profile auth The wizard collected the profile name but only printed a hint to set it manually. Now it saves to settings and writes AWS_PROFILE to the bootstrap .env, consistent with how BEDROCK_REGION and other Bedrock settings are persisted. * feat: gate AWS Bedrock behind optional `bedrock` feature flag The AWS SDK dependencies (aws-config, aws-sdk-bedrockruntime, aws-smithy-types) require cmake and a C compiler to build aws-lc-sys. Gate them behind an opt-in `bedrock` feature flag so default builds are unaffected. Build with: cargo build --features bedrock All config, settings, and wizard code stays unconditional (no AWS deps) so users can configure Bedrock even without the feature compiled — they get a clear error at startup directing them to rebuild. * fix: address review feedback and adapt Bedrock provider to registry architecture (takeover nearai#345) - Resolve merge conflicts with main's registry-based provider system - Add missing cache_creation_input_tokens/cache_read_input_tokens fields - Add missing content_parts field in test ChatMessage - Fix string literal type mismatches in wizard env_vars (.to_string()) - Remove non-functional bearer token auth (AWS_BEARER_TOKEN_BEDROCK) from wizard and documentation per reviewer feedback from @zmanian and @serrrfirat - Remove stale BEDROCK_ACCESS_KEY proxy entry from provider table - Update Bedrock provider to use is_bedrock string check (LlmBackend enum removed) - Add bedrock_profile fallback from settings in config resolution [skip-regression-check] Co-Authored-By: cgorski <cgorski@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use main's Cargo.lock as base to preserve dependency versions Regenerating Cargo.lock from scratch caused transitive dependency version drift that broke the html_to_markdown fixture test in CI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: bedrock config bugs — spurious warning, alias normalization, profile fallback - Move is_bedrock check before unknown-backend warning to prevent spurious "unknown backend" log for bedrock users - Normalize backend aliases ("aws", "aws_bedrock") to "bedrock" so the provider factory matches correctly - Add settings.bedrock_profile fallback for AWS_PROFILE, consistent with region and cross_region resolution [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address Copilot review feedback — bearer token cleanup, stop_sequences, model dedup - Remove stale bearer token refs from setup README and CHANGELOG - Remove dead bedrock_api_key secret injection mapping - Pass stop_sequences through to Bedrock InferenceConfiguration - Remove "API key" from wizard menu description (bearer token removed) - Skip duplicate LLM_MODEL write for bedrock backend in wizard - Fix cargo fmt formatting [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address review feedback — async new(), remove LiteLLM entry, wizard fixes - Remove dead LiteLLM-based bedrock entry from providers.json (native Converse API intercepts before registry lookup) - Make BedrockProvider::new() async to avoid block_in_place panic in current_thread runtimes; propagate async to create_llm_provider, build_provider_chain, and init_llm - Document CMake build prerequisite in docs/LLM_PROVIDERS.md - Clear bedrock_profile when user selects "default credentials" in wizard - Fix selected_model clearing to match established pattern (conditional on provider switch, not unconditional) - Add regression tests for bedrock model preservation and profile clearing Addresses review feedback from @zmanian on PR nearai#713. Streaming support tracked in nearai#741. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address remaining review comments — CLAUDE.md backends, wizard UX - Add `bedrock` to CLAUDE.md inline backend list (nearai#10) - Skip full setup re-run when keeping existing Bedrock config (nearai#11) - Clear stale bedrock_profile on empty named-profile input (nearai#12) - Add regression test for empty profile clearing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Chris Gorski <cgorski@cgorski.org> Co-authored-by: cgorski <cgorski@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add AWS Bedrock LLM provider via native Converse API * fix: use JSON parsing for tool result error detection instead of brittle substring matching * refactor: extract duplicated inference config builder into helper function * fix: address review feedback — safe casts, input validation, and tests - Safe u32→i32 cast for max_tokens using try_from with clamp - Remove brittle string-based error detection fallback for tool results - Validate BEDROCK_CROSS_REGION against allowed values (us/eu/apac/global) - Validate message list is non-empty before Converse API call - Log when using default us-east-1 region - Update llm_backend doc comment to list all backends - Add tests for build_inference_config and empty message handling * fix: persist AWS_PROFILE for Bedrock named profile auth The wizard collected the profile name but only printed a hint to set it manually. Now it saves to settings and writes AWS_PROFILE to the bootstrap .env, consistent with how BEDROCK_REGION and other Bedrock settings are persisted. * feat: gate AWS Bedrock behind optional `bedrock` feature flag The AWS SDK dependencies (aws-config, aws-sdk-bedrockruntime, aws-smithy-types) require cmake and a C compiler to build aws-lc-sys. Gate them behind an opt-in `bedrock` feature flag so default builds are unaffected. Build with: cargo build --features bedrock All config, settings, and wizard code stays unconditional (no AWS deps) so users can configure Bedrock even without the feature compiled — they get a clear error at startup directing them to rebuild. * fix: address review feedback and adapt Bedrock provider to registry architecture (takeover nearai#345) - Resolve merge conflicts with main's registry-based provider system - Add missing cache_creation_input_tokens/cache_read_input_tokens fields - Add missing content_parts field in test ChatMessage - Fix string literal type mismatches in wizard env_vars (.to_string()) - Remove non-functional bearer token auth (AWS_BEARER_TOKEN_BEDROCK) from wizard and documentation per reviewer feedback from @zmanian and @serrrfirat - Remove stale BEDROCK_ACCESS_KEY proxy entry from provider table - Update Bedrock provider to use is_bedrock string check (LlmBackend enum removed) - Add bedrock_profile fallback from settings in config resolution [skip-regression-check] Co-Authored-By: cgorski <cgorski@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use main's Cargo.lock as base to preserve dependency versions Regenerating Cargo.lock from scratch caused transitive dependency version drift that broke the html_to_markdown fixture test in CI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: bedrock config bugs — spurious warning, alias normalization, profile fallback - Move is_bedrock check before unknown-backend warning to prevent spurious "unknown backend" log for bedrock users - Normalize backend aliases ("aws", "aws_bedrock") to "bedrock" so the provider factory matches correctly - Add settings.bedrock_profile fallback for AWS_PROFILE, consistent with region and cross_region resolution [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address Copilot review feedback — bearer token cleanup, stop_sequences, model dedup - Remove stale bearer token refs from setup README and CHANGELOG - Remove dead bedrock_api_key secret injection mapping - Pass stop_sequences through to Bedrock InferenceConfiguration - Remove "API key" from wizard menu description (bearer token removed) - Skip duplicate LLM_MODEL write for bedrock backend in wizard - Fix cargo fmt formatting [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address review feedback — async new(), remove LiteLLM entry, wizard fixes - Remove dead LiteLLM-based bedrock entry from providers.json (native Converse API intercepts before registry lookup) - Make BedrockProvider::new() async to avoid block_in_place panic in current_thread runtimes; propagate async to create_llm_provider, build_provider_chain, and init_llm - Document CMake build prerequisite in docs/LLM_PROVIDERS.md - Clear bedrock_profile when user selects "default credentials" in wizard - Fix selected_model clearing to match established pattern (conditional on provider switch, not unconditional) - Add regression tests for bedrock model preservation and profile clearing Addresses review feedback from @zmanian on PR nearai#713. Streaming support tracked in nearai#741. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address remaining review comments — CLAUDE.md backends, wizard UX - Add `bedrock` to CLAUDE.md inline backend list (nearai#10) - Skip full setup re-run when keeping existing Bedrock config (nearai#11) - Clear stale bedrock_profile on empty named-profile input (nearai#12) - Add regression test for empty profile clearing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Chris Gorski <cgorski@cgorski.org> Co-authored-by: cgorski <cgorski@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Continuation of #345 by @cgorski.
Adds native AWS Bedrock support using
aws-sdk-bedrockruntime's Converse API, bypassing the OpenAI-compatible layer. Feature-gated behind--features bedrockto avoid pulling heavy AWS SDK dependencies by default. Supports IAM credentials, SSO profiles, instance roles, and cross-region inference routing.Changes from original
RegistryProviderConfig/ string-based backend systemcache_creation_input_tokensandcache_read_input_tokensfields (from Anthropic prompt caching feature)content_partsfield in testChatMessagestructwrite_bootstrap_env()AWS_BEARER_TOKEN_BEDROCK) from wizard and docs per reviewer feedbackBEDROCK_ACCESS_KEYproxy entry from provider tablebedrock_profilefallback from settings in config resolutionOriginal PR
#345 - feat: add AWS Bedrock LLM provider via native Converse API
Review comments addressed
Test plan
cargo clippy --all --all-features— zero warningscargo check --features bedrockandcargo check --features bedrock --tests— cleanCo-Authored-By: cgorski cgorski@users.noreply.github.com
Generated with Claude Code