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.

Files changed (20) hide show
  1. bedrock_agentcore_starter_toolkit/cli/cli.py +3 -1
  2. bedrock_agentcore_starter_toolkit/cli/runtime/commands.py +453 -176
  3. bedrock_agentcore_starter_toolkit/operations/gateway/create_role.py +6 -11
  4. bedrock_agentcore_starter_toolkit/operations/runtime/__init__.py +4 -0
  5. bedrock_agentcore_starter_toolkit/operations/runtime/destroy.py +547 -0
  6. bedrock_agentcore_starter_toolkit/operations/runtime/invoke.py +2 -2
  7. bedrock_agentcore_starter_toolkit/operations/runtime/launch.py +15 -0
  8. bedrock_agentcore_starter_toolkit/operations/runtime/models.py +10 -0
  9. bedrock_agentcore_starter_toolkit/services/import_agent/scripts/base_bedrock_translate.py +4 -3
  10. bedrock_agentcore_starter_toolkit/services/import_agent/utils.py +14 -0
  11. bedrock_agentcore_starter_toolkit/services/runtime.py +38 -4
  12. bedrock_agentcore_starter_toolkit/services/xray.py +161 -0
  13. bedrock_agentcore_starter_toolkit/utils/runtime/logs.py +18 -2
  14. bedrock_agentcore_starter_toolkit/utils/runtime/templates/Dockerfile.j2 +11 -25
  15. {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/METADATA +4 -3
  16. {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/RECORD +20 -18
  17. {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/WHEEL +0 -0
  18. {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/entry_points.txt +0 -0
  19. {bedrock_agentcore_starter_toolkit-0.1.9.dist-info → bedrock_agentcore_starter_toolkit-0.1.11.dist-info}/licenses/LICENSE.txt +0 -0
  20. {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 Summary[/green]\n\n"
241
- f"Name: {agent_name}\n"
242
- f"Runtime: {result.runtime}\n"
243
- f"Region: {result.region}\n"
244
- f"Account: {result.account_id}\n"
245
- f"Execution Role: {result.execution_role}\n"
246
- f"ECR: {'Auto-create' if result.auto_create_ecr else result.ecr_repository or 'N/A'}\n"
247
- f"Authorization: {auth_info}\n\n"
248
- f"Configuration saved to: {result.config_path}",
249
- title="Bedrock AgentCore Configured",
250
- border_style="green",
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 ARM64 Deployment Successful![/green]\n\n"
407
- f"Agent Name: {agent_name}\n"
408
- f"CodeBuild ID: [cyan]{result.codebuild_id}[/cyan]\n"
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\n"
411
- f"ARM64 container deployed to Bedrock AgentCore.\n\n"
412
- f"You can now check the status of your Bedrock AgentCore endpoint with:\n"
413
- f"[cyan]agentcore status[/cyan]\n\n"
414
- f"You can now invoke your Bedrock AgentCore endpoint with:\n"
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
- f"\n\n📋 [cyan]Agent logs available at:[/cyan]\n"
426
- f" {runtime_logs}\n"
427
- f" {otel_logs}\n\n"
428
- f"💡 [dim]Tail logs with:[/dim]\n"
429
- f" {follow_cmd}\n"
430
- f" {since_cmd}"
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="CodeBuild Deployment Complete",
437
- border_style="green",
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 Deployment Complete"
450
- deployment_type = "Local Docker Build Deployment Successful!"
471
+ title = "Local Build Success"
472
+ deployment_type = "✅ [green]Local Build Deployment Successful![/green]"
473
+ icon = "🔧"
451
474
  else:
452
- title = "CodeBuild Deployment Complete"
453
- deployment_type = "CodeBuild Deployment Successful!"
475
+ title = "Deployment Success"
476
+ deployment_type = " [green]Deployment Successful![/green]"
477
+ icon = "🚀"
454
478
 
455
479
  deploy_panel = (
456
- f"[green]{deployment_type}[/green]\n\n"
457
- f"Agent Name: {agent_name}\n"
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"You can now check the status of your Bedrock AgentCore endpoint with:\n"
461
- f"[cyan]agentcore status[/cyan]\n\n"
462
- f"You can now invoke your Bedrock AgentCore endpoint with:\n"
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]Agent logs available at:[/cyan]\n"
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="green",
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 = {"message": payload}
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
- console.print(f"Session ID: [cyan]{result.session_id}[/cyan]")
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
- console.print("\n[bold]Response:[/bold]")
570
- console.print(
571
- Syntax(
572
- json.dumps(result.response, indent=2, default=str, ensure_ascii=False),
573
- "json",
574
- background_color="default",
575
- word_wrap=True,
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
- console.print("[red].bedrock_agentcore.yaml not found[/red]")
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
- console.print("[yellow]Agent not deployed yet[/yellow]")
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
- _handle_error(f"Invocation failed: {e}", e)
670
+ _show_error_response(f"Invocation failed: {str(e)}")
671
+ raise typer.Exit(1) from e
596
672
  except Exception as e:
597
- _handle_error(f"Invocation failed: {e}", e)
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"[green]Status of the current Agent:[/green]\n\n"
624
- f"[green]Agent Name: {status_json['config']['name']}[/green]\n"
625
- f"[cyan]Configuration details:[/cyan]\n"
626
- f"[cyan]- region: {status_json['config']['region']}[/cyan]\n"
627
- f"[cyan]- account: {status_json['config']['account']}[/cyan]\n"
628
- f"[cyan]- execution role: {status_json['config']['execution_role']}[/cyan]\n"
629
- f"[cyan]- ecr repository: {status_json['config']['ecr_repository']}[/cyan]\n",
630
- title="Bedrock AgentCore Agent Status",
631
- border_style="green",
632
- )
633
- )
634
-
635
- console.print(
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
- console.print(
647
- Panel(
648
- f"[green]Status of the current Agent:[/green]\n\n"
649
- f"[green]Agent Name: {status_json['config']['name']}[/green]\n"
650
- f"[green]Agent ID: {status_json['config']['agent_id']}[/green]\n"
651
- f"[green]Agent Arn: {status_json['config']['agent_arn']}[/green]\n"
652
- f"[green]Created at: {agent_data.get('createdAt', 'Not available')}[/green]\n"
653
- f"[green]Last Updated at: {agent_data.get('lastUpdatedAt', 'Not available')}[/green]\n"
654
- f"[cyan]Configuration details:[/cyan]\n"
655
- f"[cyan]- region: {status_json['config']['region']}[/cyan]\n"
656
- f"[cyan]- account: {status_json['config'].get('account', 'Not available')}[/cyan]\n"
657
- f"[cyan]- execution role: "
658
- f"{status_json['config'].get('execution_role', 'Not available')}[/cyan]\n"
659
- f"[cyan]- ecr repository: "
660
- f"{status_json['config'].get('ecr_repository', 'Not available')}[/cyan]\n",
661
- title="Bedrock AgentCore Agent Status",
662
- border_style="green",
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
- else:
666
- console.print(
667
- Panel(
668
- "[green]Please launch agent first![/green]\n\n",
669
- title="Bedrock AgentCore Agent Status",
670
- border_style="yellow",
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
- f"[green]Status of the current Endpoint:[/green]\n\n"
679
- f"[green]Endpoint Id: {endpoint_data.get('id', 'Not available')}[/green]\n"
680
- f"[green]Endpoint Name: {endpoint_data.get('name', 'Not available')}[/green]\n"
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
- "[yellow]Please launch agent first and make sure endpoint status is READY "
695
- "before invoking![/yellow]\n\n",
696
- title="Bedrock AgentCore Endpoint Status",
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
- console.print("[yellow]Configuration not found[/yellow]")
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
- _handle_error(f"Status failed: {e}", e)
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"Status failed: {e}", e)
1018
+ _handle_error(f"Destruction failed: {e}", e)