claude-mpm 4.0.19__py3-none-any.whl → 4.0.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/__main__.py +4 -0
  4. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +38 -2
  5. claude_mpm/agents/INSTRUCTIONS.md +74 -0
  6. claude_mpm/agents/OUTPUT_STYLE.md +84 -0
  7. claude_mpm/agents/WORKFLOW.md +308 -4
  8. claude_mpm/agents/agents_metadata.py +52 -0
  9. claude_mpm/agents/base_agent_loader.py +75 -19
  10. claude_mpm/agents/templates/__init__.py +4 -0
  11. claude_mpm/agents/templates/api_qa.json +206 -0
  12. claude_mpm/agents/templates/qa.json +1 -1
  13. claude_mpm/agents/templates/research.json +24 -16
  14. claude_mpm/agents/templates/ticketing.json +18 -5
  15. claude_mpm/agents/templates/vercel_ops_agent.json +281 -0
  16. claude_mpm/agents/templates/vercel_ops_instructions.md +582 -0
  17. claude_mpm/cli/__init__.py +23 -1
  18. claude_mpm/cli/__main__.py +4 -0
  19. claude_mpm/cli/commands/mcp_command_router.py +87 -1
  20. claude_mpm/cli/commands/mcp_install_commands.py +207 -26
  21. claude_mpm/cli/commands/memory.py +32 -5
  22. claude_mpm/cli/commands/run.py +33 -6
  23. claude_mpm/cli/parsers/base_parser.py +5 -0
  24. claude_mpm/cli/parsers/mcp_parser.py +23 -0
  25. claude_mpm/cli/parsers/run_parser.py +5 -0
  26. claude_mpm/cli/utils.py +17 -4
  27. claude_mpm/constants.py +1 -0
  28. claude_mpm/core/base_service.py +8 -2
  29. claude_mpm/core/config.py +122 -32
  30. claude_mpm/core/framework_loader.py +385 -34
  31. claude_mpm/core/interactive_session.py +77 -12
  32. claude_mpm/core/oneshot_session.py +7 -1
  33. claude_mpm/core/output_style_manager.py +468 -0
  34. claude_mpm/core/unified_paths.py +190 -21
  35. claude_mpm/hooks/claude_hooks/hook_handler.py +91 -16
  36. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +3 -0
  37. claude_mpm/init.py +1 -0
  38. claude_mpm/scripts/socketio_daemon.py +67 -7
  39. claude_mpm/scripts/socketio_daemon_hardened.py +897 -0
  40. claude_mpm/services/agents/deployment/agent_deployment.py +216 -10
  41. claude_mpm/services/agents/deployment/agent_template_builder.py +37 -1
  42. claude_mpm/services/agents/deployment/async_agent_deployment.py +65 -1
  43. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +441 -0
  44. claude_mpm/services/agents/memory/__init__.py +0 -2
  45. claude_mpm/services/agents/memory/agent_memory_manager.py +577 -44
  46. claude_mpm/services/agents/memory/content_manager.py +144 -14
  47. claude_mpm/services/agents/memory/template_generator.py +7 -354
  48. claude_mpm/services/mcp_gateway/server/stdio_server.py +61 -169
  49. claude_mpm/services/memory_hook_service.py +62 -4
  50. claude_mpm/services/runner_configuration_service.py +5 -9
  51. claude_mpm/services/socketio/server/broadcaster.py +32 -1
  52. claude_mpm/services/socketio/server/core.py +4 -0
  53. claude_mpm/services/socketio/server/main.py +23 -4
  54. claude_mpm/services/subprocess_launcher_service.py +5 -0
  55. {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/METADATA +1 -1
  56. {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/RECORD +60 -54
  57. claude_mpm/services/agents/memory/analyzer.py +0 -430
  58. {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/WHEEL +0 -0
  59. {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/entry_points.txt +0 -0
  60. {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/licenses/LICENSE +0 -0
  61. {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/top_level.txt +0 -0
@@ -32,7 +32,7 @@ import os
32
32
  import shutil
33
33
  import time
34
34
  from pathlib import Path
35
- from typing import Any, Dict, List, Optional
35
+ from typing import Any, Dict, List, Optional, Tuple
36
36
 
37
37
  from claude_mpm.config.paths import paths
38
38
  from claude_mpm.constants import AgentMetadata, EnvironmentVars, Paths
@@ -55,6 +55,7 @@ from .agent_metrics_collector import AgentMetricsCollector
55
55
  from .agent_template_builder import AgentTemplateBuilder
56
56
  from .agent_validator import AgentValidator
57
57
  from .agent_version_manager import AgentVersionManager
58
+ from .multi_source_deployment_service import MultiSourceAgentDeploymentService
58
59
 
59
60
 
60
61
  class AgentDeploymentService(AgentDeploymentInterface):
@@ -161,13 +162,16 @@ class AgentDeploymentService(AgentDeploymentInterface):
161
162
 
162
163
  # Initialize discovery service (after templates_dir is set)
163
164
  self.discovery_service = AgentDiscoveryService(self.templates_dir)
165
+
166
+ # Initialize multi-source deployment service for version comparison
167
+ self.multi_source_service = MultiSourceAgentDeploymentService()
164
168
 
165
- # Find base agent file
169
+ # Find base agent file with priority-based search
166
170
  if base_agent_path:
167
171
  self.base_agent_path = Path(base_agent_path)
168
172
  else:
169
- # Use centralized paths for consistency
170
- self.base_agent_path = paths.agents_dir / "base_agent.json"
173
+ # Priority-based search for base_agent.json
174
+ self.base_agent_path = self._find_base_agent_file()
171
175
 
172
176
  # Initialize configuration manager (after base_agent_path is set)
173
177
  self.configuration_manager = AgentConfigurationManager(self.base_agent_path)
@@ -177,6 +181,68 @@ class AgentDeploymentService(AgentDeploymentInterface):
177
181
 
178
182
  self.logger.info(f"Templates directory: {self.templates_dir}")
179
183
  self.logger.info(f"Base agent path: {self.base_agent_path}")
184
+
185
+ def _find_base_agent_file(self) -> Path:
186
+ """Find base agent file with priority-based search.
187
+
188
+ Priority order:
189
+ 1. Environment variable override (CLAUDE_MPM_BASE_AGENT_PATH)
190
+ 2. Current working directory (for local development)
191
+ 3. Known development locations
192
+ 4. User override location (~/.claude/agents/)
193
+ 5. Framework agents directory (from paths)
194
+ """
195
+ # Priority 0: Check environment variable override
196
+ env_path = os.environ.get("CLAUDE_MPM_BASE_AGENT_PATH")
197
+ if env_path:
198
+ env_base_agent = Path(env_path)
199
+ if env_base_agent.exists():
200
+ self.logger.info(f"Using environment variable base_agent: {env_base_agent}")
201
+ return env_base_agent
202
+ else:
203
+ self.logger.warning(f"CLAUDE_MPM_BASE_AGENT_PATH set but file doesn't exist: {env_base_agent}")
204
+
205
+ # Priority 1: Check current working directory for local development
206
+ cwd = Path.cwd()
207
+ cwd_base_agent = cwd / "src" / "claude_mpm" / "agents" / "base_agent.json"
208
+ if cwd_base_agent.exists():
209
+ self.logger.info(f"Using local development base_agent from cwd: {cwd_base_agent}")
210
+ return cwd_base_agent
211
+
212
+ # Priority 2: Check known development locations
213
+ known_dev_paths = [
214
+ Path("/Users/masa/Projects/claude-mpm/src/claude_mpm/agents/base_agent.json"),
215
+ Path.home() / "Projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
216
+ Path.home() / "projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
217
+ ]
218
+
219
+ for dev_path in known_dev_paths:
220
+ if dev_path.exists():
221
+ self.logger.info(f"Using development base_agent: {dev_path}")
222
+ return dev_path
223
+
224
+ # Priority 3: Check user override location
225
+ user_base_agent = Path.home() / ".claude" / "agents" / "base_agent.json"
226
+ if user_base_agent.exists():
227
+ self.logger.info(f"Using user override base_agent: {user_base_agent}")
228
+ return user_base_agent
229
+
230
+ # Priority 4: Use framework agents directory (fallback)
231
+ framework_base_agent = paths.agents_dir / "base_agent.json"
232
+ if framework_base_agent.exists():
233
+ self.logger.info(f"Using framework base_agent: {framework_base_agent}")
234
+ return framework_base_agent
235
+
236
+ # If still not found, log all searched locations and raise error
237
+ self.logger.error("Base agent file not found in any location:")
238
+ self.logger.error(f" 1. CWD: {cwd_base_agent}")
239
+ self.logger.error(f" 2. Dev paths: {known_dev_paths}")
240
+ self.logger.error(f" 3. User: {user_base_agent}")
241
+ self.logger.error(f" 4. Framework: {framework_base_agent}")
242
+
243
+ # Final fallback to framework path even if it doesn't exist
244
+ # (will fail later with better error message)
245
+ return framework_base_agent
180
246
 
181
247
  def deploy_agents(
182
248
  self,
@@ -310,20 +376,40 @@ class AgentDeploymentService(AgentDeploymentInterface):
310
376
  # Load base agent content
311
377
  base_agent_data, base_agent_version = self._load_base_agent()
312
378
 
313
- # Get and filter template files
314
- template_files = self._get_filtered_templates(excluded_agents, config)
315
- results["total"] = len(template_files)
379
+ # Check if we should use multi-source deployment
380
+ use_multi_source = self._should_use_multi_source_deployment(deployment_mode)
381
+
382
+ if use_multi_source:
383
+ # Use multi-source deployment to get highest version agents
384
+ template_files, agent_sources = self._get_multi_source_templates(
385
+ excluded_agents, config, agents_dir
386
+ )
387
+ results["total"] = len(template_files)
388
+ results["multi_source"] = True
389
+ results["agent_sources"] = agent_sources
390
+ else:
391
+ # Get and filter template files from single source
392
+ template_files = self._get_filtered_templates(excluded_agents, config)
393
+ results["total"] = len(template_files)
394
+ agent_sources = {}
316
395
 
317
396
  # Deploy each agent template
318
397
  for template_file in template_files:
398
+ template_file_path = template_file if isinstance(template_file, Path) else Path(template_file)
399
+ agent_name = template_file_path.stem
400
+
401
+ # Get source info for this agent (agent_sources now uses file stems as keys)
402
+ source_info = agent_sources.get(agent_name, "unknown") if agent_sources else "single"
403
+
319
404
  self._deploy_single_agent(
320
- template_file=template_file,
405
+ template_file=template_file_path,
321
406
  agents_dir=agents_dir,
322
407
  base_agent_data=base_agent_data,
323
408
  base_agent_version=base_agent_version,
324
409
  force_rebuild=force_rebuild,
325
410
  deployment_mode=deployment_mode,
326
411
  results=results,
412
+ source_info=source_info,
327
413
  )
328
414
 
329
415
  # Deploy system instructions and framework files
@@ -467,8 +553,10 @@ class AgentDeploymentService(AgentDeploymentInterface):
467
553
  self.logger.warning(f"Could not load base agent: {e}")
468
554
 
469
555
  # Build the agent markdown
556
+ # For single agent deployment, determine source from template location
557
+ source_info = self._determine_agent_source(template_file)
470
558
  agent_content = self.template_builder.build_agent_markdown(
471
- agent_name, template_file, base_agent_data
559
+ agent_name, template_file, base_agent_data, source_info
472
560
  )
473
561
  if not agent_content:
474
562
  self.logger.error(f"Failed to build agent content for {agent_name}")
@@ -718,6 +806,7 @@ class AgentDeploymentService(AgentDeploymentInterface):
718
806
  force_rebuild: bool,
719
807
  deployment_mode: str,
720
808
  results: Dict[str, Any],
809
+ source_info: str = "unknown",
721
810
  ) -> None:
722
811
  """
723
812
  Deploy a single agent template.
@@ -733,6 +822,7 @@ class AgentDeploymentService(AgentDeploymentInterface):
733
822
  force_rebuild: Whether to force rebuild
734
823
  deployment_mode: Deployment mode (update/project)
735
824
  results: Results dictionary to update
825
+ source_info: Source of the agent (system/project/user)
736
826
  """
737
827
  try:
738
828
  # METRICS: Track individual agent deployment time
@@ -762,7 +852,7 @@ class AgentDeploymentService(AgentDeploymentInterface):
762
852
 
763
853
  # Build the agent file as markdown with YAML frontmatter
764
854
  agent_content = self.template_builder.build_agent_markdown(
765
- agent_name, template_file, base_agent_data
855
+ agent_name, template_file, base_agent_data, source_info
766
856
  )
767
857
 
768
858
  # Write the agent file
@@ -912,6 +1002,122 @@ class AgentDeploymentService(AgentDeploymentInterface):
912
1002
 
913
1003
  validator = AgentFrontmatterValidator(self.logger)
914
1004
  return validator.validate_and_repair_existing_agents(agents_dir)
1005
+
1006
+ def _determine_agent_source(self, template_path: Path) -> str:
1007
+ """Determine the source of an agent from its template path.
1008
+
1009
+ WHY: When deploying single agents, we need to track their source
1010
+ for proper version management and debugging.
1011
+
1012
+ Args:
1013
+ template_path: Path to the agent template
1014
+
1015
+ Returns:
1016
+ Source string (system/project/user/unknown)
1017
+ """
1018
+ template_str = str(template_path.resolve())
1019
+
1020
+ # Check if it's a system template
1021
+ if "/claude_mpm/agents/templates/" in template_str or "/src/claude_mpm/agents/templates/" in template_str:
1022
+ return "system"
1023
+
1024
+ # Check if it's a project agent
1025
+ if "/.claude-mpm/agents/" in template_str:
1026
+ # Check if it's in the current working directory
1027
+ if str(self.working_directory) in template_str:
1028
+ return "project"
1029
+ # Check if it's in user home
1030
+ elif str(Path.home()) in template_str:
1031
+ return "user"
1032
+
1033
+ return "unknown"
1034
+
1035
+ def _should_use_multi_source_deployment(self, deployment_mode: str) -> bool:
1036
+ """Determine if multi-source deployment should be used.
1037
+
1038
+ WHY: Multi-source deployment ensures the highest version wins,
1039
+ but we may want to preserve backward compatibility in some modes.
1040
+
1041
+ Args:
1042
+ deployment_mode: Current deployment mode
1043
+
1044
+ Returns:
1045
+ True if multi-source deployment should be used
1046
+ """
1047
+ # Always use multi-source for update mode to get highest versions
1048
+ if deployment_mode == "update":
1049
+ return True
1050
+
1051
+ # For project mode, also use multi-source to ensure highest version wins
1052
+ # This is the key change - project mode should also compare versions
1053
+ if deployment_mode == "project":
1054
+ return True
1055
+
1056
+ return False
1057
+
1058
+ def _get_multi_source_templates(
1059
+ self, excluded_agents: List[str], config: Config, agents_dir: Path
1060
+ ) -> Tuple[List[Path], Dict[str, str]]:
1061
+ """Get agent templates from multiple sources with version comparison.
1062
+
1063
+ WHY: This method uses the multi-source service to discover agents
1064
+ from all available sources and select the highest version of each.
1065
+
1066
+ Args:
1067
+ excluded_agents: List of agents to exclude
1068
+ config: Configuration object
1069
+ agents_dir: Target deployment directory
1070
+
1071
+ Returns:
1072
+ Tuple of (template_files, agent_sources)
1073
+ """
1074
+ # Determine source directories
1075
+ system_templates_dir = self.templates_dir
1076
+ project_agents_dir = None
1077
+ user_agents_dir = None
1078
+
1079
+ # Check for project agents
1080
+ if self.working_directory:
1081
+ potential_project_dir = self.working_directory / ".claude-mpm" / "agents"
1082
+ if potential_project_dir.exists():
1083
+ project_agents_dir = potential_project_dir
1084
+ self.logger.info(f"Found project agents at: {project_agents_dir}")
1085
+
1086
+ # Check for user agents
1087
+ user_home = Path.home()
1088
+ potential_user_dir = user_home / ".claude-mpm" / "agents"
1089
+ if potential_user_dir.exists():
1090
+ user_agents_dir = potential_user_dir
1091
+ self.logger.info(f"Found user agents at: {user_agents_dir}")
1092
+
1093
+ # Get agents with version comparison
1094
+ agents_to_deploy, agent_sources = self.multi_source_service.get_agents_for_deployment(
1095
+ system_templates_dir=system_templates_dir,
1096
+ project_agents_dir=project_agents_dir,
1097
+ user_agents_dir=user_agents_dir,
1098
+ working_directory=self.working_directory,
1099
+ excluded_agents=excluded_agents,
1100
+ config=config
1101
+ )
1102
+
1103
+ # Compare with deployed versions if agents directory exists
1104
+ if agents_dir.exists():
1105
+ comparison_results = self.multi_source_service.compare_deployed_versions(
1106
+ deployed_agents_dir=agents_dir,
1107
+ agents_to_deploy=agents_to_deploy,
1108
+ agent_sources=agent_sources
1109
+ )
1110
+
1111
+ # Log version upgrades and source changes
1112
+ if comparison_results.get("version_upgrades"):
1113
+ self.logger.info(f"Version upgrades available for {len(comparison_results['version_upgrades'])} agents")
1114
+ if comparison_results.get("source_changes"):
1115
+ self.logger.info(f"Source changes for {len(comparison_results['source_changes'])} agents")
1116
+
1117
+ # Convert to list of Path objects
1118
+ template_files = list(agents_to_deploy.values())
1119
+
1120
+ return template_files, agent_sources
915
1121
 
916
1122
  # ================================================================================
917
1123
  # Interface Adapter Methods
@@ -31,7 +31,7 @@ class AgentTemplateBuilder:
31
31
  self.logger = get_logger(__name__)
32
32
 
33
33
  def build_agent_markdown(
34
- self, agent_name: str, template_path: Path, base_agent_data: dict
34
+ self, agent_name: str, template_path: Path, base_agent_data: dict, source_info: str = "unknown"
35
35
  ) -> str:
36
36
  """
37
37
  Build a complete agent markdown file with YAML frontmatter.
@@ -40,6 +40,7 @@ class AgentTemplateBuilder:
40
40
  agent_name: Name of the agent
41
41
  template_path: Path to the agent template JSON file
42
42
  base_agent_data: Base agent configuration data
43
+ source_info: Source of the agent (system/project/user)
43
44
 
44
45
  Returns:
45
46
  Complete markdown content with YAML frontmatter
@@ -197,6 +198,8 @@ class AgentTemplateBuilder:
197
198
  f"color: {color}",
198
199
  f"version: {agent_version}",
199
200
  f"type: {agent_type}",
201
+ f"source: {source_info}", # Track which source provided this agent
202
+ "author: claude-mpm", # Mark as system-managed agent
200
203
  "---",
201
204
  "",
202
205
  ]
@@ -211,6 +214,39 @@ class AgentTemplateBuilder:
211
214
  or base_agent_data.get("instructions")
212
215
  or "# Agent Instructions\n\nThis agent provides specialized assistance."
213
216
  )
217
+
218
+ # Add memory update instructions if not already present
219
+ if "memory-update" not in content and "Remember" not in content:
220
+ memory_instructions = """
221
+
222
+ ## Memory Updates
223
+
224
+ When you learn something important about this project that would be useful for future tasks, include it in your response JSON block:
225
+
226
+ ```json
227
+ {
228
+ "memory-update": {
229
+ "Project Architecture": ["Key architectural patterns or structures"],
230
+ "Implementation Guidelines": ["Important coding standards or practices"],
231
+ "Current Technical Context": ["Project-specific technical details"]
232
+ }
233
+ }
234
+ ```
235
+
236
+ Or use the simpler "remember" field for general learnings:
237
+
238
+ ```json
239
+ {
240
+ "remember": ["Learning 1", "Learning 2"]
241
+ }
242
+ ```
243
+
244
+ Only include memories that are:
245
+ - Project-specific (not generic programming knowledge)
246
+ - Likely to be useful in future tasks
247
+ - Not already documented elsewhere
248
+ """
249
+ content = content + memory_instructions
214
250
 
215
251
  return frontmatter + content
216
252
 
@@ -83,7 +83,8 @@ class AsyncAgentDeploymentService:
83
83
  if base_agent_path:
84
84
  self.base_agent_path = Path(base_agent_path)
85
85
  else:
86
- self.base_agent_path = paths.agents_dir / "base_agent.json"
86
+ # Use priority-based search for base_agent.json
87
+ self.base_agent_path = self._find_base_agent_file()
87
88
 
88
89
  # Thread pool for CPU-bound JSON parsing
89
90
  self.executor = ThreadPoolExecutor(max_workers=4)
@@ -94,6 +95,69 @@ class AsyncAgentDeploymentService:
94
95
  "parallel_files_processed": 0,
95
96
  "time_saved_ms": 0.0,
96
97
  }
98
+
99
+ self.logger.info(f"Base agent path: {self.base_agent_path}")
100
+
101
+ def _find_base_agent_file(self) -> Path:
102
+ """Find base agent file with priority-based search.
103
+
104
+ Priority order:
105
+ 1. Environment variable override (CLAUDE_MPM_BASE_AGENT_PATH)
106
+ 2. Current working directory (for local development)
107
+ 3. Known development locations
108
+ 4. User override location (~/.claude/agents/)
109
+ 5. Framework agents directory (from paths)
110
+ """
111
+ # Priority 0: Check environment variable override
112
+ env_path = os.environ.get("CLAUDE_MPM_BASE_AGENT_PATH")
113
+ if env_path:
114
+ env_base_agent = Path(env_path)
115
+ if env_base_agent.exists():
116
+ self.logger.info(f"Using environment variable base_agent: {env_base_agent}")
117
+ return env_base_agent
118
+ else:
119
+ self.logger.warning(f"CLAUDE_MPM_BASE_AGENT_PATH set but file doesn't exist: {env_base_agent}")
120
+
121
+ # Priority 1: Check current working directory for local development
122
+ cwd = Path.cwd()
123
+ cwd_base_agent = cwd / "src" / "claude_mpm" / "agents" / "base_agent.json"
124
+ if cwd_base_agent.exists():
125
+ self.logger.info(f"Using local development base_agent from cwd: {cwd_base_agent}")
126
+ return cwd_base_agent
127
+
128
+ # Priority 2: Check known development locations
129
+ known_dev_paths = [
130
+ Path("/Users/masa/Projects/claude-mpm/src/claude_mpm/agents/base_agent.json"),
131
+ Path.home() / "Projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
132
+ Path.home() / "projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
133
+ ]
134
+
135
+ for dev_path in known_dev_paths:
136
+ if dev_path.exists():
137
+ self.logger.info(f"Using development base_agent: {dev_path}")
138
+ return dev_path
139
+
140
+ # Priority 3: Check user override location
141
+ user_base_agent = Path.home() / ".claude" / "agents" / "base_agent.json"
142
+ if user_base_agent.exists():
143
+ self.logger.info(f"Using user override base_agent: {user_base_agent}")
144
+ return user_base_agent
145
+
146
+ # Priority 4: Use framework agents directory (fallback)
147
+ framework_base_agent = paths.agents_dir / "base_agent.json"
148
+ if framework_base_agent.exists():
149
+ self.logger.info(f"Using framework base_agent: {framework_base_agent}")
150
+ return framework_base_agent
151
+
152
+ # If still not found, log all searched locations
153
+ self.logger.warning("Base agent file not found in any location:")
154
+ self.logger.warning(f" 1. CWD: {cwd_base_agent}")
155
+ self.logger.warning(f" 2. Dev paths: {known_dev_paths}")
156
+ self.logger.warning(f" 3. User: {user_base_agent}")
157
+ self.logger.warning(f" 4. Framework: {framework_base_agent}")
158
+
159
+ # Final fallback to framework path even if it doesn't exist
160
+ return framework_base_agent
97
161
 
98
162
  async def discover_agents_async(
99
163
  self, directories: List[Path]