claude-mpm 3.4.27__py3-none-any.whl → 3.5.1__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 (123) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/INSTRUCTIONS.md +182 -299
  3. claude_mpm/agents/agent_loader.py +283 -57
  4. claude_mpm/agents/agent_loader_integration.py +6 -9
  5. claude_mpm/agents/base_agent.json +2 -1
  6. claude_mpm/agents/base_agent_loader.py +1 -1
  7. claude_mpm/cli/__init__.py +5 -7
  8. claude_mpm/cli/commands/__init__.py +0 -2
  9. claude_mpm/cli/commands/agents.py +1 -1
  10. claude_mpm/cli/commands/memory.py +1 -1
  11. claude_mpm/cli/commands/run.py +12 -0
  12. claude_mpm/cli/parser.py +0 -13
  13. claude_mpm/cli/utils.py +1 -1
  14. claude_mpm/config/__init__.py +44 -2
  15. claude_mpm/config/agent_config.py +348 -0
  16. claude_mpm/config/paths.py +322 -0
  17. claude_mpm/constants.py +0 -1
  18. claude_mpm/core/__init__.py +2 -5
  19. claude_mpm/core/agent_registry.py +63 -17
  20. claude_mpm/core/claude_runner.py +354 -43
  21. claude_mpm/core/config.py +7 -1
  22. claude_mpm/core/config_aliases.py +4 -3
  23. claude_mpm/core/config_paths.py +151 -0
  24. claude_mpm/core/factories.py +4 -50
  25. claude_mpm/core/logger.py +11 -13
  26. claude_mpm/core/service_registry.py +2 -2
  27. claude_mpm/dashboard/static/js/components/agent-inference.js +101 -25
  28. claude_mpm/dashboard/static/js/components/event-processor.js +3 -2
  29. claude_mpm/hooks/claude_hooks/hook_handler.py +343 -83
  30. claude_mpm/hooks/memory_integration_hook.py +1 -1
  31. claude_mpm/init.py +37 -6
  32. claude_mpm/scripts/socketio_daemon.py +6 -2
  33. claude_mpm/services/__init__.py +71 -3
  34. claude_mpm/services/agents/__init__.py +85 -0
  35. claude_mpm/services/agents/deployment/__init__.py +21 -0
  36. claude_mpm/services/{agent_deployment.py → agents/deployment/agent_deployment.py} +192 -41
  37. claude_mpm/services/{agent_lifecycle_manager.py → agents/deployment/agent_lifecycle_manager.py} +11 -10
  38. claude_mpm/services/agents/loading/__init__.py +11 -0
  39. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +9 -8
  40. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +2 -2
  41. claude_mpm/services/{framework_agent_loader.py → agents/loading/framework_agent_loader.py} +116 -40
  42. claude_mpm/services/agents/management/__init__.py +9 -0
  43. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +6 -5
  44. claude_mpm/services/agents/memory/__init__.py +21 -0
  45. claude_mpm/services/{agent_memory_manager.py → agents/memory/agent_memory_manager.py} +3 -3
  46. claude_mpm/services/agents/registry/__init__.py +29 -0
  47. claude_mpm/services/{agent_registry.py → agents/registry/agent_registry.py} +101 -16
  48. claude_mpm/services/{deployed_agent_discovery.py → agents/registry/deployed_agent_discovery.py} +12 -2
  49. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +6 -5
  50. claude_mpm/services/async_session_logger.py +584 -0
  51. claude_mpm/services/claude_session_logger.py +299 -0
  52. claude_mpm/services/framework_claude_md_generator/content_assembler.py +2 -2
  53. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +17 -17
  54. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +3 -3
  55. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +1 -1
  56. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +1 -1
  57. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +19 -24
  58. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +1 -1
  59. claude_mpm/services/framework_claude_md_generator.py +4 -2
  60. claude_mpm/services/memory/__init__.py +17 -0
  61. claude_mpm/services/{memory_builder.py → memory/builder.py} +3 -3
  62. claude_mpm/services/memory/cache/__init__.py +14 -0
  63. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +1 -1
  64. claude_mpm/services/memory/cache/simple_cache.py +317 -0
  65. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +1 -1
  66. claude_mpm/services/{memory_router.py → memory/router.py} +1 -1
  67. claude_mpm/services/optimized_hook_service.py +542 -0
  68. claude_mpm/services/project_registry.py +14 -8
  69. claude_mpm/services/response_tracker.py +237 -0
  70. claude_mpm/services/ticketing_service_original.py +4 -2
  71. claude_mpm/services/version_control/branch_strategy.py +3 -1
  72. claude_mpm/utils/paths.py +12 -10
  73. claude_mpm/utils/session_logging.py +114 -0
  74. claude_mpm/validation/agent_validator.py +2 -1
  75. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/METADATA +28 -20
  76. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/RECORD +83 -106
  77. claude_mpm/cli/commands/ui.py +0 -57
  78. claude_mpm/core/simple_runner.py +0 -1046
  79. claude_mpm/hooks/builtin/__init__.py +0 -1
  80. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  81. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  82. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  83. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  84. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  85. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  86. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  87. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  88. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  89. claude_mpm/orchestration/__init__.py +0 -6
  90. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  91. claude_mpm/orchestration/archive/factory.py +0 -215
  92. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  93. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  94. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  95. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  96. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  97. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  98. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  99. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  100. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  101. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  102. claude_mpm/schemas/workflow_validator.py +0 -411
  103. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  104. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  105. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  106. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  107. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  108. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  109. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  110. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  111. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  112. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  113. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  114. claude_mpm/ui/__init__.py +0 -1
  115. claude_mpm/ui/rich_terminal_ui.py +0 -295
  116. claude_mpm/ui/terminal_ui.py +0 -328
  117. /claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +0 -0
  118. /claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +0 -0
  119. /claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +0 -0
  120. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/WHEEL +0 -0
  121. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/entry_points.txt +0 -0
  122. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/licenses/LICENSE +0 -0
  123. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/top_level.txt +0 -0
