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
@@ -1,48 +1,54 @@
1
1
  import os
2
2
  import asyncio
3
3
  import functools
4
- import hashlib
5
4
  import inspect
6
- import json
7
5
  import logging
8
6
  import threading
9
7
  import time
10
8
  from concurrent.futures import ThreadPoolExecutor
11
- from typing import Any, Callable, Dict, List, Optional, Type, Union, get_type_hints
9
+ from typing import Any, Callable, Dict, List, Optional, Type, Union
12
10
  from contextlib import contextmanager
13
11
 
14
- from cachetools import LRUCache
15
12
  from aiecs.utils.execution_utils import ExecutionUtils
13
+ from aiecs.utils.cache_provider import ICacheProvider, LRUCacheProvider
16
14
  import re
17
- from pydantic import BaseModel, ValidationError, ConfigDict
15
+ from pydantic import BaseModel, ValidationError
16
+ from pydantic_settings import BaseSettings, SettingsConfigDict
18
17
 
19
18
  logger = logging.getLogger(__name__)
20
19
 
21
20
  # Base exception hierarchy
21
+
22
+
22
23
  class ToolExecutionError(Exception):
23
24
  """Base exception for all tool execution errors."""
24
- pass
25
+
25
26
 
26
27
  class InputValidationError(ToolExecutionError):
27
28
  """Error in validating input parameters."""
28
- pass
29
+
29
30
 
30
31
  class SecurityError(ToolExecutionError):
31
32
  """Security-related error."""
32
- pass
33
+
33
34
 
34
35
  class OperationError(ToolExecutionError):
35
36
  """Error during operation execution."""
36
- pass
37
+
37
38
 
38
39
  class TimeoutError(ToolExecutionError):
39
40
  """Operation timed out."""
40
- pass
41
+
41
42
 
42
43
  # Configuration for the executor
43
- class ExecutorConfig(BaseModel):
44
+
45
+
46
+ class ExecutorConfig(BaseSettings):
44
47
  """
45
48
  Configuration for the ToolExecutor.
49
+
50
+ Automatically reads from environment variables with TOOL_EXECUTOR_ prefix.
51
+ Example: TOOL_EXECUTOR_MAX_WORKERS -> max_workers
46
52
 
47
53
  Attributes:
48
54
  enable_cache (bool): Enable caching of operation results.
@@ -58,7 +64,14 @@ class ExecutorConfig(BaseModel):
58
64
  retry_attempts (int): Number of retry attempts for transient errors.
59
65
  retry_backoff (float): Backoff factor for retries.
60
66
  timeout (int): Timeout for operations in seconds.
67
+ enable_dual_cache (bool): Enable dual-layer caching (L1: LRU + L2: Redis).
68
+ enable_redis_cache (bool): Enable Redis as L2 cache (requires enable_dual_cache=True).
69
+ redis_cache_ttl (int): Redis cache TTL in seconds (for L2 cache).
70
+ l1_cache_ttl (int): L1 cache TTL in seconds (for dual-layer cache).
61
71
  """
72
+
73
+ model_config = SettingsConfigDict(env_prefix="TOOL_EXECUTOR_")
74
+
62
75
  enable_cache: bool = True
63
76
  cache_size: int = 100
64
77
  cache_ttl: int = 3600
@@ -73,14 +86,22 @@ class ExecutorConfig(BaseModel):
73
86
  retry_backoff: float = 1.0
74
87
  timeout: int = 30
75
88
 
76
- model_config = ConfigDict(env_prefix="TOOL_EXECUTOR_")
89
+ # Dual-layer cache configuration
90
+ enable_dual_cache: bool = False
91
+ enable_redis_cache: bool = False
92
+ redis_cache_ttl: int = 86400 # 1 day
93
+ l1_cache_ttl: int = 300 # 5 minutes
94
+
77
95
 
78
96
  # Metrics counter
79
- class ExecutorMetrics:
97
+
98
+
99
+ class ToolExecutorStats:
80
100
  """
81
- Tracks executor performance metrics.
101
+ Tracks tool executor performance statistics.
82
102
  """
