feat: add AWS Bedrock AgentCore browser provider (native Rust) (#397)
* feat: add AWS Bedrock AgentCore browser provider (native Rust)
- Add agentcore provider with SigV4 authentication
- AWS SDK deps are optional behind 'agentcore' feature flag
- Build with: cargo build --features agentcore
- Supports AGENTCORE_REGION, AGENTCORE_PROFILE_ID, AGENTCORE_BROWSER_ID env vars
- Returns session ID and Live View URL in launch response
- Add connect_cdp_with_headers for signed WebSocket connections
* test: add unit tests for AgentCore provider
* refactor: use lightweight manual SigV4 signing instead of AWS SDK
- Replace aws-sigv4/aws-config with manual HMAC-SHA256 signing
- Removes ~60s compile time and significant binary size
- Credentials read from AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY env vars
- Supports AWS_SESSION_TOKEN for temporary credentials
* fix: correct AgentCore API endpoints
- Host: bedrock-agentcore.{region}.amazonaws.com
- Start session: PUT /browsers/{id}/sessions/start
- Stop session: PUT /browsers/{id}/sessions/stop
- Add urlencoding for browser ID in path
- Add AWS_DEFAULT_REGION fallback
* fix: use profileConfiguration.profileIdentifier for AgentCore profile
The AWS Bedrock AgentCore API expects profile configuration in the format:
{
"profileConfiguration": {
"profileIdentifier": "<profile-id>"
}
}
Not the flat "profileId" field that was previously used.
* feat: support AWS credential provider chain via AWS CLI
- Try env vars first (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
- Fall back to 'aws configure export-credentials --format env'
- Honor AWS_PROFILE environment variable
- Works with SSO, IAM roles, credential files, etc.
---------
Co-authored-by: Chris Tate <chris@ctate.dev>
This commit is contained in:
co-authored by
Chris Tate
parent
89595836c6
commit
8561a755ef
@@ -1619,8 +1619,18 @@ async fn handle_launch(cmd: &Value, state: &mut DaemonState) -> Result<Value, St
|
||||
}
|
||||
_ => {
|
||||
let conn = providers::connect_provider(provider).await?;
|
||||
|
||||
let ws_headers = if provider.eq_ignore_ascii_case("agentcore") {
|
||||
providers::take_agentcore_ws_headers()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let connect_result = if conn.direct_page {
|
||||
BrowserManager::connect_cdp_direct(&conn.ws_url).await
|
||||
} else if ws_headers.is_some() {
|
||||
BrowserManager::connect_cdp_with_headers(&conn.ws_url, ws_headers)
|
||||
.await
|
||||
} else {
|
||||
BrowserManager::connect_cdp(&conn.ws_url).await
|
||||
};
|
||||
@@ -1633,6 +1643,17 @@ async fn handle_launch(cmd: &Value, state: &mut DaemonState) -> Result<Value, St
|
||||
state.start_dialog_handler();
|
||||
state.update_stream_client().await;
|
||||
write_provider_file(&state.session_id, provider);
|
||||
|
||||
#[cfg(feature = "agentcore")]
|
||||
if let Some(info) = providers::get_agentcore_info() {
|
||||
return Ok(json!({
|
||||
"launched": true,
|
||||
"provider": provider,
|
||||
"agentCoreSessionId": info.session_id,
|
||||
"agentCoreLiveViewUrl": info.live_view_url
|
||||
}));
|
||||
}
|
||||
|
||||
return Ok(json!({ "launched": true, "provider": provider }));
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user