bedrock-agentcore-starter-toolkit 0.0.1__py3-none-any.whl → 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bedrock-agentcore-starter-toolkit might be problematic. Click here for more details.

Files changed (44) hide show
  1. bedrock_agentcore_starter_toolkit/__init__.py +5 -0
  2. bedrock_agentcore_starter_toolkit/cli/cli.py +39 -0
  3. bedrock_agentcore_starter_toolkit/cli/common.py +44 -0
  4. bedrock_agentcore_starter_toolkit/cli/gateway/__init__.py +1 -0
  5. bedrock_agentcore_starter_toolkit/cli/gateway/commands.py +88 -0
  6. bedrock_agentcore_starter_toolkit/cli/runtime/__init__.py +1 -0
  7. bedrock_agentcore_starter_toolkit/cli/runtime/commands.py +603 -0
  8. bedrock_agentcore_starter_toolkit/cli/runtime/configuration_manager.py +124 -0
  9. bedrock_agentcore_starter_toolkit/notebook/__init__.py +5 -0
  10. bedrock_agentcore_starter_toolkit/notebook/runtime/__init__.py +1 -0
  11. bedrock_agentcore_starter_toolkit/notebook/runtime/bedrock_agentcore.py +196 -0
  12. bedrock_agentcore_starter_toolkit/operations/__init__.py +1 -0
  13. bedrock_agentcore_starter_toolkit/operations/gateway/README.md +277 -0
  14. bedrock_agentcore_starter_toolkit/operations/gateway/__init__.py +6 -0
  15. bedrock_agentcore_starter_toolkit/operations/gateway/client.py +456 -0
  16. bedrock_agentcore_starter_toolkit/operations/gateway/constants.py +152 -0
  17. bedrock_agentcore_starter_toolkit/operations/gateway/create_lambda.py +85 -0
  18. bedrock_agentcore_starter_toolkit/operations/gateway/create_role.py +89 -0
  19. bedrock_agentcore_starter_toolkit/operations/gateway/exceptions.py +13 -0
  20. bedrock_agentcore_starter_toolkit/operations/runtime/__init__.py +26 -0
  21. bedrock_agentcore_starter_toolkit/operations/runtime/configure.py +227 -0
  22. bedrock_agentcore_starter_toolkit/operations/runtime/invoke.py +129 -0
  23. bedrock_agentcore_starter_toolkit/operations/runtime/launch.py +163 -0
  24. bedrock_agentcore_starter_toolkit/operations/runtime/models.py +76 -0
  25. bedrock_agentcore_starter_toolkit/operations/runtime/status.py +66 -0
  26. bedrock_agentcore_starter_toolkit/services/ecr.py +55 -0
  27. bedrock_agentcore_starter_toolkit/services/runtime.py +383 -0
  28. bedrock_agentcore_starter_toolkit/utils/endpoints.py +32 -0
  29. bedrock_agentcore_starter_toolkit/utils/runtime/config.py +129 -0
  30. bedrock_agentcore_starter_toolkit/utils/runtime/container.py +310 -0
  31. bedrock_agentcore_starter_toolkit/utils/runtime/entrypoint.py +197 -0
  32. bedrock_agentcore_starter_toolkit/utils/runtime/logs.py +33 -0
  33. bedrock_agentcore_starter_toolkit/utils/runtime/schema.py +141 -0
  34. bedrock_agentcore_starter_toolkit/utils/runtime/templates/Dockerfile.j2 +59 -0
  35. bedrock_agentcore_starter_toolkit/utils/runtime/templates/dockerignore.template +69 -0
  36. bedrock_agentcore_starter_toolkit-0.1.0.dist-info/METADATA +137 -0
  37. bedrock_agentcore_starter_toolkit-0.1.0.dist-info/RECORD +41 -0
  38. bedrock_agentcore_starter_toolkit-0.1.0.dist-info/entry_points.txt +2 -0
  39. bedrock_agentcore_starter_toolkit-0.1.0.dist-info/licenses/NOTICE.txt +190 -0
  40. bedrock_agentcore_starter_toolkit/init.py +0 -3
  41. bedrock_agentcore_starter_toolkit-0.0.1.dist-info/METADATA +0 -26
  42. bedrock_agentcore_starter_toolkit-0.0.1.dist-info/RECORD +0 -5
  43. {bedrock_agentcore_starter_toolkit-0.0.1.dist-info → bedrock_agentcore_starter_toolkit-0.1.0.dist-info}/WHEEL +0 -0
  44. /bedrock_agentcore_starter_toolkit-0.0.1.dist-info/licenses/LICENSE → /bedrock_agentcore_starter_toolkit-0.1.0.dist-info/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,89 @@