83
- def __init__(self):
103
+
104
+ def __init__(self) -> None:
84
105
  self.requests: int = 0
85
106
  self.failures: int = 0
86
107
  self.cache_hits: int = 0
@@ -98,13 +119,16 @@ class ExecutorMetrics:
98
119
 
99
120
  def to_dict(self) -> Dict[str, Any]:
100
121
  return {
101
- 'requests': self.requests,
102
- 'failures': self.failures,
103
- 'cache_hits': self.cache_hits,
104
- 'avg_processing_time': sum(self.processing_times) / len(self.processing_times) if self.processing_times else 0.0
122
+ "requests": self.requests,
123
+ "failures": self.failures,
124
+ "cache_hits": self.cache_hits,
125
+ "avg_processing_time": (sum(self.processing_times) / len(self.processing_times) if self.processing_times else 0.0),
105
126
  }
106
127
 
128
+
107
129
  # Decorators for tool methods
130
+
131
+
108
132
  def validate_input(schema_class: Type[BaseModel]) -> Callable:
109
133
  """
110
134
  Decorator to validate input using a Pydantic schema.
@@ -118,6 +142,7 @@ def validate_input(schema_class: Type[BaseModel]) -> Callable:
118
142
  Raises:
119
143
  InputValidationError: If input validation fails.
120
144
  """
145
+
121
146
  def decorator(func: Callable) -> Callable:
122
147
  @functools.wraps(func)
123
148
  def wrapper(self, *args, **kwargs):
@@ -127,9 +152,12 @@ def validate_input(schema_class: Type[BaseModel]) -> Callable:
127
152
  return func(self, **validated_kwargs)
128
153
  except ValidationError as e:
129
154
  raise InputValidationError(f"Invalid input parameters: {e}")
155
+
130
156
  return wrapper
157
+
131
158
  return decorator
132
159
 
160
+
133
161
  def cache_result(ttl: Optional[int] = None) -> Callable:
134
162
  """
135
163
  Decorator to cache function results with optional TTL.
@@ -140,10 +168,11 @@ def cache_result(ttl: Optional[int] = None) -> Callable:
140
168
  Returns:
141
169
  Callable: Decorated function with caching.
142
170
  """
171
+
143
172
  def decorator(func: Callable) -> Callable:
144
173
  @functools.wraps(func)
145
174
  def wrapper(self, *args, **kwargs):
146
- if not hasattr(self, '_executor') or not self._executor.config.enable_cache:
175
+ if not hasattr(self, "_executor") or not self._executor.config.enable_cache:
147
176
  return func(self, *args, **kwargs)
148
177
  cache_key = self._executor._get_cache_key(func.__name__, args, kwargs)
149
178
  result = self._executor._get_from_cache(cache_key)
@@ -154,9 +183,100 @@ def cache_result(ttl: Optional[int] = None) -> Callable:
154
183
  result = func(self, *args, **kwargs)
155
184
  self._executor._add_to_cache(cache_key, result, ttl)
156
185
  return result
