bedrock-agentcore-starter-toolkit 0.1.25__py3-none-any.whl → 0.1.27__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/cli/cli.py +9 -1
- bedrock_agentcore_starter_toolkit/cli/runtime/commands.py +263 -7
- bedrock_agentcore_starter_toolkit/cli/runtime/configuration_manager.py +31 -7
- bedrock_agentcore_starter_toolkit/notebook/runtime/bedrock_agentcore.py +240 -2
- bedrock_agentcore_starter_toolkit/operations/identity/__init__.py +5 -0
- bedrock_agentcore_starter_toolkit/operations/identity/oauth2_callback_server.py +86 -0
- bedrock_agentcore_starter_toolkit/operations/memory/manager.py +20 -33
- bedrock_agentcore_starter_toolkit/operations/memory/models/strategies/base.py +2 -0
- bedrock_agentcore_starter_toolkit/operations/memory/models/strategies/self_managed.py +107 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/__init__.py +4 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/configure.py +120 -5
- bedrock_agentcore_starter_toolkit/operations/runtime/invoke.py +30 -54
- bedrock_agentcore_starter_toolkit/operations/runtime/launch.py +213 -16
- bedrock_agentcore_starter_toolkit/operations/runtime/models.py +19 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/status.py +30 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/stop_session.py +123 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/vpc_validation.py +196 -0
- bedrock_agentcore_starter_toolkit/services/runtime.py +46 -2
- bedrock_agentcore_starter_toolkit/utils/runtime/schema.py +44 -1
- {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/METADATA +13 -12
- {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/RECORD +25 -20
- {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/WHEEL +0 -0
- {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/entry_points.txt +0 -0
- {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/licenses/LICENSE.txt +0 -0
- {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/licenses/NOTICE.txt +0 -0
|
@@ -4,11 +4,13 @@ import logging
|
|
|
4
4
|
import os
|
|
5
5
|
import re
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any, Dict, Literal, Optional, Tuple
|
|
7
|
+
from typing import Any, Dict, List, Literal, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
import boto3
|
|
8
10
|
|
|
9
11
|
from ...cli.runtime.configuration_manager import ConfigurationManager
|
|
10
12
|
from ...services.ecr import get_account_id, get_region
|
|
11
|
-
from ...utils.runtime.config import merge_agent_config, save_config
|
|
13
|
+
from ...utils.runtime.config import load_config_if_exists, merge_agent_config, save_config
|
|
12
14
|
from ...utils.runtime.container import ContainerRuntime
|
|
13
15
|
from ...utils.runtime.entrypoint import detect_dependencies
|
|
14
16
|
from ...utils.runtime.schema import (
|
|
@@ -16,8 +18,10 @@ from ...utils.runtime.schema import (
|
|
|
16
18
|
BedrockAgentCoreAgentSchema,
|
|
17
19
|
BedrockAgentCoreDeploymentInfo,
|
|
18
20
|
CodeBuildConfig,
|
|
21
|
+
LifecycleConfiguration,
|
|
19
22
|
MemoryConfig,
|
|
20
23
|
NetworkConfiguration,
|
|
24
|
+
NetworkModeConfig,
|
|
21
25
|
ObservabilityConfig,
|
|
22
26
|
ProtocolConfiguration,
|
|
23
27
|
)
|
|
@@ -133,7 +137,7 @@ def configure_bedrock_agentcore(
|
|
|
133
137
|
auto_create_ecr: bool = True,
|
|
134
138
|
auto_create_execution_role: bool = True,
|
|
135
139
|
enable_observability: bool = True,
|
|
136
|
-
memory_mode: Literal["NO_MEMORY", "STM_ONLY", "STM_AND_LTM"] = "
|
|
140
|
+
memory_mode: Literal["NO_MEMORY", "STM_ONLY", "STM_AND_LTM"] = "NO_MEMORY",
|
|
137
141
|
requirements_file: Optional[str] = None,
|
|
138
142
|
authorizer_configuration: Optional[Dict[str, Any]] = None,
|
|
139
143
|
request_header_configuration: Optional[Dict[str, Any]] = None,
|
|
@@ -142,6 +146,11 @@ def configure_bedrock_agentcore(
|
|
|
142
146
|
protocol: Optional[str] = None,
|
|
143
147
|
non_interactive: bool = False,
|
|
144
148
|
source_path: Optional[str] = None,
|
|
149
|
+
vpc_enabled: bool = False,
|
|
150
|
+
vpc_subnets: Optional[List[str]] = None,
|
|
151
|
+
vpc_security_groups: Optional[List[str]] = None,
|
|
152
|
+
idle_timeout: Optional[int] = None,
|
|
153
|
+
max_lifetime: Optional[int] = None,
|
|
145
154
|
) -> ConfigureResult:
|
|
146
155
|
"""Configure Bedrock AgentCore application with deployment settings.
|
|
147
156
|
|
|
@@ -164,6 +173,13 @@ def configure_bedrock_agentcore(
|
|
|
164
173
|
protocol: agent server protocol, must be either HTTP or MCP or A2A
|
|
165
174
|
non_interactive: Skip interactive prompts and use defaults
|
|
166
175
|
source_path: Optional path to agent source code directory
|
|
176
|
+
vpc_enabled: Whether to enable VPC networking mode
|
|
177
|
+
vpc_subnets: List of subnet IDs for VPC mode
|
|
178
|
+
vpc_security_groups: List of security group IDs for VPC mode
|
|
179
|
+
idle_timeout: Idle runtime session timeout in seconds (60-28800).
|
|
180
|
+
If not specified, AWS API default (900s / 15 minutes) is used.
|
|
181
|
+
max_lifetime: Maximum instance lifetime in seconds (60-28800).
|
|
182
|
+
If not specified, AWS API default (28800s / 8 hours) is used.
|
|
167
183
|
|
|
168
184
|
Returns:
|
|
169
185
|
ConfigureResult model with configuration details
|
|
@@ -244,7 +260,7 @@ def configure_bedrock_agentcore(
|
|
|
244
260
|
else: # STM_ONLY
|
|
245
261
|
log.info("Memory configuration: Short-term memory only")
|
|
246
262
|
else:
|
|
247
|
-
# Interactive mode
|
|
263
|
+
# Interactive mode - let user choose
|
|
248
264
|
action, value = config_manager.prompt_memory_selection()
|
|
249
265
|
|
|
250
266
|
if action == "USE_EXISTING":
|
|
@@ -274,6 +290,21 @@ def configure_bedrock_agentcore(
|
|
|
274
290
|
memory_id = None
|
|
275
291
|
memory_name = None
|
|
276
292
|
|
|
293
|
+
# Handle lifecycle configuration
|
|
294
|
+
lifecycle_config = LifecycleConfiguration()
|
|
295
|
+
if idle_timeout is not None or max_lifetime is not None:
|
|
296
|
+
lifecycle_config = LifecycleConfiguration(
|
|
297
|
+
idle_runtime_session_timeout=idle_timeout,
|
|
298
|
+
max_lifetime=max_lifetime,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
if verbose:
|
|
302
|
+
log.debug("Lifecycle configuration:")
|
|
303
|
+
if idle_timeout:
|
|
304
|
+
log.debug(" Idle timeout: %ds (%d minutes)", idle_timeout, idle_timeout / 60)
|
|
305
|
+
if max_lifetime:
|
|
306
|
+
log.debug(" Max lifetime: %ds (%d hours)", max_lifetime, max_lifetime / 3600)
|
|
307
|
+
|
|
277
308
|
if config_path.exists():
|
|
278
309
|
try:
|
|
279
310
|
from ...utils.runtime.config import load_config
|
|
@@ -305,6 +336,42 @@ def configure_bedrock_agentcore(
|
|
|
305
336
|
if verbose and execution_role_arn:
|
|
306
337
|
log.debug("Using same role for CodeBuild: %s", codebuild_execution_role_arn)
|
|
307
338
|
|
|
339
|
+
if vpc_enabled:
|
|
340
|
+
if not vpc_subnets or not vpc_security_groups:
|
|
341
|
+
raise ValueError("VPC mode requires both subnets and security groups")
|
|
342
|
+
|
|
343
|
+
for subnet_id in vpc_subnets:
|
|
344
|
+
if not subnet_id.startswith("subnet-"):
|
|
345
|
+
raise ValueError(
|
|
346
|
+
f"Invalid subnet ID format: {subnet_id}\nSubnet IDs must start with 'subnet-' (e.g., subnet-abc123)"
|
|
347
|
+
)
|
|
348
|
+
if len(subnet_id) < 15: # "subnet-" (7) + 8 chars = 15
|
|
349
|
+
raise ValueError(
|
|
350
|
+
f"Invalid subnet ID format: {subnet_id}\nSubnet ID is too short. Expected format: subnet-xxxxxxxx"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
# Validate security group IDs format
|
|
354
|
+
for sg_id in vpc_security_groups:
|
|
355
|
+
if not sg_id.startswith("sg-"):
|
|
356
|
+
raise ValueError(
|
|
357
|
+
f"Invalid security group ID format: {sg_id}\n"
|
|
358
|
+
f"Security group IDs must start with 'sg-' (e.g., sg-abc123)"
|
|
359
|
+
)
|
|
360
|
+
if len(sg_id) < 11: # "sg-" (3) + 8 chars = 11
|
|
361
|
+
raise ValueError(
|
|
362
|
+
f"Invalid security group ID format: {sg_id}\n"
|
|
363
|
+
f"Security group ID is too short. Expected format: sg-xxxxxxxx"
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
network_config = NetworkConfiguration(
|
|
367
|
+
network_mode="VPC",
|
|
368
|
+
network_mode_config=NetworkModeConfig(subnets=vpc_subnets, security_groups=vpc_security_groups),
|
|
369
|
+
)
|
|
370
|
+
log.info("Network mode: VPC with %d subnets and %d security groups", len(vpc_subnets), len(vpc_security_groups))
|
|
371
|
+
else:
|
|
372
|
+
network_config = NetworkConfiguration(network_mode="PUBLIC")
|
|
373
|
+
log.info("Network mode: PUBLIC")
|
|
374
|
+
|
|
308
375
|
# Generate Dockerfile and .dockerignore
|
|
309
376
|
bedrock_agentcore_name = None
|
|
310
377
|
# Try to find the variable name for the Bedrock AgentCore instance in the file
|
|
@@ -332,6 +399,11 @@ def configure_bedrock_agentcore(
|
|
|
332
399
|
else:
|
|
333
400
|
dockerfile_output_dir = build_dir
|
|
334
401
|
|
|
402
|
+
if memory_config.mode == "NO_MEMORY":
|
|
403
|
+
memory_id = None
|
|
404
|
+
memory_name = None
|
|
405
|
+
log.debug("Cleared memory_id/name for Dockerfile generation (memory disabled)")
|
|
406
|
+
|
|
335
407
|
# Generate Dockerfile in the correct location (no moving needed)
|
|
336
408
|
dockerfile_path = runtime.generate_dockerfile(
|
|
337
409
|
entrypoint_path,
|
|
@@ -374,6 +446,32 @@ def configure_bedrock_agentcore(
|
|
|
374
446
|
log.debug("Agent name from BedrockAgentCoreApp: %s", agent_name)
|
|
375
447
|
log.debug("Config path: %s", config_path)
|
|
376
448
|
|
|
449
|
+
existing_project_config = load_config_if_exists(config_path)
|
|
450
|
+
|
|
451
|
+
if existing_project_config and agent_name in existing_project_config.agents:
|
|
452
|
+
existing_agent = existing_project_config.agents[agent_name]
|
|
453
|
+
existing_network = existing_agent.aws.network_configuration
|
|
454
|
+
|
|
455
|
+
# Import validation helper
|
|
456
|
+
from .vpc_validation import check_network_immutability
|
|
457
|
+
|
|
458
|
+
# Check if network config is being changed
|
|
459
|
+
error = check_network_immutability(
|
|
460
|
+
existing_network_mode=existing_network.network_mode,
|
|
461
|
+
existing_subnets=existing_network.network_mode_config.subnets
|
|
462
|
+
if existing_network.network_mode_config
|
|
463
|
+
else None,
|
|
464
|
+
existing_security_groups=existing_network.network_mode_config.security_groups
|
|
465
|
+
if existing_network.network_mode_config
|
|
466
|
+
else None,
|
|
467
|
+
new_network_mode="VPC" if vpc_enabled else "PUBLIC",
|
|
468
|
+
new_subnets=vpc_subnets,
|
|
469
|
+
new_security_groups=vpc_security_groups,
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
if error:
|
|
473
|
+
raise ValueError(error)
|
|
474
|
+
|
|
377
475
|
# Convert to POSIX for cross-platform compatibility
|
|
378
476
|
entrypoint_path_str = entrypoint_path.as_posix()
|
|
379
477
|
|
|
@@ -418,9 +516,10 @@ def configure_bedrock_agentcore(
|
|
|
418
516
|
region=region,
|
|
419
517
|
ecr_repository=ecr_repository,
|
|
420
518
|
ecr_auto_create=ecr_auto_create_value,
|
|
421
|
-
network_configuration=
|
|
519
|
+
network_configuration=network_config,
|
|
422
520
|
protocol_configuration=ProtocolConfiguration(server_protocol=protocol or "HTTP"),
|
|
423
521
|
observability=ObservabilityConfig(enabled=enable_observability),
|
|
522
|
+
lifecycle_configuration=lifecycle_config,
|
|
424
523
|
),
|
|
425
524
|
bedrock_agentcore=BedrockAgentCoreDeploymentInfo(),
|
|
426
525
|
codebuild=CodeBuildConfig(
|
|
@@ -438,6 +537,18 @@ def configure_bedrock_agentcore(
|
|
|
438
537
|
if verbose:
|
|
439
538
|
log.debug("Configuration saved with agent: %s", agent_name)
|
|
440
539
|
|
|
540
|
+
# Get VPC ID for display if VPC mode
|
|
541
|
+
vpc_id = None
|
|
542
|
+
if vpc_enabled and vpc_subnets:
|
|
543
|
+
try:
|
|
544
|
+
session = boto3.Session(region_name=region)
|
|
545
|
+
ec2_client = session.client("ec2", region_name=region)
|
|
546
|
+
subnet_response = ec2_client.describe_subnets(SubnetIds=[vpc_subnets[0]])
|
|
547
|
+
if subnet_response["Subnets"]:
|
|
548
|
+
vpc_id = subnet_response["Subnets"][0]["VpcId"]
|
|
549
|
+
except Exception:
|
|
550
|
+
pass # nosec B110
|
|
551
|
+
|
|
441
552
|
return ConfigureResult(
|
|
442
553
|
config_path=config_path,
|
|
443
554
|
dockerfile_path=dockerfile_path,
|
|
@@ -448,6 +559,10 @@ def configure_bedrock_agentcore(
|
|
|
448
559
|
execution_role=execution_role_arn,
|
|
449
560
|
ecr_repository=ecr_repository,
|
|
450
561
|
auto_create_ecr=auto_create_ecr and not ecr_repository,
|
|
562
|
+
network_mode="VPC" if vpc_enabled else "PUBLIC",
|
|
563
|
+
network_subnets=vpc_subnets if vpc_enabled else None,
|
|
564
|
+
network_security_groups=vpc_security_groups if vpc_enabled else None,
|
|
565
|
+
network_vpc_id=vpc_id,
|
|
451
566
|
)
|
|
452
567
|
|
|
453
568
|
|
|
@@ -7,6 +7,7 @@ from typing import Any, Optional
|
|
|
7
7
|
|
|
8
8
|
from bedrock_agentcore.services.identity import IdentityClient
|
|
9
9
|
|
|
10
|
+
from ...operations.identity.oauth2_callback_server import WORKLOAD_USER_ID, BedrockAgentCoreIdentity3loCallback
|
|
10
11
|
from ...services.runtime import BedrockAgentCoreClient, generate_session_id
|
|
11
12
|
from ...utils.runtime.config import load_config, save_config
|
|
12
13
|
from ...utils.runtime.schema import BedrockAgentCoreConfigSchema
|
|
@@ -30,59 +31,6 @@ def invoke_bedrock_agentcore(
|
|
|
30
31
|
project_config = load_config(config_path)
|
|
31
32
|
agent_config = project_config.get_agent_config(agent_name)
|
|
32
33
|
|
|
33
|
-
# Check memory status on first invoke if memory is enabled (STM or LTM)
|
|
34
|
-
if (
|
|
35
|
-
agent_config.memory
|
|
36
|
-
and agent_config.memory.mode != "NO_MEMORY"
|
|
37
|
-
and agent_config.memory.memory_id
|
|
38
|
-
and not agent_config.memory.first_invoke_memory_check_done
|
|
39
|
-
):
|
|
40
|
-
try:
|
|
41
|
-
from ...operations.memory.constants import MemoryStatus
|
|
42
|
-
from ...operations.memory.manager import MemoryManager
|
|
43
|
-
|
|
44
|
-
memory_manager = MemoryManager(region_name=agent_config.aws.region)
|
|
45
|
-
memory_status = memory_manager.get_memory_status(agent_config.memory.memory_id)
|
|
46
|
-
|
|
47
|
-
if memory_status != MemoryStatus.ACTIVE.value:
|
|
48
|
-
# Determine memory type for better messaging
|
|
49
|
-
memory_type = "Memory"
|
|
50
|
-
if agent_config.memory.has_ltm:
|
|
51
|
-
memory_type = "Long-term memory"
|
|
52
|
-
time_estimate = "60-180 seconds"
|
|
53
|
-
else:
|
|
54
|
-
memory_type = "Short-term memory"
|
|
55
|
-
time_estimate = "30-90 seconds"
|
|
56
|
-
|
|
57
|
-
# Provide graceful error message
|
|
58
|
-
error_message = (
|
|
59
|
-
f"Memory is still provisioning (current status: {memory_status}). "
|
|
60
|
-
f"{memory_type} takes {time_estimate} to activate.\n\n"
|
|
61
|
-
f"Please wait and check status with:\n"
|
|
62
|
-
f" agentcore status{f' --agent {agent_name}' if agent_name else ''}"
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
# Log the message for visibility
|
|
66
|
-
log.warning("Memory not yet active for agent '%s': %s", agent_config.name, memory_status)
|
|
67
|
-
|
|
68
|
-
raise ValueError(error_message)
|
|
69
|
-
|
|
70
|
-
# Memory is active, mark check as done
|
|
71
|
-
agent_config.memory.first_invoke_memory_check_done = True
|
|
72
|
-
project_config.agents[agent_config.name] = agent_config
|
|
73
|
-
save_config(project_config, config_path)
|
|
74
|
-
log.info("Memory is active, proceeding with invoke")
|
|
75
|
-
|
|
76
|
-
except ImportError as e:
|
|
77
|
-
log.error("Failed to import MemoryManager: %s", e)
|
|
78
|
-
# Continue without check if import fails
|
|
79
|
-
except Exception as e:
|
|
80
|
-
# If it's our ValueError, re-raise it
|
|
81
|
-
if "Memory is still provisioning" in str(e):
|
|
82
|
-
raise
|
|
83
|
-
# For other errors, log but continue
|
|
84
|
-
log.warning("Could not check memory status: %s", e)
|
|
85
|
-
|
|
86
34
|
# Log which agent is being invoked
|
|
87
35
|
mode = "locally" if local_mode else "via cloud endpoint"
|
|
88
36
|
log.debug("Invoking BedrockAgentCore agent '%s' %s", agent_config.name, mode)
|
|
@@ -121,9 +69,19 @@ def invoke_bedrock_agentcore(
|
|
|
121
69
|
workload_name=workload_name, user_token=bearer_token, user_id=user_id
|
|
122
70
|
)["workloadAccessToken"]
|
|
123
71
|
|
|
72
|
+
agent_config.oauth_configuration[WORKLOAD_USER_ID] = user_id # type: ignore : populated by _get_workload_name(...)
|
|
73
|
+
save_config(project_config, config_path)
|
|
74
|
+
|
|
75
|
+
oauth2_callback_url = BedrockAgentCoreIdentity3loCallback.get_oauth2_callback_endpoint()
|
|
76
|
+
_update_workload_identity_with_oauth2_callback_url(
|
|
77
|
+
identity_client, workload_name=workload_name, oauth2_callback_url=oauth2_callback_url
|
|
78
|
+
)
|
|
79
|
+
|
|
124
80
|
# TODO: store and read port config of local running container
|
|
125
81
|
client = LocalBedrockAgentCoreClient("http://127.0.0.1:8080")
|
|
126
|
-
response = client.invoke_endpoint(
|
|
82
|
+
response = client.invoke_endpoint(
|
|
83
|
+
session_id, payload_str, workload_access_token, oauth2_callback_url, custom_headers
|
|
84
|
+
)
|
|
127
85
|
|
|
128
86
|
else:
|
|
129
87
|
if not agent_arn:
|
|
@@ -163,6 +121,24 @@ def invoke_bedrock_agentcore(
|
|
|
163
121
|
)
|
|
164
122
|
|
|
165
123
|
|
|
124
|
+
def _update_workload_identity_with_oauth2_callback_url(
|
|
125
|
+
identity_client: IdentityClient,
|
|
126
|
+
workload_name: str,
|
|
127
|
+
oauth2_callback_url: str,
|
|
128
|
+
) -> None:
|
|
129
|
+
workload_identity = identity_client.get_workload_identity(name=workload_name)
|
|
130
|
+
allowed_resource_oauth_2_return_urls = workload_identity.get("allowedResourceOauth2ReturnUrls") or []
|
|
131
|
+
if oauth2_callback_url in allowed_resource_oauth_2_return_urls:
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
log.info("Updating workload %s with callback url %s", workload_name, oauth2_callback_url)
|
|
135
|
+
|
|
136
|
+
identity_client.update_workload_identity(
|
|
137
|
+
name=workload_name,
|
|
138
|
+
allowed_resource_oauth_2_return_urls=[*allowed_resource_oauth_2_return_urls, oauth2_callback_url],
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
166
142
|
def _get_workload_name(
|
|
167
143
|
project_config: BedrockAgentCoreConfigSchema,
|
|
168
144
|
project_config_path: Path,
|