Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions .github/workflows/sync-from-public.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Sync from Public Repo

on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
workflow_dispatch: # Manual trigger via Actions tab

permissions:
contents: write
pull-requests: write

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Fetch public main
run: |
git remote add public https://github.com/aws/bedrock-agentcore-sdk-python.git
git fetch public main

- name: Sync main with public/main
run: |
git checkout main
git reset --hard origin/main

# Check if public/main is already merged
if git merge-base --is-ancestor public/main HEAD; then
echo "✅ main is already up to date with public/main"
exit 0
fi

# Try to merge public/main
if git merge public/main -m "chore: sync main with public/main"; then
git push origin main
echo "✅ main synced successfully"
else
echo "⚠️ Conflict detected in main"

# Capture conflicted files before aborting
conflicted_files=$(git diff --name-only --diff-filter=U 2>/dev/null || echo "Unable to determine conflicted files")
git merge --abort

# Check if a sync PR already exists
existing_pr=$(gh pr list --base "main" --search "Merge public/main" --state open --json number --jq '.[0].number' 2>/dev/null || echo "")

if [ -n "$existing_pr" ]; then
echo "ℹ️ PR #$existing_pr already exists, skipping"
exit 0
fi

conflict_branch="sync-conflict-main-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$conflict_branch"

git merge public/main --no-commit --no-ff || true
git add -A
git commit -m "chore: sync main with public/main (conflicts present)

This automated sync detected merge conflicts that require manual resolution.