186
+
187
+ return wrapper
188
+
189
+ return decorator
190
+
191
+
192
+ def cache_result_with_strategy(
193
+ ttl_strategy: Optional[Union[int, Callable]] = None,
194
+ ) -> Callable:
195
+ """
196
+ Decorator to cache function results with flexible TTL strategy.
197
+
198
+ Supports multiple TTL strategy types:
199
+ 1. Fixed TTL (int): Static TTL in seconds
200
+ 2. Callable strategy: Function that calculates TTL based on result and context
201
+ 3. None: Use default TTL from executor config
202
+
203
+ Args:
204
+ ttl_strategy: TTL strategy, can be:
205
+ - int: Fixed TTL in seconds
206
+ - Callable[[Any, tuple, dict], int]: Function(result, args, kwargs) -> ttl_seconds
207
+ - None: Use default TTL
208
+
209
+ Returns:
210
+ Callable: Decorated function with intelligent caching.
211
+
212
+ Example:
213
+ # Fixed TTL
214
+ @cache_result_with_strategy(ttl_strategy=3600)
215
+ def simple_operation(self, data):
216
+ return process(data)
217
+
218
+ # Dynamic TTL based on result
219
+ def calculate_ttl(result, args, kwargs):
220
+ if result.get('type') == 'static':
221
+ return 86400 # 1 day
222
+ return 3600 # 1 hour
223
+
224
+ @cache_result_with_strategy(ttl_strategy=calculate_ttl)
225
+ def smart_operation(self, query):
226
+ return search(query)
227
+ """
228
+
229
+ def decorator(func: Callable) -> Callable:
230
+ @functools.wraps(func)
231
+ def wrapper(self, *args, **kwargs):
232
+ if not hasattr(self, "_executor") or not self._executor.config.enable_cache:
233
+ return func(self, *args, **kwargs)
234
+
235
+ # Generate cache key
236
+ cache_key = self._executor._get_cache_key(func.__name__, args, kwargs)
237
+
238
+ # Check cache
239
+ cached = self._executor._get_from_cache(cache_key)
240
+ if cached is not None:
241
+ logger.debug(f"Cache hit for {func.__name__}")
242
+ self._executor._metrics.record_cache_hit()
243
+ return cached
244
+
245
+ # Execute function
246
+ result = func(self, *args, **kwargs)
247
+
248
+ # Calculate TTL based on strategy
249
+ # Support both regular callables and lambdas that need self
250
+ if callable(ttl_strategy):
251
+ try:
252
+ # Try calling with self first (for lambda self, result,
253
+ # args, kwargs)
254
+ import inspect
255
+
256
+ sig = inspect.signature(ttl_strategy)
257
+ if len(sig.parameters) == 4: # self, result, args, kwargs
258
+ ttl = ttl_strategy(self, result, args, kwargs)
259
+ else: # result, args, kwargs
260
+ ttl = ttl_strategy(result, args, kwargs)
261
+
262
+ if not isinstance(ttl, int) or ttl < 0:
263
+ logger.warning(f"TTL strategy returned invalid value: {ttl}. " f"Expected positive integer. Using default TTL.")
264
+ ttl = None
265
+ except Exception as e:
266
+ logger.error(f"Error calculating TTL from strategy: {e}. Using default TTL.")
267
+ ttl = None
268
+ else:
269
+ ttl = self._executor._calculate_ttl_from_strategy(ttl_strategy, result, args, kwargs)
270
+
271
+ # Cache with calculated TTL
272
+ self._executor._add_to_cache(cache_key, result, ttl)
273
+ return result
274
+
157
275
  return wrapper
276
+
158
277
  return decorator
159
278
 
279
+
160
280
  def run_in_executor(func: Callable) -> Callable:
161
281
  """
162
282
  Decorator to run a synchronous function in the thread pool executor.
@@ -167,17 +287,20 @@ def run_in_executor(func: Callable) -> Callable:
167
287
  Returns:
168
288
  Callable: Async wrapper for the function.
169
289
  """
290
+
170
291
  @functools.wraps(func)
171
292
  async def wrapper(self, *args, **kwargs):
172
- if not hasattr(self, '_executor'):
293
+ if not hasattr(self, "_executor"):
173
294
  return await func(self, *args, **kwargs)
174
295
  loop = asyncio.get_event_loop()
175
296
  return await loop.run_in_executor(
176
297
  self._executor._thread_pool,
177
- functools.partial(func, self, *args, **kwargs)
298
+ functools.partial(func, self, *args, **kwargs),
178
299
  )
300
+
179
301
  return wrapper
180
302
 
303
+
181
304
  def measure_execution_time(func: Callable) -> Callable:
182
305
  """
183
306
  Decorator to measure and log execution time.
@@ -188,9 +311,10 @@ def measure_execution_time(func: Callable) -> Callable:
188
311
  Returns:
189
312
  Callable: Decorated function with timing.
190
313
  """
