claude-mpm 0.3.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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (159) hide show
  1. claude_mpm/__init__.py +17 -0
  2. claude_mpm/__main__.py +14 -0
  3. claude_mpm/_version.py +32 -0
  4. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +88 -0
  5. claude_mpm/agents/INSTRUCTIONS.md +375 -0
  6. claude_mpm/agents/__init__.py +118 -0
  7. claude_mpm/agents/agent_loader.py +621 -0
  8. claude_mpm/agents/agent_loader_integration.py +229 -0
  9. claude_mpm/agents/agents_metadata.py +204 -0
  10. claude_mpm/agents/base_agent.json +27 -0
  11. claude_mpm/agents/base_agent_loader.py +519 -0
  12. claude_mpm/agents/schema/agent_schema.json +160 -0
  13. claude_mpm/agents/system_agent_config.py +587 -0
  14. claude_mpm/agents/templates/__init__.py +101 -0
  15. claude_mpm/agents/templates/data_engineer_agent.json +46 -0
  16. claude_mpm/agents/templates/documentation_agent.json +45 -0
  17. claude_mpm/agents/templates/engineer_agent.json +49 -0
  18. claude_mpm/agents/templates/ops_agent.json +46 -0
  19. claude_mpm/agents/templates/qa_agent.json +45 -0
  20. claude_mpm/agents/templates/research_agent.json +49 -0
  21. claude_mpm/agents/templates/security_agent.json +46 -0
  22. claude_mpm/agents/templates/update-optimized-specialized-agents.json +374 -0
  23. claude_mpm/agents/templates/version_control_agent.json +46 -0
  24. claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +6 -0
  25. claude_mpm/cli.py +655 -0
  26. claude_mpm/cli_main.py +13 -0
  27. claude_mpm/cli_module/__init__.py +15 -0
  28. claude_mpm/cli_module/args.py +222 -0
  29. claude_mpm/cli_module/commands.py +203 -0
  30. claude_mpm/cli_module/migration_example.py +183 -0
  31. claude_mpm/cli_module/refactoring_guide.md +253 -0
  32. claude_mpm/cli_old/__init__.py +1 -0
  33. claude_mpm/cli_old/ticket_cli.py +102 -0
  34. claude_mpm/config/__init__.py +5 -0
  35. claude_mpm/config/hook_config.py +42 -0
  36. claude_mpm/constants.py +150 -0
  37. claude_mpm/core/__init__.py +45 -0
  38. claude_mpm/core/agent_name_normalizer.py +248 -0
  39. claude_mpm/core/agent_registry.py +627 -0
  40. claude_mpm/core/agent_registry.py.bak +312 -0
  41. claude_mpm/core/agent_session_manager.py +273 -0
  42. claude_mpm/core/base_service.py +747 -0
  43. claude_mpm/core/base_service.py.bak +406 -0
  44. claude_mpm/core/config.py +334 -0
  45. claude_mpm/core/config_aliases.py +292 -0
  46. claude_mpm/core/container.py +347 -0
  47. claude_mpm/core/factories.py +281 -0
  48. claude_mpm/core/framework_loader.py +472 -0
  49. claude_mpm/core/injectable_service.py +206 -0
  50. claude_mpm/core/interfaces.py +539 -0
  51. claude_mpm/core/logger.py +468 -0
  52. claude_mpm/core/minimal_framework_loader.py +107 -0
  53. claude_mpm/core/mixins.py +150 -0
  54. claude_mpm/core/service_registry.py +299 -0
  55. claude_mpm/core/session_manager.py +190 -0
  56. claude_mpm/core/simple_runner.py +511 -0
  57. claude_mpm/core/tool_access_control.py +173 -0
  58. claude_mpm/hooks/README.md +243 -0
  59. claude_mpm/hooks/__init__.py +5 -0
  60. claude_mpm/hooks/base_hook.py +154 -0
  61. claude_mpm/hooks/builtin/__init__.py +1 -0
  62. claude_mpm/hooks/builtin/logging_hook_example.py +165 -0
  63. claude_mpm/hooks/builtin/post_delegation_hook_example.py +124 -0
  64. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +125 -0
  65. claude_mpm/hooks/builtin/submit_hook_example.py +100 -0
  66. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +237 -0
  67. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +239 -0
  68. claude_mpm/hooks/builtin/workflow_start_hook.py +181 -0
  69. claude_mpm/hooks/hook_client.py +264 -0
  70. claude_mpm/hooks/hook_runner.py +370 -0
  71. claude_mpm/hooks/json_rpc_executor.py +259 -0
  72. claude_mpm/hooks/json_rpc_hook_client.py +319 -0
  73. claude_mpm/hooks/tool_call_interceptor.py +204 -0
  74. claude_mpm/init.py +246 -0
  75. claude_mpm/orchestration/SUBPROCESS_DESIGN.md +66 -0
  76. claude_mpm/orchestration/__init__.py +6 -0
  77. claude_mpm/orchestration/archive/direct_orchestrator.py +195 -0
  78. claude_mpm/orchestration/archive/factory.py +215 -0
  79. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +188 -0
  80. claude_mpm/orchestration/archive/hook_integration_example.py +178 -0
  81. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +826 -0
  82. claude_mpm/orchestration/archive/orchestrator.py +501 -0
  83. claude_mpm/orchestration/archive/pexpect_orchestrator.py +252 -0
  84. claude_mpm/orchestration/archive/pty_orchestrator.py +270 -0
  85. claude_mpm/orchestration/archive/simple_orchestrator.py +82 -0
  86. claude_mpm/orchestration/archive/subprocess_orchestrator.py +801 -0
  87. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +278 -0
  88. claude_mpm/orchestration/archive/wrapper_orchestrator.py +187 -0
  89. claude_mpm/scripts/__init__.py +1 -0
  90. claude_mpm/scripts/ticket.py +269 -0
  91. claude_mpm/services/__init__.py +10 -0
  92. claude_mpm/services/agent_deployment.py +955 -0
  93. claude_mpm/services/agent_lifecycle_manager.py +948 -0
  94. claude_mpm/services/agent_management_service.py +596 -0
  95. claude_mpm/services/agent_modification_tracker.py +841 -0
  96. claude_mpm/services/agent_profile_loader.py +606 -0
  97. claude_mpm/services/agent_registry.py +677 -0
  98. claude_mpm/services/base_agent_manager.py +380 -0
  99. claude_mpm/services/framework_agent_loader.py +337 -0
  100. claude_mpm/services/framework_claude_md_generator/README.md +92 -0
  101. claude_mpm/services/framework_claude_md_generator/__init__.py +206 -0
  102. claude_mpm/services/framework_claude_md_generator/content_assembler.py +151 -0
  103. claude_mpm/services/framework_claude_md_generator/content_validator.py +126 -0
  104. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +137 -0
  105. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +106 -0
  106. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +582 -0
  107. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +97 -0
  108. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +27 -0
  109. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +23 -0
  110. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +23 -0
  111. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +20 -0
  112. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +26 -0
  113. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +30 -0
  114. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +37 -0
  115. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +111 -0
  116. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +89 -0
  117. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +39 -0
  118. claude_mpm/services/framework_claude_md_generator/section_manager.py +106 -0
  119. claude_mpm/services/framework_claude_md_generator/version_manager.py +121 -0
  120. claude_mpm/services/framework_claude_md_generator.py +621 -0
  121. claude_mpm/services/hook_service.py +388 -0
  122. claude_mpm/services/hook_service_manager.py +223 -0
  123. claude_mpm/services/json_rpc_hook_manager.py +92 -0
  124. claude_mpm/services/parent_directory_manager/README.md +83 -0
  125. claude_mpm/services/parent_directory_manager/__init__.py +577 -0
  126. claude_mpm/services/parent_directory_manager/backup_manager.py +258 -0
  127. claude_mpm/services/parent_directory_manager/config_manager.py +210 -0
  128. claude_mpm/services/parent_directory_manager/deduplication_manager.py +279 -0
  129. claude_mpm/services/parent_directory_manager/framework_protector.py +143 -0
  130. claude_mpm/services/parent_directory_manager/operations.py +186 -0
  131. claude_mpm/services/parent_directory_manager/state_manager.py +624 -0
  132. claude_mpm/services/parent_directory_manager/template_deployer.py +579 -0
  133. claude_mpm/services/parent_directory_manager/validation_manager.py +378 -0
  134. claude_mpm/services/parent_directory_manager/version_control_helper.py +339 -0
  135. claude_mpm/services/parent_directory_manager/version_manager.py +222 -0
  136. claude_mpm/services/shared_prompt_cache.py +819 -0
  137. claude_mpm/services/ticket_manager.py +213 -0
  138. claude_mpm/services/ticket_manager_di.py +318 -0
  139. claude_mpm/services/ticketing_service_original.py +508 -0
  140. claude_mpm/services/version_control/VERSION +1 -0
  141. claude_mpm/services/version_control/__init__.py +70 -0
  142. claude_mpm/services/version_control/branch_strategy.py +670 -0
  143. claude_mpm/services/version_control/conflict_resolution.py +744 -0
  144. claude_mpm/services/version_control/git_operations.py +784 -0
  145. claude_mpm/services/version_control/semantic_versioning.py +703 -0
  146. claude_mpm/ui/__init__.py +1 -0
  147. claude_mpm/ui/rich_terminal_ui.py +295 -0
  148. claude_mpm/ui/terminal_ui.py +328 -0
  149. claude_mpm/utils/__init__.py +16 -0
  150. claude_mpm/utils/config_manager.py +468 -0
  151. claude_mpm/utils/import_migration_example.py +80 -0
  152. claude_mpm/utils/imports.py +182 -0
  153. claude_mpm/utils/path_operations.py +357 -0
  154. claude_mpm/utils/paths.py +289 -0
  155. claude_mpm-0.3.0.dist-info/METADATA +290 -0
  156. claude_mpm-0.3.0.dist-info/RECORD +159 -0
  157. claude_mpm-0.3.0.dist-info/WHEEL +5 -0
  158. claude_mpm-0.3.0.dist-info/entry_points.txt +4 -0
  159. claude_mpm-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,215 @@