Source: public/main (https://github.com/aws/bedrock-agentcore-sdk-python)
Target: main

Please resolve conflicts and merge this PR." || true

git push origin "$conflict_branch"

gh pr create \
--title "🔀 [Sync Conflict] Merge public/main → main" \
--body "## Automated Sync Conflict

This PR was automatically created because merging \`public/main\` into \`main\` encountered conflicts.

**Source:** \`main\` from [aws/bedrock-agentcore-sdk-python](https://github.com/aws/bedrock-agentcore-sdk-python)
**Target:** \`main\`

### Action Required
1. \`git fetch origin && git checkout $conflict_branch\`
2. Resolve merge conflicts
3. \`git add . && git commit\`
4. \`git push origin $conflict_branch\`
5. Merge this PR

### Files with Conflicts
\`\`\`
$conflicted_files
\`\`\`" \
--base "main" \
--head "$conflict_branch" || echo "⚠️ Failed to create PR"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23 changes: 18 additions & 5 deletions src/bedrock_agentcore/memory/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,30 @@ class MemoryClient:
"list_memory_strategies",
}

def __init__(self, region_name: Optional[str] = None, integration_source: Optional[str] = None):
"""Initialize the Memory client."""
self.region_name = region_name or boto3.Session().region_name or "us-west-2"
def __init__(
self,
region_name: Optional[str] = None,
integration_source: Optional[str] = None,
boto3_session: Optional[boto3.Session] = None,
):
"""Initialize the Memory client.

Args:
region_name: AWS region name. If not provided, uses the session's region or "us-west-2".
integration_source: Optional integration source for user-agent telemetry.
boto3_session: Optional boto3 Session to use. If not provided, a default session
is created. Useful for named profiles or custom credentials.
"""
session = boto3_session if boto3_session else boto3.Session()
self.region_name = region_name or session.region_name or "us-west-2"
self.integration_source = integration_source

# Build config with user-agent for telemetry
user_agent_extra = build_user_agent_suffix(integration_source)
client_config = Config(user_agent_extra=user_agent_extra)

self.gmcp_client = boto3.client("bedrock-agentcore-control", region_name=self.region_name, config=client_config)
self.gmdp_client = boto3.client("bedrock-agentcore", region_name=self.region_name, config=client_config)
self.gmcp_client = session.client("bedrock-agentcore-control", region_name=self.region_name, config=client_config)
self.gmdp_client = session.client("bedrock-agentcore", region_name=self.region_name, config=client_config)

logger.info(
"Initialized MemoryClient for control plane: %s, data plane: %s",
Expand Down
116 changes: 116 additions & 0 deletions src/bedrock_agentcore/services/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,119 @@ async def get_api_key(self, *, provider_name: str, agent_identity_token: str) ->
req = {"resourceCredentialProviderName": provider_name, "workloadIdentityToken": agent_identity_token}

return self.dp_client.get_resource_api_key(**req)["apiKey"]

def create_payment_credential_provider(
self, name: str, credential_provider_vendor: str, provider_configuration_input: Dict
) -> Dict:
"""Create a payment credential provider.

Args:
name: Unique name for the payment credential provider
credential_provider_vendor: The vendor type (e.g., CoinbaseCDP)
provider_configuration_input: Configuration specific to the vendor, including API credentials

Returns:
Response containing the created payment credential provider details

Raises:
botocore.exceptions.ClientError: If the service request fails (e.g., permission denied,
invalid configuration, resource already exists)
"""
self.logger.info(
"Creating payment credential provider '%s' for vendor '%s'...",
name,
credential_provider_vendor,
)
return self.cp_client.create_payment_credential_provider(
name=name,
credentialProviderVendor=credential_provider_vendor,
providerConfigurationInput=provider_configuration_input,
)

def update_payment_credential_provider(
self, name: str, credential_provider_vendor: str, provider_configuration_input: Dict
) -> Dict:
"""Update an existing payment credential provider.

Args:
name: Name of the payment credential provider to update
credential_provider_vendor: The vendor type (e.g., CoinbaseCDP)
provider_configuration_input: Updated configuration specific to the vendor

Returns:
Response containing the updated payment credential provider details

Raises:
botocore.exceptions.ClientError: If the service request fails (e.g., provider not found,
permission denied, invalid configuration)
"""
self.logger.info(
"Updating payment credential provider '%s' for vendor '%s'...",
name,
credential_provider_vendor,
)
return self.cp_client.update_payment_credential_provider(
name=name,
credentialProviderVendor=credential_provider_vendor,
providerConfigurationInput=provider_configuration_input,
)

def delete_payment_credential_provider(self, name: str) -> Dict:
"""Delete a payment credential provider.

Args:
name: Name of the payment credential provider to delete

Returns:
Response confirming the deletion

Raises:
botocore.exceptions.ClientError: If the service request fails (e.g., provider not found,
permission denied)
"""
self.logger.info("Deleting payment credential provider '%s'...", name)
return self.cp_client.delete_payment_credential_provider(name=name)

def get_payment_credential_provider(self, name: str) -> Dict:
"""Retrieve information about a payment credential provider.

Args:
name: Name of the payment credential provider to retrieve

Returns:
Response containing the payment credential provider details

Raises:
botocore.exceptions.ClientError: If the service request fails (e.g., provider not found,
permission denied)
"""
self.logger.info("Fetching payment credential provider '%s'...", name)
return self.cp_client.get_payment_credential_provider(name=name)

def list_payment_credential_providers(
self, next_token: Optional[str] = None, max_results: Optional[int] = None
) -> Dict:
"""List all payment credential providers.

Args:
next_token: Token for pagination to retrieve the next set of results
max_results: Maximum number of results to return (1-20)

Returns:
Response containing a list of payment credential providers

Raises:
ValueError: If max_results is not in the valid range (1-20)
botocore.exceptions.ClientError: If the service request fails (e.g., permission denied,
service unavailable)
"""
if max_results is not None and (max_results < 1 or max_results > 20):
raise ValueError(f"max_results must be between 1 and 20, got: {max_results}")

self.logger.info("Listing payment credential providers...")
req = {}
if next_token is not None:
req["nextToken"] = next_token
if max_results is not None:
req["maxResults"] = max_results
return self.cp_client.list_payment_credential_providers(**req)
Loading
Loading