314
+
191
315
  @functools.wraps(func)
192
316
  def wrapper(self, *args, **kwargs):
193
- if not hasattr(self, '_executor') or not self._executor.config.log_execution_time:
317
+ if not hasattr(self, "_executor") or not self._executor.config.log_execution_time:
194
318
  return func(self, *args, **kwargs)
195
319
  start_time = time.time()
196
320
  try:
@@ -202,8 +326,10 @@ def measure_execution_time(func: Callable) -> Callable:
202
326
  execution_time = time.time() - start_time
203
327
  logger.error(f"{func.__name__} failed after {execution_time:.4f} seconds: {e}")
204
328
  raise
329
+
205
330
  return wrapper
206
331
 
332
+
207
333
  def sanitize_input(func: Callable) -> Callable:
208
334
  """
209
335
  Decorator to sanitize input parameters for security.
@@ -214,18 +340,21 @@ def sanitize_input(func: Callable) -> Callable:
214
340
  Returns:
215
341
  Callable: Decorated function with sanitized inputs.
216
342
  """
343
+
217
344
  @functools.wraps(func)
218
345
  def wrapper(self, *args, **kwargs):
219
- if not hasattr(self, '_executor') or not self._executor.config.enable_security_checks:
346
+ if not hasattr(self, "_executor") or not self._executor.config.enable_security_checks:
220
347
  return func(self, *args, **kwargs)
221
348
  sanitized_kwargs = {}
222
349
  for k, v in kwargs.items():
223
- if isinstance(v, str) and re.search(r'(\bSELECT\b|\bINSERT\b|--|;|/\*)', v, re.IGNORECASE):
350
+ if isinstance(v, str) and re.search(r"(\bSELECT\b|\bINSERT\b|--|;|/\*)", v, re.IGNORECASE):
224
351
  raise SecurityError(f"Input parameter '{k}' contains potentially malicious content")
225
352
  sanitized_kwargs[k] = v
226
353
  return func(self, *args, **sanitized_kwargs)
354
+
227
355
  return wrapper
228
356
 
357
+
229
358
  class ToolExecutor:
230
359
  """
231
360
  Centralized executor for tool operations, handling:
@@ -240,12 +369,18 @@ class ToolExecutor:
240
369
  executor = ToolExecutor(config={'max_workers': 8})
241
370
  result = executor.execute(tool_instance, 'operation_name', param1='value')
242
371
  """
