aiecs 1.0.8__py3-none-any.whl → 1.2.0__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 (81) hide show
  1. aiecs/__init__.py +1 -1
  2. aiecs/aiecs_client.py +159 -1
  3. aiecs/config/config.py +6 -0
  4. aiecs/domain/__init__.py +95 -0
  5. aiecs/domain/community/__init__.py +159 -0
  6. aiecs/domain/community/agent_adapter.py +516 -0
  7. aiecs/domain/community/analytics.py +465 -0
  8. aiecs/domain/community/collaborative_workflow.py +99 -7
  9. aiecs/domain/community/communication_hub.py +649 -0
  10. aiecs/domain/community/community_builder.py +322 -0
  11. aiecs/domain/community/community_integration.py +365 -12
  12. aiecs/domain/community/community_manager.py +481 -5
  13. aiecs/domain/community/decision_engine.py +459 -13
  14. aiecs/domain/community/exceptions.py +238 -0
  15. aiecs/domain/community/models/__init__.py +36 -0
  16. aiecs/domain/community/resource_manager.py +1 -1
  17. aiecs/domain/community/shared_context_manager.py +621 -0
  18. aiecs/domain/context/__init__.py +24 -0
  19. aiecs/domain/context/context_engine.py +37 -33
  20. aiecs/main.py +20 -2
  21. aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
  22. aiecs/scripts/aid/__init__.py +15 -0
  23. aiecs/scripts/aid/version_manager.py +224 -0
  24. aiecs/scripts/dependance_check/__init__.py +18 -0
  25. aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +51 -8
  26. aiecs/scripts/dependance_patch/__init__.py +8 -0
  27. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +12 -0
  28. aiecs/scripts/tools_develop/README.md +340 -0
  29. aiecs/scripts/tools_develop/__init__.py +16 -0
  30. aiecs/scripts/tools_develop/check_type_annotations.py +263 -0
  31. aiecs/scripts/tools_develop/validate_tool_schemas.py +346 -0
  32. aiecs/tools/__init__.py +53 -34
  33. aiecs/tools/docs/__init__.py +106 -0
  34. aiecs/tools/docs/ai_document_orchestrator.py +556 -0
  35. aiecs/tools/docs/ai_document_writer_orchestrator.py +2222 -0
  36. aiecs/tools/docs/content_insertion_tool.py +1234 -0
  37. aiecs/tools/docs/document_creator_tool.py +1179 -0
  38. aiecs/tools/docs/document_layout_tool.py +1105 -0
  39. aiecs/tools/docs/document_parser_tool.py +924 -0
  40. aiecs/tools/docs/document_writer_tool.py +1636 -0
  41. aiecs/tools/langchain_adapter.py +102 -51
  42. aiecs/tools/schema_generator.py +265 -0
  43. aiecs/tools/statistics/__init__.py +82 -0
  44. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +581 -0
  45. aiecs/tools/statistics/ai_insight_generator_tool.py +473 -0
  46. aiecs/tools/statistics/ai_report_orchestrator_tool.py +629 -0
  47. aiecs/tools/statistics/data_loader_tool.py +518 -0
  48. aiecs/tools/statistics/data_profiler_tool.py +599 -0
  49. aiecs/tools/statistics/data_transformer_tool.py +531 -0
  50. aiecs/tools/statistics/data_visualizer_tool.py +460 -0
  51. aiecs/tools/statistics/model_trainer_tool.py +470 -0
  52. aiecs/tools/statistics/statistical_analyzer_tool.py +426 -0
  53. aiecs/tools/task_tools/chart_tool.py +2 -1
  54. aiecs/tools/task_tools/image_tool.py +43 -43
  55. aiecs/tools/task_tools/office_tool.py +48 -36
  56. aiecs/tools/task_tools/pandas_tool.py +37 -33
  57. aiecs/tools/task_tools/report_tool.py +67 -56
  58. aiecs/tools/task_tools/research_tool.py +32 -31
  59. aiecs/tools/task_tools/scraper_tool.py +53 -46
  60. aiecs/tools/task_tools/search_tool.py +1123 -0
  61. aiecs/tools/task_tools/stats_tool.py +20 -15
  62. {aiecs-1.0.8.dist-info → aiecs-1.2.0.dist-info}/METADATA +5 -1
  63. aiecs-1.2.0.dist-info/RECORD +135 -0
  64. aiecs-1.2.0.dist-info/entry_points.txt +10 -0
  65. aiecs/tools/task_tools/search_api.py +0 -7
  66. aiecs-1.0.8.dist-info/RECORD +0 -98
  67. aiecs-1.0.8.dist-info/entry_points.txt +0 -7
  68. /aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +0 -0
  69. /aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +0 -0
  70. /aiecs/scripts/{dependency_checker.py → dependance_check/dependency_checker.py} +0 -0
  71. /aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +0 -0
  72. /aiecs/scripts/{quick_dependency_check.py → dependance_check/quick_dependency_check.py} +0 -0
  73. /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
  74. /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
  75. /aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +0 -0
  76. /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
  77. /aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +0 -0
  78. /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
  79. {aiecs-1.0.8.dist-info → aiecs-1.2.0.dist-info}/WHEEL +0 -0
  80. {aiecs-1.0.8.dist-info → aiecs-1.2.0.dist-info}/licenses/LICENSE +0 -0
  81. {aiecs-1.0.8.dist-info → aiecs-1.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,346 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 工具 Schema 质量验证器
4
+
5
+ 用于工具开发和维护,验证自动生成的 Schema 质量。
6
+ 帮助开发者识别需要改进的文档字符串,提升 Schema 描述质量。
7
+
8
+ 使用方法:
9
+ # 验证所有工具
10
+ aiecs tools validate-schemas
11
+
12
+ # 验证特定工具
13
+ aiecs tools validate-schemas pandas
14
+
15
+ # 显示详细的改进建议
16
+ aiecs tools validate-schemas pandas --verbose
17
+
18
+ # 显示示例 Schema
19
+ aiecs tools validate-schemas pandas --show-examples
20
+ """
21
+
22
+ import sys
23
+ import inspect
24
+ from typing import Dict, List, Any, Type, Optional, get_type_hints
25
+ from pydantic import BaseModel
26
+
27
+ # 确保可以导入 aiecs
28
+ import os
29
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
30
+
31
+ from aiecs.tools import discover_tools, TOOL_CLASSES
32
+ from aiecs.tools.schema_generator import generate_schema_from_method
33
+
34
+
35
+ class SchemaQualityMetrics:
36
+ """Schema 质量指标"""
37
+
38
+ def __init__(self):
39
+ self.total_methods = 0
40
+ self.schemas_generated = 0
41
+ self.schemas_failed = 0
42
+ self.total_fields = 0
43
+ self.fields_with_meaningful_descriptions = 0
44
+ self.fields_with_types = 0
45
+ self.quality_issues = []
46
+
47
+ def add_method(self, has_schema: bool):
48
+ """添加方法统计"""
49
+ self.total_methods += 1
50
+ if has_schema:
51
+ self.schemas_generated += 1
52
+ else:
53
+ self.schemas_failed += 1
54
+
55
+ def add_field(self, has_type: bool, has_meaningful_desc: bool):
56
+ """添加字段统计"""
57
+ self.total_fields += 1
58
+ if has_type:
59
+ self.fields_with_types += 1
60
+ if has_meaningful_desc:
61
+ self.fields_with_meaningful_descriptions += 1
62
+
63
+ def add_issue(self, issue: str):
64
+ """添加质量问题"""
65
+ self.quality_issues.append(issue)
66
+
67
+ def get_scores(self) -> Dict[str, float]:
68
+ """计算质量分数"""
69
+ generation_rate = (self.schemas_generated / self.total_methods * 100) if self.total_methods > 0 else 0
70
+ description_rate = (self.fields_with_meaningful_descriptions / self.total_fields * 100) if self.total_fields > 0 else 0
71
+ type_coverage = (self.fields_with_types / self.total_fields * 100) if self.total_fields > 0 else 0
72
+
73
+ return {
74
+ 'generation_rate': generation_rate,
75
+ 'description_quality': description_rate,
76
+ 'type_coverage': type_coverage,
77
+ 'overall_score': (generation_rate + description_rate + type_coverage) / 3
78
+ }
79
+
80
+
81
+ def validate_schema_quality(schema: Type[BaseModel], method: callable, method_name: str) -> List[str]:
82
+ """
83
+ 验证单个 Schema 的质量
84
+
85
+ Returns:
86
+ 质量问题列表(改进建议)
87
+ """
88
+ issues = []
89
+
90
+ # 1. 检查 Schema 描述
91
+ if not schema.__doc__ or schema.__doc__.strip() == f"Execute {method_name} operation":
92
+ issues.append(f"💡 在方法文档字符串的第一行添加有意义的描述")
93
+
94
+ # 2. 检查字段
95
+ if not schema.model_fields:
96
+ return issues
97
+
98
+ for field_name, field_info in schema.model_fields.items():
99
+ # 检查字段描述
100
+ description = field_info.description
101
+ if not description or description == f"Parameter {field_name}":
102
+ issues.append(f"💡 在文档字符串的 Args 部分为参数 '{field_name}' 添加描述")
103
+
104
+ return issues
105
+
106
+
107
+ def analyze_tool_schemas(tool_name: str, tool_class: Type) -> Dict[str, Any]:
108
+ """分析工具的 Schema 生成情况"""
109
+
110
+ metrics = SchemaQualityMetrics()
111
+ methods_info = []
112
+
113
+ for method_name in dir(tool_class):
114
+ # 跳过私有方法和特殊方法
115
+ if method_name.startswith('_'):
116
+ continue
117
+
118
+ # 跳过基类方法
119
+ if method_name in ['run', 'run_async', 'run_batch']:
120
+ continue
121
+
122
+ method = getattr(tool_class, method_name)
123
+
124
+ # 跳过非方法属性
125
+ if not callable(method) or isinstance(method, type):
126
+ continue
127
+
128
+ # 生成 Schema
129
+ schema = generate_schema_from_method(method, method_name)
130
+
131
+ method_info = {
132
+ 'name': method_name,
133
+ 'schema': schema,
134
+ 'issues': []
135
+ }
136
+
137
+ if schema:
138
+ metrics.add_method(True)
139
+
140
+ # 验证质量
141
+ issues = validate_schema_quality(schema, method, method_name)
142
+ method_info['issues'] = issues
143
+
144
+ # 统计字段
145
+ for field_name, field_info in schema.model_fields.items():
146
+ has_type = field_info.annotation is not None
147
+ has_meaningful_desc = (
148
+ field_info.description and
149
+ field_info.description != f"Parameter {field_name}"
150
+ )
151
+ metrics.add_field(has_type, has_meaningful_desc)
152
+
153
+ # 记录问题
154
+ for issue in issues:
155
+ metrics.add_issue(f"{tool_name}.{method_name}: {issue}")
156
+ else:
157
+ metrics.add_method(False)
158
+ method_info['issues'] = ['⚠️ 无法生成 Schema(可能是无参数方法)']
159
+
160
+ methods_info.append(method_info)
161
+
162
+ return {
163
+ 'metrics': metrics,
164
+ 'methods': methods_info
165
+ }
166
+
167
+
168
+ def print_tool_report(tool_name: str, result: Dict, verbose: bool = False, show_examples: bool = False):
169
+ """打印工具报告"""
170
+
171
+ metrics = result['metrics']
172
+ methods = result['methods']
173
+ scores = metrics.get_scores()
174
+
175
+ # 状态图标
176
+ overall = scores['overall_score']
177
+ if overall >= 90:
178
+ status = "✅"
179
+ grade = "A (优秀)"
180
+ elif overall >= 80:
181
+ status = "⚠️"
182
+ grade = "B (良好)"
183
+ elif overall >= 70:
184
+ status = "⚠️"
185
+ grade = "C (中等)"
186
+ else:
187
+ status = "❌"
188
+ grade = "D (需改进)"
189
+
190
+ print(f"\n{status} {tool_name}")
191
+ print(f" 方法数: {metrics.total_methods}")
192
+ print(f" 成功生成 Schema: {metrics.schemas_generated} ({scores['generation_rate']:.1f}%)")
193
+ print(f" 描述质量: {scores['description_quality']:.1f}%")
194
+ print(f" 综合评分: {scores['overall_score']:.1f}% ({grade})")
195
+
196
+ # 显示需要改进的方法
197
+ methods_with_issues = [m for m in methods if m['issues'] and m['schema']]
198
+
199
+ if methods_with_issues and (verbose or scores['description_quality'] < 80):
200
+ print(f"\n 需要改进的方法 ({len(methods_with_issues)} 个):")
201
+
202
+ for method_info in methods_with_issues[:5 if not verbose else None]:
203
+ print(f"\n {method_info['name']}:")
204
+ for issue in method_info['issues']:
205
+ print(f" {issue}")
206
+
207
+ if not verbose and len(methods_with_issues) > 5:
208
+ print(f"\n ... 还有 {len(methods_with_issues) - 5} 个方法需要改进")
209
+ print(f" 使用 --verbose 查看全部")
210
+
211
+ # 显示示例 Schema
212
+ if show_examples:
213
+ methods_with_schema = [m for m in methods if m['schema']]
214
+ if methods_with_schema:
215
+ print(f"\n 示例 Schema:")
216
+ for method_info in methods_with_schema[:2]:
217
+ schema = method_info['schema']
218
+ print(f"\n {method_info['name']} → {schema.__name__}")
219
+ print(f" 描述: {schema.__doc__}")
220
+ print(f" 字段:")
221
+ for field_name, field_info in list(schema.model_fields.items())[:3]:
222
+ required = "必需" if field_info.is_required() else "可选"
223
+ print(f" - {field_name}: {field_info.description} [{required}]")
224
+
225
+
226
+ def validate_schemas(tool_names: Optional[List[str]] = None, verbose: bool = False, show_examples: bool = False):
227
+ """
228
+ 验证工具的 Schema 质量
229
+
230
+ Args:
231
+ tool_names: 要验证的工具名称列表,None 表示验证所有工具
232
+ verbose: 是否显示详细信息
233
+ show_examples: 是否显示示例 Schema
234
+ """
235
+ print("=" * 100)
236
+ print("工具 Schema 质量验证器")
237
+ print("=" * 100)
238
+
239
+ discover_tools()
240
+
241
+ # 确定要验证的工具
242
+ if tool_names:
243
+ tools_to_check = {}
244
+ for name in tool_names:
245
+ if name in TOOL_CLASSES:
246
+ tools_to_check[name] = TOOL_CLASSES[name]
247
+ else:
248
+ print(f"\n❌ 工具 '{name}' 不存在")
249
+
250
+ if not tools_to_check:
251
+ print("\n没有找到要验证的工具")
252
+ return
253
+ else:
254
+ tools_to_check = TOOL_CLASSES
255
+
256
+ # 验证每个工具
257
+ all_results = {}
258
+ for tool_name in sorted(tools_to_check.keys()):
259
+ tool_class = tools_to_check[tool_name]
260
+ result = analyze_tool_schemas(tool_name, tool_class)
261
+ all_results[tool_name] = result
262
+
263
+ print_tool_report(tool_name, result, verbose, show_examples)
264
+
265
+ # 总体统计
266
+ if len(all_results) > 1:
267
+ total_methods = sum(r['metrics'].total_methods for r in all_results.values())
268
+ total_generated = sum(r['metrics'].schemas_generated for r in all_results.values())
269
+ total_fields = sum(r['metrics'].total_fields for r in all_results.values())
270
+ total_meaningful = sum(r['metrics'].fields_with_meaningful_descriptions for r in all_results.values())
271
+
272
+ overall_generation = (total_generated / total_methods * 100) if total_methods > 0 else 0
273
+ overall_description = (total_meaningful / total_fields * 100) if total_fields > 0 else 0
274
+
275
+ print("\n" + "=" * 100)
276
+ print(f"总体统计:")
277
+ print(f" 方法数: {total_methods}")
278
+ print(f" Schema 生成率: {total_generated}/{total_methods} ({overall_generation:.1f}%)")
279
+ print(f" 描述质量: {overall_description:.1f}%")
280
+ print("=" * 100)
281
+
282
+ print("\n💡 改进建议:")
283
+ print(" 1. 在方法的文档字符串第一行添加简短描述")
284
+ print(" 2. 在 Args 部分为每个参数添加详细描述")
285
+ print(" 3. 使用 Google 或 NumPy 风格的文档字符串")
286
+ print("\n示例:")
287
+ print(' def filter(self, records: List[Dict], condition: str) -> List[Dict]:')
288
+ print(' """')
289
+ print(' Filter DataFrame based on a condition.')
290
+ print(' ')
291
+ print(' Args:')
292
+ print(' records: List of records to filter')
293
+ print(' condition: Filter condition (pandas query syntax)')
294
+ print(' """')
295
+
296
+
297
+ def main():
298
+ """命令行入口"""
299
+ import argparse
300
+
301
+ parser = argparse.ArgumentParser(
302
+ description='验证工具 Schema 的生成质量',
303
+ formatter_class=argparse.RawDescriptionHelpFormatter,
304
+ epilog="""
305
+ 示例:
306
+ # 验证所有工具
307
+ aiecs tools validate-schemas
308
+
309
+ # 验证特定工具
310
+ aiecs tools validate-schemas pandas
311
+
312
+ # 显示详细的改进建议
313
+ aiecs tools validate-schemas pandas --verbose
314
+
315
+ # 显示示例 Schema
316
+ aiecs tools validate-schemas pandas --show-examples
317
+ """
318
+ )
319
+
320
+ parser.add_argument(
321
+ 'tools',
322
+ nargs='*',
323
+ help='要验证的工具名称(不指定则验证所有工具)'
324
+ )
325
+
326
+ parser.add_argument(
327
+ '-v', '--verbose',
328
+ action='store_true',
329
+ help='显示详细的改进建议'
330
+ )
331
+
332
+ parser.add_argument(
333
+ '-e', '--show-examples',
334
+ action='store_true',
335
+ help='显示示例 Schema'
336
+ )
337
+
338
+ args = parser.parse_args()
339
+
340
+ tool_names = args.tools if args.tools else None
341
+ validate_schemas(tool_names, args.verbose, args.show_examples)
342
+
343
+
344
+ if __name__ == '__main__':
345
+ main()
346
+
aiecs/tools/__init__.py CHANGED
@@ -11,25 +11,25 @@ from aiecs.tools.base_tool import BaseTool
11
11
 
12
12
  logger = logging.getLogger(__name__)
13
13
 
14
- # 全局工具注册表
14
+ # Global tool registry
15
15
  TOOL_REGISTRY = {}
16
16
  TOOL_CLASSES = {}
17
17
  TOOL_CONFIGS = {}
18
18
 
19
19
  def register_tool(name):
20
20
  """
21
- 装饰器,用于注册工具类
21
+ Decorator for registering tool classes
22
22
 
23
23
  Args:
24
- name: 工具名称
24
+ name: Tool name
25
25
 
26
26
  Returns:
27
- 装饰后的类
27
+ Decorated class
28
28
  """
29
29
  def wrapper(cls):
30
- # 存储工具类,但不立即实例化
30
+ # Store tool class but don't instantiate immediately
31
31
  TOOL_CLASSES[name] = cls
32
- # 兼容旧版本:如果类继承自BaseTool,则不立即实例化
32
+ # Backward compatibility: if class inherits from BaseTool, don't instantiate immediately
33
33
  if not issubclass(cls, BaseTool):
34
34
  TOOL_REGISTRY[name] = cls()
35
35
  return cls
@@ -37,22 +37,29 @@ def register_tool(name):
37
37
 
38
38
  def get_tool(name):
39
39
  """
40
- 获取工具实例
40
+ Get tool instance
41
41
 
42
42
  Args:
43
- name: 工具名称
43
+ name: Tool name
44
44
 
45
45
  Returns:
46
- 工具实例
46
+ Tool instance
47
47
 
48
48
  Raises:
49
- ValueError: 如果工具未注册
49
+ ValueError: If tool is not registered
50
50
  """
51
- if name not in TOOL_REGISTRY and name in TOOL_CLASSES:
52
- # 延迟实例化BaseTool子类
53
- tool_class = TOOL_CLASSES[name]
54
- config = TOOL_CONFIGS.get(name, {})
55
- TOOL_REGISTRY[name] = tool_class(config)
51
+ # Check if placeholder needs to be replaced or lazy instantiation is needed
52
+ if name in TOOL_CLASSES:
53
+ # If TOOL_REGISTRY contains placeholder or doesn't exist, instantiate real tool class
54
+ current_tool = TOOL_REGISTRY.get(name)
55
+ is_placeholder = getattr(current_tool, 'is_placeholder', False)
56
+
57
+ if current_tool is None or is_placeholder:
58
+ # Lazy instantiation of BaseTool subclasses, replace placeholder
59
+ tool_class = TOOL_CLASSES[name]
60
+ config = TOOL_CONFIGS.get(name, {})
61
+ TOOL_REGISTRY[name] = tool_class(config)
62
+ logger.debug(f"Instantiated tool '{name}' from class {tool_class.__name__}")
56
63
 
57
64
  if name not in TOOL_REGISTRY:
58
65
  raise ValueError(f"Tool '{name}' is not registered")
@@ -61,17 +68,17 @@ def get_tool(name):
61
68
 
62
69
  def list_tools():
63
70
  """
64
- 列出所有已注册的工具
71
+ List all registered tools
65
72
 
66
73
  Returns:
67
- 工具信息字典列表
74
+ List of tool information dictionaries
68
75
  """
69
76
  tools = []
70
77
  all_tool_names = list(set(list(TOOL_REGISTRY.keys()) + list(TOOL_CLASSES.keys())))
71
78
 
72
79
  for tool_name in all_tool_names:
73
80
  try:
74
- # 优先使用已有实例的信息
81
+ # Prefer using information from existing instances
75
82
  if tool_name in TOOL_REGISTRY:
76
83
  tool_instance = TOOL_REGISTRY[tool_name]
77
84
  tool_info = {
@@ -83,7 +90,7 @@ def list_tools():
83
90
  "status": "loaded"
84
91
  }
85
92
  elif tool_name in TOOL_CLASSES:
86
- # 从类定义获取信息,但不实例化
93
+ # Get information from class definition but don't instantiate
87
94
  tool_class = TOOL_CLASSES[tool_name]
88
95
  tool_info = {
89
96
  "name": tool_name,
@@ -100,7 +107,7 @@ def list_tools():
100
107
 
101
108
  except Exception as e:
102
109
  logger.warning(f"Failed to get info for tool {tool_name}: {e}")
103
- # 提供基本信息
110
+ # Provide basic information
104
111
  tools.append({
105
112
  "name": tool_name,
106
113
  "description": f"{tool_name} (info unavailable)",
@@ -114,26 +121,26 @@ def list_tools():
114
121
 
115
122
  def discover_tools(package_path: str = "aiecs.tools"):
116
123
  """
117
- 发现并注册包中的所有工具
124
+ Discover and register all tools in the package
118
125
 
119
126
  Args:
120
- package_path: 要搜索的包路径
127
+ package_path: Package path to search
121
128
  """
122
129
  package = importlib.import_module(package_path)
123
130
  package_dir = os.path.dirname(package.__file__)
124
131
 
125
132
  for _, module_name, is_pkg in pkgutil.iter_modules([package_dir]):
126
133
  if is_pkg:
127
- # 递归搜索子包中的工具
134
+ # Recursively search for tools in subpackages
128
135
  discover_tools(f"{package_path}.{module_name}")
129
136
  else:
130
- # 导入模块
137
+ # Import module
131
138
  try:
132
139
  importlib.import_module(f"{package_path}.{module_name}")
133
140
  except Exception as e:
134
141
  logger.error(f"Error importing module {module_name}: {e}")
135
142
 
136
- # 导入基础工具类供继承使用
143
+ # Import base tool class for inheritance
137
144
  from aiecs.tools.base_tool import BaseTool
138
145
 
139
146
  # Lazy loading strategy: don't import all tools at package init
@@ -152,18 +159,30 @@ def _register_known_tools():
152
159
  """Register known tools without importing heavy dependencies"""
153
160
  # Pre-register tool classes for discovery without importing modules
154
161
  # This allows list_tools() to work before actual tool loading
162
+ #
163
+ # NOTE: Tool names must match the names used in @register_tool decorators:
164
+ # - chart (not chart_tool)
165
+ # - classifier (not classfire_tool)
166
+ # - image (not image_tool)
167
+ # - office (not office_tool)
168
+ # - pandas (not pandas_tool)
169
+ # - report (not report_tool)
170
+ # - research (not research_tool)
171
+ # - scraper (not scraper_tool)
172
+ # - search_api (same)
173
+ # - stats (not stats_tool)
155
174
 
156
175
  known_tools = [
157
- ("chart_tool", "Chart and visualization operations"),
158
- ("classfire_tool", "Text classification and keyword extraction"),
159
- ("image_tool", "Image processing and OCR operations"),
160
- ("office_tool", "Office document processing"),
161
- ("pandas_tool", "Data analysis and manipulation"),
162
- ("report_tool", "Report generation and formatting"),
163
- ("research_tool", "Research and information gathering"),
164
- ("scraper_tool", "Web scraping and data extraction"),
176
+ ("chart", "Chart and visualization operations"),
177
+ ("classifier", "Text classification and keyword extraction"),
178
+ ("image", "Image processing and OCR operations"),
179
+ ("office", "Office document processing"),
180
+ ("pandas", "Data analysis and manipulation"),
181
+ ("report", "Report generation and formatting"),
182
+ ("research", "Research and information gathering"),
183
+ ("scraper", "Web scraping and data extraction"),
165
184
  ("search_api", "Search API integration"),
166
- ("stats_tool", "Statistical analysis and computation")
185
+ ("stats", "Statistical analysis and computation")
167
186
  ]
168
187
 
169
188
  # Register as placeholder until actually loaded
@@ -0,0 +1,106 @@
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
+ def _lazy_load_doc_tool(tool_name: str):
29
+ """Lazy load a specific document tool module"""
30
+ if tool_name in _LOADED_DOC_TOOLS:
31
+ return
32
+
33
+ # Mark as loading to prevent infinite recursion
34
+ _LOADED_DOC_TOOLS.add(tool_name)
35
+
36
+ try:
37
+ if tool_name == 'document_parser_tool':
38
+ from . import document_parser_tool
39
+ globals()['document_parser_tool'] = document_parser_tool
40
+ elif tool_name == 'ai_document_orchestrator':
41
+ from . import ai_document_orchestrator
42
+ globals()['ai_document_orchestrator'] = ai_document_orchestrator
43
+ elif tool_name == 'document_writer_tool':
44
+ from . import document_writer_tool
45
+ globals()['document_writer_tool'] = document_writer_tool
46
+ elif tool_name == 'ai_document_writer_orchestrator':
47
+ from . import ai_document_writer_orchestrator
48
+ globals()['ai_document_writer_orchestrator'] = ai_document_writer_orchestrator
49
+ elif tool_name == 'document_creator_tool':
50
+ from . import document_creator_tool
51
+ globals()['document_creator_tool'] = document_creator_tool
52
+ elif tool_name == 'document_layout_tool':
53
+ from . import document_layout_tool
54
+ globals()['document_layout_tool'] = document_layout_tool
55
+ elif tool_name == 'content_insertion_tool':
56
+ from . import content_insertion_tool
57
+ globals()['content_insertion_tool'] = content_insertion_tool
58
+
59
+ except ImportError as e:
60
+ # Remove from loaded set if import failed
61
+ _LOADED_DOC_TOOLS.discard(tool_name)
62
+ print(f"Warning: Could not import {tool_name}: {e}")
63
+
64
+ def __getattr__(name: str):
65
+ """
66
+ Lazy loading mechanism for document tools.
67
+
68
+ This allows importing tools like:
69
+ from aiecs.tools.docs import document_parser_tool
70
+ """
71
+ if name in _AVAILABLE_DOC_TOOLS:
72
+ _lazy_load_doc_tool(name)
73
+ if name in globals():
74
+ return globals()[name]
75
+
76
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
77
+
78
+ def list_doc_tools():
79
+ """List all available document tools"""
80
+ return _AVAILABLE_DOC_TOOLS.copy()
81
+
82
+ def load_all_doc_tools():
83
+ """Load all available document tools"""
84
+ for tool_name in _AVAILABLE_DOC_TOOLS:
85
+ _lazy_load_doc_tool(tool_name)
86
+
87
+ # Auto-discovery of tool modules in this directory
88
+ def _discover_doc_tools():
89
+ """Discover document tool modules in the current directory"""
90
+ current_dir = os.path.dirname(__file__)
91
+ if not current_dir:
92
+ return
93
+
94
+ for filename in os.listdir(current_dir):
95
+ if filename.endswith('_tool.py') and not filename.startswith('__'):
96
+ tool_name = filename[:-3] # Remove .py extension
97
+ if tool_name not in _AVAILABLE_DOC_TOOLS:
98
+ _AVAILABLE_DOC_TOOLS.append(tool_name)
99
+
100
+ # Discover tools on import
101
+ _discover_doc_tools()
102
+
103
+ __all__ = [
104
+ 'list_doc_tools',
105
+ 'load_all_doc_tools',
106
+ ] + _AVAILABLE_DOC_TOOLS