aiecs 1.0.1__py3-none-any.whl → 1.7.17__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.

Files changed (340) hide show
  1. aiecs/__init__.py +13 -16
  2. aiecs/__main__.py +7 -7
  3. aiecs/aiecs_client.py +269 -75
  4. aiecs/application/executors/operation_executor.py +79 -54
  5. aiecs/application/knowledge_graph/__init__.py +7 -0
  6. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  7. aiecs/application/knowledge_graph/builder/data_quality.py +302 -0
  8. aiecs/application/knowledge_graph/builder/data_reshaping.py +293 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +369 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +490 -0
  11. aiecs/application/knowledge_graph/builder/import_optimizer.py +396 -0
  12. aiecs/application/knowledge_graph/builder/schema_inference.py +462 -0
  13. aiecs/application/knowledge_graph/builder/schema_mapping.py +563 -0
  14. aiecs/application/knowledge_graph/builder/structured_pipeline.py +1384 -0
  15. aiecs/application/knowledge_graph/builder/text_chunker.py +317 -0
  16. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  17. aiecs/application/knowledge_graph/extractors/base.py +98 -0
  18. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +422 -0
  19. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +347 -0
  20. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +241 -0
  21. aiecs/application/knowledge_graph/fusion/__init__.py +78 -0
  22. aiecs/application/knowledge_graph/fusion/ab_testing.py +395 -0
  23. aiecs/application/knowledge_graph/fusion/abbreviation_expander.py +327 -0
  24. aiecs/application/knowledge_graph/fusion/alias_index.py +597 -0
  25. aiecs/application/knowledge_graph/fusion/alias_matcher.py +384 -0
  26. aiecs/application/knowledge_graph/fusion/cache_coordinator.py +343 -0
  27. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +433 -0
  28. aiecs/application/knowledge_graph/fusion/entity_linker.py +511 -0
  29. aiecs/application/knowledge_graph/fusion/evaluation_dataset.py +240 -0
  30. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +632 -0
  31. aiecs/application/knowledge_graph/fusion/matching_config.py +489 -0
  32. aiecs/application/knowledge_graph/fusion/name_normalizer.py +352 -0
  33. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +183 -0
  34. aiecs/application/knowledge_graph/fusion/semantic_name_matcher.py +464 -0
  35. aiecs/application/knowledge_graph/fusion/similarity_pipeline.py +534 -0
  36. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  37. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +342 -0
  38. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +366 -0
  39. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  40. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +195 -0
  41. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  42. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  43. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +341 -0
  44. aiecs/application/knowledge_graph/reasoning/inference_engine.py +500 -0
  45. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +163 -0
  46. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  47. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  48. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +913 -0
  49. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +866 -0
  50. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +475 -0
  51. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +396 -0
  52. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +208 -0
  53. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +170 -0
  54. aiecs/application/knowledge_graph/reasoning/query_planner.py +855 -0
  55. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +518 -0
  56. aiecs/application/knowledge_graph/retrieval/__init__.py +27 -0
  57. aiecs/application/knowledge_graph/retrieval/query_intent_classifier.py +211 -0
  58. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +592 -0
  59. aiecs/application/knowledge_graph/retrieval/strategy_types.py +23 -0
  60. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  61. aiecs/application/knowledge_graph/search/hybrid_search.py +457 -0
  62. aiecs/application/knowledge_graph/search/reranker.py +293 -0
  63. aiecs/application/knowledge_graph/search/reranker_strategies.py +535 -0
  64. aiecs/application/knowledge_graph/search/text_similarity.py +392 -0
  65. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  66. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +305 -0
  67. aiecs/application/knowledge_graph/traversal/path_scorer.py +271 -0
  68. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  69. aiecs/application/knowledge_graph/validators/relation_validator.py +239 -0
  70. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  71. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +313 -0
  72. aiecs/common/__init__.py +9 -0
  73. aiecs/common/knowledge_graph/__init__.py +17 -0
  74. aiecs/common/knowledge_graph/runnable.py +471 -0
  75. aiecs/config/__init__.py +20 -5
  76. aiecs/config/config.py +762 -31
  77. aiecs/config/graph_config.py +131 -0
  78. aiecs/config/tool_config.py +435 -0
  79. aiecs/core/__init__.py +29 -13
  80. aiecs/core/interface/__init__.py +2 -2
  81. aiecs/core/interface/execution_interface.py +22 -22
  82. aiecs/core/interface/storage_interface.py +37 -88
  83. aiecs/core/registry/__init__.py +31 -0
  84. aiecs/core/registry/service_registry.py +92 -0
  85. aiecs/domain/__init__.py +270 -1
  86. aiecs/domain/agent/__init__.py +191 -0
  87. aiecs/domain/agent/base_agent.py +3949 -0
  88. aiecs/domain/agent/exceptions.py +99 -0
  89. aiecs/domain/agent/graph_aware_mixin.py +569 -0
  90. aiecs/domain/agent/hybrid_agent.py +1731 -0
  91. aiecs/domain/agent/integration/__init__.py +29 -0
  92. aiecs/domain/agent/integration/context_compressor.py +216 -0
  93. aiecs/domain/agent/integration/context_engine_adapter.py +587 -0
  94. aiecs/domain/agent/integration/protocols.py +281 -0
  95. aiecs/domain/agent/integration/retry_policy.py +218 -0
  96. aiecs/domain/agent/integration/role_config.py +213 -0
  97. aiecs/domain/agent/knowledge_aware_agent.py +1892 -0
  98. aiecs/domain/agent/lifecycle.py +291 -0
  99. aiecs/domain/agent/llm_agent.py +692 -0
  100. aiecs/domain/agent/memory/__init__.py +12 -0
  101. aiecs/domain/agent/memory/conversation.py +1124 -0
  102. aiecs/domain/agent/migration/__init__.py +14 -0
  103. aiecs/domain/agent/migration/conversion.py +163 -0
  104. aiecs/domain/agent/migration/legacy_wrapper.py +86 -0
  105. aiecs/domain/agent/models.py +894 -0
  106. aiecs/domain/agent/observability.py +479 -0
  107. aiecs/domain/agent/persistence.py +449 -0
  108. aiecs/domain/agent/prompts/__init__.py +29 -0
  109. aiecs/domain/agent/prompts/builder.py +159 -0
  110. aiecs/domain/agent/prompts/formatters.py +187 -0
  111. aiecs/domain/agent/prompts/template.py +255 -0
  112. aiecs/domain/agent/registry.py +253 -0
  113. aiecs/domain/agent/tool_agent.py +444 -0
  114. aiecs/domain/agent/tools/__init__.py +15 -0
  115. aiecs/domain/agent/tools/schema_generator.py +377 -0
  116. aiecs/domain/community/__init__.py +155 -0
  117. aiecs/domain/community/agent_adapter.py +469 -0
  118. aiecs/domain/community/analytics.py +432 -0
  119. aiecs/domain/community/collaborative_workflow.py +648 -0
  120. aiecs/domain/community/communication_hub.py +634 -0
  121. aiecs/domain/community/community_builder.py +320 -0
  122. aiecs/domain/community/community_integration.py +796 -0
  123. aiecs/domain/community/community_manager.py +803 -0
  124. aiecs/domain/community/decision_engine.py +849 -0
  125. aiecs/domain/community/exceptions.py +231 -0
  126. aiecs/domain/community/models/__init__.py +33 -0
  127. aiecs/domain/community/models/community_models.py +234 -0
  128. aiecs/domain/community/resource_manager.py +461 -0
  129. aiecs/domain/community/shared_context_manager.py +589 -0
  130. aiecs/domain/context/__init__.py +40 -10
  131. aiecs/domain/context/context_engine.py +1910 -0
  132. aiecs/domain/context/conversation_models.py +87 -53
  133. aiecs/domain/context/graph_memory.py +582 -0
  134. aiecs/domain/execution/model.py +12 -4
  135. aiecs/domain/knowledge_graph/__init__.py +19 -0
  136. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  137. aiecs/domain/knowledge_graph/models/entity.py +148 -0
  138. aiecs/domain/knowledge_graph/models/evidence.py +178 -0
  139. aiecs/domain/knowledge_graph/models/inference_rule.py +184 -0
  140. aiecs/domain/knowledge_graph/models/path.py +171 -0
  141. aiecs/domain/knowledge_graph/models/path_pattern.py +171 -0
  142. aiecs/domain/knowledge_graph/models/query.py +261 -0
  143. aiecs/domain/knowledge_graph/models/query_plan.py +181 -0
  144. aiecs/domain/knowledge_graph/models/relation.py +202 -0
  145. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  146. aiecs/domain/knowledge_graph/schema/entity_type.py +131 -0
  147. aiecs/domain/knowledge_graph/schema/graph_schema.py +253 -0
  148. aiecs/domain/knowledge_graph/schema/property_schema.py +143 -0
  149. aiecs/domain/knowledge_graph/schema/relation_type.py +163 -0
  150. aiecs/domain/knowledge_graph/schema/schema_manager.py +691 -0
  151. aiecs/domain/knowledge_graph/schema/type_enums.py +209 -0
  152. aiecs/domain/task/dsl_processor.py +172 -56
  153. aiecs/domain/task/model.py +20 -8
  154. aiecs/domain/task/task_context.py +27 -24
  155. aiecs/infrastructure/__init__.py +0 -2
  156. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  157. aiecs/infrastructure/graph_storage/base.py +837 -0
  158. aiecs/infrastructure/graph_storage/batch_operations.py +458 -0
  159. aiecs/infrastructure/graph_storage/cache.py +424 -0
  160. aiecs/infrastructure/graph_storage/distributed.py +223 -0
  161. aiecs/infrastructure/graph_storage/error_handling.py +380 -0
  162. aiecs/infrastructure/graph_storage/graceful_degradation.py +294 -0
  163. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  164. aiecs/infrastructure/graph_storage/in_memory.py +1197 -0
  165. aiecs/infrastructure/graph_storage/index_optimization.py +446 -0
  166. aiecs/infrastructure/graph_storage/lazy_loading.py +431 -0
  167. aiecs/infrastructure/graph_storage/metrics.py +344 -0
  168. aiecs/infrastructure/graph_storage/migration.py +400 -0
  169. aiecs/infrastructure/graph_storage/pagination.py +483 -0
  170. aiecs/infrastructure/graph_storage/performance_monitoring.py +456 -0
  171. aiecs/infrastructure/graph_storage/postgres.py +1563 -0
  172. aiecs/infrastructure/graph_storage/property_storage.py +353 -0
  173. aiecs/infrastructure/graph_storage/protocols.py +76 -0
  174. aiecs/infrastructure/graph_storage/query_optimizer.py +642 -0
  175. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  176. aiecs/infrastructure/graph_storage/sqlite.py +1373 -0
  177. aiecs/infrastructure/graph_storage/streaming.py +487 -0
  178. aiecs/infrastructure/graph_storage/tenant.py +412 -0
  179. aiecs/infrastructure/messaging/celery_task_manager.py +92 -54
  180. aiecs/infrastructure/messaging/websocket_manager.py +51 -35
  181. aiecs/infrastructure/monitoring/__init__.py +22 -0
  182. aiecs/infrastructure/monitoring/executor_metrics.py +45 -11
  183. aiecs/infrastructure/monitoring/global_metrics_manager.py +212 -0
  184. aiecs/infrastructure/monitoring/structured_logger.py +3 -7
  185. aiecs/infrastructure/monitoring/tracing_manager.py +63 -35
  186. aiecs/infrastructure/persistence/__init__.py +14 -1
  187. aiecs/infrastructure/persistence/context_engine_client.py +184 -0
  188. aiecs/infrastructure/persistence/database_manager.py +67 -43
  189. aiecs/infrastructure/persistence/file_storage.py +180 -103
  190. aiecs/infrastructure/persistence/redis_client.py +74 -21
  191. aiecs/llm/__init__.py +73 -25
  192. aiecs/llm/callbacks/__init__.py +11 -0
  193. aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +26 -19
  194. aiecs/llm/client_factory.py +230 -37
  195. aiecs/llm/client_resolver.py +155 -0
  196. aiecs/llm/clients/__init__.py +38 -0
  197. aiecs/llm/clients/base_client.py +328 -0
  198. aiecs/llm/clients/google_function_calling_mixin.py +415 -0
  199. aiecs/llm/clients/googleai_client.py +314 -0
  200. aiecs/llm/clients/openai_client.py +158 -0
  201. aiecs/llm/clients/openai_compatible_mixin.py +367 -0
  202. aiecs/llm/clients/vertex_client.py +1186 -0
  203. aiecs/llm/clients/xai_client.py +201 -0
  204. aiecs/llm/config/__init__.py +51 -0
  205. aiecs/llm/config/config_loader.py +272 -0
  206. aiecs/llm/config/config_validator.py +206 -0
  207. aiecs/llm/config/model_config.py +143 -0
  208. aiecs/llm/protocols.py +149 -0
  209. aiecs/llm/utils/__init__.py +10 -0
  210. aiecs/llm/utils/validate_config.py +89 -0
  211. aiecs/main.py +140 -121
  212. aiecs/scripts/aid/VERSION_MANAGEMENT.md +138 -0
  213. aiecs/scripts/aid/__init__.py +19 -0
  214. aiecs/scripts/aid/module_checker.py +499 -0
  215. aiecs/scripts/aid/version_manager.py +235 -0
  216. aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +1 -0
  217. aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +1 -0
  218. aiecs/scripts/dependance_check/__init__.py +15 -0
  219. aiecs/scripts/dependance_check/dependency_checker.py +1835 -0
  220. aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +192 -90
  221. aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +203 -71
  222. aiecs/scripts/dependance_patch/__init__.py +7 -0
  223. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  224. aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +21 -14
  225. aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +1 -1
  226. aiecs/scripts/knowledge_graph/__init__.py +3 -0
  227. aiecs/scripts/knowledge_graph/run_threshold_experiments.py +212 -0
  228. aiecs/scripts/migrations/multi_tenancy/README.md +142 -0
  229. aiecs/scripts/tools_develop/README.md +671 -0
  230. aiecs/scripts/tools_develop/README_CONFIG_CHECKER.md +273 -0
  231. aiecs/scripts/tools_develop/TOOLS_CONFIG_GUIDE.md +1287 -0
  232. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  233. aiecs/scripts/tools_develop/__init__.py +21 -0
  234. aiecs/scripts/tools_develop/check_all_tools_config.py +548 -0
  235. aiecs/scripts/tools_develop/check_type_annotations.py +257 -0
  236. aiecs/scripts/tools_develop/pre-commit-schema-coverage.sh +66 -0
  237. aiecs/scripts/tools_develop/schema_coverage.py +511 -0
  238. aiecs/scripts/tools_develop/validate_tool_schemas.py +475 -0
  239. aiecs/scripts/tools_develop/verify_executor_config_fix.py +98 -0
  240. aiecs/scripts/tools_develop/verify_tools.py +352 -0
  241. aiecs/tasks/__init__.py +0 -1
  242. aiecs/tasks/worker.py +115 -47
  243. aiecs/tools/__init__.py +194 -72
  244. aiecs/tools/apisource/__init__.py +99 -0
  245. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  246. aiecs/tools/apisource/intelligence/data_fusion.py +632 -0
  247. aiecs/tools/apisource/intelligence/query_analyzer.py +417 -0
  248. aiecs/tools/apisource/intelligence/search_enhancer.py +385 -0
  249. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  250. aiecs/tools/apisource/monitoring/metrics.py +330 -0
  251. aiecs/tools/apisource/providers/__init__.py +112 -0
  252. aiecs/tools/apisource/providers/base.py +671 -0
  253. aiecs/tools/apisource/providers/census.py +397 -0
  254. aiecs/tools/apisource/providers/fred.py +535 -0
  255. aiecs/tools/apisource/providers/newsapi.py +409 -0
  256. aiecs/tools/apisource/providers/worldbank.py +352 -0
  257. aiecs/tools/apisource/reliability/__init__.py +12 -0
  258. aiecs/tools/apisource/reliability/error_handler.py +363 -0
  259. aiecs/tools/apisource/reliability/fallback_strategy.py +376 -0
  260. aiecs/tools/apisource/tool.py +832 -0
  261. aiecs/tools/apisource/utils/__init__.py +9 -0
  262. aiecs/tools/apisource/utils/validators.py +334 -0
  263. aiecs/tools/base_tool.py +415 -21
  264. aiecs/tools/docs/__init__.py +121 -0
  265. aiecs/tools/docs/ai_document_orchestrator.py +607 -0
  266. aiecs/tools/docs/ai_document_writer_orchestrator.py +2350 -0
  267. aiecs/tools/docs/content_insertion_tool.py +1320 -0
  268. aiecs/tools/docs/document_creator_tool.py +1464 -0
  269. aiecs/tools/docs/document_layout_tool.py +1160 -0
  270. aiecs/tools/docs/document_parser_tool.py +1016 -0
  271. aiecs/tools/docs/document_writer_tool.py +2008 -0
  272. aiecs/tools/knowledge_graph/__init__.py +17 -0
  273. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +807 -0
  274. aiecs/tools/knowledge_graph/graph_search_tool.py +944 -0
  275. aiecs/tools/knowledge_graph/kg_builder_tool.py +524 -0
  276. aiecs/tools/langchain_adapter.py +300 -138
  277. aiecs/tools/schema_generator.py +455 -0
  278. aiecs/tools/search_tool/__init__.py +100 -0
  279. aiecs/tools/search_tool/analyzers.py +581 -0
  280. aiecs/tools/search_tool/cache.py +264 -0
  281. aiecs/tools/search_tool/constants.py +128 -0
  282. aiecs/tools/search_tool/context.py +224 -0
  283. aiecs/tools/search_tool/core.py +778 -0
  284. aiecs/tools/search_tool/deduplicator.py +119 -0
  285. aiecs/tools/search_tool/error_handler.py +242 -0
  286. aiecs/tools/search_tool/metrics.py +343 -0
  287. aiecs/tools/search_tool/rate_limiter.py +172 -0
  288. aiecs/tools/search_tool/schemas.py +275 -0
  289. aiecs/tools/statistics/__init__.py +80 -0
  290. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +646 -0
  291. aiecs/tools/statistics/ai_insight_generator_tool.py +508 -0
  292. aiecs/tools/statistics/ai_report_orchestrator_tool.py +684 -0
  293. aiecs/tools/statistics/data_loader_tool.py +555 -0
  294. aiecs/tools/statistics/data_profiler_tool.py +638 -0
  295. aiecs/tools/statistics/data_transformer_tool.py +580 -0
  296. aiecs/tools/statistics/data_visualizer_tool.py +498 -0
  297. aiecs/tools/statistics/model_trainer_tool.py +507 -0
  298. aiecs/tools/statistics/statistical_analyzer_tool.py +472 -0
  299. aiecs/tools/task_tools/__init__.py +49 -36
  300. aiecs/tools/task_tools/chart_tool.py +200 -184
  301. aiecs/tools/task_tools/classfire_tool.py +268 -267
  302. aiecs/tools/task_tools/image_tool.py +220 -141
  303. aiecs/tools/task_tools/office_tool.py +226 -146
  304. aiecs/tools/task_tools/pandas_tool.py +477 -121
  305. aiecs/tools/task_tools/report_tool.py +390 -142
  306. aiecs/tools/task_tools/research_tool.py +149 -79
  307. aiecs/tools/task_tools/scraper_tool.py +339 -145
  308. aiecs/tools/task_tools/stats_tool.py +448 -209
  309. aiecs/tools/temp_file_manager.py +26 -24
  310. aiecs/tools/tool_executor/__init__.py +18 -16
  311. aiecs/tools/tool_executor/tool_executor.py +364 -52
  312. aiecs/utils/LLM_output_structor.py +74 -48
  313. aiecs/utils/__init__.py +14 -3
  314. aiecs/utils/base_callback.py +0 -3
  315. aiecs/utils/cache_provider.py +696 -0
  316. aiecs/utils/execution_utils.py +50 -31
  317. aiecs/utils/prompt_loader.py +1 -0
  318. aiecs/utils/token_usage_repository.py +37 -11
  319. aiecs/ws/socket_server.py +14 -4
  320. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/METADATA +52 -15
  321. aiecs-1.7.17.dist-info/RECORD +337 -0
  322. aiecs-1.7.17.dist-info/entry_points.txt +13 -0
  323. aiecs/config/registry.py +0 -19
  324. aiecs/domain/context/content_engine.py +0 -982
  325. aiecs/llm/base_client.py +0 -99
  326. aiecs/llm/openai_client.py +0 -125
  327. aiecs/llm/vertex_client.py +0 -186
  328. aiecs/llm/xai_client.py +0 -184
  329. aiecs/scripts/dependency_checker.py +0 -857
  330. aiecs/scripts/quick_dependency_check.py +0 -269
  331. aiecs/tools/task_tools/search_api.py +0 -7
  332. aiecs-1.0.1.dist-info/RECORD +0 -90
  333. aiecs-1.0.1.dist-info/entry_points.txt +0 -7
  334. /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
  335. /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
  336. /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
  337. /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
  338. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/WHEEL +0 -0
  339. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/licenses/LICENSE +0 -0
  340. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,131 @@
