claude-mpm 4.2.1__py3-none-any.whl → 4.2.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/templates/agent-manager.json +1 -1
- claude_mpm/agents/templates/agentic_coder_optimizer.json +1 -1
- claude_mpm/agents/templates/api_qa.json +1 -1
- claude_mpm/agents/templates/code_analyzer.json +1 -1
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +1 -1
- claude_mpm/agents/templates/engineer.json +2 -2
- claude_mpm/agents/templates/gcp_ops_agent.json +14 -9
- claude_mpm/agents/templates/imagemagick.json +1 -1
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +1 -1
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +2 -2
- claude_mpm/agents/templates/refactoring_engineer.json +1 -1
- claude_mpm/agents/templates/research.json +3 -3
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/test-non-mpm.json +20 -0
- claude_mpm/agents/templates/ticketing.json +1 -1
- claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -8
- claude_mpm/agents/templates/web_ui.json +1 -1
- claude_mpm/cli/commands/agents.py +3 -0
- claude_mpm/cli/commands/dashboard.py +3 -3
- claude_mpm/cli/commands/monitor.py +227 -64
- claude_mpm/core/config.py +25 -0
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/dashboard/static/css/code-tree.css +220 -1
- claude_mpm/dashboard/static/css/dashboard.css +286 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/js/components/code-simple.js +507 -15
- claude_mpm/dashboard/static/js/components/code-tree.js +2044 -124
- claude_mpm/dashboard/static/js/socket-client.js +5 -2
- claude_mpm/dashboard/templates/code_simple.html +79 -0
- claude_mpm/dashboard/templates/index.html +42 -41
- claude_mpm/services/agents/deployment/agent_deployment.py +4 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +101 -2
- claude_mpm/services/agents/deployment/agent_format_converter.py +53 -9
- claude_mpm/services/agents/deployment/agent_template_builder.py +355 -25
- claude_mpm/services/agents/deployment/agent_validator.py +11 -6
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +83 -15
- claude_mpm/services/agents/deployment/validation/template_validator.py +51 -40
- claude_mpm/services/cli/agent_listing_service.py +2 -2
- claude_mpm/services/dashboard/stable_server.py +389 -0
- claude_mpm/services/socketio/client_proxy.py +16 -0
- claude_mpm/services/socketio/dashboard_server.py +360 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +27 -5
- claude_mpm/services/socketio/monitor_client.py +366 -0
- claude_mpm/services/socketio/monitor_server.py +505 -0
- claude_mpm/tools/code_tree_analyzer.py +95 -17
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/RECORD +57 -52
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/top_level.txt +0 -0
|
@@ -1218,8 +1218,11 @@ class SocketClient {
|
|
|
1218
1218
|
transformedEvent[key] = eventData.data[key];
|
|
1219
1219
|
}
|
|
1220
1220
|
} else {
|
|
1221
|
-
// Log
|
|
1222
|
-
|
|
1221
|
+
// Log debug info if data field would overwrite a protected field
|
|
1222
|
+
// Only log for non-timestamp fields to reduce noise
|
|
1223
|
+
if (key !== 'timestamp') {
|
|
1224
|
+
console.debug(`Protected field '${key}' in data object was not copied to top level to preserve event structure`);
|
|
1225
|
+
}
|
|
1223
1226
|
}
|
|
1224
1227
|
});
|
|
1225
1228
|
|
|
@@ -24,6 +24,75 @@
|
|
|
24
24
|
border-radius: 4px;
|
|
25
25
|
margin-bottom: 20px;
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
/* Tree visualization styles */
|
|
29
|
+
.tree-node {
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.tree-node circle {
|
|
34
|
+
fill: #fff;
|
|
35
|
+
stroke: steelblue;
|
|
36
|
+
stroke-width: 2px;
|
|
37
|
+
transition: all 0.3s ease;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.tree-node:hover circle {
|
|
41
|
+
fill: #e6f3ff;
|
|
42
|
+
stroke-width: 3px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.tree-node text {
|
|
46
|
+
font: 12px sans-serif;
|
|
47
|
+
pointer-events: none;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.tree-link {
|
|
51
|
+
fill: none;
|
|
52
|
+
stroke: #ccc;
|
|
53
|
+
stroke-width: 2px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.view-toggle button {
|
|
57
|
+
transition: all 0.3s ease;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.view-toggle button:hover {
|
|
61
|
+
transform: translateY(-1px);
|
|
62
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.file-selector input:focus {
|
|
66
|
+
outline: none;
|
|
67
|
+
border-color: #007cba;
|
|
68
|
+
box-shadow: 0 0 0 2px rgba(0, 124, 186, 0.2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.tree-legend {
|
|
72
|
+
position: absolute;
|
|
73
|
+
top: 10px;
|
|
74
|
+
right: 10px;
|
|
75
|
+
background: rgba(255, 255, 255, 0.9);
|
|
76
|
+
border: 1px solid #ccc;
|
|
77
|
+
border-radius: 4px;
|
|
78
|
+
padding: 10px;
|
|
79
|
+
font-size: 12px;
|
|
80
|
+
z-index: 1000;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.tree-legend-item {
|
|
84
|
+
margin: 2px 0;
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.tree-legend-color {
|
|
90
|
+
width: 12px;
|
|
91
|
+
height: 12px;
|
|
92
|
+
border-radius: 50%;
|
|
93
|
+
margin-right: 8px;
|
|
94
|
+
border: 1px solid #333;
|
|
95
|
+
}
|
|
27
96
|
</style>
|
|
28
97
|
</head>
|
|
29
98
|
<body>
|
|
@@ -54,6 +123,16 @@
|
|
|
54
123
|
addStatus('⏳ Loading code-simple.js...');
|
|
55
124
|
</script>
|
|
56
125
|
|
|
126
|
+
<!-- D3.js for tree visualization -->
|
|
127
|
+
<script src="https://d3js.org/d3.v7.min.js"
|
|
128
|
+
onload="addStatus('✅ D3.js loaded successfully')"
|
|
129
|
+
onerror="addStatus('❌ Failed to load D3.js')"></script>
|
|
130
|
+
|
|
131
|
+
<!-- Socket.IO for real-time communication -->
|
|
132
|
+
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"
|
|
133
|
+
onload="addStatus('✅ Socket.IO loaded successfully')"
|
|
134
|
+
onerror="addStatus('❌ Failed to load Socket.IO')"></script>
|
|
135
|
+
|
|
57
136
|
<script src="/static/js/components/code-simple.js"
|
|
58
137
|
onload="addStatus('✅ code-simple.js loaded successfully')"
|
|
59
138
|
onerror="addStatus('❌ Failed to load code-simple.js')"></script>
|
|
@@ -247,7 +247,6 @@
|
|
|
247
247
|
<button class="tab-button" data-tab="files">📁 Files</button>
|
|
248
248
|
<button class="tab-button" data-tab="activity">🌳 Activity</button>
|
|
249
249
|
<button class="tab-button" data-tab="code">🧬 Code</button>
|
|
250
|
-
<a href="/code-simple" class="tab-button" style="background: #f7fafc; color: #4a5568; text-decoration: none; border-left: 2px solid #e2e8f0;">📁 Simple View</a>
|
|
251
250
|
</div>
|
|
252
251
|
|
|
253
252
|
<!-- Events Tab -->
|
|
@@ -389,45 +388,52 @@
|
|
|
389
388
|
<!-- Code Tab -->
|
|
390
389
|
<div class="tab-content" id="code-tab">
|
|
391
390
|
<div class="code-container">
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
<div class="
|
|
395
|
-
<
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
<span class="stat-compact">⚡ <span id="function-count">0</span></span>
|
|
404
|
-
<span class="stat-compact">📝 <span id="line-count">0</span></span>
|
|
391
|
+
<div id="code-tree-container" class="code-tree-container">
|
|
392
|
+
<!-- Top-left corner: Language selector -->
|
|
393
|
+
<div class="tree-corner-controls top-left">
|
|
394
|
+
<div class="control-group">
|
|
395
|
+
<label class="control-label">Languages:</label>
|
|
396
|
+
<div class="checkbox-group">
|
|
397
|
+
<label class="checkbox-label"><input type="checkbox" class="language-checkbox" value="python" checked> Python</label>
|
|
398
|
+
<label class="checkbox-label"><input type="checkbox" class="language-checkbox" value="javascript" checked> JS</label>
|
|
399
|
+
<label class="checkbox-label"><input type="checkbox" class="language-checkbox" value="typescript" checked> TS</label>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
405
402
|
</div>
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
<
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
403
|
+
|
|
404
|
+
<!-- Top-right corner: Layout and search -->
|
|
405
|
+
<div class="tree-corner-controls top-right">
|
|
406
|
+
<div class="control-group">
|
|
407
|
+
<select id="code-layout" class="select-compact">
|
|
408
|
+
<option value="tree">Tree</option>
|
|
409
|
+
<option value="radial">Radial</option>
|
|
410
|
+
</select>
|
|
411
|
+
<input type="text" id="code-search" placeholder="Search..." class="search-compact">
|
|
412
|
+
</div>
|
|
414
413
|
</div>
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
<
|
|
421
|
-
<
|
|
422
|
-
<
|
|
423
|
-
<label><input type="checkbox" class="language-checkbox" value="typescript" checked> TS</label>
|
|
414
|
+
|
|
415
|
+
<!-- Bottom-left corner: Stats and Status -->
|
|
416
|
+
<div class="tree-corner-controls bottom-left">
|
|
417
|
+
<div class="stats-display" id="code-stats">
|
|
418
|
+
<span id="stats-files">0 files</span> •
|
|
419
|
+
<span id="stats-classes">0 classes</span> •
|
|
420
|
+
<span id="stats-functions">0 functions</span> •
|
|
421
|
+
<span id="stats-methods">0 methods</span>
|
|
424
422
|
</div>
|
|
425
|
-
<div class="
|
|
426
|
-
<
|
|
423
|
+
<div class="status-display" id="code-breadcrumb">
|
|
424
|
+
<div class="breadcrumb-ticker" id="breadcrumb-ticker">
|
|
425
|
+
<span id="breadcrumb-content">Ready to analyze...</span>
|
|
426
|
+
</div>
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
|
|
430
|
+
<!-- Bottom-right corner: Ignore patterns -->
|
|
431
|
+
<div class="tree-corner-controls bottom-right">
|
|
432
|
+
<div class="control-group">
|
|
433
|
+
<label class="control-label">Ignore:</label>
|
|
434
|
+
<input type="text" id="ignore-patterns" placeholder="test*, *.spec.js, node_modules" class="input-compact">
|
|
427
435
|
</div>
|
|
428
436
|
</div>
|
|
429
|
-
</div>
|
|
430
|
-
<div id="code-tree-container" class="code-tree-container">
|
|
431
437
|
<div id="code-tree"></div>
|
|
432
438
|
<!-- Collapsible legend -->
|
|
433
439
|
<div class="tree-legend collapsed" id="tree-legend" style="display: none;">
|
|
@@ -447,11 +453,6 @@
|
|
|
447
453
|
</div>
|
|
448
454
|
</div>
|
|
449
455
|
</div>
|
|
450
|
-
<div class="code-breadcrumb" id="code-breadcrumb">
|
|
451
|
-
<div class="breadcrumb-ticker" id="breadcrumb-ticker">
|
|
452
|
-
<span id="breadcrumb-content">Ready to analyze...</span>
|
|
453
|
-
</div>
|
|
454
|
-
</div>
|
|
455
456
|
</div>
|
|
456
457
|
</div>
|
|
457
458
|
|
|
@@ -531,7 +532,7 @@
|
|
|
531
532
|
Promise.all([
|
|
532
533
|
loadModule('/static/dist/dashboard.js'),
|
|
533
534
|
loadModule('/static/dist/components/activity-tree.js'),
|
|
534
|
-
loadModule('/static/
|
|
535
|
+
loadModule('/static/js/components/code-tree.js'), // TEMPORARY: Direct source for debugging
|
|
535
536
|
loadModule('/static/dist/components/code-viewer.js')
|
|
536
537
|
]).then(() => {
|
|
537
538
|
console.log('All dashboard modules loaded successfully');
|
|
@@ -683,7 +683,10 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
683
683
|
|
|
684
684
|
def _get_filtered_templates(self, excluded_agents: list, config: Config) -> list:
|
|
685
685
|
"""Get and filter template files based on exclusion rules."""
|
|
686
|
-
|
|
686
|
+
filter_non_mpm = config.get("agent_deployment.filter_non_mpm_agents", True)
|
|
687
|
+
return self.discovery_service.get_filtered_templates(
|
|
688
|
+
excluded_agents, config, filter_non_mpm
|
|
689
|
+
)
|
|
687
690
|
|
|
688
691
|
def _validate_and_repair_existing_agents(self, agents_dir: Path) -> Dict[str, Any]:
|
|
689
692
|
"""Validate and repair broken frontmatter in existing agent files."""
|
|
@@ -85,7 +85,10 @@ class AgentDiscoveryService:
|
|
|
85
85
|
return agents
|
|
86
86
|
|
|
87
87
|
def get_filtered_templates(
|
|
88
|
-
self,
|
|
88
|
+
self,
|
|
89
|
+
excluded_agents: List[str],
|
|
90
|
+
config: Optional[Config] = None,
|
|
91
|
+
filter_non_mpm: bool = False,
|
|
89
92
|
) -> List[Path]:
|
|
90
93
|
"""
|
|
91
94
|
Get filtered list of template files based on configuration.
|
|
@@ -93,6 +96,7 @@ class AgentDiscoveryService:
|
|
|
93
96
|
Args:
|
|
94
97
|
excluded_agents: List of agent names to exclude
|
|
95
98
|
config: Configuration object for additional filtering
|
|
99
|
+
filter_non_mpm: Whether to filter out non-MPM agents
|
|
96
100
|
|
|
97
101
|
Returns:
|
|
98
102
|
List of template file paths to deploy
|
|
@@ -111,6 +115,7 @@ class AgentDiscoveryService:
|
|
|
111
115
|
# Apply exclusion filtering
|
|
112
116
|
filtered_files = []
|
|
113
117
|
excluded_count = 0
|
|
118
|
+
non_mpm_count = 0
|
|
114
119
|
|
|
115
120
|
for template_file in template_files:
|
|
116
121
|
agent_name = template_file.stem
|
|
@@ -121,14 +126,24 @@ class AgentDiscoveryService:
|
|
|
121
126
|
self.logger.debug(f"Excluding agent: {agent_name}")
|
|
122
127
|
continue
|
|
123
128
|
|
|
129
|
+
# Check if we should filter non-MPM agents
|
|
130
|
+
if filter_non_mpm and not self._is_mpm_agent(template_file):
|
|
131
|
+
non_mpm_count += 1
|
|
132
|
+
self.logger.debug(f"Filtering non-MPM agent: {agent_name}")
|
|
133
|
+
continue
|
|
134
|
+
|
|
124
135
|
# Validate template file
|
|
125
136
|
if self._validate_template_file(template_file):
|
|
126
137
|
filtered_files.append(template_file)
|
|
127
138
|
else:
|
|
128
139
|
self.logger.warning(f"Invalid template file: {template_file.name}")
|
|
129
140
|
|
|
141
|
+
# Log filtering results
|
|
142
|
+
if filter_non_mpm and non_mpm_count > 0:
|
|
143
|
+
self.logger.info(f"Filtered out {non_mpm_count} non-MPM agents")
|
|
144
|
+
|
|
130
145
|
self.logger.info(
|
|
131
|
-
f"Found {len(template_files)} templates, excluded {excluded_count}, deploying {len(filtered_files)}"
|
|
146
|
+
f"Found {len(template_files)} templates, excluded {excluded_count}, filtered {non_mpm_count} non-MPM, deploying {len(filtered_files)}"
|
|
132
147
|
)
|
|
133
148
|
return filtered_files
|
|
134
149
|
|
|
@@ -236,6 +251,46 @@ class AgentDiscoveryService:
|
|
|
236
251
|
)
|
|
237
252
|
return None
|
|
238
253
|
|
|
254
|
+
def _is_mpm_agent(self, template_file: Path) -> bool:
|
|
255
|
+
"""Check if agent is authored by Claude MPM team.
|
|
256
|
+
|
|
257
|
+
MPM agents must have:
|
|
258
|
+
- An author field containing 'claude mpm', 'claude-mpm', or 'anthropic'
|
|
259
|
+
- A valid agent_version field
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
template_file: Path to the agent template JSON file
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
True if this is an MPM agent, False otherwise
|
|
266
|
+
"""
|
|
267
|
+
try:
|
|
268
|
+
template_data = json.loads(template_file.read_text())
|
|
269
|
+
metadata = template_data.get("metadata", {})
|
|
270
|
+
|
|
271
|
+
# Check for author field
|
|
272
|
+
author = metadata.get("author", "").lower()
|
|
273
|
+
has_valid_author = any(
|
|
274
|
+
pattern in author
|
|
275
|
+
for pattern in ["claude mpm", "claude-mpm", "anthropic"]
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Check for version field
|
|
279
|
+
has_version = bool(template_data.get("agent_version"))
|
|
280
|
+
|
|
281
|
+
if not has_valid_author or not has_version:
|
|
282
|
+
self.logger.debug(
|
|
283
|
+
f"Filtered non-MPM agent {template_file.name}: "
|
|
284
|
+
f"author='{metadata.get('author', 'missing')}', "
|
|
285
|
+
f"version={'present' if has_version else 'missing'}"
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
return has_valid_author and has_version
|
|
289
|
+
|
|
290
|
+
except Exception as e:
|
|
291
|
+
self.logger.debug(f"Error checking if {template_file} is MPM agent: {e}")
|
|
292
|
+
return False # Treat invalid templates as non-MPM
|
|
293
|
+
|
|
239
294
|
def _is_agent_excluded(
|
|
240
295
|
self,
|
|
241
296
|
agent_name: str,
|
|
@@ -357,6 +412,50 @@ class AgentDiscoveryService:
|
|
|
357
412
|
|
|
358
413
|
return bool(re.match(pattern, agent_name))
|
|
359
414
|
|
|
415
|
+
def _is_mpm_agent(
|
|
416
|
+
self, template_file: Path, config: Optional[Config] = None
|
|
417
|
+
) -> bool:
|
|
418
|
+
"""Check if agent is authored by Claude MPM team.
|
|
419
|
+
|
|
420
|
+
MPM agents must have:
|
|
421
|
+
- An author field containing configurable MPM patterns (default: 'claude mpm', 'claude-mpm', 'anthropic')
|
|
422
|
+
- A valid agent_version field
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
template_file: Path to the agent template JSON file
|
|
426
|
+
config: Configuration object for MPM patterns
|
|
427
|
+
|
|
428
|
+
Returns:
|
|
429
|
+
True if this is an MPM agent, False otherwise
|
|
430
|
+
"""
|
|
431
|
+
try:
|
|
432
|
+
template_data = json.loads(template_file.read_text())
|
|
433
|
+
metadata = template_data.get("metadata", {})
|
|
434
|
+
|
|
435
|
+
# Get MPM author patterns from config
|
|
436
|
+
if config:
|
|
437
|
+
mpm_patterns = config.get(
|
|
438
|
+
"agent_deployment.mpm_author_patterns",
|
|
439
|
+
["claude mpm", "claude-mpm", "anthropic"],
|
|
440
|
+
)
|
|
441
|
+
else:
|
|
442
|
+
mpm_patterns = ["claude mpm", "claude-mpm", "anthropic"]
|
|
443
|
+
|
|
444
|
+
# Check for author field
|
|
445
|
+
author = metadata.get("author", "").lower()
|
|
446
|
+
has_valid_author = any(
|
|
447
|
+
pattern.lower() in author for pattern in mpm_patterns
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
# Check for version field
|
|
451
|
+
has_version = bool(template_data.get("agent_version"))
|
|
452
|
+
|
|
453
|
+
return has_valid_author and has_version
|
|
454
|
+
|
|
455
|
+
except Exception as e:
|
|
456
|
+
self.logger.debug(f"Error checking if {template_file} is MPM agent: {e}")
|
|
457
|
+
return False # Treat invalid templates as non-MPM
|
|
458
|
+
|
|
360
459
|
def get_discovery_stats(self) -> Dict[str, Any]:
|
|
361
460
|
"""
|
|
362
461
|
Get statistics about agent discovery.
|
|
@@ -8,7 +8,6 @@ maintainability and testability.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import re
|
|
11
|
-
from datetime import datetime
|
|
12
11
|
from pathlib import Path
|
|
13
12
|
from typing import Any, Dict, Optional
|
|
14
13
|
|
|
@@ -148,19 +147,38 @@ class AgentFormatConverter:
|
|
|
148
147
|
# Extract instructions from YAML content
|
|
149
148
|
instructions = self._extract_instructions_from_yaml(yaml_content, agent_name)
|
|
150
149
|
|
|
151
|
-
#
|
|
152
|
-
|
|
150
|
+
# Map model names to Claude Code format
|
|
151
|
+
model_map = {
|
|
152
|
+
"claude-3-5-sonnet-20241022": "sonnet",
|
|
153
|
+
"claude-3-5-sonnet": "sonnet",
|
|
154
|
+
"claude-3-sonnet": "sonnet",
|
|
155
|
+
"claude-3-haiku": "haiku",
|
|
156
|
+
"claude-3-opus": "opus",
|
|
157
|
+
"sonnet": "sonnet",
|
|
158
|
+
"haiku": "haiku",
|
|
159
|
+
"opus": "opus",
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
mapped_model = model_map.get(model, "sonnet")
|
|
163
|
+
|
|
164
|
+
# Create multiline description with example (Claude Code format)
|
|
165
|
+
multiline_description = f"""{description}
|
|
166
|
+
|
|
167
|
+
<example>
|
|
168
|
+
Context: When you need specialized assistance from the {name} agent.
|
|
169
|
+
user: "I need help with {agent_name.replace('_', ' ').replace('-', ' ')} tasks"
|
|
170
|
+
assistant: "I'll use the {name} agent to provide specialized assistance."
|
|
171
|
+
</example>"""
|
|
153
172
|
|
|
173
|
+
# Build new YAML frontmatter - Claude Code compatible format
|
|
174
|
+
# NOTE: Removed tags field and other non-essential fields for Claude Code compatibility
|
|
154
175
|
new_frontmatter = f"""---
|
|
155
176
|
name: {name}
|
|
156
|
-
description:
|
|
177
|
+
description: |
|
|
178
|
+
{self._indent_text(multiline_description, 2)}
|
|
179
|
+
model: {mapped_model}
|
|
157
180
|
version: "{version}"
|
|
158
181
|
author: "{author}"
|
|
159
|
-
created: "{current_time}"
|
|
160
|
-
updated: "{current_time}"
|
|
161
|
-
tags: ["{agent_name}", "mpm-framework"]
|
|
162
|
-
tools: {tools_list}
|
|
163
|
-
model: "{model}"
|
|
164
182
|
---
|
|
165
183
|
|
|
166
184
|
"""
|
|
@@ -447,3 +465,29 @@ model: "{model}"
|
|
|
447
465
|
except Exception as e:
|
|
448
466
|
self.logger.error(f"Failed to convert MD to JSON: {e}")
|
|
449
467
|
return json.dumps({"error": str(e)})
|
|
468
|
+
|
|
469
|
+
def _indent_text(self, text: str, spaces: int) -> str:
|
|
470
|
+
"""
|
|
471
|
+
Indent multiline text with specified number of spaces.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
text: Text to indent
|
|
475
|
+
spaces: Number of spaces for indentation
|
|
476
|
+
|
|
477
|
+
Returns:
|
|
478
|
+
Indented text
|
|
479
|
+
"""
|
|
480
|
+
if not text:
|
|
481
|
+
return ""
|
|
482
|
+
|
|
483
|
+
indent = " " * spaces
|
|
484
|
+
lines = text.split("\n")
|
|
485
|
+
indented_lines = []
|
|
486
|
+
|
|
487
|
+
for line in lines:
|
|
488
|
+
if line.strip(): # Non-empty lines get indented
|
|
489
|
+
indented_lines.append(indent + line)
|
|
490
|
+
else: # Empty lines stay empty
|
|
491
|
+
indented_lines.append("")
|
|
492
|
+
|
|
493
|
+
return "\n".join(indented_lines)
|