aiecs 1.2.0__tar.gz → 1.2.2__tar.gz
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 aiecs might be problematic. Click here for more details.
- {aiecs-1.2.0/aiecs.egg-info → aiecs-1.2.2}/PKG-INFO +1 -1
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/__init__.py +1 -1
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/aiecs_client.py +1 -1
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/config/config.py +38 -1
- aiecs-1.2.2/aiecs/infrastructure/monitoring/__init__.py +34 -0
- aiecs-1.2.2/aiecs/infrastructure/monitoring/global_metrics_manager.py +207 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/persistence/file_storage.py +41 -28
- aiecs-1.2.2/aiecs/llm/__init__.py +93 -0
- aiecs-1.2.2/aiecs/llm/callbacks/__init__.py +12 -0
- {aiecs-1.2.0/aiecs/llm → aiecs-1.2.2/aiecs/llm/callbacks}/custom_callbacks.py +1 -1
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/llm/client_factory.py +23 -6
- aiecs-1.2.2/aiecs/llm/clients/__init__.py +35 -0
- {aiecs-1.2.0/aiecs/llm → aiecs-1.2.2/aiecs/llm/clients}/base_client.py +73 -1
- {aiecs-1.2.0/aiecs/llm → aiecs-1.2.2/aiecs/llm/clients}/googleai_client.py +19 -15
- {aiecs-1.2.0/aiecs/llm → aiecs-1.2.2/aiecs/llm/clients}/openai_client.py +9 -14
- {aiecs-1.2.0/aiecs/llm → aiecs-1.2.2/aiecs/llm/clients}/vertex_client.py +15 -15
- {aiecs-1.2.0/aiecs/llm → aiecs-1.2.2/aiecs/llm/clients}/xai_client.py +36 -50
- aiecs-1.2.2/aiecs/llm/config/__init__.py +54 -0
- aiecs-1.2.2/aiecs/llm/config/config_loader.py +275 -0
- aiecs-1.2.2/aiecs/llm/config/config_validator.py +237 -0
- aiecs-1.2.2/aiecs/llm/config/model_config.py +132 -0
- aiecs-1.2.2/aiecs/llm/utils/__init__.py +11 -0
- aiecs-1.2.2/aiecs/llm/utils/validate_config.py +91 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/main.py +32 -2
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/tool_executor/__init__.py +2 -2
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/tool_executor/tool_executor.py +3 -3
- {aiecs-1.2.0 → aiecs-1.2.2/aiecs.egg-info}/PKG-INFO +1 -1
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs.egg-info/SOURCES.txt +15 -6
- {aiecs-1.2.0 → aiecs-1.2.2}/pyproject.toml +1 -1
- aiecs-1.2.0/aiecs/infrastructure/monitoring/__init__.py +0 -12
- aiecs-1.2.0/aiecs/llm/__init__.py +0 -56
- {aiecs-1.2.0 → aiecs-1.2.2}/LICENSE +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/MANIFEST.in +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/README.md +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/__main__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/application/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/application/executors/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/application/executors/operation_executor.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/config/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/config/registry.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/core/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/core/interface/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/core/interface/execution_interface.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/core/interface/storage_interface.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/agent_adapter.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/analytics.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/collaborative_workflow.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/communication_hub.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/community_builder.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/community_integration.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/community_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/decision_engine.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/exceptions.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/models/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/models/community_models.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/resource_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/community/shared_context_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/context/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/context/context_engine.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/context/conversation_models.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/execution/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/execution/model.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/task/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/task/dsl_processor.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/task/model.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/domain/task/task_context.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/messaging/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/messaging/celery_task_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/messaging/websocket_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/monitoring/executor_metrics.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/monitoring/structured_logger.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/monitoring/tracing_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/persistence/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/persistence/context_engine_client.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/persistence/database_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/infrastructure/persistence/redis_client.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/aid/VERSION_MANAGEMENT.md +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/aid/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/aid/version_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/dependency_checker.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/dependency_fixer.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/download_nlp_data.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/quick_dependency_check.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_check/setup_nlp_data.sh +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_patch/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_patch/fix_weasel/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/tools_develop/README.md +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/tools_develop/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/tools_develop/check_type_annotations.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/scripts/tools_develop/validate_tool_schemas.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tasks/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tasks/worker.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/base_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/ai_document_orchestrator.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/ai_document_writer_orchestrator.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/content_insertion_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/document_creator_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/document_layout_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/document_parser_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/docs/document_writer_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/langchain_adapter.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/schema_generator.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/ai_data_analysis_orchestrator.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/ai_insight_generator_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/ai_report_orchestrator_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/data_loader_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/data_profiler_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/data_transformer_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/data_visualizer_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/model_trainer_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/statistics/statistical_analyzer_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/chart_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/classfire_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/image_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/office_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/pandas_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/report_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/research_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/scraper_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/search_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/task_tools/stats_tool.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/tools/temp_file_manager.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/utils/LLM_output_structor.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/utils/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/utils/base_callback.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/utils/execution_utils.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/utils/logging.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/utils/prompt_loader.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/utils/token_usage_repository.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/ws/__init__.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs/ws/socket_server.py +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs.egg-info/dependency_links.txt +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs.egg-info/entry_points.txt +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs.egg-info/requires.txt +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/aiecs.egg-info/top_level.txt +0 -0
- {aiecs-1.2.0 → aiecs-1.2.2}/setup.cfg +0 -0
|
@@ -5,7 +5,7 @@ A powerful Python middleware framework for building AI-powered applications
|
|
|
5
5
|
with tool orchestration, task execution, and multi-provider LLM support.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = "1.2.
|
|
8
|
+
__version__ = "1.2.2"
|
|
9
9
|
__author__ = "AIECS Team"
|
|
10
10
|
__email__ = "iretbl@gmail.com"
|
|
11
11
|
|
|
@@ -12,7 +12,7 @@ from aiecs.config.config import get_settings, validate_required_settings
|
|
|
12
12
|
from aiecs.domain.task.task_context import TaskContext
|
|
13
13
|
from aiecs.tools import discover_tools, list_tools, get_tool
|
|
14
14
|
from aiecs.llm.client_factory import LLMClientFactory, LLMClientManager, AIProvider
|
|
15
|
-
from aiecs.llm.base_client import LLMMessage
|
|
15
|
+
from aiecs.llm.clients.base_client import LLMMessage
|
|
16
16
|
|
|
17
17
|
logger = logging.getLogger(__name__)
|
|
18
18
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from pydantic import Field, ConfigDict
|
|
2
2
|
from pydantic_settings import BaseSettings
|
|
3
3
|
from functools import lru_cache
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
class Settings(BaseSettings):
|
|
6
7
|
# LLM Provider Configuration (optional until used)
|
|
@@ -14,6 +15,13 @@ class Settings(BaseSettings):
|
|
|
14
15
|
xai_api_key: str = Field(default="", alias="XAI_API_KEY")
|
|
15
16
|
grok_api_key: str = Field(default="", alias="GROK_API_KEY") # Backward compatibility
|
|
16
17
|
|
|
18
|
+
# LLM Models Configuration
|
|
19
|
+
llm_models_config_path: str = Field(
|
|
20
|
+
default="",
|
|
21
|
+
alias="LLM_MODELS_CONFIG",
|
|
22
|
+
description="Path to LLM models YAML configuration file"
|
|
23
|
+
)
|
|
24
|
+
|
|
17
25
|
# Infrastructure Configuration (with sensible defaults)
|
|
18
26
|
celery_broker_url: str = Field(default="redis://localhost:6379/0", alias="CELERY_BROKER_URL")
|
|
19
27
|
cors_allowed_origins: str = Field(default="http://localhost:3000,http://express-gateway:3001", alias="CORS_ALLOWED_ORIGINS")
|
|
@@ -46,7 +54,7 @@ class Settings(BaseSettings):
|
|
|
46
54
|
reload: bool = Field(default=False, alias="RELOAD")
|
|
47
55
|
port: int = Field(default=8000, alias="PORT")
|
|
48
56
|
|
|
49
|
-
model_config = ConfigDict(env_file=".env", env_file_encoding="utf-8")
|
|
57
|
+
model_config = ConfigDict(env_file=".env", env_file_encoding="utf-8", extra="allow")
|
|
50
58
|
|
|
51
59
|
@property
|
|
52
60
|
def database_config(self) -> dict:
|
|
@@ -70,6 +78,35 @@ class Settings(BaseSettings):
|
|
|
70
78
|
"local_storage_path": "./storage"
|
|
71
79
|
}
|
|
72
80
|
|
|
81
|
+
|
|
82
|
+
def validate_llm_models_config(self) -> bool:
|
|
83
|
+
"""
|
|
84
|
+
Validate that LLM models configuration file exists.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
True if config file exists or can be found in default locations
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
FileNotFoundError: If config file doesn't exist
|
|
91
|
+
"""
|
|
92
|
+
if self.llm_models_config_path:
|
|
93
|
+
config_path = Path(self.llm_models_config_path)
|
|
94
|
+
if not config_path.exists():
|
|
95
|
+
raise FileNotFoundError(
|
|
96
|
+
f"LLM models config file not found: {config_path}"
|
|
97
|
+
)
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
# Check default locations
|
|
101
|
+
current_dir = Path(__file__).parent
|
|
102
|
+
default_path = current_dir / "llm_models.yaml"
|
|
103
|
+
|
|
104
|
+
if default_path.exists():
|
|
105
|
+
return True
|
|
106
|
+
|
|
107
|
+
# If not found, it's still okay - the config loader will try to find it
|
|
108
|
+
return True
|
|
109
|
+
|
|
73
110
|
@lru_cache()
|
|
74
111
|
def get_settings():
|
|
75
112
|
return Settings()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Infrastructure monitoring module
|
|
2
|
+
|
|
3
|
+
Contains monitoring, metrics, and observability infrastructure.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .executor_metrics import ExecutorMetrics
|
|
7
|
+
from .tracing_manager import TracingManager
|
|
8
|
+
from .global_metrics_manager import (
|
|
9
|
+
initialize_global_metrics,
|
|
10
|
+
get_global_metrics,
|
|
11
|
+
close_global_metrics,
|
|
12
|
+
is_metrics_initialized,
|
|
13
|
+
get_metrics_summary,
|
|
14
|
+
record_operation,
|
|
15
|
+
record_duration,
|
|
16
|
+
record_operation_success,
|
|
17
|
+
record_operation_failure,
|
|
18
|
+
record_retry
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"ExecutorMetrics",
|
|
23
|
+
"TracingManager",
|
|
24
|
+
"initialize_global_metrics",
|
|
25
|
+
"get_global_metrics",
|
|
26
|
+
"close_global_metrics",
|
|
27
|
+
"is_metrics_initialized",
|
|
28
|
+
"get_metrics_summary",
|
|
29
|
+
"record_operation",
|
|
30
|
+
"record_duration",
|
|
31
|
+
"record_operation_success",
|
|
32
|
+
"record_operation_failure",
|
|
33
|
+
"record_retry",
|
|
34
|
+
]
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Global Metrics Manager
|
|
3
|
+
|
|
4
|
+
This module provides a singleton ExecutorMetrics instance that can be shared
|
|
5
|
+
across all components in the application. It follows the same pattern as
|
|
6
|
+
other global managers in the infrastructure layer.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
# In main.py startup:
|
|
10
|
+
await initialize_global_metrics()
|
|
11
|
+
|
|
12
|
+
# In any component:
|
|
13
|
+
from aiecs.infrastructure.monitoring.global_metrics_manager import get_global_metrics
|
|
14
|
+
metrics = get_global_metrics()
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import asyncio
|
|
19
|
+
import os
|
|
20
|
+
from typing import Optional, Dict, Any
|
|
21
|
+
from .executor_metrics import ExecutorMetrics
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
# Global singleton instance
|
|
26
|
+
_global_metrics: Optional[ExecutorMetrics] = None
|
|
27
|
+
_initialization_lock = asyncio.Lock()
|
|
28
|
+
_initialized = False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def initialize_global_metrics(
|
|
32
|
+
enable_metrics: bool = True,
|
|
33
|
+
metrics_port: Optional[int] = None,
|
|
34
|
+
config: Optional[Dict[str, Any]] = None
|
|
35
|
+
) -> Optional[ExecutorMetrics]:
|
|
36
|
+
"""
|
|
37
|
+
Initialize the global ExecutorMetrics instance.
|
|
38
|
+
|
|
39
|
+
This should be called once during application startup (in main.py lifespan).
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
enable_metrics: Whether to enable metrics collection (default: True)
|
|
43
|
+
metrics_port: Port for metrics server (default: from env or 8001)
|
|
44
|
+
config: Additional configuration options
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
The initialized ExecutorMetrics instance or None if initialization fails
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
@asynccontextmanager
|
|
51
|
+
async def lifespan(app: FastAPI):
|
|
52
|
+
# Startup
|
|
53
|
+
await initialize_global_metrics()
|
|
54
|
+
yield
|
|
55
|
+
# Shutdown
|
|
56
|
+
await close_global_metrics()
|
|
57
|
+
"""
|
|
58
|
+
global _global_metrics, _initialized
|
|
59
|
+
|
|
60
|
+
if _initialized and _global_metrics:
|
|
61
|
+
logger.info("Global metrics already initialized")
|
|
62
|
+
return _global_metrics
|
|
63
|
+
|
|
64
|
+
async with _initialization_lock:
|
|
65
|
+
# Double-check after acquiring lock
|
|
66
|
+
if _initialized and _global_metrics:
|
|
67
|
+
return _global_metrics
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
# Determine metrics port
|
|
71
|
+
if metrics_port is None:
|
|
72
|
+
metrics_port = int(os.environ.get("METRICS_PORT", "8001"))
|
|
73
|
+
|
|
74
|
+
# Check if metrics should be enabled
|
|
75
|
+
if not enable_metrics:
|
|
76
|
+
enable_metrics = os.environ.get("ENABLE_METRICS", "true").lower() == "true"
|
|
77
|
+
|
|
78
|
+
logger.info(f"Initializing global metrics (port: {metrics_port}, enabled: {enable_metrics})...")
|
|
79
|
+
|
|
80
|
+
# Create metrics instance
|
|
81
|
+
_global_metrics = ExecutorMetrics(
|
|
82
|
+
enable_metrics=enable_metrics,
|
|
83
|
+
metrics_port=metrics_port
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
_initialized = True
|
|
87
|
+
logger.info("✅ Global metrics initialized successfully")
|
|
88
|
+
return _global_metrics
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
logger.error(f"❌ Failed to initialize global metrics: {e}")
|
|
92
|
+
logger.warning("Application will continue without metrics (degraded mode)")
|
|
93
|
+
_global_metrics = None
|
|
94
|
+
_initialized = False
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_global_metrics() -> Optional[ExecutorMetrics]:
|
|
99
|
+
"""
|
|
100
|
+
Get the global ExecutorMetrics instance.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
The global ExecutorMetrics instance or None if not initialized
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
RuntimeError: If metrics are requested but not initialized
|
|
107
|
+
|
|
108
|
+
Example:
|
|
109
|
+
metrics = get_global_metrics()
|
|
110
|
+
if metrics:
|
|
111
|
+
metrics.record_operation('my_operation', 1)
|
|
112
|
+
"""
|
|
113
|
+
global _global_metrics
|
|
114
|
+
|
|
115
|
+
if _global_metrics is None:
|
|
116
|
+
logger.warning("Global metrics not initialized - call initialize_global_metrics() first")
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
return _global_metrics
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
async def close_global_metrics():
|
|
123
|
+
"""
|
|
124
|
+
Close the global metrics instance.
|
|
125
|
+
|
|
126
|
+
This should be called during application shutdown.
|
|
127
|
+
"""
|
|
128
|
+
global _global_metrics, _initialized
|
|
129
|
+
|
|
130
|
+
if _global_metrics:
|
|
131
|
+
try:
|
|
132
|
+
# ExecutorMetrics doesn't have a close method, but we can clean up
|
|
133
|
+
logger.info("Closing global metrics...")
|
|
134
|
+
_global_metrics = None
|
|
135
|
+
_initialized = False
|
|
136
|
+
logger.info("✅ Global metrics closed successfully")
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logger.error(f"❌ Error closing global metrics: {e}")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def is_metrics_initialized() -> bool:
|
|
142
|
+
"""
|
|
143
|
+
Check if global metrics are initialized.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
True if metrics are initialized, False otherwise
|
|
147
|
+
"""
|
|
148
|
+
return _initialized and _global_metrics is not None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def get_metrics_summary() -> Dict[str, Any]:
|
|
152
|
+
"""
|
|
153
|
+
Get a summary of the global metrics status.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Dictionary containing metrics status information
|
|
157
|
+
"""
|
|
158
|
+
if not is_metrics_initialized():
|
|
159
|
+
return {
|
|
160
|
+
"initialized": False,
|
|
161
|
+
"message": "Global metrics not initialized"
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
return _global_metrics.get_metrics_summary()
|
|
166
|
+
except Exception as e:
|
|
167
|
+
return {
|
|
168
|
+
"initialized": True,
|
|
169
|
+
"error": str(e),
|
|
170
|
+
"message": "Failed to get metrics summary"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# Convenience functions for common operations
|
|
175
|
+
def record_operation(operation_type: str, success: bool = True, duration: Optional[float] = None, **kwargs):
|
|
176
|
+
"""Record an operation using global metrics."""
|
|
177
|
+
metrics = get_global_metrics()
|
|
178
|
+
if metrics:
|
|
179
|
+
metrics.record_operation(operation_type, success, duration, **kwargs)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def record_duration(operation: str, duration: float, labels: Optional[Dict[str, str]] = None):
|
|
183
|
+
"""Record operation duration using global metrics."""
|
|
184
|
+
metrics = get_global_metrics()
|
|
185
|
+
if metrics:
|
|
186
|
+
metrics.record_duration(operation, duration, labels)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def record_operation_success(operation: str, labels: Optional[Dict[str, str]] = None):
|
|
190
|
+
"""Record operation success using global metrics."""
|
|
191
|
+
metrics = get_global_metrics()
|
|
192
|
+
if metrics:
|
|
193
|
+
metrics.record_operation_success(operation, labels)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def record_operation_failure(operation: str, error_type: str, labels: Optional[Dict[str, str]] = None):
|
|
197
|
+
"""Record operation failure using global metrics."""
|
|
198
|
+
metrics = get_global_metrics()
|
|
199
|
+
if metrics:
|
|
200
|
+
metrics.record_operation_failure(operation, error_type, labels)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def record_retry(operation: str, attempt_number: int):
|
|
204
|
+
"""Record retry using global metrics."""
|
|
205
|
+
metrics = get_global_metrics()
|
|
206
|
+
if metrics:
|
|
207
|
+
metrics.record_retry(operation, attempt_number)
|
|
@@ -29,7 +29,7 @@ except ImportError:
|
|
|
29
29
|
GoogleCloudError = Exception
|
|
30
30
|
DefaultCredentialsError = Exception
|
|
31
31
|
|
|
32
|
-
from ..monitoring.
|
|
32
|
+
from ..monitoring.global_metrics_manager import get_global_metrics
|
|
33
33
|
|
|
34
34
|
logger = logging.getLogger(__name__)
|
|
35
35
|
|
|
@@ -93,8 +93,8 @@ class FileStorage:
|
|
|
93
93
|
self._cache_timestamps = {}
|
|
94
94
|
self._initialized = False
|
|
95
95
|
|
|
96
|
-
# Metrics
|
|
97
|
-
self.metrics =
|
|
96
|
+
# Metrics - use global metrics manager
|
|
97
|
+
self.metrics = get_global_metrics()
|
|
98
98
|
|
|
99
99
|
# Ensure local storage directory exists
|
|
100
100
|
if self.config.enable_local_fallback:
|
|
@@ -205,26 +205,30 @@ class FileStorage:
|
|
|
205
205
|
if self._gcs_bucket:
|
|
206
206
|
success = await self._store_gcs(key, serialized_data, metadata, compressed)
|
|
207
207
|
if success:
|
|
208
|
-
self.metrics
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
if self.metrics:
|
|
209
|
+
self.metrics.record_operation('gcs_store_success', 1)
|
|
210
|
+
duration = (datetime.utcnow() - start_time).total_seconds()
|
|
211
|
+
self.metrics.record_duration('gcs_store_duration', duration)
|
|
211
212
|
return True
|
|
212
213
|
|
|
213
214
|
# Fallback to local storage
|
|
214
215
|
if self.config.enable_local_fallback:
|
|
215
216
|
success = await self._store_local(key, serialized_data, metadata, compressed)
|
|
216
217
|
if success:
|
|
217
|
-
self.metrics
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
if self.metrics:
|
|
219
|
+
self.metrics.record_operation('local_store_success', 1)
|
|
220
|
+
duration = (datetime.utcnow() - start_time).total_seconds()
|
|
221
|
+
self.metrics.record_duration('local_store_duration', duration)
|
|
220
222
|
return True
|
|
221
223
|
|
|
222
|
-
self.metrics
|
|
224
|
+
if self.metrics:
|
|
225
|
+
self.metrics.record_operation('store_failure', 1)
|
|
223
226
|
return False
|
|
224
227
|
|
|
225
228
|
except Exception as e:
|
|
226
229
|
logger.error(f"Failed to store data for key {key}: {e}")
|
|
227
|
-
self.metrics
|
|
230
|
+
if self.metrics:
|
|
231
|
+
self.metrics.record_operation('store_error', 1)
|
|
228
232
|
raise FileStorageError(f"Storage failed: {e}")
|
|
229
233
|
|
|
230
234
|
async def retrieve(self, key: str) -> Optional[Union[str, bytes, Dict[str, Any]]]:
|
|
@@ -247,7 +251,8 @@ class FileStorage:
|
|
|
247
251
|
if self.config.enable_cache and key in self._cache:
|
|
248
252
|
cache_time = self._cache_timestamps.get(key)
|
|
249
253
|
if cache_time and (datetime.utcnow() - cache_time).total_seconds() < self.config.cache_ttl_seconds:
|
|
250
|
-
self.metrics
|
|
254
|
+
if self.metrics:
|
|
255
|
+
self.metrics.record_operation('cache_hit', 1)
|
|
251
256
|
return self._cache[key]['data']
|
|
252
257
|
else:
|
|
253
258
|
# Remove expired cache entry
|
|
@@ -258,9 +263,10 @@ class FileStorage:
|
|
|
258
263
|
if self._gcs_bucket:
|
|
259
264
|
data = await self._retrieve_gcs(key)
|
|
260
265
|
if data is not None:
|
|
261
|
-
self.metrics
|
|
262
|
-
|
|
263
|
-
|
|
266
|
+
if self.metrics:
|
|
267
|
+
self.metrics.record_operation('gcs_retrieve_success', 1)
|
|
268
|
+
duration = (datetime.utcnow() - start_time).total_seconds()
|
|
269
|
+
self.metrics.record_duration('gcs_retrieve_duration', duration)
|
|
264
270
|
|
|
265
271
|
# Update cache
|
|
266
272
|
if self.config.enable_cache:
|
|
@@ -273,9 +279,10 @@ class FileStorage:
|
|
|
273
279
|
if self.config.enable_local_fallback:
|
|
274
280
|
data = await self._retrieve_local(key)
|
|
275
281
|
if data is not None:
|
|
276
|
-
self.metrics
|
|
277
|
-
|
|
278
|
-
|
|
282
|
+
if self.metrics:
|
|
283
|
+
self.metrics.record_operation('local_retrieve_success', 1)
|
|
284
|
+
duration = (datetime.utcnow() - start_time).total_seconds()
|
|
285
|
+
self.metrics.record_duration('local_retrieve_duration', duration)
|
|
279
286
|
|
|
280
287
|
# Update cache
|
|
281
288
|
if self.config.enable_cache:
|
|
@@ -284,12 +291,14 @@ class FileStorage:
|
|
|
284
291
|
|
|
285
292
|
return data
|
|
286
293
|
|
|
287
|
-
self.metrics
|
|
294
|
+
if self.metrics:
|
|
295
|
+
self.metrics.record_operation('retrieve_not_found', 1)
|
|
288
296
|
return None
|
|
289
297
|
|
|
290
298
|
except Exception as e:
|
|
291
299
|
logger.error(f"Failed to retrieve data for key {key}: {e}")
|
|
292
|
-
self.metrics
|
|
300
|
+
if self.metrics:
|
|
301
|
+
self.metrics.record_operation('retrieve_error', 1)
|
|
293
302
|
raise FileStorageError(f"Retrieval failed: {e}")
|
|
294
303
|
|
|
295
304
|
async def delete(self, key: str) -> bool:
|
|
@@ -317,7 +326,8 @@ class FileStorage:
|
|
|
317
326
|
if self._gcs_bucket:
|
|
318
327
|
gcs_success = await self._delete_gcs(key)
|
|
319
328
|
if gcs_success:
|
|
320
|
-
self.metrics
|
|
329
|
+
if self.metrics:
|
|
330
|
+
self.metrics.record_operation('gcs_delete_success', 1)
|
|
321
331
|
else:
|
|
322
332
|
success = False
|
|
323
333
|
|
|
@@ -325,20 +335,23 @@ class FileStorage:
|
|
|
325
335
|
if self.config.enable_local_fallback:
|
|
326
336
|
local_success = await self._delete_local(key)
|
|
327
337
|
if local_success:
|
|
328
|
-
self.metrics
|
|
338
|
+
if self.metrics:
|
|
339
|
+
self.metrics.record_operation('local_delete_success', 1)
|
|
329
340
|
else:
|
|
330
341
|
success = False
|
|
331
342
|
|
|
332
|
-
if
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
343
|
+
if self.metrics:
|
|
344
|
+
if success:
|
|
345
|
+
self.metrics.record_operation('delete_success', 1)
|
|
346
|
+
else:
|
|
347
|
+
self.metrics.record_operation('delete_failure', 1)
|
|
336
348
|
|
|
337
349
|
return success
|
|
338
350
|
|
|
339
351
|
except Exception as e:
|
|
340
352
|
logger.error(f"Failed to delete data for key {key}: {e}")
|
|
341
|
-
self.metrics
|
|
353
|
+
if self.metrics:
|
|
354
|
+
self.metrics.record_operation('delete_error', 1)
|
|
342
355
|
raise FileStorageError(f"Deletion failed: {e}")
|
|
343
356
|
|
|
344
357
|
async def exists(self, key: str) -> bool:
|
|
@@ -646,7 +659,7 @@ class FileStorage:
|
|
|
646
659
|
'local_fallback_enabled': self.config.enable_local_fallback,
|
|
647
660
|
'cache_enabled': self.config.enable_cache,
|
|
648
661
|
'cache_size': len(self._cache),
|
|
649
|
-
'metrics': self.metrics.get_metrics_summary() if hasattr(self.metrics, 'get_metrics_summary') else {}
|
|
662
|
+
'metrics': self.metrics.get_metrics_summary() if self.metrics and hasattr(self.metrics, 'get_metrics_summary') else {}
|
|
650
663
|
}
|
|
651
664
|
|
|
652
665
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Package - Modular AI Provider Architecture
|
|
3
|
+
|
|
4
|
+
This package provides a unified interface to multiple AI providers through
|
|
5
|
+
individual client implementations and a factory pattern.
|
|
6
|
+
|
|
7
|
+
Package Structure:
|
|
8
|
+
- clients/: LLM client implementations
|
|
9
|
+
- config/: Configuration management
|
|
10
|
+
- callbacks/: Callback handlers
|
|
11
|
+
- utils/: Utility functions and scripts
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# Import from organized subpackages
|
|
15
|
+
from .clients import (
|
|
16
|
+
BaseLLMClient,
|
|
17
|
+
LLMMessage,
|
|
18
|
+
LLMResponse,
|
|
19
|
+
LLMClientError,
|
|
20
|
+
ProviderNotAvailableError,
|
|
21
|
+
RateLimitError,
|
|
22
|
+
OpenAIClient,
|
|
23
|
+
VertexAIClient,
|
|
24
|
+
GoogleAIClient,
|
|
25
|
+
XAIClient
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from .client_factory import (
|
|
29
|
+
AIProvider,
|
|
30
|
+
LLMClientFactory,
|
|
31
|
+
LLMClientManager,
|
|
32
|
+
get_llm_manager,
|
|
33
|
+
generate_text,
|
|
34
|
+
stream_text
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
from .config import (
|
|
38
|
+
ModelCostConfig,
|
|
39
|
+
ModelCapabilities,
|
|
40
|
+
ModelDefaultParams,
|
|
41
|
+
ModelConfig,
|
|
42
|
+
ProviderConfig,
|
|
43
|
+
LLMModelsConfig,
|
|
44
|
+
LLMConfigLoader,
|
|
45
|
+
get_llm_config_loader,
|
|
46
|
+
get_llm_config,
|
|
47
|
+
reload_llm_config
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
from .callbacks import (
|
|
51
|
+
CustomAsyncCallbackHandler
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
__all__ = [
|
|
55
|
+
# Base classes and types
|
|
56
|
+
'BaseLLMClient',
|
|
57
|
+
'LLMMessage',
|
|
58
|
+
'LLMResponse',
|
|
59
|
+
'LLMClientError',
|
|
60
|
+
'ProviderNotAvailableError',
|
|
61
|
+
'RateLimitError',
|
|
62
|
+
'AIProvider',
|
|
63
|
+
|
|
64
|
+
# Factory and manager
|
|
65
|
+
'LLMClientFactory',
|
|
66
|
+
'LLMClientManager',
|
|
67
|
+
'get_llm_manager',
|
|
68
|
+
|
|
69
|
+
# Individual clients
|
|
70
|
+
'OpenAIClient',
|
|
71
|
+
'VertexAIClient',
|
|
72
|
+
'GoogleAIClient',
|
|
73
|
+
'XAIClient',
|
|
74
|
+
|
|
75
|
+
# Convenience functions
|
|
76
|
+
'generate_text',
|
|
77
|
+
'stream_text',
|
|
78
|
+
|
|
79
|
+
# Configuration management
|
|
80
|
+
'ModelCostConfig',
|
|
81
|
+
'ModelCapabilities',
|
|
82
|
+
'ModelDefaultParams',
|
|
83
|
+
'ModelConfig',
|
|
84
|
+
'ProviderConfig',
|
|
85
|
+
'LLMModelsConfig',
|
|
86
|
+
'LLMConfigLoader',
|
|
87
|
+
'get_llm_config_loader',
|
|
88
|
+
'get_llm_config',
|
|
89
|
+
'reload_llm_config',
|
|
90
|
+
|
|
91
|
+
# Callbacks
|
|
92
|
+
'CustomAsyncCallbackHandler',
|
|
93
|
+
]
|
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
# Import the base callback handler from utils
|
|
5
5
|
from aiecs.utils.base_callback import CustomAsyncCallbackHandler
|
|
6
6
|
# Import LLM types for internal use only
|
|
7
|
-
from aiecs.llm.base_client import LLMMessage, LLMResponse
|
|
7
|
+
from aiecs.llm.clients.base_client import LLMMessage, LLMResponse
|
|
8
8
|
# Import token usage repository
|
|
9
9
|
from aiecs.utils.token_usage_repository import token_usage_repo
|
|
10
10
|
|
|
@@ -2,12 +2,12 @@ import logging
|
|
|
2
2
|
from typing import Dict, Any, Optional, Union, List
|
|
3
3
|
from enum import Enum
|
|
4
4
|
|
|
5
|
-
from .base_client import BaseLLMClient, LLMMessage, LLMResponse
|
|
6
|
-
from .openai_client import OpenAIClient
|
|
7
|
-
from .vertex_client import VertexAIClient
|
|
8
|
-
from .googleai_client import GoogleAIClient
|
|
9
|
-
from .xai_client import XAIClient
|
|
10
|
-
from
|
|
5
|
+
from .clients.base_client import BaseLLMClient, LLMMessage, LLMResponse
|
|
6
|
+
from .clients.openai_client import OpenAIClient
|
|
7
|
+
from .clients.vertex_client import VertexAIClient
|
|
8
|
+
from .clients.googleai_client import GoogleAIClient
|
|
9
|
+
from .clients.xai_client import XAIClient
|
|
10
|
+
from .callbacks.custom_callbacks import CustomAsyncCallbackHandler
|
|
11
11
|
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
@@ -72,6 +72,23 @@ class LLMClientFactory:
|
|
|
72
72
|
del cls._clients[provider]
|
|
73
73
|
except Exception as e:
|
|
74
74
|
logger.error(f"Error closing client {provider}: {e}")
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def reload_config(cls):
|
|
78
|
+
"""
|
|
79
|
+
Reload LLM models configuration.
|
|
80
|
+
|
|
81
|
+
This reloads the configuration from the YAML file, allowing for
|
|
82
|
+
hot-reloading of model settings without restarting the application.
|
|
83
|
+
"""
|
|
84
|
+
try:
|
|
85
|
+
from aiecs.llm.config import reload_llm_config
|
|
86
|
+
config = reload_llm_config()
|
|
87
|
+
logger.info(f"Reloaded LLM configuration: {len(config.providers)} providers")
|
|
88
|
+
return config
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"Failed to reload LLM configuration: {e}")
|
|
91
|
+
raise
|
|
75
92
|
|
|
76
93
|
class LLMClientManager:
|
|
77
94
|
"""High-level manager for LLM operations with context-aware provider selection"""
|