claude-mpm 3.4.27__py3-none-any.whl → 3.5.1__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/INSTRUCTIONS.md +182 -299
- claude_mpm/agents/agent_loader.py +283 -57
- claude_mpm/agents/agent_loader_integration.py +6 -9
- claude_mpm/agents/base_agent.json +2 -1
- claude_mpm/agents/base_agent_loader.py +1 -1
- claude_mpm/cli/__init__.py +5 -7
- claude_mpm/cli/commands/__init__.py +0 -2
- claude_mpm/cli/commands/agents.py +1 -1
- claude_mpm/cli/commands/memory.py +1 -1
- claude_mpm/cli/commands/run.py +12 -0
- claude_mpm/cli/parser.py +0 -13
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/config/__init__.py +44 -2
- claude_mpm/config/agent_config.py +348 -0
- claude_mpm/config/paths.py +322 -0
- claude_mpm/constants.py +0 -1
- claude_mpm/core/__init__.py +2 -5
- claude_mpm/core/agent_registry.py +63 -17
- claude_mpm/core/claude_runner.py +354 -43
- claude_mpm/core/config.py +7 -1
- claude_mpm/core/config_aliases.py +4 -3
- claude_mpm/core/config_paths.py +151 -0
- claude_mpm/core/factories.py +4 -50
- claude_mpm/core/logger.py +11 -13
- claude_mpm/core/service_registry.py +2 -2
- claude_mpm/dashboard/static/js/components/agent-inference.js +101 -25
- claude_mpm/dashboard/static/js/components/event-processor.js +3 -2
- claude_mpm/hooks/claude_hooks/hook_handler.py +343 -83
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/init.py +37 -6
- claude_mpm/scripts/socketio_daemon.py +6 -2
- claude_mpm/services/__init__.py +71 -3
- claude_mpm/services/agents/__init__.py +85 -0
- claude_mpm/services/agents/deployment/__init__.py +21 -0
- claude_mpm/services/{agent_deployment.py → agents/deployment/agent_deployment.py} +192 -41
- claude_mpm/services/{agent_lifecycle_manager.py → agents/deployment/agent_lifecycle_manager.py} +11 -10
- claude_mpm/services/agents/loading/__init__.py +11 -0
- claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +9 -8
- claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +2 -2
- claude_mpm/services/{framework_agent_loader.py → agents/loading/framework_agent_loader.py} +116 -40
- claude_mpm/services/agents/management/__init__.py +9 -0
- claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +6 -5
- claude_mpm/services/agents/memory/__init__.py +21 -0
- claude_mpm/services/{agent_memory_manager.py → agents/memory/agent_memory_manager.py} +3 -3
- claude_mpm/services/agents/registry/__init__.py +29 -0
- claude_mpm/services/{agent_registry.py → agents/registry/agent_registry.py} +101 -16
- claude_mpm/services/{deployed_agent_discovery.py → agents/registry/deployed_agent_discovery.py} +12 -2
- claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +6 -5
- claude_mpm/services/async_session_logger.py +584 -0
- claude_mpm/services/claude_session_logger.py +299 -0
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +2 -2
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +17 -17
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +1 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +1 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +19 -24
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +1 -1
- claude_mpm/services/framework_claude_md_generator.py +4 -2
- claude_mpm/services/memory/__init__.py +17 -0
- claude_mpm/services/{memory_builder.py → memory/builder.py} +3 -3
- claude_mpm/services/memory/cache/__init__.py +14 -0
- claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +1 -1
- claude_mpm/services/memory/cache/simple_cache.py +317 -0
- claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +1 -1
- claude_mpm/services/{memory_router.py → memory/router.py} +1 -1
- claude_mpm/services/optimized_hook_service.py +542 -0
- claude_mpm/services/project_registry.py +14 -8
- claude_mpm/services/response_tracker.py +237 -0
- claude_mpm/services/ticketing_service_original.py +4 -2
- claude_mpm/services/version_control/branch_strategy.py +3 -1
- claude_mpm/utils/paths.py +12 -10
- claude_mpm/utils/session_logging.py +114 -0
- claude_mpm/validation/agent_validator.py +2 -1
- {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/METADATA +28 -20
- {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/RECORD +83 -106
- claude_mpm/cli/commands/ui.py +0 -57
- claude_mpm/core/simple_runner.py +0 -1046
- claude_mpm/hooks/builtin/__init__.py +0 -1
- claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
- claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
- claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
- claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
- claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
- claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
- claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
- claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
- claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
- claude_mpm/orchestration/__init__.py +0 -6
- claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
- claude_mpm/orchestration/archive/factory.py +0 -215
- claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
- claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
- claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
- claude_mpm/orchestration/archive/orchestrator.py +0 -501
- claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
- claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
- claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
- claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
- claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
- claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
- claude_mpm/schemas/workflow_validator.py +0 -411
- claude_mpm/services/parent_directory_manager/__init__.py +0 -577
- claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
- claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
- claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
- claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
- claude_mpm/services/parent_directory_manager/operations.py +0 -186
- claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
- claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
- claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
- claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
- claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
- claude_mpm/ui/__init__.py +0 -1
- claude_mpm/ui/rich_terminal_ui.py +0 -295
- claude_mpm/ui/terminal_ui.py +0 -328
- /claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +0 -0
- /claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +0 -0
- /claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +0 -0
- {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/WHEEL +0 -0
- {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/top_level.txt +0 -0
claude_mpm/cli/utils.py
CHANGED
|
@@ -60,7 +60,7 @@ def get_agent_versions_display() -> Optional[str]:
|
|
|
60
60
|
Formatted string containing agent version information, or None if failed
|
|
61
61
|
"""
|
|
62
62
|
try:
|
|
63
|
-
from ..services
|
|
63
|
+
from ..services import AgentDeploymentService
|
|
64
64
|
deployment_service = AgentDeploymentService()
|
|
65
65
|
|
|
66
66
|
# Get deployed agents
|
claude_mpm/config/__init__.py
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
"""Configuration module for claude-mpm."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Import only modules that exist
|
|
4
|
+
__all__ = []
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
# Import centralized path management
|
|
7
|
+
try:
|
|
8
|
+
from .paths import (
|
|
9
|
+
paths,
|
|
10
|
+
ClaudeMPMPaths,
|
|
11
|
+
get_project_root,
|
|
12
|
+
get_src_dir,
|
|
13
|
+
get_claude_mpm_dir,
|
|
14
|
+
get_agents_dir,
|
|
15
|
+
get_services_dir,
|
|
16
|
+
get_config_dir,
|
|
17
|
+
get_version,
|
|
18
|
+
ensure_src_in_path
|
|
19
|
+
)
|
|
20
|
+
__all__.extend([
|
|
21
|
+
'paths',
|
|
22
|
+
'ClaudeMPMPaths',
|
|
23
|
+
'get_project_root',
|
|
24
|
+
'get_src_dir',
|
|
25
|
+
'get_claude_mpm_dir',
|
|
26
|
+
'get_agents_dir',
|
|
27
|
+
'get_services_dir',
|
|
28
|
+
'get_config_dir',
|
|
29
|
+
'get_version',
|
|
30
|
+
'ensure_src_in_path'
|
|
31
|
+
])
|
|
32
|
+
except ImportError:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
# Try to import HookConfig if it exists
|
|
36
|
+
try:
|
|
37
|
+
from .hook_config import HookConfig
|
|
38
|
+
__all__.append('HookConfig')
|
|
39
|
+
except ImportError:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
# Import AgentConfig
|
|
43
|
+
try:
|
|
44
|
+
from .agent_config import AgentConfig, get_agent_config, set_agent_config, reset_agent_config
|
|
45
|
+
__all__.extend(['AgentConfig', 'get_agent_config', 'set_agent_config', 'reset_agent_config'])
|
|
46
|
+
except ImportError:
|
|
47
|
+
pass
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Agent Configuration Module
|
|
4
|
+
|
|
5
|
+
Provides configuration support for agent loading across all tiers,
|
|
6
|
+
with special support for PROJECT-level agent directories.
|
|
7
|
+
|
|
8
|
+
This module handles:
|
|
9
|
+
- Agent directory discovery and configuration
|
|
10
|
+
- Environment variable support for agent paths
|
|
11
|
+
- Project-specific agent overrides
|
|
12
|
+
- Tier precedence configuration
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Dict, Optional, List, Any
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
from enum import Enum
|
|
22
|
+
|
|
23
|
+
from claude_mpm.core.config_paths import ConfigPaths
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AgentPrecedenceMode(Enum):
|
|
29
|
+
"""Agent loading precedence modes."""
|
|
30
|
+
STRICT = "strict" # PROJECT > USER > SYSTEM (no fallback)
|
|
31
|
+
OVERRIDE = "override" # PROJECT > USER > SYSTEM (with fallback)
|
|
32
|
+
MERGE = "merge" # Merge agents from all tiers
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class AgentConfig:
|
|
37
|
+
"""Configuration for agent loading and discovery."""
|
|
38
|
+
|
|
39
|
+
# Agent directory paths
|
|
40
|
+
project_agents_dir: Optional[Path] = None
|
|
41
|
+
user_agents_dir: Optional[Path] = None
|
|
42
|
+
system_agents_dir: Optional[Path] = None
|
|
43
|
+
|
|
44
|
+
# Additional search paths (from environment or config)
|
|
45
|
+
additional_paths: List[Path] = field(default_factory=list)
|
|
46
|
+
|
|
47
|
+
# Precedence configuration
|
|
48
|
+
precedence_mode: AgentPrecedenceMode = AgentPrecedenceMode.OVERRIDE
|
|
49
|
+
|
|
50
|
+
# Feature flags
|
|
51
|
+
enable_project_agents: bool = True
|
|
52
|
+
enable_user_agents: bool = True
|
|
53
|
+
enable_system_agents: bool = True
|
|
54
|
+
enable_hot_reload: bool = True
|
|
55
|
+
|
|
56
|
+
# Cache configuration
|
|
57
|
+
cache_ttl_seconds: int = 3600
|
|
58
|
+
enable_caching: bool = True
|
|
59
|
+
|
|
60
|
+
# Validation settings
|
|
61
|
+
validate_on_load: bool = True
|
|
62
|
+
strict_validation: bool = False
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def from_environment(cls) -> 'AgentConfig':
|
|
66
|
+
"""
|
|
67
|
+
Create configuration from environment variables.
|
|
68
|
+
|
|
69
|
+
Environment variables:
|
|
70
|
+
- CLAUDE_MPM_PROJECT_AGENTS_DIR: Override project agents directory
|
|
71
|
+
- CLAUDE_MPM_USER_AGENTS_DIR: Override user agents directory
|
|
72
|
+
- CLAUDE_MPM_SYSTEM_AGENTS_DIR: Override system agents directory
|
|
73
|
+
- CLAUDE_MPM_AGENT_SEARCH_PATH: Additional paths (colon-separated)
|
|
74
|
+
- CLAUDE_MPM_AGENT_PRECEDENCE: Precedence mode (strict/override/merge)
|
|
75
|
+
- CLAUDE_MPM_DISABLE_PROJECT_AGENTS: Disable project agents
|
|
76
|
+
- CLAUDE_MPM_DISABLE_USER_AGENTS: Disable user agents
|
|
77
|
+
- CLAUDE_MPM_DISABLE_SYSTEM_AGENTS: Disable system agents
|
|
78
|
+
- CLAUDE_MPM_AGENT_HOT_RELOAD: Enable/disable hot reload
|
|
79
|
+
- CLAUDE_MPM_AGENT_CACHE_TTL: Cache TTL in seconds
|
|
80
|
+
"""
|
|
81
|
+
config = cls()
|
|
82
|
+
|
|
83
|
+
# Directory overrides
|
|
84
|
+
if proj_dir := os.getenv('CLAUDE_MPM_PROJECT_AGENTS_DIR'):
|
|
85
|
+
config.project_agents_dir = Path(proj_dir)
|
|
86
|
+
logger.info(f"Project agents directory override: {proj_dir}")
|
|
87
|
+
|
|
88
|
+
if user_dir := os.getenv('CLAUDE_MPM_USER_AGENTS_DIR'):
|
|
89
|
+
config.user_agents_dir = Path(user_dir)
|
|
90
|
+
logger.info(f"User agents directory override: {user_dir}")
|
|
91
|
+
|
|
92
|
+
if sys_dir := os.getenv('CLAUDE_MPM_SYSTEM_AGENTS_DIR'):
|
|
93
|
+
config.system_agents_dir = Path(sys_dir)
|
|
94
|
+
logger.info(f"System agents directory override: {sys_dir}")
|
|
95
|
+
|
|
96
|
+
# Additional search paths
|
|
97
|
+
if search_path := os.getenv('CLAUDE_MPM_AGENT_SEARCH_PATH'):
|
|
98
|
+
paths = [Path(p.strip()) for p in search_path.split(':') if p.strip()]
|
|
99
|
+
config.additional_paths = [p for p in paths if p.exists()]
|
|
100
|
+
logger.info(f"Additional agent search paths: {config.additional_paths}")
|
|
101
|
+
|
|
102
|
+
# Precedence mode
|
|
103
|
+
if precedence := os.getenv('CLAUDE_MPM_AGENT_PRECEDENCE'):
|
|
104
|
+
try:
|
|
105
|
+
config.precedence_mode = AgentPrecedenceMode(precedence.lower())
|
|
106
|
+
logger.info(f"Agent precedence mode: {config.precedence_mode.value}")
|
|
107
|
+
except ValueError:
|
|
108
|
+
logger.warning(f"Invalid precedence mode: {precedence}, using default")
|
|
109
|
+
|
|
110
|
+
# Feature flags
|
|
111
|
+
config.enable_project_agents = os.getenv('CLAUDE_MPM_DISABLE_PROJECT_AGENTS', '').lower() != 'true'
|
|
112
|
+
config.enable_user_agents = os.getenv('CLAUDE_MPM_DISABLE_USER_AGENTS', '').lower() != 'true'
|
|
113
|
+
config.enable_system_agents = os.getenv('CLAUDE_MPM_DISABLE_SYSTEM_AGENTS', '').lower() != 'true'
|
|
114
|
+
config.enable_hot_reload = os.getenv('CLAUDE_MPM_AGENT_HOT_RELOAD', 'true').lower() == 'true'
|
|
115
|
+
|
|
116
|
+
# Cache configuration
|
|
117
|
+
if cache_ttl := os.getenv('CLAUDE_MPM_AGENT_CACHE_TTL'):
|
|
118
|
+
try:
|
|
119
|
+
config.cache_ttl_seconds = int(cache_ttl)
|
|
120
|
+
except ValueError:
|
|
121
|
+
logger.warning(f"Invalid cache TTL: {cache_ttl}, using default")
|
|
122
|
+
|
|
123
|
+
return config
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def from_file(cls, config_file: Path) -> 'AgentConfig':
|
|
127
|
+
"""
|
|
128
|
+
Load configuration from a JSON or YAML file.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
config_file: Path to configuration file
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
AgentConfig instance
|
|
135
|
+
"""
|
|
136
|
+
if not config_file.exists():
|
|
137
|
+
logger.warning(f"Config file not found: {config_file}")
|
|
138
|
+
return cls()
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
if config_file.suffix in ['.yaml', '.yml']:
|
|
142
|
+
import yaml
|
|
143
|
+
with open(config_file, 'r') as f:
|
|
144
|
+
data = yaml.safe_load(f)
|
|
145
|
+
else:
|
|
146
|
+
with open(config_file, 'r') as f:
|
|
147
|
+
data = json.load(f)
|
|
148
|
+
|
|
149
|
+
config = cls()
|
|
150
|
+
|
|
151
|
+
# Parse directory paths
|
|
152
|
+
if 'project_agents_dir' in data:
|
|
153
|
+
config.project_agents_dir = Path(data['project_agents_dir'])
|
|
154
|
+
if 'user_agents_dir' in data:
|
|
155
|
+
config.user_agents_dir = Path(data['user_agents_dir'])
|
|
156
|
+
if 'system_agents_dir' in data:
|
|
157
|
+
config.system_agents_dir = Path(data['system_agents_dir'])
|
|
158
|
+
|
|
159
|
+
# Parse additional paths
|
|
160
|
+
if 'additional_paths' in data:
|
|
161
|
+
config.additional_paths = [Path(p) for p in data['additional_paths']]
|
|
162
|
+
|
|
163
|
+
# Parse precedence mode
|
|
164
|
+
if 'precedence_mode' in data:
|
|
165
|
+
config.precedence_mode = AgentPrecedenceMode(data['precedence_mode'])
|
|
166
|
+
|
|
167
|
+
# Parse feature flags
|
|
168
|
+
for flag in ['enable_project_agents', 'enable_user_agents',
|
|
169
|
+
'enable_system_agents', 'enable_hot_reload',
|
|
170
|
+
'enable_caching', 'validate_on_load', 'strict_validation']:
|
|
171
|
+
if flag in data:
|
|
172
|
+
setattr(config, flag, bool(data[flag]))
|
|
173
|
+
|
|
174
|
+
# Parse cache TTL
|
|
175
|
+
if 'cache_ttl_seconds' in data:
|
|
176
|
+
config.cache_ttl_seconds = int(data['cache_ttl_seconds'])
|
|
177
|
+
|
|
178
|
+
return config
|
|
179
|
+
|
|
180
|
+
except Exception as e:
|
|
181
|
+
logger.error(f"Error loading config from {config_file}: {e}")
|
|
182
|
+
return cls()
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def auto_discover(cls) -> 'AgentConfig':
|
|
186
|
+
"""
|
|
187
|
+
Automatically discover agent directories and create configuration.
|
|
188
|
+
|
|
189
|
+
This method:
|
|
190
|
+
1. Checks environment variables first
|
|
191
|
+
2. Looks for config files in standard locations
|
|
192
|
+
3. Auto-discovers agent directories
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
AgentConfig with discovered settings
|
|
196
|
+
"""
|
|
197
|
+
# Start with environment configuration
|
|
198
|
+
config = cls.from_environment()
|
|
199
|
+
|
|
200
|
+
# Look for config file if not already configured
|
|
201
|
+
if not config.project_agents_dir and not config.user_agents_dir:
|
|
202
|
+
# Check for project config file
|
|
203
|
+
project_config = Path.cwd() / ConfigPaths.CONFIG_DIR / 'agent_config.yaml'
|
|
204
|
+
if project_config.exists():
|
|
205
|
+
logger.info(f"Loading project agent config from {project_config}")
|
|
206
|
+
file_config = cls.from_file(project_config)
|
|
207
|
+
# Merge with environment config (env takes precedence)
|
|
208
|
+
config = cls._merge_configs(config, file_config)
|
|
209
|
+
|
|
210
|
+
# Check for user config file
|
|
211
|
+
user_config_dir = ConfigPaths.get_user_config_dir()
|
|
212
|
+
if user_config_dir:
|
|
213
|
+
user_config = user_config_dir / 'agent_config.yaml'
|
|
214
|
+
if user_config.exists():
|
|
215
|
+
logger.info(f"Loading user agent config from {user_config}")
|
|
216
|
+
file_config = cls.from_file(user_config)
|
|
217
|
+
config = cls._merge_configs(config, file_config)
|
|
218
|
+
|
|
219
|
+
# Auto-discover directories if not configured
|
|
220
|
+
if not config.project_agents_dir:
|
|
221
|
+
project_agents = Path.cwd() / ConfigPaths.CONFIG_DIR / 'agents'
|
|
222
|
+
if project_agents.exists():
|
|
223
|
+
config.project_agents_dir = project_agents
|
|
224
|
+
logger.debug(f"Auto-discovered project agents at {project_agents}")
|
|
225
|
+
|
|
226
|
+
if not config.user_agents_dir:
|
|
227
|
+
user_agents = ConfigPaths.get_user_agents_dir()
|
|
228
|
+
if user_agents and user_agents.exists():
|
|
229
|
+
config.user_agents_dir = user_agents
|
|
230
|
+
logger.debug(f"Auto-discovered user agents at {user_agents}")
|
|
231
|
+
|
|
232
|
+
if not config.system_agents_dir:
|
|
233
|
+
# Default to built-in agents
|
|
234
|
+
system_agents = Path(__file__).parent.parent / 'agents'
|
|
235
|
+
if system_agents.exists():
|
|
236
|
+
config.system_agents_dir = system_agents
|
|
237
|
+
logger.debug(f"Auto-discovered system agents at {system_agents}")
|
|
238
|
+
|
|
239
|
+
return config
|
|
240
|
+
|
|
241
|
+
@staticmethod
|
|
242
|
+
def _merge_configs(primary: 'AgentConfig', secondary: 'AgentConfig') -> 'AgentConfig':
|
|
243
|
+
"""
|
|
244
|
+
Merge two configurations, with primary taking precedence.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
primary: Primary configuration (higher precedence)
|
|
248
|
+
secondary: Secondary configuration (lower precedence)
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Merged configuration
|
|
252
|
+
"""
|
|
253
|
+
result = AgentConfig()
|
|
254
|
+
|
|
255
|
+
# Merge directory paths (primary takes precedence)
|
|
256
|
+
result.project_agents_dir = primary.project_agents_dir or secondary.project_agents_dir
|
|
257
|
+
result.user_agents_dir = primary.user_agents_dir or secondary.user_agents_dir
|
|
258
|
+
result.system_agents_dir = primary.system_agents_dir or secondary.system_agents_dir
|
|
259
|
+
|
|
260
|
+
# Merge additional paths
|
|
261
|
+
result.additional_paths = list(set(primary.additional_paths + secondary.additional_paths))
|
|
262
|
+
|
|
263
|
+
# Use primary's settings for other fields
|
|
264
|
+
result.precedence_mode = primary.precedence_mode
|
|
265
|
+
result.enable_project_agents = primary.enable_project_agents
|
|
266
|
+
result.enable_user_agents = primary.enable_user_agents
|
|
267
|
+
result.enable_system_agents = primary.enable_system_agents
|
|
268
|
+
result.enable_hot_reload = primary.enable_hot_reload
|
|
269
|
+
result.cache_ttl_seconds = primary.cache_ttl_seconds
|
|
270
|
+
result.enable_caching = primary.enable_caching
|
|
271
|
+
result.validate_on_load = primary.validate_on_load
|
|
272
|
+
result.strict_validation = primary.strict_validation
|
|
273
|
+
|
|
274
|
+
return result
|
|
275
|
+
|
|
276
|
+
def get_enabled_tiers(self) -> Dict[str, Optional[Path]]:
|
|
277
|
+
"""
|
|
278
|
+
Get enabled agent directories by tier.
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
Dictionary mapping tier names to their paths (if enabled)
|
|
282
|
+
"""
|
|
283
|
+
tiers = {}
|
|
284
|
+
|
|
285
|
+
if self.enable_project_agents and self.project_agents_dir:
|
|
286
|
+
tiers['project'] = self.project_agents_dir
|
|
287
|
+
|
|
288
|
+
if self.enable_user_agents and self.user_agents_dir:
|
|
289
|
+
tiers['user'] = self.user_agents_dir
|
|
290
|
+
|
|
291
|
+
if self.enable_system_agents and self.system_agents_dir:
|
|
292
|
+
tiers['system'] = self.system_agents_dir
|
|
293
|
+
|
|
294
|
+
return tiers
|
|
295
|
+
|
|
296
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
297
|
+
"""Convert configuration to dictionary for serialization."""
|
|
298
|
+
return {
|
|
299
|
+
'project_agents_dir': str(self.project_agents_dir) if self.project_agents_dir else None,
|
|
300
|
+
'user_agents_dir': str(self.user_agents_dir) if self.user_agents_dir else None,
|
|
301
|
+
'system_agents_dir': str(self.system_agents_dir) if self.system_agents_dir else None,
|
|
302
|
+
'additional_paths': [str(p) for p in self.additional_paths],
|
|
303
|
+
'precedence_mode': self.precedence_mode.value,
|
|
304
|
+
'enable_project_agents': self.enable_project_agents,
|
|
305
|
+
'enable_user_agents': self.enable_user_agents,
|
|
306
|
+
'enable_system_agents': self.enable_system_agents,
|
|
307
|
+
'enable_hot_reload': self.enable_hot_reload,
|
|
308
|
+
'cache_ttl_seconds': self.cache_ttl_seconds,
|
|
309
|
+
'enable_caching': self.enable_caching,
|
|
310
|
+
'validate_on_load': self.validate_on_load,
|
|
311
|
+
'strict_validation': self.strict_validation
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
# Global configuration instance
|
|
316
|
+
_global_config: Optional[AgentConfig] = None
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def get_agent_config() -> AgentConfig:
|
|
320
|
+
"""
|
|
321
|
+
Get the global agent configuration.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
AgentConfig instance (auto-discovered if not set)
|
|
325
|
+
"""
|
|
326
|
+
global _global_config
|
|
327
|
+
if _global_config is None:
|
|
328
|
+
_global_config = AgentConfig.auto_discover()
|
|
329
|
+
return _global_config
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def set_agent_config(config: AgentConfig) -> None:
|
|
333
|
+
"""
|
|
334
|
+
Set the global agent configuration.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
config: AgentConfig instance to use globally
|
|
338
|
+
"""
|
|
339
|
+
global _global_config
|
|
340
|
+
_global_config = config
|
|
341
|
+
logger.info(f"Agent configuration updated: {config.get_enabled_tiers()}")
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def reset_agent_config() -> None:
|
|
345
|
+
"""Reset the global agent configuration to auto-discover on next access."""
|
|
346
|
+
global _global_config
|
|
347
|
+
_global_config = None
|
|
348
|
+
logger.info("Agent configuration reset")
|