243
- def __init__(self, config: Optional[Dict[str, Any]] = None):
372
+
373
+ def __init__(
374
+ self,
375
+ config: Optional[Dict[str, Any]] = None,
376
+ cache_provider: Optional[ICacheProvider] = None,
377
+ ):
244
378
  """
245
379
  Initialize the executor with optional configuration.
246
380
 
247
381
  Args:
248
382
  config (Dict[str, Any], optional): Configuration overrides for ExecutorConfig.
383
+ cache_provider (ICacheProvider, optional): Custom cache provider. If None, uses default based on config.
249
384
 
250
385
  Raises:
251
386
  ValueError: If config is invalid.
@@ -253,18 +388,81 @@ class ToolExecutor:
253
388
  self.config = ExecutorConfig(**(config or {}))
254
389
  logging.basicConfig(
255
390
  level=getattr(logging, self.config.log_level),
256
- format='%(asctime)s %(levelname)s %(name)s: %(message)s'
391
+ format="%(asctime)s %(levelname)s %(name)s: %(message)s",
257
392
  )
258
393
  self._thread_pool = ThreadPoolExecutor(max_workers=max(os.cpu_count() or 4, self.config.max_workers))
259
394
  self._locks: Dict[str, threading.Lock] = {}
260
- self._metrics = ExecutorMetrics()
395
+ self._metrics = ToolExecutorStats()
261
396
  self.execution_utils = ExecutionUtils(
262
397
  cache_size=self.config.cache_size,
263
398
  cache_ttl=self.config.cache_ttl,
264
399
  retry_attempts=self.config.retry_attempts,
265
- retry_backoff=self.config.retry_backoff
400
+ retry_backoff=self.config.retry_backoff,
266
401
  )
267
402
 
403
+ # Support pluggable cache provider
404
+ if cache_provider is not None:
405
+ # User provided custom cache provider
406
+ self.cache_provider = cache_provider
407
+ logger.info(f"Using custom cache provider: {cache_provider.__class__.__name__}")
408
+ elif self.config.enable_dual_cache and self.config.enable_redis_cache:
409
+ # Enable dual-layer cache (L1: LRU + L2: Redis)
410
+ self.cache_provider = self._initialize_dual_cache()
411
+ else:
412
+ # Default: use LRUCacheProvider wrapping ExecutionUtils
413
+ self.cache_provider = LRUCacheProvider(self.execution_utils)
414
+ logger.debug("Using default LRUCacheProvider")
415
+
416
+ def _initialize_dual_cache(self) -> ICacheProvider:
417
+ """
418
+ Initialize dual-layer cache (L1: LRU + L2: Redis).
419
+
420
+ Returns:
421
+ DualLayerCacheProvider instance or fallback to LRUCacheProvider
422
+ """
423
+ try:
424
+ from aiecs.utils.cache_provider import (
425
+ DualLayerCacheProvider,
426
+ RedisCacheProvider,
427
+ )
428
+
429
+ # Create L1 cache (LRU)
430
+ l1_cache = LRUCacheProvider(self.execution_utils)
431
+
432
+ # Create L2 cache (Redis) - this requires async initialization
433
+ # We'll use a lazy initialization approach
434
+ try:
435
+ # Try to get global Redis client synchronously
436
+ # Note: This assumes Redis client is already initialized
437
+ from aiecs.infrastructure.persistence import redis_client
438
+
439
+ if redis_client is not None:
440
+ l2_cache = RedisCacheProvider(
441
+ redis_client,
442
+ prefix="tool_executor:",
443
+ default_ttl=self.config.redis_cache_ttl,
444
+ )
445
+
446
+ dual_cache = DualLayerCacheProvider(
447
+ l1_provider=l1_cache,
448
+ l2_provider=l2_cache,
449
+ l1_ttl=self.config.l1_cache_ttl,
450
+ )
451
+
452
+ logger.info("Dual-layer cache enabled (L1: LRU + L2: Redis)")
453
+ return dual_cache
454
+ else:
455
+ logger.warning("Redis client not initialized, falling back to LRU cache")
456
+ return l1_cache
457
+
458
+ except ImportError:
459
+ logger.warning("Redis client not available, falling back to LRU cache")
460
+ return l1_cache
461
+
462
+ except Exception as e:
463
+ logger.warning(f"Failed to initialize dual-layer cache: {e}, falling back to LRU")
464
+ return LRUCacheProvider(self.execution_utils)
465
+
268
466
  def _get_cache_key(self, func_name: str, args: tuple, kwargs: Dict[str, Any]) -> str:
269
467
  """
270
468
  Generate a context-aware cache key from function name, user ID, task ID, and arguments.
@@ -281,9 +479,64 @@ class ToolExecutor:
281
479
  task_id = kwargs.get("task_id", "none")
282
480
  return self.execution_utils.generate_cache_key(func_name, user_id, task_id, args, kwargs)
283
481
 
