claude-mpm 3.3.0__py3-none-any.whl → 3.4.0__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/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 +749 -26
- claude_mpm/cli/commands/run.py +115 -14
- claude_mpm/cli/parser.py +89 -1
- claude_mpm/constants.py +6 -0
- claude_mpm/core/claude_runner.py +74 -11
- claude_mpm/core/config.py +1 -1
- claude_mpm/core/session_manager.py +46 -0
- claude_mpm/core/simple_runner.py +74 -11
- claude_mpm/hooks/builtin/mpm_command_hook.py +5 -5
- claude_mpm/hooks/claude_hooks/hook_handler.py +213 -30
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +9 -2
- claude_mpm/hooks/memory_integration_hook.py +51 -5
- claude_mpm/services/__init__.py +23 -5
- claude_mpm/services/agent_memory_manager.py +800 -71
- claude_mpm/services/memory_builder.py +823 -0
- claude_mpm/services/memory_optimizer.py +619 -0
- claude_mpm/services/memory_router.py +445 -0
- claude_mpm/services/project_analyzer.py +771 -0
- claude_mpm/services/socketio_server.py +649 -45
- claude_mpm/services/version_control/git_operations.py +26 -0
- claude_mpm-3.4.0.dist-info/METADATA +183 -0
- {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/RECORD +36 -52
- claude_mpm/agents/agent-template.yaml +0 -83
- claude_mpm/agents/templates/test-integration-agent.md +0 -34
- claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +0 -6
- claude_mpm/cli/README.md +0 -109
- claude_mpm/cli_module/refactoring_guide.md +0 -253
- claude_mpm/core/agent_registry.py.bak +0 -312
- claude_mpm/core/base_service.py.bak +0 -406
- claude_mpm/core/websocket_handler.py +0 -233
- claude_mpm/hooks/README.md +0 -97
- claude_mpm/orchestration/SUBPROCESS_DESIGN.md +0 -66
- claude_mpm/schemas/README_SECURITY.md +0 -92
- claude_mpm/schemas/agent_schema.json +0 -395
- claude_mpm/schemas/agent_schema_documentation.md +0 -181
- claude_mpm/schemas/agent_schema_security_notes.md +0 -165
- claude_mpm/schemas/examples/standard_workflow.json +0 -505
- claude_mpm/schemas/ticket_workflow_documentation.md +0 -482
- claude_mpm/schemas/ticket_workflow_schema.json +0 -590
- claude_mpm/services/framework_claude_md_generator/README.md +0 -92
- claude_mpm/services/parent_directory_manager/README.md +0 -83
- claude_mpm/services/version_control/VERSION +0 -1
- claude_mpm/services/websocket_server.py +0 -376
- claude_mpm-3.3.0.dist-info/METADATA +0 -432
- {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/WHEEL +0 -0
- {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/top_level.txt +0 -0
|
@@ -49,7 +49,7 @@ def manage_memory(args):
|
|
|
49
49
|
_show_status(memory_manager)
|
|
50
50
|
|
|
51
51
|
elif args.memory_command == "view":
|
|
52
|
-
|
|
52
|
+
_show_memories(args, memory_manager)
|
|
53
53
|
|
|
54
54
|
elif args.memory_command == "add":
|
|
55
55
|
_add_learning(args, memory_manager)
|
|
@@ -57,6 +57,30 @@ 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
|
+
|
|
75
|
+
elif args.memory_command == "init":
|
|
76
|
+
_init_memory(args, memory_manager)
|
|
77
|
+
|
|
78
|
+
else:
|
|
79
|
+
logger.error(f"Unknown memory command: {args.memory_command}")
|
|
80
|
+
print(f"Unknown memory command: {args.memory_command}")
|
|
81
|
+
print("Available commands: init, status, view, add, clean, optimize, build, cross-ref, route, show")
|
|
82
|
+
return 1
|
|
83
|
+
|
|
60
84
|
except Exception as e:
|
|
61
85
|
logger.error(f"Error managing memory: {e}")
|
|
62
86
|
print(f"❌ Error: {e}")
|
|
@@ -65,19 +89,170 @@ def manage_memory(args):
|
|
|
65
89
|
return 0
|
|
66
90
|
|
|
67
91
|
|
|
92
|
+
def _init_memory(args, memory_manager):
|
|
93
|
+
"""
|
|
94
|
+
Initialize project-specific memories via agent delegation.
|
|
95
|
+
|
|
96
|
+
WHY: When starting with a new project, agents need project-specific knowledge
|
|
97
|
+
beyond what automatic analysis provides. This command triggers an agent task
|
|
98
|
+
to comprehensively scan the project and create custom memories.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
args: Command line arguments (unused but kept for consistency)
|
|
102
|
+
memory_manager: AgentMemoryManager instance
|
|
103
|
+
"""
|
|
104
|
+
logger = get_logger("cli")
|
|
105
|
+
|
|
106
|
+
print("🚀 Initializing project-specific memories...")
|
|
107
|
+
print("=" * 80)
|
|
108
|
+
print()
|
|
109
|
+
print("This will analyze the project to:")
|
|
110
|
+
print(" 1. Scan project structure and documentation")
|
|
111
|
+
print(" 2. Analyze source code for patterns and conventions")
|
|
112
|
+
print(" 3. Create targeted memories for each agent type")
|
|
113
|
+
print(" 4. Add insights using 'claude-mpm memory add' commands")
|
|
114
|
+
print()
|
|
115
|
+
print("The analysis will cover:")
|
|
116
|
+
print(" • Project architecture and design patterns")
|
|
117
|
+
print(" • Coding conventions and standards")
|
|
118
|
+
print(" • Key modules and integration points")
|
|
119
|
+
print(" • Testing patterns and quality standards")
|
|
120
|
+
print(" • Performance considerations")
|
|
121
|
+
print(" • Domain-specific terminology")
|
|
122
|
+
print()
|
|
123
|
+
print("=" * 80)
|
|
124
|
+
print()
|
|
125
|
+
print("[Agent Task: Initialize Project-Specific Memories]")
|
|
126
|
+
print()
|
|
127
|
+
print("Please analyze this project and create custom memories for all agents.")
|
|
128
|
+
print()
|
|
129
|
+
print("Instructions:")
|
|
130
|
+
print("1. Scan the project structure, documentation, and source code")
|
|
131
|
+
print("2. Identify key patterns, conventions, and project-specific knowledge")
|
|
132
|
+
print("3. Create targeted memories for each agent type")
|
|
133
|
+
print("4. Use 'claude-mpm memory add <agent> <type> \"<content>\"' commands")
|
|
134
|
+
print()
|
|
135
|
+
print("Focus areas:")
|
|
136
|
+
print(" • Architectural patterns and design decisions")
|
|
137
|
+
print(" • Coding conventions from actual source code")
|
|
138
|
+
print(" • Key modules, APIs, and integration points")
|
|
139
|
+
print(" • Testing patterns and quality standards")
|
|
140
|
+
print(" • Performance considerations specific to this project")
|
|
141
|
+
print(" • Common pitfalls based on the codebase")
|
|
142
|
+
print(" • Domain-specific terminology and concepts")
|
|
143
|
+
print()
|
|
144
|
+
print("Example commands to use:")
|
|
145
|
+
print(' claude-mpm memory add engineer pattern "Use dependency injection with @inject"')
|
|
146
|
+
print(' claude-mpm memory add qa pattern "Test files follow test_<module>_<feature>.py"')
|
|
147
|
+
print(' claude-mpm memory add research context "Project uses microservices architecture"')
|
|
148
|
+
print()
|
|
149
|
+
print("Begin by examining the project structure and key files.")
|
|
150
|
+
print()
|
|
151
|
+
print("=" * 80)
|
|
152
|
+
print()
|
|
153
|
+
print("📝 Note: Copy the task above to execute the memory initialization process.")
|
|
154
|
+
print(" Use 'claude-mpm memory add' commands to add discovered insights.")
|
|
155
|
+
|
|
156
|
+
|
|
68
157
|
def _show_status(memory_manager):
|
|
69
158
|
"""
|
|
70
|
-
Show memory
|
|
159
|
+
Show comprehensive memory system status.
|
|
71
160
|
|
|
72
|
-
WHY: Users need to see
|
|
73
|
-
|
|
161
|
+
WHY: Users need to see memory system health, file sizes, optimization
|
|
162
|
+
opportunities, and agent-specific statistics to understand the system state.
|
|
74
163
|
|
|
75
164
|
Args:
|
|
76
165
|
memory_manager: AgentMemoryManager instance
|
|
77
166
|
"""
|
|
78
|
-
print("Agent Memory Status")
|
|
167
|
+
print("Agent Memory System Status")
|
|
79
168
|
print("-" * 80)
|
|
80
169
|
|
|
170
|
+
try:
|
|
171
|
+
# Get comprehensive status from memory manager
|
|
172
|
+
status = memory_manager.get_memory_status()
|
|
173
|
+
|
|
174
|
+
if not status.get("success", True):
|
|
175
|
+
print(f"❌ Error getting status: {status.get('error', 'Unknown error')}")
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
# Show system overview
|
|
179
|
+
system_health = status.get("system_health", "unknown")
|
|
180
|
+
health_emoji = {
|
|
181
|
+
"healthy": "✅",
|
|
182
|
+
"needs_optimization": "⚠️",
|
|
183
|
+
"high_usage": "📊",
|
|
184
|
+
"no_memory_dir": "📁"
|
|
185
|
+
}.get(system_health, "❓")
|
|
186
|
+
|
|
187
|
+
print(f"🧠 Memory System Health: {health_emoji} {system_health}")
|
|
188
|
+
print(f"📁 Memory Directory: {status.get('memory_directory', 'Unknown')}")
|
|
189
|
+
print(f"🔧 System Enabled: {'Yes' if status.get('system_enabled', True) else 'No'}")
|
|
190
|
+
print(f"📚 Auto Learning: {'Yes' if status.get('auto_learning', True) else 'No'}")
|
|
191
|
+
print(f"📊 Total Agents: {status.get('total_agents', 0)}")
|
|
192
|
+
print(f"💾 Total Size: {status.get('total_size_kb', 0):.1f} KB")
|
|
193
|
+
print()
|
|
194
|
+
|
|
195
|
+
# Show optimization opportunities
|
|
196
|
+
opportunities = status.get("optimization_opportunities", [])
|
|
197
|
+
if opportunities:
|
|
198
|
+
print(f"⚠️ Optimization Opportunities ({len(opportunities)}):")
|
|
199
|
+
for opportunity in opportunities[:5]: # Show top 5
|
|
200
|
+
print(f" • {opportunity}")
|
|
201
|
+
if len(opportunities) > 5:
|
|
202
|
+
print(f" ... and {len(opportunities) - 5} more")
|
|
203
|
+
print()
|
|
204
|
+
|
|
205
|
+
# Show per-agent details
|
|
206
|
+
agents = status.get("agents", {})
|
|
207
|
+
if agents:
|
|
208
|
+
print(f"📋 Agent Memory Details:")
|
|
209
|
+
for agent_id, agent_info in sorted(agents.items()):
|
|
210
|
+
if "error" in agent_info:
|
|
211
|
+
print(f" ❌ {agent_id}: Error - {agent_info['error']}")
|
|
212
|
+
continue
|
|
213
|
+
|
|
214
|
+
size_kb = agent_info.get("size_kb", 0)
|
|
215
|
+
size_limit = agent_info.get("size_limit_kb", 8)
|
|
216
|
+
utilization = agent_info.get("size_utilization", 0)
|
|
217
|
+
sections = agent_info.get("sections", 0)
|
|
218
|
+
items = agent_info.get("items", 0)
|
|
219
|
+
last_modified = agent_info.get("last_modified", "Unknown")
|
|
220
|
+
auto_learning = agent_info.get("auto_learning", True)
|
|
221
|
+
|
|
222
|
+
# Format last modified time
|
|
223
|
+
try:
|
|
224
|
+
from datetime import datetime
|
|
225
|
+
dt = datetime.fromisoformat(last_modified.replace('Z', '+00:00'))
|
|
226
|
+
last_modified_str = dt.strftime('%Y-%m-%d %H:%M:%S')
|
|
227
|
+
except:
|
|
228
|
+
last_modified_str = last_modified
|
|
229
|
+
|
|
230
|
+
# Status indicator based on usage
|
|
231
|
+
if utilization > 90:
|
|
232
|
+
status_emoji = "🔴" # High usage
|
|
233
|
+
elif utilization > 70:
|
|
234
|
+
status_emoji = "🟡" # Medium usage
|
|
235
|
+
else:
|
|
236
|
+
status_emoji = "🟢" # Low usage
|
|
237
|
+
|
|
238
|
+
print(f" {status_emoji} {agent_id}")
|
|
239
|
+
print(f" Size: {size_kb:.1f} KB / {size_limit} KB ({utilization:.1f}%)")
|
|
240
|
+
print(f" Content: {sections} sections, {items} items")
|
|
241
|
+
print(f" Auto-learning: {'On' if auto_learning else 'Off'}")
|
|
242
|
+
print(f" Last modified: {last_modified_str}")
|
|
243
|
+
else:
|
|
244
|
+
print("📭 No agent memories found")
|
|
245
|
+
|
|
246
|
+
except Exception as e:
|
|
247
|
+
print(f"❌ Error showing status: {e}")
|
|
248
|
+
# Fallback to basic status display
|
|
249
|
+
_show_basic_status(memory_manager)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _show_basic_status(memory_manager):
|
|
253
|
+
"""Fallback basic status display if comprehensive status fails."""
|
|
254
|
+
print("\n--- Basic Status (Fallback) ---")
|
|
255
|
+
|
|
81
256
|
memory_dir = memory_manager.memories_dir
|
|
82
257
|
if not memory_dir.exists():
|
|
83
258
|
print("📁 Memory directory not found - no agent memories stored yet")
|
|
@@ -93,7 +268,6 @@ def _show_status(memory_manager):
|
|
|
93
268
|
|
|
94
269
|
print(f"📁 Memory directory: {memory_dir}")
|
|
95
270
|
print(f"📊 Total memory files: {len(memory_files)}")
|
|
96
|
-
print()
|
|
97
271
|
|
|
98
272
|
total_size = 0
|
|
99
273
|
for file_path in sorted(memory_files):
|
|
@@ -101,26 +275,8 @@ def _show_status(memory_manager):
|
|
|
101
275
|
size_kb = stat.st_size / 1024
|
|
102
276
|
total_size += stat.st_size
|
|
103
277
|
|
|
104
|
-
# Extract agent ID from filename (remove '_agent' suffix)
|
|
105
278
|
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()
|
|
279
|
+
print(f" {agent_id}: {size_kb:.1f} KB")
|
|
124
280
|
|
|
125
281
|
print(f"💾 Total size: {total_size / 1024:.1f} KB")
|
|
126
282
|
|
|
@@ -229,4 +385,571 @@ def _clean_memory(args, memory_manager):
|
|
|
229
385
|
print(" Future cleanup will remove:")
|
|
230
386
|
print(" - Memory files older than 30 days with no recent access")
|
|
231
387
|
print(" - Corrupted memory files")
|
|
232
|
-
print(" - Memory files for non-existent agents")
|
|
388
|
+
print(" - Memory files for non-existent agents")
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _optimize_memory(args, memory_manager):
|
|
392
|
+
"""
|
|
393
|
+
Optimize memory files by removing duplicates and consolidating similar items.
|
|
394
|
+
|
|
395
|
+
WHY: Memory files can become cluttered over time with duplicate or redundant
|
|
396
|
+
information. This command provides automated cleanup while preserving
|
|
397
|
+
important learnings.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
args: Command arguments with optional agent_id
|
|
401
|
+
memory_manager: AgentMemoryManager instance
|
|
402
|
+
"""
|
|
403
|
+
print("🔧 Memory Optimization")
|
|
404
|
+
print("-" * 80)
|
|
405
|
+
|
|
406
|
+
agent_id = getattr(args, 'agent_id', None)
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
if agent_id:
|
|
410
|
+
print(f"📊 Optimizing memory for agent: {agent_id}")
|
|
411
|
+
result = memory_manager.optimize_memory(agent_id)
|
|
412
|
+
else:
|
|
413
|
+
print("📊 Optimizing all agent memories...")
|
|
414
|
+
result = memory_manager.optimize_memory()
|
|
415
|
+
|
|
416
|
+
if result.get("success"):
|
|
417
|
+
if agent_id:
|
|
418
|
+
# Single agent results
|
|
419
|
+
_display_single_optimization_result(result)
|
|
420
|
+
else:
|
|
421
|
+
# All agents results
|
|
422
|
+
_display_bulk_optimization_results(result)
|
|
423
|
+
else:
|
|
424
|
+
print(f"❌ Optimization failed: {result.get('error', 'Unknown error')}")
|
|
425
|
+
|
|
426
|
+
except Exception as e:
|
|
427
|
+
print(f"❌ Error during optimization: {e}")
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def _build_memory(args, memory_manager):
|
|
431
|
+
"""
|
|
432
|
+
Build agent memories from project documentation.
|
|
433
|
+
|
|
434
|
+
WHY: Project documentation contains valuable patterns and guidelines that
|
|
435
|
+
agents should be aware of. This command automatically extracts and assigns
|
|
436
|
+
relevant information to appropriate agents.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
args: Command arguments with optional force_rebuild flag
|
|
440
|
+
memory_manager: AgentMemoryManager instance
|
|
441
|
+
"""
|
|
442
|
+
print("📚 Memory Building from Documentation")
|
|
443
|
+
print("-" * 80)
|
|
444
|
+
|
|
445
|
+
force_rebuild = getattr(args, 'force_rebuild', False)
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
print("🔍 Analyzing project documentation...")
|
|
449
|
+
result = memory_manager.build_memories_from_docs(force_rebuild)
|
|
450
|
+
|
|
451
|
+
if result.get("success"):
|
|
452
|
+
print(f"✅ Successfully processed documentation")
|
|
453
|
+
print(f" Files processed: {result.get('files_processed', 0)}")
|
|
454
|
+
print(f" Memories created: {result.get('memories_created', 0)}")
|
|
455
|
+
print(f" Memories updated: {result.get('memories_updated', 0)}")
|
|
456
|
+
print(f" Agents affected: {result.get('total_agents_affected', 0)}")
|
|
457
|
+
|
|
458
|
+
if result.get('agents_affected'):
|
|
459
|
+
print(f" Affected agents: {', '.join(result['agents_affected'])}")
|
|
460
|
+
|
|
461
|
+
# Show file-specific results
|
|
462
|
+
files_results = result.get('files', {})
|
|
463
|
+
if files_results:
|
|
464
|
+
print("\n📄 File processing details:")
|
|
465
|
+
for file_path, file_result in files_results.items():
|
|
466
|
+
if file_result.get('success'):
|
|
467
|
+
extracted = file_result.get('items_extracted', 0)
|
|
468
|
+
created = file_result.get('memories_created', 0)
|
|
469
|
+
print(f" {file_path}: {extracted} items extracted, {created} memories created")
|
|
470
|
+
|
|
471
|
+
if result.get('errors'):
|
|
472
|
+
print("\n⚠️ Errors encountered:")
|
|
473
|
+
for error in result['errors']:
|
|
474
|
+
print(f" {error}")
|
|
475
|
+
|
|
476
|
+
else:
|
|
477
|
+
print(f"❌ Build failed: {result.get('error', 'Unknown error')}")
|
|
478
|
+
|
|
479
|
+
except Exception as e:
|
|
480
|
+
print(f"❌ Error building memories: {e}")
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def _cross_reference_memory(args, memory_manager):
|
|
484
|
+
"""
|
|
485
|
+
Find cross-references and common patterns across agent memories.
|
|
486
|
+
|
|
487
|
+
WHY: Different agents may have learned similar information or there may be
|
|
488
|
+
knowledge gaps that can be identified through cross-referencing.
|
|
489
|
+
|
|
490
|
+
Args:
|
|
491
|
+
args: Command arguments with optional query
|
|
492
|
+
memory_manager: AgentMemoryManager instance
|
|
493
|
+
"""
|
|
494
|
+
print("🔗 Memory Cross-Reference Analysis")
|
|
495
|
+
print("-" * 80)
|
|
496
|
+
|
|
497
|
+
query = getattr(args, 'query', None)
|
|
498
|
+
|
|
499
|
+
try:
|
|
500
|
+
if query:
|
|
501
|
+
print(f"🔍 Searching for: '{query}'")
|
|
502
|
+
else:
|
|
503
|
+
print("🔍 Analyzing all agent memories for patterns...")
|
|
504
|
+
|
|
505
|
+
result = memory_manager.cross_reference_memories(query)
|
|
506
|
+
|
|
507
|
+
if result.get("success") is False:
|
|
508
|
+
print(f"❌ Analysis failed: {result.get('error', 'Unknown error')}")
|
|
509
|
+
return
|
|
510
|
+
|
|
511
|
+
# Display common patterns
|
|
512
|
+
common_patterns = result.get("common_patterns", [])
|
|
513
|
+
if common_patterns:
|
|
514
|
+
print(f"\n🔄 Common patterns found ({len(common_patterns)}):")
|
|
515
|
+
for pattern in common_patterns[:10]: # Show top 10
|
|
516
|
+
agents = ', '.join(pattern['agents'])
|
|
517
|
+
print(f" • {pattern['pattern']}")
|
|
518
|
+
print(f" Found in: {agents} ({pattern['count']} instances)")
|
|
519
|
+
else:
|
|
520
|
+
print("\n🔄 No common patterns found")
|
|
521
|
+
|
|
522
|
+
# Display query matches if query was provided
|
|
523
|
+
if query and result.get("query_matches"):
|
|
524
|
+
print(f"\n🎯 Query matches for '{query}':")
|
|
525
|
+
for match in result["query_matches"]:
|
|
526
|
+
print(f" 📋 {match['agent']}:")
|
|
527
|
+
for line in match['matches'][:3]: # Show first 3 matches
|
|
528
|
+
print(f" • {line}")
|
|
529
|
+
|
|
530
|
+
# Display agent correlations
|
|
531
|
+
correlations = result.get("agent_correlations", {})
|
|
532
|
+
if correlations:
|
|
533
|
+
print(f"\n🤝 Agent knowledge correlations:")
|
|
534
|
+
sorted_correlations = sorted(correlations.items(), key=lambda x: x[1], reverse=True)
|
|
535
|
+
for agents, count in sorted_correlations[:5]: # Show top 5
|
|
536
|
+
print(f" {agents}: {count} common items")
|
|
537
|
+
else:
|
|
538
|
+
print("\n🤝 No significant correlations found")
|
|
539
|
+
|
|
540
|
+
except Exception as e:
|
|
541
|
+
print(f"❌ Error during cross-reference analysis: {e}")
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def _show_memories(args, memory_manager):
|
|
545
|
+
"""
|
|
546
|
+
Show agent memories in a user-friendly format with cross-references and patterns.
|
|
547
|
+
|
|
548
|
+
WHY: Users need to see agent memories in a readable format to understand
|
|
549
|
+
what agents have learned and identify common patterns across agents.
|
|
550
|
+
|
|
551
|
+
DESIGN DECISION: Added --raw flag to output structured JSON data for
|
|
552
|
+
programmatic processing, enabling external tools and scripts to access
|
|
553
|
+
all agent memories in a structured format.
|
|
554
|
+
|
|
555
|
+
Args:
|
|
556
|
+
args: Command arguments with optional agent_id, format, and raw flag
|
|
557
|
+
memory_manager: AgentMemoryManager instance
|
|
558
|
+
"""
|
|
559
|
+
agent_id = getattr(args, 'agent_id', None)
|
|
560
|
+
format_type = getattr(args, 'format', 'detailed')
|
|
561
|
+
raw_output = getattr(args, 'raw', False)
|
|
562
|
+
|
|
563
|
+
try:
|
|
564
|
+
if raw_output:
|
|
565
|
+
# Output structured JSON data
|
|
566
|
+
if agent_id:
|
|
567
|
+
# Get single agent memory in raw format
|
|
568
|
+
_output_single_agent_raw(agent_id, memory_manager)
|
|
569
|
+
else:
|
|
570
|
+
# Get all agent memories in raw format
|
|
571
|
+
_output_all_memories_raw(memory_manager)
|
|
572
|
+
else:
|
|
573
|
+
# Normal user-friendly display
|
|
574
|
+
print("🧠 Agent Memories Display")
|
|
575
|
+
print("-" * 80)
|
|
576
|
+
|
|
577
|
+
if agent_id:
|
|
578
|
+
_show_single_agent_memory(agent_id, format_type, memory_manager)
|
|
579
|
+
else:
|
|
580
|
+
_show_all_agent_memories(format_type, memory_manager)
|
|
581
|
+
|
|
582
|
+
except Exception as e:
|
|
583
|
+
if raw_output:
|
|
584
|
+
# Output error in JSON format for consistency
|
|
585
|
+
error_output = {
|
|
586
|
+
"success": False,
|
|
587
|
+
"error": str(e),
|
|
588
|
+
"timestamp": datetime.now().isoformat()
|
|
589
|
+
}
|
|
590
|
+
print(json.dumps(error_output, indent=2))
|
|
591
|
+
else:
|
|
592
|
+
print(f"❌ Error showing memories: {e}")
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
def _show_single_agent_memory(agent_id, format_type, memory_manager):
|
|
596
|
+
"""Show memory for a single agent in the specified format."""
|
|
597
|
+
memory_content = memory_manager.load_agent_memory(agent_id)
|
|
598
|
+
|
|
599
|
+
if not memory_content:
|
|
600
|
+
print(f"📭 No memory found for agent: {agent_id}")
|
|
601
|
+
return
|
|
602
|
+
|
|
603
|
+
print(f"🤖 Agent: {agent_id}")
|
|
604
|
+
print("-" * 40)
|
|
605
|
+
|
|
606
|
+
if format_type == 'full':
|
|
607
|
+
print(memory_content)
|
|
608
|
+
else:
|
|
609
|
+
# Parse and display memory sections
|
|
610
|
+
sections = _parse_memory_content(memory_content)
|
|
611
|
+
|
|
612
|
+
for section_name, items in sections.items():
|
|
613
|
+
if items:
|
|
614
|
+
print(f"\n📚 {section_name} ({len(items)} items):")
|
|
615
|
+
for i, item in enumerate(items[:5], 1): # Show first 5 items
|
|
616
|
+
print(f" {i}. {item}")
|
|
617
|
+
if len(items) > 5:
|
|
618
|
+
print(f" ... and {len(items) - 5} more")
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def _show_all_agent_memories(format_type, memory_manager):
|
|
622
|
+
"""Show memories for all agents with cross-references."""
|
|
623
|
+
# Get all available agent memory files
|
|
624
|
+
memory_dir = memory_manager.memories_dir
|
|
625
|
+
if not memory_dir.exists():
|
|
626
|
+
print("📁 No memory directory found")
|
|
627
|
+
return
|
|
628
|
+
|
|
629
|
+
memory_files = list(memory_dir.glob("*_agent.md"))
|
|
630
|
+
if not memory_files:
|
|
631
|
+
print("📭 No agent memories found")
|
|
632
|
+
return
|
|
633
|
+
|
|
634
|
+
print(f"📊 Found memories for {len(memory_files)} agents")
|
|
635
|
+
print()
|
|
636
|
+
|
|
637
|
+
agent_memories = {}
|
|
638
|
+
total_items = 0
|
|
639
|
+
|
|
640
|
+
# Load all agent memories
|
|
641
|
+
for file_path in sorted(memory_files):
|
|
642
|
+
agent_id = file_path.stem.replace('_agent', '')
|
|
643
|
+
try:
|
|
644
|
+
memory_content = memory_manager.load_agent_memory(agent_id)
|
|
645
|
+
if memory_content:
|
|
646
|
+
sections = _parse_memory_content(memory_content)
|
|
647
|
+
agent_memories[agent_id] = sections
|
|
648
|
+
|
|
649
|
+
# Count items
|
|
650
|
+
item_count = sum(len(items) for items in sections.values())
|
|
651
|
+
total_items += item_count
|
|
652
|
+
|
|
653
|
+
if format_type == 'summary':
|
|
654
|
+
print(f"🤖 {agent_id}")
|
|
655
|
+
print(f" 📚 {len(sections)} sections, {item_count} total items")
|
|
656
|
+
|
|
657
|
+
# Show section summary
|
|
658
|
+
for section_name, items in sections.items():
|
|
659
|
+
if items:
|
|
660
|
+
print(f" • {section_name}: {len(items)} items")
|
|
661
|
+
print()
|
|
662
|
+
elif format_type == 'detailed':
|
|
663
|
+
print(f"🤖 {agent_id}")
|
|
664
|
+
print(f" 📚 {len(sections)} sections, {item_count} total items")
|
|
665
|
+
|
|
666
|
+
for section_name, items in sections.items():
|
|
667
|
+
if items:
|
|
668
|
+
print(f"\n 📖 {section_name}:")
|
|
669
|
+
for item in items[:3]: # Show first 3 items
|
|
670
|
+
print(f" • {item}")
|
|
671
|
+
if len(items) > 3:
|
|
672
|
+
print(f" ... and {len(items) - 3} more")
|
|
673
|
+
print()
|
|
674
|
+
except Exception as e:
|
|
675
|
+
print(f"❌ Error loading memory for {agent_id}: {e}")
|
|
676
|
+
|
|
677
|
+
print(f"📊 Total: {total_items} memory items across {len(agent_memories)} agents")
|
|
678
|
+
|
|
679
|
+
# Show cross-references if we have multiple agents
|
|
680
|
+
if len(agent_memories) > 1:
|
|
681
|
+
print("\n🔗 Cross-References and Common Patterns:")
|
|
682
|
+
_find_common_patterns(agent_memories)
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
def _parse_memory_content(content):
|
|
686
|
+
"""Parse memory content into sections and items."""
|
|
687
|
+
sections = {}
|
|
688
|
+
current_section = None
|
|
689
|
+
current_items = []
|
|
690
|
+
|
|
691
|
+
for line in content.split('\n'):
|
|
692
|
+
line = line.strip()
|
|
693
|
+
|
|
694
|
+
if line.startswith('## ') and not line.startswith('## Memory Usage'):
|
|
695
|
+
# New section
|
|
696
|
+
if current_section and current_items:
|
|
697
|
+
sections[current_section] = current_items.copy()
|
|
698
|
+
|
|
699
|
+
current_section = line[3:].strip()
|
|
700
|
+
current_items = []
|
|
701
|
+
elif line.startswith('- ') and current_section:
|
|
702
|
+
# Item in current section
|
|
703
|
+
item = line[2:].strip()
|
|
704
|
+
if item and len(item) > 5: # Filter out very short items
|
|
705
|
+
current_items.append(item)
|
|
706
|
+
|
|
707
|
+
# Add final section
|
|
708
|
+
if current_section and current_items:
|
|
709
|
+
sections[current_section] = current_items
|
|
710
|
+
|
|
711
|
+
return sections
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def _find_common_patterns(agent_memories):
|
|
715
|
+
"""Find common patterns across agent memories."""
|
|
716
|
+
pattern_count = {}
|
|
717
|
+
agent_patterns = {}
|
|
718
|
+
|
|
719
|
+
# Collect all patterns and which agents have them
|
|
720
|
+
for agent_id, sections in agent_memories.items():
|
|
721
|
+
agent_patterns[agent_id] = set()
|
|
722
|
+
|
|
723
|
+
for section_name, items in sections.items():
|
|
724
|
+
for item in items:
|
|
725
|
+
# Normalize item for comparison (lowercase, basic cleanup)
|
|
726
|
+
normalized = item.lower().strip()
|
|
727
|
+
if len(normalized) > 10: # Skip very short items
|
|
728
|
+
pattern_count[normalized] = pattern_count.get(normalized, 0) + 1
|
|
729
|
+
agent_patterns[agent_id].add(normalized)
|
|
730
|
+
|
|
731
|
+
# Find patterns that appear in multiple agents
|
|
732
|
+
common_patterns = [(pattern, count) for pattern, count in pattern_count.items() if count > 1]
|
|
733
|
+
common_patterns.sort(key=lambda x: x[1], reverse=True)
|
|
734
|
+
|
|
735
|
+
if common_patterns:
|
|
736
|
+
print("\n🔄 Most Common Patterns:")
|
|
737
|
+
for pattern, count in common_patterns[:5]:
|
|
738
|
+
# Find which agents have this pattern
|
|
739
|
+
agents_with_pattern = [agent for agent, patterns in agent_patterns.items()
|
|
740
|
+
if pattern in patterns]
|
|
741
|
+
print(f" • {pattern[:80]}{'...' if len(pattern) > 80 else ''}")
|
|
742
|
+
print(f" Found in: {', '.join(agents_with_pattern)} ({count} agents)")
|
|
743
|
+
print()
|
|
744
|
+
else:
|
|
745
|
+
print(" No common patterns found across agents")
|
|
746
|
+
|
|
747
|
+
# Show agent similarities
|
|
748
|
+
print("\n🤝 Agent Knowledge Similarity:")
|
|
749
|
+
agents = list(agent_memories.keys())
|
|
750
|
+
for i, agent1 in enumerate(agents):
|
|
751
|
+
for agent2 in agents[i+1:]:
|
|
752
|
+
common_items = len(agent_patterns[agent1] & agent_patterns[agent2])
|
|
753
|
+
if common_items > 0:
|
|
754
|
+
total_items = len(agent_patterns[agent1] | agent_patterns[agent2])
|
|
755
|
+
similarity = (common_items / total_items) * 100 if total_items > 0 else 0
|
|
756
|
+
print(f" {agent1} ↔ {agent2}: {common_items} common items ({similarity:.1f}% similarity)")
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
def _route_memory_command(args, memory_manager):
|
|
760
|
+
"""
|
|
761
|
+
Test memory command routing logic.
|
|
762
|
+
|
|
763
|
+
WHY: Users and developers need to understand how memory commands are routed
|
|
764
|
+
to appropriate agents for debugging and customization purposes.
|
|
765
|
+
|
|
766
|
+
Args:
|
|
767
|
+
args: Command arguments with content to route
|
|
768
|
+
memory_manager: AgentMemoryManager instance
|
|
769
|
+
"""
|
|
770
|
+
print("🎯 Memory Command Routing Test")
|
|
771
|
+
print("-" * 80)
|
|
772
|
+
|
|
773
|
+
content = getattr(args, 'content', None)
|
|
774
|
+
if not content:
|
|
775
|
+
print("❌ No content provided for routing analysis")
|
|
776
|
+
print(" Usage: memory route --content 'your content here'")
|
|
777
|
+
return
|
|
778
|
+
|
|
779
|
+
try:
|
|
780
|
+
print(f"📝 Analyzing content: '{content[:100]}{'...' if len(content) > 100 else ''}'")
|
|
781
|
+
|
|
782
|
+
result = memory_manager.route_memory_command(content)
|
|
783
|
+
|
|
784
|
+
if result.get("success") is False:
|
|
785
|
+
print(f"❌ Routing failed: {result.get('error', 'Unknown error')}")
|
|
786
|
+
return
|
|
787
|
+
|
|
788
|
+
target_agent = result.get("target_agent", "unknown")
|
|
789
|
+
section = result.get("section", "unknown")
|
|
790
|
+
confidence = result.get("confidence", 0.0)
|
|
791
|
+
reasoning = result.get("reasoning", "No reasoning provided")
|
|
792
|
+
|
|
793
|
+
print(f"\n🎯 Routing Decision:")
|
|
794
|
+
print(f" Target Agent: {target_agent}")
|
|
795
|
+
print(f" Section: {section}")
|
|
796
|
+
print(f" Confidence: {confidence:.2f}")
|
|
797
|
+
print(f" Reasoning: {reasoning}")
|
|
798
|
+
|
|
799
|
+
# Show agent scores if available
|
|
800
|
+
agent_scores = result.get("agent_scores", {})
|
|
801
|
+
if agent_scores:
|
|
802
|
+
print(f"\n📊 Agent Relevance Scores:")
|
|
803
|
+
sorted_scores = sorted(
|
|
804
|
+
[(agent, data['score']) for agent, data in agent_scores.items()],
|
|
805
|
+
key=lambda x: x[1], reverse=True
|
|
806
|
+
)
|
|
807
|
+
for agent, score in sorted_scores[:5]: # Show top 5
|
|
808
|
+
print(f" {agent}: {score:.3f}")
|
|
809
|
+
# Show matched keywords if available
|
|
810
|
+
if agent in agent_scores and agent_scores[agent].get('matched_keywords'):
|
|
811
|
+
keywords = ', '.join(agent_scores[agent]['matched_keywords'][:3])
|
|
812
|
+
print(f" Keywords: {keywords}")
|
|
813
|
+
|
|
814
|
+
except Exception as e:
|
|
815
|
+
print(f"❌ Error routing memory command: {e}")
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def _display_single_optimization_result(result):
|
|
819
|
+
"""Display optimization results for a single agent."""
|
|
820
|
+
agent_id = result.get("agent_id", "unknown")
|
|
821
|
+
original_size = result.get("original_size", 0)
|
|
822
|
+
optimized_size = result.get("optimized_size", 0)
|
|
823
|
+
size_reduction = result.get("size_reduction", 0)
|
|
824
|
+
size_reduction_percent = result.get("size_reduction_percent", 0)
|
|
825
|
+
|
|
826
|
+
print(f"✅ Optimization completed for {agent_id}")
|
|
827
|
+
print(f" Original size: {original_size:,} bytes")
|
|
828
|
+
print(f" Optimized size: {optimized_size:,} bytes")
|
|
829
|
+
print(f" Size reduction: {size_reduction:,} bytes ({size_reduction_percent}%)")
|
|
830
|
+
|
|
831
|
+
duplicates = result.get("duplicates_removed", 0)
|
|
832
|
+
consolidated = result.get("items_consolidated", 0)
|
|
833
|
+
reordered = result.get("items_reordered", 0)
|
|
834
|
+
|
|
835
|
+
if duplicates > 0:
|
|
836
|
+
print(f" Duplicates removed: {duplicates}")
|
|
837
|
+
if consolidated > 0:
|
|
838
|
+
print(f" Items consolidated: {consolidated}")
|
|
839
|
+
if reordered > 0:
|
|
840
|
+
print(f" Sections reordered: {reordered}")
|
|
841
|
+
|
|
842
|
+
backup_path = result.get("backup_created")
|
|
843
|
+
if backup_path:
|
|
844
|
+
print(f" Backup created: {backup_path}")
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
def _display_bulk_optimization_results(result):
|
|
848
|
+
"""Display optimization results for all agents."""
|
|
849
|
+
summary = result.get("summary", {})
|
|
850
|
+
|
|
851
|
+
print(f"✅ Bulk optimization completed")
|
|
852
|
+
print(f" Agents processed: {summary.get('agents_processed', 0)}")
|
|
853
|
+
print(f" Agents optimized: {summary.get('agents_optimized', 0)}")
|
|
854
|
+
print(f" Total size before: {summary.get('total_size_before', 0):,} bytes")
|
|
855
|
+
print(f" Total size after: {summary.get('total_size_after', 0):,} bytes")
|
|
856
|
+
print(f" Total reduction: {summary.get('total_size_reduction', 0):,} bytes ({summary.get('total_size_reduction_percent', 0)}%)")
|
|
857
|
+
print(f" Total duplicates removed: {summary.get('total_duplicates_removed', 0)}")
|
|
858
|
+
print(f" Total items consolidated: {summary.get('total_items_consolidated', 0)}")
|
|
859
|
+
|
|
860
|
+
# Show per-agent summary
|
|
861
|
+
agents_results = result.get("agents", {})
|
|
862
|
+
if agents_results:
|
|
863
|
+
print(f"\n📊 Per-agent results:")
|
|
864
|
+
for agent_id, agent_result in agents_results.items():
|
|
865
|
+
if agent_result.get("success"):
|
|
866
|
+
reduction = agent_result.get("size_reduction_percent", 0)
|
|
867
|
+
duplicates = agent_result.get("duplicates_removed", 0)
|
|
868
|
+
consolidated = agent_result.get("items_consolidated", 0)
|
|
869
|
+
|
|
870
|
+
status_parts = []
|
|
871
|
+
if duplicates > 0:
|
|
872
|
+
status_parts.append(f"{duplicates} dupes")
|
|
873
|
+
if consolidated > 0:
|
|
874
|
+
status_parts.append(f"{consolidated} consolidated")
|
|
875
|
+
|
|
876
|
+
status = f" ({', '.join(status_parts)})" if status_parts else ""
|
|
877
|
+
print(f" {agent_id}: {reduction}% reduction{status}")
|
|
878
|
+
else:
|
|
879
|
+
error = agent_result.get("error", "Unknown error")
|
|
880
|
+
print(f" {agent_id}: ❌ {error}")
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
def _output_all_memories_raw(memory_manager):
|
|
884
|
+
"""
|
|
885
|
+
Output all agent memories in raw JSON format.
|
|
886
|
+
|
|
887
|
+
WHY: Provides programmatic access to all agent memories for external tools,
|
|
888
|
+
scripts, or APIs that need to process or analyze the complete memory state.
|
|
889
|
+
|
|
890
|
+
Args:
|
|
891
|
+
memory_manager: AgentMemoryManager instance
|
|
892
|
+
"""
|
|
893
|
+
try:
|
|
894
|
+
raw_data = memory_manager.get_all_memories_raw()
|
|
895
|
+
print(json.dumps(raw_data, indent=2, ensure_ascii=False))
|
|
896
|
+
except Exception as e:
|
|
897
|
+
error_output = {
|
|
898
|
+
"success": False,
|
|
899
|
+
"error": f"Failed to retrieve all memories: {str(e)}",
|
|
900
|
+
"timestamp": datetime.now().isoformat()
|
|
901
|
+
}
|
|
902
|
+
print(json.dumps(error_output, indent=2))
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def _output_single_agent_raw(agent_id, memory_manager):
|
|
906
|
+
"""
|
|
907
|
+
Output single agent memory in raw JSON format.
|
|
908
|
+
|
|
909
|
+
WHY: Provides programmatic access to a specific agent's memory for
|
|
910
|
+
targeted analysis or processing by external tools.
|
|
911
|
+
|
|
912
|
+
Args:
|
|
913
|
+
agent_id: ID of the agent to retrieve memory for
|
|
914
|
+
memory_manager: AgentMemoryManager instance
|
|
915
|
+
"""
|
|
916
|
+
try:
|
|
917
|
+
# Get all memories and extract the specific agent
|
|
918
|
+
all_memories = memory_manager.get_all_memories_raw()
|
|
919
|
+
|
|
920
|
+
if not all_memories.get("success", False):
|
|
921
|
+
error_output = {
|
|
922
|
+
"success": False,
|
|
923
|
+
"error": all_memories.get("error", "Failed to retrieve memories"),
|
|
924
|
+
"timestamp": datetime.now().isoformat()
|
|
925
|
+
}
|
|
926
|
+
print(json.dumps(error_output, indent=2))
|
|
927
|
+
return
|
|
928
|
+
|
|
929
|
+
agents = all_memories.get("agents", {})
|
|
930
|
+
if agent_id not in agents:
|
|
931
|
+
error_output = {
|
|
932
|
+
"success": False,
|
|
933
|
+
"error": f"No memory found for agent: {agent_id}",
|
|
934
|
+
"available_agents": list(agents.keys()),
|
|
935
|
+
"timestamp": datetime.now().isoformat()
|
|
936
|
+
}
|
|
937
|
+
print(json.dumps(error_output, indent=2))
|
|
938
|
+
return
|
|
939
|
+
|
|
940
|
+
# Return single agent data with metadata
|
|
941
|
+
single_agent_output = {
|
|
942
|
+
"success": True,
|
|
943
|
+
"timestamp": all_memories["timestamp"],
|
|
944
|
+
"agent": agents[agent_id]
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
print(json.dumps(single_agent_output, indent=2, ensure_ascii=False))
|
|
948
|
+
|
|
949
|
+
except Exception as e:
|
|
950
|
+
error_output = {
|
|
951
|
+
"success": False,
|
|
952
|
+
"error": f"Failed to retrieve memory for agent {agent_id}: {str(e)}",
|
|
953
|
+
"timestamp": datetime.now().isoformat()
|
|
954
|
+
}
|
|
955
|
+
print(json.dumps(error_output, indent=2))
|