aiecs 1.0.1__py3-none-any.whl → 1.7.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aiecs might be problematic. Click here for more details.

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 +399 -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 +3870 -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 +1435 -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 +884 -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 +364 -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 +224 -36
  195. aiecs/llm/client_resolver.py +155 -0
  196. aiecs/llm/clients/__init__.py +38 -0
  197. aiecs/llm/clients/base_client.py +324 -0
  198. aiecs/llm/clients/google_function_calling_mixin.py +457 -0
  199. aiecs/llm/clients/googleai_client.py +241 -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 +897 -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 +1323 -0
  269. aiecs/tools/docs/document_layout_tool.py +1160 -0
  270. aiecs/tools/docs/document_parser_tool.py +1011 -0
  271. aiecs/tools/docs/document_writer_tool.py +1829 -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 +175 -131
  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.6.dist-info}/METADATA +52 -15
  321. aiecs-1.7.6.dist-info/RECORD +337 -0
  322. aiecs-1.7.6.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.6.dist-info}/WHEEL +0 -0
  339. {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/licenses/LICENSE +0 -0
  340. {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/top_level.txt +0 -0
aiecs/tools/base_tool.py CHANGED
@@ -1,27 +1,22 @@
1
- import asyncio
2
1
  import inspect
3
2
  import logging
4
- from typing import Any, Dict, List, Optional, Type, Union
3
+ from typing import Any, Dict, List, Optional, Type
5
4
 
6
5
  from pydantic import BaseModel, ValidationError
7
6
  import re
8
7
 
9
8
  from aiecs.tools.tool_executor import (
10
- ToolExecutor,
11
- ToolExecutionError,
12
9
  InputValidationError,
13
- OperationError,
14
10
  SecurityError,
15
11
  get_executor,
16
- validate_input,
17
- cache_result,
18
- run_in_executor,
19
- measure_execution_time,
20
- sanitize_input
12
+ ExecutorConfig,
21
13
  )
14
+ from aiecs.config.tool_config import get_tool_config_loader
15
+ from aiecs.tools.schema_generator import generate_schema_from_method
22
16
 
23
17
  logger = logging.getLogger(__name__)
24
18
 
19
+
25
20
  class BaseTool:
26
21
  """
27
22
  Base class for all tools, providing common functionality:
@@ -49,26 +44,156 @@ class BaseTool:
49
44
  # Implementation
50
45
  pass
51
46
  """
52
- def __init__(self, config: Optional[Dict[str, Any]] = None):
47
+
48
+ def __init__(self, config: Optional[Dict[str, Any]] = None, tool_name: Optional[str] = None):
53
49
  """
54
50
  Initialize the tool with optional configuration.
55
51
 
52
+ Configuration is automatically loaded from:
53
+ 1. Explicit config dict (highest priority)
54
+ 2. YAML config files (config/tools/{tool_name}.yaml or config/tools.yaml)
55
+ 3. Environment variables (via dotenv from .env files)
56
+ 4. Tool defaults (lowest priority)
57
+
56
58
  Args:
57
- config (Dict[str, Any], optional): Tool-specific configuration.
59
+ config (Dict[str, Any], optional): Tool-specific configuration that overrides
60
+ all other sources. If None, configuration is loaded automatically.
61
+ tool_name (str, optional): Registered tool name. If None, uses class name.
58
62
 
59
63
  Raises:
60
64
  ValueError: If config is invalid.
65
+ ValidationError: If config validation fails (when Config class exists).
61
66
  """
62
- self._executor = get_executor(config)
63
- self._config = config or {}
67
+ # Detect Config class if it exists
68
+ config_class = self._detect_config_class()
69
+
70
+ # Determine tool name (for config file discovery)
71
+ if tool_name is None:
72
+ tool_name = self.__class__.__name__
73
+
74
+ # Load configuration using ToolConfigLoader
75
+ if config_class:
76
+ # Tool has Config class - use loader to load and validate config
77
+ loader = get_tool_config_loader()
78
+ try:
79
+ loaded_config = loader.load_tool_config(
80
+ tool_name=tool_name,
81
+ config_schema=config_class,
82
+ explicit_config=config,
83
+ )
84
+ # Instantiate Config class with loaded config
85
+ self._config_obj = config_class(**loaded_config)
86
+ self._config = loaded_config
87
+ except ValidationError as e:
88
+ logger.error(f"Configuration validation failed for {tool_name}: {e}")
89
+ raise
90
+ except Exception as e:
91
+ logger.warning(f"Failed to load configuration for {tool_name}: {e}. Using defaults.")
92
+ # Fallback to explicit config or empty dict
93
+ self._config = config or {}
94
+ try:
95
+ self._config_obj = config_class(**self._config)
96
+ except Exception:
97
+ # If even defaults fail, create empty config object
98
+ self._config_obj = None
99
+ else:
100
+ # No Config class - backward compatibility mode
101
+ # Still try to load from YAML/env if config provided, otherwise use as-is
102
+ if config:
103
+ # Use explicit config as-is
104
+ self._config = config
105
+ else:
106
+ # Try to load from YAML/env even without Config class
107
+ loader = get_tool_config_loader()
108
+ try:
109
+ self._config = loader.load_tool_config(
110
+ tool_name=tool_name,
111
+ config_schema=None,
112
+ explicit_config=None,
113
+ )
114
+ except Exception as e:
115
+ logger.debug(f"Could not load config for {tool_name}: {e}. Using empty config.")
116
+ self._config = {}
117
+ self._config_obj = None
118
+
119
+ # Extract only executor-related config fields to avoid passing tool-specific
120
+ # fields (e.g., user_agent, temp_dir) to ExecutorConfig
121
+ executor_config = self._extract_executor_config(self._config)
122
+ self._executor = get_executor(executor_config)
64
123
  self._schemas: Dict[str, Type[BaseModel]] = {}
65
124
  self._async_methods: List[str] = []
125
+ # Schema coverage tracking
126
+ self._schema_coverage: Dict[str, Any] = {
127
+ "total_methods": 0,
128
+ "manual_schemas": 0,
129
+ "auto_generated_schemas": 0,
130
+ "missing_schemas": 0,
131
+ "schema_quality": {},
132
+ }
66
133
  self._register_schemas()
67
134
  self._register_async_methods()
135
+ # Log schema coverage after registration
136
+ self._log_schema_coverage()
137
+
138
+ def _extract_executor_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
139
+ """
140
+ Extract only executor-related configuration fields from the full config.
141
+
142
+ This prevents tool-specific fields (e.g., user_agent, temp_dir) from being
143
+ passed to ExecutorConfig, which would cause validation issues or be silently
144
+ ignored.
145
+
146
+ Args:
147
+ config (Dict[str, Any]): Full configuration dictionary.
148
+
149
+ Returns:
150
+ Dict[str, Any]: Filtered configuration containing only ExecutorConfig fields.
151
+ """
152
+ if not config:
153
+ return {}
154
+
155
+ # Get all valid field names from ExecutorConfig
156
+ executor_fields = set(ExecutorConfig.model_fields.keys())
157
+
158
+ # Filter config to only include executor-related fields
159
+ executor_config = {
160
+ key: value
161
+ for key, value in config.items()
162
+ if key in executor_fields
163
+ }
164
+
165
+ return executor_config
166
+
167
+ def _detect_config_class(self) -> Optional[Type[BaseModel]]:
168
+ """
169
+ Detect Config class in tool class hierarchy via introspection.
170
+
171
+ Looks for a class named 'Config' that inherits from BaseModel or BaseSettings.
172
+
173
+ Returns:
174
+ Config class if found, None otherwise
175
+ """
176
+ # Check current class and all base classes
177
+ for cls in [self.__class__] + list(self.__class__.__mro__):
178
+ if hasattr(cls, "Config"):
179
+ config_attr = getattr(cls, "Config")
180
+ # Check if Config is a class and inherits from BaseModel
181
+ if isinstance(config_attr, type):
182
+ # Import BaseSettings here to avoid circular imports
183
+ try:
184
+ from pydantic_settings import BaseSettings
185
+ if issubclass(config_attr, (BaseModel, BaseSettings)):
186
+ return config_attr
187
+ except ImportError:
188
+ # Fallback if pydantic_settings not available
189
+ if issubclass(config_attr, BaseModel):
190
+ return config_attr
191
+ return None
68
192
 
69
193
  def _register_schemas(self) -> None:
70
194
  """
71
195
  Register Pydantic schemas for operations by inspecting inner Schema classes.
196
+ Falls back to auto-generation when manual schemas are missing.
72
197
 
73
198
  Example:
74
199
  class MyTool(BaseTool):
@@ -76,13 +201,215 @@ class BaseTool:
76
201
  path: str
77
202
  def read(self, path: str):
78
203
  pass
79
- # Registers 'read' -> ReadSchema
204
+ # Registers 'read' -> ReadSchema (manual)
205
+ # Auto-generates schema for 'write' if WriteSchema doesn't exist
80
206
  """
207
+ # First pass: Register manual schemas
208
+ manual_schemas = {}
81
209
  for attr_name in dir(self.__class__):
82
210
  attr = getattr(self.__class__, attr_name)
83
- if isinstance(attr, type) and issubclass(attr, BaseModel) and attr.__name__.endswith('Schema'):
84
- op_name = attr.__name__.replace('Schema', '').lower()
211
+ if isinstance(attr, type) and issubclass(attr, BaseModel) and attr.__name__.endswith("Schema"):
212
+ # Normalize schema name to operation name
213
+ # Handle Method_nameSchema -> method_name convention
214
+ schema_base_name = attr.__name__.replace("Schema", "")
215
+ # Convert CamelCase to snake_case, then to lowercase
216
+ # e.g., Read_csvSchema -> read_csv
217
+ op_name = self._normalize_schema_name_to_method(schema_base_name)
218
+ manual_schemas[op_name] = attr
85
219
  self._schemas[op_name] = attr
220
+ self._schema_coverage["manual_schemas"] += 1
221
+ logger.debug(f"Registered manual schema {attr.__name__} -> {op_name}")
222
+
223
+ # Second pass: Auto-generate schemas for methods without manual schemas
224
+ public_methods = self._get_public_methods()
225
+ self._schema_coverage["total_methods"] = len(public_methods)
226
+
227
+ for method_name in public_methods:
228
+ # Skip if already has manual schema
229
+ if method_name in self._schemas:
230
+ continue
231
+
232
+ # Skip async wrappers (they share schemas with sync methods)
233
+ if method_name.endswith("_async"):
234
+ sync_method_name = method_name[:-6] # Remove "_async"
235
+ if sync_method_name in self._schemas:
236
+ self._schemas[method_name] = self._schemas[sync_method_name]
237
+ logger.debug(f"Reusing schema for async method {method_name} from {sync_method_name}")
238
+ continue
239
+
240
+ # Try to auto-generate schema
241
+ method = getattr(self.__class__, method_name)
242
+ if callable(method) and not isinstance(method, type):
243
+ try:
244
+ auto_schema = generate_schema_from_method(method, method_name)
245
+ if auto_schema:
246
+ self._schemas[method_name] = auto_schema
247
+ self._schema_coverage["auto_generated_schemas"] += 1
248
+ logger.info(f"Auto-generated schema for method {method_name} -> {auto_schema.__name__}")
249
+ else:
250
+ self._schema_coverage["missing_schemas"] += 1
251
+ logger.debug(f"No schema generated for method {method_name} (no parameters)")
252
+ except Exception as e:
253
+ self._schema_coverage["missing_schemas"] += 1
254
+ logger.warning(f"Failed to auto-generate schema for {method_name}: {e}")
255
+
256
+ def _normalize_schema_name_to_method(self, schema_base_name: str) -> str:
257
+ """
258
+ Convert schema name to method name.
259
+
260
+ Handles conventions like:
261
+ - Read_csvSchema -> read_csv
262
+ - ReadCsvSchema -> readcsv (fallback, but should use Read_csvSchema)
263
+ - ReadSchema -> read
264
+
265
+ Args:
266
+ schema_base_name: Schema name without "Schema" suffix
267
+
268
+ Returns:
269
+ Normalized method name
270
+ """
271
+ # If name contains underscores, preserve them (e.g., Read_csv -> read_csv)
272
+ if "_" in schema_base_name:
273
+ # Convert first letter to lowercase, keep rest as-is
274
+ if schema_base_name:
275
+ return schema_base_name[0].lower() + schema_base_name[1:]
276
+ return schema_base_name.lower()
277
+
278
+ # Convert CamelCase to snake_case
279
+ # Insert underscore before uppercase letters (except first)
280
+ result = []
281
+ for i, char in enumerate(schema_base_name):
282
+ if char.isupper() and i > 0:
283
+ result.append("_")
284
+ result.append(char.lower())
285
+ return "".join(result)
286
+
287
+ def _get_public_methods(self) -> List[str]:
288
+ """
289
+ Get list of public methods that should have schemas.
290
+
291
+ Returns:
292
+ List of method names
293
+ """
294
+ methods = []
295
+ for attr_name in dir(self.__class__):
296
+ # Skip private methods
297
+ if attr_name.startswith("_"):
298
+ continue
299
+
300
+ # Skip base class methods
301
+ if attr_name in ["run", "run_async", "run_batch"]:
302
+ continue
303
+
304
+ attr = getattr(self.__class__, attr_name)
305
+
306
+ # Skip non-method attributes
307
+ if not callable(attr):
308
+ continue
309
+
310
+ # Skip classes (like Config, Schema, etc.)
311
+ if isinstance(attr, type):
312
+ continue
313
+
314
+ methods.append(attr_name)
315
+
316
+ return methods
317
+
318
+ def _log_schema_coverage(self) -> None:
319
+ """
320
+ Log schema coverage metrics after registration.
321
+ """
322
+ coverage = self._schema_coverage
323
+ total = coverage["total_methods"]
324
+ if total == 0:
325
+ return
326
+
327
+ manual = coverage["manual_schemas"]
328
+ auto = coverage["auto_generated_schemas"]
329
+ missing = coverage["missing_schemas"]
330
+
331
+ coverage_pct = ((manual + auto) / total * 100) if total > 0 else 0
332
+
333
+ logger.info(
334
+ f"Schema coverage for {self.__class__.__name__}: "
335
+ f"{coverage_pct:.1f}% ({manual + auto}/{total}) - "
336
+ f"Manual: {manual}, Auto: {auto}, Missing: {missing}"
337
+ )
338
+
339
+ if missing > 0:
340
+ logger.debug(f"{missing} methods without schemas in {self.__class__.__name__}")
341
+
342
+ def get_schema_coverage(self) -> Dict[str, Any]:
343
+ """
344
+ Get schema coverage metrics for this tool.
345
+
346
+ Returns:
347
+ Dictionary with coverage metrics:
348
+ - total_methods: Total number of public methods
349
+ - manual_schemas: Number of manually defined schemas
350
+ - auto_generated_schemas: Number of auto-generated schemas
351
+ - missing_schemas: Number of methods without schemas
352
+ - coverage_percentage: Percentage of methods with schemas
353
+ - quality_metrics: Quality metrics for schemas
354
+ """
355
+ total = self._schema_coverage["total_methods"]
356
+ manual = self._schema_coverage["manual_schemas"]
357
+ auto = self._schema_coverage["auto_generated_schemas"]
358
+ missing = self._schema_coverage["missing_schemas"]
359
+
360
+ coverage_pct = ((manual + auto) / total * 100) if total > 0 else 0
361
+
362
+ # Calculate quality metrics
363
+ quality_metrics = self._calculate_schema_quality()
364
+
365
+ return {
366
+ "total_methods": total,
367
+ "manual_schemas": manual,
368
+ "auto_generated_schemas": auto,
369
+ "missing_schemas": missing,
370
+ "coverage_percentage": coverage_pct,
371
+ "quality_metrics": quality_metrics,
372
+ }
373
+
374
+ def _calculate_schema_quality(self) -> Dict[str, float]:
375
+ """
376
+ Calculate schema quality metrics.
377
+
378
+ Returns:
379
+ Dictionary with quality scores:
380
+ - description_quality: Percentage of fields with meaningful descriptions
381
+ - type_coverage: Percentage of fields with type annotations
382
+ - overall_score: Overall quality score
383
+ """
384
+ total_fields = 0
385
+ fields_with_descriptions = 0
386
+ fields_with_types = 0
387
+
388
+ for schema in self._schemas.values():
389
+ if not hasattr(schema, "model_fields"):
390
+ continue
391
+
392
+ for field_name, field_info in schema.model_fields.items():
393
+ total_fields += 1
394
+
395
+ # Check for meaningful description (not just "Parameter {name}")
396
+ desc = field_info.description
397
+ if desc and desc != f"Parameter {field_name}":
398
+ fields_with_descriptions += 1
399
+
400
+ # Check for type annotation
401
+ if field_info.annotation is not None and field_info.annotation != Any:
402
+ fields_with_types += 1
403
+
404
+ description_quality = (fields_with_descriptions / total_fields * 100) if total_fields > 0 else 0
405
+ type_coverage = (fields_with_types / total_fields * 100) if total_fields > 0 else 0
406
+ overall_score = (description_quality + type_coverage) / 2 if total_fields > 0 else 0
407
+
408
+ return {
409
+ "description_quality": description_quality,
410
+ "type_coverage": type_coverage,
411
+ "overall_score": overall_score,
412
+ }
86
413
 
87
414
  def _register_async_methods(self) -> None:
88
415
  """
@@ -90,7 +417,7 @@ class BaseTool:
90
417
  """
91
418
  for attr_name in dir(self.__class__):
92
419
  attr = getattr(self.__class__, attr_name)
93
- if inspect.iscoroutinefunction(attr) and not attr_name.startswith('_'):
420
+ if inspect.iscoroutinefunction(attr) and not attr_name.startswith("_"):
94
421
  self._async_methods.append(attr_name)
95
422
 
96
423
  def _sanitize_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
@@ -108,7 +435,7 @@ class BaseTool:
108
435
  """
109
436
  sanitized = {}
110
437
  for k, v in kwargs.items():
111
- if isinstance(v, str) and re.search(r'(\bSELECT\b|\bINSERT\b|--|;|/\*)', v, re.IGNORECASE):
438
+ if isinstance(v, str) and re.search(r"(\bSELECT\b|\bINSERT\b|--|;|/\*)", v, re.IGNORECASE):
112
439
  raise SecurityError(f"Input parameter '{k}' contains potentially malicious content")
113
440
  sanitized[k] = v
114
441
  return sanitized
@@ -184,6 +511,8 @@ class BaseTool:
184
511
  def _get_method_schema(self, method_name: str) -> Optional[Type[BaseModel]]:
185
512
  """
186
513
  Get the schema for a method if it exists.
514
+ Checks registered schemas first, then tries to find manual schema,
515
+ and finally falls back to auto-generation.
187
516
 
188
517
  Args:
189
518
  method_name (str): The name of the method.
@@ -191,12 +520,77 @@ class BaseTool:
191
520
  Returns:
192
521
  Optional[Type[BaseModel]]: The schema class or None.
193
522
  """
523
+ # First check registered schemas (includes both manual and auto-generated)
194
524
  if method_name in self._schemas:
195
- return self._schemas[method_name]
196
- schema_name = method_name[0].upper() + method_name[1:] + 'Schema'
525
+ schema = self._schemas[method_name]
526
+ # Log whether it's manual or auto-generated
527
+ schema_type = "manual" if self._is_manual_schema(method_name, schema) else "auto-generated"
528
+ logger.debug(f"Retrieved {schema_type} schema for method {method_name}")
529
+ return schema
530
+
531
+ # Try to find manual schema by convention
532
+ # Convert method_name to schema name (e.g., read_csv -> Read_csvSchema)
533
+ schema_name = self._method_name_to_schema_name(method_name)
197
534
  for attr_name in dir(self.__class__):
198
535
  if attr_name == schema_name:
199
536
  attr = getattr(self.__class__, attr_name)
200
537
  if isinstance(attr, type) and issubclass(attr, BaseModel):
538
+ # Register it for future use
539
+ self._schemas[method_name] = attr
540
+ self._schema_coverage["manual_schemas"] += 1
541
+ logger.debug(f"Found and registered manual schema {schema_name} for method {method_name}")
201
542
  return attr
543
+
544
+ # Fallback to auto-generation if method exists
545
+ if hasattr(self.__class__, method_name):
546
+ method = getattr(self.__class__, method_name)
547
+ if callable(method) and not isinstance(method, type):
548
+ try:
549
+ auto_schema = generate_schema_from_method(method, method_name)
550
+ if auto_schema:
551
+ self._schemas[method_name] = auto_schema
552
+ self._schema_coverage["auto_generated_schemas"] += 1
553
+ logger.info(f"Auto-generated schema on-demand for method {method_name}")
554
+ return auto_schema
555
+ except Exception as e:
556
+ logger.debug(f"Could not auto-generate schema for {method_name}: {e}")
557
+
202
558
  return None
559
+
560
+ def _method_name_to_schema_name(self, method_name: str) -> str:
561
+ """
562
+ Convert method name to schema name following convention.
563
+
564
+ Examples:
565
+ - read_csv -> Read_csvSchema
566
+ - read -> ReadSchema
567
+
568
+ Args:
569
+ method_name: Method name in snake_case
570
+
571
+ Returns:
572
+ Schema class name
573
+ """
574
+ # Preserve underscores: read_csv -> Read_csv
575
+ parts = method_name.split("_")
576
+ capitalized_parts = [part.capitalize() for part in parts]
577
+ return "".join(capitalized_parts) + "Schema"
578
+
579
+ def _is_manual_schema(self, method_name: str, schema: Type[BaseModel]) -> bool:
580
+ """
581
+ Check if a schema was manually defined (not auto-generated).
582
+
583
+ Args:
584
+ method_name: Method name
585
+ schema: Schema class
586
+
587
+ Returns:
588
+ True if schema is manually defined, False if auto-generated
589
+ """
590
+ # Check if schema exists as a class attribute
591
+ schema_name = schema.__name__
592
+ if hasattr(self.__class__, schema_name):
593
+ attr = getattr(self.__class__, schema_name)
594
+ if isinstance(attr, type) and attr == schema:
595
+ return True
596
+ return False
@@ -0,0 +1,121 @@
1
+ # python-middleware/aiecs/tools/docs/__init__.py
2
+
3
+ """
4
+ Document Tools Module
5
+
6
+ This module contains specialized tools for document processing and analysis:
7
+ - document_parser_tool: Modern high-performance document parsing with AI
8
+ - ai_document_orchestrator: AI-powered document processing orchestrator
9
+ """
10
+
11
+ # Lazy import all document tools to avoid heavy dependencies at import time
12
+ import os
13
+
14
+ # Define available document tools for lazy loading
15
+ _AVAILABLE_DOC_TOOLS = [
16
+ "document_parser_tool",
17
+ "ai_document_orchestrator",
18
+ "document_writer_tool",
19
+ "ai_document_writer_orchestrator",
20
+ "document_creator_tool",
21
+ "document_layout_tool",
22
+ "content_insertion_tool",
23
+ ]
24
+
25
+ # Track which tools have been loaded
26
+ _LOADED_DOC_TOOLS = set()
27
+
28
+
29
+ def _lazy_load_doc_tool(tool_name: str):
30
+ """Lazy load a specific document tool module"""
31
+ if tool_name in _LOADED_DOC_TOOLS:
32
+ return
33
+
34
+ # Mark as loading to prevent infinite recursion
35
+ _LOADED_DOC_TOOLS.add(tool_name)
36
+
37
+ try:
38
+ if tool_name == "document_parser_tool":
39
+ from . import document_parser_tool
40
+
41
+ globals()["document_parser_tool"] = document_parser_tool
42
+ elif tool_name == "ai_document_orchestrator":
43
+ from . import ai_document_orchestrator
44
+
45
+ globals()["ai_document_orchestrator"] = ai_document_orchestrator
46
+ elif tool_name == "document_writer_tool":
47
+ from . import document_writer_tool
48
+
49
+ globals()["document_writer_tool"] = document_writer_tool
50
+ elif tool_name == "ai_document_writer_orchestrator":
51
+ from . import ai_document_writer_orchestrator
52
+
53
+ globals()["ai_document_writer_orchestrator"] = ai_document_writer_orchestrator
54
+ elif tool_name == "document_creator_tool":
55
+ from . import document_creator_tool
56
+
57
+ globals()["document_creator_tool"] = document_creator_tool
58
+ elif tool_name == "document_layout_tool":
59
+ from . import document_layout_tool
60
+
61
+ globals()["document_layout_tool"] = document_layout_tool
62
+ elif tool_name == "content_insertion_tool":
63
+ from . import content_insertion_tool
64
+
65
+ globals()["content_insertion_tool"] = content_insertion_tool
66
+
67
+ except ImportError as e:
68
+ # Remove from loaded set if import failed
69
+ _LOADED_DOC_TOOLS.discard(tool_name)
70
+ print(f"Warning: Could not import {tool_name}: {e}")
71
+
72
+
73
+ def __getattr__(name: str):
74
+ """
75
+ Lazy loading mechanism for document tools.
76
+
77
+ This allows importing tools like:
78
+ from aiecs.tools.docs import document_parser_tool
79
+ """
80
+ if name in _AVAILABLE_DOC_TOOLS:
81
+ _lazy_load_doc_tool(name)
82
+ if name in globals():
83
+ return globals()[name]
84
+
85
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
86
+
87
+
88
+ def list_doc_tools():
89
+ """List all available document tools"""
90
+ return _AVAILABLE_DOC_TOOLS.copy()
91
+
92
+
93
+ def load_all_doc_tools():
94
+ """Load all available document tools"""
95
+ for tool_name in _AVAILABLE_DOC_TOOLS:
96
+ _lazy_load_doc_tool(tool_name)
97
+
98
+
99
+ # Auto-discovery of tool modules in this directory
100
+
101
+
102
+ def _discover_doc_tools():
103
+ """Discover document tool modules in the current directory"""
104
+ current_dir = os.path.dirname(__file__)
105
+ if not current_dir:
106
+ return
107
+
108
+ for filename in os.listdir(current_dir):
109
+ if filename.endswith("_tool.py") and not filename.startswith("__"):
110
+ tool_name = filename[:-3] # Remove .py extension
111
+ if tool_name not in _AVAILABLE_DOC_TOOLS:
112
+ _AVAILABLE_DOC_TOOLS.append(tool_name)
113
+
114
+
115
+ # Discover tools on import
116
+ _discover_doc_tools()
117
+
118
+ __all__ = [
119
+ "list_doc_tools",
120
+ "load_all_doc_tools",
121
+ ] + _AVAILABLE_DOC_TOOLS