482
+ def _calculate_ttl_from_strategy(
483
+ self,
484
+ ttl_strategy: Optional[Union[int, Callable]],
485
+ result: Any,
486
+ args: tuple,
487
+ kwargs: Dict[str, Any],
488
+ ) -> Optional[int]:
489
+ """
490
+ Calculate TTL based on the provided strategy.
491
+
492
+ Supports multiple strategy types:
493
+ 1. None: Use default TTL from config
494
+ 2. int: Fixed TTL in seconds
495
+ 3. Callable: Dynamic TTL calculation function
496
+
497
+ Args:
498
+ ttl_strategy: TTL strategy (None, int, or Callable)
499
+ result: Function execution result
500
+ args: Function positional arguments
501
+ kwargs: Function keyword arguments
502
+
503
+ Returns:
504
+ Optional[int]: Calculated TTL in seconds, or None for default
505
+
506
+ Example:
507
+ # Strategy function signature
508
+ def my_ttl_strategy(result: Any, args: tuple, kwargs: dict) -> int:
509
+ if result.get('type') == 'permanent':
510
+ return 86400 * 30 # 30 days
511
+ return 3600 # 1 hour
512
+ """
513
+ # Case 1: No strategy - use default
514
+ if ttl_strategy is None:
515
+ return None
516
+
517
+ # Case 2: Fixed TTL (integer)
518
+ if isinstance(ttl_strategy, int):
519
+ return ttl_strategy
520
+
521
+ # Case 3: Callable strategy - dynamic calculation
522
+ if callable(ttl_strategy):
523
+ try:
524
+ calculated_ttl = ttl_strategy(result, args, kwargs)
525
+ if not isinstance(calculated_ttl, int) or calculated_ttl < 0:
526
+ logger.warning(f"TTL strategy returned invalid value: {calculated_ttl}. " f"Expected positive integer. Using default TTL.")
527
+ return None
528
+ return calculated_ttl
529
+ except Exception as e:
530
+ logger.error(f"Error calculating TTL from strategy: {e}. Using default TTL.")
531
+ return None
532
+
533
+ # Invalid strategy type
534
+ logger.warning(f"Invalid TTL strategy type: {type(ttl_strategy)}. " f"Expected None, int, or Callable. Using default TTL.")
535
+ return None
536
+
284
537
  def _get_from_cache(self, cache_key: str) -> Optional[Any]:
285
538
  """
286
- Get a result from cache if it exists and is not expired.
539
+ Get a result from cache if it exists and is not expired (synchronous).
287
540
 
288
541
  Args:
289
542
  cache_key (str): Cache key.
@@ -293,11 +546,11 @@ class ToolExecutor:
293
546
  """
294
547
  if not self.config.enable_cache:
295
548
  return None
296
- return self.execution_utils.get_from_cache(cache_key)
549
+ return self.cache_provider.get(cache_key)
297
550
 
298
551
  def _add_to_cache(self, cache_key: str, result: Any, ttl: Optional[int] = None) -> None:
299
552
  """
300
- Add a result to the cache with optional TTL.
553
+ Add a result to the cache with optional TTL (synchronous).
301
554
 
302
555
  Args:
303
556
  cache_key (str): Cache key.
@@ -306,7 +559,46 @@ class ToolExecutor:
306
559
  """
307
560
  if not self.config.enable_cache:
308
561
  return
309
- self.execution_utils.add_to_cache(cache_key, result, ttl)
562
+ self.cache_provider.set(cache_key, result, ttl)
563
+
564
+ async def _get_from_cache_async(self, cache_key: str) -> Optional[Any]:
565
+ """
566
+ Get a result from cache if it exists and is not expired (asynchronous).
567
+
568
+ Args:
569
+ cache_key (str): Cache key.
570
+
571
+ Returns:
572
+ Optional[Any]: Cached result or None.
573
+ """
574
+ if not self.config.enable_cache:
575
+ return None
576
+
577
+ # Use async interface if available
578
+ if hasattr(self.cache_provider, "get_async"):
579
+ return await self.cache_provider.get_async(cache_key)
580
+ else:
581
+ # Fallback to sync interface
582
+ return self.cache_provider.get(cache_key)
583
+
584
+ async def _add_to_cache_async(self, cache_key: str, result: Any, ttl: Optional[int] = None) -> None:
585
+ """
586
+ Add a result to the cache with optional TTL (asynchronous).
587
+
588
+ Args:
589
+ cache_key (str): Cache key.
590
+ result (Any): Result to cache.
591
+ ttl (Optional[int]): Time-to-live in seconds.
592
+ """
593
+ if not self.config.enable_cache:
594
+ return
595
+
596
+ # Use async interface if available
597
+ if hasattr(self.cache_provider, "set_async"):
598
+ await self.cache_provider.set_async(cache_key, result, ttl)
599
+ else:
600
+ # Fallback to sync interface
601
+ self.cache_provider.set(cache_key, result, ttl)
310
602
 