1
+ """Orchestrator factory for creating orchestrators based on mode and configuration."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+ from typing import Optional, Dict, Type, Any
6
+ from enum import Enum
7
+
8
+ from ..core.logger import get_logger
9
+ from .orchestrator import MPMOrchestrator
10
+ from .system_prompt_orchestrator import SystemPromptOrchestrator
11
+ from .subprocess_orchestrator import SubprocessOrchestrator
12
+ from .interactive_subprocess_orchestrator import InteractiveSubprocessOrchestrator
13
+
14
+
15
+ class OrchestratorMode(Enum):
16
+ """Available orchestrator modes."""
17
+ SYSTEM_PROMPT = "system_prompt"
18
+ SUBPROCESS = "subprocess"
19
+ INTERACTIVE_SUBPROCESS = "interactive_subprocess"
20
+ DIRECT = "direct"
21
+ PTY = "pty"
22
+ WRAPPER = "wrapper"
23
+ SIMPLE = "simple"
24
+
25
+
26
+ class OrchestratorFactory:
27
+ """Factory for creating orchestrators based on mode and configuration.
28
+
29
+ This factory simplifies orchestrator selection and reduces complexity
30
+ in the run_session function by centralizing the logic for choosing
31
+ and instantiating the appropriate orchestrator.
32
+ """
33
+
34
+ # Registry of available orchestrators
35
+ _registry: Dict[OrchestratorMode, Type[MPMOrchestrator]] = {
36
+ OrchestratorMode.SYSTEM_PROMPT: SystemPromptOrchestrator,
37
+ OrchestratorMode.SUBPROCESS: SubprocessOrchestrator,
38
+ OrchestratorMode.INTERACTIVE_SUBPROCESS: InteractiveSubprocessOrchestrator,
39
+ }
40
+
41
+ def __init__(self):
42
+ """Initialize the orchestrator factory."""
43
+ self.logger = get_logger(self.__class__.__name__)
44
+ self._discover_orchestrators()
45
+
46
+ def _discover_orchestrators(self):
47
+ """Discover and register additional orchestrators.
48
+
49
+ This method enables automatic discovery of new orchestrator types
50
+ without modifying the factory code.
51
+ """
52
+ # Try to import optional orchestrators
53
+ try:
54
+ from .direct_orchestrator import DirectOrchestrator
55
+ self._registry[OrchestratorMode.DIRECT] = DirectOrchestrator
56
+ self.logger.debug("Registered DirectOrchestrator")
57
+ except ImportError:
58
+ self.logger.debug("DirectOrchestrator not available")
59
+
60
+ try:
61
+ from .pty_orchestrator import PTYOrchestrator
62
+ self._registry[OrchestratorMode.PTY] = PTYOrchestrator
63
+ self.logger.debug("Registered PTYOrchestrator")
64
+ except ImportError:
65
+ self.logger.debug("PTYOrchestrator not available")
66
+
67
+ try:
68
+ from .wrapper_orchestrator import WrapperOrchestrator
69
+ self._registry[OrchestratorMode.WRAPPER] = WrapperOrchestrator
70
+ self.logger.debug("Registered WrapperOrchestrator")
71
+ except ImportError:
72
+ self.logger.debug("WrapperOrchestrator not available")
73
+
74
+ try:
75
+ from .simple_orchestrator import SimpleOrchestrator
76
+ self._registry[OrchestratorMode.SIMPLE] = SimpleOrchestrator
77
+ self.logger.debug("Registered SimpleOrchestrator")
78
+ except ImportError:
79
+ self.logger.debug("SimpleOrchestrator not available")
80
+
81
+ def create_orchestrator(
82
+ self,
83
+ mode: Optional[str] = None,
84
+ config: Optional[Dict[str, Any]] = None
85
+ ) -> MPMOrchestrator:
86
+ """Create an orchestrator based on mode and configuration.
87
+
88
+ Args:
89
+ mode: Orchestrator mode (string or OrchestratorMode enum)
90
+ config: Configuration dictionary containing:
91
+ - framework_path: Path to framework directory
92
+ - agents_dir: Custom agents directory
93
+ - log_level: Logging level (OFF, INFO, DEBUG)
94
+ - log_dir: Custom log directory
95
+ - hook_manager: Hook service manager instance
96
+ - enable_todo_hijacking: Enable TODO hijacking (subprocess mode)
97
+ - subprocess: Use subprocess orchestration
98
+ - interactive_subprocess: Use interactive subprocess
99
+ - Any other orchestrator-specific parameters
100
+
101
+ Returns:
102
+ Configured orchestrator instance
103
+
104
+ Raises:
105
+ ValueError: If mode is invalid or orchestrator creation fails
106
+ """
107
+ if config is None:
108
+ config = {}
109
+
110
+ # Determine orchestrator mode
111
+ orchestrator_mode = self._determine_mode(mode, config)
112
+
113
+ # Validate mode
114
+ if orchestrator_mode not in self._registry:
115
+ available = ", ".join(m.value for m in self._registry.keys())
116
+ raise ValueError(
117
+ f"Invalid orchestrator mode: {orchestrator_mode.value}. "
118
+ f"Available modes: {available}"
119
+ )
120
+
121
+ # Get orchestrator class
122
+ orchestrator_class = self._registry[orchestrator_mode]
123
+
124
+ # Extract common parameters
125
+ common_params = {
126
+ "framework_path": config.get("framework_path"),
127
+ "agents_dir": config.get("agents_dir"),
128
+ "log_level": config.get("log_level", "OFF"),
129
+ "log_dir": config.get("log_dir"),
130
+ }
131
+
132
+ # Add hook manager if available
133
+ if "hook_manager" in config:
134
+ common_params["hook_manager"] = config["hook_manager"]
135
+
136
+ # Add mode-specific parameters
137
+ if orchestrator_mode == OrchestratorMode.SUBPROCESS:
138
+ common_params["enable_todo_hijacking"] = config.get("enable_todo_hijacking", False)
139
+
140
+ try:
141
+ # Create orchestrator instance
142
+ orchestrator = orchestrator_class(**common_params)
143
+
144
+ # Configure additional settings
145
+ if "no_tickets" in config and config["no_tickets"]:
146
+ orchestrator.ticket_creation_enabled = False
147
+ self.logger.info("Ticket creation disabled for orchestrator")
148
+
149
+ self.logger.info(
150
+ f"Created {orchestrator_class.__name__} "
151
+ f"(mode: {orchestrator_mode.value})"
152
+ )
153
+
154
+ return orchestrator
155
+
156
+ except Exception as e:
157
+ self.logger.error(f"Failed to create orchestrator: {e}")
158
+ raise ValueError(f"Failed to create orchestrator: {e}") from e
159
+
160
+ def _determine_mode(
161
+ self,
162
+ mode: Optional[str],
163
+ config: Dict[str, Any]
164
+ ) -> OrchestratorMode:
165
+ """Determine orchestrator mode from explicit mode or config flags.
166
+
167
+ Args:
168
+ mode: Explicit mode string
169
+ config: Configuration dictionary
170
+
171
+ Returns:
172
+ OrchestratorMode enum value
173
+ """
174
+ # Always use subprocess orchestrator for simplicity
175
+ # This provides consistent behavior in both interactive and non-interactive modes
176
+ return OrchestratorMode.SUBPROCESS
177
+
178
+ def list_available_modes(self) -> Dict[str, Dict[str, Any]]:
179
+ """List all available orchestrator modes with metadata.
180
+
181
+ Returns:
182
+ Dictionary mapping mode names to metadata
183
+ """
184
+ modes = {}
185
+ for mode, orchestrator_class in self._registry.items():
186
+ modes[mode.value] = {
187
+ "class": orchestrator_class.__name__,
188
+ "module": orchestrator_class.__module__,
189
+ "description": orchestrator_class.__doc__.strip() if orchestrator_class.__doc__ else "No description",
190
+ }
191
+ return modes
192
+
193
+ def register_orchestrator(
194
+ self,
195
+ mode: OrchestratorMode,
196
+ orchestrator_class: Type[MPMOrchestrator]
197
+ ):
198
+ """Register a custom orchestrator.
199
+
200
+ Args:
201
+ mode: Orchestrator mode
202
+ orchestrator_class: Orchestrator class (must inherit from MPMOrchestrator)
203
+
204
+ Raises:
205
+ ValueError: If orchestrator class is invalid
206
+ """
207
+ if not issubclass(orchestrator_class, MPMOrchestrator):
208
+ raise ValueError(
209
+ f"{orchestrator_class.__name__} must inherit from MPMOrchestrator"
210
+ )
211
+
212
+ self._registry[mode] = orchestrator_class
213
+ self.logger.info(
214
+ f"Registered {orchestrator_class.__name__} for mode {mode.value}"
215
+ )
@@ -0,0 +1,188 @@
1
+ """Example orchestrator that integrates with the hook service."""
2
+
3
+ import asyncio
4
+ import logging
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from src.hooks.hook_client import get_hook_client, HookServiceClient
8
+ from src.hooks.base_hook import HookType
9
+ from src.orchestration.orchestrator import Orchestrator
10
+ from src.services.ticket_manager import TicketManager
11
+ from src.utils.logger import get_logger
12
+
13
+ logger = get_logger(__name__)
14
+
15
+
16
+ class HookEnabledOrchestrator(Orchestrator):
17
+ """Orchestrator that integrates with the centralized hook service."""
18
+
19
+ def __init__(self, *args, **kwargs):
20
+ """Initialize hook-enabled orchestrator."""
21
+ super().__init__(*args, **kwargs)
22
+
23
+ # Initialize hook client
24
+ self.hook_client = get_hook_client()
25
+
26
+ # Check hook service health
27
+ health = self.hook_client.health_check()
28
+ if health.get('status') == 'healthy':
29
+ logger.info(f"Hook service is healthy with {health.get('hooks_count', 0)} hooks")
30
+ else:
31
+ logger.warning(f"Hook service is not available: {health.get('error')}")
32
+
33
+ async def process_prompt(self, prompt: str) -> str:
34
+ """Process user prompt with hook integration.
35
+
36
+ Args:
37
+ prompt: User prompt to process
38
+
39
+ Returns:
40
+ Response from orchestration
41
+ """
42
+ try:
43
+ # Execute submit hooks
44
+ logger.debug("Executing submit hooks...")
45
+ submit_results = self.hook_client.execute_submit_hook(
46
+ prompt=prompt,
47
+ session_id=getattr(self, 'session_id', None)
48
+ )
49
+
50
+ # Get modified prompt data
51
+ modified_data = self.hook_client.get_modified_data(submit_results)
52
+ if modified_data.get('prompt'):
53
+ prompt = modified_data['prompt']
54
+
55
+ # Check for priority override
56
+ if modified_data.get('priority'):
57
+ logger.info(f"Priority detected: {modified_data['priority']}")
58
+
59
+ # Process prompt through normal orchestration
60
+ response = await super().process_prompt(prompt)
61
+
62
+ # Execute ticket extraction hooks on the conversation
63
+ logger.debug("Executing ticket extraction hooks...")
64
+ extraction_results = self.hook_client.execute_ticket_extraction_hook(
65
+ content={
66
+ 'prompt': prompt,
67
+ 'response': response
68
+ }
69
+ )
70
+
71
+ # Extract and create tickets
72
+ tickets = self.hook_client.get_extracted_tickets(extraction_results)
73
+ if tickets:
74
+ logger.info(f"Extracted {len(tickets)} tickets from conversation")
75
+ await self._create_tickets(tickets)
76
+
77
+ return response
78
+
79
+ except Exception as e:
80
+ logger.error(f"Error in hook-enabled orchestration: {e}")
81
+ # Fallback to normal orchestration if hooks fail
82
+ return await super().process_prompt(prompt)
83
+
84
+ async def delegate_to_agent(self, agent_name: str, context: Dict[str, Any]) -> Any:
85
+ """Delegate to agent with hook integration.
86
+
87
+ Args:
88
+ agent_name: Name of agent to delegate to
89
+ context: Context to pass to agent
90
+
91
+ Returns:
92
+ Result from agent
93
+ """
94
+ try:
95
+ # Execute pre-delegation hooks
96
+ logger.debug(f"Executing pre-delegation hooks for {agent_name}...")
97
+ pre_results = self.hook_client.execute_pre_delegation_hook(
98
+ agent=agent_name,
99
+ context=context
100
+ )
101
+
102
+ # Get modified context
103
+ modified_data = self.hook_client.get_modified_data(pre_results)
104
+ if 'context' in modified_data:
105
+ context = modified_data['context']
106
+ logger.debug("Context modified by pre-delegation hooks")
107
+
108
+ # Delegate to agent
109
+ result = await super().delegate_to_agent(agent_name, context)
110
+
111
+ # Execute post-delegation hooks
112
+ logger.debug(f"Executing post-delegation hooks for {agent_name}...")
113
+ post_results = self.hook_client.execute_post_delegation_hook(
114
+ agent=agent_name,
115
+ result=result,
116
+ execution_time_ms=context.get('execution_time_ms')
117
+ )
118
+
119
+ # Get modified result
120
+ modified_data = self.hook_client.get_modified_data(post_results)
121
+ if 'result' in modified_data:
122
+ result = modified_data['result']
123
+ logger.debug("Result modified by post-delegation hooks")
124
+
125
+ # Check for validation issues
126
+ for post_result in post_results:
127
+ if 'validation_issues' in post_result.get('data', {}):
128
+ issues = post_result['data']['validation_issues']
129
+ logger.warning(f"Validation issues: {issues}")
130
+
131
+ return result
132
+
133
+ except Exception as e:
134
+ logger.error(f"Error in hook-enabled delegation: {e}")
135
+ # Fallback to normal delegation if hooks fail
136
+ return await super().delegate_to_agent(agent_name, context)
137
+
138
+ async def _create_tickets(self, tickets: List[Dict[str, Any]]):
139
+ """Create tickets in the ticket system.
140
+
141
+ Args:
142
+ tickets: List of ticket dictionaries
143
+ """
144
+ try:
145
+ # Initialize ticket manager if needed
146
+ if not hasattr(self, 'ticket_manager'):
147
+ self.ticket_manager = TicketManager()
148
+
149
+ for ticket in tickets:
150
+ try:
151
+ # Create ticket
152
+ ticket_id = await self.ticket_manager.create_ticket(
153
+ title=ticket.get('title', 'Untitled'),
154
+ description=ticket.get('description', ''),
155
+ priority=ticket.get('priority', 'normal'),
156
+ ticket_type=ticket.get('type', 'task'),
157
+ metadata=ticket.get('metadata', {})
158
+ )
159
+ logger.info(f"Created ticket {ticket_id}: {ticket['title']}")
160
+ except Exception as e:
161
+ logger.error(f"Failed to create ticket: {e}")
162
+
163
+ except Exception as e:
164
+ logger.error(f"Error creating tickets: {e}")
165
+
166
+
167
+ # Example usage
168
+ async def main():
169
+ """Example usage of hook-enabled orchestrator."""
170
+ # Create orchestrator
171
+ orchestrator = HookEnabledOrchestrator()
172
+
173
+ # Process some prompts
174
+ prompts = [
175
+ "URGENT: Fix the bug in the login system",
176
+ "TODO: Add unit tests for the new API endpoints",
177
+ "Can you create ticket: Implement user dashboard feature",
178
+ "Research the best practices for React performance optimization"
179
+ ]
180
+
181
+ for prompt in prompts:
182
+ print(f"\nProcessing: {prompt}")
183
+ response = await orchestrator.process_prompt(prompt)
184
+ print(f"Response: {response[:100]}...")
185
+
186
+
187
+ if __name__ == "__main__":
188
+ asyncio.run(main())
@@ -0,0 +1,178 @@
1
+ """Example of how to integrate hooks into orchestrator methods."""
2
+
3
+ from typing import Optional
4
+ from ..hooks.hook_client import HookServiceClient
5
+
6
+
7
+ class HookIntegrationExample:
8
+ """Example methods showing how to integrate hooks into orchestrators."""
9
+
10
+ def __init__(self, hook_client: Optional[HookServiceClient] = None):
11
+ """Initialize with optional hook client."""
12
+ self.hook_client = hook_client
13
+
14
+ def process_user_input_with_hooks(self, user_input: str) -> str:
15
+ """Process user input through submit hooks before sending to Claude.
16
+
17
+ This method shows how to:
18
+ 1. Send user input to hook service
19
+ 2. Get modified input back
20
+ 3. Use the modified input for Claude
21
+ """
22
+ if not self.hook_client:
23
+ # No hooks available, return original input
24
+ return user_input
25
+
26
+ try:
27
+ # Execute submit hooks
28
+ results = self.hook_client.execute_submit_hook(
29
+ prompt=user_input,
30
+ session_id="current_session"
31
+ )
32
+
33
+ # Get modified data from hooks
34
+ modified_data = self.hook_client.get_modified_data(results)
35
+
36
+ # Use modified prompt if available
37
+ if modified_data.get('prompt'):
38
+ return modified_data['prompt']
39
+
40
+ # Check for priority changes
41
+ if modified_data.get('priority'):
42
+ # Could adjust Claude model or other settings based on priority
43
+ print(f"Priority set by hooks: {modified_data['priority']}")
44
+
45
+ return user_input
46
+
47
+ except Exception as e:
48
+ print(f"Hook processing failed: {e}")
49
+ # Fallback to original input
50
+ return user_input
51
+
52
+ def process_agent_delegation_with_hooks(self, agent_name: str, task: str) -> tuple[str, str]:
53
+ """Process agent delegation through pre-delegation hooks.
54
+
55
+ Returns:
56
+ Tuple of (agent_name, task) potentially modified by hooks
57
+ """
58
+ if not self.hook_client:
59
+ return agent_name, task
60
+
61
+ try:
62
+ # Execute pre-delegation hooks
63
+ context = {
64
+ 'agent': agent_name,
65
+ 'task': task
66
+ }
67
+
68
+ results = self.hook_client.execute_pre_delegation_hook(
69
+ agent=agent_name,
70
+ context=context
71
+ )
72
+
73
+ # Get modified data
74
+ modified_data = self.hook_client.get_modified_data(results)
75
+
76
+ # Update agent or task if modified
77
+ new_agent = modified_data.get('agent', agent_name)
78
+ new_context = modified_data.get('context', {})
79
+ new_task = new_context.get('task', task)
80
+
81
+ return new_agent, new_task
82
+
83
+ except Exception as e:
84
+ print(f"Pre-delegation hook failed: {e}")
85
+ return agent_name, task
86
+
87
+ def process_agent_response_with_hooks(self, agent_name: str, response: str) -> str:
88
+ """Process agent response through post-delegation hooks.
89
+
90
+ Returns:
91
+ Potentially modified response
92
+ """
93
+ if not self.hook_client:
94
+ return response
95
+
96
+ try:
97
+ # Execute post-delegation hooks
98
+ result = {
99
+ 'response': response,
100
+ 'success': True
101
+ }
102
+
103
+ results = self.hook_client.execute_post_delegation_hook(
104
+ agent=agent_name,
105
+ result=result
106
+ )
107
+
108
+ # Get modified data
109
+ modified_data = self.hook_client.get_modified_data(results)
110
+
111
+ # Use modified response if available
112
+ if modified_data.get('result', {}).get('response'):
113
+ return modified_data['result']['response']
114
+
115
+ return response
116
+
117
+ except Exception as e:
118
+ print(f"Post-delegation hook failed: {e}")
119
+ return response
120
+
121
+ def extract_tickets_with_hooks(self, conversation: str) -> list:
122
+ """Extract tickets from conversation using ticket extraction hooks.
123
+
124
+ Returns:
125
+ List of extracted tickets
126
+ """
127
+ if not self.hook_client:
128
+ return []
129
+
130
+ try:
131
+ # Execute ticket extraction hooks
132
+ results = self.hook_client.execute_ticket_extraction_hook(
133
+ content={'conversation': conversation}
134
+ )
135
+
136
+ # Get extracted tickets
137
+ tickets = self.hook_client.get_extracted_tickets(results)
138
+
139
+ return tickets
140
+
141
+ except Exception as e:
142
+ print(f"Ticket extraction hook failed: {e}")
143
+ return []
144
+
145
+
146
+ # Example of integrating into an existing orchestrator method
147
+ def example_orchestrator_run_method(self, user_input: str):
148
+ """Example of how to modify an existing orchestrator run method."""
149
+
150
+ # Process input through hooks if available
151
+ if self.hook_client:
152
+ user_input = self.process_user_input_with_hooks(user_input)
153
+
154
+ # Continue with normal orchestration
155
+ # ... existing orchestrator code ...
156
+
157
+ # When delegating to agents
158
+ if needs_delegation:
159
+ agent_name = "Engineer"
160
+ task = "Implement the feature"
161
+
162
+ # Process through pre-delegation hooks
163
+ if self.hook_client:
164
+ agent_name, task = self.process_agent_delegation_with_hooks(agent_name, task)
165
+
166
+ # Perform delegation
167
+ response = self.delegate_to_agent(agent_name, task)
168
+
169
+ # Process response through post-delegation hooks
170
+ if self.hook_client:
171
+ response = self.process_agent_response_with_hooks(agent_name, response)
172
+
173
+ # Extract tickets from the conversation
174
+ if self.hook_client:
175
+ conversation = f"User: {user_input}\nAssistant: {response}"
176
+ tickets = self.extract_tickets_with_hooks(conversation)
177
+ for ticket in tickets:
178
+ print(f"Extracted ticket: {ticket['title']}")