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.
- claude_mpm/agents/INSTRUCTIONS.md +71 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +1 -1
- claude_mpm/agents/templates/engineer.json +1 -1
- claude_mpm/agents/templates/ops.json +1 -1
- claude_mpm/agents/templates/pm.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +1 -1
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/test_integration.json +112 -0
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/cli/commands/memory.py +575 -25
- claude_mpm/cli/commands/run.py +115 -14
- claude_mpm/cli/parser.py +76 -0
- claude_mpm/constants.py +5 -0
- claude_mpm/core/claude_runner.py +13 -11
- claude_mpm/core/session_manager.py +46 -0
- claude_mpm/core/simple_runner.py +13 -11
- claude_mpm/hooks/claude_hooks/hook_handler.py +2 -26
- claude_mpm/scripts/launch_socketio_dashboard.py +261 -0
- claude_mpm/services/agent_memory_manager.py +264 -23
- claude_mpm/services/memory_builder.py +491 -0
- claude_mpm/services/memory_optimizer.py +619 -0
- claude_mpm/services/memory_router.py +445 -0
- claude_mpm/services/socketio_server.py +389 -1
- claude_mpm-3.3.2.dist-info/METADATA +159 -0
- {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/RECORD +31 -29
- claude_mpm/agents/templates/test-integration-agent.md +0 -34
- claude_mpm/core/websocket_handler.py +0 -233
- claude_mpm/services/websocket_server.py +0 -376
- claude_mpm-3.2.1.dist-info/METADATA +0 -432
- {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/WHEEL +0 -0
- {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.2.1.dist-info → claude_mpm-3.3.2.dist-info}/licenses/LICENSE +0 -0
- {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
|
|
85
|
+
Show comprehensive memory system status.
|
|
71
86
|
|
|
72
|
-
WHY: Users need to see
|
|
73
|
-
|
|
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}")
|