claude-mpm 5.0.2__py3-none-any.whl → 5.4.3__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +1218 -905
- claude_mpm/agents/agent_loader.py +10 -17
- claude_mpm/agents/base_agent_loader.py +10 -35
- claude_mpm/agents/frontmatter_validator.py +68 -0
- claude_mpm/agents/templates/circuit-breakers.md +431 -45
- claude_mpm/cli/__init__.py +0 -1
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/agent_state_manager.py +67 -23
- claude_mpm/cli/commands/agents.py +446 -25
- claude_mpm/cli/commands/auto_configure.py +535 -233
- claude_mpm/cli/commands/configure.py +1500 -147
- claude_mpm/cli/commands/configure_agent_display.py +13 -6
- claude_mpm/cli/commands/mpm_init/core.py +158 -1
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
- claude_mpm/cli/commands/postmortem.py +401 -0
- claude_mpm/cli/commands/run.py +1 -39
- claude_mpm/cli/commands/skills.py +322 -19
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +8 -0
- claude_mpm/cli/interactive/agent_wizard.py +302 -195
- claude_mpm/cli/parsers/agents_parser.py +137 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
- claude_mpm/cli/parsers/base_parser.py +9 -0
- claude_mpm/cli/parsers/skills_parser.py +7 -0
- claude_mpm/cli/startup.py +133 -85
- claude_mpm/commands/mpm-agents-auto-configure.md +2 -2
- claude_mpm/commands/mpm-agents-list.md +2 -2
- claude_mpm/commands/mpm-config-view.md +2 -2
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/{mpm-ticket-organize.md → mpm-organize.md} +4 -5
- claude_mpm/commands/mpm-postmortem.md +123 -0
- claude_mpm/commands/mpm-session-resume.md +2 -2
- claude_mpm/commands/mpm-ticket-view.md +2 -2
- claude_mpm/config/agent_presets.py +312 -82
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/config/skill_presets.py +392 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +2 -25
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework/loaders/file_loader.py +54 -101
- claude_mpm/core/interactive_session.py +19 -5
- claude_mpm/core/oneshot_session.py +16 -4
- claude_mpm/core/output_style_manager.py +173 -43
- claude_mpm/core/protocols/__init__.py +23 -0
- claude_mpm/core/protocols/runner_protocol.py +103 -0
- claude_mpm/core/protocols/session_protocol.py +131 -0
- claude_mpm/core/shared/singleton_manager.py +11 -4
- claude_mpm/core/socketio_pool.py +3 -3
- claude_mpm/core/system_context.py +38 -0
- claude_mpm/core/unified_agent_registry.py +134 -16
- claude_mpm/core/unified_config.py +22 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +35 -2
- claude_mpm/hooks/claude_hooks/hook_handler.py +4 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/services/agents/agent_recommendation_service.py +279 -0
- claude_mpm/services/agents/cache_git_manager.py +621 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +3 -2
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +110 -3
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +518 -55
- claude_mpm/services/agents/git_source_manager.py +20 -0
- claude_mpm/services/agents/sources/git_source_sync_service.py +45 -6
- claude_mpm/services/agents/toolchain_detector.py +6 -5
- claude_mpm/services/analysis/__init__.py +35 -0
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- claude_mpm/services/analysis/postmortem_reporter.py +474 -0
- claude_mpm/services/analysis/postmortem_service.py +765 -0
- claude_mpm/services/command_deployment_service.py +106 -5
- claude_mpm/services/core/base.py +7 -2
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
- claude_mpm/services/event_bus/config.py +3 -1
- claude_mpm/services/git/git_operations_service.py +8 -8
- claude_mpm/services/mcp_config_manager.py +75 -145
- claude_mpm/services/mcp_service_verifier.py +6 -3
- claude_mpm/services/monitor/daemon.py +37 -10
- claude_mpm/services/monitor/daemon_manager.py +134 -21
- claude_mpm/services/monitor/server.py +225 -19
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/runner_configuration_service.py +16 -3
- claude_mpm/services/session_management_service.py +16 -4
- claude_mpm/services/socketio/event_normalizer.py +15 -1
- claude_mpm/services/socketio/server/core.py +160 -21
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/utils/agent_filters.py +261 -0
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +372 -0
- claude_mpm/utils/progress.py +5 -1
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/METADATA +69 -84
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/RECORD +112 -153
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/entry_points.txt +0 -2
- claude_mpm/dashboard/analysis_runner.py +0 -455
- claude_mpm/dashboard/index.html +0 -13
- claude_mpm/dashboard/open_dashboard.py +0 -66
- claude_mpm/dashboard/static/css/activity.css +0 -1958
- claude_mpm/dashboard/static/css/connection-status.css +0 -370
- claude_mpm/dashboard/static/css/dashboard.css +0 -4701
- claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
- claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
- claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
- claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
- claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
- claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
- claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
- claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
- claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
- claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
- claude_mpm/dashboard/static/js/connection-manager.js +0 -536
- claude_mpm/dashboard/static/js/dashboard.js +0 -1914
- claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/js/socket-client.js +0 -1474
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/socket.io.min.js +0 -7
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
- claude_mpm/dashboard/templates/code_simple.html +0 -153
- claude_mpm/dashboard/templates/index.html +0 -606
- claude_mpm/dashboard/test_dashboard.html +0 -372
- claude_mpm/scripts/mcp_server.py +0 -75
- claude_mpm/scripts/mcp_wrapper.py +0 -39
- claude_mpm/services/mcp_gateway/__init__.py +0 -159
- claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
- claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
- claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
- claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
- claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
- claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
- claude_mpm/services/mcp_gateway/core/base.py +0 -312
- claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
- claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
- claude_mpm/services/mcp_gateway/core/process_pool.py +0 -971
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
- claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
- claude_mpm/services/mcp_gateway/main.py +0 -589
- claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
- claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
- claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
- claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
- claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
- claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
- /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/top_level.txt +0 -0
|
@@ -45,7 +45,6 @@ from claude_mpm.core.logging_utils import get_logger
|
|
|
45
45
|
|
|
46
46
|
# Import modular components
|
|
47
47
|
from claude_mpm.core.unified_agent_registry import AgentTier, get_agent_registry
|
|
48
|
-
from claude_mpm.core.unified_paths import get_path_manager
|
|
49
48
|
from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
|
|
50
49
|
|
|
51
50
|
from ..core.agent_name_normalizer import AgentNameNormalizer
|
|
@@ -102,33 +101,27 @@ def _get_agent_templates_dirs() -> Dict[AgentTier, Optional[Path]]:
|
|
|
102
101
|
"""
|
|
103
102
|
Get directories containing agent JSON files across all tiers.
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
- SYSTEM: Built-in agents relative to this module
|
|
104
|
+
SIMPLIFIED ARCHITECTURE:
|
|
105
|
+
- SOURCE: ~/.claude-mpm/cache/remote-agents/ (git cache from GitHub)
|
|
106
|
+
- DEPLOYMENT: .claude/agents/ (project-level Claude Code discovery)
|
|
109
107
|
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
This function is kept for backward compatibility but the tier-based
|
|
109
|
+
system is being phased out in favor of the simplified architecture.
|
|
112
110
|
|
|
113
111
|
Returns:
|
|
114
112
|
Dict mapping AgentTier to Path (or None if not available)
|
|
115
113
|
"""
|
|
116
114
|
dirs = {}
|
|
117
115
|
|
|
118
|
-
# PROJECT tier -
|
|
119
|
-
#
|
|
120
|
-
project_dir = Path.cwd() /
|
|
116
|
+
# PROJECT tier - Deprecated in simplified architecture
|
|
117
|
+
# Agents are now deployed to .claude/agents/ directly
|
|
118
|
+
project_dir = Path.cwd() / ".claude" / "agents"
|
|
121
119
|
if project_dir.exists():
|
|
122
120
|
dirs[AgentTier.PROJECT] = project_dir
|
|
123
121
|
logger.debug(f"Found PROJECT agents at: {project_dir}")
|
|
124
122
|
|
|
125
|
-
# USER tier -
|
|
126
|
-
|
|
127
|
-
if user_config_dir:
|
|
128
|
-
user_agents_dir = user_config_dir / "agents"
|
|
129
|
-
if user_agents_dir.exists():
|
|
130
|
-
dirs[AgentTier.USER] = user_agents_dir
|
|
131
|
-
logger.debug(f"Found USER agents at: {user_agents_dir}")
|
|
123
|
+
# USER tier - Deprecated in simplified architecture
|
|
124
|
+
# (Kept for backward compatibility but not actively used)
|
|
132
125
|
|
|
133
126
|
# SYSTEM tier - built-in agents
|
|
134
127
|
system_dir = Path(__file__).parent / "templates"
|
|
@@ -311,42 +311,17 @@ def _remove_test_mode_instructions(content: str) -> str:
|
|
|
311
311
|
Returns:
|
|
312
312
|
str: Content with test-mode instructions removed
|
|
313
313
|
"""
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if line.strip() == "## Standard Test Response Protocol":
|
|
324
|
-
skip_section = True
|
|
325
|
-
i += 1
|
|
326
|
-
continue
|
|
327
|
-
|
|
328
|
-
# Check if we're in the test section and need to continue skipping
|
|
329
|
-
if skip_section:
|
|
330
|
-
# Check if we've reached a new top-level section (## but not ###)
|
|
331
|
-
# Only stop skipping when we hit another ## section (same level as test section)
|
|
332
|
-
if line.startswith("##") and not line.startswith("###"):
|
|
333
|
-
skip_section = False
|
|
334
|
-
# Don't skip this line - it's the start of a new section
|
|
335
|
-
filtered_lines.append(line)
|
|
336
|
-
i += 1
|
|
337
|
-
continue
|
|
338
|
-
# Skip this line as we're still in test section (includes ### subsections)
|
|
339
|
-
i += 1
|
|
340
|
-
continue
|
|
341
|
-
|
|
342
|
-
# Not in test section, keep the line
|
|
343
|
-
filtered_lines.append(line)
|
|
344
|
-
i += 1
|
|
345
|
-
|
|
346
|
-
# Join back and clean up extra blank lines
|
|
347
|
-
result = "\n".join(filtered_lines)
|
|
314
|
+
import re
|
|
315
|
+
|
|
316
|
+
# Pattern matches from "## Standard Test Response Protocol"
|
|
317
|
+
# until the next "##" (but not "###") or end of string
|
|
318
|
+
# Uses negative lookahead to stop at ## but not ###
|
|
319
|
+
pattern = r"## Standard Test Response Protocol\n.*?(?=\n##(?!#)|\Z)"
|
|
320
|
+
|
|
321
|
+
# Remove the test section (DOTALL allows . to match newlines)
|
|
322
|
+
result = re.sub(pattern, "", content, flags=re.DOTALL)
|
|
348
323
|
|
|
349
|
-
#
|
|
324
|
+
# Clean up multiple consecutive newlines
|
|
350
325
|
while "\n\n\n" in result:
|
|
351
326
|
result = result.replace("\n\n\n", "\n\n")
|
|
352
327
|
|
|
@@ -143,6 +143,10 @@ class FrontmatterValidator:
|
|
|
143
143
|
"dependencies",
|
|
144
144
|
"capabilities",
|
|
145
145
|
"color",
|
|
146
|
+
# NEW: Collection-based identification fields
|
|
147
|
+
"collection_id",
|
|
148
|
+
"source_path",
|
|
149
|
+
"canonical_id",
|
|
146
150
|
}
|
|
147
151
|
|
|
148
152
|
def validate_and_correct(self, frontmatter: Dict[str, Any]) -> ValidationResult:
|
|
@@ -176,6 +180,8 @@ class FrontmatterValidator:
|
|
|
176
180
|
self._validate_author_field(corrected, errors, warnings)
|
|
177
181
|
self._validate_tags_field(corrected, errors, warnings)
|
|
178
182
|
self._validate_numeric_fields(corrected, errors, warnings)
|
|
183
|
+
# NEW: Validate collection-based identification fields
|
|
184
|
+
self._validate_collection_fields(corrected, field_corrections, errors, warnings)
|
|
179
185
|
|
|
180
186
|
# Determine if valid
|
|
181
187
|
is_valid = len(errors) == 0
|
|
@@ -464,6 +470,68 @@ class FrontmatterValidator:
|
|
|
464
470
|
f"Field '{field_name}' value {value} outside recommended range [{min_val}, {max_val}]"
|
|
465
471
|
)
|
|
466
472
|
|
|
473
|
+
def _validate_collection_fields(
|
|
474
|
+
self,
|
|
475
|
+
corrected: Dict[str, Any],
|
|
476
|
+
field_corrections: Dict[str, Any],
|
|
477
|
+
errors: List[str],
|
|
478
|
+
warnings: List[str],
|
|
479
|
+
) -> None:
|
|
480
|
+
"""Validate collection-based identification fields.
|
|
481
|
+
|
|
482
|
+
NEW: Validates collection_id, source_path, and canonical_id fields.
|
|
483
|
+
|
|
484
|
+
These fields are auto-populated by RemoteAgentDiscoveryService for remote agents
|
|
485
|
+
and should follow specific formats:
|
|
486
|
+
- collection_id: "owner/repo-name" (e.g., "bobmatnyc/claude-mpm-agents")
|
|
487
|
+
- source_path: Relative path in repo (e.g., "agents/pm.md")
|
|
488
|
+
- canonical_id: "collection_id:agent_id" or "legacy:filename"
|
|
489
|
+
"""
|
|
490
|
+
# Validate collection_id format (optional field)
|
|
491
|
+
if "collection_id" in corrected:
|
|
492
|
+
collection_id = corrected["collection_id"]
|
|
493
|
+
if not isinstance(collection_id, str):
|
|
494
|
+
errors.append(
|
|
495
|
+
f"Field 'collection_id' must be a string, got {type(collection_id).__name__}"
|
|
496
|
+
)
|
|
497
|
+
elif "/" not in collection_id:
|
|
498
|
+
warnings.append(
|
|
499
|
+
f"Field 'collection_id' should be in format 'owner/repo-name', got '{collection_id}'"
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
# Validate source_path format (optional field)
|
|
503
|
+
if "source_path" in corrected:
|
|
504
|
+
source_path = corrected["source_path"]
|
|
505
|
+
if not isinstance(source_path, str):
|
|
506
|
+
errors.append(
|
|
507
|
+
f"Field 'source_path' must be a string, got {type(source_path).__name__}"
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
# Validate canonical_id format (optional field)
|
|
511
|
+
if "canonical_id" in corrected:
|
|
512
|
+
canonical_id = corrected["canonical_id"]
|
|
513
|
+
if not isinstance(canonical_id, str):
|
|
514
|
+
errors.append(
|
|
515
|
+
f"Field 'canonical_id' must be a string, got {type(canonical_id).__name__}"
|
|
516
|
+
)
|
|
517
|
+
elif ":" not in canonical_id:
|
|
518
|
+
warnings.append(
|
|
519
|
+
f"Field 'canonical_id' should be in format 'collection:agent_id' or 'legacy:filename', got '{canonical_id}'"
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
# Auto-generate canonical_id if collection_id is present but canonical_id is missing
|
|
523
|
+
if "collection_id" in corrected and "canonical_id" not in corrected:
|
|
524
|
+
collection_id = corrected["collection_id"]
|
|
525
|
+
agent_id = corrected.get("name", "unknown")
|
|
526
|
+
|
|
527
|
+
# Generate canonical_id
|
|
528
|
+
canonical_id = f"{collection_id}:{agent_id}"
|
|
529
|
+
corrected["canonical_id"] = canonical_id
|
|
530
|
+
field_corrections["canonical_id"] = canonical_id
|
|
531
|
+
warnings.append(
|
|
532
|
+
f"Auto-generated canonical_id: '{canonical_id}' from collection_id and name"
|
|
533
|
+
)
|
|
534
|
+
|
|
467
535
|
def _normalize_model(self, model: str) -> str:
|
|
468
536
|
"""
|
|
469
537
|
Normalize model name to standard tier using ModelTier enum.
|