1
+ """
2
+ Knowledge Graph Configuration
3
+
4
+ Configuration settings for knowledge graph storage and operations.
5
+ """
6
+
7
+ from enum import Enum
8
+ from pydantic import Field
9
+
10
+
11
+ class GraphStorageBackend(str, Enum):
12
+ """Available graph storage backends"""
13
+
14
+ INMEMORY = "inmemory"
15
+ SQLITE = "sqlite"
16
+ POSTGRESQL = "postgresql"
17
+
18
+
19
+ class KnowledgeGraphConfig:
20
+ """
21
+ Knowledge Graph Configuration
22
+
23
+ This class provides configuration settings for knowledge graph operations.
24
+ It integrates with AIECS Settings through environment variables.
25
+ """
26
+
27
+ # Storage backend selection
28
+ backend: GraphStorageBackend = Field(
29
+ default=GraphStorageBackend.INMEMORY,
30
+ description="Graph storage backend to use",
31
+ )
32
+
33
+ # SQLite configuration (for file-based persistence)
34
+ sqlite_db_path: str = Field(
35
+ default="./storage/knowledge_graph.db",
36
+ description="Path to SQLite database file",
37
+ )
38
+
39
+ # In-memory configuration
40
+ inmemory_max_nodes: int = Field(
41
+ default=100000,
42
+ description="Maximum number of nodes for in-memory storage",
43
+ )
44
+
45
+ # Vector search configuration
46
+ vector_dimension: int = Field(
47
+ default=1536,
48
+ description="Dimension of embedding vectors (default for OpenAI ada-002)",
49
+ )
50
+
51
+ # Query configuration
52
+ default_search_limit: int = Field(
53
+ default=10,
54
+ description="Default number of results to return in searches",
55
+ )
56
+
57
+ max_traversal_depth: int = Field(default=5, description="Maximum depth for graph traversal queries")
58
+
59
+ # Cache configuration
60
+ enable_query_cache: bool = Field(default=True, description="Enable caching of query results")
61
+
62
+ cache_ttl_seconds: int = Field(
63
+ default=300,
64
+ description="Time-to-live for cached query results (seconds)",
65
+ )
66
+
67
+ # Feature flags for new capabilities
68
+ enable_runnable_pattern: bool = Field(
69
+ default=True,
70
+ description="Enable Runnable pattern for composable graph operations",
71
+ )
72
+
73
+ enable_knowledge_fusion: bool = Field(
74
+ default=True,
75
+ description="Enable knowledge fusion for cross-document entity merging",
76
+ )
77
+
78
+ enable_reranking: bool = Field(
79
+ default=True,
80
+ description="Enable result reranking for improved search relevance",
81
+ )
82
+
83
+ enable_logical_queries: bool = Field(
84
+ default=True,
85
+ description="Enable logical query parsing for structured queries",
86
+ )
87
+
88
+ enable_structured_import: bool = Field(default=True, description="Enable structured data import (CSV/JSON)")
89
+
90
+ # Knowledge Fusion configuration
91
+ fusion_similarity_threshold: float = Field(
92
+ default=0.85,
93
+ description="Similarity threshold for entity fusion (0.0-1.0)",
94
+ )
95
+
96
+ fusion_conflict_resolution: str = Field(
97
+ default="most_complete",
98
+ description="Conflict resolution strategy: most_complete, most_recent, most_confident, longest, keep_all",
99
+ )
100
+
101
+ # Reranking configuration
102
+ reranking_default_strategy: str = Field(
103
+ default="hybrid",
104
+ description="Default reranking strategy: text, semantic, structural, hybrid",
105
+ )
106
+
107
+ reranking_top_k: int = Field(default=100, description="Top-K results to fetch before reranking")
108
+
109
+ # Schema cache configuration
110
+ enable_schema_cache: bool = Field(
111
+ default=True,
112
+ description="Enable schema caching for improved performance",
113
+ )
114
+
115
+ schema_cache_ttl_seconds: int = Field(default=3600, description="Time-to-live for cached schemas (seconds)")
116
+
117
+ # Query optimization configuration
118
+ enable_query_optimization: bool = Field(
119
+ default=True,
120
+ description="Enable query optimization for better performance",
121
+ )
122
+
123
+ query_optimization_strategy: str = Field(
124
+ default="balanced",
125
+ description="Query optimization strategy: cost, latency, balanced",
126
+ )
127
+
128
+
129
+ def get_graph_config() -> KnowledgeGraphConfig:
130
+ """Get knowledge graph configuration singleton"""
131
+ return KnowledgeGraphConfig()
@@ -0,0 +1,435 @@
1
+ """
2
+ Configuration loader for tool configurations.
3
+
4
+ This module provides a singleton configuration loader that loads and manages
5
+ tool configurations from YAML files and .env files with support for
6
+ sensitive credential separation and runtime configuration management.
7
+ """
8
+
9
+ import logging
10
+ import os
11
+ from pathlib import Path
12
+ from typing import Any, Dict, Optional, Type, Union
13
+ import yaml
14
+ from threading import Lock
15
+ from dotenv import load_dotenv
16
+ from pydantic import BaseModel, ValidationError
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class ToolConfigLoader:
22
+ """
23
+ Singleton configuration loader for tools.
24
+
25
+ Supports:
26
+ - Loading sensitive configuration from .env files (via dotenv)
27
+ - Loading runtime configuration from YAML files
28
+ - Configuration merging with precedence order
29
+ - Schema validation against tool's Pydantic Config class
30
+ - Config directory discovery (walking up directory tree)
31
+ - Thread-safe access
32
+ - Caching for performance
33
+ """
34
+
35
+ _instance: Optional["ToolConfigLoader"] = None
36
+ _lock = Lock()
37
+ _config_lock = Lock()
38
+ _initialized: bool = False
39
+
40
+ def __new__(cls):
41
+ """Ensure singleton instance"""
42
+ if cls._instance is None:
43
+ with cls._lock:
44
+ if cls._instance is None:
45
+ cls._instance = super().__new__(cls)
46
+ cls._instance._initialized = False
47
+ return cls._instance
48
+
49
+ def __init__(self) -> None:
50
+ """Initialize the configuration loader"""
51
+ if self._initialized:
52
+ return
53
+
54
+ self._config_path: Optional[Path] = None
55
+ self._cached_config_dir: Optional[Path] = None
56
+ self._initialized = True
57
+ logger.info("ToolConfigLoader initialized")
58
+
59
+ def find_config_directory(self) -> Optional[Path]:
60
+ """
61
+ Discover config/ directory in project.
62
+
63
+ Search order:
64
+ 1. Custom config path set via set_config_path()
65
+ 2. Settings tool_config_path (if available)
66
+ 3. Environment variable TOOL_CONFIG_PATH
67
+ 4. Walk up directory tree from current working directory
68
+ 5. Check aiecs/config/ directory
69
+
70
+ Returns:
71
+ Path to config directory if found, None otherwise
72
+ """
73
+ # Check if custom path was set
74
+ if self._config_path:
75
+ if self._config_path.is_dir():
76
+ return self._config_path
77
+ elif self._config_path.is_file():
78
+ return self._config_path.parent
79
+
80
+ # Check if config directory was already cached
81
+ if self._cached_config_dir and self._cached_config_dir.exists():
82
+ return self._cached_config_dir
83
+
84
+ # Check settings (if available)
85
+ try:
86
+ from aiecs.config.config import get_settings
87
+
88
+ settings = get_settings()
89
+ if hasattr(settings, "tool_config_path") and settings.tool_config_path:
90
+ path = Path(settings.tool_config_path)
91
+ if path.exists():
92
+ logger.info(f"Using tool config path from settings: {path}")
93
+ self._cached_config_dir = path if path.is_dir() else path.parent
94
+ return self._cached_config_dir
95
+ except Exception as e:
96
+ logger.debug(f"Could not load settings: {e}")
97
+
98
+ # Check environment variable
99
+ env_path = os.environ.get("TOOL_CONFIG_PATH")
100
+ if env_path:
101
+ path = Path(env_path)
102
+ if path.exists():
103
+ logger.info(f"Using tool config path from environment: {path}")
104
+ self._cached_config_dir = path if path.is_dir() else path.parent
105
+ return self._cached_config_dir
106
+
107
+ # Walk up directory tree from current working directory
108
+ current_dir = Path.cwd()
109
+ while current_dir != current_dir.parent: # Stop at root
110
+ config_dir = current_dir / "config"
111
+ if config_dir.exists() and config_dir.is_dir():
112
+ logger.info(f"Found config directory: {config_dir}")
113
+ self._cached_config_dir = config_dir
114
+ return config_dir
115
+ current_dir = current_dir.parent
116
+
117
+ # Check aiecs/config/ directory as fallback
118
+ aiecs_config_dir = Path(__file__).parent.parent / "config"
119
+ if aiecs_config_dir.exists() and aiecs_config_dir.is_dir():
120
+ logger.info(f"Using aiecs config directory: {aiecs_config_dir}")
121
+ self._cached_config_dir = aiecs_config_dir
122
+ return aiecs_config_dir
123
+
124
+ logger.debug("No config directory found")
125
+ return None
126
+
127
+ def load_env_config(self) -> Dict[str, Any]:
128
+ """
129
+ Load sensitive configuration from .env files via dotenv.
130
+
131
+ Supports multiple .env files in order:
132
+ 1. .env (base)
133
+ 2. .env.local (local overrides)
134
+ 3. .env.production (production overrides, if NODE_ENV=production)
135
+
136
+ Returns:
137
+ Dictionary of environment variables loaded from .env files
138
+ """
139
+ config_dir = self.find_config_directory()
140
+ env_vars = {}
141
+
142
+ # Determine base directory for .env files
143
+ if config_dir:
144
+ base_dir = config_dir.parent if (config_dir / "tools").exists() else config_dir
145
+ else:
146
+ base_dir = Path.cwd()
147
+
148
+ # Load .env files in order (later files override earlier ones)
149
+ env_files = [".env"]
150
+ if os.environ.get("NODE_ENV") == "production":
151
+ env_files.append(".env.production")
152
+ else:
153
+ env_files.append(".env.local")
154
+
155
+ for env_file in env_files:
156
+ env_path = base_dir / env_file
157
+ if env_path.exists():
158
+ try:
159
+ load_dotenv(env_path, override=False) # Don't override already loaded vars
160
+ logger.debug(f"Loaded environment variables from {env_path}")
161
+ except Exception as e:
162
+ logger.warning(f"Failed to load {env_path}: {e}")
163
+
164
+ # Return all environment variables (dotenv loads them into os.environ)
165
+ # We return empty dict here since dotenv modifies os.environ directly
166
+ # The actual env vars will be picked up by BaseSettings or os.getenv()
167
+ return {}
168
+
169
+ def load_yaml_config(self, tool_name: str) -> Dict[str, Any]:
170
+ """
171
+ Load runtime configuration from YAML files.
172
+
173
+ Loads from:
174
+ 1. Tool-specific: config/tools/{tool_name}.yaml
175
+ 2. Global: config/tools.yaml
176
+
177
+ Tool-specific config takes precedence over global config.
178
+
179
+ Args:
180
+ tool_name: Name of the tool (e.g., "DocumentParserTool")
181
+
182
+ Returns:
183
+ Dictionary of configuration values from YAML files
184
+ """
185
+ config_dir = self.find_config_directory()
186
+ if not config_dir:
187
+ logger.debug("No config directory found, skipping YAML config loading")
188
+ return {}
189
+
190
+ merged_config = {}
191
+
192
+ # Load global config first (lower precedence)
193
+ global_config_path = config_dir / "tools.yaml"
194
+ if global_config_path.exists():
195
+ try:
196
+ with open(global_config_path, "r", encoding="utf-8") as f:
197
+ global_data = yaml.safe_load(f)
198
+ if global_data:
199
+ # Support tool-specific sections in global config
200
+ if isinstance(global_data, dict):
201
+ # If there's a tools section, look for tool-specific config
202
+ if "tools" in global_data and isinstance(global_data["tools"], dict):
203
+ # Global defaults
204
+ merged_config.update(global_data.get("defaults", {}))
205
+ else:
206
+ # Flat global config
207
+ merged_config.update(global_data)
208
+ logger.debug(f"Loaded global config from {global_config_path}")
209
+ except yaml.YAMLError as e:
210
+ logger.warning(f"Invalid YAML in {global_config_path}: {e}. Skipping.")
211
+ except Exception as e:
212
+ logger.warning(f"Failed to load {global_config_path}: {e}. Skipping.")
213
+
214
+ # Load tool-specific config (higher precedence)
215
+ # Try multiple locations:
216
+ # 1. config/tools/{tool_name}.yaml (standard location)
217
+ # 2. config/{tool_name}.yaml (direct in config_dir, for custom paths)
218
+ tools_dir = config_dir / "tools"
219
+ search_dirs = []
220
+ if tools_dir.exists() and tools_dir.is_dir():
221
+ search_dirs.append(tools_dir)
222
+ # Also search directly in config_dir for custom path structures
223
+ search_dirs.append(config_dir)
224
+
225
+ # Try multiple naming conventions for tool config files
226
+ # 1. {tool_name}.yaml (e.g., image.yaml)
227
+ # 2. {tool_name}_tool.yaml (e.g., image_tool.yaml)
228
+ # 3. {ToolName}.yaml (e.g., ImageTool.yaml)
229
+ possible_names = [
230
+ f"{tool_name}.yaml",
231
+ f"{tool_name}_tool.yaml",
232
+ ]
233
+ # Also try with capitalized class name if tool_name is lowercase
234
+ if tool_name.islower():
235
+ class_name = tool_name.replace("_", "").title() + "Tool"
236
+ possible_names.append(f"{class_name}.yaml")
237
+
238
+ tool_config_path = None
239
+ for search_dir in search_dirs:
240
+ for name in possible_names:
241
+ candidate_path = search_dir / name
242
+ if candidate_path.exists():
243
+ tool_config_path = candidate_path
244
+ break
245
+ if tool_config_path:
246
+ break
247
+
248
+ if tool_config_path:
249
+ try:
250
+ with open(tool_config_path, "r", encoding="utf-8") as f:
251
+ tool_data = yaml.safe_load(f)
252
+ if tool_data:
253
+ # Merge tool-specific config (overrides global)
254
+ merged_config.update(tool_data)
255
+ logger.debug(f"Loaded tool-specific config from {tool_config_path}")
256
+ except yaml.YAMLError as e:
257
+ logger.warning(f"Invalid YAML in {tool_config_path}: {e}. Skipping.")
258
+ except Exception as e:
259
+ logger.warning(f"Failed to load {tool_config_path}: {e}. Skipping.")
260
+
261
+ return merged_config
262
+
263
+ def merge_config(
264
+ self,
265
+ explicit_config: Optional[Dict[str, Any]] = None,
266
+ yaml_config: Optional[Dict[str, Any]] = None,
267
+ env_config: Optional[Dict[str, Any]] = None,
268
+ defaults: Optional[Dict[str, Any]] = None,
269
+ ) -> Dict[str, Any]:
270
+ """
271
+ Merge configurations according to precedence order.
272
+
273
+ Precedence (highest to lowest):
274
+ 1. Explicit config dict
275
+ 2. YAML config
276
+ 3. Environment variables
277
+ 4. Defaults
278
+
279
+ Args:
280
+ explicit_config: Explicit configuration dict (highest priority)
281
+ yaml_config: Configuration from YAML files
282
+ env_config: Configuration from environment variables
283
+ defaults: Default configuration values (lowest priority)
284
+
285
+ Returns:
286
+ Merged configuration dictionary
287
+ """
288
+ merged = {}
289
+
290
+ # Start with defaults (lowest priority)
291
+ if defaults:
292
+ merged.update(defaults)
293
+
294
+ # Add environment variables (dotenv loads them into os.environ)
295
+ # Note: We don't merge env_config here since dotenv modifies os.environ
296
+ # Environment variables will be picked up by BaseSettings automatically
297
+
298
+ # Add YAML config
299
+ if yaml_config:
300
+ merged.update(yaml_config)
301
+
302
+ # Add explicit config (highest priority)
303
+ if explicit_config:
304
+ merged.update(explicit_config)
305
+
306
+ return merged
307
+
308
+ def validate_config(self, config_dict: Dict[str, Any], config_schema: Type[BaseModel]) -> Dict[str, Any]:
309
+ """
310
+ Validate merged config against tool's Pydantic schema.
311
+
312
+ Args:
313
+ config_dict: Configuration dictionary to validate
314
+ config_schema: Pydantic model class for validation
315
+
316
+ Returns:
317
+ Validated configuration dictionary
318
+
319
+ Raises:
320
+ ValidationError: If configuration is invalid
321
+ """
322
+ try:
323
+ # Create instance of config schema to validate
324
+ config_instance = config_schema(**config_dict)
325
+ # Convert back to dict (handles aliases, validators, etc.)
326
+ return config_instance.model_dump()
327
+ except ValidationError as e:
328
+ error_messages = []
329
+ for error in e.errors():
330
+ field = " -> ".join(str(loc) for loc in error["loc"])
331
+ error_messages.append(f"{field}: {error['msg']}")
332
+ raise ValidationError(
333
+ f"Tool configuration validation failed:\n" + "\n".join(error_messages),
334
+ e.model,
335
+ ) from e
336
+
337
+ def load_tool_config(
338
+ self,
339
+ tool_name: str,
340
+ config_schema: Optional[Type[BaseModel]] = None,
341
+ explicit_config: Optional[Dict[str, Any]] = None,
342
+ ) -> Dict[str, Any]:
343
+ """
344
+ Main entry point for loading tool configuration.
345
+
346
+ Loads, merges, and validates configuration from all sources:
347
+ 1. Explicit config dict (highest priority)
348
+ 2. YAML config files (tool-specific and global)
349
+ 3. Environment variables (via dotenv)
350
+ 4. Tool defaults (lowest priority)
351
+
352
+ Args:
353
+ tool_name: Name of the tool (e.g., "DocumentParserTool")
354
+ config_schema: Optional Pydantic model class for validation
355
+ explicit_config: Optional explicit configuration dict (overrides everything)
356
+
357
+ Returns:
358
+ Merged and validated configuration dictionary
359
+
360
+ Raises:
361
+ ValidationError: If config_schema is provided and validation fails
362
+ """
363
+ with self._config_lock:
364
+ # Load environment variables from .env files
365
+ self.load_env_config()
366
+
367
+ # Load YAML configuration
368
+ yaml_config = self.load_yaml_config(tool_name)
369
+
370
+ # Get defaults from config schema if available
371
+ defaults = {}
372
+ if config_schema:
373
+ try:
374
+ # Create instance with no args to get defaults
375
+ default_instance = config_schema()
376
+ defaults = default_instance.model_dump(exclude_unset=True)
377
+ except Exception:
378
+ # Schema might require some fields, that's okay
379
+ pass
380
+
381
+ # Merge configurations according to precedence
382
+ merged_config = self.merge_config(
383
+ explicit_config=explicit_config,
384
+ yaml_config=yaml_config,
385
+ defaults=defaults,
386
+ )
387
+
388
+ # Validate against schema if provided
389
+ if config_schema:
390
+ merged_config = self.validate_config(merged_config, config_schema)
391
+
392
+ logger.debug(f"Loaded config for {tool_name}: {len(merged_config)} keys")
393
+ return merged_config
394
+
395
+ def set_config_path(self, path: Optional[Union[str, Path]] = None) -> None:
396
+ """
397
+ Set custom config path.
398
+
399
+ Args:
400
+ path: Path to config directory or file. If None, resets to auto-discovery.
401
+ """
402
+ if path is None:
403
+ self._config_path = None
404
+ # Clear cached config directory to force re-discovery
405
+ self._cached_config_dir = None
406
+ logger.info("Reset config path to auto-discovery")
407
+ else:
408
+ self._config_path = Path(path)
409
+ # Clear cached config directory to force re-discovery
410
+ self._cached_config_dir = None
411
+ logger.info(f"Set custom config path: {self._config_path}")
412
+
413
+ def get_config_path(self) -> Optional[Path]:
414
+ """
415
+ Get current config path.
416
+
417
+ Returns:
418
+ Path to config directory if set, None otherwise
419
+ """
420
+ return self._config_path or self._cached_config_dir
421
+
422
+
423
+ # Global singleton instance
424
+ _loader = ToolConfigLoader()
425
+
426
+
427
+ def get_tool_config_loader() -> ToolConfigLoader:
428
+ """
429
+ Get the global tool configuration loader instance.
430
+
431
+ Returns:
432
+ ToolConfigLoader: Global singleton instance
433
+ """
434
+ return _loader
435
+
aiecs/core/__init__.py CHANGED
@@ -4,6 +4,7 @@ Core module for the Python middleware application.
4
4
  This module provides the core interfaces and abstractions including:
