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.

Files changed (25) hide show
  1. bedrock_agentcore_starter_toolkit/cli/cli.py +9 -1
  2. bedrock_agentcore_starter_toolkit/cli/runtime/commands.py +263 -7
  3. bedrock_agentcore_starter_toolkit/cli/runtime/configuration_manager.py +31 -7
  4. bedrock_agentcore_starter_toolkit/notebook/runtime/bedrock_agentcore.py +240 -2
  5. bedrock_agentcore_starter_toolkit/operations/identity/__init__.py +5 -0
  6. bedrock_agentcore_starter_toolkit/operations/identity/oauth2_callback_server.py +86 -0
  7. bedrock_agentcore_starter_toolkit/operations/memory/manager.py +20 -33
  8. bedrock_agentcore_starter_toolkit/operations/memory/models/strategies/base.py +2 -0
  9. bedrock_agentcore_starter_toolkit/operations/memory/models/strategies/self_managed.py +107 -0
  10. bedrock_agentcore_starter_toolkit/operations/runtime/__init__.py +4 -0
  11. bedrock_agentcore_starter_toolkit/operations/runtime/configure.py +120 -5
  12. bedrock_agentcore_starter_toolkit/operations/runtime/invoke.py +30 -54
  13. bedrock_agentcore_starter_toolkit/operations/runtime/launch.py +213 -16
  14. bedrock_agentcore_starter_toolkit/operations/runtime/models.py +19 -0
  15. bedrock_agentcore_starter_toolkit/operations/runtime/status.py +30 -0
  16. bedrock_agentcore_starter_toolkit/operations/runtime/stop_session.py +123 -0
  17. bedrock_agentcore_starter_toolkit/operations/runtime/vpc_validation.py +196 -0
  18. bedrock_agentcore_starter_toolkit/services/runtime.py +46 -2
  19. bedrock_agentcore_starter_toolkit/utils/runtime/schema.py +44 -1
  20. {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/METADATA +13 -12
  21. {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/RECORD +25 -20
  22. {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/WHEEL +0 -0
  23. {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/entry_points.txt +0 -0
  24. {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/licenses/LICENSE.txt +0 -0
  25. {bedrock_agentcore_starter_toolkit-0.1.25.dist-info → bedrock_agentcore_starter_toolkit-0.1.27.dist-info}/licenses/NOTICE.txt +0 -0
@@ -5,7 +5,14 @@ import typer
5
5
  from ..cli.gateway.commands import create_mcp_gateway, create_mcp_gateway_target, gateway_app
6
6
  from ..utils.logging_config import setup_toolkit_logging
7
7
  from .import_agent.commands import import_agent
8
- from .runtime.commands import configure_app, destroy, invoke, launch, status
8
+ from .runtime.commands import (
9
+ configure_app,
10
+ destroy,
11
+ invoke,
12
+ launch,
13
+ status,
14
+ stop_session,
15
+ )
9
16
 
10
17
  app = typer.Typer(name="agentcore", help="BedrockAgentCore CLI", add_completion=False, rich_markup_mode="rich")
11
18
 
@@ -18,6 +25,7 @@ app.command("status")(status)
18
25
  app.command("launch")(launch)
19
26
  app.command("import-agent")(import_agent)
20
27
  app.command("destroy")(destroy)
28
+ app.command("stop-session")(stop_session)
21
29
  app.add_typer(configure_app)
22
30
 
23
31
  # gateway
@@ -4,6 +4,7 @@ import json
4
4
  import logging
5
5
  import os
6
6
  from pathlib import Path
7
+ from threading import Thread
7
8
  from typing import List, Optional
8
9
 
9
10
  import typer
@@ -12,6 +13,7 @@ from prompt_toolkit.completion import PathCompleter
12
13
  from rich.panel import Panel
13
14
  from rich.syntax import Syntax
14
15
 
16
+ from ...operations.identity.oauth2_callback_server import start_oauth2_callback_server
15
17
  from ...operations.runtime import (
16
18
  configure_bedrock_agentcore,
17
19
  destroy_bedrock_agentcore,
@@ -255,6 +257,33 @@ def configure(
255
257
  help="Comma-separated list of allowed request headers "
256
258
  "(Authorization or X-Amzn-Bedrock-AgentCore-Runtime-Custom-*)",
257
259
  ),
260
+ vpc: bool = typer.Option(
261
+ False, "--vpc", help="Enable VPC networking mode (requires --subnets and --security-groups)"
262
+ ),
263
+ subnets: Optional[str] = typer.Option(
264
+ None,
265
+ "--subnets",
266
+ help="Comma-separated list of subnet IDs (e.g., subnet-abc123,subnet-def456). Required with --vpc.",
267
+ ),
268
+ security_groups: Optional[str] = typer.Option(
269
+ None,
270
+ "--security-groups",
271
+ help="Comma-separated list of security group IDs (e.g., sg-xyz789). Required with --vpc.",
272
+ ),
273
+ idle_timeout: Optional[int] = typer.Option(
274
+ None,
275
+ "--idle-timeout",
276
+ help="Idle runtime session timeout in seconds (60-28800, default: 900)",
277
+ min=60,
278
+ max=28800,
279
+ ),
280
+ max_lifetime: Optional[int] = typer.Option(
281
+ None,
282
+ "--max-lifetime",
283
+ help="Maximum instance lifetime in seconds (60-28800, default: 28800)",
284
+ min=60,
285
+ max=28800,
286
+ ),
258
287
  verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose output"),
259
288
  region: Optional[str] = typer.Option(None, "--region", "-r"),
260
289
  protocol: Optional[str] = typer.Option(None, "--protocol", "-p", help="Server protocol (HTTP or MCP or A2A)"),
@@ -275,6 +304,64 @@ def configure(
275
304
  if protocol and protocol.upper() not in ["HTTP", "MCP", "A2A"]:
276
305
  _handle_error("Error: --protocol must be either HTTP or MCP or A2A")
277
306
 
307
+ # Validate VPC configuration
308
+ vpc_subnets = None
309
+ vpc_security_groups = None
310
+
311
+ if vpc:
312
+ # VPC mode requires both subnets and security groups
313
+ if not subnets or not security_groups:
314
+ _handle_error(
315
+ "VPC mode requires both --subnets and --security-groups.\n"
316
+ "Example: agentcore configure --entrypoint my_agent.py --vpc "
317
+ "--subnets subnet-abc123,subnet-def456 --security-groups sg-xyz789"
318
+ )
319
+
320
+ # Parse and validate subnet IDs - UPDATED VALIDATION
321
+ vpc_subnets = [s.strip() for s in subnets.split(",") if s.strip()]
322
+ for subnet_id in vpc_subnets:
323
+ # Format: subnet-{8-17 hex characters}
324
+ if not subnet_id.startswith("subnet-"):
325
+ _handle_error(
326
+ f"Invalid subnet ID format: {subnet_id}\nSubnet IDs must start with 'subnet-' (e.g., subnet-abc123)"
327
+ )
328
+ # Check minimum length (subnet- + at least 8 chars)
329
+ if len(subnet_id) < 15: # "subnet-" (7) + 8 chars = 15
330
+ _handle_error(
331
+ f"Invalid subnet ID format: {subnet_id}\nSubnet ID is too short. Expected format: subnet-xxxxxxxx"
332
+ )
333
+
334
+ # Parse and validate security group IDs - UPDATED VALIDATION
335
+ vpc_security_groups = [sg.strip() for sg in security_groups.split(",") if sg.strip()]
336
+ for sg_id in vpc_security_groups:
337
+ # Format: sg-{8-17 hex characters}
338
+ if not sg_id.startswith("sg-"):
339
+ _handle_error(
340
+ f"Invalid security group ID format: {sg_id}\n"
341
+ f"Security group IDs must start with 'sg-' (e.g., sg-abc123)"
342
+ )
343
+ # Check minimum length (sg- + at least 8 chars)
344
+ if len(sg_id) < 11: # "sg-" (3) + 8 chars = 11
345
+ _handle_error(
346
+ f"Invalid security group ID format: {sg_id}\n"
347
+ f"Security group ID is too short. Expected format: sg-xxxxxxxx"
348
+ )
349
+
350
+ _print_success(
351
+ f"VPC mode enabled with {len(vpc_subnets)} subnets and {len(vpc_security_groups)} security groups"
352
+ )
353
+
354
+ elif subnets or security_groups:
355
+ # Error: VPC resources provided without --vpc flag
356
+ _handle_error(
357
+ "The --subnets and --security-groups flags require --vpc flag.\n"
358
+ "Use: agentcore configure --entrypoint my_agent.py --vpc --subnets ... --security-groups ..."
359
+ )
360
+ # Validate lifecycle configuration
361
+ if idle_timeout is not None and max_lifetime is not None:
362
+ if idle_timeout > max_lifetime:
363
+ _handle_error(f"Error: --idle-timeout ({idle_timeout}s) must be <= --max-lifetime ({max_lifetime}s)")
364
+
278
365
  console.print("[cyan]Configuring Bedrock AgentCore...[/cyan]")
279
366
 
280
367
  # Create configuration manager early for consistent prompting
@@ -397,6 +484,11 @@ def configure(
397
484
  protocol=protocol.upper() if protocol else None,
398
485
  non_interactive=non_interactive,
399
486
  source_path=source_path,
487
+ vpc_enabled=vpc,
488
+ vpc_subnets=vpc_subnets,
489
+ vpc_security_groups=vpc_security_groups,
490
+ idle_timeout=idle_timeout,
491
+ max_lifetime=max_lifetime,
400
492
  )
401
493
 
402
494
  # Prepare authorization info for summary
@@ -410,10 +502,29 @@ def configure(
410
502
  headers = request_header_config.get("requestHeaderAllowlist", [])
411
503
  headers_info = f"Request Headers Allowlist: [dim]{len(headers)} headers configured[/dim]\n"
412
504
 
505
+ network_info = "Public"
506
+ if vpc:
507
+ network_info = f"VPC ({len(vpc_subnets)} subnets, {len(vpc_security_groups)} security groups)"
508
+
413
509
  execution_role_display = "Auto-create" if not result.execution_role else result.execution_role
414
- memory_info = "Short-term memory (30-day retention)"
415
- if disable_memory:
510
+ saved_config = load_config(result.config_path)
511
+ saved_agent = saved_config.get_agent_config(agent_name)
512
+
513
+ # Display memory status based on actual configuration
514
+ if saved_agent.memory.mode == "NO_MEMORY":
416
515
  memory_info = "Disabled"
516
+ elif saved_agent.memory.mode == "STM_AND_LTM":
517
+ memory_info = "Short-term + Long-term memory (30-day retention)"
518
+ else: # STM_ONLY
519
+ memory_info = "Short-term memory (30-day retention)"
520
+
521
+ lifecycle_info = ""
522
+ if idle_timeout or max_lifetime:
523
+ lifecycle_info = "\n[bold]Lifecycle Settings:[/bold]\n"
524
+ if idle_timeout:
525
+ lifecycle_info += f"Idle Timeout: [cyan]{idle_timeout}s ({idle_timeout // 60} minutes)[/cyan]\n"
526
+ if max_lifetime:
527
+ lifecycle_info += f"Max Lifetime: [cyan]{max_lifetime}s ({max_lifetime // 3600} hours)[/cyan]\n"
417
528
 
418
529
  console.print(
419
530
  Panel(
@@ -427,9 +538,11 @@ def configure(
427
538
  f"ECR Repository: [cyan]"
428
539
  f"{'Auto-create' if result.auto_create_ecr else result.ecr_repository or 'N/A'}"
429
540
  f"[/cyan]\n"
541
+ f"Network Mode: [cyan]{network_info}[/cyan]\n"
430
542
  f"Authorization: [cyan]{auth_info}[/cyan]\n\n"
431
543
  f"{headers_info}\n"
432
544
  f"Memory: [cyan]{memory_info}[/cyan]\n\n"
545
+ f"{lifecycle_info}\n"
433
546
  f"📄 Config saved to: [dim]{result.config_path}[/dim]\n\n"
434
547
  f"[bold]Next Steps:[/bold]\n"
435
548
  f" [cyan]agentcore launch[/cyan]",
@@ -566,6 +679,7 @@ def launch(
566
679
  use_codebuild=not local_build,
567
680
  env_vars=env_vars,
568
681
  auto_update_on_conflict=auto_update_on_conflict,
682
+ console=console,
569
683
  )
570
684
 
571
685
  project_config = load_config(config_path)
@@ -575,12 +689,23 @@ def launch(
575
689
  _print_success(f"Docker image built: {result.tag}")
576
690
  _print_success("Ready to run locally")
577
691
  console.print("Starting server at http://localhost:8080")
692
+ console.print("Starting OAuth2 3LO callback server at http://localhost:8081")
578
693
  console.print("[yellow]Press Ctrl+C to stop[/yellow]\n")
579
694
 
580
695
  if result.runtime is None or result.port is None:
581
696
  _handle_error("Unable to launch locally")
582
697
 
583
698
  try:
699
+ oauth2_callback_endpoint = Thread(
700
+ target=start_oauth2_callback_server,
701
+ args=(
702
+ config_path,
703
+ agent,
704
+ ),
705
+ name="OAuth2 3LO Callback Server",
706
+ daemon=True,
707
+ )
708
+ oauth2_callback_endpoint.start()
584
709
  result.runtime.run_local(result.tag, result.port, result.env_vars)
585
710
  except KeyboardInterrupt:
586
711
  console.print("\n[yellow]Stopped[/yellow]")
@@ -970,11 +1095,6 @@ def status(
970
1095
 
971
1096
  # Determine overall status
972
1097
  endpoint_status = endpoint_data.get("status", "Unknown") if endpoint_data else "Not Ready"
973
- # memory_info = ""
974
- # if hasattr(status_json["config"], "memory_id") and status_json["config"].get("memory_id"):
975
- # memory_type = status_json["config"].get("memory_type", "Short-term")
976
- # memory_id = status_json["config"].get("memory_id")
977
- # memory_info = f"Memory: [cyan]{memory_type}[/cyan] ([dim]{memory_id}[/dim])\n"
978
1098
  if endpoint_status == "READY":
979
1099
  status_text = "Ready - Agent deployed and endpoint available"
980
1100
  else:
@@ -992,6 +1112,26 @@ def status(
992
1112
  f"Account: [dim]{status_json['config'].get('account', 'Not available')}[/dim]\n\n"
993
1113
  )
994
1114
 
1115
+ # Add network information
1116
+ network_mode = status_json.get("agent", {}).get("networkConfiguration", {}).get("networkMode")
1117
+ if network_mode == "VPC":
1118
+ # Get VPC info from agent response (not config)
1119
+ network_config = (
1120
+ status_json.get("agent", {}).get("networkConfiguration", {}).get("networkModeConfig", {})
1121
+ )
1122
+ vpc_subnets = network_config.get("subnets", [])
1123
+ vpc_security_groups = network_config.get("securityGroups", [])
1124
+ subnet_count = len(vpc_subnets)
1125
+ sg_count = len(vpc_security_groups)
1126
+ vpc_id = status_json.get("config", {}).get("network_vpc_id", "unknown")
1127
+ if vpc_id:
1128
+ panel_content += f"Network: [cyan]VPC[/cyan] ([dim]{vpc_id}[/dim])\n"
1129
+ panel_content += f" {subnet_count} subnets, {sg_count} security groups\n\n"
1130
+ else:
1131
+ panel_content += "Network: [cyan]VPC[/cyan]\n\n"
1132
+ else:
1133
+ panel_content += "Network: [cyan]Public[/cyan]\n\n"
1134
+
995
1135
  # Add memory status with proper provisioning indication
996
1136
  if "memory_id" in status_json.get("config", {}) and status_json["config"]["memory_id"]:
997
1137
  memory_type = status_json["config"].get("memory_type", "Unknown")
@@ -1021,6 +1161,19 @@ def status(
1021
1161
  f"[/dim]\n\n"
1022
1162
  )
1023
1163
 
1164
+ if status_json["config"].get("idle_timeout") or status_json["config"].get("max_lifetime"):
1165
+ panel_content += "[bold]Lifecycle Settings:[/bold]\n"
1166
+
1167
+ idle = status_json["config"].get("idle_timeout")
1168
+ if idle:
1169
+ panel_content += f"Idle Timeout: [cyan]{idle}s ({idle // 60} minutes)[/cyan]\n"
1170
+
1171
+ max_life = status_json["config"].get("max_lifetime")
1172
+ if max_life:
1173
+ panel_content += f"Max Lifetime: [cyan]{max_life}s ({max_life // 3600} hours)[/cyan]\n"
1174
+
1175
+ panel_content += "\n"
1176
+
1024
1177
  # Add CloudWatch logs information
1025
1178
  agent_id = status_json.get("config", {}).get("agent_id")
1026
1179
  if agent_id:
@@ -1115,6 +1268,109 @@ def status(
1115
1268
  raise typer.Exit(1) from e
1116
1269
 
1117
1270
 
1271
+ def stop_session(
1272
+ session_id: Optional[str] = typer.Option(
1273
+ None,
1274
+ "--session-id",
1275
+ "-s",
1276
+ help="Runtime session ID to stop. If not provided, stops the last active session from invoke.",
1277
+ ),
1278
+ agent: Optional[str] = typer.Option(
1279
+ None,
1280
+ "--agent",
1281
+ "-a",
1282
+ help="Agent name (use 'agentcore configure list' to see available agents)",
1283
+ ),
1284
+ ):
1285
+ """Stop an active runtime session.
1286
+
1287
+ Terminates the compute session for the running agent. This frees up resources
1288
+ and ends any ongoing agent processing for that session.
1289
+
1290
+ 🔍 How to find session IDs:
1291
+ • Last invoked session is automatically tracked (no flag needed)
1292
+ • Check 'agentcore status' to see the tracked session ID
1293
+ • Check CloudWatch logs for session IDs from previous invokes
1294
+ • Session IDs are also visible in the config file: .bedrock_agentcore.yaml
1295
+
1296
+ ⏱️ Session Lifecycle:
1297
+ • Runtime sessions are created when you invoke an agent
1298
+ • They automatically expire after the configured idle timeout
1299
+ • Stopping a session immediately frees resources without waiting for timeout
1300
+
1301
+ Examples:
1302
+ # Stop the last invoked session (most common)
1303
+ agentcore stop-session
1304
+
1305
+ # Stop a specific session by ID
1306
+ agentcore stop-session --session-id abc123xyz
1307
+
1308
+ # Stop last session for a specific agent
1309
+ agentcore stop-session --agent my-agent
1310
+
1311
+ # Get current session ID before stopping
1312
+ agentcore status # Shows tracked session ID
1313
+ agentcore stop-session
1314
+ """
1315
+ config_path = Path.cwd() / ".bedrock_agentcore.yaml"
1316
+
1317
+ try:
1318
+ from ...operations.runtime import stop_runtime_session
1319
+
1320
+ result = stop_runtime_session(
1321
+ config_path=config_path,
1322
+ session_id=session_id,
1323
+ agent_name=agent,
1324
+ )
1325
+
1326
+ # Show result panel
1327
+ status_icon = "✅" if result.status_code == 200 else "⚠️"
1328
+ status_color = "green" if result.status_code == 200 else "yellow"
1329
+
1330
+ console.print(
1331
+ Panel(
1332
+ f"[{status_color}]{status_icon} {result.message}[/{status_color}]\n\n"
1333
+ f"[bold]Session Details:[/bold]\n"
1334
+ f"Session ID: [cyan]{result.session_id}[/cyan]\n"
1335
+ f"Agent: [cyan]{result.agent_name}[/cyan]\n"
1336
+ f"Status Code: [cyan]{result.status_code}[/cyan]\n\n"
1337
+ f"[dim]💡 Runtime sessions automatically expire after idle timeout.\n"
1338
+ f" Manually stopping frees resources immediately.[/dim]",
1339
+ title="Session Stopped",
1340
+ border_style="bright_blue",
1341
+ )
1342
+ )
1343
+
1344
+ except FileNotFoundError:
1345
+ _show_configuration_not_found_panel()
1346
+ raise typer.Exit(1) from None
1347
+ except ValueError as e:
1348
+ console.print(
1349
+ Panel(
1350
+ f"[red]❌ Failed to Stop Session[/red]\n\n"
1351
+ f"Error: {str(e)}\n\n"
1352
+ f"[bold]How to find session IDs:[/bold]\n"
1353
+ f" • Check 'agentcore status' for the tracked session ID\n"
1354
+ f" • Check CloudWatch logs for session IDs\n"
1355
+ f" • Invoke the agent first to create a session\n\n"
1356
+ f"[dim]Note: Runtime sessions cannot be listed. You can only stop\n"
1357
+ f"the session from your last invoke or a specific session ID.[/dim]",
1358
+ title="Stop Session Error",
1359
+ border_style="red",
1360
+ )
1361
+ )
1362
+ raise typer.Exit(1) from e
1363
+ except Exception as e:
1364
+ console.print(
1365
+ Panel(
1366
+ f"[red]❌ Unexpected Error[/red]\n\n{str(e)}",
1367
+ title="Stop Session Error",
1368
+ border_style="red",
1369
+ )
1370
+ )
1371
+ raise typer.Exit(1) from e
1372
+
1373
+
1118
1374
  def destroy(
1119
1375
  agent: Optional[str] = typer.Option(
1120
1376
  None, "--agent", "-a", help="Agent name (use 'agentcore configure list' to see available agents)"
@@ -267,8 +267,8 @@ class ConfigurationManager:
267
267
 
268
268
  Returns:
269
269
  Tuple of (action, value) where:
270
- - action is "USE_EXISTING", "CREATE_NEW"
271
- - value is memory_id for USE_EXISTING, mode for CREATE_NEW
270
+ - action is "USE_EXISTING", "CREATE_NEW", "SKIP"
271
+ - value is memory_id for USE_EXISTING, mode for CREATE_NEW, None for SKIP
272
272
  """
273
273
  if self.non_interactive:
274
274
  # In non-interactive mode, default to creating new STM
@@ -285,8 +285,19 @@ class ConfigurationManager:
285
285
  region = self.region or (self.existing_config.aws.region if self.existing_config else None)
286
286
 
287
287
  if not region:
288
- # No region available - skip to new memory creation
289
- console.print("[dim]No region configured yet, proceeding with new memory creation[/dim]")
288
+ # No region available - offer skip option
289
+ console.print("[dim]No region configured yet[/dim]")
290
+ console.print("\n[dim]Options:[/dim]")
291
+ console.print("[dim] • Press Enter to create new memory[/dim]")
292
+ console.print("[dim] • Type 's' to skip memory setup[/dim]") # <-- ADD
293
+ console.print()
294
+
295
+ response = _prompt_with_default("Your choice", "").strip().lower()
296
+
297
+ if response == "s" or response == "skip": # <-- ADD
298
+ _print_success("Skipping memory configuration")
299
+ return ("SKIP", None)
300
+
290
301
  return self._prompt_new_memory_config()
291
302
 
292
303
  memory_manager = MemoryManager(region_name=region)
@@ -311,10 +322,14 @@ class ConfigurationManager:
311
322
  console.print("\n[dim]Options:[/dim]")
312
323
  console.print("[dim] • Enter a number to use existing memory[/dim]")
313
324
  console.print("[dim] • Press Enter to create new memory[/dim]")
325
+ console.print("[dim] • Type 's' to skip memory setup[/dim]")
314
326
 
315
327
  response = _prompt_with_default("Your choice", "").strip().lower()
316
328
 
317
- if response.isdigit():
329
+ if response == "s" or response == "skip":
330
+ _print_success("Skipping memory configuration")
331
+ return ("SKIP", None)
332
+ elif response.isdigit():
318
333
  idx = int(response) - 1
319
334
  if 0 <= idx < len(existing_memories):
320
335
  selected = existing_memories[idx]
@@ -323,7 +338,16 @@ class ConfigurationManager:
323
338
  else:
324
339
  # No existing memories found
325
340
  console.print("[yellow]No existing memory resources found in your account[/yellow]")
326
- console.print("[dim]Proceeding with new memory creation...[/dim]\n")
341
+ console.print("\n[dim]Options:[/dim]")
342
+ console.print("[dim] • Press Enter to create new memory[/dim]")
343
+ console.print("[dim] • Type 's' to skip memory setup[/dim]")
344
+ console.print()
345
+
346
+ response = _prompt_with_default("Your choice", "").strip().lower()
347
+
348
+ if response == "s" or response == "skip":
349
+ _print_success("Skipping memory configuration")
350
+ return ("SKIP", None)
327
351
 
328
352
  except Exception as e:
329
353
  console.print(f"[dim]Could not list existing memories: {e}[/dim]")
@@ -332,7 +356,7 @@ class ConfigurationManager:
332
356
  return self._prompt_new_memory_config()
333
357
 
334
358
  def _prompt_new_memory_config(self) -> Tuple[str, str]:
335
- """Prompt for new memory configuration (no skip option)."""
359
+ """Prompt for new memory configuration - LTM yes/no only."""
336
360
  console.print("[green]✓ Short-term memory will be enabled (default)[/green]")
337
361
  console.print(" • Stores conversations within sessions")
338
362
  console.print(" • Provides immediate context recall")