1
+ """Creates an execution role to use in the Bedrock AgentCore Gateway module."""
2
+
3
+ import json
4
+ import logging
5
+ from typing import Optional
6
+
7
+ from boto3 import Session
8
+ from botocore.client import BaseClient
9
+ from botocore.exceptions import ClientError
10
+
11
+ from ...operations.gateway.constants import (
12
+ BEDROCK_AGENTCORE_TRUST_POLICY,
13
+ POLICIES,
14
+ POLICIES_TO_CREATE,
15
+ )
16
+
17
+
18
+ def create_gateway_execution_role(
19
+ session: Session, logger: logging.Logger, role_name: str = "AgentCoreGatewayExecutionRole"
20
+ ) -> str:
21
+ """Create the Gateway execution role.
22
+
23
+ :param logger: the logger to use.
24
+ :return: the role ARN.
25
+ """
26
+ iam = session.client("iam")
27
+ # Create the role
28
+ try:
29
+ role = iam.create_role(
30
+ RoleName=role_name,
31
+ AssumeRolePolicyDocument=json.dumps(BEDROCK_AGENTCORE_TRUST_POLICY),
32
+ Description="Execution role for AgentCore Gateway",
33
+ )
34
+ for policy_name, policy in POLICIES_TO_CREATE:
35
+ _attach_policy(
36
+ iam_client=iam,
37
+ role_name=role_name,
38
+ policy_name=policy_name,
39
+ policy_document=json.dumps(policy),
40
+ )
41
+ for policy_arn in POLICIES:
42
+ _attach_policy(iam_client=iam, role_name=role_name, policy_arn=policy_arn)
43
+
44
+ return role["Role"]["Arn"]
45
+
46
+ except iam.exceptions.EntityAlreadyExistsException:
47
+ try:
48
+ role = iam.get_role(RoleName=role_name)
49
+ logger.info("✓ Role already exists: %s", role["Role"]["Arn"])
50
+ return role["Role"]["Arn"]
51
+ except ClientError as e:
52
+ logger.error("Error getting existing role: %s", e)
53
+ raise
54
+ except ClientError as e:
55
+ logger.error("Error creating role: %s", e)
56
+ raise
57
+
58
+
59
+ def _attach_policy(
60
+ iam_client: BaseClient,
61
+ role_name: str,
62
+ policy_arn: Optional[str] = None,
63
+ policy_document: Optional[str] = None,
64
+ policy_name: Optional[str] = None,
65
+ ) -> None:
66
+ """Attach a policy to an IAM role.
67
+
68
+ :param iam_client: the IAM client to use.
69
+ :param role_name: name of the role.
70
+ :param policy_arn: the arn of the policy to attach.
71
+ :param policy_document: the policy document (if not using a policy_arn).
72
+ :param policy_name: the policy name (if not using a policy_arn).
73
+ :return:
74
+ """
75
+ if policy_arn and policy_document:
76
+ raise Exception("Cannot specify both policy arn and policy document.")
77
+ try:
78
+ if policy_arn:
79
+ iam_client.attach_role_policy(RoleName=role_name, PolicyArn=policy_arn)
80
+ elif policy_document and policy_name:
81
+ policy = iam_client.create_policy(
82
+ PolicyName=policy_name,
83
+ PolicyDocument=policy_document,
84
+ )
85
+ iam_client.attach_role_policy(RoleName=role_name, PolicyArn=policy["Policy"]["Arn"])
86
+ else:
87
+ raise Exception("Must specify both policy document and policy name or just a policy arn")
88
+ except ClientError as e:
89
+ raise RuntimeError(f"Failed to attach AgentCore policy: {e}") from e
@@ -0,0 +1,13 @@
1
+ """Exceptions for the Bedrock AgentCore Gateway module."""
2
+
3
+
4
+ class GatewayException(Exception):
5
+ """Base exception for all Gateway SDK errors."""
6
+
7
+ pass
8
+
9
+
10
+ class GatewaySetupException(GatewayException):
11
+ """Raised when gateway or Cognito setup fails."""
12
+
13
+ pass
@@ -0,0 +1,26 @@
1
+ """Bedrock AgentCore operations - shared business logic for CLI and notebook interfaces."""
2
+
3
+ from .configure import configure_bedrock_agentcore, validate_agent_name
4
+ from .invoke import invoke_bedrock_agentcore
5
+ from .launch import launch_bedrock_agentcore
6
+ from .models import (
7
+ ConfigureResult,
8
+ InvokeResult,
9
+ LaunchResult,
10
+ StatusConfigInfo,
11
+ StatusResult,
12
+ )
13
+ from .status import get_status
14
+
15
+ __all__ = [
16
+ "configure_bedrock_agentcore",
17
+ "validate_agent_name",
18
+ "launch_bedrock_agentcore",
19
+ "invoke_bedrock_agentcore",
20
+ "get_status",
21
+ "ConfigureResult",
22
+ "InvokeResult",
23
+ "LaunchResult",
24
+ "StatusResult",
25
+ "StatusConfigInfo",
26
+ ]
@@ -0,0 +1,227 @@
1
+ """Configure operation - creates BedrockAgentCore configuration and Dockerfile."""
2
+
3
+ import logging
4
+ import re
5
+ from pathlib import Path
6
+ from typing import Any, Dict, Optional, Tuple
7
+
8
+ from ...services.ecr import get_account_id, get_region
9
+ from ...utils.runtime.config import merge_agent_config, save_config
10
+ from ...utils.runtime.container import ContainerRuntime
11
+ from ...utils.runtime.schema import (
12
+ AWSConfig,
13
+ BedrockAgentCoreAgentSchema,
14
+ BedrockAgentCoreDeploymentInfo,
15
+ NetworkConfiguration,
16
+ ObservabilityConfig,
17
+ ProtocolConfiguration,
18
+ )
19
+ from .models import ConfigureResult
20
+
21
+ log = logging.getLogger(__name__)
22
+
23
+
24
+ def configure_bedrock_agentcore(
25
+ agent_name: str,
26
+ entrypoint_path: Path,
27
+ execution_role: Optional[str] = None,
28
+ ecr_repository: Optional[str] = None,
29
+ container_runtime: Optional[str] = None,
30
+ auto_create_ecr: bool = True,
31
+ enable_observability: bool = True,
32
+ requirements_file: Optional[str] = None,
33
+ authorizer_configuration: Optional[Dict[str, Any]] = None,
34
+ verbose: bool = False,
35
+ region: Optional[str] = None,
36
+ protocol: Optional[str] = None,
37
+ ) -> ConfigureResult:
38
+ """Configure Bedrock AgentCore application with deployment settings.
39
+
40
+ Args:
41
+ agent_name: name of the agent,
42
+ entrypoint_path: Path to the entrypoint file
43
+ execution_role: AWS execution role ARN or name
44
+ ecr_repository: ECR repository URI
45
+ container_runtime: Container runtime to use
46
+ auto_create_ecr: Whether to auto-create ECR repository
47
+ enable_observability: Whether to enable observability
48
+ requirements_file: Path to requirements file
49
+ authorizer_configuration: JWT authorizer configuration dictionary
50
+ verbose: Whether to provide verbose output during configuration
51
+ region: AWS region for deployment
52
+ protocol: agent server protocol, must be either HTTP or MCP
53
+
54
+ Returns:
55
+ ConfigureResult model with configuration details
56
+ """
57
+ # Set logging level based on verbose flag
58
+ if verbose:
59
+ log.setLevel(logging.DEBUG)
60
+ log.debug("Verbose mode enabled")
61
+ else:
62
+ log.setLevel(logging.INFO)
63
+ # Log agent name at the start of configuration
64
+ log.info("Configuring BedrockAgentCore agent: %s", agent_name)
65
+ build_dir = Path.cwd()
66
+
67
+ if verbose:
68
+ log.debug("Build directory: %s", build_dir)
69
+ log.debug("Bedrock AgentCore name: %s", agent_name)
70
+ log.debug("Entrypoint path: %s", entrypoint_path)
71
+
72
+ # Get AWS info
73
+ if verbose:
74
+ log.debug("Retrieving AWS account information...")
75
+ account_id = get_account_id()
76
+ region = region or get_region()
77
+
78
+ if verbose:
79
+ log.debug("AWS account ID: %s", account_id)
80
+ log.debug("AWS region: %s", region)
81
+
82
+ # Initialize container runtime
83
+ if verbose:
84
+ log.debug("Initializing container runtime with: %s", container_runtime or "default")
85
+ runtime = ContainerRuntime(container_runtime)
86
+
87
+ # Handle execution role ARN
88
+ if execution_role and not execution_role.startswith("arn:aws:iam::"):
89
+ execution_role_arn = f"arn:aws:iam::{account_id}:role/{execution_role}"
90
+ if verbose:
91
+ log.debug("Converting role name to ARN: %s → %s", execution_role, execution_role_arn)
92
+ else:
93
+ execution_role_arn = execution_role
94
+ if verbose:
95
+ log.debug("Using execution role as provided: %s", execution_role_arn)
96
+
97
+ # Generate Dockerfile and .dockerignore
98
+ bedrock_agentcore_name = None
99
+ # Try to find the variable name for the Bedrock AgentCore instance in the file
100
+ if verbose:
101
+ log.debug("Attempting to find Bedrock AgentCore instance name in %s", entrypoint_path)
102
+
103
+ if verbose:
104
+ log.debug("Generating Dockerfile with parameters:")
105
+ log.debug(" Entrypoint: %s", entrypoint_path)
106
+ log.debug(" Build directory: %s", build_dir)
107
+ log.debug(" Bedrock AgentCore name: %s", bedrock_agentcore_name or "bedrock_agentcore")
108
+ log.debug(" Region: %s", region)
109
+ log.debug(" Enable observability: %s", enable_observability)
110
+ log.debug(" Requirements file: %s", requirements_file)
111
+
112
+ dockerfile_path = runtime.generate_dockerfile(
113
+ entrypoint_path,
114
+ build_dir,
115
+ bedrock_agentcore_name or "bedrock_agentcore",
116
+ region,
117
+ enable_observability,
118
+ requirements_file,
119
+ )
120
+
121
+ # Check if .dockerignore was created
122
+ dockerignore_path = build_dir / ".dockerignore"
123
+
124
+ log.info("Generated Dockerfile: %s", dockerfile_path)
125
+ if dockerignore_path.exists():
126
+ log.info("Generated .dockerignore: %s", dockerignore_path)
127
+
128
+ # Handle project configuration (named agents)
129
+ config_path = build_dir / ".bedrock_agentcore.yaml"
130
+
131
+ if verbose:
132
+ log.debug("Agent name from BedrockAgentCoreApp: %s", agent_name)
133
+ log.debug("Config path: %s", config_path)
134
+
135
+ # Determine entrypoint format
136
+ if bedrock_agentcore_name:
137
+ entrypoint = f"{str(entrypoint_path)}:{bedrock_agentcore_name}"
138
+ else:
139
+ entrypoint = str(entrypoint_path)
140
+
141
+ if verbose:
142
+ log.debug("Using entrypoint format: %s", entrypoint)
143
+
144
+ # Create new configuration
145
+ ecr_auto_create_value = bool(auto_create_ecr and not ecr_repository)
146
+
147
+ if verbose:
148
+ log.debug("ECR auto-create: %s", ecr_auto_create_value)
149
+
150
+ if verbose:
151
+ log.debug("Creating BedrockAgentCoreConfigSchema with following parameters:")
152
+ log.debug(" Name: %s", agent_name)
153
+ log.debug(" Entrypoint: %s", entrypoint)
154
+ log.debug(" Platform: %s", ContainerRuntime.DEFAULT_PLATFORM)
155
+ log.debug(" Container runtime: %s", runtime.runtime)
156
+ log.debug(" Execution role: %s", execution_role_arn)
157
+ ecr_repo_display = ecr_repository if ecr_repository else "Auto-create" if ecr_auto_create_value else "N/A"
158
+ log.debug(" ECR repository: %s", ecr_repo_display)
159
+ log.debug(" Enable observability: %s", enable_observability)
160
+
161
+ # Create new agent configuration
162
+ config = BedrockAgentCoreAgentSchema(
163
+ name=agent_name,
164
+ entrypoint=entrypoint,
165
+ platform=ContainerRuntime.DEFAULT_PLATFORM,
166
+ container_runtime=runtime.runtime,
167
+ aws=AWSConfig(
168
+ execution_role=execution_role_arn,
169
+ account=account_id,
170
+ region=region,
171
+ ecr_repository=ecr_repository,
172
+ ecr_auto_create=ecr_auto_create_value,
173
+ network_configuration=NetworkConfiguration(network_mode="PUBLIC"),
174
+ protocol_configuration=ProtocolConfiguration(server_protocol=protocol or "HTTP"),
175
+ observability=ObservabilityConfig(enabled=enable_observability),
176
+ ),
177
+ bedrock_agentcore=BedrockAgentCoreDeploymentInfo(),
178
+ authorizer_configuration=authorizer_configuration,
179
+ )
180
+
181
+ # Use simplified config merging
182
+ project_config = merge_agent_config(config_path, agent_name, config)
183
+ save_config(project_config, config_path)
184
+
185
+ if verbose:
186
+ log.debug("Configuration saved with agent: %s", agent_name)
187
+
188
+ return ConfigureResult(
189
+ config_path=config_path,
190
+ dockerfile_path=dockerfile_path,
191
+ dockerignore_path=dockerignore_path if dockerignore_path.exists() else None,
192
+ runtime=runtime.get_name(),
193
+ region=region,
194
+ account_id=account_id,
195
+ execution_role=execution_role_arn,
196
+ ecr_repository=ecr_repository,
197
+ auto_create_ecr=auto_create_ecr and not ecr_repository,
198
+ )
199
+
200
+
201
+ AGENT_NAME_REGEX = r"^[a-zA-Z][a-zA-Z0-9_]{0,47}$"
202
+ AGENT_NAME_ERROR = (
203
+ "Invalid agent name. Must start with a letter, contain only letters/numbers/underscores, "
204
+ "and be 1-48 characters long."
205
+ )
206
+
207
+
208
+ def validate_agent_name(name: str) -> Tuple[bool, str]:
209
+ """Check if name matches the pattern [a-zA-Z][a-zA-Z0-9_]{0,47}.
210
+
211
+ This pattern requires:
212
+ - First character: letter (a-z or A-Z)
213
+ - Remaining 0-47 characters: letters, digits, or underscores
214
+ - Total maximum length: 48 characters
215
+
216
+ Args:
217
+ name: The string to validate
218
+
219
+ Returns:
220
+ bool: True if the string matches the pattern, False otherwise
221
+ """
222
+ match = bool(re.match(AGENT_NAME_REGEX, name))
223
+
224
+ if match:
225
+ return match, ""
226
+ else:
227
+ return match, AGENT_NAME_ERROR
@@ -0,0 +1,129 @@
1
+ """Invoke operation - invokes deployed Bedrock AgentCore endpoints."""
2
+
3
+ import json
4
+ import logging
5
+ from pathlib import Path
6
+ from typing import Any, Optional
7
+
8
+ from bedrock_agentcore.services.identity import IdentityClient
9
+
10
+ from ...services.runtime import BedrockAgentCoreClient, generate_session_id
11
+ from ...utils.runtime.config import load_config, save_config
12
+ from ...utils.runtime.schema import BedrockAgentCoreConfigSchema
13
+ from .models import InvokeResult
14
+
15
+ log = logging.getLogger(__name__)
16
+
17
+
18
+ def invoke_bedrock_agentcore(
19
+ config_path: Path,
20
+ payload: Any,
21
+ agent_name: Optional[str] = None,
22
+ session_id: Optional[str] = None,
23
+ bearer_token: Optional[str] = None,
24
+ user_id: Optional[str] = None,
25
+ local_mode: Optional[bool] = False,
26
+ ) -> InvokeResult:
27
+ """Invoke deployed Bedrock AgentCore endpoint."""
28
+ # Load project configuration
29
+ project_config = load_config(config_path)
30
+ agent_config = project_config.get_agent_config(agent_name)
31
+ # Log which agent is being invoked
32
+ mode = "locally" if local_mode else "via cloud endpoint"
33
+ log.info("Invoking BedrockAgentCore agent '%s' %s", agent_config.name, mode)
34
+
35
+ region = agent_config.aws.region
36
+ if not region:
37
+ raise ValueError("Region not configured.")
38
+
39
+ agent_arn = agent_config.bedrock_agentcore.agent_arn
40
+
41
+ # Handle session ID
42
+ if not session_id:
43
+ session_id = agent_config.bedrock_agentcore.agent_session_id
44
+ if not session_id:
45
+ session_id = generate_session_id()
46
+
47
+ # Save session ID for reuse
48
+ agent_config.bedrock_agentcore.agent_session_id = session_id
49
+
50
+ # Update project config and save
51
+ project_config.agents[agent_config.name] = agent_config
52
+ save_config(project_config, config_path)
53
+
54
+ # Convert payload to string if needed
55
+ if isinstance(payload, dict):
56
+ payload_str = json.dumps(payload)
57
+ else:
58
+ payload_str = str(payload)
59
+
60
+ if local_mode:
61
+ from ...services.runtime import LocalBedrockAgentCoreClient
62
+
63
+ identity_client = IdentityClient(region)
64
+ workload_name = _get_workload_name(project_config, config_path, agent_config.name, identity_client)
65
+ workload_access_token = identity_client.get_workload_access_token(
66
+ workload_name=workload_name, user_token=bearer_token, user_id=user_id
67
+ )["workloadAccessToken"]
68
+
69
+ # TODO: store and read port config of local running container
70
+ client = LocalBedrockAgentCoreClient("http://0.0.0.0:8080")
71
+ response = client.invoke_endpoint(session_id, payload_str, workload_access_token)
72
+
73
+ else:
74
+ if not agent_arn:
75
+ raise ValueError("Bedrock AgentCore not deployed. Run launch first.")
76
+
77
+ # Invoke endpoint using appropriate client
78
+ if bearer_token:
79
+ if user_id:
80
+ log.warning("Both bearer token and user id are specified, ignoring user id")
81
+
82
+ # Use HTTP client with bearer token
83
+ from ...services.runtime import HttpBedrockAgentCoreClient
84
+
85
+ client = HttpBedrockAgentCoreClient(region)
86
+ response = client.invoke_endpoint(
87
+ agent_arn=agent_arn,
88
+ payload=payload_str,
89
+ session_id=session_id,
90
+ bearer_token=bearer_token,
91
+ )
92
+ else:
93
+ # Use existing boto3 client
94
+ bedrock_agentcore_client = BedrockAgentCoreClient(region)
95
+ response = bedrock_agentcore_client.invoke_endpoint(
96
+ agent_arn=agent_arn, payload=payload_str, session_id=session_id, user_id=user_id
97
+ )
98
+
99
+ return InvokeResult(
100
+ response=response,
101
+ session_id=session_id,
102
+ agent_arn=agent_arn,
103
+ )
104
+
105
+
106
+ def _get_workload_name(
107
+ project_config: BedrockAgentCoreConfigSchema,
108
+ project_config_path: Path,
109
+ agent_name: str,
110
+ identity_client: IdentityClient,
111
+ ) -> str:
112
+ agent_config = project_config.get_agent_config(agent_name)
113
+ oauth_config = agent_config.oauth_configuration
114
+ workload_name = None
115
+ if oauth_config:
116
+ workload_name = oauth_config.get("workload_name", None)
117
+ else:
118
+ oauth_config = {}
119
+ agent_config.oauth_configuration = oauth_config
120
+
121
+ if not workload_name:
122
+ log.info("Workload not detected, creating...")
123
+ workload_name = identity_client.create_workload_identity()["name"]
124
+ log.info("Created workload %s", workload_name)
125
+
126
+ oauth_config["workload_name"] = workload_name
127
+ save_config(project_config, project_config_path)
128
+
129
+ return workload_name
@@ -0,0 +1,163 @@
1
+ """Launch operation - deploys Bedrock AgentCore locally or to cloud."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+ from ...services.ecr import create_ecr_repository, deploy_to_ecr
8
+ from ...services.runtime import BedrockAgentCoreClient
9
+ from ...utils.runtime.config import load_config, save_config
10
+ from ...utils.runtime.container import ContainerRuntime
11
+ from .models import LaunchResult
12
+
13
+ log = logging.getLogger(__name__)
14
+
15
+
16
+ def launch_bedrock_agentcore(
17
+ config_path: Path,
18
+ agent_name: Optional[str] = None,
19
+ local: bool = False,
20
+ push_ecr_only: bool = False,
21
+ env_vars: Optional[dict] = None,
22
+ ) -> LaunchResult:
23
+ """Launch Bedrock AgentCore locally or to cloud.
24
+
25
+ Args:
26
+ config_path: Path to BedrockAgentCore configuration file
27
+ agent_name: Name of agent to launch (for project configurations)
28
+ local: Whether to run locally
29
+ push_ecr_only: Whether to only build and push to ECR without deploying
30
+ env_vars: Environment variables to pass to local container (dict of key-value pairs)
31
+
32
+ Returns:
33
+ LaunchResult model with launch details
34
+ """
35
+ # Load project configuration
36
+ project_config = load_config(config_path)
37
+ agent_config = project_config.get_agent_config(agent_name)
38
+
39
+ # Log which agent is being launched
40
+ mode = "locally" if local else "to ECR only" if push_ecr_only else "to cloud"
41
+ log.info("Launching Bedrock AgentCore agent '%s' %s", agent_config.name, mode)
42
+
43
+ # Validate configuration
44
+ errors = agent_config.validate(for_local=local)
45
+ if errors:
46
+ raise ValueError(f"Invalid configuration: {', '.join(errors)}")
47
+
48
+ # Initialize container runtime
49
+ runtime = ContainerRuntime(agent_config.container_runtime)
50
+
51
+ # Get build context - always use project root (where config and Dockerfile are)
52
+ build_dir = config_path.parent
53
+
54
+ bedrock_agentcore_name = agent_config.name
55
+ tag = f"bedrock_agentcore-{bedrock_agentcore_name}:latest"
56
+
57
+ # Step 1: Build Docker image
58
+ success, output = runtime.build(build_dir, tag)
59
+ if not success:
60
+ error_lines = output[-10:] if len(output) > 10 else output
61
+ raise RuntimeError(f"Build failed: {' '.join(error_lines)}")
62
+
63
+ log.info("Docker image built: %s", tag)
64
+
65
+ if local:
66
+ # Return info for local deployment
67
+ return LaunchResult(
68
+ mode="local",
69
+ tag=tag,
70
+ port=8080,
71
+ runtime=runtime,
72
+ env_vars=env_vars,
73
+ )
74
+
75
+ # Step 2: Push to ECR
76
+ log.info("Uploading to ECR...")
77
+
78
+ region = agent_config.aws.region
79
+ if not region:
80
+ raise ValueError("Region not found in configuration")
81
+
82
+ # Handle ECR repository
83
+ ecr_uri = agent_config.aws.ecr_repository
84
+ if not ecr_uri and agent_config.aws.ecr_auto_create:
85
+ repo_name = f"bedrock_agentcore-{bedrock_agentcore_name}"
86
+ ecr_uri = create_ecr_repository(repo_name, region)
87
+
88
+ # Update the config
89
+ agent_config.aws.ecr_repository = ecr_uri
90
+ agent_config.aws.ecr_auto_create = False
91
+
92
+ # Update the project config and save
93
+ project_config.agents[agent_config.name] = agent_config
94
+ save_config(project_config, config_path)
95
+
96
+ if not ecr_uri:
97
+ raise ValueError("ECR repository not configured and auto-create not enabled")
98
+
99
+ # Deploy to ECR
100
+ repo_name = ecr_uri.split("/")[-1]
101
+ deploy_to_ecr(tag, repo_name, region, runtime)
102
+
103
+ log.info("Image uploaded to ECR: %s", ecr_uri)
104
+
105
+ # If push_ecr_only, return early
106
+ if push_ecr_only:
107
+ return LaunchResult(
108
+ mode="push-ecr",
109
+ tag=tag,
110
+ ecr_uri=ecr_uri,
111
+ build_output=output,
112
+ )
113
+
114
+ # Step 3: Deploy agent
115
+ log.info("Creating/updating agent...")
116
+
117
+ bedrock_agentcore_client = BedrockAgentCoreClient(region)
118
+
119
+ # Transform network configuration to AWS API format
120
+ network_config = agent_config.aws.network_configuration.to_aws_dict()
121
+ protocol_config = agent_config.aws.protocol_configuration.to_aws_dict()
122
+
123
+ if not agent_config.aws.execution_role:
124
+ raise ValueError("Execution role not configured")
125
+
126
+ agent_info = bedrock_agentcore_client.create_or_update_agent(
127
+ agent_id=agent_config.bedrock_agentcore.agent_id,
128
+ agent_name=bedrock_agentcore_name,
129
+ image_uri=f"{ecr_uri}:latest",
130
+ execution_role_arn=agent_config.aws.execution_role,
131
+ network_config=network_config,
132
+ authorizer_config=agent_config.get_authorizer_configuration(),
133
+ protocol_config=protocol_config,
134
+ env_vars=env_vars,
135
+ )
136
+
137
+ # Save deployment info
138
+ agent_id = agent_info["id"]
139
+ agent_arn = agent_info["arn"]
140
+
141
+ # Update the config
142
+ agent_config.bedrock_agentcore.agent_id = agent_id
143
+ agent_config.bedrock_agentcore.agent_arn = agent_arn
144
+
145
+ # Update the project config and save
146
+ project_config.agents[agent_config.name] = agent_config
147
+ save_config(project_config, config_path)
148
+
149
+ log.info("Agent created/updated: %s", agent_arn)
150
+
151
+ # Step 4: Wait for agent to be ready
152
+ log.info("Polling for endpoint to be ready...")
153
+ result = bedrock_agentcore_client.wait_for_agent_endpoint_ready(agent_id)
154
+ log.info("Agent endpoint: %s", result)
155
+
156
+ return LaunchResult(
157
+ mode="cloud",
158
+ tag=tag,
159
+ agent_arn=agent_arn,
160
+ agent_id=agent_id,
161
+ ecr_uri=ecr_uri,
162
+ build_output=output,
163
+ )