claude-mpm 4.13.1__py3-none-any.whl → 4.14.0__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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (50) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +68 -0
  3. claude_mpm/cli/__init__.py +10 -0
  4. claude_mpm/cli/commands/local_deploy.py +536 -0
  5. claude_mpm/cli/parsers/base_parser.py +7 -0
  6. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  7. claude_mpm/commands/mpm-agents-detect.md +168 -0
  8. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  9. claude_mpm/commands/mpm-agents.md +75 -1
  10. claude_mpm/commands/mpm-auto-configure.md +217 -0
  11. claude_mpm/commands/mpm-help.md +160 -0
  12. claude_mpm/config/model_config.py +428 -0
  13. claude_mpm/core/interactive_session.py +3 -0
  14. claude_mpm/services/core/interfaces/__init__.py +74 -2
  15. claude_mpm/services/core/interfaces/health.py +172 -0
  16. claude_mpm/services/core/interfaces/model.py +281 -0
  17. claude_mpm/services/core/interfaces/process.py +372 -0
  18. claude_mpm/services/core/interfaces/restart.py +307 -0
  19. claude_mpm/services/core/interfaces/stability.py +260 -0
  20. claude_mpm/services/core/models/__init__.py +35 -0
  21. claude_mpm/services/core/models/health.py +189 -0
  22. claude_mpm/services/core/models/process.py +258 -0
  23. claude_mpm/services/core/models/restart.py +302 -0
  24. claude_mpm/services/core/models/stability.py +264 -0
  25. claude_mpm/services/local_ops/__init__.py +163 -0
  26. claude_mpm/services/local_ops/crash_detector.py +257 -0
  27. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  28. claude_mpm/services/local_ops/health_checks/http_check.py +223 -0
  29. claude_mpm/services/local_ops/health_checks/process_check.py +235 -0
  30. claude_mpm/services/local_ops/health_checks/resource_check.py +254 -0
  31. claude_mpm/services/local_ops/health_manager.py +430 -0
  32. claude_mpm/services/local_ops/log_monitor.py +396 -0
  33. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  34. claude_mpm/services/local_ops/process_manager.py +595 -0
  35. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  36. claude_mpm/services/local_ops/restart_manager.py +401 -0
  37. claude_mpm/services/local_ops/restart_policy.py +387 -0
  38. claude_mpm/services/local_ops/state_manager.py +371 -0
  39. claude_mpm/services/local_ops/unified_manager.py +600 -0
  40. claude_mpm/services/model/__init__.py +147 -0
  41. claude_mpm/services/model/base_provider.py +365 -0
  42. claude_mpm/services/model/claude_provider.py +412 -0
  43. claude_mpm/services/model/model_router.py +453 -0
  44. claude_mpm/services/model/ollama_provider.py +415 -0
  45. {claude_mpm-4.13.1.dist-info → claude_mpm-4.14.0.dist-info}/METADATA +1 -1
  46. {claude_mpm-4.13.1.dist-info → claude_mpm-4.14.0.dist-info}/RECORD +50 -15
  47. {claude_mpm-4.13.1.dist-info → claude_mpm-4.14.0.dist-info}/WHEEL +0 -0
  48. {claude_mpm-4.13.1.dist-info → claude_mpm-4.14.0.dist-info}/entry_points.txt +0 -0
  49. {claude_mpm-4.13.1.dist-info → claude_mpm-4.14.0.dist-info}/licenses/LICENSE +0 -0
  50. {claude_mpm-4.13.1.dist-info → claude_mpm-4.14.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,147 @@
1
+ """
2
+ Model Services Package for Claude MPM Framework
3
+ ================================================
4
+
5
+ WHY: Provides hybrid local/cloud content processing with intelligent routing
6
+ and automatic fallback. Enables privacy-preserving local model execution via
7
+ Ollama with cloud fallback to Claude for reliability.
8
+
9
+ ARCHITECTURE:
10
+ - Interfaces: Core contracts for model providers and routing (IModelProvider, IModelRouter)
11
+ - Base Provider: Common functionality for all providers (BaseModelProvider)
12
+ - Providers: Ollama (local) and Claude (cloud) implementations
13
+ - Router: Intelligent routing with fallback logic (ModelRouter)
14
+ - Configuration: Centralized config management (model_config.py)
15
+
16
+ USAGE:
17
+
18
+ Basic Usage with Auto-Routing:
19
+ ```python
20
+ from claude_mpm.services.model import ModelRouter
21
+ from claude_mpm.services.core.interfaces.model import ModelCapability
22
+
23
+ # Create router with default config (auto mode)
24
+ router = ModelRouter()
25
+ await router.initialize()
26
+
27
+ # Analyze content (tries Ollama first, falls back to Claude)
28
+ response = await router.analyze_content(
29
+ content="Your article text here...",
30
+ task=ModelCapability.SEO_ANALYSIS
31
+ )
32
+
33
+ if response.success:
34
+ print(f"Analysis by {response.provider}:")
35
+ print(response.result)
36
+ ```
37
+
38
+ Direct Provider Usage:
39
+ ```python
40
+ from claude_mpm.services.model import OllamaProvider
41
+
42
+ # Use Ollama directly
43
+ provider = OllamaProvider(config={
44
+ "host": "http://localhost:11434"
45
+ })
46
+
47
+ if await provider.is_available():
48
+ response = await provider.analyze_content(
49
+ content="Text to analyze",
50
+ task=ModelCapability.READABILITY
51
+ )
52
+ ```
53
+
54
+ Configuration-Based Setup:
55
+ ```python
56
+ from claude_mpm.config.model_config import ModelConfigManager
57
+ from claude_mpm.services.model import ModelRouter
58
+
59
+ # Load config from file
60
+ config = ModelConfigManager.load_config(".claude/configuration.yaml")
61
+ router_config = ModelConfigManager.get_router_config(config)
62
+
63
+ # Create router with loaded config
64
+ router = ModelRouter(config=router_config)
65
+ await router.initialize()
66
+ ```
67
+
68
+ PROVIDER STRATEGIES:
69
+ - AUTO: Try Ollama first, fallback to Claude (default)
70
+ - OLLAMA: Local-only, fail if unavailable (privacy mode)
71
+ - CLAUDE: Cloud-only, always use Claude
72
+ - PRIVACY: Like OLLAMA with privacy-focused messages
73
+
74
+ RECOMMENDED MODELS (Ollama):
75
+ - SEO Analysis: llama3.3:70b - Comprehensive SEO insights
76
+ - Readability: gemma2:9b - Fast, accurate readability scoring
77
+ - Grammar: qwen3:14b - Specialized grammar checking
78
+ - Summarization: mistral:7b - Concise, effective summaries
79
+ - Keyword Extraction: seoassistant - SEO-specialized model
80
+
81
+ CONFIGURATION:
82
+ See claude_mpm.config.model_config for detailed configuration options.
83
+
84
+ Example configuration.yaml:
85
+ ```yaml
86
+ content_agent:
87
+ model_provider: auto
88
+
89
+ ollama:
90
+ enabled: true
91
+ host: http://localhost:11434
92
+ fallback_to_cloud: true
93
+ models:
94
+ seo_analysis: llama3.3:70b
95
+ readability: gemma2:9b
96
+
97
+ claude:
98
+ enabled: true
99
+ model: claude-3-5-sonnet-20241022
100
+ ```
101
+
102
+ PHASE 1 STATUS (Current):
103
+ ✅ Core interfaces and contracts defined
104
+ ✅ Base provider with common functionality
105
+ ✅ Ollama provider with direct API integration
106
+ ✅ Claude provider (Phase 1: mock responses)
107
+ ✅ Router with intelligent fallback logic
108
+ ✅ Configuration management with validation
109
+ ⏳ Claude API integration (Phase 2)
110
+ ⏳ Content agent integration (Phase 2)
111
+ """
112
+
113
+ # Re-export interfaces for convenience
114
+ from claude_mpm.services.core.interfaces.model import (
115
+ IModelProvider,
116
+ IModelRouter,
117
+ ModelCapability,
118
+ ModelProvider,
119
+ ModelResponse,
120
+ )
121
+ from claude_mpm.services.model.base_provider import BaseModelProvider
122
+ from claude_mpm.services.model.claude_provider import ClaudeProvider
123
+ from claude_mpm.services.model.model_router import ModelRouter, RoutingStrategy
124
+ from claude_mpm.services.model.ollama_provider import OllamaProvider
125
+
126
+ __all__ = [ # noqa: RUF022 - Semantic grouping preferred over alphabetical
127
+ # Base classes
128
+ "BaseModelProvider",
129
+ # Providers
130
+ "ClaudeProvider",
131
+ "OllamaProvider",
132
+ # Router
133
+ "ModelRouter",
134
+ "RoutingStrategy",
135
+ # Interfaces
136
+ "IModelProvider",
137
+ "IModelRouter",
138
+ # Data types
139
+ "ModelCapability",
140
+ "ModelProvider",
141
+ "ModelResponse",
142
+ ]
143
+
144
+ # Version and metadata
145
+ __version__ = "1.0.0"
146
+ __phase__ = "1"
147
+ __status__ = "Core Infrastructure Complete"
@@ -0,0 +1,365 @@
1
+ """
2
+ Base Model Provider Implementation for Claude MPM Framework
3
+ ===========================================================
4
+
5
+ WHY: Provides common functionality for all model providers, reducing
6
+ duplication and ensuring consistent behavior across implementations.
7
+
8
+ DESIGN DECISION: Abstract base class extends both BaseService and IModelProvider,
9
+ providing service lifecycle management plus model-specific utilities.
10
+
11
+ RESPONSIBILITIES:
12
+ - Common error handling and logging
13
+ - Task-specific prompt generation
14
+ - Response formatting and validation
15
+ - Performance metrics tracking
16
+ - Retry logic for transient failures
17
+ """
18
+
19
+ import asyncio
20
+ import time
21
+ from abc import abstractmethod
22
+ from typing import Any, Dict, Optional
23
+
24
+ from claude_mpm.core.logger import get_logger
25
+ from claude_mpm.services.core.base import BaseService
26
+ from claude_mpm.services.core.interfaces.model import (
27
+ IModelProvider,
28
+ ModelCapability,
29
+ ModelResponse,
30
+ )
31
+
32
+
33
+ class BaseModelProvider(BaseService, IModelProvider):
34
+ """
35
+ Abstract base class for model providers.
36
+
37
+ WHY: Centralizes common provider functionality like prompt generation,
38
+ error handling, and response formatting.
39
+
40
+ Usage:
41
+ class MyProvider(BaseModelProvider):
42
+ async def analyze_content(self, content, task, model=None, **kwargs):
43
+ prompt = self.get_task_prompt(task, content)
44
+ # Call provider API
45
+ return self.create_response(...)
46
+ """
47
+
48
+ # Task-specific prompt templates
49
+ TASK_PROMPTS: Dict[ModelCapability, str] = {
50
+ ModelCapability.SEO_ANALYSIS: """Analyze the following content for SEO effectiveness. Provide:
51
+ 1. Primary and secondary keywords identified
52
+ 2. Keyword density analysis
53
+ 3. Meta description recommendation
54
+ 4. Title tag optimization suggestions
55
+ 5. Content structure analysis (H1, H2, etc.)
56
+ 6. SEO score (0-100) with justification
57
+
58
+ Content to analyze:
59
+ {content}
60
+
61
+ Provide your analysis in a structured format.""",
62
+ ModelCapability.READABILITY: """Analyze the readability of the following content. Provide:
63
+ 1. Readability score (Flesch-Kincaid or similar)
64
+ 2. Average sentence length
65
+ 3. Complex word count
66
+ 4. Grade level assessment
67
+ 5. Suggestions for improvement
68
+ 6. Overall readability rating (Easy/Medium/Hard)
69
+
70
+ Content to analyze:
71
+ {content}
72
+
73
+ Provide your analysis in a structured format.""",
74
+ ModelCapability.GRAMMAR: """Perform a grammar and style check on the following content. Identify:
75
+ 1. Grammatical errors with corrections
76
+ 2. Spelling mistakes
77
+ 3. Punctuation issues
78
+ 4. Style inconsistencies
79
+ 5. Clarity improvements
80
+ 6. Overall quality score (0-100)
81
+
82
+ Content to analyze:
83
+ {content}
84
+
85
+ Provide your analysis in a structured format.""",
86
+ ModelCapability.SUMMARIZATION: """Provide a comprehensive summary of the following content:
87
+ 1. Main topic and key points (3-5 bullet points)
88
+ 2. Supporting details
89
+ 3. Conclusions or recommendations
90
+ 4. One-sentence TL;DR
91
+
92
+ Content to summarize:
93
+ {content}
94
+
95
+ Provide your summary in a structured format.""",
96
+ ModelCapability.KEYWORD_EXTRACTION: """Extract and analyze keywords from the following content:
97
+ 1. Primary keywords (top 5-10)
98
+ 2. Long-tail keyword phrases
99
+ 3. Semantic relationships between keywords
100
+ 4. Keyword relevance scores
101
+ 5. Suggested additional keywords
102
+
103
+ Content to analyze:
104
+ {content}
105
+
106
+ Provide your keyword analysis in a structured format.""",
107
+ ModelCapability.ACCESSIBILITY: """Analyze the accessibility of the following content:
108
+ 1. Language complexity level
109
+ 2. Inclusivity assessment
110
+ 3. Plain language recommendations
111
+ 4. Potential barriers for readers with disabilities
112
+ 5. WCAG compliance suggestions
113
+ 6. Accessibility score (0-100)
114
+
115
+ Content to analyze:
116
+ {content}
117
+
118
+ Provide your analysis in a structured format.""",
119
+ ModelCapability.SENTIMENT: """Analyze the sentiment and tone of the following content:
120
+ 1. Overall sentiment (Positive/Negative/Neutral)
121
+ 2. Sentiment score (-1 to +1)
122
+ 3. Emotional tone detected
123
+ 4. Audience perception analysis
124
+ 5. Tone consistency evaluation
125
+
126
+ Content to analyze:
127
+ {content}
128
+
129
+ Provide your analysis in a structured format.""",
130
+ ModelCapability.GENERAL: """Analyze the following content and provide:
131
+ 1. Overview and main themes
132
+ 2. Quality assessment
133
+ 3. Structural analysis
134
+ 4. Improvement suggestions
135
+ 5. Overall effectiveness rating
136
+
137
+ Content to analyze:
138
+ {content}
139
+
140
+ Provide your analysis in a structured format.""",
141
+ }
142
+
143
+ def __init__(
144
+ self,
145
+ provider_name: str,
146
+ config: Optional[Dict[str, Any]] = None,
147
+ ):
148
+ """
149
+ Initialize base model provider.
150
+
151
+ Args:
152
+ provider_name: Name of the provider (e.g., "ollama", "claude")
153
+ config: Provider-specific configuration
154
+ """
155
+ super().__init__(service_name=f"{provider_name}_provider", config=config)
156
+ self.provider_name = provider_name
157
+ self.logger = get_logger(f"model.{provider_name}")
158
+ self._request_count = 0
159
+ self._error_count = 0
160
+ self._total_latency = 0.0
161
+
162
+ def get_task_prompt(self, task: ModelCapability, content: str) -> str:
163
+ """
164
+ Generate task-specific prompt.
165
+
166
+ WHY: Centralizes prompt engineering. Tasks require different analysis
167
+ approaches and output formats.
168
+
169
+ Args:
170
+ task: Type of analysis to perform
171
+ content: Content to analyze
172
+
173
+ Returns:
174
+ Formatted prompt string
175
+ """
176
+ template = self.TASK_PROMPTS.get(
177
+ task, self.TASK_PROMPTS[ModelCapability.GENERAL]
178
+ )
179
+ return template.format(content=content)
180
+
181
+ def create_response(
182
+ self,
183
+ success: bool,
184
+ model: str,
185
+ task: ModelCapability,
186
+ result: str = "",
187
+ metadata: Optional[Dict[str, Any]] = None,
188
+ error: Optional[str] = None,
189
+ ) -> ModelResponse:
190
+ """
191
+ Create standardized model response.
192
+
193
+ WHY: Ensures consistent response format across all providers.
194
+
195
+ Args:
196
+ success: Whether operation succeeded
197
+ model: Model used
198
+ task: Task performed
199
+ result: Analysis result
200
+ metadata: Additional metadata
201
+ error: Error message if failed
202
+
203
+ Returns:
204
+ ModelResponse object
205
+ """
206
+ return ModelResponse(
207
+ success=success,
208
+ provider=self.provider_name,
209
+ model=model,
210
+ task=task.value,
211
+ result=result,
212
+ metadata=metadata or {},
213
+ error=error,
214
+ )
215
+
216
+ async def analyze_with_retry(
217
+ self,
218
+ analyze_func,
219
+ content: str,
220
+ task: ModelCapability,
221
+ model: Optional[str] = None,
222
+ max_retries: int = 3,
223
+ **kwargs,
224
+ ) -> ModelResponse:
225
+ """
226
+ Execute analysis with retry logic.
227
+
228
+ WHY: Handles transient failures (network issues, rate limits, etc.)
229
+ without requiring retry logic in each provider implementation.
230
+
231
+ Args:
232
+ analyze_func: Async function to call for analysis
233
+ content: Content to analyze
234
+ task: Task to perform
235
+ model: Optional model to use
236
+ max_retries: Maximum retry attempts
237
+ **kwargs: Additional arguments for analyze_func
238
+
239
+ Returns:
240
+ ModelResponse from successful attempt or final error
241
+ """
242
+ last_error = None
243
+
244
+ for attempt in range(max_retries):
245
+ try:
246
+ start_time = time.time()
247
+ response = await analyze_func(content, task, model, **kwargs)
248
+ latency = time.time() - start_time
249
+
250
+ # Track metrics
251
+ self._request_count += 1
252
+ self._total_latency += latency
253
+
254
+ if response.success:
255
+ response.metadata["latency_seconds"] = latency
256
+ response.metadata["attempt"] = attempt + 1
257
+ self.log_debug(
258
+ f"Analysis completed in {latency:.2f}s (attempt {attempt + 1})"
259
+ )
260
+ return response
261
+ last_error = response.error
262
+ self._error_count += 1
263
+
264
+ except Exception as e:
265
+ last_error = str(e)
266
+ self._error_count += 1
267
+ self.log_warning(
268
+ f"Analysis attempt {attempt + 1} failed: {e}",
269
+ exc_info=True,
270
+ )
271
+
272
+ # Wait before retry (exponential backoff)
273
+ if attempt < max_retries - 1:
274
+ wait_time = 2**attempt # 1s, 2s, 4s
275
+ self.log_info(f"Retrying in {wait_time}s...")
276
+ await asyncio.sleep(wait_time)
277
+
278
+ # All retries failed
279
+ self.log_error(f"All {max_retries} attempts failed. Last error: {last_error}")
280
+ return self.create_response(
281
+ success=False,
282
+ model=model or "unknown",
283
+ task=task,
284
+ error=f"Failed after {max_retries} attempts: {last_error}",
285
+ )
286
+
287
+ def validate_content(self, content: str, max_length: Optional[int] = None) -> bool:
288
+ """
289
+ Validate content before analysis.
290
+
291
+ WHY: Prevents invalid requests and provides early error detection.
292
+
293
+ Args:
294
+ content: Content to validate
295
+ max_length: Optional maximum length in characters
296
+
297
+ Returns:
298
+ True if valid, False otherwise
299
+ """
300
+ if not content or not content.strip():
301
+ self.log_warning("Empty content provided for analysis")
302
+ return False
303
+
304
+ if max_length and len(content) > max_length:
305
+ self.log_warning(
306
+ f"Content length {len(content)} exceeds maximum {max_length}"
307
+ )
308
+ return False
309
+
310
+ return True
311
+
312
+ def get_metrics(self) -> Dict[str, Any]:
313
+ """
314
+ Get provider performance metrics.
315
+
316
+ Returns:
317
+ Dictionary of metrics (request count, error rate, avg latency)
318
+ """
319
+ avg_latency = (
320
+ self._total_latency / self._request_count if self._request_count > 0 else 0
321
+ )
322
+ error_rate = (
323
+ self._error_count / self._request_count if self._request_count > 0 else 0
324
+ )
325
+
326
+ return {
327
+ "provider": self.provider_name,
328
+ "request_count": self._request_count,
329
+ "error_count": self._error_count,
330
+ "error_rate": error_rate,
331
+ "avg_latency_seconds": avg_latency,
332
+ }
333
+
334
+ async def initialize(self) -> bool:
335
+ """
336
+ Initialize provider.
337
+
338
+ Subclasses should override to perform provider-specific setup.
339
+
340
+ Returns:
341
+ True if initialization successful
342
+ """
343
+ self.log_info(f"Initializing {self.provider_name} provider")
344
+ self._initialized = True
345
+ return True
346
+
347
+ async def shutdown(self) -> None:
348
+ """
349
+ Shutdown provider and cleanup resources.
350
+
351
+ Subclasses should override to perform provider-specific cleanup.
352
+ """
353
+ self.log_info(f"Shutting down {self.provider_name} provider")
354
+ self._shutdown = True
355
+
356
+ @abstractmethod
357
+ async def get_model_info(self, model: str) -> Dict[str, Any]:
358
+ """
359
+ Get model information.
360
+
361
+ Must be implemented by subclasses.
362
+ """
363
+
364
+
365
+ __all__ = ["BaseModelProvider"]