311
603
  def get_lock(self, resource_id: str) -> threading.Lock:
312
604
  """
@@ -379,8 +671,8 @@ class ToolExecutor:
379
671
  SecurityError: If inputs contain malicious content.
380
672
  """
381
673
  method = getattr(tool_instance, operation, None)
382
- if not method or not callable(method) or operation.startswith('_'):
383
- available_ops = [m for m in dir(tool_instance) if not m.startswith('_') and callable(getattr(tool_instance, m))]
674
+ if not method or not callable(method) or operation.startswith("_"):
675
+ available_ops = [m for m in dir(tool_instance) if not m.startswith("_") and callable(getattr(tool_instance, m))]
384
676
  raise ToolExecutionError(f"Unsupported operation: {operation}. Available operations: {', '.join(available_ops)}")
385
677
  logger.info(f"Executing {tool_instance.__class__.__name__}.{operation} with params: {kwargs}")
386
678
  start_time = time.time()
@@ -388,7 +680,7 @@ class ToolExecutor:
388
680
  # Sanitize inputs
389
681
  if self.config.enable_security_checks:
390
682
  for k, v in kwargs.items():
391
- if isinstance(v, str) and re.search(r'(\bSELECT\b|\bINSERT\b|--|;|/\*)', v, re.IGNORECASE):
683
+ if isinstance(v, str) and re.search(r"(\bSELECT\b|\bINSERT\b|--|;|/\*)", v, re.IGNORECASE):
392
684
  raise SecurityError(f"Input parameter '{k}' contains potentially malicious content")
393
685
  # Use cache if enabled
394
686
  if self.config.enable_cache:
@@ -410,7 +702,10 @@ class ToolExecutor:
410
702
  return result
411
703
  except Exception as e:
412
704
  self._metrics.record_failure()
413
- logger.error(f"Error executing {tool_instance.__class__.__name__}.{operation}: {str(e)}", exc_info=True)
705
+ logger.error(
706
+ f"Error executing {tool_instance.__class__.__name__}.{operation}: {str(e)}",
707
+ exc_info=True,
708
+ )
414
709
  raise OperationError(f"Error executing {operation}: {str(e)}") from e
415
710
 
416
711
  async def execute_async(self, tool_instance: Any, operation: str, **kwargs) -> Any:
@@ -431,8 +726,8 @@ class ToolExecutor:
431
726
  SecurityError: If inputs contain malicious content.
