claude-mpm 4.4.0__py3-none-any.whl → 4.4.3__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/VERSION +1 -1
- claude_mpm/agents/WORKFLOW.md +2 -14
- claude_mpm/cli/commands/configure.py +2 -29
- claude_mpm/cli/commands/mpm_init.py +3 -3
- claude_mpm/cli/parsers/configure_parser.py +4 -15
- claude_mpm/core/framework/__init__.py +38 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +356 -0
- claude_mpm/core/framework/formatters/content_formatter.py +283 -0
- claude_mpm/core/framework/formatters/context_generator.py +180 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +202 -0
- claude_mpm/core/framework/loaders/file_loader.py +213 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +151 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +208 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +222 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +238 -0
- claude_mpm/core/framework_loader.py +277 -1798
- claude_mpm/hooks/__init__.py +9 -1
- claude_mpm/hooks/kuzu_memory_hook.py +352 -0
- claude_mpm/services/core/path_resolver.py +1 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +1 -0
- claude_mpm/services/mcp_config_manager.py +67 -4
- claude_mpm/services/mcp_gateway/core/process_pool.py +281 -0
- claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +3 -13
- claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
- claude_mpm/services/mcp_gateway/tools/__init__.py +13 -2
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +36 -6
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +542 -0
- claude_mpm/services/shared/__init__.py +2 -1
- claude_mpm/services/shared/service_factory.py +8 -5
- claude_mpm/services/unified/config_strategies/__init__.py +190 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +689 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +748 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +999 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +871 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +802 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1105 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/METADATA +15 -15
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/RECORD +47 -27
- claude_mpm/cli/commands/configure_tui.py +0 -1927
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.4.
|
1
|
+
4.4.3
|
claude_mpm/agents/WORKFLOW.md
CHANGED
@@ -67,20 +67,8 @@ Return: Clean or list of blocked items
|
|
67
67
|
**When user mentions**: ticket, epic, issue, task tracking
|
68
68
|
|
69
69
|
**Process**:
|
70
|
-
|
71
|
-
|
72
|
-
3. Update with `aitrackdown comment/transition`
|
73
|
-
|
74
|
-
**Hierarchy**:
|
75
|
-
```
|
76
|
-
EP-0001 (Epic)
|
77
|
-
└── ISS-0001 (Session Issue)
|
78
|
-
├── TSK-0001 (Research)
|
79
|
-
├── TSK-0002 (Code Analyzer)
|
80
|
-
├── TSK-0003 (Implementation)
|
81
|
-
├── TSK-0004 (QA)
|
82
|
-
└── TSK-0005 (Documentation)
|
83
|
-
```
|
70
|
+
Use the mcp-ticketer MCP service for ticket management.
|
71
|
+
Ticketing is handled through the MCP Gateway, not internal CLI commands.
|
84
72
|
|
85
73
|
## Structural Delegation Format
|
86
74
|
|
@@ -246,35 +246,8 @@ class ConfigureCommand(BaseCommand):
|
|
246
246
|
return self._run_interactive_tui(args)
|
247
247
|
|
248
248
|
def _run_interactive_tui(self, args) -> CommandResult:
|
249
|
-
"""Run the main interactive
|
250
|
-
#
|
251
|
-
use_textual = getattr(args, "use_textual", True)
|
252
|
-
force_rich = getattr(args, "force_rich", False)
|
253
|
-
|
254
|
-
if use_textual and not force_rich:
|
255
|
-
try:
|
256
|
-
# Try to import and use Textual TUI
|
257
|
-
from .configure_tui import can_use_tui, launch_tui
|
258
|
-
|
259
|
-
if can_use_tui():
|
260
|
-
self.console.print(
|
261
|
-
"[cyan]Launching full-screen configuration interface...[/cyan]"
|
262
|
-
)
|
263
|
-
return launch_tui(self.current_scope, self.project_dir)
|
264
|
-
# Fall back to Rich TUI if terminal doesn't support full-screen
|
265
|
-
self.console.print(
|
266
|
-
"[yellow]Terminal doesn't support full-screen mode. Using menu interface.[/yellow]"
|
267
|
-
)
|
268
|
-
except ImportError:
|
269
|
-
# Textual not available, fall back to Rich
|
270
|
-
self.console.print(
|
271
|
-
"[yellow]Textual not installed. Using menu interface.[/yellow]"
|
272
|
-
)
|
273
|
-
self.console.print(
|
274
|
-
"[dim]Install textual for a better experience: pip install textual[/dim]"
|
275
|
-
)
|
276
|
-
|
277
|
-
# Original Rich-based TUI
|
249
|
+
"""Run the main interactive menu interface."""
|
250
|
+
# Rich-based menu interface
|
278
251
|
try:
|
279
252
|
self.console.clear()
|
280
253
|
|
@@ -643,9 +643,9 @@ The final CLAUDE.md should be a comprehensive, well-organized guide that any AI
|
|
643
643
|
):
|
644
644
|
checks_passed.append("Archived existing CLAUDE.md")
|
645
645
|
|
646
|
-
# Check for issues
|
647
|
-
if
|
648
|
-
for issue in
|
646
|
+
# Check for issues in validation report
|
647
|
+
if validation.get('issues'):
|
648
|
+
for issue in validation['issues']:
|
649
649
|
warnings.append(issue['description'])
|
650
650
|
|
651
651
|
if warnings:
|
@@ -25,11 +25,11 @@ def add_configure_subparser(subparsers) -> argparse.ArgumentParser:
|
|
25
25
|
Returns:
|
26
26
|
The configured configure subparser
|
27
27
|
"""
|
28
|
-
# Configure command - interactive
|
28
|
+
# Configure command - interactive configuration
|
29
29
|
configure_parser = subparsers.add_parser(
|
30
30
|
CLICommands.CONFIGURE.value,
|
31
|
-
help="Interactive
|
32
|
-
description="Launch an interactive Rich-based
|
31
|
+
help="Interactive configuration interface for managing agents and behaviors",
|
32
|
+
description="Launch an interactive Rich-based menu for configuring claude-mpm agents, templates, and behavior files",
|
33
33
|
)
|
34
34
|
|
35
35
|
# Add common arguments
|
@@ -122,21 +122,10 @@ def add_configure_subparser(subparsers) -> argparse.ArgumentParser:
|
|
122
122
|
# Display options
|
123
123
|
display_group = configure_parser.add_argument_group("display options")
|
124
124
|
display_group.add_argument(
|
125
|
-
"--no-colors", action="store_true", help="Disable colored output in the
|
125
|
+
"--no-colors", action="store_true", help="Disable colored output in the interface"
|
126
126
|
)
|
127
127
|
display_group.add_argument(
|
128
128
|
"--compact", action="store_true", help="Use compact display mode"
|
129
129
|
)
|
130
|
-
display_group.add_argument(
|
131
|
-
"--force-rich",
|
132
|
-
action="store_true",
|
133
|
-
help="Force use of Rich menu interface instead of full-screen Textual TUI",
|
134
|
-
)
|
135
|
-
display_group.add_argument(
|
136
|
-
"--no-textual",
|
137
|
-
dest="use_textual",
|
138
|
-
action="store_false",
|
139
|
-
help="Disable Textual TUI and use Rich menu interface",
|
140
|
-
)
|
141
130
|
|
142
131
|
return configure_parser
|
@@ -0,0 +1,38 @@
|
|
1
|
+
"""Framework module for Claude MPM.
|
2
|
+
|
3
|
+
This module provides the modular framework loading system with specialized components
|
4
|
+
for handling different aspects of framework initialization and management.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .loaders import (
|
8
|
+
AgentLoader,
|
9
|
+
FileLoader,
|
10
|
+
InstructionLoader,
|
11
|
+
PackagedLoader,
|
12
|
+
)
|
13
|
+
from .formatters import (
|
14
|
+
CapabilityGenerator,
|
15
|
+
ContentFormatter,
|
16
|
+
ContextGenerator,
|
17
|
+
)
|
18
|
+
from .processors import (
|
19
|
+
MemoryProcessor,
|
20
|
+
MetadataProcessor,
|
21
|
+
TemplateProcessor,
|
22
|
+
)
|
23
|
+
|
24
|
+
__all__ = [
|
25
|
+
# Loaders
|
26
|
+
"FileLoader",
|
27
|
+
"PackagedLoader",
|
28
|
+
"InstructionLoader",
|
29
|
+
"AgentLoader",
|
30
|
+
# Formatters
|
31
|
+
"ContentFormatter",
|
32
|
+
"CapabilityGenerator",
|
33
|
+
"ContextGenerator",
|
34
|
+
# Processors
|
35
|
+
"MetadataProcessor",
|
36
|
+
"TemplateProcessor",
|
37
|
+
"MemoryProcessor",
|
38
|
+
]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"""Framework formatters for content generation and formatting."""
|
2
|
+
|
3
|
+
from .capability_generator import CapabilityGenerator
|
4
|
+
from .content_formatter import ContentFormatter
|
5
|
+
from .context_generator import ContextGenerator
|
6
|
+
|
7
|
+
__all__ = [
|
8
|
+
"ContentFormatter",
|
9
|
+
"CapabilityGenerator",
|
10
|
+
"ContextGenerator",
|
11
|
+
]
|
@@ -0,0 +1,356 @@
|
|
1
|
+
"""Agent capability generator for dynamic agent discovery."""
|
2
|
+
|
3
|
+
import json
|
4
|
+
import time
|
5
|
+
from pathlib import Path
|
6
|
+
from typing import Any, Dict, List, Optional
|
7
|
+
|
8
|
+
import yaml
|
9
|
+
|
10
|
+
from claude_mpm.core.logging_utils import get_logger
|
11
|
+
|
12
|
+
# Import resource handling for packaged installations
|
13
|
+
try:
|
14
|
+
from importlib.resources import files
|
15
|
+
except ImportError:
|
16
|
+
try:
|
17
|
+
from importlib_resources import files
|
18
|
+
except ImportError:
|
19
|
+
files = None
|
20
|
+
|
21
|
+
|
22
|
+
class CapabilityGenerator:
|
23
|
+
"""Generates agent capability sections from deployed agents."""
|
24
|
+
|
25
|
+
def __init__(self):
|
26
|
+
"""Initialize the capability generator."""
|
27
|
+
self.logger = get_logger("capability_generator")
|
28
|
+
|
29
|
+
def generate_capabilities_section(
|
30
|
+
self,
|
31
|
+
deployed_agents: List[Dict[str, Any]],
|
32
|
+
local_agents: Dict[str, Dict[str, Any]],
|
33
|
+
) -> str:
|
34
|
+
"""Generate dynamic agent capabilities section.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
deployed_agents: List of deployed agent metadata
|
38
|
+
local_agents: Dictionary of local JSON template agents
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
Formatted capabilities section string
|
42
|
+
"""
|
43
|
+
# Build capabilities section
|
44
|
+
section = "\n\n## Available Agent Capabilities\n\n"
|
45
|
+
|
46
|
+
# Combine deployed and local agents
|
47
|
+
all_agents = {} # key: agent_id, value: (agent_data, priority)
|
48
|
+
|
49
|
+
# Add local agents first (highest priority)
|
50
|
+
for agent_id, agent_data in local_agents.items():
|
51
|
+
all_agents[agent_id] = (agent_data, -1) # Priority -1 for local agents
|
52
|
+
|
53
|
+
# Add deployed agents with lower priority
|
54
|
+
for priority, agent_data in enumerate(deployed_agents):
|
55
|
+
agent_id = agent_data["id"]
|
56
|
+
# Only add if not already present
|
57
|
+
if agent_id not in all_agents:
|
58
|
+
all_agents[agent_id] = (agent_data, priority)
|
59
|
+
|
60
|
+
# Extract just the agent data and sort
|
61
|
+
final_agents = [agent_data for agent_data, _ in all_agents.values()]
|
62
|
+
|
63
|
+
if not final_agents:
|
64
|
+
return self.get_fallback_capabilities()
|
65
|
+
|
66
|
+
# Sort agents alphabetically by ID
|
67
|
+
final_agents.sort(key=lambda x: x["id"])
|
68
|
+
|
69
|
+
# Display all agents with their rich descriptions
|
70
|
+
for agent in final_agents:
|
71
|
+
# Clean up display name - handle common acronyms
|
72
|
+
display_name = agent.get("display_name", agent["id"])
|
73
|
+
display_name = (
|
74
|
+
display_name.replace("Qa ", "QA ")
|
75
|
+
.replace("Ui ", "UI ")
|
76
|
+
.replace("Api ", "API ")
|
77
|
+
)
|
78
|
+
if display_name.lower() == "qa agent":
|
79
|
+
display_name = "QA Agent"
|
80
|
+
|
81
|
+
# Add local indicator if this is a local agent
|
82
|
+
if agent.get("is_local"):
|
83
|
+
tier_label = f" [LOCAL-{agent.get('tier', 'PROJECT').upper()}]"
|
84
|
+
section += f"\n### {display_name} (`{agent['id']}`) {tier_label}\n"
|
85
|
+
else:
|
86
|
+
section += f"\n### {display_name} (`{agent['id']}`)\n"
|
87
|
+
|
88
|
+
section += f"{agent.get('description', 'Specialized agent')}\n"
|
89
|
+
|
90
|
+
# Add routing information if available
|
91
|
+
if agent.get("routing"):
|
92
|
+
routing = agent["routing"]
|
93
|
+
routing_hints = []
|
94
|
+
|
95
|
+
if routing.get("keywords"):
|
96
|
+
# Show first 5 keywords for brevity
|
97
|
+
keywords = routing["keywords"][:5]
|
98
|
+
routing_hints.append(f"Keywords: {', '.join(keywords)}")
|
99
|
+
|
100
|
+
if routing.get("paths"):
|
101
|
+
# Show first 3 paths for brevity
|
102
|
+
paths = routing["paths"][:3]
|
103
|
+
routing_hints.append(f"Paths: {', '.join(paths)}")
|
104
|
+
|
105
|
+
if routing.get("priority"):
|
106
|
+
routing_hints.append(f"Priority: {routing['priority']}")
|
107
|
+
|
108
|
+
if routing_hints:
|
109
|
+
section += f"- **Routing**: {' | '.join(routing_hints)}\n"
|
110
|
+
|
111
|
+
# Add when_to_use if present
|
112
|
+
if routing.get("when_to_use"):
|
113
|
+
section += f"- **When to use**: {routing['when_to_use']}\n"
|
114
|
+
|
115
|
+
# Add any additional metadata if present
|
116
|
+
if agent.get("authority"):
|
117
|
+
section += f"- **Authority**: {agent['authority']}\n"
|
118
|
+
if agent.get("primary_function"):
|
119
|
+
section += f"- **Primary Function**: {agent['primary_function']}\n"
|
120
|
+
if agent.get("handoff_to"):
|
121
|
+
section += f"- **Handoff To**: {agent['handoff_to']}\n"
|
122
|
+
if agent.get("tools") and agent["tools"] != "standard":
|
123
|
+
section += f"- **Tools**: {agent['tools']}\n"
|
124
|
+
if agent.get("model") and agent["model"] != "opus":
|
125
|
+
section += f"- **Model**: {agent['model']}\n"
|
126
|
+
|
127
|
+
# Add memory routing information if available
|
128
|
+
if agent.get("memory_routing"):
|
129
|
+
memory_routing = agent["memory_routing"]
|
130
|
+
if memory_routing.get("description"):
|
131
|
+
section += f"- **Memory Routing**: {memory_routing['description']}\n"
|
132
|
+
|
133
|
+
# Add simple Context-Aware Agent Selection
|
134
|
+
section += "\n## Context-Aware Agent Selection\n\n"
|
135
|
+
section += "Select agents based on their descriptions above. Key principles:\n"
|
136
|
+
section += "- **PM questions** → Answer directly (only exception)\n"
|
137
|
+
section += "- Match task requirements to agent descriptions and authority\n"
|
138
|
+
section += "- Consider agent handoff recommendations\n"
|
139
|
+
section += "- Use the agent ID in parentheses when delegating via Task tool\n"
|
140
|
+
|
141
|
+
# Add summary
|
142
|
+
section += f"\n**Total Available Agents**: {len(final_agents)}\n"
|
143
|
+
|
144
|
+
return section
|
145
|
+
|
146
|
+
def parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
|
147
|
+
"""Parse agent metadata from deployed agent file.
|
148
|
+
|
149
|
+
Args:
|
150
|
+
agent_file: Path to deployed agent file
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
Dictionary with agent metadata or None
|
154
|
+
"""
|
155
|
+
try:
|
156
|
+
with open(agent_file) as f:
|
157
|
+
content = f.read()
|
158
|
+
|
159
|
+
# Default values
|
160
|
+
agent_data = {
|
161
|
+
"id": agent_file.stem,
|
162
|
+
"display_name": agent_file.stem.replace("_", " ").replace("-", " ").title(),
|
163
|
+
"description": "Specialized agent",
|
164
|
+
}
|
165
|
+
|
166
|
+
# Extract YAML frontmatter if present
|
167
|
+
if content.startswith("---"):
|
168
|
+
end_marker = content.find("---", 3)
|
169
|
+
if end_marker > 0:
|
170
|
+
frontmatter = content[3:end_marker]
|
171
|
+
metadata = yaml.safe_load(frontmatter)
|
172
|
+
if metadata:
|
173
|
+
# Use name as ID for Task tool
|
174
|
+
agent_data["id"] = metadata.get("name", agent_data["id"])
|
175
|
+
agent_data["display_name"] = (
|
176
|
+
metadata.get("name", agent_data["display_name"])
|
177
|
+
.replace("-", " ")
|
178
|
+
.title()
|
179
|
+
)
|
180
|
+
|
181
|
+
# Copy all metadata fields directly
|
182
|
+
for key, value in metadata.items():
|
183
|
+
if key not in ["name"]: # Skip already processed fields
|
184
|
+
agent_data[key] = value
|
185
|
+
|
186
|
+
# Try to load routing metadata from JSON template if not in YAML frontmatter
|
187
|
+
if "routing" not in agent_data:
|
188
|
+
routing_data = self.load_routing_from_template(agent_file.stem)
|
189
|
+
if routing_data:
|
190
|
+
agent_data["routing"] = routing_data
|
191
|
+
|
192
|
+
# Try to load memory routing metadata from JSON template
|
193
|
+
if "memory_routing" not in agent_data:
|
194
|
+
memory_routing_data = self.load_memory_routing_from_template(agent_file.stem)
|
195
|
+
if memory_routing_data:
|
196
|
+
agent_data["memory_routing"] = memory_routing_data
|
197
|
+
|
198
|
+
return agent_data
|
199
|
+
|
200
|
+
except Exception as e:
|
201
|
+
self.logger.debug(f"Could not parse metadata from {agent_file}: {e}")
|
202
|
+
return None
|
203
|
+
|
204
|
+
def load_routing_from_template(
|
205
|
+
self, agent_name: str, framework_path: Optional[Path] = None
|
206
|
+
) -> Optional[Dict[str, Any]]:
|
207
|
+
"""Load routing metadata from agent JSON template.
|
208
|
+
|
209
|
+
Args:
|
210
|
+
agent_name: Name of the agent
|
211
|
+
framework_path: Path to framework installation
|
212
|
+
|
213
|
+
Returns:
|
214
|
+
Dictionary with routing metadata or None if not found
|
215
|
+
"""
|
216
|
+
try:
|
217
|
+
# Check if we have a framework path
|
218
|
+
if not framework_path or framework_path == Path("__PACKAGED__"):
|
219
|
+
# For packaged installations, try to load from package resources
|
220
|
+
if files:
|
221
|
+
try:
|
222
|
+
templates_package = files("claude_mpm.agents.templates")
|
223
|
+
template_file = templates_package / f"{agent_name}.json"
|
224
|
+
|
225
|
+
if template_file.is_file():
|
226
|
+
template_content = template_file.read_text()
|
227
|
+
template_data = json.loads(template_content)
|
228
|
+
return template_data.get("routing")
|
229
|
+
except Exception as e:
|
230
|
+
self.logger.debug(
|
231
|
+
f"Could not load routing from packaged template for {agent_name}: {e}"
|
232
|
+
)
|
233
|
+
return None
|
234
|
+
|
235
|
+
# For development mode, load from filesystem
|
236
|
+
templates_dir = framework_path / "src" / "claude_mpm" / "agents" / "templates"
|
237
|
+
template_file = templates_dir / f"{agent_name}.json"
|
238
|
+
|
239
|
+
if template_file.exists():
|
240
|
+
with open(template_file) as f:
|
241
|
+
template_data = json.load(f)
|
242
|
+
return template_data.get("routing")
|
243
|
+
|
244
|
+
# Also check for variations in naming (underscore vs dash)
|
245
|
+
alternative_names = list(
|
246
|
+
{
|
247
|
+
agent_name.replace("-", "_"),
|
248
|
+
agent_name.replace("_", "-"),
|
249
|
+
agent_name.replace("-", ""),
|
250
|
+
agent_name.replace("_", ""),
|
251
|
+
}
|
252
|
+
)
|
253
|
+
|
254
|
+
for alt_name in alternative_names:
|
255
|
+
if alt_name != agent_name:
|
256
|
+
alt_file = templates_dir / f"{alt_name}.json"
|
257
|
+
if alt_file.exists():
|
258
|
+
with open(alt_file) as f:
|
259
|
+
template_data = json.load(f)
|
260
|
+
return template_data.get("routing")
|
261
|
+
|
262
|
+
return None
|
263
|
+
|
264
|
+
except Exception as e:
|
265
|
+
self.logger.debug(f"Could not load routing metadata for {agent_name}: {e}")
|
266
|
+
return None
|
267
|
+
|
268
|
+
def load_memory_routing_from_template(
|
269
|
+
self, agent_name: str, framework_path: Optional[Path] = None
|
270
|
+
) -> Optional[Dict[str, Any]]:
|
271
|
+
"""Load memory routing metadata from agent JSON template.
|
272
|
+
|
273
|
+
Args:
|
274
|
+
agent_name: Name of the agent
|
275
|
+
framework_path: Path to framework installation
|
276
|
+
|
277
|
+
Returns:
|
278
|
+
Dictionary with memory routing metadata or None if not found
|
279
|
+
"""
|
280
|
+
try:
|
281
|
+
# Check if we have a framework path
|
282
|
+
if not framework_path or framework_path == Path("__PACKAGED__"):
|
283
|
+
# For packaged installations, try to load from package resources
|
284
|
+
if files:
|
285
|
+
try:
|
286
|
+
templates_package = files("claude_mpm.agents.templates")
|
287
|
+
template_file = templates_package / f"{agent_name}.json"
|
288
|
+
|
289
|
+
if template_file.is_file():
|
290
|
+
template_content = template_file.read_text()
|
291
|
+
template_data = json.loads(template_content)
|
292
|
+
return template_data.get("memory_routing")
|
293
|
+
except Exception as e:
|
294
|
+
self.logger.debug(
|
295
|
+
f"Could not load memory routing from packaged template for {agent_name}: {e}"
|
296
|
+
)
|
297
|
+
return None
|
298
|
+
|
299
|
+
# For development mode, load from filesystem
|
300
|
+
templates_dir = framework_path / "src" / "claude_mpm" / "agents" / "templates"
|
301
|
+
template_file = templates_dir / f"{agent_name}.json"
|
302
|
+
|
303
|
+
if template_file.exists():
|
304
|
+
with open(template_file) as f:
|
305
|
+
template_data = json.load(f)
|
306
|
+
return template_data.get("memory_routing")
|
307
|
+
|
308
|
+
# Also check for variations in naming
|
309
|
+
alternative_names = list(
|
310
|
+
{
|
311
|
+
agent_name.replace("-", "_"),
|
312
|
+
agent_name.replace("_", "-"),
|
313
|
+
agent_name.replace("-agent", ""),
|
314
|
+
agent_name.replace("_agent", ""),
|
315
|
+
agent_name + "_agent",
|
316
|
+
agent_name + "-agent",
|
317
|
+
}
|
318
|
+
)
|
319
|
+
|
320
|
+
for alt_name in alternative_names:
|
321
|
+
if alt_name != agent_name:
|
322
|
+
alt_file = templates_dir / f"{alt_name}.json"
|
323
|
+
if alt_file.exists():
|
324
|
+
with open(alt_file) as f:
|
325
|
+
template_data = json.load(f)
|
326
|
+
return template_data.get("memory_routing")
|
327
|
+
|
328
|
+
return None
|
329
|
+
|
330
|
+
except Exception as e:
|
331
|
+
self.logger.debug(f"Could not load memory routing from template for {agent_name}: {e}")
|
332
|
+
return None
|
333
|
+
|
334
|
+
def get_fallback_capabilities(self) -> str:
|
335
|
+
"""Return fallback capabilities when dynamic discovery fails.
|
336
|
+
|
337
|
+
Returns:
|
338
|
+
Fallback agent capabilities section
|
339
|
+
"""
|
340
|
+
return """
|
341
|
+
|
342
|
+
## Available Agent Capabilities
|
343
|
+
|
344
|
+
You have the following specialized agents available for delegation:
|
345
|
+
|
346
|
+
- **Engineer** (`engineer`): Code implementation and development
|
347
|
+
- **Research** (`research-agent`): Investigation and analysis
|
348
|
+
- **QA** (`qa-agent`): Testing and quality assurance
|
349
|
+
- **Documentation** (`documentation-agent`): Documentation creation and maintenance
|
350
|
+
- **Security** (`security-agent`): Security analysis and protection
|
351
|
+
- **Data Engineer** (`data-engineer`): Data management and pipelines
|
352
|
+
- **Ops** (`ops-agent`): Deployment and operations
|
353
|
+
- **Version Control** (`version-control`): Git operations and version management
|
354
|
+
|
355
|
+
**IMPORTANT**: Use the exact agent ID in parentheses when delegating tasks.
|
356
|
+
"""
|