@@ -1 +0,0 @@
1
- """Built-in hooks for claude-mpm."""
@@ -1,165 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Example logging hook for Claude MPM.
4
-
5
- This hook demonstrates how to capture and log all prompts and responses
6
- through the hook system, providing an alternative to built-in logging.
7
- """
8
-
9
- import json
10
- import os
11
- from datetime import datetime
12
- from pathlib import Path
13
- from typing import Dict, Any, Optional
14
-
15
- # Configure your logging directory
16
- LOG_DIR = Path.home() / ".claude-mpm-hook-logs"
17
- LOG_DIR.mkdir(exist_ok=True)
18
-
19
-
20
- def execute_pre_delegation_hook(agent: str, context: Dict[str, Any]) -> Dict[str, Any]:
21
- """
22
- Log task details before delegation.
23
-
24
- Args:
25
- agent: The agent being invoked
26
- context: Contains 'task' and other context data
27
-
28
- Returns:
29
- Empty dict (no modifications)
30
- """
31
- timestamp = datetime.now().isoformat()
32
- log_entry = {
33
- "timestamp": timestamp,
34
- "event": "pre_delegation",
35
- "agent": agent,
36
- "task": context.get("task", ""),
37
- "context": context
38
- }
39
-
40
- # Write to daily log file
41
- log_file = LOG_DIR / f"delegations_{datetime.now().strftime('%Y%m%d')}.jsonl"
42
- with open(log_file, 'a') as f:
43
- f.write(json.dumps(log_entry) + '\n')
44
-
45
- return {}
46
-
47
-
48
- def execute_post_delegation_hook(agent: str, result: Dict[str, Any]) -> Dict[str, Any]:
49
- """
50
- Log complete prompt and response after delegation.
51
-
52
- Args:
53
- agent: The agent that was invoked
54
- result: Contains task, response, execution_time, tokens
55
-
56
- Returns:
57
- Empty dict (no modifications)
58
- """
59
- timestamp = datetime.now().isoformat()
60
-
61
- # Extract data
62
- task = result.get("task", "")
63
- response = result.get("response", "")
64
- execution_time = result.get("execution_time", 0)
65
- tokens = result.get("tokens", 0)
66
-
67
- # Create detailed log entry
68
- log_entry = {
69
- "timestamp": timestamp,
70
- "event": "post_delegation",
71
- "agent": agent,
72
- "task": task,
73
- "response_length": len(response),
74
- "execution_time": execution_time,
75
- "tokens": tokens,
76
- "success": not response.startswith("Error:"),
77
- "response_preview": response[:500] + "..." if len(response) > 500 else response
78
- }
79
-
80
- # Write to agent-specific log
81
- agent_log_dir = LOG_DIR / "agents" / agent.lower()
82
- agent_log_dir.mkdir(parents=True, exist_ok=True)
83
-
84
- log_file = agent_log_dir / f"{datetime.now().strftime('%Y%m%d')}.jsonl"
85
- with open(log_file, 'a') as f:
86
- f.write(json.dumps(log_entry) + '\n')
87
-
88
- # Save full prompt/response if needed
89
- if os.environ.get("CLAUDE_MPM_HOOK_LOG_FULL", "").lower() == "true":
90
- # Create unique filename
91
- task_hash = str(hash(task))[-8:]
92
- prompt_file = agent_log_dir / f"prompt_{timestamp}_{task_hash}.txt"
93
- response_file = agent_log_dir / f"response_{timestamp}_{task_hash}.txt"
94
-
95
- # Note: We don't have access to the original prompt in post-delegation
96
- # To capture prompts, you'd need to store them in pre-delegation
97
- # and match them up using task hash or similar
98
-
99
- response_file.write_text(response)
100
-
101
- log_entry["response_file"] = str(response_file)
102
-
103
- return {}
104
-
105
-
106
- def execute_submit_hook(prompt: str, session_type: str) -> Dict[str, Any]:
107
- """
108
- Log user prompts at session start.
109
-
110
- Args:
111
- prompt: The user's input prompt
112
- session_type: Type of session (e.g., "subprocess")
113
-
114
- Returns:
115
- Empty dict (no modifications)
116
- """
117
- timestamp = datetime.now().isoformat()
118
- log_entry = {
119
- "timestamp": timestamp,
120
- "event": "user_submit",
121
- "session_type": session_type,
122
- "prompt": prompt,
123
- "prompt_length": len(prompt)
124
- }
125
-
126
- # Write to session log
127
- log_file = LOG_DIR / f"sessions_{datetime.now().strftime('%Y%m%d')}.jsonl"
128
- with open(log_file, 'a') as f:
129
- f.write(json.dumps(log_entry) + '\n')
130
-
131
- print(f"[Logging Hook] Logged user prompt to {log_file}")
132
-
133
- return {}
134
-
135
-
136
- # Optional: Hook metadata for registration
137
- HOOK_METADATA = {
138
- "name": "logging_hook",
139
- "description": "Comprehensive logging of all prompts and responses",
140
- "version": "1.0.0",
141
- "author": "claude-mpm",
142
- "events": ["pre_delegation", "post_delegation", "submit"],
143
- "config": {
144
- "log_dir": str(LOG_DIR),
145
- "full_logging": os.environ.get("CLAUDE_MPM_HOOK_LOG_FULL", "false")
146
- }
147
- }
148
-
149
-
150
- if __name__ == "__main__":
151
- # Test the hook
152
- print(f"Logging hook configured to write to: {LOG_DIR}")
153
- print("Set CLAUDE_MPM_HOOK_LOG_FULL=true to save complete responses")
154
-
155
- # Example usage
156
- execute_submit_hook("Test prompt", "test")
157
- execute_pre_delegation_hook("Engineer", {"task": "Test task"})
158
- execute_post_delegation_hook("Engineer", {
159
- "task": "Test task",
160
- "response": "Test response",
161
- "execution_time": 1.5,
162
- "tokens": 100
163
- })
164
-
165
- print(f"\nCheck logs in: {LOG_DIR}")
@@ -1,67 +0,0 @@
1
- """Example of how to register memory integration hooks.
2
-
3
- WHY: This demonstrates how to register the memory hooks with the HookService
4
- for automatic memory injection and learning extraction.
5
- """
6
-
7
- from claude_mpm.hooks.memory_integration_hook import (
8
- MemoryPreDelegationHook,
9
- MemoryPostDelegationHook
10
- )
11
- from claude_mpm.services.hook_service import HookService
12
- from claude_mpm.core.config import Config
13
-
14
-
15
- def register_memory_hooks(hook_service: HookService, config: Config = None):
16
- """Register memory integration hooks with the hook service.
17
-
18
- WHY: To enable automatic memory management, both hooks need to be
19
- registered with appropriate priorities:
20
- - Pre-hook runs early (priority 20) to inject memory into context
21
- - Post-hook runs late (priority 80) to extract learnings after processing
22
-
23
- Args:
24
- hook_service: The HookService instance to register with
25
- config: Optional configuration (will create default if not provided)
26
- """
27
- config = config or Config()
28
-
29
- # Only register if memory system is enabled
30
- if not config.get('memory.enabled', True):
31
- return
32
-
33
- # Register pre-delegation hook for memory injection
34
- pre_hook = MemoryPreDelegationHook(config)
35
- hook_service.register_hook(pre_hook)
36
-
37
- # Register post-delegation hook for learning extraction
38
- # Only if auto-learning is enabled
39
- if config.get('memory.auto_learning', False):
40
- post_hook = MemoryPostDelegationHook(config)
41
- hook_service.register_hook(post_hook)
42
-
43
-
44
- # Example usage:
45
- if __name__ == "__main__":
46
- # This would typically be done during application initialization
47
- config = Config(config={
48
- 'memory': {
49
- 'enabled': True,
50
- 'auto_learning': True,
51
- 'limits': {
52
- 'default_size_kb': 8,
53
- 'max_items_per_section': 20
54
- }
55
- }
56
- })
57
-
58
- # Create hook service (normally this would be passed from main app)
59
- from claude_mpm.services.hook_service import HookService
60
- hook_service = HookService(config)
61
-
62
- # Register memory hooks
63
- register_memory_hooks(hook_service, config)
64
-
65
- print("Memory hooks registered successfully!")
66
- print(f"Pre-delegation hook: {hook_service.get_hooks('pre_delegation')}")
67
- print(f"Post-delegation hook: {hook_service.get_hooks('post_delegation')}")
@@ -1,125 +0,0 @@
1
- """Hook to intercept and handle /mpm: commands."""
2
-
3
- import os
4
- import subprocess
5
- import sys
6
- from pathlib import Path
7
-
8
- from claude_mpm.hooks.base_hook import SubmitHook, HookContext, HookResult
9
- from claude_mpm.core.logger import get_logger
10
-
11
- logger = get_logger(__name__)
12
-
13
-
14
- class MpmCommandHook(SubmitHook):
15
- """Hook that intercepts /mpm commands and routes them to the command router."""
16
-
17
- def __init__(self):
18
- super().__init__(name="mpm_command", priority=1) # High priority to intercept early
19
- self.command_prefix = "/mpm "
20
- self.command_router_path = self._find_command_router()
21
-
22
- def _find_command_router(self) -> Path:
23
- """Find the command router script."""
24
- # Look for command router relative to project root
25
- possible_paths = [
26
- Path(".claude/scripts/command_router.py"),
27
- Path(__file__).parent.parent.parent.parent.parent / ".claude/scripts/command_router.py"
28
- ]
29
-
30
- for path in possible_paths:
31
- if path.exists():
32
- return path.resolve()
33
-
34
- # Default path
35
- return Path(".claude/scripts/command_router.py").resolve()
36
-
37
- def execute(self, context: HookContext) -> HookResult:
38
- """Check for /mpm commands and execute them directly."""
39
- try:
40
- prompt = context.data.get('prompt', '').strip()
41
-
42
- # Check if this is an /mpm command
43
- if not prompt.startswith(self.command_prefix):
44
- # Not our command, pass through
45
- return HookResult(
46
- success=True,
47
- data=context.data,
48
- modified=False
49
- )
50
-
51
- # Extract command and arguments
52
- command_line = prompt[len(self.command_prefix):].strip()
53
- parts = command_line.split()
54
-
55
- if not parts:
56
- return HookResult(
57
- success=True,
58
- data={
59
- 'prompt': '',
60
- 'response': "No command specified. Available commands: test",
61
- 'skip_llm': True
62
- },
63
- modified=True,
64
- metadata={'command_handled': True}
65
- )
66
-
67
- command = parts[0]
68
- args = parts[1:]
69
-
70
- logger.info(f"Executing /mpm {command} with args: {args}")
71
-
72
- # Execute command using command router
73
- try:
74
- # Run the command router script
75
- cmd = [sys.executable, str(self.command_router_path), command] + args
76
- result = subprocess.run(
77
- cmd,
78
- capture_output=True,
79
- text=True,
80
- check=False
81
- )
82
-
83
- if result.returncode == 0:
84
- response = result.stdout.strip()
85
- else:
86
- response = f"Command failed: {result.stderr.strip() or 'Unknown error'}"
87
-
88
- logger.info(f"Command result: {response}")
89
-
90
- # Return result without going to LLM
91
- return HookResult(
92
- success=True,
93
- data={
94
- 'prompt': '', # Clear prompt to prevent LLM processing
95
- 'response': response,
96
- 'skip_llm': True # Flag to skip LLM
97
- },
98
- modified=True,
99
- metadata={
100
- 'command_handled': True,
101
- 'command': command,
102
- 'args': args
103
- }
104
- )
105
-
106
- except Exception as e:
107
- logger.error(f"Failed to execute command: {e}")
108
- return HookResult(
109
- success=True,
110
- data={
111
- 'prompt': '',
112
- 'response': f"Error executing command: {str(e)}",
113
- 'skip_llm': True
114
- },
115
- modified=True,
116
- metadata={'command_error': str(e)}
117
- )
118
-
119
- except Exception as e:
120
- logger.error(f"MPM command hook failed: {e}")
121
- # On error, pass through to normal processing
122
- return HookResult(
123
- success=False,
124
- error=str(e)
125
- )
@@ -1,124 +0,0 @@
1
- """Example post-delegation hook implementation."""
2
-
3
- import json
4
- import re
5
- from typing import Dict, Any, List
6
-
7
- from claude_mpm.hooks.base_hook import PostDelegationHook, HookContext, HookResult
8
- from claude_mpm.core.logger import get_logger
9
-
10
- logger = get_logger(__name__)
11
-
12
-
13
- class ResultValidatorHook(PostDelegationHook):
14
- """Hook that validates agent results for quality and completeness."""
15
-
16
- def __init__(self):
17
- super().__init__(name="result_validator", priority=10)
18
-
19
- def execute(self, context: HookContext) -> HookResult:
20
- """Validate agent results."""
21
- try:
22
- result = context.data.get('result', {})
23
- agent = context.data.get('agent', 'unknown')
24
-
25
- # Validation checks
26
- issues = []
27
-
28
- # Check for empty results
29
- if not result:
30
- issues.append("Empty result returned")
31
-
32
- # Check for error indicators
33
- error_patterns = ['error', 'failed', 'exception', 'traceback']
34
- result_str = json.dumps(result).lower()
35
- for pattern in error_patterns:
36
- if pattern in result_str and 'success' not in result:
37
- issues.append(f"Result contains '{pattern}' indicator")
38
-
39
- # Agent-specific validation
40
- if agent.lower() == 'engineer' and 'code' in str(result):
41
- # Check for code quality indicators
42
- if 'todo' in result_str or 'fixme' in result_str:
43
- issues.append("Code contains TODO/FIXME comments")
44
-
45
- if issues:
46
- logger.warning(f"Validation issues found: {issues}")
47
- return HookResult(
48
- success=True,
49
- data={
50
- 'result': result,
51
- 'validation_issues': issues
52
- },
53
- modified=True,
54
- metadata={'issues_count': len(issues)}
55
- )
56
- else:
57
- return HookResult(
58
- success=True,
59
- data=context.data,
60
- modified=False,
61
- metadata={'validated': True}
62
- )
63
-
64
- except Exception as e:
65
- logger.error(f"Result validation failed: {e}")
66
- return HookResult(
67
- success=False,
68
- error=str(e)
69
- )
70
-
71
-
72
- class ResultMetricsHook(PostDelegationHook):
73
- """Hook that collects metrics from agent results."""
74
-
75
- def __init__(self):
76
- super().__init__(name="result_metrics", priority=50)
77
-
78
- def execute(self, context: HookContext) -> HookResult:
79
- """Collect metrics from agent results."""
80
- try:
81
- result = context.data.get('result', {})
82
- agent = context.data.get('agent', 'unknown')
83
- execution_time = context.metadata.get('execution_time_ms', 0)
84
-
85
- # Collect metrics
86
- metrics = {
87
- 'agent': agent,
88
- 'execution_time_ms': execution_time,
89
- 'result_size_bytes': len(json.dumps(result).encode()),
90
- 'timestamp': context.timestamp.isoformat()
91
- }
92
-
93
- # Agent-specific metrics
94
- if agent.lower() == 'engineer':
95
- # Count code-related metrics
96
- code_content = str(result)
97
- metrics['lines_of_code'] = code_content.count('\n')
98
- metrics['functions_created'] = len(re.findall(r'def\s+\w+', code_content))
99
- metrics['classes_created'] = len(re.findall(r'class\s+\w+', code_content))
100
-
101
- elif agent.lower() == 'qa':
102
- # Count test-related metrics
103
- test_content = str(result)
104
- metrics['tests_count'] = len(re.findall(r'test_\w+', test_content))
105
- metrics['assertions_count'] = len(re.findall(r'assert\s+', test_content))
106
-
107
- logger.info(f"Collected metrics: {metrics}")
108
-
109
- return HookResult(
110
- success=True,
111
- data={
112
- 'result': result,
113
- 'metrics': metrics
114
- },
115
- modified=True,
116
- metadata=metrics
117
- )
118
-
119
- except Exception as e:
120
- logger.error(f"Metrics collection failed: {e}")
121
- return HookResult(
122
- success=False,
123
- error=str(e)
124
- )
@@ -1,125 +0,0 @@
1
- """Example pre-delegation hook implementation."""
2
-
3
- import json
4
- from typing import Dict, Any, List
5
-
6
- from claude_mpm.hooks.base_hook import PreDelegationHook, HookContext, HookResult
7
- from claude_mpm.core.logger import get_logger
8
-
9
- logger = get_logger(__name__)
10
-
11
-
12
- class ContextFilterHook(PreDelegationHook):
13
- """Hook that filters sensitive information from context before delegation."""
14
-
15
- def __init__(self):
16
- super().__init__(name="context_filter", priority=10)
17
- self.sensitive_keys = {
18
- 'api_key', 'secret', 'password', 'token',
19
- 'private_key', 'credentials', 'auth'
20
- }
21
-
22
- def execute(self, context: HookContext) -> HookResult:
23
- """Filter sensitive information from delegation context."""
24
- try:
25
- agent_context = context.data.get('context', {})
26
- filtered_context = self._filter_sensitive(agent_context)
27
-
28
- if filtered_context != agent_context:
29
- logger.info("Filtered sensitive information from context")
30
- return HookResult(
31
- success=True,
32
- data={
33
- 'agent': context.data.get('agent'),
34
- 'context': filtered_context
35
- },
36
- modified=True,
37
- metadata={'filtered_keys': True}
38
- )
39
- else:
40
- return HookResult(
41
- success=True,
42
- data=context.data,
43
- modified=False
44
- )
45
-
46
- except Exception as e:
47
- logger.error(f"Context filtering failed: {e}")
48
- return HookResult(
49
- success=False,
50
- error=str(e)
51
- )
52
-
53
- def _filter_sensitive(self, data: Any) -> Any:
54
- """Recursively filter sensitive keys from data."""
55
- if isinstance(data, dict):
56
- filtered = {}
57
- for key, value in data.items():
58
- if any(sensitive in key.lower() for sensitive in self.sensitive_keys):
59
- filtered[key] = "[REDACTED]"
60
- else:
61
- filtered[key] = self._filter_sensitive(value)
62
- return filtered
63
- elif isinstance(data, list):
64
- return [self._filter_sensitive(item) for item in data]
65
- else:
66
- return data
67
-
68
-
69
- class AgentCapabilityEnhancerHook(PreDelegationHook):
70
- """Hook that enhances agent context with additional capabilities."""
71
-
72
- def __init__(self):
73
- super().__init__(name="capability_enhancer", priority=30)
74
- self.agent_enhancements = {
75
- 'engineer': {
76
- 'tools': ['code_analysis', 'refactoring', 'testing'],
77
- 'context': 'You have access to advanced code analysis tools.'
78
- },
79
- 'researcher': {
80
- 'tools': ['web_search', 'document_analysis'],
81
- 'context': 'You can search the web and analyze documents.'
82
- },
83
- 'qa': {
84
- 'tools': ['test_runner', 'coverage_analyzer'],
85
- 'context': 'You have access to comprehensive testing tools.'
86
- }
87
- }
88
-
89
- def execute(self, context: HookContext) -> HookResult:
90
- """Enhance agent capabilities based on agent type."""
91
- try:
92
- agent_type = context.data.get('agent', '').lower()
93
-
94
- if agent_type in self.agent_enhancements:
95
- enhancement = self.agent_enhancements[agent_type]
96
-
97
- # Add enhancements to context
98
- enhanced_context = context.data.get('context', {}).copy()
99
- enhanced_context['additional_tools'] = enhancement['tools']
100
- enhanced_context['enhanced_context'] = enhancement['context']
101
-
102
- logger.info(f"Enhanced {agent_type} agent with additional capabilities")
103
-
104
- return HookResult(
105
- success=True,
106
- data={
107
- 'agent': context.data.get('agent'),
108
- 'context': enhanced_context
109
- },
110
- modified=True,
111
- metadata={'enhancements_applied': True}
112
- )
113
- else:
114
- return HookResult(
115
- success=True,
116
- data=context.data,
117
- modified=False
118
- )
119
-
120
- except Exception as e:
121
- logger.error(f"Capability enhancement failed: {e}")
122
- return HookResult(
123
- success=False,
124
- error=str(e)
125
- )