432
727
  """
433
728
  method = getattr(tool_instance, operation, None)
434
- if not method or not callable(method) or operation.startswith('_'):
435
- available_ops = [m for m in dir(tool_instance) if not m.startswith('_') and callable(getattr(tool_instance, m))]
729
+ if not method or not callable(method) or operation.startswith("_"):
730
+ available_ops = [m for m in dir(tool_instance) if not m.startswith("_") and callable(getattr(tool_instance, m))]
436
731
  raise ToolExecutionError(f"Unsupported operation: {operation}. Available operations: {', '.join(available_ops)}")
437
732
  is_async = inspect.iscoroutinefunction(method)
438
733
  logger.info(f"Executing async {tool_instance.__class__.__name__}.{operation} with params: {kwargs}")
@@ -441,15 +736,15 @@ class ToolExecutor:
441
736
  # Sanitize inputs
442
737
  if self.config.enable_security_checks:
443
738
  for k, v in kwargs.items():
444
- if isinstance(v, str) and re.search(r'(\bSELECT\b|\bINSERT\b|--|;|/\*)', v, re.IGNORECASE):
739
+ if isinstance(v, str) and re.search(r"(\bSELECT\b|\bINSERT\b|--|;|/\*)", v, re.IGNORECASE):
445
740
  raise SecurityError(f"Input parameter '{k}' contains potentially malicious content")
446
- # Use cache if enabled
741
+ # Use cache if enabled (async)
447
742
  if self.config.enable_cache:
448
743
  cache_key = self._get_cache_key(operation, (), kwargs)
449
- cached_result = self._get_from_cache(cache_key)
744
+ cached_result = await self._get_from_cache_async(cache_key)
450
745
  if cached_result is not None:
451
746
  self._metrics.record_cache_hit()
452
- logger.debug(f"Cache hit for {operation}")
747
+ logger.debug(f"Cache hit for {operation} (async)")
453
748
  return cached_result
454
749
 
455
750
  async def _execute():
@@ -457,18 +752,22 @@ class ToolExecutor:
457
752
  return await method(**kwargs)
458
753
  loop = asyncio.get_event_loop()
459
754
  return await loop.run_in_executor(self._thread_pool, functools.partial(method, **kwargs))
755
+
460
756
  result = await self._retry_operation(_execute)
461
757
  self._metrics.record_request(time.time() - start_time)
462
758
  if self.config.log_execution_time:
463
759
  logger.info(f"{tool_instance.__class__.__name__}.{operation} executed in {time.time() - start_time:.4f} seconds")
464
760
 
465
- # Cache result if enabled
761
+ # Cache result if enabled (async)
466
762
  if self.config.enable_cache:
467
- self._add_to_cache(cache_key, result)
763
+ await self._add_to_cache_async(cache_key, result)
468
764
  return result
469
765
  except Exception as e:
470
766
  self._metrics.record_failure()
471
- logger.error(f"Error executing {tool_instance.__class__.__name__}.{operation}: {str(e)}", exc_info=True)
767
+ logger.error(
768
+ f"Error executing {tool_instance.__class__.__name__}.{operation}: {str(e)}",
769
+ exc_info=True,
770
+ )
472
771
  raise OperationError(f"Error executing {operation}: {str(e)}") from e
473
772
 
474
773
  async def execute_batch(self, tool_instance: Any, operations: List[Dict[str, Any]]) -> List[Any]:
@@ -488,8 +787,8 @@ class ToolExecutor:
488
787
  """
489
788
  tasks = []
490
789
  for op_data in operations:
491
- op = op_data.get('op')
492
- kwargs = op_data.get('kwargs', {})
790
+ op = op_data.get("op")
791
+ kwargs = op_data.get("kwargs", {})
493
792
  if not op:
494
793
  raise InputValidationError("Operation name missing in batch request")
495
794
  tasks.append(self.execute_async(tool_instance, op, **kwargs))
@@ -499,20 +798,33 @@ class ToolExecutor:
499
798
  logger.error(f"Batch operation {operations[i]['op']} failed: {result}")
500
799
  return results
501
800
 
502
- # Singleton executor instance
801
+
802
+ # Singleton executor instance (for backward compatibility)
503
803
  _default_executor = None
504
804
 
805
+
505
806
  def get_executor(config: Optional[Dict[str, Any]] = None) -> ToolExecutor:
506
807
  """
507
- Get or create the default executor instance.
808
+ Get or create executor instance.
809
+
810
+ If config is provided, creates a new executor with that config.
811
+ If config is None, returns the default singleton executor.
508
812
 
509
813
  Args:
510
814
  config (Dict[str, Any], optional): Configuration overrides.
815
+ If provided, creates a new executor instance.
816
+ If None, returns the default singleton.
511
817
 
512
818
  Returns:
513
- ToolExecutor: Singleton executor instance.
819
+ ToolExecutor: Executor instance.
514
820
  """
515
821
  global _default_executor
822
+
823
+ # If config is provided, create a new executor with that config
824
+ if config is not None:
825
+ return ToolExecutor(config)
826
+
827
+ # Otherwise, return the default singleton
516
828
  if _default_executor is None:
517
- _default_executor = ToolExecutor(config)
829
+ _default_executor = ToolExecutor()
518
830
  return _default_executor