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
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Memory Router Service
|
|
4
|
+
====================
|
|
5
|
+
|
|
6
|
+
Routes memory commands to appropriate agents based on content analysis.
|
|
7
|
+
|
|
8
|
+
This service provides:
|
|
9
|
+
- Content analysis to determine target agent
|
|
10
|
+
- Support for "remember", "memorize", "add to memory" commands
|
|
11
|
+
- Routing decision with reasoning
|
|
12
|
+
- Context-aware agent selection
|
|
13
|
+
|
|
14
|
+
WHY: When users say "remember this for next time", the system needs to determine
|
|
15
|
+
which agent should store the information. This service analyzes content to make
|
|
16
|
+
intelligent routing decisions for PM delegation.
|
|
17
|
+
|
|
18
|
+
DESIGN DECISION: Uses keyword matching and context analysis rather than ML models
|
|
19
|
+
for simplicity and transparency. Routing decisions include reasoning to help
|
|
20
|
+
users understand why content was assigned to specific agents.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import re
|
|
24
|
+
from typing import Dict, List, Optional, Any, Tuple
|
|
25
|
+
from datetime import datetime
|
|
26
|
+
|
|
27
|
+
from claude_mpm.core import LoggerMixin
|
|
28
|
+
from claude_mpm.core.config import Config
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class MemoryRouter(LoggerMixin):
|
|
32
|
+
"""Routes memory commands to appropriate agents based on content analysis.
|
|
33
|
+
|
|
34
|
+
WHY: Different types of learnings belong to different agents. Engineering
|
|
35
|
+
insights should go to the engineer agent, while research findings should
|
|
36
|
+
go to the research agent. This service provides intelligent routing.
|
|
37
|
+
|
|
38
|
+
DESIGN DECISION: Uses explicit keyword patterns and rules rather than ML
|
|
39
|
+
to ensure predictable, transparent routing decisions that users can understand.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# Agent routing patterns - keywords that indicate agent specialization
|
|
43
|
+
AGENT_PATTERNS = {
|
|
44
|
+
'engineer': {
|
|
45
|
+
'keywords': [
|
|
46
|
+
'implementation', 'code', 'coding', 'programming', 'function', 'method',
|
|
47
|
+
'class', 'module', 'import', 'dependency', 'build', 'compile', 'deploy',
|
|
48
|
+
'refactor', 'optimize', 'performance', 'algorithm', 'data structure',
|
|
49
|
+
'design pattern', 'architecture', 'api', 'interface', 'library',
|
|
50
|
+
'framework', 'testing', 'unit test', 'integration test', 'debug',
|
|
51
|
+
'error handling', 'exception'
|
|
52
|
+
],
|
|
53
|
+
'sections': [
|
|
54
|
+
'Coding Patterns Learned', 'Implementation Guidelines',
|
|
55
|
+
'Performance Considerations', 'Integration Points'
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
'research': {
|
|
59
|
+
'keywords': [
|
|
60
|
+
'research', 'analysis', 'investigate', 'explore', 'study', 'examine',
|
|
61
|
+
'findings', 'discovery', 'insights', 'documentation', 'specification',
|
|
62
|
+
'requirements', 'use case', 'user story', 'business logic',
|
|
63
|
+
'domain knowledge', 'best practices', 'standards', 'compliance',
|
|
64
|
+
'security', 'vulnerability', 'threat', 'risk'
|
|
65
|
+
],
|
|
66
|
+
'sections': [
|
|
67
|
+
'Domain-Specific Knowledge', 'Research Findings',
|
|
68
|
+
'Security Considerations', 'Compliance Requirements'
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
'qa': {
|
|
72
|
+
'keywords': [
|
|
73
|
+
'test', 'testing', 'quality', 'bug', 'defect', 'issue', 'validation',
|
|
74
|
+
'verification', 'quality assurance', 'test case', 'test plan',
|
|
75
|
+
'coverage', 'automation', 'regression', 'smoke test', 'acceptance',
|
|
76
|
+
'criteria', 'checklist', 'review', 'audit', 'compliance',
|
|
77
|
+
'standards', 'metrics', 'measurement'
|
|
78
|
+
],
|
|
79
|
+
'sections': [
|
|
80
|
+
'Quality Standards', 'Testing Strategies',
|
|
81
|
+
'Common Issues Found', 'Verification Patterns'
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
'documentation': {
|
|
85
|
+
'keywords': [
|
|
86
|
+
'document', 'documentation', 'readme', 'guide', 'manual', 'help',
|
|
87
|
+
'instructions', 'tutorial', 'explanation', 'description', 'overview',
|
|
88
|
+
'summary', 'specification', 'reference', 'glossary', 'faq',
|
|
89
|
+
'examples', 'usage', 'howto', 'walkthrough'
|
|
90
|
+
],
|
|
91
|
+
'sections': [
|
|
92
|
+
'Documentation Patterns', 'User Guide Standards',
|
|
93
|
+
'Content Organization', 'Writing Guidelines'
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
'security': {
|
|
97
|
+
'keywords': [
|
|
98
|
+
'security', 'authentication', 'authorization', 'encryption', 'decrypt',
|
|
99
|
+
'password', 'token', 'certificate', 'ssl', 'tls', 'vulnerability',
|
|
100
|
+
'exploit', 'attack', 'malware', 'virus', 'firewall', 'access control',
|
|
101
|
+
'permissions', 'privilege', 'audit', 'compliance', 'privacy',
|
|
102
|
+
'data protection', 'gdpr', 'sensitive data'
|
|
103
|
+
],
|
|
104
|
+
'sections': [
|
|
105
|
+
'Security Patterns', 'Threat Analysis',
|
|
106
|
+
'Compliance Requirements', 'Access Control Patterns'
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
'pm': {
|
|
110
|
+
'keywords': [
|
|
111
|
+
'project', 'management', 'coordination', 'planning', 'schedule',
|
|
112
|
+
'timeline', 'milestone', 'deliverable', 'stakeholder', 'requirement',
|
|
113
|
+
'priority', 'resource', 'allocation', 'budget', 'scope', 'risk',
|
|
114
|
+
'communication', 'meeting', 'status', 'progress', 'workflow',
|
|
115
|
+
'process', 'methodology', 'agile', 'scrum', 'kanban'
|
|
116
|
+
],
|
|
117
|
+
'sections': [
|
|
118
|
+
'Project Coordination', 'Team Communication',
|
|
119
|
+
'Process Improvements', 'Risk Management'
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# Default agent for unmatched content
|
|
125
|
+
DEFAULT_AGENT = 'pm'
|
|
126
|
+
|
|
127
|
+
def __init__(self, config: Optional[Config] = None):
|
|
128
|
+
"""Initialize the memory router.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
config: Optional Config object
|
|
132
|
+
"""
|
|
133
|
+
super().__init__()
|
|
134
|
+
self.config = config or Config()
|
|
135
|
+
|
|
136
|
+
def analyze_and_route(self, content: str, context: Optional[Dict] = None) -> Dict[str, Any]:
|
|
137
|
+
"""Analyze content and determine target agent for memory storage.
|
|
138
|
+
|
|
139
|
+
WHY: Different types of information belong to different agents. This method
|
|
140
|
+
analyzes content using keyword patterns and context to make intelligent
|
|
141
|
+
routing decisions.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
content: The content to be remembered
|
|
145
|
+
context: Optional context for routing decisions
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Dict containing routing decision and reasoning
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
# Clean and normalize content for analysis
|
|
152
|
+
normalized_content = self._normalize_content(content)
|
|
153
|
+
|
|
154
|
+
# Analyze content for agent patterns
|
|
155
|
+
agent_scores = self._calculate_agent_scores(normalized_content)
|
|
156
|
+
|
|
157
|
+
# Apply context-based adjustments
|
|
158
|
+
if context:
|
|
159
|
+
agent_scores = self._apply_context_adjustments(agent_scores, context)
|
|
160
|
+
|
|
161
|
+
# Select target agent
|
|
162
|
+
target_agent, confidence = self._select_target_agent(agent_scores)
|
|
163
|
+
|
|
164
|
+
# Determine appropriate section
|
|
165
|
+
section = self._determine_section(target_agent, normalized_content)
|
|
166
|
+
|
|
167
|
+
# Build reasoning
|
|
168
|
+
reasoning = self._build_reasoning(target_agent, agent_scores, section, context)
|
|
169
|
+
|
|
170
|
+
result = {
|
|
171
|
+
"target_agent": target_agent,
|
|
172
|
+
"section": section,
|
|
173
|
+
"confidence": confidence,
|
|
174
|
+
"reasoning": reasoning,
|
|
175
|
+
"agent_scores": agent_scores,
|
|
176
|
+
"timestamp": datetime.now().isoformat(),
|
|
177
|
+
"content_length": len(content)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
self.logger.debug(f"Routed content to {target_agent} with confidence {confidence}")
|
|
181
|
+
return result
|
|
182
|
+
|
|
183
|
+
except Exception as e:
|
|
184
|
+
self.logger.error(f"Error analyzing content for routing: {e}")
|
|
185
|
+
return {
|
|
186
|
+
"target_agent": self.DEFAULT_AGENT,
|
|
187
|
+
"section": "Recent Learnings",
|
|
188
|
+
"confidence": 0.1,
|
|
189
|
+
"reasoning": f"Error during analysis, defaulting to {self.DEFAULT_AGENT}",
|
|
190
|
+
"error": str(e)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
def test_routing_patterns(self, test_cases: List[Dict[str, str]]) -> List[Dict[str, Any]]:
|
|
194
|
+
"""Test routing logic with provided test cases.
|
|
195
|
+
|
|
196
|
+
WHY: Routing patterns need validation to ensure they work correctly.
|
|
197
|
+
This method allows testing of routing logic with known inputs.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
test_cases: List of test cases with 'content' and optional 'expected_agent'
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
List of routing results for each test case
|
|
204
|
+
"""
|
|
205
|
+
results = []
|
|
206
|
+
|
|
207
|
+
for i, test_case in enumerate(test_cases):
|
|
208
|
+
content = test_case.get('content', '')
|
|
209
|
+
expected = test_case.get('expected_agent')
|
|
210
|
+
|
|
211
|
+
routing_result = self.analyze_and_route(content)
|
|
212
|
+
|
|
213
|
+
test_result = {
|
|
214
|
+
"test_case": i + 1,
|
|
215
|
+
"content": content[:100] + "..." if len(content) > 100 else content,
|
|
216
|
+
"expected_agent": expected,
|
|
217
|
+
"actual_agent": routing_result['target_agent'],
|
|
218
|
+
"confidence": routing_result['confidence'],
|
|
219
|
+
"correct": expected == routing_result['target_agent'] if expected else None,
|
|
220
|
+
"reasoning": routing_result['reasoning']
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
results.append(test_result)
|
|
224
|
+
|
|
225
|
+
return results
|
|
226
|
+
|
|
227
|
+
def get_routing_patterns(self) -> Dict[str, Any]:
|
|
228
|
+
"""Get current routing patterns and statistics.
|
|
229
|
+
|
|
230
|
+
WHY: Users and developers need to understand how routing works and
|
|
231
|
+
potentially customize patterns for their specific use cases.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
Dict containing routing patterns and statistics
|
|
235
|
+
"""
|
|
236
|
+
return {
|
|
237
|
+
"agents": list(self.AGENT_PATTERNS.keys()),
|
|
238
|
+
"default_agent": self.DEFAULT_AGENT,
|
|
239
|
+
"patterns": {
|
|
240
|
+
agent: {
|
|
241
|
+
"keyword_count": len(patterns['keywords']),
|
|
242
|
+
"section_count": len(patterns['sections']),
|
|
243
|
+
"keywords": patterns['keywords'][:10], # Show first 10
|
|
244
|
+
"sections": patterns['sections']
|
|
245
|
+
}
|
|
246
|
+
for agent, patterns in self.AGENT_PATTERNS.items()
|
|
247
|
+
},
|
|
248
|
+
"total_keywords": sum(len(p['keywords']) for p in self.AGENT_PATTERNS.values())
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
def _normalize_content(self, content: str) -> str:
|
|
252
|
+
"""Normalize content for analysis.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
content: Raw content
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
Normalized content string
|
|
259
|
+
"""
|
|
260
|
+
# Convert to lowercase and remove extra whitespace
|
|
261
|
+
normalized = re.sub(r'\s+', ' ', content.lower().strip())
|
|
262
|
+
|
|
263
|
+
# Remove common noise words that don't help with routing
|
|
264
|
+
noise_words = ['the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by']
|
|
265
|
+
words = normalized.split()
|
|
266
|
+
filtered_words = [w for w in words if w not in noise_words and len(w) > 2]
|
|
267
|
+
|
|
268
|
+
return ' '.join(filtered_words)
|
|
269
|
+
|
|
270
|
+
def _calculate_agent_scores(self, content: str) -> Dict[str, float]:
|
|
271
|
+
"""Calculate relevance scores for each agent.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
content: Normalized content
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
Dict mapping agent names to relevance scores
|
|
278
|
+
"""
|
|
279
|
+
scores = {}
|
|
280
|
+
|
|
281
|
+
for agent, patterns in self.AGENT_PATTERNS.items():
|
|
282
|
+
score = 0.0
|
|
283
|
+
matched_keywords = []
|
|
284
|
+
|
|
285
|
+
for keyword in patterns['keywords']:
|
|
286
|
+
# Exact keyword match
|
|
287
|
+
if keyword in content:
|
|
288
|
+
score += 1.0
|
|
289
|
+
matched_keywords.append(keyword)
|
|
290
|
+
# Partial match (word contains keyword)
|
|
291
|
+
elif any(keyword in word for word in content.split()):
|
|
292
|
+
score += 0.5
|
|
293
|
+
|
|
294
|
+
# Normalize score by number of keywords for this agent
|
|
295
|
+
if patterns['keywords']:
|
|
296
|
+
score = score / len(patterns['keywords'])
|
|
297
|
+
|
|
298
|
+
scores[agent] = {
|
|
299
|
+
'score': score,
|
|
300
|
+
'matched_keywords': matched_keywords[:5], # Limit for readability
|
|
301
|
+
'match_count': len(matched_keywords)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return scores
|
|
305
|
+
|
|
306
|
+
def _apply_context_adjustments(self, agent_scores: Dict[str, Any], context: Dict) -> Dict[str, Any]:
|
|
307
|
+
"""Apply context-based adjustments to agent scores.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
agent_scores: Current agent scores
|
|
311
|
+
context: Context information
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Adjusted agent scores
|
|
315
|
+
"""
|
|
316
|
+
# Context hints for routing
|
|
317
|
+
if 'agent_hint' in context:
|
|
318
|
+
hint = context['agent_hint'].lower()
|
|
319
|
+
if hint in agent_scores:
|
|
320
|
+
agent_scores[hint]['score'] += 0.3
|
|
321
|
+
agent_scores[hint]['context_boost'] = True
|
|
322
|
+
|
|
323
|
+
# Task type hints
|
|
324
|
+
if 'task_type' in context:
|
|
325
|
+
task_type = context['task_type'].lower()
|
|
326
|
+
task_mappings = {
|
|
327
|
+
'implementation': 'engineer',
|
|
328
|
+
'coding': 'engineer',
|
|
329
|
+
'analysis': 'research',
|
|
330
|
+
'testing': 'qa',
|
|
331
|
+
'documentation': 'documentation',
|
|
332
|
+
'security': 'security',
|
|
333
|
+
'planning': 'pm'
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if task_type in task_mappings:
|
|
337
|
+
target_agent = task_mappings[task_type]
|
|
338
|
+
if target_agent in agent_scores:
|
|
339
|
+
agent_scores[target_agent]['score'] += 0.2
|
|
340
|
+
agent_scores[target_agent]['task_type_boost'] = True
|
|
341
|
+
|
|
342
|
+
return agent_scores
|
|
343
|
+
|
|
344
|
+
def _select_target_agent(self, agent_scores: Dict[str, Any]) -> Tuple[str, float]:
|
|
345
|
+
"""Select target agent based on scores.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
agent_scores: Agent relevance scores
|
|
349
|
+
|
|
350
|
+
Returns:
|
|
351
|
+
Tuple of (target_agent, confidence)
|
|
352
|
+
"""
|
|
353
|
+
# Find agent with highest score
|
|
354
|
+
best_agent = self.DEFAULT_AGENT
|
|
355
|
+
best_score = 0.0
|
|
356
|
+
|
|
357
|
+
for agent, score_data in agent_scores.items():
|
|
358
|
+
score = score_data['score']
|
|
359
|
+
if score > best_score:
|
|
360
|
+
best_score = score
|
|
361
|
+
best_agent = agent
|
|
362
|
+
|
|
363
|
+
# If no clear winner, use default
|
|
364
|
+
if best_score < 0.1:
|
|
365
|
+
return self.DEFAULT_AGENT, 0.1
|
|
366
|
+
|
|
367
|
+
# Convert score to confidence (0.0 to 1.0)
|
|
368
|
+
confidence = min(1.0, best_score * 2) # Scale up for better confidence values
|
|
369
|
+
|
|
370
|
+
return best_agent, confidence
|
|
371
|
+
|
|
372
|
+
def _determine_section(self, agent: str, content: str) -> str:
|
|
373
|
+
"""Determine appropriate section for the content.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
agent: Target agent
|
|
377
|
+
content: Normalized content
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
Section name for memory storage
|
|
381
|
+
"""
|
|
382
|
+
if agent not in self.AGENT_PATTERNS:
|
|
383
|
+
return "Recent Learnings"
|
|
384
|
+
|
|
385
|
+
sections = self.AGENT_PATTERNS[agent]['sections']
|
|
386
|
+
|
|
387
|
+
# Simple heuristics for section selection
|
|
388
|
+
if 'mistake' in content or 'error' in content or 'avoid' in content:
|
|
389
|
+
return 'Common Mistakes to Avoid'
|
|
390
|
+
elif 'pattern' in content or 'architecture' in content:
|
|
391
|
+
return sections[0] if sections else 'Recent Learnings' # First section is usually patterns
|
|
392
|
+
elif 'guideline' in content or 'standard' in content:
|
|
393
|
+
return 'Implementation Guidelines'
|
|
394
|
+
elif 'context' in content or 'current' in content:
|
|
395
|
+
return 'Current Technical Context'
|
|
396
|
+
else:
|
|
397
|
+
# Default to first available section or Recent Learnings
|
|
398
|
+
return sections[0] if sections else 'Recent Learnings'
|
|
399
|
+
|
|
400
|
+
def _build_reasoning(self, target_agent: str, agent_scores: Dict[str, Any],
|
|
401
|
+
section: str, context: Optional[Dict]) -> str:
|
|
402
|
+
"""Build human-readable reasoning for routing decision.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
target_agent: Selected target agent
|
|
406
|
+
agent_scores: All agent scores
|
|
407
|
+
section: Selected section
|
|
408
|
+
context: Optional context
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Human-readable reasoning string
|
|
412
|
+
"""
|
|
413
|
+
if target_agent not in agent_scores:
|
|
414
|
+
return f"Defaulted to {target_agent} agent due to analysis error"
|
|
415
|
+
|
|
416
|
+
score_data = agent_scores[target_agent]
|
|
417
|
+
score = score_data['score']
|
|
418
|
+
matched_keywords = score_data.get('matched_keywords', [])
|
|
419
|
+
|
|
420
|
+
reasoning_parts = []
|
|
421
|
+
|
|
422
|
+
# Primary reasoning
|
|
423
|
+
if score > 0.3:
|
|
424
|
+
reasoning_parts.append(f"Strong match for {target_agent} agent")
|
|
425
|
+
elif score > 0.1:
|
|
426
|
+
reasoning_parts.append(f"Moderate match for {target_agent} agent")
|
|
427
|
+
else:
|
|
428
|
+
reasoning_parts.append(f"Weak match, defaulting to {target_agent} agent")
|
|
429
|
+
|
|
430
|
+
# Keyword evidence
|
|
431
|
+
if matched_keywords:
|
|
432
|
+
keyword_str = ", ".join(matched_keywords)
|
|
433
|
+
reasoning_parts.append(f"matched keywords: {keyword_str}")
|
|
434
|
+
|
|
435
|
+
# Context boosts
|
|
436
|
+
if score_data.get('context_boost'):
|
|
437
|
+
reasoning_parts.append("boosted by context hint")
|
|
438
|
+
if score_data.get('task_type_boost'):
|
|
439
|
+
reasoning_parts.append("boosted by task type")
|
|
440
|
+
|
|
441
|
+
# Section selection
|
|
442
|
+
if section != "Recent Learnings":
|
|
443
|
+
reasoning_parts.append(f"assigned to '{section}' section")
|
|
444
|
+
|
|
445
|
+
return "; ".join(reasoning_parts).capitalize()
|