claude-mpm 4.7.4__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.
Files changed (308) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  4. claude_mpm/agents/BASE_PM.md +106 -1
  5. claude_mpm/agents/OUTPUT_STYLE.md +329 -11
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
  7. claude_mpm/agents/agent_loader.py +17 -5
  8. claude_mpm/agents/frontmatter_validator.py +284 -253
  9. claude_mpm/agents/templates/README.md +465 -0
  10. claude_mpm/agents/templates/agent-manager.json +4 -1
  11. claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
  12. claude_mpm/agents/templates/api_qa.json +11 -2
  13. claude_mpm/agents/templates/circuit_breakers.md +638 -0
  14. claude_mpm/agents/templates/clerk-ops.json +12 -2
  15. claude_mpm/agents/templates/code_analyzer.json +8 -2
  16. claude_mpm/agents/templates/content-agent.json +358 -0
  17. claude_mpm/agents/templates/dart_engineer.json +15 -2
  18. claude_mpm/agents/templates/data_engineer.json +15 -2
  19. claude_mpm/agents/templates/documentation.json +10 -2
  20. claude_mpm/agents/templates/engineer.json +21 -1
  21. claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
  22. claude_mpm/agents/templates/git_file_tracking.md +584 -0
  23. claude_mpm/agents/templates/golang_engineer.json +270 -0
  24. claude_mpm/agents/templates/imagemagick.json +4 -1
  25. claude_mpm/agents/templates/java_engineer.json +346 -0
  26. claude_mpm/agents/templates/local_ops_agent.json +1227 -6
  27. claude_mpm/agents/templates/memory_manager.json +4 -1
  28. claude_mpm/agents/templates/nextjs_engineer.json +141 -133
  29. claude_mpm/agents/templates/ops.json +12 -2
  30. claude_mpm/agents/templates/php-engineer.json +270 -174
  31. claude_mpm/agents/templates/pm_examples.md +474 -0
  32. claude_mpm/agents/templates/pm_red_flags.md +240 -0
  33. claude_mpm/agents/templates/product_owner.json +338 -0
  34. claude_mpm/agents/templates/project_organizer.json +14 -4
  35. claude_mpm/agents/templates/prompt-engineer.json +13 -2
  36. claude_mpm/agents/templates/python_engineer.json +174 -81
  37. claude_mpm/agents/templates/qa.json +11 -2
  38. claude_mpm/agents/templates/react_engineer.json +16 -3
  39. claude_mpm/agents/templates/refactoring_engineer.json +12 -2
  40. claude_mpm/agents/templates/research.json +34 -21
  41. claude_mpm/agents/templates/response_format.md +583 -0
  42. claude_mpm/agents/templates/ruby-engineer.json +129 -192
  43. claude_mpm/agents/templates/rust_engineer.json +270 -0
  44. claude_mpm/agents/templates/security.json +10 -2
  45. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  46. claude_mpm/agents/templates/ticketing.json +10 -2
  47. claude_mpm/agents/templates/typescript_engineer.json +116 -125
  48. claude_mpm/agents/templates/validation_templates.md +312 -0
  49. claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
  50. claude_mpm/agents/templates/version_control.json +12 -2
  51. claude_mpm/agents/templates/web_qa.json +11 -2
  52. claude_mpm/agents/templates/web_ui.json +15 -2
  53. claude_mpm/cli/__init__.py +34 -614
  54. claude_mpm/cli/commands/agent_manager.py +25 -12
  55. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  56. claude_mpm/cli/commands/agents.py +235 -148
  57. claude_mpm/cli/commands/agents_detect.py +380 -0
  58. claude_mpm/cli/commands/agents_recommend.py +309 -0
  59. claude_mpm/cli/commands/aggregate.py +7 -3
  60. claude_mpm/cli/commands/analyze.py +9 -4
  61. claude_mpm/cli/commands/analyze_code.py +7 -2
  62. claude_mpm/cli/commands/auto_configure.py +570 -0
  63. claude_mpm/cli/commands/config.py +47 -13
  64. claude_mpm/cli/commands/configure.py +419 -1571
  65. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  66. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  67. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  68. claude_mpm/cli/commands/configure_models.py +18 -0
  69. claude_mpm/cli/commands/configure_navigation.py +167 -0
  70. claude_mpm/cli/commands/configure_paths.py +104 -0
  71. claude_mpm/cli/commands/configure_persistence.py +254 -0
  72. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  73. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  74. claude_mpm/cli/commands/configure_validators.py +73 -0
  75. claude_mpm/cli/commands/local_deploy.py +537 -0
  76. claude_mpm/cli/commands/memory.py +54 -20
  77. claude_mpm/cli/commands/mpm_init.py +585 -196
  78. claude_mpm/cli/commands/mpm_init_handler.py +37 -3
  79. claude_mpm/cli/commands/search.py +170 -4
  80. claude_mpm/cli/commands/upgrade.py +152 -0
  81. claude_mpm/cli/executor.py +202 -0
  82. claude_mpm/cli/helpers.py +105 -0
  83. claude_mpm/cli/interactive/__init__.py +3 -0
  84. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  85. claude_mpm/cli/parsers/__init__.py +7 -1
  86. claude_mpm/cli/parsers/agents_parser.py +9 -0
  87. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  88. claude_mpm/cli/parsers/base_parser.py +110 -3
  89. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  90. claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
  91. claude_mpm/cli/shared/output_formatters.py +28 -19
  92. claude_mpm/cli/startup.py +481 -0
  93. claude_mpm/cli/utils.py +52 -1
  94. claude_mpm/commands/mpm-agents-detect.md +168 -0
  95. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  96. claude_mpm/commands/mpm-agents.md +75 -1
  97. claude_mpm/commands/mpm-auto-configure.md +217 -0
  98. claude_mpm/commands/mpm-help.md +163 -0
  99. claude_mpm/commands/mpm-init.md +148 -3
  100. claude_mpm/commands/mpm-version.md +113 -0
  101. claude_mpm/commands/mpm.md +1 -0
  102. claude_mpm/config/agent_config.py +2 -2
  103. claude_mpm/config/model_config.py +428 -0
  104. claude_mpm/constants.py +1 -0
  105. claude_mpm/core/base_service.py +13 -12
  106. claude_mpm/core/enums.py +452 -0
  107. claude_mpm/core/factories.py +1 -1
  108. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  109. claude_mpm/core/interactive_session.py +9 -3
  110. claude_mpm/core/log_manager.py +2 -0
  111. claude_mpm/core/logging_config.py +6 -2
  112. claude_mpm/core/oneshot_session.py +8 -4
  113. claude_mpm/core/optimized_agent_loader.py +3 -3
  114. claude_mpm/core/output_style_manager.py +12 -192
  115. claude_mpm/core/service_registry.py +5 -1
  116. claude_mpm/core/types.py +2 -9
  117. claude_mpm/core/typing_utils.py +7 -6
  118. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  119. claude_mpm/dashboard/templates/index.html +3 -41
  120. claude_mpm/hooks/__init__.py +20 -0
  121. claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
  122. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  123. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
  124. claude_mpm/hooks/failure_learning/__init__.py +60 -0
  125. claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
  126. claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
  127. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
  128. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  129. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  130. claude_mpm/hooks/kuzu_memory_hook.py +37 -12
  131. claude_mpm/hooks/kuzu_response_hook.py +183 -0
  132. claude_mpm/models/resume_log.py +340 -0
  133. claude_mpm/services/agents/__init__.py +18 -5
  134. claude_mpm/services/agents/auto_config_manager.py +796 -0
  135. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  136. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  137. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  138. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  139. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  140. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  141. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  142. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  143. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  144. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  145. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  146. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  147. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  148. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  149. claude_mpm/services/agents/local_template_manager.py +1 -1
  150. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  151. claude_mpm/services/agents/observers.py +547 -0
  152. claude_mpm/services/agents/recommender.py +568 -0
  153. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  154. claude_mpm/services/command_handler_service.py +11 -5
  155. claude_mpm/services/core/__init__.py +33 -1
  156. claude_mpm/services/core/interfaces/__init__.py +90 -3
  157. claude_mpm/services/core/interfaces/agent.py +184 -0
  158. claude_mpm/services/core/interfaces/health.py +172 -0
  159. claude_mpm/services/core/interfaces/model.py +281 -0
  160. claude_mpm/services/core/interfaces/process.py +372 -0
  161. claude_mpm/services/core/interfaces/project.py +121 -0
  162. claude_mpm/services/core/interfaces/restart.py +307 -0
  163. claude_mpm/services/core/interfaces/stability.py +260 -0
  164. claude_mpm/services/core/memory_manager.py +11 -24
  165. claude_mpm/services/core/models/__init__.py +79 -0
  166. claude_mpm/services/core/models/agent_config.py +381 -0
  167. claude_mpm/services/core/models/health.py +162 -0
  168. claude_mpm/services/core/models/process.py +235 -0
  169. claude_mpm/services/core/models/restart.py +302 -0
  170. claude_mpm/services/core/models/stability.py +264 -0
  171. claude_mpm/services/core/models/toolchain.py +306 -0
  172. claude_mpm/services/core/path_resolver.py +23 -7
  173. claude_mpm/services/diagnostics/__init__.py +2 -2
  174. claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
  175. claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
  176. claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
  177. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
  178. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  179. claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
  180. claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
  181. claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
  182. claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
  183. claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
  184. claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
  185. claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
  186. claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
  187. claude_mpm/services/diagnostics/models.py +19 -24
  188. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  189. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  190. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  191. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  192. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  193. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  194. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  195. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  196. claude_mpm/services/local_ops/__init__.py +163 -0
  197. claude_mpm/services/local_ops/crash_detector.py +257 -0
  198. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  199. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  200. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  201. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  202. claude_mpm/services/local_ops/health_manager.py +430 -0
  203. claude_mpm/services/local_ops/log_monitor.py +396 -0
  204. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  205. claude_mpm/services/local_ops/process_manager.py +595 -0
  206. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  207. claude_mpm/services/local_ops/restart_manager.py +401 -0
  208. claude_mpm/services/local_ops/restart_policy.py +387 -0
  209. claude_mpm/services/local_ops/state_manager.py +372 -0
  210. claude_mpm/services/local_ops/unified_manager.py +600 -0
  211. claude_mpm/services/mcp_config_manager.py +9 -4
  212. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  213. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  214. claude_mpm/services/mcp_gateway/main.py +30 -0
  215. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
  216. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
  217. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
  218. claude_mpm/services/mcp_service_verifier.py +1 -1
  219. claude_mpm/services/memory/failure_tracker.py +563 -0
  220. claude_mpm/services/memory_hook_service.py +165 -4
  221. claude_mpm/services/model/__init__.py +147 -0
  222. claude_mpm/services/model/base_provider.py +365 -0
  223. claude_mpm/services/model/claude_provider.py +412 -0
  224. claude_mpm/services/model/model_router.py +453 -0
  225. claude_mpm/services/model/ollama_provider.py +415 -0
  226. claude_mpm/services/monitor/daemon_manager.py +3 -2
  227. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  228. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  229. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  230. claude_mpm/services/monitor/server.py +2 -1
  231. claude_mpm/services/project/__init__.py +23 -0
  232. claude_mpm/services/project/detection_strategies.py +719 -0
  233. claude_mpm/services/project/toolchain_analyzer.py +581 -0
  234. claude_mpm/services/self_upgrade_service.py +342 -0
  235. claude_mpm/services/session_management_service.py +3 -2
  236. claude_mpm/services/session_manager.py +205 -1
  237. claude_mpm/services/shared/async_service_base.py +16 -27
  238. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  239. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  240. claude_mpm/services/socketio/handlers/hook.py +13 -2
  241. claude_mpm/services/socketio/handlers/registry.py +4 -2
  242. claude_mpm/services/socketio/server/main.py +10 -8
  243. claude_mpm/services/subprocess_launcher_service.py +14 -5
  244. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
  245. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  246. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  247. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
  248. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  249. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  250. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  251. claude_mpm/services/unified/deployment_strategies/local.py +6 -5
  252. claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
  253. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
  254. claude_mpm/services/unified/interfaces.py +3 -1
  255. claude_mpm/services/unified/unified_analyzer.py +14 -10
  256. claude_mpm/services/unified/unified_config.py +2 -1
  257. claude_mpm/services/unified/unified_deployment.py +9 -4
  258. claude_mpm/services/version_service.py +104 -1
  259. claude_mpm/skills/__init__.py +21 -0
  260. claude_mpm/skills/bundled/__init__.py +6 -0
  261. claude_mpm/skills/bundled/api-documentation.md +393 -0
  262. claude_mpm/skills/bundled/async-testing.md +571 -0
  263. claude_mpm/skills/bundled/code-review.md +143 -0
  264. claude_mpm/skills/bundled/database-migration.md +199 -0
  265. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  266. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  267. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  268. claude_mpm/skills/bundled/git-workflow.md +414 -0
  269. claude_mpm/skills/bundled/imagemagick.md +204 -0
  270. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  271. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  272. claude_mpm/skills/bundled/pdf.md +141 -0
  273. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  274. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  275. claude_mpm/skills/bundled/security-scanning.md +327 -0
  276. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  277. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  278. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  279. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  280. claude_mpm/skills/bundled/xlsx.md +157 -0
  281. claude_mpm/skills/registry.py +286 -0
  282. claude_mpm/skills/skill_manager.py +310 -0
  283. claude_mpm/storage/state_storage.py +15 -15
  284. claude_mpm/tools/code_tree_analyzer.py +177 -141
  285. claude_mpm/tools/code_tree_events.py +4 -2
  286. claude_mpm/utils/agent_dependency_loader.py +40 -20
  287. claude_mpm/utils/display_helper.py +260 -0
  288. claude_mpm/utils/git_analyzer.py +407 -0
  289. claude_mpm/utils/robust_installer.py +73 -19
  290. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
  291. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
  292. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  293. claude_mpm/dashboard/static/index-hub-backup.html +0 -713
  294. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  295. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  296. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  297. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  298. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  299. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  300. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  301. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  302. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  303. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  304. claude_mpm/services/project/analyzer_refactored.py +0 -450
  305. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
  306. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
  307. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
  308. {claude_mpm-4.7.4.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 == "success":
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("success")
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": "running",
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": "active",
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 == "success":
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("success")
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": "healthy",
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,
@@ -6,16 +6,39 @@ This module contains all project-related services including
6
6
  project analysis and registry management.
7
7
 
8
8
  Part of TSK-0046: Service Layer Architecture Reorganization
9
+ Part of TSK-0054: Auto-Configuration Feature - Phase 2
9
10
 
10
11
  Services:
11
12
  - ProjectAnalyzer: Analyzes project structure and metadata
12
13
  - ProjectRegistry: Manages project registration and discovery
14
+ - ToolchainAnalyzerService: Analyzes project toolchains for auto-configuration
15
+
16
+ Detection Strategies:
17
+ - NodeJSDetectionStrategy: Detects Node.js projects
18
+ - PythonDetectionStrategy: Detects Python projects
19
+ - RustDetectionStrategy: Detects Rust projects
20
+ - GoDetectionStrategy: Detects Go projects
21
+ - IToolchainDetectionStrategy: Base interface for detection strategies
13
22
  """
14
23
 
15
24
  from .analyzer import ProjectAnalyzer
25
+ from .detection_strategies import (
26
+ GoDetectionStrategy,
27
+ IToolchainDetectionStrategy,
28
+ NodeJSDetectionStrategy,
29
+ PythonDetectionStrategy,
30
+ RustDetectionStrategy,
31
+ )
16
32
  from .registry import ProjectRegistry
33
+ from .toolchain_analyzer import ToolchainAnalyzerService
17
34
 
18
35
  __all__ = [
36
+ "GoDetectionStrategy",
37
+ "IToolchainDetectionStrategy",
38
+ "NodeJSDetectionStrategy",
19
39
  "ProjectAnalyzer",
20
40
  "ProjectRegistry",
41
+ "PythonDetectionStrategy",
42
+ "RustDetectionStrategy",
43
+ "ToolchainAnalyzerService",
21
44
  ]