aiecs 1.0.1__py3-none-any.whl → 1.7.6__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 aiecs might be problematic. Click here for more details.
- aiecs/__init__.py +13 -16
- aiecs/__main__.py +7 -7
- aiecs/aiecs_client.py +269 -75
- aiecs/application/executors/operation_executor.py +79 -54
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/data_quality.py +302 -0
- aiecs/application/knowledge_graph/builder/data_reshaping.py +293 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +369 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +490 -0
- aiecs/application/knowledge_graph/builder/import_optimizer.py +396 -0
- aiecs/application/knowledge_graph/builder/schema_inference.py +462 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +563 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +1384 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +317 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +98 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +422 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +347 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +241 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +78 -0
- aiecs/application/knowledge_graph/fusion/ab_testing.py +395 -0
- aiecs/application/knowledge_graph/fusion/abbreviation_expander.py +327 -0
- aiecs/application/knowledge_graph/fusion/alias_index.py +597 -0
- aiecs/application/knowledge_graph/fusion/alias_matcher.py +384 -0
- aiecs/application/knowledge_graph/fusion/cache_coordinator.py +343 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +433 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +511 -0
- aiecs/application/knowledge_graph/fusion/evaluation_dataset.py +240 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +632 -0
- aiecs/application/knowledge_graph/fusion/matching_config.py +489 -0
- aiecs/application/knowledge_graph/fusion/name_normalizer.py +352 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +183 -0
- aiecs/application/knowledge_graph/fusion/semantic_name_matcher.py +464 -0
- aiecs/application/knowledge_graph/fusion/similarity_pipeline.py +534 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +342 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +366 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +195 -0
- aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
- aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
- aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +341 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +500 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +163 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +913 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +866 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +475 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +396 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +208 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +170 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +855 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +518 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +27 -0
- aiecs/application/knowledge_graph/retrieval/query_intent_classifier.py +211 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +592 -0
- aiecs/application/knowledge_graph/retrieval/strategy_types.py +23 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +457 -0
- aiecs/application/knowledge_graph/search/reranker.py +293 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +535 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +392 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +305 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +271 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +239 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +313 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +471 -0
- aiecs/config/__init__.py +20 -5
- aiecs/config/config.py +762 -31
- aiecs/config/graph_config.py +131 -0
- aiecs/config/tool_config.py +399 -0
- aiecs/core/__init__.py +29 -13
- aiecs/core/interface/__init__.py +2 -2
- aiecs/core/interface/execution_interface.py +22 -22
- aiecs/core/interface/storage_interface.py +37 -88
- aiecs/core/registry/__init__.py +31 -0
- aiecs/core/registry/service_registry.py +92 -0
- aiecs/domain/__init__.py +270 -1
- aiecs/domain/agent/__init__.py +191 -0
- aiecs/domain/agent/base_agent.py +3870 -0
- aiecs/domain/agent/exceptions.py +99 -0
- aiecs/domain/agent/graph_aware_mixin.py +569 -0
- aiecs/domain/agent/hybrid_agent.py +1435 -0
- aiecs/domain/agent/integration/__init__.py +29 -0
- aiecs/domain/agent/integration/context_compressor.py +216 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +587 -0
- aiecs/domain/agent/integration/protocols.py +281 -0
- aiecs/domain/agent/integration/retry_policy.py +218 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +1892 -0
- aiecs/domain/agent/lifecycle.py +291 -0
- aiecs/domain/agent/llm_agent.py +692 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +1124 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +163 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +86 -0
- aiecs/domain/agent/models.py +884 -0
- aiecs/domain/agent/observability.py +479 -0
- aiecs/domain/agent/persistence.py +449 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +159 -0
- aiecs/domain/agent/prompts/formatters.py +187 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +253 -0
- aiecs/domain/agent/tool_agent.py +444 -0
- aiecs/domain/agent/tools/__init__.py +15 -0
- aiecs/domain/agent/tools/schema_generator.py +364 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +469 -0
- aiecs/domain/community/analytics.py +432 -0
- aiecs/domain/community/collaborative_workflow.py +648 -0
- aiecs/domain/community/communication_hub.py +634 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +796 -0
- aiecs/domain/community/community_manager.py +803 -0
- aiecs/domain/community/decision_engine.py +849 -0
- aiecs/domain/community/exceptions.py +231 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +234 -0
- aiecs/domain/community/resource_manager.py +461 -0
- aiecs/domain/community/shared_context_manager.py +589 -0
- aiecs/domain/context/__init__.py +40 -10
- aiecs/domain/context/context_engine.py +1910 -0
- aiecs/domain/context/conversation_models.py +87 -53
- aiecs/domain/context/graph_memory.py +582 -0
- aiecs/domain/execution/model.py +12 -4
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +148 -0
- aiecs/domain/knowledge_graph/models/evidence.py +178 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +184 -0
- aiecs/domain/knowledge_graph/models/path.py +171 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +171 -0
- aiecs/domain/knowledge_graph/models/query.py +261 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +181 -0
- aiecs/domain/knowledge_graph/models/relation.py +202 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +131 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +253 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +143 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +163 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +691 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +209 -0
- aiecs/domain/task/dsl_processor.py +172 -56
- aiecs/domain/task/model.py +20 -8
- aiecs/domain/task/task_context.py +27 -24
- aiecs/infrastructure/__init__.py +0 -2
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +837 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +458 -0
- aiecs/infrastructure/graph_storage/cache.py +424 -0
- aiecs/infrastructure/graph_storage/distributed.py +223 -0
- aiecs/infrastructure/graph_storage/error_handling.py +380 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +294 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +1197 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +446 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +431 -0
- aiecs/infrastructure/graph_storage/metrics.py +344 -0
- aiecs/infrastructure/graph_storage/migration.py +400 -0
- aiecs/infrastructure/graph_storage/pagination.py +483 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +456 -0
- aiecs/infrastructure/graph_storage/postgres.py +1563 -0
- aiecs/infrastructure/graph_storage/property_storage.py +353 -0
- aiecs/infrastructure/graph_storage/protocols.py +76 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +642 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +1373 -0
- aiecs/infrastructure/graph_storage/streaming.py +487 -0
- aiecs/infrastructure/graph_storage/tenant.py +412 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +92 -54
- aiecs/infrastructure/messaging/websocket_manager.py +51 -35
- aiecs/infrastructure/monitoring/__init__.py +22 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +45 -11
- aiecs/infrastructure/monitoring/global_metrics_manager.py +212 -0
- aiecs/infrastructure/monitoring/structured_logger.py +3 -7
- aiecs/infrastructure/monitoring/tracing_manager.py +63 -35
- aiecs/infrastructure/persistence/__init__.py +14 -1
- aiecs/infrastructure/persistence/context_engine_client.py +184 -0
- aiecs/infrastructure/persistence/database_manager.py +67 -43
- aiecs/infrastructure/persistence/file_storage.py +180 -103
- aiecs/infrastructure/persistence/redis_client.py +74 -21
- aiecs/llm/__init__.py +73 -25
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +26 -19
- aiecs/llm/client_factory.py +224 -36
- aiecs/llm/client_resolver.py +155 -0
- aiecs/llm/clients/__init__.py +38 -0
- aiecs/llm/clients/base_client.py +324 -0
- aiecs/llm/clients/google_function_calling_mixin.py +457 -0
- aiecs/llm/clients/googleai_client.py +241 -0
- aiecs/llm/clients/openai_client.py +158 -0
- aiecs/llm/clients/openai_compatible_mixin.py +367 -0
- aiecs/llm/clients/vertex_client.py +897 -0
- aiecs/llm/clients/xai_client.py +201 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +272 -0
- aiecs/llm/config/config_validator.py +206 -0
- aiecs/llm/config/model_config.py +143 -0
- aiecs/llm/protocols.py +149 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +89 -0
- aiecs/main.py +140 -121
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +138 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/module_checker.py +499 -0
- aiecs/scripts/aid/version_manager.py +235 -0
- aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +1 -0
- aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +1 -0
- aiecs/scripts/dependance_check/__init__.py +15 -0
- aiecs/scripts/dependance_check/dependency_checker.py +1835 -0
- aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +192 -90
- aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +203 -71
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +21 -14
- aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +1 -1
- aiecs/scripts/knowledge_graph/__init__.py +3 -0
- aiecs/scripts/knowledge_graph/run_threshold_experiments.py +212 -0
- aiecs/scripts/migrations/multi_tenancy/README.md +142 -0
- aiecs/scripts/tools_develop/README.md +671 -0
- aiecs/scripts/tools_develop/README_CONFIG_CHECKER.md +273 -0
- aiecs/scripts/tools_develop/TOOLS_CONFIG_GUIDE.md +1287 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_all_tools_config.py +548 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +257 -0
- aiecs/scripts/tools_develop/pre-commit-schema-coverage.sh +66 -0
- aiecs/scripts/tools_develop/schema_coverage.py +511 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +475 -0
- aiecs/scripts/tools_develop/verify_executor_config_fix.py +98 -0
- aiecs/scripts/tools_develop/verify_tools.py +352 -0
- aiecs/tasks/__init__.py +0 -1
- aiecs/tasks/worker.py +115 -47
- aiecs/tools/__init__.py +194 -72
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +632 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +417 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +385 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +330 -0
- aiecs/tools/apisource/providers/__init__.py +112 -0
- aiecs/tools/apisource/providers/base.py +671 -0
- aiecs/tools/apisource/providers/census.py +397 -0
- aiecs/tools/apisource/providers/fred.py +535 -0
- aiecs/tools/apisource/providers/newsapi.py +409 -0
- aiecs/tools/apisource/providers/worldbank.py +352 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +363 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +376 -0
- aiecs/tools/apisource/tool.py +832 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +334 -0
- aiecs/tools/base_tool.py +415 -21
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +607 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2350 -0
- aiecs/tools/docs/content_insertion_tool.py +1320 -0
- aiecs/tools/docs/document_creator_tool.py +1323 -0
- aiecs/tools/docs/document_layout_tool.py +1160 -0
- aiecs/tools/docs/document_parser_tool.py +1011 -0
- aiecs/tools/docs/document_writer_tool.py +1829 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +807 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +944 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +524 -0
- aiecs/tools/langchain_adapter.py +300 -138
- aiecs/tools/schema_generator.py +455 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +581 -0
- aiecs/tools/search_tool/cache.py +264 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +224 -0
- aiecs/tools/search_tool/core.py +778 -0
- aiecs/tools/search_tool/deduplicator.py +119 -0
- aiecs/tools/search_tool/error_handler.py +242 -0
- aiecs/tools/search_tool/metrics.py +343 -0
- aiecs/tools/search_tool/rate_limiter.py +172 -0
- aiecs/tools/search_tool/schemas.py +275 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +646 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +508 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +684 -0
- aiecs/tools/statistics/data_loader_tool.py +555 -0
- aiecs/tools/statistics/data_profiler_tool.py +638 -0
- aiecs/tools/statistics/data_transformer_tool.py +580 -0
- aiecs/tools/statistics/data_visualizer_tool.py +498 -0
- aiecs/tools/statistics/model_trainer_tool.py +507 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +472 -0
- aiecs/tools/task_tools/__init__.py +49 -36
- aiecs/tools/task_tools/chart_tool.py +200 -184
- aiecs/tools/task_tools/classfire_tool.py +268 -267
- aiecs/tools/task_tools/image_tool.py +175 -131
- aiecs/tools/task_tools/office_tool.py +226 -146
- aiecs/tools/task_tools/pandas_tool.py +477 -121
- aiecs/tools/task_tools/report_tool.py +390 -142
- aiecs/tools/task_tools/research_tool.py +149 -79
- aiecs/tools/task_tools/scraper_tool.py +339 -145
- aiecs/tools/task_tools/stats_tool.py +448 -209
- aiecs/tools/temp_file_manager.py +26 -24
- aiecs/tools/tool_executor/__init__.py +18 -16
- aiecs/tools/tool_executor/tool_executor.py +364 -52
- aiecs/utils/LLM_output_structor.py +74 -48
- aiecs/utils/__init__.py +14 -3
- aiecs/utils/base_callback.py +0 -3
- aiecs/utils/cache_provider.py +696 -0
- aiecs/utils/execution_utils.py +50 -31
- aiecs/utils/prompt_loader.py +1 -0
- aiecs/utils/token_usage_repository.py +37 -11
- aiecs/ws/socket_server.py +14 -4
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/METADATA +52 -15
- aiecs-1.7.6.dist-info/RECORD +337 -0
- aiecs-1.7.6.dist-info/entry_points.txt +13 -0
- aiecs/config/registry.py +0 -19
- aiecs/domain/context/content_engine.py +0 -982
- aiecs/llm/base_client.py +0 -99
- aiecs/llm/openai_client.py +0 -125
- aiecs/llm/vertex_client.py +0 -186
- aiecs/llm/xai_client.py +0 -184
- aiecs/scripts/dependency_checker.py +0 -857
- aiecs/scripts/quick_dependency_check.py +0 -269
- aiecs/tools/task_tools/search_api.py +0 -7
- aiecs-1.0.1.dist-info/RECORD +0 -90
- aiecs-1.0.1.dist-info/entry_points.txt +0 -7
- /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
- /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
- /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
- /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/WHEEL +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/top_level.txt +0 -0
|
@@ -5,10 +5,11 @@ import os
|
|
|
5
5
|
|
|
6
6
|
logger = logging.getLogger(__name__)
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
class RedisClient:
|
|
9
10
|
"""Redis client singleton for sharing across different caching strategies"""
|
|
10
11
|
|
|
11
|
-
def __init__(self):
|
|
12
|
+
def __init__(self) -> None:
|
|
12
13
|
self._client: Optional[redis.Redis] = None
|
|
13
14
|
self._connection_pool: Optional[redis.ConnectionPool] = None
|
|
14
15
|
|
|
@@ -16,10 +17,10 @@ class RedisClient:
|
|
|
16
17
|
"""Initialize Redis client"""
|
|
17
18
|
try:
|
|
18
19
|
# Get Redis configuration from environment variables
|
|
19
|
-
redis_host = os.getenv(
|
|
20
|
-
redis_port = int(os.getenv(
|
|
21
|
-
redis_db = int(os.getenv(
|
|
22
|
-
redis_password = os.getenv(
|
|
20
|
+
redis_host = os.getenv("REDIS_HOST", "localhost")
|
|
21
|
+
redis_port = int(os.getenv("REDIS_PORT", 6379))
|
|
22
|
+
redis_db = int(os.getenv("REDIS_DB", 0))
|
|
23
|
+
redis_password = os.getenv("REDIS_PASSWORD")
|
|
23
24
|
|
|
24
25
|
# Create connection pool
|
|
25
26
|
self._connection_pool = redis.ConnectionPool(
|
|
@@ -29,7 +30,7 @@ class RedisClient:
|
|
|
29
30
|
password=redis_password,
|
|
30
31
|
decode_responses=True,
|
|
31
32
|
max_connections=20,
|
|
32
|
-
retry_on_timeout=True
|
|
33
|
+
retry_on_timeout=True,
|
|
33
34
|
)
|
|
34
35
|
|
|
35
36
|
# Create Redis client
|
|
@@ -62,27 +63,69 @@ class RedisClient:
|
|
|
62
63
|
async def hincrby(self, name: str, key: str, amount: int = 1) -> int:
|
|
63
64
|
"""Atomically increment hash field"""
|
|
64
65
|
client = await self.get_client()
|
|
65
|
-
return await client.hincrby(name, key, amount)
|
|
66
|
+
return await client.hincrby(name, key, amount) # type: ignore[misc]
|
|
66
67
|
|
|
67
68
|
async def hget(self, name: str, key: str) -> Optional[str]:
|
|
68
69
|
"""Get hash field value"""
|
|
69
70
|
client = await self.get_client()
|
|
70
|
-
return await client.hget(name, key)
|
|
71
|
+
return await client.hget(name, key) # type: ignore[misc]
|
|
71
72
|
|
|
72
73
|
async def hgetall(self, name: str) -> dict:
|
|
73
74
|
"""Get all hash fields"""
|
|
74
75
|
client = await self.get_client()
|
|
75
|
-
return await client.hgetall(name)
|
|
76
|
-
|
|
77
|
-
async def hset(
|
|
78
|
-
|
|
76
|
+
return await client.hgetall(name) # type: ignore[misc]
|
|
77
|
+
|
|
78
|
+
async def hset(
|
|
79
|
+
self,
|
|
80
|
+
name: str,
|
|
81
|
+
key: Optional[str] = None,
|
|
82
|
+
value: Optional[str] = None,
|
|
83
|
+
mapping: Optional[dict] = None,
|
|
84
|
+
) -> int:
|
|
85
|
+
"""Set hash fields
|
|
86
|
+
|
|
87
|
+
Supports two calling patterns:
|
|
88
|
+
1. hset(name, key, value) - Set single field (positional)
|
|
89
|
+
2. hset(name, key=key, value=value) - Set single field (keyword)
|
|
90
|
+
3. hset(name, mapping={...}) - Set multiple fields
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
name: Redis hash key name
|
|
94
|
+
key: Field name (for single field set)
|
|
95
|
+
value: Field value (for single field set)
|
|
96
|
+
mapping: Dictionary of field-value pairs (for multiple fields)
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Number of fields that were added
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
ValueError: If neither (key, value) nor mapping is provided
|
|
103
|
+
|
|
104
|
+
Examples:
|
|
105
|
+
# Single field with positional args
|
|
106
|
+
await redis_client.hset("myhash", "field1", "value1")
|
|
107
|
+
|
|
108
|
+
# Single field with keyword args
|
|
109
|
+
await redis_client.hset("myhash", key="field1", value="value1")
|
|
110
|
+
|
|
111
|
+
# Multiple fields with mapping
|
|
112
|
+
await redis_client.hset("myhash", mapping={"field1": "value1", "field2": "value2"})
|
|
113
|
+
"""
|
|
79
114
|
client = await self.get_client()
|
|
80
|
-
|
|
115
|
+
|
|
116
|
+
if mapping is not None:
|
|
117
|
+
# Multiple fields mode
|
|
118
|
+
return await client.hset(name, mapping=mapping) # type: ignore[misc]
|
|
119
|
+
elif key is not None and value is not None:
|
|
120
|
+
# Single field mode
|
|
121
|
+
return await client.hset(name, key=key, value=value) # type: ignore[misc]
|
|
122
|
+
else:
|
|
123
|
+
raise ValueError("Either provide (key, value) or mapping parameter. " f"Got: key={key}, value={value}, mapping={mapping}")
|
|
81
124
|
|
|
82
125
|
async def expire(self, name: str, time: int) -> bool:
|
|
83
126
|
"""Set expiration time"""
|
|
84
127
|
client = await self.get_client()
|
|
85
|
-
return await client.expire(name, time)
|
|
128
|
+
return await client.expire(name, time) # type: ignore[misc]
|
|
86
129
|
|
|
87
130
|
async def exists(self, name: str) -> bool:
|
|
88
131
|
"""Check if key exists"""
|
|
@@ -99,11 +142,11 @@ class RedisClient:
|
|
|
99
142
|
logger.error(f"Redis ping failed: {e}")
|
|
100
143
|
return False
|
|
101
144
|
|
|
102
|
-
async def info(self, section: str = None) -> dict:
|
|
145
|
+
async def info(self, section: Optional[str] = None) -> dict:
|
|
103
146
|
"""Get Redis server information"""
|
|
104
147
|
try:
|
|
105
148
|
client = await self.get_client()
|
|
106
|
-
return await client.info(section)
|
|
149
|
+
return await client.info(section) # type: ignore[misc]
|
|
107
150
|
except Exception as e:
|
|
108
151
|
logger.error(f"Redis info failed: {e}")
|
|
109
152
|
return {}
|
|
@@ -112,16 +155,16 @@ class RedisClient:
|
|
|
112
155
|
"""Delete one or more keys"""
|
|
113
156
|
try:
|
|
114
157
|
client = await self.get_client()
|
|
115
|
-
return await client.delete(*keys)
|
|
158
|
+
return await client.delete(*keys) # type: ignore[misc]
|
|
116
159
|
except Exception as e:
|
|
117
160
|
logger.error(f"Redis delete failed: {e}")
|
|
118
161
|
return 0
|
|
119
162
|
|
|
120
|
-
async def set(self, key: str, value: str, ex: int = None) -> bool:
|
|
163
|
+
async def set(self, key: str, value: str, ex: Optional[int] = None) -> bool:
|
|
121
164
|
"""Set a key-value pair with optional expiration"""
|
|
122
165
|
try:
|
|
123
166
|
client = await self.get_client()
|
|
124
|
-
return await client.set(key, value, ex=ex)
|
|
167
|
+
return await client.set(key, value, ex=ex) # type: ignore[misc]
|
|
125
168
|
except Exception as e:
|
|
126
169
|
logger.error(f"Redis set failed for key {key}: {e}")
|
|
127
170
|
return False
|
|
@@ -130,17 +173,21 @@ class RedisClient:
|
|
|
130
173
|
"""Get value by key"""
|
|
131
174
|
try:
|
|
132
175
|
client = await self.get_client()
|
|
133
|
-
return await client.get(key)
|
|
176
|
+
return await client.get(key) # type: ignore[misc]
|
|
134
177
|
except Exception as e:
|
|
135
178
|
logger.error(f"Redis get failed for key {key}: {e}")
|
|
136
179
|
return None
|
|
137
180
|
|
|
181
|
+
|
|
138
182
|
# ✅ Key changes:
|
|
139
183
|
# 1. No longer create instance immediately.
|
|
140
|
-
# 2. Define a global variable with initial value None. This variable will
|
|
184
|
+
# 2. Define a global variable with initial value None. This variable will
|
|
185
|
+
# be populated by lifespan.
|
|
141
186
|
redis_client: Optional[RedisClient] = None
|
|
142
187
|
|
|
143
188
|
# 3. Provide an initialization function for lifespan to call
|
|
189
|
+
|
|
190
|
+
|
|
144
191
|
async def initialize_redis_client():
|
|
145
192
|
"""Create and initialize global Redis client instance at application startup."""
|
|
146
193
|
global redis_client
|
|
@@ -148,13 +195,19 @@ async def initialize_redis_client():
|
|
|
148
195
|
redis_client = RedisClient()
|
|
149
196
|
await redis_client.initialize()
|
|
150
197
|
|
|
198
|
+
|
|
151
199
|
# 4. Provide a close function for lifespan to call
|
|
200
|
+
|
|
201
|
+
|
|
152
202
|
async def close_redis_client():
|
|
153
203
|
"""Close global Redis client instance at application shutdown."""
|
|
154
204
|
if redis_client:
|
|
155
205
|
await redis_client.close()
|
|
156
206
|
|
|
207
|
+
|
|
157
208
|
# For backward compatibility, keep get_redis_client function
|
|
209
|
+
|
|
210
|
+
|
|
158
211
|
async def get_redis_client() -> RedisClient:
|
|
159
212
|
"""Get global Redis client instance"""
|
|
160
213
|
if redis_client is None:
|
aiecs/llm/__init__.py
CHANGED
|
@@ -3,52 +3,100 @@ LLM Package - Modular AI Provider Architecture
|
|
|
3
3
|
|
|
4
4
|
This package provides a unified interface to multiple AI providers through
|
|
5
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
|
|
6
12
|
"""
|
|
7
13
|
|
|
8
|
-
# Import
|
|
9
|
-
from .
|
|
14
|
+
# Import from organized subpackages
|
|
15
|
+
from .clients import (
|
|
10
16
|
BaseLLMClient,
|
|
17
|
+
CacheControl,
|
|
11
18
|
LLMMessage,
|
|
12
19
|
LLMResponse,
|
|
13
20
|
LLMClientError,
|
|
14
21
|
ProviderNotAvailableError,
|
|
15
|
-
RateLimitError
|
|
22
|
+
RateLimitError,
|
|
23
|
+
OpenAIClient,
|
|
24
|
+
VertexAIClient,
|
|
25
|
+
GoogleAIClient,
|
|
26
|
+
XAIClient,
|
|
16
27
|
)
|
|
17
28
|
|
|
29
|
+
from .protocols import LLMClientProtocol
|
|
30
|
+
|
|
18
31
|
from .client_factory import (
|
|
19
32
|
AIProvider,
|
|
20
33
|
LLMClientFactory,
|
|
21
34
|
LLMClientManager,
|
|
22
35
|
get_llm_manager,
|
|
23
36
|
generate_text,
|
|
24
|
-
stream_text
|
|
37
|
+
stream_text,
|
|
25
38
|
)
|
|
26
39
|
|
|
27
|
-
from .
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
from .config import (
|
|
41
|
+
ModelCostConfig,
|
|
42
|
+
ModelCapabilities,
|
|
43
|
+
ModelDefaultParams,
|
|
44
|
+
ModelConfig,
|
|
45
|
+
ProviderConfig,
|
|
46
|
+
LLMModelsConfig,
|
|
47
|
+
LLMConfigLoader,
|
|
48
|
+
get_llm_config_loader,
|
|
49
|
+
get_llm_config,
|
|
50
|
+
reload_llm_config,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
from .callbacks import CustomAsyncCallbackHandler
|
|
54
|
+
|
|
55
|
+
from .client_resolver import (
|
|
56
|
+
resolve_llm_client,
|
|
57
|
+
clear_client_cache,
|
|
58
|
+
get_cached_providers,
|
|
59
|
+
)
|
|
30
60
|
|
|
31
61
|
__all__ = [
|
|
32
62
|
# Base classes and types
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
63
|
+
"BaseLLMClient",
|
|
64
|
+
"CacheControl",
|
|
65
|
+
"LLMMessage",
|
|
66
|
+
"LLMResponse",
|
|
67
|
+
"LLMClientError",
|
|
68
|
+
"ProviderNotAvailableError",
|
|
69
|
+
"RateLimitError",
|
|
70
|
+
"AIProvider",
|
|
71
|
+
# Protocols
|
|
72
|
+
"LLMClientProtocol",
|
|
41
73
|
# Factory and manager
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
74
|
+
"LLMClientFactory",
|
|
75
|
+
"LLMClientManager",
|
|
76
|
+
"get_llm_manager",
|
|
46
77
|
# Individual clients
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
"OpenAIClient",
|
|
79
|
+
"VertexAIClient",
|
|
80
|
+
"GoogleAIClient",
|
|
81
|
+
"XAIClient",
|
|
51
82
|
# Convenience functions
|
|
52
|
-
|
|
53
|
-
|
|
83
|
+
"generate_text",
|
|
84
|
+
"stream_text",
|
|
85
|
+
# Client resolution helpers
|
|
86
|
+
"resolve_llm_client",
|
|
87
|
+
"clear_client_cache",
|
|
88
|
+
"get_cached_providers",
|
|
89
|
+
# Configuration management
|
|
90
|
+
"ModelCostConfig",
|
|
91
|
+
"ModelCapabilities",
|
|
92
|
+
"ModelDefaultParams",
|
|
93
|
+
"ModelConfig",
|
|
94
|
+
"ProviderConfig",
|
|
95
|
+
"LLMModelsConfig",
|
|
96
|
+
"LLMConfigLoader",
|
|
97
|
+
"get_llm_config_loader",
|
|
98
|
+
"get_llm_config",
|
|
99
|
+
"reload_llm_config",
|
|
100
|
+
# Callbacks
|
|
101
|
+
"CustomAsyncCallbackHandler",
|
|
54
102
|
]
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from typing import Any, List, Optional
|
|
2
2
|
import logging
|
|
3
|
+
import time
|
|
3
4
|
|
|
4
5
|
# Import the base callback handler from utils
|
|
5
|
-
from
|
|
6
|
+
from aiecs.utils.base_callback import CustomAsyncCallbackHandler
|
|
7
|
+
|
|
6
8
|
# Import LLM types for internal use only
|
|
7
|
-
from .base_client import LLMMessage, LLMResponse
|
|
8
9
|
# Import token usage repository
|
|
9
|
-
from
|
|
10
|
+
from aiecs.utils.token_usage_repository import token_usage_repo
|
|
10
11
|
|
|
11
12
|
logger = logging.getLogger(__name__)
|
|
12
13
|
|
|
@@ -22,12 +23,13 @@ class RedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
22
23
|
raise ValueError("user_id must be provided for RedisTokenCallbackHandler")
|
|
23
24
|
self.user_id = user_id
|
|
24
25
|
self.cycle_start_date = cycle_start_date
|
|
25
|
-
self.start_time = None
|
|
26
|
-
self.messages = None
|
|
26
|
+
self.start_time: Optional[float] = None
|
|
27
|
+
self.messages: Optional[List[dict]] = None
|
|
27
28
|
|
|
28
29
|
async def on_llm_start(self, messages: List[dict], **kwargs: Any) -> None:
|
|
29
30
|
"""Triggered when LLM call starts"""
|
|
30
31
|
import time
|
|
32
|
+
|
|
31
33
|
self.start_time = time.time()
|
|
32
34
|
self.messages = messages
|
|
33
35
|
|
|
@@ -39,6 +41,7 @@ class RedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
39
41
|
# Record call duration
|
|
40
42
|
if self.start_time:
|
|
41
43
|
import time
|
|
44
|
+
|
|
42
45
|
call_duration = time.time() - self.start_time
|
|
43
46
|
logger.info(f"[Callback] LLM call completed for user '{self.user_id}' in {call_duration:.2f}s")
|
|
44
47
|
|
|
@@ -47,11 +50,7 @@ class RedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
47
50
|
|
|
48
51
|
if tokens_used and tokens_used > 0:
|
|
49
52
|
# Delegate recording work to repository
|
|
50
|
-
await token_usage_repo.increment_total_usage(
|
|
51
|
-
self.user_id,
|
|
52
|
-
tokens_used,
|
|
53
|
-
self.cycle_start_date
|
|
54
|
-
)
|
|
53
|
+
await token_usage_repo.increment_total_usage(self.user_id, tokens_used, self.cycle_start_date)
|
|
55
54
|
|
|
56
55
|
logger.info(f"[Callback] Recorded {tokens_used} tokens for user '{self.user_id}'")
|
|
57
56
|
else:
|
|
@@ -65,6 +64,7 @@ class RedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
65
64
|
"""Triggered when LLM call encounters an error"""
|
|
66
65
|
if self.start_time:
|
|
67
66
|
import time
|
|
67
|
+
|
|
68
68
|
call_duration = time.time() - self.start_time
|
|
69
69
|
logger.error(f"[Callback] LLM call failed for user '{self.user_id}' after {call_duration:.2f}s: {error}")
|
|
70
70
|
else:
|
|
@@ -82,13 +82,14 @@ class DetailedRedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
82
82
|
raise ValueError("user_id must be provided for DetailedRedisTokenCallbackHandler")
|
|
83
83
|
self.user_id = user_id
|
|
84
84
|
self.cycle_start_date = cycle_start_date
|
|
85
|
-
self.start_time = None
|
|
86
|
-
self.messages = None
|
|
85
|
+
self.start_time: Optional[float] = None
|
|
86
|
+
self.messages: Optional[List[dict]] = None
|
|
87
87
|
self.prompt_tokens = 0
|
|
88
88
|
|
|
89
89
|
async def on_llm_start(self, messages: List[dict], **kwargs: Any) -> None:
|
|
90
90
|
"""Triggered when LLM call starts"""
|
|
91
91
|
import time
|
|
92
|
+
|
|
92
93
|
self.start_time = time.time()
|
|
93
94
|
self.messages = messages
|
|
94
95
|
|
|
@@ -103,6 +104,7 @@ class DetailedRedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
103
104
|
# Record call duration
|
|
104
105
|
if self.start_time:
|
|
105
106
|
import time
|
|
107
|
+
|
|
106
108
|
call_duration = time.time() - self.start_time
|
|
107
109
|
logger.info(f"[DetailedCallback] LLM call completed for user '{self.user_id}' in {call_duration:.2f}s")
|
|
108
110
|
|
|
@@ -119,7 +121,7 @@ class DetailedRedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
119
121
|
self.user_id,
|
|
120
122
|
prompt_tokens,
|
|
121
123
|
completion_tokens,
|
|
122
|
-
self.cycle_start_date
|
|
124
|
+
self.cycle_start_date,
|
|
123
125
|
)
|
|
124
126
|
|
|
125
127
|
logger.info(f"[DetailedCallback] Recorded detailed tokens for user '{self.user_id}': prompt={prompt_tokens}, completion={completion_tokens}")
|
|
@@ -134,6 +136,7 @@ class DetailedRedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
134
136
|
"""Triggered when LLM call encounters an error"""
|
|
135
137
|
if self.start_time:
|
|
136
138
|
import time
|
|
139
|
+
|
|
137
140
|
call_duration = time.time() - self.start_time
|
|
138
141
|
logger.error(f"[DetailedCallback] LLM call failed for user '{self.user_id}' after {call_duration:.2f}s: {error}")
|
|
139
142
|
else:
|
|
@@ -141,7 +144,7 @@ class DetailedRedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
141
144
|
|
|
142
145
|
def _estimate_prompt_tokens(self, messages: List[dict]) -> int:
|
|
143
146
|
"""Estimate token count for input messages"""
|
|
144
|
-
total_chars = sum(len(msg.get(
|
|
147
|
+
total_chars = sum(len(msg.get("content", "")) for msg in messages)
|
|
145
148
|
# Rough estimation: 4 characters ≈ 1 token
|
|
146
149
|
return total_chars // 4
|
|
147
150
|
|
|
@@ -153,14 +156,14 @@ class DetailedRedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
153
156
|
tuple: (prompt_tokens, completion_tokens)
|
|
154
157
|
"""
|
|
155
158
|
# If response has detailed token information, use it first
|
|
156
|
-
prompt_tokens = response.get(
|
|
157
|
-
completion_tokens = response.get(
|
|
159
|
+
prompt_tokens = response.get("prompt_tokens") or 0
|
|
160
|
+
completion_tokens = response.get("completion_tokens") or 0
|
|
158
161
|
|
|
159
162
|
if prompt_tokens > 0 and completion_tokens > 0:
|
|
160
163
|
return prompt_tokens, completion_tokens
|
|
161
164
|
|
|
162
165
|
# If only total token count is available, try to allocate
|
|
163
|
-
tokens_used = response.get(
|
|
166
|
+
tokens_used = response.get("tokens_used") or 0
|
|
164
167
|
if tokens_used > 0:
|
|
165
168
|
# Use previously estimated prompt tokens
|
|
166
169
|
prompt_tokens = self.prompt_tokens
|
|
@@ -168,7 +171,7 @@ class DetailedRedisTokenCallbackHandler(CustomAsyncCallbackHandler):
|
|
|
168
171
|
return prompt_tokens, completion_tokens
|
|
169
172
|
|
|
170
173
|
# If no token information, try to estimate from response content
|
|
171
|
-
content = response.get(
|
|
174
|
+
content = response.get("content", "")
|
|
172
175
|
if content:
|
|
173
176
|
completion_tokens = len(content) // 4
|
|
174
177
|
prompt_tokens = self.prompt_tokens
|
|
@@ -219,10 +222,14 @@ def create_token_callback(user_id: str, cycle_start_date: Optional[str] = None)
|
|
|
219
222
|
"""Create a basic token recording callback handler"""
|
|
220
223
|
return RedisTokenCallbackHandler(user_id, cycle_start_date)
|
|
221
224
|
|
|
225
|
+
|
|
222
226
|
def create_detailed_token_callback(user_id: str, cycle_start_date: Optional[str] = None) -> DetailedRedisTokenCallbackHandler:
|
|
223
227
|
"""Create a detailed token recording callback handler"""
|
|
224
228
|
return DetailedRedisTokenCallbackHandler(user_id, cycle_start_date)
|
|
225
229
|
|
|
226
|
-
|
|
230
|
+
|
|
231
|
+
def create_composite_callback(
|
|
232
|
+
*handlers: CustomAsyncCallbackHandler,
|
|
233
|
+
) -> CompositeCallbackHandler:
|
|
227
234
|
"""Create a composite callback handler"""
|
|
228
235
|
return CompositeCallbackHandler(list(handlers))
|