5
5
  - Execution interfaces
6
6
  - Core abstractions
7
+ - Service registry (no dependencies, safe to import anywhere)
7
8
  """
8
9
 
9
10
  # Core interfaces
@@ -12,7 +13,7 @@ from .interface.execution_interface import (
12
13
  IToolProvider,
13
14
  IToolExecutor,
14
15
  ICacheProvider,
15
- IOperationExecutor
16
+ IOperationExecutor,
16
17
  )
17
18
 
18
19
  from .interface.storage_interface import (
@@ -21,23 +22,38 @@ from .interface.storage_interface import (
21
22
  ICheckpointStorage,
22
23
  ITaskContextStorage,
23
24
  IStorageBackend,
24
- ICheckpointerBackend
25
+ ICheckpointerBackend,
26
+ )
27
+
28
+ # Service registry (zero dependencies, safe for module-level imports)
29
+ from .registry import (
30
+ AI_SERVICE_REGISTRY,
31
+ register_ai_service,
32
+ get_ai_service,
33
+ list_registered_services,
34
+ clear_registry,
25
35
  )
26
36
 
27
37
  __all__ = [
28
38
  # Execution interfaces
29
- 'ExecutionInterface',
30
- 'IToolProvider',
31
- 'IToolExecutor',
32
- 'ICacheProvider',
33
- 'IOperationExecutor',
39
+ "ExecutionInterface",
40
+ "IToolProvider",
41
+ "IToolExecutor",
42
+ "ICacheProvider",
43
+ "IOperationExecutor",
34
44
  # Storage interfaces
35
- 'ISessionStorage',
36
- 'IConversationStorage',
37
- 'ICheckpointStorage',
38
- 'ITaskContextStorage',
39
- 'IStorageBackend',
40
- 'ICheckpointerBackend',
45
+ "ISessionStorage",
46
+ "IConversationStorage",
47
+ "ICheckpointStorage",
48
+ "ITaskContextStorage",
49
+ "IStorageBackend",
50
+ "ICheckpointerBackend",
51
+ # Service registry
52
+ "AI_SERVICE_REGISTRY",
53
+ "register_ai_service",
54
+ "get_ai_service",
55
+ "list_registered_services",
56
+ "clear_registry",
41
57
  ]
42
58
 
43
59
  # Version information
@@ -5,7 +5,7 @@ from .execution_interface import (
5
5
  IToolProvider,
6
6
  IToolExecutor,
7
7
  ICacheProvider,
8
- IOperationExecutor
8
+ IOperationExecutor,
9
9
  )
10
10
 
11
11
  from .storage_interface import (
@@ -14,7 +14,7 @@ from .storage_interface import (
14
14
  ICheckpointStorage,
15
15
  ITaskContextStorage,
16
16
  IStorageBackend,
17
- ICheckpointerBackend
17
+ ICheckpointerBackend,
18
18
  )
19
19
 
20
20
  __all__ = [