claude-mpm 4.13.2__py3-none-any.whl → 4.18.2__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/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +48 -17
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +227 -8
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/agentic-coder-optimizer.json +9 -2
- claude_mpm/agents/templates/api_qa.json +7 -1
- claude_mpm/agents/templates/clerk-ops.json +8 -1
- claude_mpm/agents/templates/code_analyzer.json +4 -1
- claude_mpm/agents/templates/dart_engineer.json +11 -1
- claude_mpm/agents/templates/data_engineer.json +11 -1
- claude_mpm/agents/templates/documentation.json +6 -1
- claude_mpm/agents/templates/engineer.json +18 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +8 -1
- claude_mpm/agents/templates/golang_engineer.json +11 -1
- claude_mpm/agents/templates/java_engineer.json +12 -2
- claude_mpm/agents/templates/local_ops_agent.json +1217 -6
- claude_mpm/agents/templates/nextjs_engineer.json +11 -1
- claude_mpm/agents/templates/ops.json +8 -1
- claude_mpm/agents/templates/php-engineer.json +11 -1
- claude_mpm/agents/templates/project_organizer.json +10 -3
- claude_mpm/agents/templates/prompt-engineer.json +5 -1
- claude_mpm/agents/templates/python_engineer.json +11 -1
- claude_mpm/agents/templates/qa.json +7 -1
- claude_mpm/agents/templates/react_engineer.json +11 -1
- claude_mpm/agents/templates/refactoring_engineer.json +8 -1
- claude_mpm/agents/templates/research.json +4 -1
- claude_mpm/agents/templates/ruby-engineer.json +11 -1
- claude_mpm/agents/templates/rust_engineer.json +11 -1
- claude_mpm/agents/templates/security.json +6 -1
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +6 -1
- claude_mpm/agents/templates/typescript_engineer.json +11 -1
- claude_mpm/agents/templates/vercel_ops_agent.json +8 -1
- claude_mpm/agents/templates/version_control.json +8 -1
- claude_mpm/agents/templates/web_qa.json +7 -1
- claude_mpm/agents/templates/web_ui.json +11 -1
- claude_mpm/cli/__init__.py +34 -706
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +204 -148
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +7 -9
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +294 -1788
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +39 -25
- claude_mpm/cli/commands/mpm_init_handler.py +8 -3
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/base_parser.py +98 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/auto_config_manager.py +10 -11
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/interfaces/__init__.py +74 -2
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/models/__init__.py +33 -0
- claude_mpm/services/core/models/agent_config.py +12 -28
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +36 -31
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +71 -24
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/memory_hook_service.py +4 -1
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +117 -8
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +238 -174
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ollama Model Provider Implementation for Claude MPM Framework
|
|
3
|
+
=============================================================
|
|
4
|
+
|
|
5
|
+
WHY: Enables local model execution via Ollama for privacy-sensitive content
|
|
6
|
+
analysis. Provides cost-effective alternative to cloud APIs with full control
|
|
7
|
+
over model selection and hosting.
|
|
8
|
+
|
|
9
|
+
DESIGN DECISION: Uses direct HTTP API calls to Ollama service rather than
|
|
10
|
+
heavyweight LangChain dependency. Keeps implementation lightweight and focused.
|
|
11
|
+
|
|
12
|
+
ARCHITECTURE:
|
|
13
|
+
- Direct integration with Ollama API (http://localhost:11434 by default)
|
|
14
|
+
- Task-specific model mapping based on research recommendations
|
|
15
|
+
- Automatic model availability checking and validation
|
|
16
|
+
- Graceful degradation when Ollama not available
|
|
17
|
+
|
|
18
|
+
RECOMMENDED MODELS (from research):
|
|
19
|
+
- SEO Analysis: llama3.3:70b (comprehensive analysis)
|
|
20
|
+
- Readability: gemma2:9b (fast, accurate)
|
|
21
|
+
- Grammar: qwen3:14b (specialized for grammar)
|
|
22
|
+
- Summarization: mistral:7b (concise summaries)
|
|
23
|
+
- Keyword Extraction: seoassistant (specialized SEO tool)
|
|
24
|
+
- General: gemma2:9b (good default balance)
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import asyncio
|
|
28
|
+
from typing import Any, Dict, List, Optional
|
|
29
|
+
|
|
30
|
+
import aiohttp
|
|
31
|
+
|
|
32
|
+
from claude_mpm.services.core.interfaces.model import ModelCapability, ModelResponse
|
|
33
|
+
from claude_mpm.services.model.base_provider import BaseModelProvider
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OllamaProvider(BaseModelProvider):
|
|
37
|
+
"""
|
|
38
|
+
Ollama local model provider.
|
|
39
|
+
|
|
40
|
+
WHY: Provides privacy-preserving local content analysis without sending
|
|
41
|
+
data to cloud services. Cost-effective for high-volume processing.
|
|
42
|
+
|
|
43
|
+
Configuration:
|
|
44
|
+
host: Ollama API endpoint (default: http://localhost:11434)
|
|
45
|
+
timeout: Request timeout in seconds (default: 30)
|
|
46
|
+
models: Dict mapping capabilities to model names (optional)
|
|
47
|
+
|
|
48
|
+
Usage:
|
|
49
|
+
provider = OllamaProvider(config={
|
|
50
|
+
"host": "http://localhost:11434",
|
|
51
|
+
"models": {
|
|
52
|
+
"seo_analysis": "llama3.3:70b"
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
if await provider.is_available():
|
|
57
|
+
response = await provider.analyze_content(
|
|
58
|
+
content="Your content",
|
|
59
|
+
task=ModelCapability.SEO_ANALYSIS
|
|
60
|
+
)
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Default model mappings based on research recommendations
|
|
64
|
+
DEFAULT_MODELS: Dict[ModelCapability, str] = {
|
|
65
|
+
ModelCapability.SEO_ANALYSIS: "llama3.3:70b",
|
|
66
|
+
ModelCapability.READABILITY: "gemma2:9b",
|
|
67
|
+
ModelCapability.GRAMMAR: "qwen3:14b",
|
|
68
|
+
ModelCapability.SUMMARIZATION: "mistral:7b",
|
|
69
|
+
ModelCapability.KEYWORD_EXTRACTION: "seoassistant",
|
|
70
|
+
ModelCapability.ACCESSIBILITY: "gemma2:9b",
|
|
71
|
+
ModelCapability.SENTIMENT: "gemma2:9b",
|
|
72
|
+
ModelCapability.GENERAL: "gemma2:9b",
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
|
76
|
+
"""
|
|
77
|
+
Initialize Ollama provider.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
config: Configuration dict with:
|
|
81
|
+
- host: Ollama API endpoint
|
|
82
|
+
- timeout: Request timeout in seconds
|
|
83
|
+
- models: Custom model mappings
|
|
84
|
+
"""
|
|
85
|
+
super().__init__(provider_name="ollama", config=config or {})
|
|
86
|
+
|
|
87
|
+
self.host = self.get_config("host", "http://localhost:11434")
|
|
88
|
+
self.timeout = self.get_config("timeout", 30)
|
|
89
|
+
|
|
90
|
+
# Merge custom models with defaults
|
|
91
|
+
custom_models = self.get_config("models", {})
|
|
92
|
+
self.model_mapping = self.DEFAULT_MODELS.copy()
|
|
93
|
+
if custom_models:
|
|
94
|
+
# Convert string keys to ModelCapability if needed
|
|
95
|
+
for key, value in custom_models.items():
|
|
96
|
+
if isinstance(key, str):
|
|
97
|
+
try:
|
|
98
|
+
capability = ModelCapability(key)
|
|
99
|
+
self.model_mapping[capability] = value
|
|
100
|
+
except ValueError:
|
|
101
|
+
self.log_warning(f"Unknown capability in config: {key}")
|
|
102
|
+
else:
|
|
103
|
+
self.model_mapping[key] = value
|
|
104
|
+
|
|
105
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
|
106
|
+
self._available_models: List[str] = []
|
|
107
|
+
|
|
108
|
+
async def initialize(self) -> bool:
|
|
109
|
+
"""
|
|
110
|
+
Initialize Ollama provider.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
True if initialization successful
|
|
114
|
+
"""
|
|
115
|
+
self.log_info(f"Initializing Ollama provider at {self.host}")
|
|
116
|
+
|
|
117
|
+
# Create HTTP session
|
|
118
|
+
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
|
119
|
+
self._session = aiohttp.ClientSession(timeout=timeout)
|
|
120
|
+
|
|
121
|
+
# Check availability
|
|
122
|
+
if not await self.is_available():
|
|
123
|
+
self.log_warning("Ollama service not available")
|
|
124
|
+
self._initialized = False
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
# Fetch available models
|
|
128
|
+
self._available_models = await self.get_available_models()
|
|
129
|
+
self.log_info(f"Found {len(self._available_models)} available models")
|
|
130
|
+
|
|
131
|
+
self._initialized = True
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
async def shutdown(self) -> None:
|
|
135
|
+
"""Shutdown provider and cleanup resources."""
|
|
136
|
+
self.log_info("Shutting down Ollama provider")
|
|
137
|
+
|
|
138
|
+
if self._session and not self._session.closed:
|
|
139
|
+
await self._session.close()
|
|
140
|
+
|
|
141
|
+
self._shutdown = True
|
|
142
|
+
|
|
143
|
+
async def is_available(self) -> bool:
|
|
144
|
+
"""
|
|
145
|
+
Check if Ollama service is available.
|
|
146
|
+
|
|
147
|
+
WHY: Enables auto-fallback routing. Returns False if service
|
|
148
|
+
is not running or unreachable.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
True if Ollama is reachable and functional
|
|
152
|
+
"""
|
|
153
|
+
try:
|
|
154
|
+
# Ensure we have a session
|
|
155
|
+
if not self._session or self._session.closed:
|
|
156
|
+
timeout = aiohttp.ClientTimeout(total=5)
|
|
157
|
+
self._session = aiohttp.ClientSession(timeout=timeout)
|
|
158
|
+
|
|
159
|
+
# Try to fetch tags (models list)
|
|
160
|
+
async with self._session.get(f"{self.host}/api/tags") as response:
|
|
161
|
+
if response.status == 200:
|
|
162
|
+
return True
|
|
163
|
+
self.log_warning(f"Ollama returned status {response.status}")
|
|
164
|
+
return False
|
|
165
|
+
|
|
166
|
+
except aiohttp.ClientError as e:
|
|
167
|
+
self.log_debug(f"Ollama not available: {e}")
|
|
168
|
+
return False
|
|
169
|
+
except Exception as e:
|
|
170
|
+
self.log_warning(f"Error checking Ollama availability: {e}")
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
async def get_available_models(self) -> List[str]:
|
|
174
|
+
"""
|
|
175
|
+
List available models from Ollama.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
List of model names (e.g., ["llama3.3:70b", "gemma2:9b"])
|
|
179
|
+
"""
|
|
180
|
+
try:
|
|
181
|
+
if not self._session or self._session.closed:
|
|
182
|
+
timeout = aiohttp.ClientTimeout(total=5)
|
|
183
|
+
self._session = aiohttp.ClientSession(timeout=timeout)
|
|
184
|
+
|
|
185
|
+
async with self._session.get(f"{self.host}/api/tags") as response:
|
|
186
|
+
if response.status == 200:
|
|
187
|
+
data = await response.json()
|
|
188
|
+
return [model["name"] for model in data.get("models", [])]
|
|
189
|
+
self.log_error(f"Failed to fetch models: status {response.status}")
|
|
190
|
+
return []
|
|
191
|
+
|
|
192
|
+
except Exception as e:
|
|
193
|
+
self.log_error(f"Error fetching available models: {e}")
|
|
194
|
+
return []
|
|
195
|
+
|
|
196
|
+
def get_supported_capabilities(self) -> List[ModelCapability]:
|
|
197
|
+
"""
|
|
198
|
+
Return all supported capabilities.
|
|
199
|
+
|
|
200
|
+
WHY: Ollama supports all capabilities, routing to different models.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
List of all ModelCapability values
|
|
204
|
+
"""
|
|
205
|
+
return list(ModelCapability)
|
|
206
|
+
|
|
207
|
+
def _get_model_for_task(self, task: ModelCapability) -> str:
|
|
208
|
+
"""
|
|
209
|
+
Get optimal model for task.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
task: Task capability
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Model name from mapping
|
|
216
|
+
"""
|
|
217
|
+
return self.model_mapping.get(
|
|
218
|
+
task, self.DEFAULT_MODELS[ModelCapability.GENERAL]
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
async def analyze_content(
|
|
222
|
+
self,
|
|
223
|
+
content: str,
|
|
224
|
+
task: ModelCapability,
|
|
225
|
+
model: Optional[str] = None,
|
|
226
|
+
**kwargs,
|
|
227
|
+
) -> ModelResponse:
|
|
228
|
+
"""
|
|
229
|
+
Analyze content using Ollama model.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
content: Text content to analyze
|
|
233
|
+
task: Type of analysis
|
|
234
|
+
model: Optional specific model (overrides task mapping)
|
|
235
|
+
**kwargs: Additional options:
|
|
236
|
+
- temperature: Sampling temperature (0.0-1.0)
|
|
237
|
+
- max_tokens: Maximum response tokens
|
|
238
|
+
- stream: Enable streaming (not yet implemented)
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
ModelResponse with analysis results
|
|
242
|
+
"""
|
|
243
|
+
# Validate content
|
|
244
|
+
if not self.validate_content(content, max_length=100000):
|
|
245
|
+
return self.create_response(
|
|
246
|
+
success=False,
|
|
247
|
+
model=model or "unknown",
|
|
248
|
+
task=task,
|
|
249
|
+
error="Invalid content provided",
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Check if initialized
|
|
253
|
+
if not self._initialized:
|
|
254
|
+
await self.initialize()
|
|
255
|
+
|
|
256
|
+
if not self._initialized:
|
|
257
|
+
return self.create_response(
|
|
258
|
+
success=False,
|
|
259
|
+
model=model or "unknown",
|
|
260
|
+
task=task,
|
|
261
|
+
error="Ollama provider not initialized",
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Select model
|
|
265
|
+
selected_model = model or self._get_model_for_task(task)
|
|
266
|
+
|
|
267
|
+
# Check if model is available
|
|
268
|
+
if selected_model not in self._available_models:
|
|
269
|
+
self.log_warning(
|
|
270
|
+
f"Model {selected_model} not found. "
|
|
271
|
+
f"Available: {', '.join(self._available_models[:5])}..."
|
|
272
|
+
)
|
|
273
|
+
return self.create_response(
|
|
274
|
+
success=False,
|
|
275
|
+
model=selected_model,
|
|
276
|
+
task=task,
|
|
277
|
+
error=f"Model {selected_model} not available in Ollama",
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# Generate prompt
|
|
281
|
+
prompt = self.get_task_prompt(task, content)
|
|
282
|
+
|
|
283
|
+
# Call Ollama API with retry logic
|
|
284
|
+
return await self.analyze_with_retry(
|
|
285
|
+
self._call_ollama,
|
|
286
|
+
prompt,
|
|
287
|
+
task,
|
|
288
|
+
selected_model,
|
|
289
|
+
**kwargs,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
async def _call_ollama(
|
|
293
|
+
self,
|
|
294
|
+
prompt: str,
|
|
295
|
+
task: ModelCapability,
|
|
296
|
+
model: str,
|
|
297
|
+
**kwargs,
|
|
298
|
+
) -> ModelResponse:
|
|
299
|
+
"""
|
|
300
|
+
Internal method to call Ollama API.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
prompt: Generated prompt
|
|
304
|
+
task: Task capability
|
|
305
|
+
model: Model to use
|
|
306
|
+
**kwargs: Additional options
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
ModelResponse
|
|
310
|
+
"""
|
|
311
|
+
try:
|
|
312
|
+
# Prepare request
|
|
313
|
+
payload = {
|
|
314
|
+
"model": model,
|
|
315
|
+
"prompt": prompt,
|
|
316
|
+
"stream": False, # TODO: Implement streaming
|
|
317
|
+
"options": {},
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
# Add optional parameters
|
|
321
|
+
if "temperature" in kwargs:
|
|
322
|
+
payload["options"]["temperature"] = kwargs["temperature"]
|
|
323
|
+
if "max_tokens" in kwargs:
|
|
324
|
+
payload["options"]["num_predict"] = kwargs["max_tokens"]
|
|
325
|
+
|
|
326
|
+
# Make request
|
|
327
|
+
async with self._session.post(
|
|
328
|
+
f"{self.host}/api/generate",
|
|
329
|
+
json=payload,
|
|
330
|
+
) as response:
|
|
331
|
+
if response.status == 200:
|
|
332
|
+
data = await response.json()
|
|
333
|
+
result_text = data.get("response", "")
|
|
334
|
+
|
|
335
|
+
# Extract metadata
|
|
336
|
+
metadata = {
|
|
337
|
+
"model": model,
|
|
338
|
+
"total_duration": data.get("total_duration", 0)
|
|
339
|
+
/ 1e9, # ns to s
|
|
340
|
+
"load_duration": data.get("load_duration", 0) / 1e9,
|
|
341
|
+
"prompt_eval_count": data.get("prompt_eval_count", 0),
|
|
342
|
+
"eval_count": data.get("eval_count", 0),
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return self.create_response(
|
|
346
|
+
success=True,
|
|
347
|
+
model=model,
|
|
348
|
+
task=task,
|
|
349
|
+
result=result_text,
|
|
350
|
+
metadata=metadata,
|
|
351
|
+
)
|
|
352
|
+
error_text = await response.text()
|
|
353
|
+
return self.create_response(
|
|
354
|
+
success=False,
|
|
355
|
+
model=model,
|
|
356
|
+
task=task,
|
|
357
|
+
error=f"Ollama API error {response.status}: {error_text}",
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
except asyncio.TimeoutError:
|
|
361
|
+
return self.create_response(
|
|
362
|
+
success=False,
|
|
363
|
+
model=model,
|
|
364
|
+
task=task,
|
|
365
|
+
error=f"Request timeout after {self.timeout}s",
|
|
366
|
+
)
|
|
367
|
+
except Exception as e:
|
|
368
|
+
return self.create_response(
|
|
369
|
+
success=False,
|
|
370
|
+
model=model,
|
|
371
|
+
task=task,
|
|
372
|
+
error=f"Request failed: {e!s}",
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
async def get_model_info(self, model: str) -> Dict[str, Any]:
|
|
376
|
+
"""
|
|
377
|
+
Get detailed information about a model.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
model: Model name
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
Dictionary with model information
|
|
384
|
+
"""
|
|
385
|
+
try:
|
|
386
|
+
if not self._session or self._session.closed:
|
|
387
|
+
timeout = aiohttp.ClientTimeout(total=5)
|
|
388
|
+
self._session = aiohttp.ClientSession(timeout=timeout)
|
|
389
|
+
|
|
390
|
+
async with self._session.post(
|
|
391
|
+
f"{self.host}/api/show",
|
|
392
|
+
json={"name": model},
|
|
393
|
+
) as response:
|
|
394
|
+
if response.status == 200:
|
|
395
|
+
data = await response.json()
|
|
396
|
+
return {
|
|
397
|
+
"name": model,
|
|
398
|
+
"modelfile": data.get("modelfile", ""),
|
|
399
|
+
"parameters": data.get("parameters", ""),
|
|
400
|
+
"template": data.get("template", ""),
|
|
401
|
+
"details": data.get("details", {}),
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
"name": model,
|
|
405
|
+
"error": f"Status {response.status}",
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
except Exception as e:
|
|
409
|
+
return {
|
|
410
|
+
"name": model,
|
|
411
|
+
"error": str(e),
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
__all__ = ["OllamaProvider"]
|
|
@@ -31,6 +31,7 @@ import time
|
|
|
31
31
|
from pathlib import Path
|
|
32
32
|
from typing import Optional, Tuple
|
|
33
33
|
|
|
34
|
+
from ...core.enums import OperationResult
|
|
34
35
|
from ...core.logging_config import get_logger
|
|
35
36
|
|
|
36
37
|
|
|
@@ -906,7 +907,7 @@ class DaemonManager:
|
|
|
906
907
|
with self.startup_status_file.open() as f:
|
|
907
908
|
status = f.read().strip()
|
|
908
909
|
|
|
909
|
-
if status ==
|
|
910
|
+
if status == OperationResult.SUCCESS:
|
|
910
911
|
# Cleanup status file
|
|
911
912
|
Path(self.startup_status_file).unlink(missing_ok=True)
|
|
912
913
|
return True
|
|
@@ -936,7 +937,7 @@ class DaemonManager:
|
|
|
936
937
|
# Don't check if file exists - we need to write to it regardless
|
|
937
938
|
# The parent created it and is waiting for us to update it
|
|
938
939
|
with self.startup_status_file.open("w") as f:
|
|
939
|
-
f.write(
|
|
940
|
+
f.write(OperationResult.SUCCESS)
|
|
940
941
|
f.flush() # Ensure it's written immediately
|
|
941
942
|
os.fsync(f.fileno()) # Force write to disk
|
|
942
943
|
except Exception:
|
|
@@ -18,6 +18,7 @@ from typing import Dict, Set
|
|
|
18
18
|
|
|
19
19
|
import socketio
|
|
20
20
|
|
|
21
|
+
from ....core.enums import ServiceState
|
|
21
22
|
from ....core.logging_config import get_logger
|
|
22
23
|
|
|
23
24
|
|
|
@@ -128,7 +129,7 @@ class DashboardHandler:
|
|
|
128
129
|
try:
|
|
129
130
|
status = {
|
|
130
131
|
"service": "unified-monitor",
|
|
131
|
-
"status":
|
|
132
|
+
"status": ServiceState.RUNNING,
|
|
132
133
|
"clients_connected": len(self.connected_clients),
|
|
133
134
|
"uptime": asyncio.get_event_loop().time(),
|
|
134
135
|
"features": {
|
|
@@ -19,6 +19,7 @@ from typing import Dict, List
|
|
|
19
19
|
|
|
20
20
|
import socketio
|
|
21
21
|
|
|
22
|
+
from ....core.enums import ServiceState
|
|
22
23
|
from ....core.logging_config import get_logger
|
|
23
24
|
|
|
24
25
|
|
|
@@ -170,7 +171,7 @@ class HookHandler:
|
|
|
170
171
|
session_info = {
|
|
171
172
|
"session_id": session_id,
|
|
172
173
|
"start_time": asyncio.get_event_loop().time(),
|
|
173
|
-
"status":
|
|
174
|
+
"status": ServiceState.RUNNING,
|
|
174
175
|
"event_count": 0,
|
|
175
176
|
"last_activity": asyncio.get_event_loop().time(),
|
|
176
177
|
"metadata": data.get("metadata", {}),
|
|
@@ -23,6 +23,7 @@ import time
|
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from typing import Optional, Tuple
|
|
25
25
|
|
|
26
|
+
from ....core.enums import OperationResult
|
|
26
27
|
from ....core.logging_config import get_logger
|
|
27
28
|
|
|
28
29
|
|
|
@@ -388,7 +389,7 @@ class DaemonLifecycle:
|
|
|
388
389
|
with self.startup_status_file.open() as f:
|
|
389
390
|
status = f.read().strip()
|
|
390
391
|
|
|
391
|
-
if status ==
|
|
392
|
+
if status == OperationResult.SUCCESS:
|
|
392
393
|
# Child started successfully
|
|
393
394
|
self._cleanup_status_file()
|
|
394
395
|
return True
|
|
@@ -438,7 +439,7 @@ class DaemonLifecycle:
|
|
|
438
439
|
if self.startup_status_file:
|
|
439
440
|
try:
|
|
440
441
|
with self.startup_status_file.open("w") as f:
|
|
441
|
-
f.write(
|
|
442
|
+
f.write(OperationResult.SUCCESS)
|
|
442
443
|
except Exception as e:
|
|
443
444
|
self.logger.error(f"Failed to report startup success: {e}")
|
|
444
445
|
|
|
@@ -26,6 +26,7 @@ from typing import Dict, Optional
|
|
|
26
26
|
import socketio
|
|
27
27
|
from aiohttp import web
|
|
28
28
|
|
|
29
|
+
from ...core.enums import ServiceState
|
|
29
30
|
from ...core.logging_config import get_logger
|
|
30
31
|
from ...dashboard.api.simple_directory import list_directory
|
|
31
32
|
from .event_emitter import get_event_emitter
|
|
@@ -333,7 +334,7 @@ class UnifiedMonitorServer:
|
|
|
333
334
|
|
|
334
335
|
return web.json_response(
|
|
335
336
|
{
|
|
336
|
-
"status":
|
|
337
|
+
"status": ServiceState.RUNNING,
|
|
337
338
|
"service": "claude-mpm-monitor", # Important: must match what is_our_service() checks
|
|
338
339
|
"version": version,
|
|
339
340
|
"port": self.port,
|
|
@@ -17,6 +17,7 @@ from datetime import timezone
|
|
|
17
17
|
from typing import Any, Dict, List, Optional
|
|
18
18
|
|
|
19
19
|
from claude_mpm.core.base_service import BaseService
|
|
20
|
+
from claude_mpm.core.enums import OperationResult, ServiceState
|
|
20
21
|
from claude_mpm.services.core.interfaces import SessionManagementInterface
|
|
21
22
|
|
|
22
23
|
|
|
@@ -223,7 +224,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
|
|
|
223
224
|
"id": session_id,
|
|
224
225
|
"config": session_config,
|
|
225
226
|
"start_time": time.time(),
|
|
226
|
-
"status":
|
|
227
|
+
"status": ServiceState.RUNNING,
|
|
227
228
|
"type": session_config.get("type", "interactive"),
|
|
228
229
|
}
|
|
229
230
|
|
|
@@ -267,7 +268,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
|
|
|
267
268
|
return self.active_sessions[session_id].copy()
|
|
268
269
|
return {
|
|
269
270
|
"id": session_id,
|
|
270
|
-
"status":
|
|
271
|
+
"status": OperationResult.ERROR,
|
|
271
272
|
"error": "Session not found",
|
|
272
273
|
}
|
|
273
274
|
|