bedrock-agentcore-starter-toolkit 0.1.26__py3-none-any.whl → 0.1.28__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 (23) hide show
  1. bedrock_agentcore_starter_toolkit/cli/cli.py +9 -1
  2. bedrock_agentcore_starter_toolkit/cli/runtime/commands.py +263 -12
  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/memory/manager.py +20 -33
  6. bedrock_agentcore_starter_toolkit/operations/memory/models/strategies/base.py +2 -0
  7. bedrock_agentcore_starter_toolkit/operations/memory/models/strategies/self_managed.py +107 -0
  8. bedrock_agentcore_starter_toolkit/operations/runtime/__init__.py +4 -0
  9. bedrock_agentcore_starter_toolkit/operations/runtime/configure.py +130 -11
  10. bedrock_agentcore_starter_toolkit/operations/runtime/invoke.py +0 -53
  11. bedrock_agentcore_starter_toolkit/operations/runtime/launch.py +213 -16
  12. bedrock_agentcore_starter_toolkit/operations/runtime/models.py +19 -0
  13. bedrock_agentcore_starter_toolkit/operations/runtime/status.py +30 -0
  14. bedrock_agentcore_starter_toolkit/operations/runtime/stop_session.py +123 -0
  15. bedrock_agentcore_starter_toolkit/operations/runtime/vpc_validation.py +196 -0
  16. bedrock_agentcore_starter_toolkit/services/runtime.py +43 -1
  17. bedrock_agentcore_starter_toolkit/utils/runtime/schema.py +44 -1
  18. {bedrock_agentcore_starter_toolkit-0.1.26.dist-info → bedrock_agentcore_starter_toolkit-0.1.28.dist-info}/METADATA +8 -8
  19. {bedrock_agentcore_starter_toolkit-0.1.26.dist-info → bedrock_agentcore_starter_toolkit-0.1.28.dist-info}/RECORD +23 -20
  20. {bedrock_agentcore_starter_toolkit-0.1.26.dist-info → bedrock_agentcore_starter_toolkit-0.1.28.dist-info}/WHEEL +0 -0
  21. {bedrock_agentcore_starter_toolkit-0.1.26.dist-info → bedrock_agentcore_starter_toolkit-0.1.28.dist-info}/entry_points.txt +0 -0
  22. {bedrock_agentcore_starter_toolkit-0.1.26.dist-info → bedrock_agentcore_starter_toolkit-0.1.28.dist-info}/licenses/LICENSE.txt +0 -0
  23. {bedrock_agentcore_starter_toolkit-0.1.26.dist-info → bedrock_agentcore_starter_toolkit-0.1.28.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
@@ -162,20 +162,28 @@ def _detect_entrypoint_in_source(source_path: str, non_interactive: bool = False
162
162
  # Use operations layer for detection
163
163
  detected = detect_entrypoint(source_dir)
164
164
 
165
- if not detected:
166
- # No fallback prompt - fail with clear error message
165
+ if len(detected) == 0:
166
+ # No files found - error
167
167
  rel_source = get_relative_path(source_dir)
168
168
  _handle_error(
169
169
  f"No entrypoint file found in {rel_source}\n"
170
170
  f"Expected one of: main.py, agent.py, app.py, __main__.py\n"
171
171
  f"Please specify full file path (e.g., {rel_source}/your_agent.py)"
172
172
  )
173
+ elif len(detected) > 1:
174
+ # Multiple files found - error with list
175
+ rel_source = get_relative_path(source_dir)
176
+ files_list = ", ".join(f.name for f in detected)
177
+ _handle_error(
178
+ f"Multiple entrypoint files found in {rel_source}: {files_list}\n"
179
+ f"Please specify full file path (e.g., {rel_source}/main.py)"
180
+ )
173
181
 
174
- # Show detection and confirm
175
- rel_entrypoint = get_relative_path(detected)
182
+ # Exactly one file - show detection and confirm
183
+ rel_entrypoint = get_relative_path(detected[0])
176
184
 
177
185
  _print_success(f"Using entrypoint file: [cyan]{rel_entrypoint}[/cyan]")
178
- return str(detected)
186
+ return str(detected[0])
179
187
 
180
188
 
181
189
  # Define options at module level to avoid B008
@@ -257,6 +265,33 @@ def configure(
257
265
  help="Comma-separated list of allowed request headers "
258
266
  "(Authorization or X-Amzn-Bedrock-AgentCore-Runtime-Custom-*)",
259
267
  ),
268
+ vpc: bool = typer.Option(
269
+ False, "--vpc", help="Enable VPC networking mode (requires --subnets and --security-groups)"
270
+ ),
271
+ subnets: Optional[str] = typer.Option(
272
+ None,
273
+ "--subnets",
274
+ help="Comma-separated list of subnet IDs (e.g., subnet-abc123,subnet-def456). Required with --vpc.",
275
+ ),
276
+ security_groups: Optional[str] = typer.Option(
277
+ None,
278
+ "--security-groups",
279
+ help="Comma-separated list of security group IDs (e.g., sg-xyz789). Required with --vpc.",
280
+ ),
281
+ idle_timeout: Optional[int] = typer.Option(
282
+ None,
283
+ "--idle-timeout",
284
+ help="Idle runtime session timeout in seconds (60-28800, default: 900)",
285
+ min=60,
286
+ max=28800,
287
+ ),
288
+ max_lifetime: Optional[int] = typer.Option(
289
+ None,
290
+ "--max-lifetime",
291
+ help="Maximum instance lifetime in seconds (60-28800, default: 28800)",
292
+ min=60,
293
+ max=28800,
294
+ ),
260
295
  verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose output"),
261
296
  region: Optional[str] = typer.Option(None, "--region", "-r"),
262
297
  protocol: Optional[str] = typer.Option(None, "--protocol", "-p", help="Server protocol (HTTP or MCP or A2A)"),
@@ -277,6 +312,64 @@ def configure(
277
312
  if protocol and protocol.upper() not in ["HTTP", "MCP", "A2A"]:
278
313
  _handle_error("Error: --protocol must be either HTTP or MCP or A2A")
279
314
 
315
+ # Validate VPC configuration
316
+ vpc_subnets = None
317
+ vpc_security_groups = None
318
+
319
+ if vpc:
320
+ # VPC mode requires both subnets and security groups
321
+ if not subnets or not security_groups:
322
+ _handle_error(
323
+ "VPC mode requires both --subnets and --security-groups.\n"
324
+ "Example: agentcore configure --entrypoint my_agent.py --vpc "
325
+ "--subnets subnet-abc123,subnet-def456 --security-groups sg-xyz789"
326
+ )
327
+
328
+ # Parse and validate subnet IDs - UPDATED VALIDATION
329
+ vpc_subnets = [s.strip() for s in subnets.split(",") if s.strip()]
330
+ for subnet_id in vpc_subnets:
331
+ # Format: subnet-{8-17 hex characters}
332
+ if not subnet_id.startswith("subnet-"):
333
+ _handle_error(
334
+ f"Invalid subnet ID format: {subnet_id}\nSubnet IDs must start with 'subnet-' (e.g., subnet-abc123)"
335
+ )
336
+ # Check minimum length (subnet- + at least 8 chars)
337
+ if len(subnet_id) < 15: # "subnet-" (7) + 8 chars = 15
338
+ _handle_error(
339
+ f"Invalid subnet ID format: {subnet_id}\nSubnet ID is too short. Expected format: subnet-xxxxxxxx"
340
+ )
341
+
342
+ # Parse and validate security group IDs - UPDATED VALIDATION
343
+ vpc_security_groups = [sg.strip() for sg in security_groups.split(",") if sg.strip()]
344
+ for sg_id in vpc_security_groups:
345
+ # Format: sg-{8-17 hex characters}
346
+ if not sg_id.startswith("sg-"):
347
+ _handle_error(
348
+ f"Invalid security group ID format: {sg_id}\n"
349
+ f"Security group IDs must start with 'sg-' (e.g., sg-abc123)"
350
+ )
351
+ # Check minimum length (sg- + at least 8 chars)
352
+ if len(sg_id) < 11: # "sg-" (3) + 8 chars = 11
353
+ _handle_error(
354
+ f"Invalid security group ID format: {sg_id}\n"
355
+ f"Security group ID is too short. Expected format: sg-xxxxxxxx"
356
+ )
357
+
358
+ _print_success(
359
+ f"VPC mode enabled with {len(vpc_subnets)} subnets and {len(vpc_security_groups)} security groups"
360
+ )
361
+
362
+ elif subnets or security_groups:
363
+ # Error: VPC resources provided without --vpc flag
364
+ _handle_error(
365
+ "The --subnets and --security-groups flags require --vpc flag.\n"
366
+ "Use: agentcore configure --entrypoint my_agent.py --vpc --subnets ... --security-groups ..."
367
+ )
368
+ # Validate lifecycle configuration
369
+ if idle_timeout is not None and max_lifetime is not None:
370
+ if idle_timeout > max_lifetime:
371
+ _handle_error(f"Error: --idle-timeout ({idle_timeout}s) must be <= --max-lifetime ({max_lifetime}s)")
372
+
280
373
  console.print("[cyan]Configuring Bedrock AgentCore...[/cyan]")
281
374
 
282
375
  # Create configuration manager early for consistent prompting
@@ -399,6 +492,11 @@ def configure(
399
492
  protocol=protocol.upper() if protocol else None,
400
493
  non_interactive=non_interactive,
401
494
  source_path=source_path,
495
+ vpc_enabled=vpc,
496
+ vpc_subnets=vpc_subnets,
497
+ vpc_security_groups=vpc_security_groups,
498
+ idle_timeout=idle_timeout,
499
+ max_lifetime=max_lifetime,
402
500
  )
403
501
 
404
502
  # Prepare authorization info for summary
@@ -412,10 +510,29 @@ def configure(
412
510
  headers = request_header_config.get("requestHeaderAllowlist", [])
413
511
  headers_info = f"Request Headers Allowlist: [dim]{len(headers)} headers configured[/dim]\n"
414
512
 
513
+ network_info = "Public"
514
+ if vpc:
515
+ network_info = f"VPC ({len(vpc_subnets)} subnets, {len(vpc_security_groups)} security groups)"
516
+
415
517
  execution_role_display = "Auto-create" if not result.execution_role else result.execution_role
416
- memory_info = "Short-term memory (30-day retention)"
417
- if disable_memory:
518
+ saved_config = load_config(result.config_path)
519
+ saved_agent = saved_config.get_agent_config(agent_name)
520
+
521
+ # Display memory status based on actual configuration
522
+ if saved_agent.memory.mode == "NO_MEMORY":
418
523
  memory_info = "Disabled"
524
+ elif saved_agent.memory.mode == "STM_AND_LTM":
525
+ memory_info = "Short-term + Long-term memory (30-day retention)"
526
+ else: # STM_ONLY
527
+ memory_info = "Short-term memory (30-day retention)"
528
+
529
+ lifecycle_info = ""
530
+ if idle_timeout or max_lifetime:
531
+ lifecycle_info = "\n[bold]Lifecycle Settings:[/bold]\n"
532
+ if idle_timeout:
533
+ lifecycle_info += f"Idle Timeout: [cyan]{idle_timeout}s ({idle_timeout // 60} minutes)[/cyan]\n"
534
+ if max_lifetime:
535
+ lifecycle_info += f"Max Lifetime: [cyan]{max_lifetime}s ({max_lifetime // 3600} hours)[/cyan]\n"
419
536
 
420
537
  console.print(
421
538
  Panel(
@@ -429,9 +546,11 @@ def configure(
429
546
  f"ECR Repository: [cyan]"
430
547
  f"{'Auto-create' if result.auto_create_ecr else result.ecr_repository or 'N/A'}"
431
548
  f"[/cyan]\n"
549
+ f"Network Mode: [cyan]{network_info}[/cyan]\n"
432
550
  f"Authorization: [cyan]{auth_info}[/cyan]\n\n"
433
551
  f"{headers_info}\n"
434
552
  f"Memory: [cyan]{memory_info}[/cyan]\n\n"
553
+ f"{lifecycle_info}\n"
435
554
  f"📄 Config saved to: [dim]{result.config_path}[/dim]\n\n"
436
555
  f"[bold]Next Steps:[/bold]\n"
437
556
  f" [cyan]agentcore launch[/cyan]",
@@ -568,6 +687,7 @@ def launch(
568
687
  use_codebuild=not local_build,
569
688
  env_vars=env_vars,
570
689
  auto_update_on_conflict=auto_update_on_conflict,
690
+ console=console,
571
691
  )
572
692
 
573
693
  project_config = load_config(config_path)
@@ -983,11 +1103,6 @@ def status(
983
1103
 
984
1104
  # Determine overall status
985
1105
  endpoint_status = endpoint_data.get("status", "Unknown") if endpoint_data else "Not Ready"
986
- # memory_info = ""
987
- # if hasattr(status_json["config"], "memory_id") and status_json["config"].get("memory_id"):
988
- # memory_type = status_json["config"].get("memory_type", "Short-term")
989
- # memory_id = status_json["config"].get("memory_id")
990
- # memory_info = f"Memory: [cyan]{memory_type}[/cyan] ([dim]{memory_id}[/dim])\n"
991
1106
  if endpoint_status == "READY":
992
1107
  status_text = "Ready - Agent deployed and endpoint available"
993
1108
  else:
@@ -1005,6 +1120,26 @@ def status(
1005
1120
  f"Account: [dim]{status_json['config'].get('account', 'Not available')}[/dim]\n\n"
1006
1121
  )
1007
1122
 
1123
+ # Add network information
1124
+ network_mode = status_json.get("agent", {}).get("networkConfiguration", {}).get("networkMode")
1125
+ if network_mode == "VPC":
1126
+ # Get VPC info from agent response (not config)
1127
+ network_config = (
1128
+ status_json.get("agent", {}).get("networkConfiguration", {}).get("networkModeConfig", {})
1129
+ )
1130
+ vpc_subnets = network_config.get("subnets", [])
1131
+ vpc_security_groups = network_config.get("securityGroups", [])
1132
+ subnet_count = len(vpc_subnets)
1133
+ sg_count = len(vpc_security_groups)
1134
+ vpc_id = status_json.get("config", {}).get("network_vpc_id", "unknown")
1135
+ if vpc_id:
1136
+ panel_content += f"Network: [cyan]VPC[/cyan] ([dim]{vpc_id}[/dim])\n"
1137
+ panel_content += f" {subnet_count} subnets, {sg_count} security groups\n\n"
1138
+ else:
1139
+ panel_content += "Network: [cyan]VPC[/cyan]\n\n"
1140
+ else:
1141
+ panel_content += "Network: [cyan]Public[/cyan]\n\n"
1142
+
1008
1143
  # Add memory status with proper provisioning indication
1009
1144
  if "memory_id" in status_json.get("config", {}) and status_json["config"]["memory_id"]:
1010
1145
  memory_type = status_json["config"].get("memory_type", "Unknown")
@@ -1034,6 +1169,19 @@ def status(
1034
1169
  f"[/dim]\n\n"
1035
1170
  )
1036
1171
 
1172
+ if status_json["config"].get("idle_timeout") or status_json["config"].get("max_lifetime"):
1173
+ panel_content += "[bold]Lifecycle Settings:[/bold]\n"
1174
+
1175
+ idle = status_json["config"].get("idle_timeout")
1176
+ if idle:
1177
+ panel_content += f"Idle Timeout: [cyan]{idle}s ({idle // 60} minutes)[/cyan]\n"
1178
+
1179
+ max_life = status_json["config"].get("max_lifetime")
1180
+ if max_life:
1181
+ panel_content += f"Max Lifetime: [cyan]{max_life}s ({max_life // 3600} hours)[/cyan]\n"
1182
+
1183
+ panel_content += "\n"
1184
+
1037
1185
  # Add CloudWatch logs information
1038
1186
  agent_id = status_json.get("config", {}).get("agent_id")
1039
1187
  if agent_id:
@@ -1128,6 +1276,109 @@ def status(
1128
1276
  raise typer.Exit(1) from e
1129
1277
 
1130
1278
 
1279
+ def stop_session(
1280
+ session_id: Optional[str] = typer.Option(
1281
+ None,
1282
+ "--session-id",
1283
+ "-s",
1284
+ help="Runtime session ID to stop. If not provided, stops the last active session from invoke.",
1285
+ ),
1286
+ agent: Optional[str] = typer.Option(
1287
+ None,
1288
+ "--agent",
1289
+ "-a",
1290
+ help="Agent name (use 'agentcore configure list' to see available agents)",
1291
+ ),
1292
+ ):
1293
+ """Stop an active runtime session.
1294
+
1295
+ Terminates the compute session for the running agent. This frees up resources
1296
+ and ends any ongoing agent processing for that session.
1297
+
1298
+ 🔍 How to find session IDs:
1299
+ • Last invoked session is automatically tracked (no flag needed)
1300
+ • Check 'agentcore status' to see the tracked session ID
1301
+ • Check CloudWatch logs for session IDs from previous invokes
1302
+ • Session IDs are also visible in the config file: .bedrock_agentcore.yaml
1303
+
1304
+ ⏱️ Session Lifecycle:
1305
+ • Runtime sessions are created when you invoke an agent
1306
+ • They automatically expire after the configured idle timeout
1307
+ • Stopping a session immediately frees resources without waiting for timeout
1308
+
1309
+ Examples:
1310
+ # Stop the last invoked session (most common)
1311
+ agentcore stop-session
1312
+
1313
+ # Stop a specific session by ID
1314
+ agentcore stop-session --session-id abc123xyz
1315
+
1316
+ # Stop last session for a specific agent
1317
+ agentcore stop-session --agent my-agent
1318
+
1319
+ # Get current session ID before stopping
1320
+ agentcore status # Shows tracked session ID
1321
+ agentcore stop-session
1322
+ """
1323
+ config_path = Path.cwd() / ".bedrock_agentcore.yaml"
1324
+
1325
+ try:
1326
+ from ...operations.runtime import stop_runtime_session
1327
+
1328
+ result = stop_runtime_session(
1329
+ config_path=config_path,
1330
+ session_id=session_id,
1331
+ agent_name=agent,
1332
+ )
1333
+
1334
+ # Show result panel
1335
+ status_icon = "✅" if result.status_code == 200 else "⚠️"
1336
+ status_color = "green" if result.status_code == 200 else "yellow"
1337
+
1338
+ console.print(
1339
+ Panel(
1340
+ f"[{status_color}]{status_icon} {result.message}[/{status_color}]\n\n"
1341
+ f"[bold]Session Details:[/bold]\n"
1342
+ f"Session ID: [cyan]{result.session_id}[/cyan]\n"
1343
+ f"Agent: [cyan]{result.agent_name}[/cyan]\n"
1344
+ f"Status Code: [cyan]{result.status_code}[/cyan]\n\n"
1345
+ f"[dim]💡 Runtime sessions automatically expire after idle timeout.\n"
1346
+ f" Manually stopping frees resources immediately.[/dim]",
1347
+ title="Session Stopped",
1348
+ border_style="bright_blue",
1349
+ )
1350
+ )
1351
+
1352
+ except FileNotFoundError:
1353
+ _show_configuration_not_found_panel()
1354
+ raise typer.Exit(1) from None
1355
+ except ValueError as e:
1356
+ console.print(
1357
+ Panel(
1358
+ f"[red]❌ Failed to Stop Session[/red]\n\n"
1359
+ f"Error: {str(e)}\n\n"
1360
+ f"[bold]How to find session IDs:[/bold]\n"
1361
+ f" • Check 'agentcore status' for the tracked session ID\n"
1362
+ f" • Check CloudWatch logs for session IDs\n"
1363
+ f" • Invoke the agent first to create a session\n\n"
1364
+ f"[dim]Note: Runtime sessions cannot be listed. You can only stop\n"
1365
+ f"the session from your last invoke or a specific session ID.[/dim]",
1366
+ title="Stop Session Error",
1367
+ border_style="red",
1368
+ )
1369
+ )
1370
+ raise typer.Exit(1) from e
1371
+ except Exception as e:
1372
+ console.print(
1373
+ Panel(
1374
+ f"[red]❌ Unexpected Error[/red]\n\n{str(e)}",
1375
+ title="Stop Session Error",
1376
+ border_style="red",
1377
+ )
1378
+ )
1379
+ raise typer.Exit(1) from e
1380
+
1381
+
1131
1382
  def destroy(
1132
1383
  agent: Optional[str] = typer.Option(
1133
1384
  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")