aiecs 1.5.1__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.
Files changed (302) hide show
  1. aiecs/__init__.py +72 -0
  2. aiecs/__main__.py +41 -0
  3. aiecs/aiecs_client.py +469 -0
  4. aiecs/application/__init__.py +10 -0
  5. aiecs/application/executors/__init__.py +10 -0
  6. aiecs/application/executors/operation_executor.py +363 -0
  7. aiecs/application/knowledge_graph/__init__.py +7 -0
  8. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
  11. aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
  12. aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
  13. aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
  14. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  15. aiecs/application/knowledge_graph/extractors/base.py +100 -0
  16. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
  17. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
  18. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
  19. aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
  20. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
  21. aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
  22. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
  23. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
  24. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  25. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
  26. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
  27. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  28. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
  29. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  30. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  31. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
  32. aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
  33. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
  34. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  35. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  36. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
  37. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
  38. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
  39. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
  40. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
  41. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
  42. aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
  43. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
  44. aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
  45. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
  46. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  47. aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
  48. aiecs/application/knowledge_graph/search/reranker.py +295 -0
  49. aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
  50. aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
  51. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  52. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
  53. aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
  54. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  55. aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
  56. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  57. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
  58. aiecs/common/__init__.py +9 -0
  59. aiecs/common/knowledge_graph/__init__.py +17 -0
  60. aiecs/common/knowledge_graph/runnable.py +484 -0
  61. aiecs/config/__init__.py +16 -0
  62. aiecs/config/config.py +498 -0
  63. aiecs/config/graph_config.py +137 -0
  64. aiecs/config/registry.py +23 -0
  65. aiecs/core/__init__.py +46 -0
  66. aiecs/core/interface/__init__.py +34 -0
  67. aiecs/core/interface/execution_interface.py +152 -0
  68. aiecs/core/interface/storage_interface.py +171 -0
  69. aiecs/domain/__init__.py +289 -0
  70. aiecs/domain/agent/__init__.py +189 -0
  71. aiecs/domain/agent/base_agent.py +697 -0
  72. aiecs/domain/agent/exceptions.py +103 -0
  73. aiecs/domain/agent/graph_aware_mixin.py +559 -0
  74. aiecs/domain/agent/hybrid_agent.py +490 -0
  75. aiecs/domain/agent/integration/__init__.py +26 -0
  76. aiecs/domain/agent/integration/context_compressor.py +222 -0
  77. aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
  78. aiecs/domain/agent/integration/retry_policy.py +219 -0
  79. aiecs/domain/agent/integration/role_config.py +213 -0
  80. aiecs/domain/agent/knowledge_aware_agent.py +646 -0
  81. aiecs/domain/agent/lifecycle.py +296 -0
  82. aiecs/domain/agent/llm_agent.py +300 -0
  83. aiecs/domain/agent/memory/__init__.py +12 -0
  84. aiecs/domain/agent/memory/conversation.py +197 -0
  85. aiecs/domain/agent/migration/__init__.py +14 -0
  86. aiecs/domain/agent/migration/conversion.py +160 -0
  87. aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
  88. aiecs/domain/agent/models.py +317 -0
  89. aiecs/domain/agent/observability.py +407 -0
  90. aiecs/domain/agent/persistence.py +289 -0
  91. aiecs/domain/agent/prompts/__init__.py +29 -0
  92. aiecs/domain/agent/prompts/builder.py +161 -0
  93. aiecs/domain/agent/prompts/formatters.py +189 -0
  94. aiecs/domain/agent/prompts/template.py +255 -0
  95. aiecs/domain/agent/registry.py +260 -0
  96. aiecs/domain/agent/tool_agent.py +257 -0
  97. aiecs/domain/agent/tools/__init__.py +12 -0
  98. aiecs/domain/agent/tools/schema_generator.py +221 -0
  99. aiecs/domain/community/__init__.py +155 -0
  100. aiecs/domain/community/agent_adapter.py +477 -0
  101. aiecs/domain/community/analytics.py +481 -0
  102. aiecs/domain/community/collaborative_workflow.py +642 -0
  103. aiecs/domain/community/communication_hub.py +645 -0
  104. aiecs/domain/community/community_builder.py +320 -0
  105. aiecs/domain/community/community_integration.py +800 -0
  106. aiecs/domain/community/community_manager.py +813 -0
  107. aiecs/domain/community/decision_engine.py +879 -0
  108. aiecs/domain/community/exceptions.py +225 -0
  109. aiecs/domain/community/models/__init__.py +33 -0
  110. aiecs/domain/community/models/community_models.py +268 -0
  111. aiecs/domain/community/resource_manager.py +457 -0
  112. aiecs/domain/community/shared_context_manager.py +603 -0
  113. aiecs/domain/context/__init__.py +58 -0
  114. aiecs/domain/context/context_engine.py +989 -0
  115. aiecs/domain/context/conversation_models.py +354 -0
  116. aiecs/domain/context/graph_memory.py +467 -0
  117. aiecs/domain/execution/__init__.py +12 -0
  118. aiecs/domain/execution/model.py +57 -0
  119. aiecs/domain/knowledge_graph/__init__.py +19 -0
  120. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  121. aiecs/domain/knowledge_graph/models/entity.py +130 -0
  122. aiecs/domain/knowledge_graph/models/evidence.py +194 -0
  123. aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
  124. aiecs/domain/knowledge_graph/models/path.py +179 -0
  125. aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
  126. aiecs/domain/knowledge_graph/models/query.py +272 -0
  127. aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
  128. aiecs/domain/knowledge_graph/models/relation.py +136 -0
  129. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  130. aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
  131. aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
  132. aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
  133. aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
  134. aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
  135. aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
  136. aiecs/domain/task/__init__.py +13 -0
  137. aiecs/domain/task/dsl_processor.py +613 -0
  138. aiecs/domain/task/model.py +62 -0
  139. aiecs/domain/task/task_context.py +268 -0
  140. aiecs/infrastructure/__init__.py +24 -0
  141. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  142. aiecs/infrastructure/graph_storage/base.py +601 -0
  143. aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
  144. aiecs/infrastructure/graph_storage/cache.py +429 -0
  145. aiecs/infrastructure/graph_storage/distributed.py +226 -0
  146. aiecs/infrastructure/graph_storage/error_handling.py +390 -0
  147. aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
  148. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  149. aiecs/infrastructure/graph_storage/in_memory.py +514 -0
  150. aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
  151. aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
  152. aiecs/infrastructure/graph_storage/metrics.py +357 -0
  153. aiecs/infrastructure/graph_storage/migration.py +413 -0
  154. aiecs/infrastructure/graph_storage/pagination.py +471 -0
  155. aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
  156. aiecs/infrastructure/graph_storage/postgres.py +871 -0
  157. aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
  158. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  159. aiecs/infrastructure/graph_storage/sqlite.py +623 -0
  160. aiecs/infrastructure/graph_storage/streaming.py +495 -0
  161. aiecs/infrastructure/messaging/__init__.py +13 -0
  162. aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
  163. aiecs/infrastructure/messaging/websocket_manager.py +298 -0
  164. aiecs/infrastructure/monitoring/__init__.py +34 -0
  165. aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
  166. aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
  167. aiecs/infrastructure/monitoring/structured_logger.py +48 -0
  168. aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
  169. aiecs/infrastructure/persistence/__init__.py +24 -0
  170. aiecs/infrastructure/persistence/context_engine_client.py +187 -0
  171. aiecs/infrastructure/persistence/database_manager.py +333 -0
  172. aiecs/infrastructure/persistence/file_storage.py +754 -0
  173. aiecs/infrastructure/persistence/redis_client.py +220 -0
  174. aiecs/llm/__init__.py +86 -0
  175. aiecs/llm/callbacks/__init__.py +11 -0
  176. aiecs/llm/callbacks/custom_callbacks.py +264 -0
  177. aiecs/llm/client_factory.py +420 -0
  178. aiecs/llm/clients/__init__.py +33 -0
  179. aiecs/llm/clients/base_client.py +193 -0
  180. aiecs/llm/clients/googleai_client.py +181 -0
  181. aiecs/llm/clients/openai_client.py +131 -0
  182. aiecs/llm/clients/vertex_client.py +437 -0
  183. aiecs/llm/clients/xai_client.py +184 -0
  184. aiecs/llm/config/__init__.py +51 -0
  185. aiecs/llm/config/config_loader.py +275 -0
  186. aiecs/llm/config/config_validator.py +236 -0
  187. aiecs/llm/config/model_config.py +151 -0
  188. aiecs/llm/utils/__init__.py +10 -0
  189. aiecs/llm/utils/validate_config.py +91 -0
  190. aiecs/main.py +363 -0
  191. aiecs/scripts/__init__.py +3 -0
  192. aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
  193. aiecs/scripts/aid/__init__.py +19 -0
  194. aiecs/scripts/aid/version_manager.py +215 -0
  195. aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
  196. aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
  197. aiecs/scripts/dependance_check/__init__.py +17 -0
  198. aiecs/scripts/dependance_check/dependency_checker.py +938 -0
  199. aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
  200. aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
  201. aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
  202. aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
  203. aiecs/scripts/dependance_patch/__init__.py +7 -0
  204. aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
  205. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  206. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
  207. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
  208. aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
  209. aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
  210. aiecs/scripts/tools_develop/README.md +449 -0
  211. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  212. aiecs/scripts/tools_develop/__init__.py +21 -0
  213. aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
  214. aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
  215. aiecs/scripts/tools_develop/verify_tools.py +356 -0
  216. aiecs/tasks/__init__.py +1 -0
  217. aiecs/tasks/worker.py +172 -0
  218. aiecs/tools/__init__.py +299 -0
  219. aiecs/tools/apisource/__init__.py +99 -0
  220. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  221. aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
  222. aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
  223. aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
  224. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  225. aiecs/tools/apisource/monitoring/metrics.py +303 -0
  226. aiecs/tools/apisource/providers/__init__.py +115 -0
  227. aiecs/tools/apisource/providers/base.py +664 -0
  228. aiecs/tools/apisource/providers/census.py +401 -0
  229. aiecs/tools/apisource/providers/fred.py +564 -0
  230. aiecs/tools/apisource/providers/newsapi.py +412 -0
  231. aiecs/tools/apisource/providers/worldbank.py +357 -0
  232. aiecs/tools/apisource/reliability/__init__.py +12 -0
  233. aiecs/tools/apisource/reliability/error_handler.py +375 -0
  234. aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
  235. aiecs/tools/apisource/tool.py +850 -0
  236. aiecs/tools/apisource/utils/__init__.py +9 -0
  237. aiecs/tools/apisource/utils/validators.py +338 -0
  238. aiecs/tools/base_tool.py +201 -0
  239. aiecs/tools/docs/__init__.py +121 -0
  240. aiecs/tools/docs/ai_document_orchestrator.py +599 -0
  241. aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
  242. aiecs/tools/docs/content_insertion_tool.py +1333 -0
  243. aiecs/tools/docs/document_creator_tool.py +1317 -0
  244. aiecs/tools/docs/document_layout_tool.py +1166 -0
  245. aiecs/tools/docs/document_parser_tool.py +994 -0
  246. aiecs/tools/docs/document_writer_tool.py +1818 -0
  247. aiecs/tools/knowledge_graph/__init__.py +17 -0
  248. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
  249. aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
  250. aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
  251. aiecs/tools/langchain_adapter.py +542 -0
  252. aiecs/tools/schema_generator.py +275 -0
  253. aiecs/tools/search_tool/__init__.py +100 -0
  254. aiecs/tools/search_tool/analyzers.py +589 -0
  255. aiecs/tools/search_tool/cache.py +260 -0
  256. aiecs/tools/search_tool/constants.py +128 -0
  257. aiecs/tools/search_tool/context.py +216 -0
  258. aiecs/tools/search_tool/core.py +749 -0
  259. aiecs/tools/search_tool/deduplicator.py +123 -0
  260. aiecs/tools/search_tool/error_handler.py +271 -0
  261. aiecs/tools/search_tool/metrics.py +371 -0
  262. aiecs/tools/search_tool/rate_limiter.py +178 -0
  263. aiecs/tools/search_tool/schemas.py +277 -0
  264. aiecs/tools/statistics/__init__.py +80 -0
  265. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
  266. aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
  267. aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
  268. aiecs/tools/statistics/data_loader_tool.py +564 -0
  269. aiecs/tools/statistics/data_profiler_tool.py +658 -0
  270. aiecs/tools/statistics/data_transformer_tool.py +573 -0
  271. aiecs/tools/statistics/data_visualizer_tool.py +495 -0
  272. aiecs/tools/statistics/model_trainer_tool.py +487 -0
  273. aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
  274. aiecs/tools/task_tools/__init__.py +86 -0
  275. aiecs/tools/task_tools/chart_tool.py +732 -0
  276. aiecs/tools/task_tools/classfire_tool.py +922 -0
  277. aiecs/tools/task_tools/image_tool.py +447 -0
  278. aiecs/tools/task_tools/office_tool.py +684 -0
  279. aiecs/tools/task_tools/pandas_tool.py +635 -0
  280. aiecs/tools/task_tools/report_tool.py +635 -0
  281. aiecs/tools/task_tools/research_tool.py +392 -0
  282. aiecs/tools/task_tools/scraper_tool.py +715 -0
  283. aiecs/tools/task_tools/stats_tool.py +688 -0
  284. aiecs/tools/temp_file_manager.py +130 -0
  285. aiecs/tools/tool_executor/__init__.py +37 -0
  286. aiecs/tools/tool_executor/tool_executor.py +881 -0
  287. aiecs/utils/LLM_output_structor.py +445 -0
  288. aiecs/utils/__init__.py +34 -0
  289. aiecs/utils/base_callback.py +47 -0
  290. aiecs/utils/cache_provider.py +695 -0
  291. aiecs/utils/execution_utils.py +184 -0
  292. aiecs/utils/logging.py +1 -0
  293. aiecs/utils/prompt_loader.py +14 -0
  294. aiecs/utils/token_usage_repository.py +323 -0
  295. aiecs/ws/__init__.py +0 -0
  296. aiecs/ws/socket_server.py +52 -0
  297. aiecs-1.5.1.dist-info/METADATA +608 -0
  298. aiecs-1.5.1.dist-info/RECORD +302 -0
  299. aiecs-1.5.1.dist-info/WHEEL +5 -0
  300. aiecs-1.5.1.dist-info/entry_points.txt +10 -0
  301. aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
  302. aiecs-1.5.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,484 @@
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 abc import ABC, abstractmethod
9
+ from typing import Any, Dict, Optional, TypeVar, Generic
10
+ from dataclasses import dataclass, field
11
+ from enum import Enum
12
+ import asyncio
13
+ import time
14
+ import logging
15
+ from datetime import datetime
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ # Type variable for configuration
20
+ ConfigT = TypeVar("ConfigT")
21
+ # Type variable for result
22
+ ResultT = TypeVar("ResultT")
23
+
24
+
25
+ class RunnableState(Enum):
26
+ """Runnable component lifecycle states"""
27
+
28
+ CREATED = "created"
29
+ INITIALIZING = "initializing"
30
+ READY = "ready"
31
+ RUNNING = "running"
32
+ COMPLETED = "completed"
33
+ FAILED = "failed"
34
+ STOPPED = "stopped"
35
+
36
+
37
+ @dataclass
38
+ class RunnableConfig:
39
+ """
40
+ Base configuration for Runnable components
41
+
42
+ Attributes:
43
+ max_retries: Maximum number of retry attempts on failure
44
+ retry_delay: Initial delay between retries in seconds
45
+ retry_backoff: Exponential backoff multiplier for retries
46
+ max_retry_delay: Maximum delay between retries in seconds
47
+ timeout: Execution timeout in seconds (None = no timeout)
48
+ enable_circuit_breaker: Enable circuit breaker pattern
49
+ circuit_breaker_threshold: Number of failures before opening circuit
50
+ circuit_breaker_timeout: Time to wait before attempting reset (seconds)
51
+ """
52
+
53
+ max_retries: int = 3
54
+ retry_delay: float = 1.0
55
+ retry_backoff: float = 2.0
56
+ max_retry_delay: float = 30.0
57
+ timeout: Optional[float] = None
58
+ enable_circuit_breaker: bool = False
59
+ circuit_breaker_threshold: int = 5
60
+ circuit_breaker_timeout: float = 60.0
61
+
62
+ # Additional custom configuration
63
+ custom_config: Dict[str, Any] = field(default_factory=dict)
64
+
65
+
66
+ @dataclass
67
+ class ExecutionMetrics:
68
+ """Metrics collected during execution"""
69
+
70
+ start_time: Optional[datetime] = None
71
+ end_time: Optional[datetime] = None
72
+ duration_seconds: float = 0.0
73
+ retry_count: int = 0
74
+ success: bool = False
75
+ error: Optional[str] = None
76
+
77
+
78
+ class CircuitBreaker:
79
+ """
80
+ Circuit breaker pattern implementation
81
+
82
+ Prevents cascading failures by stopping execution after threshold failures.
83
+ """
84
+
85
+ def __init__(self, threshold: int = 5, timeout: float = 60.0):
86
+ """
87
+ Initialize circuit breaker
88
+
89
+ Args:
90
+ threshold: Number of failures before opening circuit
91
+ timeout: Time to wait before attempting reset (seconds)
92
+ """
93
+ self.threshold = threshold
94
+ self.timeout = timeout
95
+ self.failure_count = 0
96
+ self.last_failure_time: Optional[float] = None
97
+ self.is_open = False
98
+
99
+ def record_success(self) -> None:
100
+ """Record successful execution"""
101
+ self.failure_count = 0
102
+ self.is_open = False
103
+
104
+ def record_failure(self) -> None:
105
+ """Record failed execution"""
106
+ self.failure_count += 1
107
+ self.last_failure_time = time.time()
108
+
109
+ if self.failure_count >= self.threshold:
110
+ self.is_open = True
111
+ logger.warning(f"Circuit breaker opened after {self.failure_count} failures")
112
+
113
+ def can_execute(self) -> bool:
114
+ """Check if execution is allowed"""
115
+ if not self.is_open:
116
+ return True
117
+
118
+ # Check if timeout has passed (half-open state)
119
+ if self.last_failure_time and (time.time() - self.last_failure_time) >= self.timeout:
120
+ logger.info("Circuit breaker attempting reset (half-open)")
121
+ self.is_open = False
122
+ self.failure_count = 0
123
+ return True
124
+
125
+ return False
126
+
127
+
128
+ class Runnable(ABC, Generic[ConfigT, ResultT]):
129
+ """
130
+ Abstract base class for async runnable components
131
+
132
+ Provides standardized lifecycle management with:
133
+ - Setup/Execute/Teardown pattern
134
+ - Configuration management with validation
135
+ - Error handling and retry logic with exponential backoff
136
+ - Circuit breaker pattern for fault tolerance
137
+ - Execution metrics and monitoring
138
+ - Timeout support
139
+
140
+ Type Parameters:
141
+ ConfigT: Configuration type (subclass of RunnableConfig)
142
+ ResultT: Result type returned by execute()
143
+
144
+ Example:
145
+ ```python
146
+ @dataclass
147
+ class MyConfig(RunnableConfig):
148
+ api_key: str = ""
149
+ max_items: int = 100
150
+
151
+ class MyComponent(Runnable[MyConfig, Dict[str, Any]]):
152
+ async def _setup(self) -> None:
153
+ # Initialize resources
154
+ self.client = APIClient(self.config.api_key)
155
+
156
+ async def _execute(self, **kwargs) -> Dict[str, Any]:
157
+ # Main execution logic
158
+ return await self.client.fetch_data()
159
+
160
+ async def _teardown(self) -> None:
161
+ # Cleanup resources
162
+ await self.client.close()
163
+ ```
164
+ """
165
+
166
+ def __init__(self, config: Optional[ConfigT] = None):
167
+ """
168
+ Initialize runnable component
169
+
170
+ Args:
171
+ config: Component configuration (uses default if None)
172
+ """
173
+ self._config = config or self._get_default_config()
174
+ self._state = RunnableState.CREATED
175
+ self._metrics = ExecutionMetrics()
176
+ self._circuit_breaker: Optional[CircuitBreaker] = None
177
+
178
+ # Initialize circuit breaker if enabled
179
+ if self._config.enable_circuit_breaker:
180
+ self._circuit_breaker = CircuitBreaker(
181
+ threshold=self._config.circuit_breaker_threshold,
182
+ timeout=self._config.circuit_breaker_timeout,
183
+ )
184
+
185
+ # Validate configuration
186
+ self._validate_config()
187
+
188
+ @property
189
+ def config(self) -> ConfigT:
190
+ """Get component configuration"""
191
+ return self._config
192
+
193
+ @property
194
+ def state(self) -> RunnableState:
195
+ """Get current component state"""
196
+ return self._state
197
+
198
+ @property
199
+ def metrics(self) -> ExecutionMetrics:
200
+ """Get execution metrics"""
201
+ return self._metrics
202
+
203
+ def _get_default_config(self) -> ConfigT:
204
+ """
205
+ Get default configuration
206
+
207
+ Override in subclasses to provide custom default configuration.
208
+
209
+ Returns:
210
+ Default configuration instance
211
+ """
212
+ return RunnableConfig() # type: ignore
213
+
214
+ def _validate_config(self) -> None:
215
+ """
216
+ Validate configuration
217
+
218
+ Override in subclasses to add custom validation logic.
219
+ Raise ValueError if configuration is invalid.
220
+ """
221
+ if self._config.max_retries < 0:
222
+ raise ValueError("max_retries must be non-negative")
223
+ if self._config.retry_delay < 0:
224
+ raise ValueError("retry_delay must be non-negative")
225
+ if self._config.retry_backoff < 1.0:
226
+ raise ValueError("retry_backoff must be >= 1.0")
227
+
228
+ async def setup(self) -> None:
229
+ """
230
+ Setup component (initialize resources)
231
+
232
+ This method should be called before run() or execute().
233
+ Transitions state from CREATED to READY.
234
+
235
+ Raises:
236
+ RuntimeError: If component is not in CREATED state
237
+ Exception: If setup fails
238
+ """
239
+ if self._state != RunnableState.CREATED:
240
+ raise RuntimeError(f"Cannot setup component in state {self._state.value}")
241
+
242
+ try:
243
+ self._state = RunnableState.INITIALIZING
244
+ logger.info(f"Setting up {self.__class__.__name__}...")
245
+
246
+ await self._setup()
247
+
248
+ self._state = RunnableState.READY
249
+ logger.info(f"{self.__class__.__name__} setup complete")
250
+
251
+ except Exception as e:
252
+ self._state = RunnableState.FAILED
253
+ logger.error(f"{self.__class__.__name__} setup failed: {e}")
254
+ raise
255
+
256
+ @abstractmethod
257
+ async def _setup(self) -> None:
258
+ """
259
+ Subclass-specific setup logic
260
+
261
+ Override this method to implement custom initialization.
262
+ Called by setup() method.
263
+ """
264
+
265
+ async def execute(self, **kwargs) -> ResultT:
266
+ """
267
+ Execute component logic (without retry/circuit breaker)
268
+
269
+ This is a low-level execution method. Use run() for production
270
+ code to get retry and circuit breaker support.
271
+
272
+ Args:
273
+ **kwargs: Execution parameters
274
+
275
+ Returns:
276
+ Execution result
277
+
278
+ Raises:
279
+ RuntimeError: If component is not in READY state
280
+ Exception: If execution fails
281
+ """
282
+ if self._state != RunnableState.READY:
283
+ raise RuntimeError(
284
+ f"Cannot execute component in state {self._state.value}. " f"Call setup() first."
285
+ )
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 = (
296
+ self._metrics.end_time - self._metrics.start_time
297
+ ).total_seconds()
298
+ self._metrics.success = True
299
+
300
+ # Reset to READY for potential re-execution
301
+ self._state = RunnableState.READY
302
+ logger.debug(
303
+ f"{self.__class__.__name__} execution completed in "
304
+ f"{self._metrics.duration_seconds:.2f}s"
305
+ )
306
+
307
+ return result
308
+
309
+ except Exception as e:
310
+ self._metrics.end_time = datetime.utcnow()
311
+ self._metrics.duration_seconds = (
312
+ self._metrics.end_time - self._metrics.start_time
313
+ ).total_seconds()
314
+ self._metrics.error = str(e)
315
+ self._state = RunnableState.FAILED
316
+ logger.error(f"{self.__class__.__name__} execution failed: {e}")
317
+ raise
318
+
319
+ @abstractmethod
320
+ async def _execute(self, **kwargs) -> ResultT:
321
+ """
322
+ Subclass-specific execution logic
323
+
324
+ Override this method to implement the main component logic.
325
+ Called by execute() and run() methods.
326
+
327
+ Args:
328
+ **kwargs: Execution parameters
329
+
330
+ Returns:
331
+ Execution result
332
+ """
333
+
334
+ async def run(self, **kwargs) -> ResultT:
335
+ """
336
+ Run component with retry logic and circuit breaker
337
+
338
+ This is the recommended method for production use.
339
+ Includes:
340
+ - Circuit breaker check
341
+ - Retry logic with exponential backoff
342
+ - Timeout support
343
+ - Automatic state management
344
+
345
+ Args:
346
+ **kwargs: Execution parameters
347
+
348
+ Returns:
349
+ Execution result
350
+
351
+ Raises:
352
+ RuntimeError: If circuit breaker is open
353
+ asyncio.TimeoutError: If execution times out
354
+ Exception: If all retries fail
355
+ """
356
+ # Check circuit breaker
357
+ if self._circuit_breaker and not self._circuit_breaker.can_execute():
358
+ raise RuntimeError(f"Circuit breaker is open for {self.__class__.__name__}")
359
+
360
+ last_exception: Optional[Exception] = None
361
+ retry_delay = self._config.retry_delay
362
+
363
+ for attempt in range(self._config.max_retries + 1):
364
+ try:
365
+ # Execute with timeout if configured
366
+ if self._config.timeout:
367
+ result = await asyncio.wait_for(
368
+ self.execute(**kwargs), timeout=self._config.timeout
369
+ )
370
+ else:
371
+ result = await self.execute(**kwargs)
372
+
373
+ # Record success in circuit breaker
374
+ if self._circuit_breaker:
375
+ self._circuit_breaker.record_success()
376
+
377
+ # Update retry count on success (number of retries that
378
+ # occurred)
379
+ if attempt > 0:
380
+ self._metrics.retry_count = attempt
381
+
382
+ return result
383
+
384
+ except Exception as e:
385
+ last_exception = e
386
+ # Track number of retries (not including initial attempt)
387
+ if attempt > 0:
388
+ self._metrics.retry_count = attempt
389
+
390
+ # Record failure in circuit breaker
391
+ if self._circuit_breaker:
392
+ self._circuit_breaker.record_failure()
393
+
394
+ # Don't retry if this was the last attempt
395
+ if attempt >= self._config.max_retries:
396
+ logger.error(
397
+ f"{self.__class__.__name__} failed after " f"{attempt + 1} attempts: {e}"
398
+ )
399
+ break
400
+
401
+ # Log retry attempt
402
+ logger.warning(
403
+ f"{self.__class__.__name__} attempt {attempt + 1} failed: {e}. "
404
+ f"Retrying in {retry_delay:.1f}s..."
405
+ )
406
+
407
+ # Wait before retry
408
+ await asyncio.sleep(retry_delay)
409
+
410
+ # Increase delay with exponential backoff
411
+ retry_delay = min(
412
+ retry_delay * self._config.retry_backoff,
413
+ self._config.max_retry_delay,
414
+ )
415
+
416
+ # Reset state to READY for next attempt
417
+ self._state = RunnableState.READY
418
+
419
+ # All retries failed
420
+ raise last_exception or RuntimeError("Execution failed")
421
+
422
+ async def teardown(self) -> None:
423
+ """
424
+ Teardown component (cleanup resources)
425
+
426
+ This method should be called after execution is complete.
427
+ Can be called from any state.
428
+
429
+ Raises:
430
+ Exception: If teardown fails
431
+ """
432
+ try:
433
+ logger.info(f"Tearing down {self.__class__.__name__}...")
434
+
435
+ await self._teardown()
436
+
437
+ self._state = RunnableState.STOPPED
438
+ logger.info(f"{self.__class__.__name__} teardown complete")
439
+
440
+ except Exception as e:
441
+ logger.error(f"{self.__class__.__name__} teardown failed: {e}")
442
+ raise
443
+
444
+ @abstractmethod
445
+ async def _teardown(self) -> None:
446
+ """
447
+ Subclass-specific teardown logic
448
+
449
+ Override this method to implement custom cleanup.
450
+ Called by teardown() method.
451
+ """
452
+
453
+ async def __aenter__(self):
454
+ """Async context manager entry"""
455
+ await self.setup()
456
+ return self
457
+
458
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
459
+ """Async context manager exit"""
460
+ await self.teardown()
461
+ return False
462
+
463
+ def reset_metrics(self) -> None:
464
+ """Reset execution metrics"""
465
+ self._metrics = ExecutionMetrics()
466
+
467
+ def get_metrics_dict(self) -> Dict[str, Any]:
468
+ """
469
+ Get metrics as dictionary
470
+
471
+ Returns:
472
+ Dictionary with execution metrics
473
+ """
474
+ return {
475
+ "start_time": (
476
+ self._metrics.start_time.isoformat() if self._metrics.start_time else None
477
+ ),
478
+ "end_time": (self._metrics.end_time.isoformat() if self._metrics.end_time else None),
479
+ "duration_seconds": self._metrics.duration_seconds,
480
+ "retry_count": self._metrics.retry_count,
481
+ "success": self._metrics.success,
482
+ "error": self._metrics.error,
483
+ "state": self._state.value,
484
+ }
@@ -0,0 +1,16 @@
1
+ """Configuration module
2
+
3
+ Contains application configuration and service registry.
4
+ """
5
+
6
+ from .config import Settings, get_settings, validate_required_settings
7
+ from .registry import register_ai_service, get_ai_service, AI_SERVICE_REGISTRY
8
+
9
+ __all__ = [
10
+ "Settings",
11
+ "get_settings",
12
+ "validate_required_settings",
13
+ "register_ai_service",
14
+ "get_ai_service",
15
+ "AI_SERVICE_REGISTRY",
16
+ ]