bedrock-agentcore-starter-toolkit 0.1.9__py3-none-any.whl → 0.1.11__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 +3 -1
- bedrock_agentcore_starter_toolkit/cli/runtime/commands.py +453 -176
- bedrock_agentcore_starter_toolkit/operations/gateway/create_role.py +6 -11
- bedrock_agentcore_starter_toolkit/operations/runtime/__init__.py +4 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/destroy.py +547 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/invoke.py +2 -2
- bedrock_agentcore_starter_toolkit/operations/runtime/launch.py +15 -0
- bedrock_agentcore_starter_toolkit/operations/runtime/models.py +10 -0
- bedrock_agentcore_starter_toolkit/services/import_agent/scripts/base_bedrock_translate.py +4 -3
- bedrock_agentcore_starter_toolkit/services/import_agent/utils.py +14 -0
- bedrock_agentcore_starter_toolkit/services/runtime.py +38 -4
- bedrock_agentcore_starter_toolkit/services/xray.py +161 -0
- bedrock_agentcore_starter_toolkit/utils/runtime/logs.py +18 -2
- bedrock_agentcore_starter_toolkit/utils/runtime/templates/Dockerfile.j2 +11 -25
- {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/METADATA +4 -3
- {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/RECORD +20 -18
- {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/WHEEL +0 -0
- {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/entry_points.txt +0 -0
- {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/licenses/LICENSE.txt +0 -0
- {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/licenses/NOTICE.txt +0 -0
|
@@ -14,12 +14,15 @@ from rich.syntax import Syntax
|
|
|
14
14
|
|
|
15
15
|
from ...operations.runtime import (
|
|
16
16
|
configure_bedrock_agentcore,
|
|
17
|
+
destroy_bedrock_agentcore,
|
|
17
18
|
get_status,
|
|
18
19
|
invoke_bedrock_agentcore,
|
|
19
20
|
launch_bedrock_agentcore,
|
|
20
21
|
validate_agent_name,
|
|
21
22
|
)
|
|
23
|
+
from ...utils.runtime.config import load_config
|
|
22
24
|
from ...utils.runtime.entrypoint import parse_entrypoint
|
|
25
|
+
from ...utils.runtime.logs import get_agent_log_paths, get_aws_tail_commands, get_genai_observability_url
|
|
23
26
|
from ..common import _handle_error, _print_success, console
|
|
24
27
|
from .configuration_manager import ConfigurationManager
|
|
25
28
|
|
|
@@ -27,6 +30,22 @@ from .configuration_manager import ConfigurationManager
|
|
|
27
30
|
logger = logging.getLogger(__name__)
|
|
28
31
|
|
|
29
32
|
|
|
33
|
+
def _show_configuration_not_found_panel():
|
|
34
|
+
"""Show standardized configuration not found panel."""
|
|
35
|
+
console.print(
|
|
36
|
+
Panel(
|
|
37
|
+
"⚠️ [yellow]Configuration Not Found[/yellow]\n\n"
|
|
38
|
+
"No agent configuration found in this directory.\n\n"
|
|
39
|
+
"[bold]Get Started:[/bold]\n"
|
|
40
|
+
" [cyan]agentcore configure --entrypoint your_agent.py[/cyan]\n"
|
|
41
|
+
" [cyan]agentcore launch[/cyan]\n"
|
|
42
|
+
' [cyan]agentcore invoke \'{"prompt": "Hello"}\'[/cyan]',
|
|
43
|
+
title="⚠️ Setup Required",
|
|
44
|
+
border_style="bright_blue",
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
30
49
|
def _validate_requirements_file(file_path: str) -> str:
|
|
31
50
|
"""Validate requirements file and return the path."""
|
|
32
51
|
from ...utils.runtime.entrypoint import validate_requirements_file
|
|
@@ -95,8 +114,6 @@ def list_agents():
|
|
|
95
114
|
"""List configured agents."""
|
|
96
115
|
config_path = Path.cwd() / ".bedrock_agentcore.yaml"
|
|
97
116
|
try:
|
|
98
|
-
from ...utils.runtime.config import load_config
|
|
99
|
-
|
|
100
117
|
project_config = load_config(config_path)
|
|
101
118
|
if not project_config.agents:
|
|
102
119
|
console.print("[yellow]No agents configured.[/yellow]")
|
|
@@ -237,17 +254,23 @@ def configure(
|
|
|
237
254
|
|
|
238
255
|
console.print(
|
|
239
256
|
Panel(
|
|
240
|
-
f"[green]Configuration
|
|
241
|
-
f"
|
|
242
|
-
f"
|
|
243
|
-
f"
|
|
244
|
-
f"
|
|
245
|
-
f"
|
|
246
|
-
f"
|
|
247
|
-
f"
|
|
248
|
-
f"
|
|
249
|
-
|
|
250
|
-
|
|
257
|
+
f"[green]Configuration Complete[/green]\n\n"
|
|
258
|
+
f"[bold]Agent Details:[/bold]\n"
|
|
259
|
+
f"Agent Name: [cyan]{agent_name}[/cyan]\n"
|
|
260
|
+
f"Runtime: [cyan]{result.runtime}[/cyan]\n"
|
|
261
|
+
f"Region: [cyan]{result.region}[/cyan]\n"
|
|
262
|
+
f"Account: [dim]{result.account_id}[/dim]\n\n"
|
|
263
|
+
f"[bold]Configuration:[/bold]\n"
|
|
264
|
+
f"Execution Role: [dim]{result.execution_role}[/dim]\n"
|
|
265
|
+
f"ECR Repository: [dim]"
|
|
266
|
+
f"{'Auto-create' if result.auto_create_ecr else result.ecr_repository or 'N/A'}"
|
|
267
|
+
f"[/dim]\n"
|
|
268
|
+
f"Authorization: [dim]{auth_info}[/dim]\n\n"
|
|
269
|
+
f"📄 Config saved to: [dim]{result.config_path}[/dim]\n\n"
|
|
270
|
+
f"[bold]Next Steps:[/bold]\n"
|
|
271
|
+
f" [cyan]agentcore launch[/cyan]",
|
|
272
|
+
title="Configuration Success",
|
|
273
|
+
border_style="bright_blue",
|
|
251
274
|
)
|
|
252
275
|
)
|
|
253
276
|
|
|
@@ -381,6 +404,8 @@ def launch(
|
|
|
381
404
|
auto_update_on_conflict=auto_update_on_conflict,
|
|
382
405
|
)
|
|
383
406
|
|
|
407
|
+
project_config = load_config(config_path)
|
|
408
|
+
agent_config = project_config.get_agent_config(agent)
|
|
384
409
|
# Handle result based on mode
|
|
385
410
|
if result.mode == "local":
|
|
386
411
|
_print_success(f"Docker image built: {result.tag}")
|
|
@@ -397,80 +422,77 @@ def launch(
|
|
|
397
422
|
console.print("\n[yellow]Stopped[/yellow]")
|
|
398
423
|
|
|
399
424
|
elif result.mode == "codebuild":
|
|
400
|
-
_print_success(f"CodeBuild completed: [cyan]{result.codebuild_id}[/cyan]")
|
|
401
|
-
_print_success(f"ARM64 image pushed to ECR: [cyan]{result.ecr_uri}:latest[/cyan]")
|
|
402
|
-
|
|
403
425
|
# Show deployment success panel
|
|
404
426
|
agent_name = result.tag.split(":")[0].replace("bedrock_agentcore-", "")
|
|
427
|
+
|
|
428
|
+
# Get region from configuration
|
|
429
|
+
region = agent_config.aws.region if agent_config else "us-east-1"
|
|
430
|
+
|
|
405
431
|
deploy_panel = (
|
|
406
|
-
f"[green]CodeBuild
|
|
407
|
-
f"Agent
|
|
408
|
-
f"
|
|
432
|
+
f"✅ [green]CodeBuild Deployment Successful![/green]\n\n"
|
|
433
|
+
f"[bold]Agent Details:[/bold]\n"
|
|
434
|
+
f"Agent Name: [cyan]{agent_name}[/cyan]\n"
|
|
409
435
|
f"Agent ARN: [cyan]{result.agent_arn}[/cyan]\n"
|
|
410
|
-
f"ECR URI: [cyan]{result.ecr_uri}:latest[/cyan]\n
|
|
411
|
-
f"
|
|
412
|
-
f"
|
|
413
|
-
f"[
|
|
414
|
-
f"
|
|
415
|
-
f'[cyan]agentcore invoke \'{{"prompt": "Hello"}}\'[/cyan]'
|
|
436
|
+
f"ECR URI: [cyan]{result.ecr_uri}:latest[/cyan]\n"
|
|
437
|
+
f"CodeBuild ID: [dim]{result.codebuild_id}[/dim]\n\n"
|
|
438
|
+
f"🚀 ARM64 container deployed to Bedrock AgentCore\n\n"
|
|
439
|
+
f"[bold]Next Steps:[/bold]\n"
|
|
440
|
+
f" [cyan]agentcore status[/cyan]\n"
|
|
441
|
+
f' [cyan]agentcore invoke \'{{"prompt": "Hello"}}\'[/cyan]'
|
|
416
442
|
)
|
|
417
443
|
|
|
418
444
|
# Add log information if we have agent_id
|
|
419
445
|
if result.agent_id:
|
|
420
|
-
from ...utils.runtime.logs import get_agent_log_paths, get_aws_tail_commands
|
|
421
|
-
|
|
422
446
|
runtime_logs, otel_logs = get_agent_log_paths(result.agent_id)
|
|
423
447
|
follow_cmd, since_cmd = get_aws_tail_commands(runtime_logs)
|
|
424
|
-
deploy_panel +=
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
448
|
+
deploy_panel += f"\n\n📋 [cyan]CloudWatch Logs:[/cyan]\n {runtime_logs}\n {otel_logs}\n\n"
|
|
449
|
+
# Only show GenAI Observability Dashboard if OTEL is enabled
|
|
450
|
+
if agent_config and agent_config.aws.observability.enabled:
|
|
451
|
+
deploy_panel += (
|
|
452
|
+
f"🔍 [cyan]GenAI Observability Dashboard:[/cyan]\n"
|
|
453
|
+
f" {get_genai_observability_url(region)}\n\n"
|
|
454
|
+
f"⏱️ [dim]Note: Observability data may take up to 10 minutes to appear "
|
|
455
|
+
f"after first launch[/dim]\n\n"
|
|
456
|
+
)
|
|
457
|
+
deploy_panel += f"💡 [dim]Tail logs with:[/dim]\n {follow_cmd}\n {since_cmd}"
|
|
432
458
|
|
|
433
459
|
console.print(
|
|
434
460
|
Panel(
|
|
435
461
|
deploy_panel,
|
|
436
|
-
title="
|
|
437
|
-
border_style="
|
|
462
|
+
title="Deployment Success",
|
|
463
|
+
border_style="bright_blue",
|
|
438
464
|
)
|
|
439
465
|
)
|
|
440
466
|
|
|
441
467
|
else: # cloud mode (either CodeBuild default or local-build)
|
|
442
|
-
_print_success(f"Image pushed to ECR: [cyan]{result.ecr_uri}:latest[/cyan]")
|
|
443
|
-
|
|
444
|
-
# Show deployment success panel
|
|
445
468
|
agent_name = result.tag.split(":")[0].replace("bedrock_agentcore-", "")
|
|
446
469
|
|
|
447
|
-
# Determine deployment type for panel title
|
|
448
470
|
if local_build:
|
|
449
|
-
title = "Local Build
|
|
450
|
-
deployment_type = "Local
|
|
471
|
+
title = "Local Build Success"
|
|
472
|
+
deployment_type = "✅ [green]Local Build Deployment Successful![/green]"
|
|
473
|
+
icon = "🔧"
|
|
451
474
|
else:
|
|
452
|
-
title = "
|
|
453
|
-
deployment_type = "
|
|
475
|
+
title = "Deployment Success"
|
|
476
|
+
deployment_type = "✅ [green]Deployment Successful![/green]"
|
|
477
|
+
icon = "🚀"
|
|
454
478
|
|
|
455
479
|
deploy_panel = (
|
|
456
|
-
f"
|
|
457
|
-
f"Agent
|
|
480
|
+
f"{deployment_type}\n\n"
|
|
481
|
+
f"[bold]Agent Details:[/bold]\n"
|
|
482
|
+
f"Agent Name: [cyan]{agent_name}[/cyan]\n"
|
|
458
483
|
f"Agent ARN: [cyan]{result.agent_arn}[/cyan]\n"
|
|
459
484
|
f"ECR URI: [cyan]{result.ecr_uri}[/cyan]\n\n"
|
|
460
|
-
f"
|
|
461
|
-
f"[
|
|
462
|
-
f"
|
|
463
|
-
f'[cyan]agentcore invoke \'{{"prompt": "Hello"}}\'[/cyan]'
|
|
485
|
+
f"{icon} Container deployed to Bedrock AgentCore\n\n"
|
|
486
|
+
f"[bold]Next Steps:[/bold]\n"
|
|
487
|
+
f" [cyan]agentcore status[/cyan]\n"
|
|
488
|
+
f' [cyan]agentcore invoke \'{{"prompt": "Hello"}}\'[/cyan]'
|
|
464
489
|
)
|
|
465
490
|
|
|
466
|
-
# Add log information if we have agent_id
|
|
467
491
|
if result.agent_id:
|
|
468
|
-
from ...utils.runtime.logs import get_agent_log_paths, get_aws_tail_commands
|
|
469
|
-
|
|
470
492
|
runtime_logs, otel_logs = get_agent_log_paths(result.agent_id)
|
|
471
493
|
follow_cmd, since_cmd = get_aws_tail_commands(runtime_logs)
|
|
472
494
|
deploy_panel += (
|
|
473
|
-
f"\n\n📋 [cyan]
|
|
495
|
+
f"\n\n📋 [cyan]CloudWatch Logs:[/cyan]\n"
|
|
474
496
|
f" {runtime_logs}\n"
|
|
475
497
|
f" {otel_logs}\n\n"
|
|
476
498
|
f"💡 [dim]Tail logs with:[/dim]\n"
|
|
@@ -482,7 +504,7 @@ def launch(
|
|
|
482
504
|
Panel(
|
|
483
505
|
deploy_panel,
|
|
484
506
|
title=title,
|
|
485
|
-
border_style="
|
|
507
|
+
border_style="bright_blue",
|
|
486
508
|
)
|
|
487
509
|
)
|
|
488
510
|
|
|
@@ -498,6 +520,56 @@ def launch(
|
|
|
498
520
|
raise
|
|
499
521
|
|
|
500
522
|
|
|
523
|
+
def _show_invoke_info_panel(agent_name: str, invoke_result=None, config=None):
|
|
524
|
+
"""Show consistent panel with invoke information (session, request_id, arn, logs)."""
|
|
525
|
+
info_lines = []
|
|
526
|
+
# Session ID
|
|
527
|
+
if invoke_result and invoke_result.session_id:
|
|
528
|
+
info_lines.append(f"Session: [cyan]{invoke_result.session_id}[/cyan]")
|
|
529
|
+
# Request ID
|
|
530
|
+
if invoke_result and isinstance(invoke_result.response, dict):
|
|
531
|
+
request_id = invoke_result.response.get("ResponseMetadata", {}).get("RequestId")
|
|
532
|
+
if request_id:
|
|
533
|
+
info_lines.append(f"Request ID: [cyan]{request_id}[/cyan]")
|
|
534
|
+
# Agent ARN
|
|
535
|
+
if invoke_result and invoke_result.agent_arn:
|
|
536
|
+
info_lines.append(f"ARN: [cyan]{invoke_result.agent_arn}[/cyan]")
|
|
537
|
+
# CloudWatch logs and GenAI Observability Dashboard (if we have config with agent_id)
|
|
538
|
+
if config and hasattr(config, "bedrock_agentcore") and config.bedrock_agentcore.agent_id:
|
|
539
|
+
try:
|
|
540
|
+
runtime_logs, _ = get_agent_log_paths(config.bedrock_agentcore.agent_id)
|
|
541
|
+
follow_cmd, since_cmd = get_aws_tail_commands(runtime_logs)
|
|
542
|
+
info_lines.append(f"Logs: {follow_cmd}")
|
|
543
|
+
info_lines.append(f" {since_cmd}")
|
|
544
|
+
|
|
545
|
+
# Only show GenAI Observability Dashboard if OTEL is enabled
|
|
546
|
+
if config.aws.observability.enabled:
|
|
547
|
+
info_lines.append(f"GenAI Dashboard: {get_genai_observability_url(config.aws.region)}")
|
|
548
|
+
except Exception:
|
|
549
|
+
pass # nosec B110
|
|
550
|
+
panel_content = "\n".join(info_lines) if info_lines else "Invoke information unavailable"
|
|
551
|
+
console.print(
|
|
552
|
+
Panel(
|
|
553
|
+
panel_content,
|
|
554
|
+
title=f"{agent_name}",
|
|
555
|
+
border_style="bright_blue",
|
|
556
|
+
padding=(0, 1),
|
|
557
|
+
)
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
def _show_success_response(content):
|
|
562
|
+
"""Show success response content below panel."""
|
|
563
|
+
if content:
|
|
564
|
+
console.print("\n[bold]Response:[/bold]")
|
|
565
|
+
console.print(content)
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def _show_error_response(error_msg: str):
|
|
569
|
+
"""Show error message in red below panel."""
|
|
570
|
+
console.print(f"\n[red]{error_msg}[/red]")
|
|
571
|
+
|
|
572
|
+
|
|
501
573
|
def invoke(
|
|
502
574
|
payload: str = typer.Argument(..., help="JSON payload to send"),
|
|
503
575
|
agent: Optional[str] = typer.Option(
|
|
@@ -514,8 +586,6 @@ def invoke(
|
|
|
514
586
|
config_path = Path.cwd() / ".bedrock_agentcore.yaml"
|
|
515
587
|
|
|
516
588
|
try:
|
|
517
|
-
from ...utils.runtime.config import load_config
|
|
518
|
-
|
|
519
589
|
# Load project configuration to check if auth is configured
|
|
520
590
|
project_config = load_config(config_path)
|
|
521
591
|
config = project_config.get_agent_config(agent)
|
|
@@ -524,7 +594,7 @@ def invoke(
|
|
|
524
594
|
try:
|
|
525
595
|
payload_data = json.loads(payload)
|
|
526
596
|
except json.JSONDecodeError:
|
|
527
|
-
payload_data = {"
|
|
597
|
+
payload_data = {"prompt": payload}
|
|
528
598
|
|
|
529
599
|
# Handle bearer token - only use if auth config is defined in .bedrock_agentcore.yaml
|
|
530
600
|
final_bearer_token = None
|
|
@@ -543,17 +613,6 @@ def invoke(
|
|
|
543
613
|
"[yellow]Warning: Bearer token provided but OAuth is not configured in .bedrock_agentcore.yaml[/yellow]"
|
|
544
614
|
)
|
|
545
615
|
|
|
546
|
-
# Display payload
|
|
547
|
-
console.print("[bold]Payload:[/bold]")
|
|
548
|
-
console.print(
|
|
549
|
-
Syntax(
|
|
550
|
-
json.dumps(payload_data, indent=2, ensure_ascii=False),
|
|
551
|
-
"json",
|
|
552
|
-
background_color="default",
|
|
553
|
-
word_wrap=True,
|
|
554
|
-
)
|
|
555
|
-
)
|
|
556
|
-
|
|
557
616
|
# Invoke
|
|
558
617
|
result = invoke_bedrock_agentcore(
|
|
559
618
|
config_path=config_path,
|
|
@@ -564,37 +623,89 @@ def invoke(
|
|
|
564
623
|
user_id=user_id,
|
|
565
624
|
local_mode=local_mode,
|
|
566
625
|
)
|
|
567
|
-
|
|
626
|
+
agent_display = config.name if config else (agent or "unknown")
|
|
627
|
+
_show_invoke_info_panel(agent_display, result, config)
|
|
568
628
|
if result.response != {}:
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
629
|
+
content = result.response
|
|
630
|
+
if isinstance(content, dict) and "response" in content:
|
|
631
|
+
content = content["response"]
|
|
632
|
+
if isinstance(content, list):
|
|
633
|
+
if len(content) == 1:
|
|
634
|
+
content = content[0]
|
|
635
|
+
else:
|
|
636
|
+
# Handle mix of strings and bytes
|
|
637
|
+
string_items = []
|
|
638
|
+
for item in content:
|
|
639
|
+
if isinstance(item, bytes):
|
|
640
|
+
string_items.append(item.decode("utf-8", errors="replace"))
|
|
641
|
+
else:
|
|
642
|
+
string_items.append(str(item))
|
|
643
|
+
content = "".join(string_items)
|
|
644
|
+
# Parse JSON string if needed (handles escape sequences)
|
|
645
|
+
if isinstance(content, str):
|
|
646
|
+
try:
|
|
647
|
+
parsed = json.loads(content)
|
|
648
|
+
if isinstance(parsed, dict) and "response" in parsed:
|
|
649
|
+
content = parsed["response"]
|
|
650
|
+
elif isinstance(parsed, str):
|
|
651
|
+
content = parsed
|
|
652
|
+
except (json.JSONDecodeError, TypeError):
|
|
653
|
+
pass
|
|
654
|
+
_show_success_response(content)
|
|
578
655
|
|
|
579
656
|
except FileNotFoundError:
|
|
580
|
-
|
|
581
|
-
console.print("Run the following commands to get started:")
|
|
582
|
-
console.print(" 1. agentcore configure --entrypoint your_agent.py")
|
|
583
|
-
console.print(" 2. agentcore launch")
|
|
584
|
-
console.print(' 3. agentcore invoke \'{"message": "Hello"}\'')
|
|
657
|
+
_show_configuration_not_found_panel()
|
|
585
658
|
raise typer.Exit(1) from None
|
|
586
659
|
except ValueError as e:
|
|
660
|
+
try:
|
|
661
|
+
agent_display = config.name if config else (agent or "unknown")
|
|
662
|
+
agent_config = config
|
|
663
|
+
except NameError:
|
|
664
|
+
agent_display = agent or "unknown"
|
|
665
|
+
agent_config = None
|
|
666
|
+
_show_invoke_info_panel(agent_display, invoke_result=None, config=agent_config)
|
|
587
667
|
if "not deployed" in str(e):
|
|
588
|
-
|
|
589
|
-
console.print("Deploy your agent first:")
|
|
590
|
-
console.print(" agentcore launch # Deploy to AWS (recommended)")
|
|
591
|
-
console.print(" agentcore launch --local # Run locally")
|
|
592
|
-
console.print("Then check status: agentcore status")
|
|
593
|
-
_handle_error("Bedrock AgentCore not deployed. Run 'bedrock_agentcore launch' first", e)
|
|
668
|
+
_show_error_response("Agent not deployed - run 'agentcore launch' to deploy")
|
|
594
669
|
else:
|
|
595
|
-
|
|
670
|
+
_show_error_response(f"Invocation failed: {str(e)}")
|
|
671
|
+
raise typer.Exit(1) from e
|
|
596
672
|
except Exception as e:
|
|
597
|
-
|
|
673
|
+
try:
|
|
674
|
+
agent_config = config
|
|
675
|
+
agent_name = config.name if config else (agent or "unknown")
|
|
676
|
+
except (NameError, AttributeError):
|
|
677
|
+
try:
|
|
678
|
+
fallback_project_config = load_config(config_path)
|
|
679
|
+
agent_config = fallback_project_config.get_agent_config(agent)
|
|
680
|
+
agent_name = agent_config.name if agent_config else (agent or "unknown")
|
|
681
|
+
except Exception:
|
|
682
|
+
agent_config = None
|
|
683
|
+
agent_name = agent or "unknown"
|
|
684
|
+
|
|
685
|
+
from ...operations.runtime.models import InvokeResult
|
|
686
|
+
|
|
687
|
+
request_id = getattr(e, "response", {}).get("ResponseMetadata", {}).get("RequestId")
|
|
688
|
+
effective_session = session_id or (
|
|
689
|
+
agent_config.bedrock_agentcore.agent_session_id
|
|
690
|
+
if agent_config and hasattr(agent_config, "bedrock_agentcore")
|
|
691
|
+
else None
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
error_result = (
|
|
695
|
+
InvokeResult(
|
|
696
|
+
response={"ResponseMetadata": {"RequestId": request_id}} if request_id else {},
|
|
697
|
+
session_id=effective_session or "unknown",
|
|
698
|
+
agent_arn=agent_config.bedrock_agentcore.agent_arn
|
|
699
|
+
if agent_config and hasattr(agent_config, "bedrock_agentcore")
|
|
700
|
+
else None,
|
|
701
|
+
)
|
|
702
|
+
if (request_id or effective_session or agent_config)
|
|
703
|
+
else None
|
|
704
|
+
)
|
|
705
|
+
|
|
706
|
+
_show_invoke_info_panel(agent_name, invoke_result=error_result, config=agent_config)
|
|
707
|
+
_show_error_response(f"Invocation failed: {str(e)}")
|
|
708
|
+
raise typer.Exit(1) from e
|
|
598
709
|
|
|
599
710
|
|
|
600
711
|
def status(
|
|
@@ -620,104 +731,103 @@ def status(
|
|
|
620
731
|
if status_json["agent"] is None:
|
|
621
732
|
console.print(
|
|
622
733
|
Panel(
|
|
623
|
-
f"[
|
|
624
|
-
f"[
|
|
625
|
-
f"[cyan]
|
|
626
|
-
f"[cyan]
|
|
627
|
-
f"[cyan]
|
|
628
|
-
f"[
|
|
629
|
-
f"
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
Panel(
|
|
637
|
-
"[yellow]Agent is configured, but not launched yet. "
|
|
638
|
-
"Please use `agentcore launch` to launch the agent. [/yellow]\n\n",
|
|
639
|
-
title="Bedrock AgentCore Agent Status",
|
|
640
|
-
border_style="yellow",
|
|
734
|
+
f"⚠️ [yellow]Configured but not deployed[/yellow]\n\n"
|
|
735
|
+
f"[bold]Agent Details:[/bold]\n"
|
|
736
|
+
f"Agent Name: [cyan]{status_json['config']['name']}[/cyan]\n"
|
|
737
|
+
f"Region: [cyan]{status_json['config']['region']}[/cyan]\n"
|
|
738
|
+
f"Account: [cyan]{status_json['config']['account']}[/cyan]\n\n"
|
|
739
|
+
f"[bold]Configuration:[/bold]\n"
|
|
740
|
+
f"Execution Role: [dim]{status_json['config']['execution_role']}[/dim]\n"
|
|
741
|
+
f"ECR Repository: [dim]{status_json['config']['ecr_repository']}[/dim]\n\n"
|
|
742
|
+
f"Your agent is configured but not yet launched.\n\n"
|
|
743
|
+
f"[bold]Next Steps:[/bold]\n"
|
|
744
|
+
f" [cyan]agentcore launch[/cyan]",
|
|
745
|
+
title=f"Agent Status: {status_json['config']['name']}",
|
|
746
|
+
border_style="bright_blue",
|
|
641
747
|
)
|
|
642
748
|
)
|
|
643
749
|
|
|
644
750
|
elif "agent" in status_json and status_json["agent"] is not None:
|
|
645
751
|
agent_data = status_json["agent"]
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
752
|
+
endpoint_data = status_json.get("endpoint", {})
|
|
753
|
+
|
|
754
|
+
# Determine overall status
|
|
755
|
+
endpoint_status = endpoint_data.get("status", "Unknown") if endpoint_data else "Not Ready"
|
|
756
|
+
if endpoint_status == "READY":
|
|
757
|
+
status_text = "Ready - Agent deployed and endpoint available"
|
|
758
|
+
else:
|
|
759
|
+
status_text = "Deploying - Agent created, endpoint starting"
|
|
760
|
+
|
|
761
|
+
# Build consolidated panel with logs
|
|
762
|
+
panel_content = (
|
|
763
|
+
f"{status_text}\n\n"
|
|
764
|
+
f"[bold]Agent Details:[/bold]\n"
|
|
765
|
+
f"Agent Name: [cyan]{status_json['config']['name']}[/cyan]\n"
|
|
766
|
+
f"Agent ARN: [cyan]{status_json['config']['agent_arn']}[/cyan]\n"
|
|
767
|
+
f"Endpoint: [cyan]{endpoint_data.get('name', 'DEFAULT')}[/cyan] "
|
|
768
|
+
f"([cyan]{endpoint_status}[/cyan])\n"
|
|
769
|
+
f"Region: [cyan]{status_json['config']['region']}[/cyan] | "
|
|
770
|
+
f"Account: [dim]{status_json['config'].get('account', 'Not available')}[/dim]\n\n"
|
|
771
|
+
f"[bold]Deployment Info:[/bold]\n"
|
|
772
|
+
f"Created: [dim]{agent_data.get('createdAt', 'Not available')}[/dim]\n"
|
|
773
|
+
f"Last Updated: [dim]"
|
|
774
|
+
f"{endpoint_data.get('lastUpdatedAt') or agent_data.get('lastUpdatedAt', 'Not available')}"
|
|
775
|
+
f"[/dim]\n\n"
|
|
664
776
|
)
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
777
|
+
|
|
778
|
+
# Add CloudWatch logs information
|
|
779
|
+
agent_id = status_json.get("config", {}).get("agent_id")
|
|
780
|
+
if agent_id:
|
|
781
|
+
try:
|
|
782
|
+
endpoint_name = endpoint_data.get("name")
|
|
783
|
+
runtime_logs, otel_logs = get_agent_log_paths(agent_id, endpoint_name)
|
|
784
|
+
follow_cmd, since_cmd = get_aws_tail_commands(runtime_logs)
|
|
785
|
+
|
|
786
|
+
panel_content += f"📋 [cyan]CloudWatch Logs:[/cyan]\n {runtime_logs}\n {otel_logs}\n\n"
|
|
787
|
+
|
|
788
|
+
# Only show GenAI Observability Dashboard if OTEL is enabled
|
|
789
|
+
project_config = load_config(config_path)
|
|
790
|
+
agent_config = project_config.get_agent_config(agent)
|
|
791
|
+
if agent_config and agent_config.aws.observability.enabled:
|
|
792
|
+
panel_content += (
|
|
793
|
+
f"🔍 [cyan]GenAI Observability Dashboard:[/cyan]\n"
|
|
794
|
+
f" {get_genai_observability_url(status_json['config']['region'])}\n\n"
|
|
795
|
+
f"⏱️ [dim]Note: Observability data may take up to 10 minutes to appear "
|
|
796
|
+
f"after first launch[/dim]\n\n"
|
|
797
|
+
)
|
|
798
|
+
|
|
799
|
+
panel_content += f"💡 [dim]Tail logs with:[/dim]\n {follow_cmd}\n {since_cmd}\n\n"
|
|
800
|
+
except Exception: # nosec B110
|
|
801
|
+
# If log retrieval fails, continue without logs section
|
|
802
|
+
pass
|
|
803
|
+
|
|
804
|
+
# Add ready-to-invoke message if endpoint is ready
|
|
805
|
+
if endpoint_status == "READY":
|
|
806
|
+
panel_content += (
|
|
807
|
+
'[bold]Ready to invoke:[/bold]\n [cyan]agentcore invoke \'{"prompt": "Hello"}\'[/cyan]'
|
|
808
|
+
)
|
|
809
|
+
else:
|
|
810
|
+
panel_content += (
|
|
811
|
+
"[bold]Next Steps:[/bold]\n"
|
|
812
|
+
" [cyan]agentcore status[/cyan] # Check when endpoint is ready"
|
|
671
813
|
)
|
|
672
|
-
)
|
|
673
814
|
|
|
674
|
-
if "endpoint" in status_json and status_json["endpoint"] is not None:
|
|
675
|
-
endpoint_data = status_json["endpoint"]
|
|
676
815
|
console.print(
|
|
677
816
|
Panel(
|
|
678
|
-
|
|
679
|
-
f"
|
|
680
|
-
|
|
681
|
-
f"[green]Endpoint Arn: "
|
|
682
|
-
f"{endpoint_data.get('agentRuntimeEndpointArn', 'Not available')}[/green]\n"
|
|
683
|
-
f"[green]Agent Arn: {endpoint_data.get('agentRuntimeArn', 'Not available')}[/green]\n"
|
|
684
|
-
f"[green]STATUS: [cyan]{endpoint_data.get('status', 'Unknown')}[/cyan][/green]\n"
|
|
685
|
-
f"[green]Last Updated at: "
|
|
686
|
-
f"{endpoint_data.get('lastUpdatedAt', 'Not available')}[/green]\n",
|
|
687
|
-
title="Bedrock AgentCore Endpoint Status",
|
|
688
|
-
border_style="green",
|
|
817
|
+
panel_content,
|
|
818
|
+
title=f"Agent Status: {status_json['config']['name']}",
|
|
819
|
+
border_style="bright_blue",
|
|
689
820
|
)
|
|
690
821
|
)
|
|
691
822
|
else:
|
|
692
823
|
console.print(
|
|
693
824
|
Panel(
|
|
694
|
-
"[
|
|
695
|
-
"
|
|
696
|
-
|
|
697
|
-
border_style="yellow",
|
|
825
|
+
"[green]Please launch agent first![/green]\n\n",
|
|
826
|
+
title="Bedrock AgentCore Agent Status",
|
|
827
|
+
border_style="bright_blue",
|
|
698
828
|
)
|
|
699
829
|
)
|
|
700
830
|
|
|
701
|
-
# Show log information
|
|
702
|
-
agent_id = status_json.get("config", {}).get("agent_id")
|
|
703
|
-
if agent_id:
|
|
704
|
-
try:
|
|
705
|
-
from ...utils.runtime.logs import get_agent_log_paths, get_aws_tail_commands
|
|
706
|
-
|
|
707
|
-
endpoint_name = status_json.get("endpoint", {}).get("name")
|
|
708
|
-
|
|
709
|
-
runtime_logs, otel_logs = get_agent_log_paths(agent_id, endpoint_name)
|
|
710
|
-
follow_cmd, since_cmd = get_aws_tail_commands(runtime_logs)
|
|
711
|
-
|
|
712
|
-
console.print("\n📋 [cyan]Agent logs available at:[/cyan]")
|
|
713
|
-
console.print(f" {runtime_logs}")
|
|
714
|
-
console.print(f" {otel_logs}")
|
|
715
|
-
console.print("\n💡 [dim]Tail logs with:[/dim]")
|
|
716
|
-
console.print(f" {follow_cmd}")
|
|
717
|
-
console.print(f" {since_cmd}")
|
|
718
|
-
except (ValueError, TypeError) as e:
|
|
719
|
-
# If logging info fails, log the error and continue
|
|
720
|
-
logger.debug("Failed to display log paths: %s", str(e))
|
|
721
831
|
else: # full json verbose output
|
|
722
832
|
console.print(
|
|
723
833
|
Syntax(
|
|
@@ -729,13 +839,180 @@ def status(
|
|
|
729
839
|
)
|
|
730
840
|
|
|
731
841
|
except FileNotFoundError:
|
|
732
|
-
|
|
842
|
+
_show_configuration_not_found_panel()
|
|
843
|
+
raise typer.Exit(1) from None
|
|
844
|
+
except ValueError as e:
|
|
845
|
+
console.print(
|
|
846
|
+
Panel(
|
|
847
|
+
f"❌ [red]Status Check Failed[/red]\n\n"
|
|
848
|
+
f"Error: {str(e)}\n\n"
|
|
849
|
+
f"[bold]Next Steps:[/bold]\n"
|
|
850
|
+
f" [cyan]agentcore configure --entrypoint your_agent.py[/cyan]\n"
|
|
851
|
+
f" [cyan]agentcore launch[/cyan]",
|
|
852
|
+
title="❌ Status Error",
|
|
853
|
+
border_style="bright_blue",
|
|
854
|
+
)
|
|
855
|
+
)
|
|
856
|
+
raise typer.Exit(1) from e
|
|
857
|
+
except Exception as e:
|
|
858
|
+
console.print(
|
|
859
|
+
Panel(
|
|
860
|
+
f"❌ [red]Status Check Failed[/red]\n\n"
|
|
861
|
+
f"Unexpected error: {str(e)}\n\n"
|
|
862
|
+
f"[bold]Next Steps:[/bold]\n"
|
|
863
|
+
f" [cyan]agentcore configure --entrypoint your_agent.py[/cyan]\n"
|
|
864
|
+
f" [cyan]agentcore launch[/cyan]",
|
|
865
|
+
title="❌ Status Error",
|
|
866
|
+
border_style="bright_blue",
|
|
867
|
+
)
|
|
868
|
+
)
|
|
869
|
+
raise typer.Exit(1) from e
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
def destroy(
|
|
873
|
+
agent: Optional[str] = typer.Option(
|
|
874
|
+
None, "--agent", "-a", help="Agent name (use 'agentcore configure list' to see available agents)"
|
|
875
|
+
),
|
|
876
|
+
dry_run: bool = typer.Option(
|
|
877
|
+
False, "--dry-run", help="Show what would be destroyed without actually destroying anything"
|
|
878
|
+
),
|
|
879
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation prompts and destroy immediately"),
|
|
880
|
+
delete_ecr_repo: bool = typer.Option(
|
|
881
|
+
False, "--delete-ecr-repo", help="Also delete the ECR repository after removing images"
|
|
882
|
+
),
|
|
883
|
+
) -> None:
|
|
884
|
+
"""Destroy Bedrock AgentCore resources.
|
|
885
|
+
|
|
886
|
+
This command removes the following AWS resources for the specified agent:
|
|
887
|
+
- Bedrock AgentCore endpoint (if exists)
|
|
888
|
+
- Bedrock AgentCore agent runtime
|
|
889
|
+
- ECR images (all images in the agent's repository)
|
|
890
|
+
- CodeBuild project
|
|
891
|
+
- IAM execution role (only if not used by other agents)
|
|
892
|
+
- Agent deployment configuration
|
|
893
|
+
- ECR repository (only if --delete-ecr-repo is specified)
|
|
894
|
+
|
|
895
|
+
CAUTION: This action cannot be undone. Use --dry-run to preview changes first.
|
|
896
|
+
"""
|
|
897
|
+
config_path = Path.cwd() / ".bedrock_agentcore.yaml"
|
|
898
|
+
|
|
899
|
+
try:
|
|
900
|
+
# Load project configuration to get agent details
|
|
901
|
+
project_config = load_config(config_path)
|
|
902
|
+
agent_config = project_config.get_agent_config(agent)
|
|
903
|
+
|
|
904
|
+
if not agent_config:
|
|
905
|
+
_handle_error(f"Agent '{agent or 'default'}' not found in configuration")
|
|
906
|
+
|
|
907
|
+
actual_agent_name = agent_config.name
|
|
908
|
+
|
|
909
|
+
# Show what will be destroyed
|
|
910
|
+
if dry_run:
|
|
911
|
+
console.print(
|
|
912
|
+
f"[cyan]🔍 Dry run: Preview of resources that would be destroyed for agent "
|
|
913
|
+
f"'{actual_agent_name}'[/cyan]\n"
|
|
914
|
+
)
|
|
915
|
+
else:
|
|
916
|
+
console.print(f"[yellow]⚠️ About to destroy resources for agent '{actual_agent_name}'[/yellow]\n")
|
|
917
|
+
|
|
918
|
+
# Check if agent is deployed
|
|
919
|
+
if not agent_config.bedrock_agentcore:
|
|
920
|
+
console.print("[yellow]Agent is not deployed, nothing to destroy[/yellow]")
|
|
921
|
+
return
|
|
922
|
+
|
|
923
|
+
# Show deployment details
|
|
924
|
+
console.print("[cyan]Current deployment:[/cyan]")
|
|
925
|
+
if agent_config.bedrock_agentcore.agent_arn:
|
|
926
|
+
console.print(f" • Agent ARN: {agent_config.bedrock_agentcore.agent_arn}")
|
|
927
|
+
if agent_config.bedrock_agentcore.agent_id:
|
|
928
|
+
console.print(f" • Agent ID: {agent_config.bedrock_agentcore.agent_id}")
|
|
929
|
+
if agent_config.aws.ecr_repository:
|
|
930
|
+
console.print(f" • ECR Repository: {agent_config.aws.ecr_repository}")
|
|
931
|
+
if agent_config.aws.execution_role:
|
|
932
|
+
console.print(f" • Execution Role: {agent_config.aws.execution_role}")
|
|
933
|
+
console.print()
|
|
934
|
+
|
|
935
|
+
# Confirmation prompt (unless force or dry_run)
|
|
936
|
+
if not dry_run and not force:
|
|
937
|
+
console.print("[red]This will permanently delete AWS resources and cannot be undone![/red]")
|
|
938
|
+
if delete_ecr_repo:
|
|
939
|
+
console.print("[red]This includes deleting the ECR repository itself![/red]")
|
|
940
|
+
response = typer.confirm(
|
|
941
|
+
f"Are you sure you want to destroy the agent '{actual_agent_name}' and all its resources?"
|
|
942
|
+
)
|
|
943
|
+
if not response:
|
|
944
|
+
console.print("[yellow]Destruction cancelled[/yellow]")
|
|
945
|
+
return
|
|
946
|
+
|
|
947
|
+
# Perform the destroy operation
|
|
948
|
+
with console.status(f"[bold]{'Analyzing' if dry_run else 'Destroying'} Bedrock AgentCore resources...[/bold]"):
|
|
949
|
+
result = destroy_bedrock_agentcore(
|
|
950
|
+
config_path=config_path,
|
|
951
|
+
agent_name=actual_agent_name,
|
|
952
|
+
dry_run=dry_run,
|
|
953
|
+
force=force,
|
|
954
|
+
delete_ecr_repo=delete_ecr_repo,
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
# Display results
|
|
958
|
+
if dry_run:
|
|
959
|
+
console.print(f"[cyan]📋 Dry run completed for agent '{result.agent_name}'[/cyan]\n")
|
|
960
|
+
title = "Resources That Would Be Destroyed"
|
|
961
|
+
color = "cyan"
|
|
962
|
+
else:
|
|
963
|
+
if result.errors:
|
|
964
|
+
console.print(
|
|
965
|
+
f"[yellow]⚠️ Destruction completed with errors for agent '{result.agent_name}'[/yellow]\n"
|
|
966
|
+
)
|
|
967
|
+
title = "Destruction Results (With Errors)"
|
|
968
|
+
color = "yellow"
|
|
969
|
+
else:
|
|
970
|
+
console.print(f"[green]✅ Successfully destroyed resources for agent '{result.agent_name}'[/green]\n")
|
|
971
|
+
title = "Resources Successfully Destroyed"
|
|
972
|
+
color = "green"
|
|
973
|
+
|
|
974
|
+
# Show resources removed
|
|
975
|
+
if result.resources_removed:
|
|
976
|
+
resources_text = "\n".join([f" ✓ {resource}" for resource in result.resources_removed])
|
|
977
|
+
console.print(Panel(resources_text, title=title, border_style=color))
|
|
978
|
+
else:
|
|
979
|
+
console.print(Panel("No resources were found to destroy", title="Results", border_style="yellow"))
|
|
980
|
+
|
|
981
|
+
# Show warnings
|
|
982
|
+
if result.warnings:
|
|
983
|
+
warnings_text = "\n".join([f" ⚠️ {warning}" for warning in result.warnings])
|
|
984
|
+
console.print(Panel(warnings_text, title="Warnings", border_style="yellow"))
|
|
985
|
+
|
|
986
|
+
# Show errors
|
|
987
|
+
if result.errors:
|
|
988
|
+
errors_text = "\n".join([f" ❌ {error}" for error in result.errors])
|
|
989
|
+
console.print(Panel(errors_text, title="Errors", border_style="red"))
|
|
990
|
+
|
|
991
|
+
# Next steps
|
|
992
|
+
if not dry_run and not result.errors:
|
|
993
|
+
console.print("\n[dim]Next steps:[/dim]")
|
|
994
|
+
console.print(" • Run 'agentcore configure --entrypoint <file>' to set up a new agent")
|
|
995
|
+
console.print(" • Run 'agentcore launch' to deploy to Bedrock AgentCore")
|
|
996
|
+
elif dry_run:
|
|
997
|
+
console.print("\n[dim]To actually destroy these resources, run:[/dim]")
|
|
998
|
+
destroy_cmd = f" agentcore destroy{f' --agent {actual_agent_name}' if agent else ''}"
|
|
999
|
+
if delete_ecr_repo:
|
|
1000
|
+
destroy_cmd += " --delete-ecr-repo"
|
|
1001
|
+
console.print(destroy_cmd)
|
|
1002
|
+
|
|
1003
|
+
except FileNotFoundError:
|
|
1004
|
+
console.print("[red].bedrock_agentcore.yaml not found[/red]")
|
|
733
1005
|
console.print("Run the following commands to get started:")
|
|
734
1006
|
console.print(" 1. agentcore configure --entrypoint your_agent.py")
|
|
735
1007
|
console.print(" 2. agentcore launch")
|
|
736
1008
|
console.print(' 3. agentcore invoke \'{"message": "Hello"}\'')
|
|
737
1009
|
raise typer.Exit(1) from None
|
|
738
1010
|
except ValueError as e:
|
|
739
|
-
|
|
1011
|
+
if "not found" in str(e):
|
|
1012
|
+
_handle_error("Agent not found. Use 'agentcore configure list' to see available agents", e)
|
|
1013
|
+
else:
|
|
1014
|
+
_handle_error(f"Destruction failed: {e}", e)
|
|
1015
|
+
except RuntimeError as e:
|
|
1016
|
+
_handle_error(f"Destruction failed: {e}", e)
|
|
740
1017
|
except Exception as e:
|
|
741
|
-
_handle_error(f"
|
|
1018
|
+
_handle_error(f"Destruction failed: {e}", e)
|