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,76 @@
1
+ """Pydantic models for operation requests and responses."""
2
+
3
+ from pathlib import Path
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+
8
+ from ...utils.runtime.container import ContainerRuntime
9
+
10
+
11
+ # Configure operation models
12
+ class ConfigureResult(BaseModel):
13
+ """Result of configure operation."""
14
+
15
+ config_path: Path = Field(..., description="Path to configuration file")
16
+ dockerfile_path: Path = Field(..., description="Path to generated Dockerfile")
17
+ dockerignore_path: Optional[Path] = Field(None, description="Path to generated .dockerignore")
18
+ runtime: str = Field(..., description="Container runtime name")
19
+ region: str = Field(..., description="AWS region")
20
+ account_id: str = Field(..., description="AWS account ID")
21
+ execution_role: Optional[str] = Field(None, description="AWS execution role ARN")
22
+ ecr_repository: Optional[str] = Field(None, description="ECR repository URI")
23
+ auto_create_ecr: bool = Field(False, description="Whether ECR will be auto-created")
24
+
25
+
26
+ # Launch operation models
27
+ class LaunchResult(BaseModel):
28
+ """Result of launch operation."""
29
+
30
+ mode: str = Field(..., description="Launch mode: local, push-ecr, or cloud")
31
+ tag: str = Field(..., description="Docker image tag")
32
+ env_vars: Optional[Dict[str, str]] = Field(default=None, description="Environment variables for local deployment")
33
+
34
+ # Local mode fields
35
+ port: Optional[int] = Field(default=None, description="Port for local deployment")
36
+ runtime: Optional[ContainerRuntime] = Field(default=None, description="Container runtime instance")
37
+
38
+ # Cloud mode fields
39
+ ecr_uri: Optional[str] = Field(default=None, description="ECR repository URI")
40
+ agent_id: Optional[str] = Field(default=None, description="BedrockAgentCore agent ID")
41
+ agent_arn: Optional[str] = Field(default=None, description="BedrockAgentCore agent ARN")
42
+
43
+ # Build output (optional)
44
+ build_output: Optional[List[str]] = Field(default=None, description="Docker build output")
45
+
46
+ model_config = ConfigDict(arbitrary_types_allowed=True) # For runtime field
47
+
48
+
49
+ class InvokeResult(BaseModel):
50
+ """Result of invoke operation."""
51
+
52
+ response: Dict[str, Any] = Field(..., description="Response from Bedrock AgentCore endpoint")
53
+ session_id: str = Field(..., description="Session ID used for invocation")
54
+ agent_arn: Optional[str] = Field(default=None, description="BedrockAgentCore agent ARN")
55
+
56
+
57
+ # Status operation models
58
+ class StatusConfigInfo(BaseModel):
59
+ """Configuration information for status."""
60
+
61
+ name: str = Field(..., description="Bedrock AgentCore application name")
62
+ entrypoint: str = Field(..., description="Entrypoint file path")
63
+ region: Optional[str] = Field(None, description="AWS region")
64
+ account: Optional[str] = Field(None, description="AWS account ID")
65
+ execution_role: Optional[str] = Field(None, description="AWS execution role ARN")
66
+ ecr_repository: Optional[str] = Field(None, description="ECR repository URI")
67
+ agent_id: Optional[str] = Field(None, description="BedrockAgentCore agent ID")
68
+ agent_arn: Optional[str] = Field(None, description="BedrockAgentCore agent ARN")
69
+
70
+
71
+ class StatusResult(BaseModel):
72
+ """Result of status operation."""
73
+
74
+ config: StatusConfigInfo = Field(..., description="Configuration information")
75
+ agent: Optional[Dict[str, Any]] = Field(None, description="Agent runtime details or error")
76
+ endpoint: Optional[Dict[str, Any]] = Field(None, description="Endpoint details or error")
@@ -0,0 +1,66 @@
1
+ """Status operations for Bedrock AgentCore SDK."""
2
+
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ from ...services.runtime import BedrockAgentCoreClient
7
+ from ...utils.runtime.config import load_config
8
+ from .models import StatusConfigInfo, StatusResult
9
+
10
+
11
+ def get_status(config_path: Path, agent_name: Optional[str] = None) -> StatusResult:
12
+ """Get Bedrock AgentCore status including config and runtime details.
13
+
14
+ Args:
15
+ config_path: Path to BedrockAgentCore configuration file
16
+ agent_name: Name of agent to get status for (for project configurations)
17
+
18
+ Returns:
19
+ StatusResult with config, agent, and endpoint status
20
+
21
+ Raises:
22
+ FileNotFoundError: If configuration file doesn't exist
23
+ ValueError: If Bedrock AgentCore is not deployed or configuration is invalid
24
+ """
25
+ # Load project configuration
26
+ project_config = load_config(config_path)
27
+ agent_config = project_config.get_agent_config(agent_name)
28
+
29
+ # Build config info
30
+ config_info = StatusConfigInfo(
31
+ name=agent_config.name,
32
+ entrypoint=agent_config.entrypoint,
33
+ region=agent_config.aws.region,
34
+ account=agent_config.aws.account,
35
+ execution_role=agent_config.aws.execution_role,
36
+ ecr_repository=agent_config.aws.ecr_repository,
37
+ agent_id=agent_config.bedrock_agentcore.agent_id,
38
+ agent_arn=agent_config.bedrock_agentcore.agent_arn,
39
+ )
40
+
41
+ # Initialize status result
42
+ agent_details = None
43
+ endpoint_details = None
44
+
45
+ # If agent is deployed, get runtime status
46
+ if agent_config.bedrock_agentcore.agent_id and agent_config.aws.region:
47
+ try:
48
+ client = BedrockAgentCoreClient(agent_config.aws.region)
49
+
50
+ # Get agent runtime details
51
+ try:
52
+ agent_details = client.get_agent_runtime(agent_config.bedrock_agentcore.agent_id)
53
+ except Exception as e:
54
+ agent_details = {"error": str(e)}
55
+
56
+ # Get endpoint details
57
+ try:
58
+ endpoint_details = client.get_agent_runtime_endpoint(agent_config.bedrock_agentcore.agent_id)
59
+ except Exception as e:
60
+ endpoint_details = {"error": str(e)}
61
+
62
+ except Exception as e:
63
+ agent_details = {"error": f"Failed to initialize Bedrock AgentCore client: {e}"}
64
+ endpoint_details = {"error": f"Failed to initialize Bedrock AgentCore client: {e}"}
65
+
66
+ return StatusResult(config=config_info, agent=agent_details, endpoint=endpoint_details)
@@ -0,0 +1,55 @@
1
+ """ECR (Elastic Container Registry) service integration."""
2
+
3
+ import base64
4
+
5
+ import boto3
6
+
7
+ from ..utils.runtime.container import ContainerRuntime
8
+
9
+
10
+ def get_account_id() -> str:
11
+ """Get AWS account ID."""
12
+ return boto3.client("sts").get_caller_identity()["Account"]
13
+
14
+
15
+ def get_region() -> str:
16
+ """Get AWS region."""
17
+ return boto3.Session().region_name or "us-west-2"
18
+
19
+
20
+ def create_ecr_repository(repo_name: str, region: str) -> str:
21
+ """Create or get existing ECR repository."""
22
+ ecr = boto3.client("ecr", region_name=region)
23
+ try:
24
+ response = ecr.create_repository(repositoryName=repo_name)
25
+ return response["repository"]["repositoryUri"]
26
+ except ecr.exceptions.RepositoryAlreadyExistsException:
27
+ response = ecr.describe_repositories(repositoryNames=[repo_name])
28
+ return response["repositories"][0]["repositoryUri"]
29
+
30
+
31
+ def deploy_to_ecr(local_tag: str, repo_name: str, region: str, container_runtime: ContainerRuntime) -> str:
32
+ """Build and push image to ECR."""
33
+ ecr = boto3.client("ecr", region_name=region)
34
+
35
+ # Get or create repository
36
+ ecr_uri = create_ecr_repository(repo_name, region)
37
+
38
+ # Get auth token
39
+ auth_data = ecr.get_authorization_token()["authorizationData"][0]
40
+ token = base64.b64decode(auth_data["authorizationToken"]).decode("utf-8")
41
+ username, password = token.split(":")
42
+
43
+ # Login to ECR
44
+ if not container_runtime.login(auth_data["proxyEndpoint"], username, password):
45
+ raise RuntimeError("Failed to login to ECR")
46
+
47
+ # Tag and push
48
+ ecr_tag = f"{ecr_uri}:latest"
49
+ if not container_runtime.tag(local_tag, ecr_tag):
50
+ raise RuntimeError("Failed to tag image")
51
+
52
+ if not container_runtime.push(ecr_tag):
53
+ raise RuntimeError("Failed to push image to ECR")
54
+
55
+ return ecr_tag
@@ -0,0 +1,383 @@
1
+ """BedrockAgentCore service client for agent management."""
2
+
3
+ import json
4
+ import logging
5
+ import time
6
+ import urllib.parse
7
+ import uuid
8
+ from typing import Any, Dict, Optional
9
+
10
+ import boto3
11
+ import requests
12
+
13
+ from ..utils.endpoints import get_control_plane_endpoint, get_data_plane_endpoint
14
+
15
+
16
+ def generate_session_id() -> str:
17
+ """Generate session ID."""
18
+ return str(uuid.uuid4())
19
+
20
+
21
+ def _handle_http_response(response) -> dict:
22
+ response.raise_for_status()
23
+ if "text/event-stream" in response.headers.get("content-type", ""):
24
+ return _handle_streaming_response(response)
25
+ else:
26
+ # Check if response has content
27
+ if not response.content:
28
+ raise ValueError("Empty response from agent endpoint")
29
+
30
+ return {"response": response.text}
31
+
32
+
33
+ def _handle_aws_response(response) -> dict:
34
+ if "text/event-stream" in response.get("contentType", ""):
35
+ return _handle_streaming_response(response["response"])
36
+ else:
37
+ try:
38
+ events = []
39
+ for event in response.get("response", []):
40
+ events.append(event)
41
+ except Exception as e:
42
+ events = [f"Error reading EventStream: {e}"]
43
+
44
+ response["response"] = events
45
+ return response
46
+
47
+
48
+ def _handle_streaming_response(response) -> Dict[str, Any]:
49
+ logger = logging.getLogger("bedrock_agentcore.stream")
50
+ logger.setLevel(logging.INFO)
51
+
52
+ content = []
53
+ for line in response.iter_lines(chunk_size=1):
54
+ if line:
55
+ line = line.decode("utf-8")
56
+ if line.startswith("data: "):
57
+ line = line[6:]
58
+ logger.info(line)
59
+ content.append(line)
60
+
61
+ return {"response": "\n".join(content)}
62
+
63
+
64
+ class BedrockAgentCoreClient:
65
+ """Bedrock AgentCore client for agent management."""
66
+
67
+ def __init__(self, region: str):
68
+ """Initialize Bedrock AgentCore client.
69
+
70
+ Args:
71
+ region: AWS region for the client
72
+ """
73
+ self.region = region
74
+ self.logger = logging.getLogger(f"bedrock_agentcore.runtime.{region}")
75
+
76
+ # Get endpoint URLs and log them
77
+ control_plane_url = get_control_plane_endpoint(region)
78
+ data_plane_url = get_data_plane_endpoint(region)
79
+
80
+ self.logger.debug("Initializing Bedrock AgentCore client for region: %s", region)
81
+ self.logger.debug("Control plane: %s", control_plane_url)
82
+ self.logger.debug("Data plane: %s", data_plane_url)
83
+
84
+ self.client = boto3.client("bedrock-agentcore-control", region_name=region, endpoint_url=control_plane_url)
85
+ self.dataplane_client = boto3.client("bedrock-agentcore", region_name=region, endpoint_url=data_plane_url)
86
+
87
+ def create_agent(
88
+ self,
89
+ agent_name: str,
90
+ image_uri: str,
91
+ execution_role_arn: str,
92
+ network_config: Optional[Dict] = None,
93
+ authorizer_config: Optional[Dict] = None,
94
+ protocol_config: Optional[Dict] = None,
95
+ env_vars: Optional[Dict] = None,
96
+ ) -> Dict[str, str]:
97
+ """Create new agent."""
98
+ self.logger.info("Creating agent '%s' with image URI: %s", agent_name, image_uri)
99
+ try:
100
+ # Build parameters dict, only including optional configs when present
101
+ params = {
102
+ "agentRuntimeName": agent_name,
103
+ "agentRuntimeArtifact": {"containerConfiguration": {"containerUri": image_uri}},
104
+ "roleArn": execution_role_arn,
105
+ }
106
+
107
+ if network_config is not None:
108
+ params["networkConfiguration"] = network_config
109
+
110
+ if authorizer_config is not None:
111
+ params["authorizerConfiguration"] = authorizer_config
112
+
113
+ if protocol_config is not None:
114
+ params["protocolConfiguration"] = protocol_config
115
+
116
+ if env_vars is not None:
117
+ params["environmentVariables"] = env_vars
118
+
119
+ resp = self.client.create_agent_runtime(**params)
120
+ agent_id = resp["agentRuntimeId"]
121
+ agent_arn = resp["agentRuntimeArn"]
122
+ self.logger.info("Successfully created agent '%s' with ID: %s, ARN: %s", agent_name, agent_id, agent_arn)
123
+ return {"id": agent_id, "arn": agent_arn}
124
+ except Exception as e:
125
+ self.logger.error("Failed to create agent '%s': %s", agent_name, str(e))
126
+ raise
127
+
128
+ def update_agent(
129
+ self,
130
+ agent_id: str,
131
+ image_uri: str,
132
+ execution_role_arn: str,
133
+ network_config: Optional[Dict] = None,
134
+ authorizer_config: Optional[Dict] = None,
135
+ protocol_config: Optional[Dict] = None,
136
+ env_vars: Optional[Dict] = None,
137
+ ) -> Dict[str, str]:
138
+ """Update existing agent."""
139
+ self.logger.info("Updating agent ID '%s' with image URI: %s", agent_id, image_uri)
140
+ try:
141
+ # Build parameters dict, only including optional configs when present
142
+ params = {
143
+ "agentRuntimeId": agent_id,
144
+ "agentRuntimeArtifact": {"containerConfiguration": {"containerUri": image_uri}},
145
+ "roleArn": execution_role_arn,
146
+ }
147
+
148
+ if network_config is not None:
149
+ params["networkConfiguration"] = network_config
150
+
151
+ if authorizer_config is not None:
152
+ params["authorizerConfiguration"] = authorizer_config
153
+
154
+ if protocol_config is not None:
155
+ params["protocolConfiguration"] = protocol_config
156
+
157
+ if env_vars is not None:
158
+ params["environmentVariables"] = env_vars
159
+
160
+ resp = self.client.update_agent_runtime(**params)
161
+ agent_arn = resp["agentRuntimeArn"]
162
+ self.logger.info("Successfully updated agent ID '%s', ARN: %s", agent_id, agent_arn)
163
+ return {"id": agent_id, "arn": agent_arn}
164
+ except Exception as e:
165
+ self.logger.error("Failed to update agent ID '%s': %s", agent_id, str(e))
166
+ raise
167
+
168
+ def create_or_update_agent(
169
+ self,
170
+ agent_id: Optional[str],
171
+ agent_name: str,
172
+ image_uri: str,
173
+ execution_role_arn: str,
174
+ network_config: Optional[Dict] = None,
175
+ authorizer_config: Optional[Dict] = None,
176
+ protocol_config: Optional[Dict] = None,
177
+ env_vars: Optional[Dict] = None,
178
+ ) -> Dict[str, str]:
179
+ """Create or update agent."""
180
+ if agent_id:
181
+ return self.update_agent(
182
+ agent_id, image_uri, execution_role_arn, network_config, authorizer_config, protocol_config, env_vars
183
+ )
184
+ return self.create_agent(
185
+ agent_name, image_uri, execution_role_arn, network_config, authorizer_config, protocol_config, env_vars
186
+ )
187
+
188
+ def wait_for_agent_endpoint_ready(self, agent_id: str, endpoint_name: str = "DEFAULT", max_wait: int = 120) -> str:
189
+ """Wait for agent endpoint to be ready.
190
+
191
+ Args:
192
+ agent_id: Agent ID to wait for
193
+ endpoint_name: Endpoint name, defaults to "DEFAULT"
194
+ max_wait: Maximum wait time in seconds
195
+
196
+ Returns:
197
+ Agent endpoint ARN when ready
198
+ """
199
+ start_time = time.time()
200
+
201
+ while time.time() - start_time < max_wait:
202
+ try:
203
+ resp = self.client.get_agent_runtime_endpoint(
204
+ agentRuntimeId=agent_id,
205
+ endpointName=endpoint_name,
206
+ )
207
+ status = resp.get("status", "UNKNOWN")
208
+
209
+ if status == "READY":
210
+ return resp["agentRuntimeEndpointArn"]
211
+ elif status in ["CREATE_FAILED", "UPDATE_FAILED"]:
212
+ raise Exception(
213
+ f"Agent endpoint {status.lower().replace('_', ' ')}: {resp.get('failureReason', 'Unknown')}"
214
+ )
215
+ elif status not in ["CREATING", "UPDATING"]:
216
+ pass
217
+ except self.client.exceptions.ResourceNotFoundException:
218
+ pass
219
+ except Exception as e:
220
+ if "ResourceNotFoundException" not in str(e):
221
+ raise
222
+ time.sleep(2)
223
+ return (
224
+ f"Endpoint is taking longer than {max_wait} seconds to be ready, "
225
+ f"please check status and try to invoke after some time"
226
+ )
227
+
228
+ def get_agent_runtime(self, agent_id: str) -> Dict:
229
+ """Get agent runtime details.
230
+
231
+ Args:
232
+ agent_id: Agent ID to get details for
233
+
234
+ Returns:
235
+ Agent runtime details
236
+ """
237
+ return self.client.get_agent_runtime(agentRuntimeId=agent_id)
238
+
239
+ def get_agent_runtime_endpoint(self, agent_id: str, endpoint_name: str = "DEFAULT") -> Dict:
240
+ """Get agent runtime endpoint details.
241
+
242
+ Args:
243
+ agent_id: Agent ID to get endpoint for
244
+ endpoint_name: Endpoint name, defaults to "DEFAULT"
245
+
246
+ Returns:
247
+ Agent endpoint details
248
+ """
249
+ return self.client.get_agent_runtime_endpoint(
250
+ agentRuntimeId=agent_id,
251
+ endpointName=endpoint_name,
252
+ )
253
+
254
+ def invoke_endpoint(
255
+ self,
256
+ agent_arn: str,
257
+ payload: str,
258
+ session_id: str,
259
+ endpoint_name: str = "DEFAULT",
260
+ user_id: Optional[str] = None,
261
+ ) -> Dict:
262
+ """Invoke agent endpoint."""
263
+ req = {
264
+ "agentRuntimeArn": agent_arn,
265
+ "qualifier": endpoint_name,
266
+ "runtimeSessionId": session_id,
267
+ "payload": payload,
268
+ }
269
+
270
+ if user_id:
271
+ req["runtimeUserId"] = user_id
272
+
273
+ response = self.dataplane_client.invoke_agent_runtime(**req)
274
+ return _handle_aws_response(response)
275
+
276
+
277
+ class HttpBedrockAgentCoreClient:
278
+ """Bedrock AgentCore client for agent management using HTTP requests with bearer token."""
279
+
280
+ def __init__(self, region: str):
281
+ """Initialize HttpBedrockAgentCoreClient.
282
+
283
+ Args:
284
+ region: AWS region for the client
285
+ """
286
+ self.region = region
287
+ self.dp_endpoint = get_data_plane_endpoint(region)
288
+ self.logger = logging.getLogger(f"bedrock_agentcore.http_runtime.{region}")
289
+
290
+ self.logger.debug("Initializing HTTP Bedrock AgentCore client for region: %s", region)
291
+ self.logger.debug("Data plane: %s", self.dp_endpoint)
292
+
293
+ def invoke_endpoint(
294
+ self,
295
+ agent_arn: str,
296
+ payload,
297
+ session_id: str,
298
+ bearer_token: Optional[str],
299
+ endpoint_name: str = "DEFAULT",
300
+ ) -> Dict:
301
+ """Invoke agent endpoint using HTTP request with bearer token.
302
+
303
+ Args:
304
+ agent_arn: Agent ARN to invoke
305
+ payload: Payload to send (dict or string)
306
+ session_id: Session ID for the request
307
+ bearer_token: Bearer token for authentication
308
+ endpoint_name: Endpoint name, defaults to "DEFAULT"
309
+
310
+ Returns:
311
+ Response from the agent endpoint
312
+ """
313
+ # Escape agent ARN for URL
314
+ escaped_arn = urllib.parse.quote(agent_arn, safe="")
315
+
316
+ # Build URL
317
+ url = f"{self.dp_endpoint}/runtimes/{escaped_arn}/invocations"
318
+ # Headers
319
+ headers = {
320
+ "Authorization": f"Bearer {bearer_token}",
321
+ "Content-Type": "application/json",
322
+ "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id": session_id,
323
+ }
324
+
325
+ # Parse the payload string back to JSON object to send properly
326
+ # This ensures consistent payload structure between boto3 and HTTP clients
327
+ try:
328
+ body = json.loads(payload) if isinstance(payload, str) else payload
329
+ except json.JSONDecodeError:
330
+ # Fallback for non-JSON strings - wrap in payload object
331
+ self.logger.warning("Failed to parse payload as JSON, wrapping in payload object")
332
+ body = {"payload": payload}
333
+
334
+ try:
335
+ # Make request with timeout
336
+ response = requests.post(
337
+ url,
338
+ params={"qualifier": endpoint_name},
339
+ headers=headers,
340
+ json=body,
341
+ timeout=100,
342
+ stream=True,
343
+ )
344
+ return _handle_http_response(response)
345
+ except requests.exceptions.RequestException as e:
346
+ self.logger.error("Failed to invoke agent endpoint: %s", str(e))
347
+ raise
348
+
349
+
350
+ class LocalBedrockAgentCoreClient:
351
+ """Local Bedrock AgentCore client for invoking endpoints."""
352
+
353
+ def __init__(self, endpoint: str):
354
+ """Initialize the local client with the given endpoint."""
355
+ self.endpoint = endpoint
356
+ self.logger = logging.getLogger("bedrock_agentcore.http_local")
357
+
358
+ def invoke_endpoint(self, session_id: str, payload: str, workload_access_token: str):
359
+ """Invoke the endpoint with the given parameters."""
360
+ from bedrock_agentcore.runtime.models import ACCESS_TOKEN_HEADER, SESSION_HEADER
361
+
362
+ url = f"{self.endpoint}/invocations"
363
+
364
+ headers = {
365
+ "Content-Type": "application/json",
366
+ ACCESS_TOKEN_HEADER: workload_access_token,
367
+ SESSION_HEADER: session_id,
368
+ }
369
+
370
+ try:
371
+ body = json.loads(payload) if isinstance(payload, str) else payload
372
+ except json.JSONDecodeError:
373
+ # Fallback for non-JSON strings - wrap in payload object
374
+ self.logger.warning("Failed to parse payload as JSON, wrapping in payload object")
375
+ body = {"payload": payload}
376
+
377
+ try:
378
+ # Make request with timeout
379
+ response = requests.post(url, headers=headers, json=body, timeout=100, stream=True)
380
+ return _handle_http_response(response)
381
+ except requests.exceptions.RequestException as e:
382
+ self.logger.error("Failed to invoke agent endpoint: %s", str(e))
383
+ raise
@@ -0,0 +1,32 @@
1
+ """Endpoint utilities for BedrockAgentCore services."""
2
+
3
+ import os
4
+
5
+ # Environment-configurable constants with fallback defaults
6
+ DP_ENDPOINT_OVERRIDE = os.getenv("BEDROCK_AGENTCORE_DP_ENDPOINT")
7
+ CP_ENDPOINT_OVERRIDE = os.getenv("BEDROCK_AGENTCORE_CP_ENDPOINT")
8
+ DEFAULT_REGION = os.getenv("AWS_REGION", "us-west-2")
9
+
10
+
11
+ def get_data_plane_endpoint(region: str = DEFAULT_REGION) -> str:
12
+ """Get the data plane endpoint URL for BedrockAgentCore services.
13
+
14
+ Args:
15
+ region: AWS region to use. Defaults to DEFAULT_REGION.
16
+
17
+ Returns:
18
+ The data plane endpoint URL, either from environment override or constructed URL.
19
+ """
20
+ return DP_ENDPOINT_OVERRIDE or f"https://bedrock-agentcore.{region}.amazonaws.com"
21
+
22
+
23
+ def get_control_plane_endpoint(region: str = DEFAULT_REGION) -> str:
24
+ """Get the control plane endpoint URL for BedrockAgentCore services.
25
+
26
+ Args:
27
+ region: AWS region to use. Defaults to DEFAULT_REGION.
28
+
29
+ Returns:
30
+ The control plane endpoint URL, either from environment override or constructed URL.
31
+ """
32
+ return CP_ENDPOINT_OVERRIDE or f"https://bedrock-agentcore-control.{region}.amazonaws.com"