claude-mpm 3.2.1__py3-none-any.whl → 3.3.2__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.
Files changed (35) hide show
  1. claude_mpm/agents/INSTRUCTIONS.md +71 -2
  2. claude_mpm/agents/templates/data_engineer.json +1 -1
  3. claude_mpm/agents/templates/documentation.json +1 -1
  4. claude_mpm/agents/templates/engineer.json +1 -1
  5. claude_mpm/agents/templates/ops.json +1 -1
  6. claude_mpm/agents/templates/pm.json +1 -1
  7. claude_mpm/agents/templates/qa.json +1 -1
  8. claude_mpm/agents/templates/research.json +1 -1
  9. claude_mpm/agents/templates/security.json +1 -1
  10. claude_mpm/agents/templates/test_integration.json +112 -0
  11. claude_mpm/agents/templates/version_control.json +1 -1
  12. claude_mpm/cli/commands/memory.py +575 -25
  13. claude_mpm/cli/commands/run.py +115 -14
  14. claude_mpm/cli/parser.py +76 -0
  15. claude_mpm/constants.py +5 -0
  16. claude_mpm/core/claude_runner.py +13 -11
  17. claude_mpm/core/session_manager.py +46 -0
  18. claude_mpm/core/simple_runner.py +13 -11
  19. claude_mpm/hooks/claude_hooks/hook_handler.py +2 -26
  20. claude_mpm/scripts/launch_socketio_dashboard.py +261 -0
  21. claude_mpm/services/agent_memory_manager.py +264 -23
  22. claude_mpm/services/memory_builder.py +491 -0
  23. claude_mpm/services/memory_optimizer.py +619 -0
  24. claude_mpm/services/memory_router.py +445 -0
  25. claude_mpm/services/socketio_server.py +389 -1
  26. claude_mpm-3.3.2.dist-info/METADATA +159 -0
  27. {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/RECORD +31 -29
  28. claude_mpm/agents/templates/test-integration-agent.md +0 -34
  29. claude_mpm/core/websocket_handler.py +0 -233
  30. claude_mpm/services/websocket_server.py +0 -376
  31. claude_mpm-3.2.1.dist-info/METADATA +0 -432
  32. {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/WHEEL +0 -0
  33. {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/entry_points.txt +0 -0
  34. {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/licenses/LICENSE +0 -0
  35. {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/top_level.txt +0 -0
@@ -57,6 +57,21 @@ def manage_memory(args):
57
57
  elif args.memory_command == "clean":
58
58
  _clean_memory(args, memory_manager)
59
59
 
60
+ elif args.memory_command == "optimize":
61
+ _optimize_memory(args, memory_manager)
62
+
63
+ elif args.memory_command == "build":
64
+ _build_memory(args, memory_manager)
65
+
66
+ elif args.memory_command == "cross-ref":
67
+ _cross_reference_memory(args, memory_manager)
68
+
69
+ elif args.memory_command == "route":
70
+ _route_memory_command(args, memory_manager)
71
+
72
+ elif args.memory_command == "show":
73
+ _show_memories(args, memory_manager)
74
+
60
75
  except Exception as e:
61
76
  logger.error(f"Error managing memory: {e}")
62
77
  print(f"❌ Error: {e}")
@@ -67,17 +82,103 @@ def manage_memory(args):
67
82
 
68
83
  def _show_status(memory_manager):
69
84
  """
70
- Show memory file status.
85
+ Show comprehensive memory system status.
71
86
 
72
- WHY: Users need to see what memory files exist, their sizes, and
73
- when they were last updated to understand the memory system state.
87
+ WHY: Users need to see memory system health, file sizes, optimization
88
+ opportunities, and agent-specific statistics to understand the system state.
74
89
 
75
90
  Args:
76
91
  memory_manager: AgentMemoryManager instance
77
92
  """
78
- print("Agent Memory Status")
93
+ print("Agent Memory System Status")
79
94
  print("-" * 80)
80
95
 
96
+ try:
97
+ # Get comprehensive status from memory manager
98
+ status = memory_manager.get_memory_status()
99
+
100
+ if not status.get("success", True):
101
+ print(f"❌ Error getting status: {status.get('error', 'Unknown error')}")
102
+ return
103
+
104
+ # Show system overview
105
+ system_health = status.get("system_health", "unknown")
106
+ health_emoji = {
107
+ "healthy": "✅",
108
+ "needs_optimization": "⚠️",
109
+ "high_usage": "📊",
110
+ "no_memory_dir": "📁"
111
+ }.get(system_health, "❓")
112
+
113
+ print(f"🧠 Memory System Health: {health_emoji} {system_health}")
114
+ print(f"📁 Memory Directory: {status.get('memory_directory', 'Unknown')}")
115
+ print(f"🔧 System Enabled: {'Yes' if status.get('system_enabled', True) else 'No'}")
116
+ print(f"📚 Auto Learning: {'Yes' if status.get('auto_learning', False) else 'No'}")
117
+ print(f"📊 Total Agents: {status.get('total_agents', 0)}")
118
+ print(f"💾 Total Size: {status.get('total_size_kb', 0):.1f} KB")
119
+ print()
120
+
121
+ # Show optimization opportunities
122
+ opportunities = status.get("optimization_opportunities", [])
123
+ if opportunities:
124
+ print(f"⚠️ Optimization Opportunities ({len(opportunities)}):")
125
+ for opportunity in opportunities[:5]: # Show top 5
126
+ print(f" • {opportunity}")
127
+ if len(opportunities) > 5:
128
+ print(f" ... and {len(opportunities) - 5} more")
129
+ print()
130
+
131
+ # Show per-agent details
132
+ agents = status.get("agents", {})
133
+ if agents:
134
+ print(f"📋 Agent Memory Details:")
135
+ for agent_id, agent_info in sorted(agents.items()):
136
+ if "error" in agent_info:
137
+ print(f" ❌ {agent_id}: Error - {agent_info['error']}")
138
+ continue
139
+
140
+ size_kb = agent_info.get("size_kb", 0)
141
+ size_limit = agent_info.get("size_limit_kb", 8)
142
+ utilization = agent_info.get("size_utilization", 0)
143
+ sections = agent_info.get("sections", 0)
144
+ items = agent_info.get("items", 0)
145
+ last_modified = agent_info.get("last_modified", "Unknown")
146
+ auto_learning = agent_info.get("auto_learning", False)
147
+
148
+ # Format last modified time
149
+ try:
150
+ from datetime import datetime
151
+ dt = datetime.fromisoformat(last_modified.replace('Z', '+00:00'))
152
+ last_modified_str = dt.strftime('%Y-%m-%d %H:%M:%S')
153
+ except:
154
+ last_modified_str = last_modified
155
+
156
+ # Status indicator based on usage
157
+ if utilization > 90:
158
+ status_emoji = "🔴" # High usage
159
+ elif utilization > 70:
160
+ status_emoji = "🟡" # Medium usage
161
+ else:
162
+ status_emoji = "🟢" # Low usage
163
+
164
+ print(f" {status_emoji} {agent_id}")
165
+ print(f" Size: {size_kb:.1f} KB / {size_limit} KB ({utilization:.1f}%)")
166
+ print(f" Content: {sections} sections, {items} items")
167
+ print(f" Auto-learning: {'On' if auto_learning else 'Off'}")
168
+ print(f" Last modified: {last_modified_str}")
169
+ else:
170
+ print("📭 No agent memories found")
171
+
172
+ except Exception as e:
173
+ print(f"❌ Error showing status: {e}")
174
+ # Fallback to basic status display
175
+ _show_basic_status(memory_manager)
176
+
177
+
178
+ def _show_basic_status(memory_manager):
179
+ """Fallback basic status display if comprehensive status fails."""
180
+ print("\n--- Basic Status (Fallback) ---")
181
+
81
182
  memory_dir = memory_manager.memories_dir
82
183
  if not memory_dir.exists():
83
184
  print("📁 Memory directory not found - no agent memories stored yet")
@@ -93,7 +194,6 @@ def _show_status(memory_manager):
93
194
 
94
195
  print(f"📁 Memory directory: {memory_dir}")
95
196
  print(f"📊 Total memory files: {len(memory_files)}")
96
- print()
97
197
 
98
198
  total_size = 0
99
199
  for file_path in sorted(memory_files):
@@ -101,26 +201,8 @@ def _show_status(memory_manager):
101
201
  size_kb = stat.st_size / 1024
102
202
  total_size += stat.st_size
103
203
 
104
- # Extract agent ID from filename (remove '_agent' suffix)
105
204
  agent_id = file_path.stem.replace('_agent', '')
106
-
107
- # Try to count sections in markdown file
108
- try:
109
- content = file_path.read_text()
110
- # Count level 2 headers (sections)
111
- section_count = len([line for line in content.splitlines() if line.startswith('## ')])
112
- # Count bullet points (learnings)
113
- learning_count = len([line for line in content.splitlines() if line.strip().startswith('- ')])
114
- except:
115
- section_count = "?"
116
- learning_count = "?"
117
-
118
- print(f"🧠 {agent_id}")
119
- print(f" Size: {size_kb:.1f} KB")
120
- print(f" Sections: {section_count}")
121
- print(f" Items: {learning_count}")
122
- print(f" Last modified: {datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S')}")
123
- print()
205
+ print(f" {agent_id}: {size_kb:.1f} KB")
124
206
 
125
207
  print(f"💾 Total size: {total_size / 1024:.1f} KB")
126
208
 
@@ -229,4 +311,472 @@ def _clean_memory(args, memory_manager):
229
311
  print(" Future cleanup will remove:")
230
312
  print(" - Memory files older than 30 days with no recent access")
231
313
  print(" - Corrupted memory files")
232
- print(" - Memory files for non-existent agents")
314
+ print(" - Memory files for non-existent agents")
315
+
316
+
317
+ def _optimize_memory(args, memory_manager):
318
+ """
319
+ Optimize memory files by removing duplicates and consolidating similar items.
320
+
321
+ WHY: Memory files can become cluttered over time with duplicate or redundant
322
+ information. This command provides automated cleanup while preserving
323
+ important learnings.
324
+
325
+ Args:
326
+ args: Command arguments with optional agent_id
327
+ memory_manager: AgentMemoryManager instance
328
+ """
329
+ print("🔧 Memory Optimization")
330
+ print("-" * 80)
331
+
332
+ agent_id = getattr(args, 'agent_id', None)
333
+
334
+ try:
335
+ if agent_id:
336
+ print(f"📊 Optimizing memory for agent: {agent_id}")
337
+ result = memory_manager.optimize_memory(agent_id)
338
+ else:
339
+ print("📊 Optimizing all agent memories...")
340
+ result = memory_manager.optimize_memory()
341
+
342
+ if result.get("success"):
343
+ if agent_id:
344
+ # Single agent results
345
+ _display_single_optimization_result(result)
346
+ else:
347
+ # All agents results
348
+ _display_bulk_optimization_results(result)
349
+ else:
350
+ print(f"❌ Optimization failed: {result.get('error', 'Unknown error')}")
351
+
352
+ except Exception as e:
353
+ print(f"❌ Error during optimization: {e}")
354
+
355
+
356
+ def _build_memory(args, memory_manager):
357
+ """
358
+ Build agent memories from project documentation.
359
+
360
+ WHY: Project documentation contains valuable patterns and guidelines that
361
+ agents should be aware of. This command automatically extracts and assigns
362
+ relevant information to appropriate agents.
363
+
364
+ Args:
365
+ args: Command arguments with optional force_rebuild flag
366
+ memory_manager: AgentMemoryManager instance
367
+ """
368
+ print("📚 Memory Building from Documentation")
369
+ print("-" * 80)
370
+
371
+ force_rebuild = getattr(args, 'force_rebuild', False)
372
+
373
+ try:
374
+ print("🔍 Analyzing project documentation...")
375
+ result = memory_manager.build_memories_from_docs(force_rebuild)
376
+
377
+ if result.get("success"):
378
+ print(f"✅ Successfully processed documentation")
379
+ print(f" Files processed: {result.get('files_processed', 0)}")
380
+ print(f" Memories created: {result.get('memories_created', 0)}")
381
+ print(f" Memories updated: {result.get('memories_updated', 0)}")
382
+ print(f" Agents affected: {result.get('total_agents_affected', 0)}")
383
+
384
+ if result.get('agents_affected'):
385
+ print(f" Affected agents: {', '.join(result['agents_affected'])}")
386
+
387
+ # Show file-specific results
388
+ files_results = result.get('files', {})
389
+ if files_results:
390
+ print("\n📄 File processing details:")
391
+ for file_path, file_result in files_results.items():
392
+ if file_result.get('success'):
393
+ extracted = file_result.get('items_extracted', 0)
394
+ created = file_result.get('memories_created', 0)
395
+ print(f" {file_path}: {extracted} items extracted, {created} memories created")
396
+
397
+ if result.get('errors'):
398
+ print("\n⚠️ Errors encountered:")
399
+ for error in result['errors']:
400
+ print(f" {error}")
401
+
402
+ else:
403
+ print(f"❌ Build failed: {result.get('error', 'Unknown error')}")
404
+
405
+ except Exception as e:
406
+ print(f"❌ Error building memories: {e}")
407
+
408
+
409
+ def _cross_reference_memory(args, memory_manager):
410
+ """
411
+ Find cross-references and common patterns across agent memories.
412
+
413
+ WHY: Different agents may have learned similar information or there may be
414
+ knowledge gaps that can be identified through cross-referencing.
415
+
416
+ Args:
417
+ args: Command arguments with optional query
418
+ memory_manager: AgentMemoryManager instance
419
+ """
420
+ print("🔗 Memory Cross-Reference Analysis")
421
+ print("-" * 80)
422
+
423
+ query = getattr(args, 'query', None)
424
+
425
+ try:
426
+ if query:
427
+ print(f"🔍 Searching for: '{query}'")
428
+ else:
429
+ print("🔍 Analyzing all agent memories for patterns...")
430
+
431
+ result = memory_manager.cross_reference_memories(query)
432
+
433
+ if result.get("success") is False:
434
+ print(f"❌ Analysis failed: {result.get('error', 'Unknown error')}")
435
+ return
436
+
437
+ # Display common patterns
438
+ common_patterns = result.get("common_patterns", [])
439
+ if common_patterns:
440
+ print(f"\n🔄 Common patterns found ({len(common_patterns)}):")
441
+ for pattern in common_patterns[:10]: # Show top 10
442
+ agents = ', '.join(pattern['agents'])
443
+ print(f" • {pattern['pattern']}")
444
+ print(f" Found in: {agents} ({pattern['count']} instances)")
445
+ else:
446
+ print("\n🔄 No common patterns found")
447
+
448
+ # Display query matches if query was provided
449
+ if query and result.get("query_matches"):
450
+ print(f"\n🎯 Query matches for '{query}':")
451
+ for match in result["query_matches"]:
452
+ print(f" 📋 {match['agent']}:")
453
+ for line in match['matches'][:3]: # Show first 3 matches
454
+ print(f" • {line}")
455
+
456
+ # Display agent correlations
457
+ correlations = result.get("agent_correlations", {})
458
+ if correlations:
459
+ print(f"\n🤝 Agent knowledge correlations:")
460
+ sorted_correlations = sorted(correlations.items(), key=lambda x: x[1], reverse=True)
461
+ for agents, count in sorted_correlations[:5]: # Show top 5
462
+ print(f" {agents}: {count} common items")
463
+ else:
464
+ print("\n🤝 No significant correlations found")
465
+
466
+ except Exception as e:
467
+ print(f"❌ Error during cross-reference analysis: {e}")
468
+
469
+
470
+ def _show_memories(args, memory_manager):
471
+ """
472
+ Show agent memories in a user-friendly format with cross-references and patterns.
473
+
474
+ WHY: Users need to see agent memories in a readable format to understand
475
+ what agents have learned and identify common patterns across agents.
476
+
477
+ Args:
478
+ args: Command arguments with optional agent_id and format
479
+ memory_manager: AgentMemoryManager instance
480
+ """
481
+ print("🧠 Agent Memories Display")
482
+ print("-" * 80)
483
+
484
+ agent_id = getattr(args, 'agent_id', None)
485
+ format_type = getattr(args, 'format', 'summary')
486
+
487
+ try:
488
+ if agent_id:
489
+ _show_single_agent_memory(agent_id, format_type, memory_manager)
490
+ else:
491
+ _show_all_agent_memories(format_type, memory_manager)
492
+
493
+ except Exception as e:
494
+ print(f"❌ Error showing memories: {e}")
495
+
496
+
497
+ def _show_single_agent_memory(agent_id, format_type, memory_manager):
498
+ """Show memory for a single agent in the specified format."""
499
+ memory_content = memory_manager.load_agent_memory(agent_id)
500
+
501
+ if not memory_content:
502
+ print(f"📭 No memory found for agent: {agent_id}")
503
+ return
504
+
505
+ print(f"🤖 Agent: {agent_id}")
506
+ print("-" * 40)
507
+
508
+ if format_type == 'full':
509
+ print(memory_content)
510
+ else:
511
+ # Parse and display memory sections
512
+ sections = _parse_memory_content(memory_content)
513
+
514
+ for section_name, items in sections.items():
515
+ if items:
516
+ print(f"\n📚 {section_name} ({len(items)} items):")
517
+ for i, item in enumerate(items[:5], 1): # Show first 5 items
518
+ print(f" {i}. {item}")
519
+ if len(items) > 5:
520
+ print(f" ... and {len(items) - 5} more")
521
+
522
+
523
+ def _show_all_agent_memories(format_type, memory_manager):
524
+ """Show memories for all agents with cross-references."""
525
+ # Get all available agent memory files
526
+ memory_dir = memory_manager.memories_dir
527
+ if not memory_dir.exists():
528
+ print("📁 No memory directory found")
529
+ return
530
+
531
+ memory_files = list(memory_dir.glob("*_agent.md"))
532
+ if not memory_files:
533
+ print("📭 No agent memories found")
534
+ return
535
+
536
+ print(f"📊 Found memories for {len(memory_files)} agents")
537
+ print()
538
+
539
+ agent_memories = {}
540
+ total_items = 0
541
+
542
+ # Load all agent memories
543
+ for file_path in sorted(memory_files):
544
+ agent_id = file_path.stem.replace('_agent', '')
545
+ try:
546
+ memory_content = memory_manager.load_agent_memory(agent_id)
547
+ if memory_content:
548
+ sections = _parse_memory_content(memory_content)
549
+ agent_memories[agent_id] = sections
550
+
551
+ # Count items
552
+ item_count = sum(len(items) for items in sections.values())
553
+ total_items += item_count
554
+
555
+ if format_type == 'summary':
556
+ print(f"🤖 {agent_id}")
557
+ print(f" 📚 {len(sections)} sections, {item_count} total items")
558
+
559
+ # Show section summary
560
+ for section_name, items in sections.items():
561
+ if items:
562
+ print(f" • {section_name}: {len(items)} items")
563
+ print()
564
+ elif format_type == 'detailed':
565
+ print(f"🤖 {agent_id}")
566
+ print(f" 📚 {len(sections)} sections, {item_count} total items")
567
+
568
+ for section_name, items in sections.items():
569
+ if items:
570
+ print(f"\n 📖 {section_name}:")
571
+ for item in items[:3]: # Show first 3 items
572
+ print(f" • {item}")
573
+ if len(items) > 3:
574
+ print(f" ... and {len(items) - 3} more")
575
+ print()
576
+ except Exception as e:
577
+ print(f"❌ Error loading memory for {agent_id}: {e}")
578
+
579
+ print(f"📊 Total: {total_items} memory items across {len(agent_memories)} agents")
580
+
581
+ # Show cross-references if we have multiple agents
582
+ if len(agent_memories) > 1:
583
+ print("\n🔗 Cross-References and Common Patterns:")
584
+ _find_common_patterns(agent_memories)
585
+
586
+
587
+ def _parse_memory_content(content):
588
+ """Parse memory content into sections and items."""
589
+ sections = {}
590
+ current_section = None
591
+ current_items = []
592
+
593
+ for line in content.split('\n'):
594
+ line = line.strip()
595
+
596
+ if line.startswith('## ') and not line.startswith('## Memory Usage'):
597
+ # New section
598
+ if current_section and current_items:
599
+ sections[current_section] = current_items.copy()
600
+
601
+ current_section = line[3:].strip()
602
+ current_items = []
603
+ elif line.startswith('- ') and current_section:
604
+ # Item in current section
605
+ item = line[2:].strip()
606
+ if item and len(item) > 5: # Filter out very short items
607
+ current_items.append(item)
608
+
609
+ # Add final section
610
+ if current_section and current_items:
611
+ sections[current_section] = current_items
612
+
613
+ return sections
614
+
615
+
616
+ def _find_common_patterns(agent_memories):
617
+ """Find common patterns across agent memories."""
618
+ pattern_count = {}
619
+ agent_patterns = {}
620
+
621
+ # Collect all patterns and which agents have them
622
+ for agent_id, sections in agent_memories.items():
623
+ agent_patterns[agent_id] = set()
624
+
625
+ for section_name, items in sections.items():
626
+ for item in items:
627
+ # Normalize item for comparison (lowercase, basic cleanup)
628
+ normalized = item.lower().strip()
629
+ if len(normalized) > 10: # Skip very short items
630
+ pattern_count[normalized] = pattern_count.get(normalized, 0) + 1
631
+ agent_patterns[agent_id].add(normalized)
632
+
633
+ # Find patterns that appear in multiple agents
634
+ common_patterns = [(pattern, count) for pattern, count in pattern_count.items() if count > 1]
635
+ common_patterns.sort(key=lambda x: x[1], reverse=True)
636
+
637
+ if common_patterns:
638
+ print("\n🔄 Most Common Patterns:")
639
+ for pattern, count in common_patterns[:5]:
640
+ # Find which agents have this pattern
641
+ agents_with_pattern = [agent for agent, patterns in agent_patterns.items()
642
+ if pattern in patterns]
643
+ print(f" • {pattern[:80]}{'...' if len(pattern) > 80 else ''}")
644
+ print(f" Found in: {', '.join(agents_with_pattern)} ({count} agents)")
645
+ print()
646
+ else:
647
+ print(" No common patterns found across agents")
648
+
649
+ # Show agent similarities
650
+ print("\n🤝 Agent Knowledge Similarity:")
651
+ agents = list(agent_memories.keys())
652
+ for i, agent1 in enumerate(agents):
653
+ for agent2 in agents[i+1:]:
654
+ common_items = len(agent_patterns[agent1] & agent_patterns[agent2])
655
+ if common_items > 0:
656
+ total_items = len(agent_patterns[agent1] | agent_patterns[agent2])
657
+ similarity = (common_items / total_items) * 100 if total_items > 0 else 0
658
+ print(f" {agent1} ↔ {agent2}: {common_items} common items ({similarity:.1f}% similarity)")
659
+
660
+
661
+ def _route_memory_command(args, memory_manager):
662
+ """
663
+ Test memory command routing logic.
664
+
665
+ WHY: Users and developers need to understand how memory commands are routed
666
+ to appropriate agents for debugging and customization purposes.
667
+
668
+ Args:
669
+ args: Command arguments with content to route
670
+ memory_manager: AgentMemoryManager instance
671
+ """
672
+ print("🎯 Memory Command Routing Test")
673
+ print("-" * 80)
674
+
675
+ content = getattr(args, 'content', None)
676
+ if not content:
677
+ print("❌ No content provided for routing analysis")
678
+ print(" Usage: memory route --content 'your content here'")
679
+ return
680
+
681
+ try:
682
+ print(f"📝 Analyzing content: '{content[:100]}{'...' if len(content) > 100 else ''}'")
683
+
684
+ result = memory_manager.route_memory_command(content)
685
+
686
+ if result.get("success") is False:
687
+ print(f"❌ Routing failed: {result.get('error', 'Unknown error')}")
688
+ return
689
+
690
+ target_agent = result.get("target_agent", "unknown")
691
+ section = result.get("section", "unknown")
692
+ confidence = result.get("confidence", 0.0)
693
+ reasoning = result.get("reasoning", "No reasoning provided")
694
+
695
+ print(f"\n🎯 Routing Decision:")
696
+ print(f" Target Agent: {target_agent}")
697
+ print(f" Section: {section}")
698
+ print(f" Confidence: {confidence:.2f}")
699
+ print(f" Reasoning: {reasoning}")
700
+
701
+ # Show agent scores if available
702
+ agent_scores = result.get("agent_scores", {})
703
+ if agent_scores:
704
+ print(f"\n📊 Agent Relevance Scores:")
705
+ sorted_scores = sorted(
706
+ [(agent, data['score']) for agent, data in agent_scores.items()],
707
+ key=lambda x: x[1], reverse=True
708
+ )
709
+ for agent, score in sorted_scores[:5]: # Show top 5
710
+ print(f" {agent}: {score:.3f}")
711
+ # Show matched keywords if available
712
+ if agent in agent_scores and agent_scores[agent].get('matched_keywords'):
713
+ keywords = ', '.join(agent_scores[agent]['matched_keywords'][:3])
714
+ print(f" Keywords: {keywords}")
715
+
716
+ except Exception as e:
717
+ print(f"❌ Error routing memory command: {e}")
718
+
719
+
720
+ def _display_single_optimization_result(result):
721
+ """Display optimization results for a single agent."""
722
+ agent_id = result.get("agent_id", "unknown")
723
+ original_size = result.get("original_size", 0)
724
+ optimized_size = result.get("optimized_size", 0)
725
+ size_reduction = result.get("size_reduction", 0)
726
+ size_reduction_percent = result.get("size_reduction_percent", 0)
727
+
728
+ print(f"✅ Optimization completed for {agent_id}")
729
+ print(f" Original size: {original_size:,} bytes")
730
+ print(f" Optimized size: {optimized_size:,} bytes")
731
+ print(f" Size reduction: {size_reduction:,} bytes ({size_reduction_percent}%)")
732
+
733
+ duplicates = result.get("duplicates_removed", 0)
734
+ consolidated = result.get("items_consolidated", 0)
735
+ reordered = result.get("items_reordered", 0)
736
+
737
+ if duplicates > 0:
738
+ print(f" Duplicates removed: {duplicates}")
739
+ if consolidated > 0:
740
+ print(f" Items consolidated: {consolidated}")
741
+ if reordered > 0:
742
+ print(f" Sections reordered: {reordered}")
743
+
744
+ backup_path = result.get("backup_created")
745
+ if backup_path:
746
+ print(f" Backup created: {backup_path}")
747
+
748
+
749
+ def _display_bulk_optimization_results(result):
750
+ """Display optimization results for all agents."""
751
+ summary = result.get("summary", {})
752
+
753
+ print(f"✅ Bulk optimization completed")
754
+ print(f" Agents processed: {summary.get('agents_processed', 0)}")
755
+ print(f" Agents optimized: {summary.get('agents_optimized', 0)}")
756
+ print(f" Total size before: {summary.get('total_size_before', 0):,} bytes")
757
+ print(f" Total size after: {summary.get('total_size_after', 0):,} bytes")
758
+ print(f" Total reduction: {summary.get('total_size_reduction', 0):,} bytes ({summary.get('total_size_reduction_percent', 0)}%)")
759
+ print(f" Total duplicates removed: {summary.get('total_duplicates_removed', 0)}")
760
+ print(f" Total items consolidated: {summary.get('total_items_consolidated', 0)}")
761
+
762
+ # Show per-agent summary
763
+ agents_results = result.get("agents", {})
764
+ if agents_results:
765
+ print(f"\n📊 Per-agent results:")
766
+ for agent_id, agent_result in agents_results.items():
767
+ if agent_result.get("success"):
768
+ reduction = agent_result.get("size_reduction_percent", 0)
769
+ duplicates = agent_result.get("duplicates_removed", 0)
770
+ consolidated = agent_result.get("items_consolidated", 0)
771
+
772
+ status_parts = []
773
+ if duplicates > 0:
774
+ status_parts.append(f"{duplicates} dupes")
775
+ if consolidated > 0:
776
+ status_parts.append(f"{consolidated} consolidated")
777
+
778
+ status = f" ({', '.join(status_parts)})" if status_parts else ""
779
+ print(f" {agent_id}: {reduction}% reduction{status}")
780
+ else:
781
+ error = agent_result.get("error", "Unknown error")
782
+ print(f" {agent_id}: ❌ {error}")