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
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Runnable Pattern for Async Components
|
|
3
|
+
|
|
4
|
+
Provides a formal base class for async task components with standardized
|
|
5
|
+
lifecycle management, configuration, error handling, and retry logic.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import Any, Dict, Optional, TypeVar, Generic
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from enum import Enum
|
|
14
|
+
import asyncio
|
|
15
|
+
import time
|
|
16
|
+
import logging
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
# Type variable for configuration - must be a subclass of RunnableConfig
|
|
22
|
+
ConfigT = TypeVar("ConfigT", bound="RunnableConfig")
|
|
23
|
+
# Type variable for result
|
|
24
|
+
ResultT = TypeVar("ResultT")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RunnableState(Enum):
|
|
28
|
+
"""Runnable component lifecycle states"""
|
|
29
|
+
|
|
30
|
+
CREATED = "created"
|
|
31
|
+
INITIALIZING = "initializing"
|
|
32
|
+
READY = "ready"
|
|
33
|
+
RUNNING = "running"
|
|
34
|
+
COMPLETED = "completed"
|
|
35
|
+
FAILED = "failed"
|
|
36
|
+
STOPPED = "stopped"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class RunnableConfig:
|
|
41
|
+
"""
|
|
42
|
+
Base configuration for Runnable components
|
|
43
|
+
|
|
44
|
+
Attributes:
|
|
45
|
+
max_retries: Maximum number of retry attempts on failure
|
|
46
|
+
retry_delay: Initial delay between retries in seconds
|
|
47
|
+
retry_backoff: Exponential backoff multiplier for retries
|
|
48
|
+
max_retry_delay: Maximum delay between retries in seconds
|
|
49
|
+
timeout: Execution timeout in seconds (None = no timeout)
|
|
50
|
+
enable_circuit_breaker: Enable circuit breaker pattern
|
|
51
|
+
circuit_breaker_threshold: Number of failures before opening circuit
|
|
52
|
+
circuit_breaker_timeout: Time to wait before attempting reset (seconds)
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
max_retries: int = 3
|
|
56
|
+
retry_delay: float = 1.0
|
|
57
|
+
retry_backoff: float = 2.0
|
|
58
|
+
max_retry_delay: float = 30.0
|
|
59
|
+
timeout: Optional[float] = None
|
|
60
|
+
enable_circuit_breaker: bool = False
|
|
61
|
+
circuit_breaker_threshold: int = 5
|
|
62
|
+
circuit_breaker_timeout: float = 60.0
|
|
63
|
+
|
|
64
|
+
# Additional custom configuration
|
|
65
|
+
custom_config: Dict[str, Any] = field(default_factory=dict)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class ExecutionMetrics:
|
|
70
|
+
"""Metrics collected during execution"""
|
|
71
|
+
|
|
72
|
+
start_time: Optional[datetime] = None
|
|
73
|
+
end_time: Optional[datetime] = None
|
|
74
|
+
duration_seconds: float = 0.0
|
|
75
|
+
retry_count: int = 0
|
|
76
|
+
success: bool = False
|
|
77
|
+
error: Optional[str] = None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class CircuitBreaker:
|
|
81
|
+
"""
|
|
82
|
+
Circuit breaker pattern implementation
|
|
83
|
+
|
|
84
|
+
Prevents cascading failures by stopping execution after threshold failures.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(self, threshold: int = 5, timeout: float = 60.0):
|
|
88
|
+
"""
|
|
89
|
+
Initialize circuit breaker
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
threshold: Number of failures before opening circuit
|
|
93
|
+
timeout: Time to wait before attempting reset (seconds)
|
|
94
|
+
"""
|
|
95
|
+
self.threshold = threshold
|
|
96
|
+
self.timeout = timeout
|
|
97
|
+
self.failure_count = 0
|
|
98
|
+
self.last_failure_time: Optional[float] = None
|
|
99
|
+
self.is_open = False
|
|
100
|
+
|
|
101
|
+
def record_success(self) -> None:
|
|
102
|
+
"""Record successful execution"""
|
|
103
|
+
self.failure_count = 0
|
|
104
|
+
self.is_open = False
|
|
105
|
+
|
|
106
|
+
def record_failure(self) -> None:
|
|
107
|
+
"""Record failed execution"""
|
|
108
|
+
self.failure_count += 1
|
|
109
|
+
self.last_failure_time = time.time()
|
|
110
|
+
|
|
111
|
+
if self.failure_count >= self.threshold:
|
|
112
|
+
self.is_open = True
|
|
113
|
+
logger.warning(f"Circuit breaker opened after {self.failure_count} failures")
|
|
114
|
+
|
|
115
|
+
def can_execute(self) -> bool:
|
|
116
|
+
"""Check if execution is allowed"""
|
|
117
|
+
if not self.is_open:
|
|
118
|
+
return True
|
|
119
|
+
|
|
120
|
+
# Check if timeout has passed (half-open state)
|
|
121
|
+
if self.last_failure_time and (time.time() - self.last_failure_time) >= self.timeout:
|
|
122
|
+
logger.info("Circuit breaker attempting reset (half-open)")
|
|
123
|
+
self.is_open = False
|
|
124
|
+
self.failure_count = 0
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class Runnable(ABC, Generic[ConfigT, ResultT]):
|
|
131
|
+
"""
|
|
132
|
+
Abstract base class for async runnable components
|
|
133
|
+
|
|
134
|
+
Provides standardized lifecycle management with:
|
|
135
|
+
- Setup/Execute/Teardown pattern
|
|
136
|
+
- Configuration management with validation
|
|
137
|
+
- Error handling and retry logic with exponential backoff
|
|
138
|
+
- Circuit breaker pattern for fault tolerance
|
|
139
|
+
- Execution metrics and monitoring
|
|
140
|
+
- Timeout support
|
|
141
|
+
|
|
142
|
+
Type Parameters:
|
|
143
|
+
ConfigT: Configuration type (subclass of RunnableConfig)
|
|
144
|
+
ResultT: Result type returned by execute()
|
|
145
|
+
|
|
146
|
+
Example:
|
|
147
|
+
```python
|
|
148
|
+
@dataclass
|
|
149
|
+
class MyConfig(RunnableConfig):
|
|
150
|
+
api_key: str = ""
|
|
151
|
+
max_items: int = 100
|
|
152
|
+
|
|
153
|
+
class MyComponent(Runnable[MyConfig, Dict[str, Any]]):
|
|
154
|
+
async def _setup(self) -> None:
|
|
155
|
+
# Initialize resources
|
|
156
|
+
self.client = APIClient(self.config.api_key)
|
|
157
|
+
|
|
158
|
+
async def _execute(self, **kwargs) -> Dict[str, Any]:
|
|
159
|
+
# Main execution logic
|
|
160
|
+
return await self.client.fetch_data()
|
|
161
|
+
|
|
162
|
+
async def _teardown(self) -> None:
|
|
163
|
+
# Cleanup resources
|
|
164
|
+
await self.client.close()
|
|
165
|
+
```
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def __init__(self, config: Optional[ConfigT] = None):
|
|
169
|
+
"""
|
|
170
|
+
Initialize runnable component
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
config: Component configuration (uses default if None)
|
|
174
|
+
"""
|
|
175
|
+
self._config = config or self._get_default_config()
|
|
176
|
+
self._state = RunnableState.CREATED
|
|
177
|
+
self._metrics = ExecutionMetrics()
|
|
178
|
+
self._circuit_breaker: Optional[CircuitBreaker] = None
|
|
179
|
+
|
|
180
|
+
# Initialize circuit breaker if enabled
|
|
181
|
+
if self._config.enable_circuit_breaker:
|
|
182
|
+
self._circuit_breaker = CircuitBreaker(
|
|
183
|
+
threshold=self._config.circuit_breaker_threshold,
|
|
184
|
+
timeout=self._config.circuit_breaker_timeout,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Validate configuration
|
|
188
|
+
self._validate_config()
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def config(self) -> ConfigT:
|
|
192
|
+
"""Get component configuration"""
|
|
193
|
+
return self._config
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def state(self) -> RunnableState:
|
|
197
|
+
"""Get current component state"""
|
|
198
|
+
return self._state
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def metrics(self) -> ExecutionMetrics:
|
|
202
|
+
"""Get execution metrics"""
|
|
203
|
+
return self._metrics
|
|
204
|
+
|
|
205
|
+
def _get_default_config(self) -> ConfigT:
|
|
206
|
+
"""
|
|
207
|
+
Get default configuration
|
|
208
|
+
|
|
209
|
+
Override in subclasses to provide custom default configuration.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Default configuration instance
|
|
213
|
+
"""
|
|
214
|
+
return RunnableConfig() # type: ignore
|
|
215
|
+
|
|
216
|
+
def _validate_config(self) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Validate configuration
|
|
219
|
+
|
|
220
|
+
Override in subclasses to add custom validation logic.
|
|
221
|
+
Raise ValueError if configuration is invalid.
|
|
222
|
+
"""
|
|
223
|
+
if self._config.max_retries < 0:
|
|
224
|
+
raise ValueError("max_retries must be non-negative")
|
|
225
|
+
if self._config.retry_delay < 0:
|
|
226
|
+
raise ValueError("retry_delay must be non-negative")
|
|
227
|
+
if self._config.retry_backoff < 1.0:
|
|
228
|
+
raise ValueError("retry_backoff must be >= 1.0")
|
|
229
|
+
|
|
230
|
+
async def setup(self) -> None:
|
|
231
|
+
"""
|
|
232
|
+
Setup component (initialize resources)
|
|
233
|
+
|
|
234
|
+
This method should be called before run() or execute().
|
|
235
|
+
Transitions state from CREATED to READY.
|
|
236
|
+
|
|
237
|
+
Raises:
|
|
238
|
+
RuntimeError: If component is not in CREATED state
|
|
239
|
+
Exception: If setup fails
|
|
240
|
+
"""
|
|
241
|
+
if self._state != RunnableState.CREATED:
|
|
242
|
+
raise RuntimeError(f"Cannot setup component in state {self._state.value}")
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
self._state = RunnableState.INITIALIZING
|
|
246
|
+
logger.info(f"Setting up {self.__class__.__name__}...")
|
|
247
|
+
|
|
248
|
+
await self._setup()
|
|
249
|
+
|
|
250
|
+
self._state = RunnableState.READY
|
|
251
|
+
logger.info(f"{self.__class__.__name__} setup complete")
|
|
252
|
+
|
|
253
|
+
except Exception as e:
|
|
254
|
+
self._state = RunnableState.FAILED
|
|
255
|
+
logger.error(f"{self.__class__.__name__} setup failed: {e}")
|
|
256
|
+
raise
|
|
257
|
+
|
|
258
|
+
@abstractmethod
|
|
259
|
+
async def _setup(self) -> None:
|
|
260
|
+
"""
|
|
261
|
+
Subclass-specific setup logic
|
|
262
|
+
|
|
263
|
+
Override this method to implement custom initialization.
|
|
264
|
+
Called by setup() method.
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
async def execute(self, **kwargs) -> ResultT:
|
|
268
|
+
"""
|
|
269
|
+
Execute component logic (without retry/circuit breaker)
|
|
270
|
+
|
|
271
|
+
This is a low-level execution method. Use run() for production
|
|
272
|
+
code to get retry and circuit breaker support.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
**kwargs: Execution parameters
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Execution result
|
|
279
|
+
|
|
280
|
+
Raises:
|
|
281
|
+
RuntimeError: If component is not in READY state
|
|
282
|
+
Exception: If execution fails
|
|
283
|
+
"""
|
|
284
|
+
if self._state != RunnableState.READY:
|
|
285
|
+
raise RuntimeError(f"Cannot execute component in state {self._state.value}. " f"Call setup() first.")
|
|
286
|
+
|
|
287
|
+
try:
|
|
288
|
+
self._state = RunnableState.RUNNING
|
|
289
|
+
self._metrics.start_time = datetime.utcnow()
|
|
290
|
+
|
|
291
|
+
logger.debug(f"Executing {self.__class__.__name__}...")
|
|
292
|
+
result = await self._execute(**kwargs)
|
|
293
|
+
|
|
294
|
+
self._metrics.end_time = datetime.utcnow()
|
|
295
|
+
self._metrics.duration_seconds = (self._metrics.end_time - self._metrics.start_time).total_seconds()
|
|
296
|
+
self._metrics.success = True
|
|
297
|
+
|
|
298
|
+
# Reset to READY for potential re-execution
|
|
299
|
+
self._state = RunnableState.READY
|
|
300
|
+
logger.debug(f"{self.__class__.__name__} execution completed in " f"{self._metrics.duration_seconds:.2f}s")
|
|
301
|
+
|
|
302
|
+
return result
|
|
303
|
+
|
|
304
|
+
except Exception as e:
|
|
305
|
+
self._metrics.end_time = datetime.utcnow()
|
|
306
|
+
if self._metrics.start_time is not None:
|
|
307
|
+
self._metrics.duration_seconds = (self._metrics.end_time - self._metrics.start_time).total_seconds()
|
|
308
|
+
else:
|
|
309
|
+
self._metrics.duration_seconds = 0.0
|
|
310
|
+
self._metrics.error = str(e)
|
|
311
|
+
self._state = RunnableState.FAILED
|
|
312
|
+
logger.error(f"{self.__class__.__name__} execution failed: {e}")
|
|
313
|
+
raise
|
|
314
|
+
|
|
315
|
+
@abstractmethod
|
|
316
|
+
async def _execute(self, **kwargs) -> ResultT:
|
|
317
|
+
"""
|
|
318
|
+
Subclass-specific execution logic
|
|
319
|
+
|
|
320
|
+
Override this method to implement the main component logic.
|
|
321
|
+
Called by execute() and run() methods.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
**kwargs: Execution parameters
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Execution result
|
|
328
|
+
"""
|
|
329
|
+
|
|
330
|
+
async def run(self, **kwargs) -> ResultT:
|
|
331
|
+
"""
|
|
332
|
+
Run component with retry logic and circuit breaker
|
|
333
|
+
|
|
334
|
+
This is the recommended method for production use.
|
|
335
|
+
Includes:
|
|
336
|
+
- Circuit breaker check
|
|
337
|
+
- Retry logic with exponential backoff
|
|
338
|
+
- Timeout support
|
|
339
|
+
- Automatic state management
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
**kwargs: Execution parameters
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
Execution result
|
|
346
|
+
|
|
347
|
+
Raises:
|
|
348
|
+
RuntimeError: If circuit breaker is open
|
|
349
|
+
asyncio.TimeoutError: If execution times out
|
|
350
|
+
Exception: If all retries fail
|
|
351
|
+
"""
|
|
352
|
+
# Check circuit breaker
|
|
353
|
+
if self._circuit_breaker and not self._circuit_breaker.can_execute():
|
|
354
|
+
raise RuntimeError(f"Circuit breaker is open for {self.__class__.__name__}")
|
|
355
|
+
|
|
356
|
+
last_exception: Optional[Exception] = None
|
|
357
|
+
retry_delay = self._config.retry_delay
|
|
358
|
+
|
|
359
|
+
for attempt in range(self._config.max_retries + 1):
|
|
360
|
+
try:
|
|
361
|
+
# Execute with timeout if configured
|
|
362
|
+
if self._config.timeout:
|
|
363
|
+
result = await asyncio.wait_for(self.execute(**kwargs), timeout=self._config.timeout)
|
|
364
|
+
else:
|
|
365
|
+
result = await self.execute(**kwargs)
|
|
366
|
+
|
|
367
|
+
# Record success in circuit breaker
|
|
368
|
+
if self._circuit_breaker:
|
|
369
|
+
self._circuit_breaker.record_success()
|
|
370
|
+
|
|
371
|
+
# Update retry count on success (number of retries that
|
|
372
|
+
# occurred)
|
|
373
|
+
if attempt > 0:
|
|
374
|
+
self._metrics.retry_count = attempt
|
|
375
|
+
|
|
376
|
+
return result
|
|
377
|
+
|
|
378
|
+
except Exception as e:
|
|
379
|
+
last_exception = e
|
|
380
|
+
# Track number of retries (not including initial attempt)
|
|
381
|
+
if attempt > 0:
|
|
382
|
+
self._metrics.retry_count = attempt
|
|
383
|
+
|
|
384
|
+
# Record failure in circuit breaker
|
|
385
|
+
if self._circuit_breaker:
|
|
386
|
+
self._circuit_breaker.record_failure()
|
|
387
|
+
|
|
388
|
+
# Don't retry if this was the last attempt
|
|
389
|
+
if attempt >= self._config.max_retries:
|
|
390
|
+
logger.error(f"{self.__class__.__name__} failed after " f"{attempt + 1} attempts: {e}")
|
|
391
|
+
break
|
|
392
|
+
|
|
393
|
+
# Log retry attempt
|
|
394
|
+
logger.warning(f"{self.__class__.__name__} attempt {attempt + 1} failed: {e}. " f"Retrying in {retry_delay:.1f}s...")
|
|
395
|
+
|
|
396
|
+
# Wait before retry
|
|
397
|
+
await asyncio.sleep(retry_delay)
|
|
398
|
+
|
|
399
|
+
# Increase delay with exponential backoff
|
|
400
|
+
retry_delay = min(
|
|
401
|
+
retry_delay * self._config.retry_backoff,
|
|
402
|
+
self._config.max_retry_delay,
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
# Reset state to READY for next attempt
|
|
406
|
+
self._state = RunnableState.READY
|
|
407
|
+
|
|
408
|
+
# All retries failed
|
|
409
|
+
raise last_exception or RuntimeError("Execution failed")
|
|
410
|
+
|
|
411
|
+
async def teardown(self) -> None:
|
|
412
|
+
"""
|
|
413
|
+
Teardown component (cleanup resources)
|
|
414
|
+
|
|
415
|
+
This method should be called after execution is complete.
|
|
416
|
+
Can be called from any state.
|
|
417
|
+
|
|
418
|
+
Raises:
|
|
419
|
+
Exception: If teardown fails
|
|
420
|
+
"""
|
|
421
|
+
try:
|
|
422
|
+
logger.info(f"Tearing down {self.__class__.__name__}...")
|
|
423
|
+
|
|
424
|
+
await self._teardown()
|
|
425
|
+
|
|
426
|
+
self._state = RunnableState.STOPPED
|
|
427
|
+
logger.info(f"{self.__class__.__name__} teardown complete")
|
|
428
|
+
|
|
429
|
+
except Exception as e:
|
|
430
|
+
logger.error(f"{self.__class__.__name__} teardown failed: {e}")
|
|
431
|
+
raise
|
|
432
|
+
|
|
433
|
+
@abstractmethod
|
|
434
|
+
async def _teardown(self) -> None:
|
|
435
|
+
"""
|
|
436
|
+
Subclass-specific teardown logic
|
|
437
|
+
|
|
438
|
+
Override this method to implement custom cleanup.
|
|
439
|
+
Called by teardown() method.
|
|
440
|
+
"""
|
|
441
|
+
|
|
442
|
+
async def __aenter__(self):
|
|
443
|
+
"""Async context manager entry"""
|
|
444
|
+
await self.setup()
|
|
445
|
+
return self
|
|
446
|
+
|
|
447
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
448
|
+
"""Async context manager exit"""
|
|
449
|
+
await self.teardown()
|
|
450
|
+
return False
|
|
451
|
+
|
|
452
|
+
def reset_metrics(self) -> None:
|
|
453
|
+
"""Reset execution metrics"""
|
|
454
|
+
self._metrics = ExecutionMetrics()
|
|
455
|
+
|
|
456
|
+
def get_metrics_dict(self) -> Dict[str, Any]:
|
|
457
|
+
"""
|
|
458
|
+
Get metrics as dictionary
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
Dictionary with execution metrics
|
|
462
|
+
"""
|
|
463
|
+
return {
|
|
464
|
+
"start_time": (self._metrics.start_time.isoformat() if self._metrics.start_time else None),
|
|
465
|
+
"end_time": (self._metrics.end_time.isoformat() if self._metrics.end_time else None),
|
|
466
|
+
"duration_seconds": self._metrics.duration_seconds,
|
|
467
|
+
"retry_count": self._metrics.retry_count,
|
|
468
|
+
"success": self._metrics.success,
|
|
469
|
+
"error": self._metrics.error,
|
|
470
|
+
"state": self._state.value,
|
|
471
|
+
}
|
aiecs/config/__init__.py
CHANGED
|
@@ -3,13 +3,28 @@
|
|
|
3
3
|
Contains application configuration and service registry.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from .config import Settings, get_settings
|
|
7
|
-
from .
|
|
6
|
+
from .config import Settings, get_settings, validate_required_settings
|
|
7
|
+
from .tool_config import ToolConfigLoader, get_tool_config_loader
|
|
8
|
+
|
|
9
|
+
# Re-export registry functions from core.registry for backward compatibility
|
|
10
|
+
# The registry has been moved to aiecs.core.registry to prevent circular imports
|
|
11
|
+
from ..core.registry import (
|
|
12
|
+
register_ai_service,
|
|
13
|
+
get_ai_service,
|
|
14
|
+
AI_SERVICE_REGISTRY,
|
|
15
|
+
list_registered_services,
|
|
16
|
+
clear_registry,
|
|
17
|
+
)
|
|
8
18
|
|
|
9
19
|
__all__ = [
|
|
10
20
|
"Settings",
|
|
11
21
|
"get_settings",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
22
|
+
"validate_required_settings",
|
|
23
|
+
"register_ai_service", # Re-exported from core.registry
|
|
24
|
+
"get_ai_service", # Re-exported from core.registry
|
|
25
|
+
"AI_SERVICE_REGISTRY", # Re-exported from core.registry
|
|
26
|
+
"list_registered_services", # Re-exported from core.registry
|
|
27
|
+
"clear_registry", # Re-exported from core.registry
|
|
28
|
+
"ToolConfigLoader",
|
|
29
|
+
"get_tool_config_loader",
|
|
15
30
|
]
|