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.
- bedrock_agentcore_starter_toolkit/__init__.py +5 -0
- bedrock_agentcore_starter_toolkit/cli/cli.py +39 -0
- bedrock_agentcore_starter_toolkit/cli/common.py +44 -0
- bedrock_agentcore_starter_toolkit/cli/gateway/__init__.py +1 -0
- bedrock_agentcore_starter_toolkit/cli/gateway/commands.py +88 -0
- bedrock_agentcore_starter_toolkit/cli/runtime/__init__.py +1 -0
- bedrock_agentcore_starter_toolkit/cli/runtime/commands.py +603 -0
- bedrock_agentcore_starter_toolkit/cli/runtime/configuration_manager.py +124 -0
- bedrock_agentcore_starter_toolkit/notebook/__init__.py +5 -0
- bedrock_agentcore_starter_toolkit/notebook/runtime/__init__.py +1 -0
- bedrock_agentcore_starter_toolkit/notebook/runtime/bedrock_agentcore.py +196 -0
- bedrock_agentcore_starter_toolkit/operations/__init__.py +1 -0
- bedrock_agentcore_starter_toolkit/operations/gateway/README.md +277 -0
- bedrock_agentcore_starter_toolkit/operations/gateway/__init__.py +6 -0
- bedrock_agentcore_starter_toolkit/operations/gateway/client.py +456 -0
- bedrock_agentcore_starter_toolkit/operations/gateway/constants.py +152 -0
- bedrock_agentcore_starter_toolkit/operations/gateway/create_lambda.py +85 -0
- bedrock_agentcore_starter_toolkit/operations/gateway/create_role.py +89 -0
- bedrock_agentcore_starter_toolkit/operations/gateway/exceptions.py +13 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/__init__.py +26 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/configure.py +227 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/invoke.py +129 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/launch.py +163 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/models.py +76 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/status.py +66 -0
- bedrock_agentcore_starter_toolkit/services/ecr.py +55 -0
- bedrock_agentcore_starter_toolkit/services/runtime.py +383 -0
- bedrock_agentcore_starter_toolkit/utils/endpoints.py +32 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/config.py +129 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/container.py +310 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/entrypoint.py +197 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/logs.py +33 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/schema.py +141 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/templates/Dockerfile.j2 +59 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/templates/dockerignore.template +69 -0
- bedrock_agentcore_starter_toolkit-0.1.0.dist-info/METADATA +137 -0
- bedrock_agentcore_starter_toolkit-0.1.0.dist-info/RECORD +41 -0
- bedrock_agentcore_starter_toolkit-0.1.0.dist-info/entry_points.txt +2 -0
- bedrock_agentcore_starter_toolkit-0.1.0.dist-info/licenses/NOTICE.txt +190 -0
- bedrock_agentcore_starter_toolkit/init.py +0 -3
- bedrock_agentcore_starter_toolkit-0.0.1.dist-info/METADATA +0 -26
- bedrock_agentcore_starter_toolkit-0.0.1.dist-info/RECORD +0 -5
- {bedrock_agentcore_starter_toolkit-0.0.1.dist-info → bedrock_agentcore_starter_toolkit-0.1.0.dist-info}/WHEEL +0 -0
- /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
|
+
)
|