aiecs 1.0.8__py3-none-any.whl → 1.1.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 (45) hide show
  1. aiecs/__init__.py +1 -1
  2. aiecs/aiecs_client.py +159 -1
  3. aiecs/config/config.py +4 -0
  4. aiecs/domain/context/__init__.py +24 -0
  5. aiecs/main.py +20 -2
  6. aiecs/scripts/dependance_check/__init__.py +18 -0
  7. aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +50 -8
  8. aiecs/scripts/dependance_patch/__init__.py +8 -0
  9. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +12 -0
  10. aiecs/scripts/tools_develop/README.md +340 -0
  11. aiecs/scripts/tools_develop/__init__.py +16 -0
  12. aiecs/scripts/tools_develop/check_type_annotations.py +263 -0
  13. aiecs/scripts/tools_develop/validate_tool_schemas.py +346 -0
  14. aiecs/tools/__init__.py +33 -14
  15. aiecs/tools/docs/__init__.py +103 -0
  16. aiecs/tools/docs/ai_document_orchestrator.py +543 -0
  17. aiecs/tools/docs/ai_document_writer_orchestrator.py +2199 -0
  18. aiecs/tools/docs/content_insertion_tool.py +1214 -0
  19. aiecs/tools/docs/document_creator_tool.py +1161 -0
  20. aiecs/tools/docs/document_layout_tool.py +1090 -0
  21. aiecs/tools/docs/document_parser_tool.py +904 -0
  22. aiecs/tools/docs/document_writer_tool.py +1583 -0
  23. aiecs/tools/langchain_adapter.py +102 -51
  24. aiecs/tools/schema_generator.py +265 -0
  25. aiecs/tools/task_tools/image_tool.py +1 -1
  26. aiecs/tools/task_tools/office_tool.py +9 -0
  27. aiecs/tools/task_tools/scraper_tool.py +1 -1
  28. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/METADATA +1 -1
  29. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/RECORD +44 -28
  30. aiecs-1.1.0.dist-info/entry_points.txt +9 -0
  31. aiecs-1.0.8.dist-info/entry_points.txt +0 -7
  32. /aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +0 -0
  33. /aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +0 -0
  34. /aiecs/scripts/{dependency_checker.py → dependance_check/dependency_checker.py} +0 -0
  35. /aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +0 -0
  36. /aiecs/scripts/{quick_dependency_check.py → dependance_check/quick_dependency_check.py} +0 -0
  37. /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
  38. /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
  39. /aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +0 -0
  40. /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
  41. /aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +0 -0
  42. /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
  43. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/WHEEL +0 -0
  44. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/licenses/LICENSE +0 -0
  45. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/top_level.txt +0 -0
@@ -13,6 +13,9 @@ import logging
13
13
  from typing import Any, Dict, List, Optional, Type, Union, get_type_hints
14
14
  from pydantic import BaseModel, Field
15
15
 
16
+ # Import schema generator
17
+ from aiecs.tools.schema_generator import generate_schema_from_method
18
+
16
19
  try:
17
20
  from langchain.tools import BaseTool as LangchainBaseTool
18
21
  from langchain.callbacks.manager import CallbackManagerForToolRun, AsyncCallbackManagerForToolRun
@@ -33,24 +36,27 @@ logger = logging.getLogger(__name__)
33
36
  class LangchainToolAdapter(LangchainBaseTool):
34
37
  """
35
38
  Langchain tool adapter for single operation
36
-
39
+
37
40
  Wraps one operation method of BaseTool as an independent Langchain tool
38
41
  """
39
-
42
+
40
43
  # Define class attributes
41
44
  name: str = ""
42
45
  description: str = ""
43
-
46
+ base_tool_name: str = ""
47
+ operation_name: str = ""
48
+ operation_schema: Optional[Type[BaseModel]] = None
49
+
44
50
  def __init__(
45
- self,
51
+ self,
46
52
  base_tool_name: str,
47
- operation_name: str,
53
+ operation_name: str,
48
54
  operation_schema: Optional[Type[BaseModel]] = None,
49
55
  description: Optional[str] = None
50
56
  ):
51
57
  """
52
58
  Initialize adapter
53
-
59
+
54
60
  Args:
55
61
  base_tool_name: Original tool name
56
62
  operation_name: Operation name
@@ -58,56 +64,55 @@ class LangchainToolAdapter(LangchainBaseTool):
58
64
  description: Tool description
59
65
  """
60
66
  # Construct tool name and description
61
- self.name = f"{base_tool_name}_{operation_name}"
62
- self.description = description or f"Execute {operation_name} operation from {base_tool_name} tool"
63
-
64
- # Store tool information (use self.__dict__ to set directly to avoid pydantic validation)
65
- self.__dict__['base_tool_name'] = base_tool_name
66
- self.__dict__['operation_name'] = operation_name
67
- self.__dict__['operation_schema'] = operation_schema
68
-
69
- # Set parameter Schema
70
- if operation_schema:
71
- self.args_schema = operation_schema
72
-
73
- super().__init__()
67
+ tool_name = f"{base_tool_name}_{operation_name}"
68
+ tool_description = description or f"Execute {operation_name} operation from {base_tool_name} tool"
69
+
70
+ # Initialize parent class with all required fields
71
+ super().__init__(
72
+ name=tool_name,
73
+ description=tool_description,
74
+ base_tool_name=base_tool_name,
75
+ operation_name=operation_name,
76
+ operation_schema=operation_schema,
77
+ args_schema=operation_schema
78
+ )
74
79
 
75
80
  def _run(
76
- self,
77
- run_manager: Optional[CallbackManagerForToolRun] = None,
81
+ self,
82
+ run_manager: Optional[CallbackManagerForToolRun] = None,
78
83
  **kwargs: Any
79
84
  ) -> Any:
80
85
  """Execute operation synchronously"""
81
86
  try:
82
87
  # Get original tool instance
83
- base_tool = get_tool(self.__dict__['base_tool_name'])
84
-
88
+ base_tool = get_tool(self.base_tool_name)
89
+
85
90
  # Execute operation
86
- result = base_tool.run(self.__dict__['operation_name'], **kwargs)
87
-
91
+ result = base_tool.run(self.operation_name, **kwargs)
92
+
88
93
  logger.info(f"Successfully executed {self.name} with result type: {type(result)}")
89
94
  return result
90
-
95
+
91
96
  except Exception as e:
92
97
  logger.error(f"Error executing {self.name}: {str(e)}")
93
98
  raise
94
-
99
+
95
100
  async def _arun(
96
- self,
101
+ self,
97
102
  run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
98
103
  **kwargs: Any
99
104
  ) -> Any:
100
105
  """Execute operation asynchronously"""
101
106
  try:
102
107
  # Get original tool instance
103
- base_tool = get_tool(self.__dict__['base_tool_name'])
104
-
108
+ base_tool = get_tool(self.base_tool_name)
109
+
105
110
  # Execute asynchronous operation
106
- result = await base_tool.run_async(self.__dict__['operation_name'], **kwargs)
107
-
111
+ result = await base_tool.run_async(self.operation_name, **kwargs)
112
+
108
113
  logger.info(f"Successfully executed {self.name} async with result type: {type(result)}")
109
114
  return result
110
-
115
+
111
116
  except Exception as e:
112
117
  logger.error(f"Error executing {self.name} async: {str(e)}")
113
118
  raise
@@ -121,47 +126,90 @@ class ToolRegistry:
121
126
  def discover_operations(self, base_tool_class: Type[BaseTool]) -> List[Dict[str, Any]]:
122
127
  """
123
128
  Discover all operation methods and Schemas of BaseTool class
124
-
129
+
125
130
  Args:
126
131
  base_tool_class: BaseTool subclass
127
-
132
+
128
133
  Returns:
129
134
  List of operation information, including method names, Schemas, descriptions, etc.
130
135
  """
131
136
  operations = []
132
-
137
+
133
138
  # Get all Schema classes
139
+ # Build a mapping from normalized names to Schema classes
140
+ # Check both class-level and module-level schemas
134
141
  schemas = {}
142
+
143
+ # 1. Check class-level schemas (e.g., ChartTool)
135
144
  for attr_name in dir(base_tool_class):
136
145
  attr = getattr(base_tool_class, attr_name)
137
146
  if isinstance(attr, type) and issubclass(attr, BaseModel) and attr.__name__.endswith('Schema'):
138
- op_name = attr.__name__.replace('Schema', '').lower()
139
- schemas[op_name] = attr
140
-
147
+ # Normalize: remove 'Schema' suffix, convert to lowercase, remove underscores
148
+ schema_base_name = attr.__name__.replace('Schema', '')
149
+ normalized_name = schema_base_name.replace('_', '').lower()
150
+ schemas[normalized_name] = attr
151
+ logger.debug(f"Found class-level schema {attr.__name__} -> normalized: {normalized_name}")
152
+
153
+ # 2. Check module-level schemas (e.g., ImageTool)
154
+ tool_module = inspect.getmodule(base_tool_class)
155
+ if tool_module:
156
+ for attr_name in dir(tool_module):
157
+ if attr_name.startswith('_'):
158
+ continue
159
+ attr = getattr(tool_module, attr_name)
160
+ if isinstance(attr, type) and issubclass(attr, BaseModel) and attr.__name__.endswith('Schema'):
161
+ # Skip if already found at class level
162
+ schema_base_name = attr.__name__.replace('Schema', '')
163
+ normalized_name = schema_base_name.replace('_', '').lower()
164
+ if normalized_name not in schemas:
165
+ schemas[normalized_name] = attr
166
+ logger.debug(f"Found module-level schema {attr.__name__} -> normalized: {normalized_name}")
167
+
141
168
  # Get all public methods
142
169
  for method_name in dir(base_tool_class):
143
170
  if method_name.startswith('_'):
144
171
  continue
145
-
172
+
146
173
  method = getattr(base_tool_class, method_name)
147
174
  if not callable(method):
148
175
  continue
149
-
150
- # Skip base class methods
176
+
177
+ # Skip base class methods and Schema classes themselves
151
178
  if method_name in ['run', 'run_async', 'run_batch']:
152
179
  continue
153
-
180
+
181
+ # Skip if it's a class (like Config or Schema classes)
182
+ if isinstance(method, type):
183
+ continue
184
+
185
+ # Normalize method name: remove underscores and convert to lowercase
186
+ normalized_method_name = method_name.replace('_', '').lower()
187
+
188
+ # Try to find matching schema
189
+ matching_schema = schemas.get(normalized_method_name)
190
+
191
+ if matching_schema:
192
+ logger.debug(f"Matched method {method_name} with manual schema {matching_schema.__name__}")
193
+ else:
194
+ # Auto-generate schema if not found
195
+ auto_schema = generate_schema_from_method(method, method_name)
196
+ if auto_schema:
197
+ matching_schema = auto_schema
198
+ logger.debug(f"Auto-generated schema for method {method_name}: {auto_schema.__name__}")
199
+ else:
200
+ logger.debug(f"No schema found or generated for method {method_name}")
201
+
154
202
  # Get method information
155
203
  operation_info = {
156
204
  'name': method_name,
157
205
  'method': method,
158
- 'schema': schemas.get(method_name),
206
+ 'schema': matching_schema,
159
207
  'description': inspect.getdoc(method) or f"Execute {method_name} operation",
160
208
  'is_async': inspect.iscoroutinefunction(method)
161
209
  }
162
-
210
+
163
211
  operations.append(operation_info)
164
-
212
+
165
213
  return operations
166
214
 
167
215
  def _extract_description(self, method, base_tool_name: str, operation_name: str, schema: Optional[Type[BaseModel]] = None) -> str:
@@ -255,20 +303,23 @@ class ToolRegistry:
255
303
  def create_all_langchain_tools(self) -> List[LangchainToolAdapter]:
256
304
  """
257
305
  Create Langchain adapters for all registered BaseTools
258
-
306
+
259
307
  Returns:
260
308
  List of all Langchain tool adapters
261
309
  """
262
310
  all_tools = []
263
-
264
- for tool_name in list_tools():
311
+
312
+ # list_tools() returns a list of dicts, extract tool names
313
+ tool_infos = list_tools()
314
+ for tool_info in tool_infos:
315
+ tool_name = tool_info['name']
265
316
  try:
266
317
  tools = self.create_langchain_tools(tool_name)
267
318
  all_tools.extend(tools)
268
319
  except Exception as e:
269
320
  logger.error(f"Failed to create Langchain tools for {tool_name}: {e}")
270
-
271
- logger.info(f"Created total {len(all_tools)} Langchain tools from {len(list_tools())} base tools")
321
+
322
+ logger.info(f"Created total {len(all_tools)} Langchain tools from {len(tool_infos)} base tools")
272
323
  return all_tools
273
324
 
274
325
  def get_tool(self, name: str) -> Optional[LangchainToolAdapter]:
@@ -0,0 +1,265 @@
1
+ """
2
+ 自动 Schema 生成工具
3
+
4
+ 从方法签名和类型注解自动生成 Pydantic Schema
5
+ """
6
+
7
+ import inspect
8
+ import logging
9
+ from typing import Any, Dict, List, Optional, Type, get_type_hints, Union
10
+ from pydantic import BaseModel, Field, create_model, ConfigDict
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def _normalize_type(param_type: Type) -> Type:
16
+ """
17
+ 标准化类型,处理不支持的类型
18
+
19
+ 将 pandas.DataFrame 等复杂类型映射为 Any
20
+ """
21
+ # 获取类型名称
22
+ type_name = getattr(param_type, '__name__', str(param_type))
23
+
24
+ # 检查是否是 pandas 类型
25
+ if 'DataFrame' in type_name or 'Series' in type_name:
26
+ return Any
27
+
28
+ return param_type
29
+
30
+
31
+ def _extract_param_description_from_docstring(docstring: str, param_name: str) -> Optional[str]:
32
+ """
33
+ 从文档字符串中提取参数描述
34
+
35
+ 支持格式:
36
+ - Google style: Args: param_name: description
37
+ - NumPy style: Parameters: param_name : type description
38
+ """
39
+ if not docstring:
40
+ return None
41
+
42
+ lines = docstring.split('\n')
43
+ in_args_section = False
44
+ current_param = None
45
+ description_lines = []
46
+
47
+ for line in lines:
48
+ stripped = line.strip()
49
+
50
+ # 检测 Args/Parameters 部分
51
+ if stripped in ['Args:', 'Arguments:', 'Parameters:']:
52
+ in_args_section = True
53
+ continue
54
+
55
+ # 检测结束
56
+ if in_args_section and stripped in ['Returns:', 'Raises:', 'Yields:', 'Examples:', 'Note:', 'Notes:']:
57
+ break
58
+
59
+ if in_args_section:
60
+ # Google style: param_name: description 或 param_name (type): description
61
+ if ':' in stripped and not stripped.startswith(' '):
62
+ # 保存之前的参数
63
+ if current_param == param_name and description_lines:
64
+ return ' '.join(description_lines).strip()
65
+
66
+ # 解析新参数
67
+ parts = stripped.split(':', 1)
68
+ if len(parts) == 2:
69
+ # 移除可能的类型注解 (type)
70
+ param_part = parts[0].strip()
71
+ if '(' in param_part:
72
+ param_part = param_part.split('(')[0].strip()
73
+
74
+ current_param = param_part
75
+ description_lines = [parts[1].strip()]
76
+ elif current_param and stripped:
77
+ # 继续描述
78
+ description_lines.append(stripped)
79
+
80
+ # 检查最后一个参数
81
+ if current_param == param_name and description_lines:
82
+ return ' '.join(description_lines).strip()
83
+
84
+ return None
85
+
86
+
87
+ def generate_schema_from_method(
88
+ method: callable,
89
+ method_name: str,
90
+ base_class: Type[BaseModel] = BaseModel
91
+ ) -> Optional[Type[BaseModel]]:
92
+ """
93
+ 从方法签名自动生成 Pydantic Schema
94
+
95
+ Args:
96
+ method: 要生成 Schema 的方法
97
+ method_name: 方法名称
98
+ base_class: Schema 基类
99
+
100
+ Returns:
101
+ 生成的 Pydantic Schema 类,如果无法生成则返回 None
102
+ """
103
+ try:
104
+ # 获取方法签名
105
+ sig = inspect.signature(method)
106
+
107
+ # 获取类型注解
108
+ try:
109
+ type_hints = get_type_hints(method)
110
+ except Exception as e:
111
+ logger.debug(f"Failed to get type hints for {method_name}: {e}")
112
+ type_hints = {}
113
+
114
+ # 获取文档字符串
115
+ docstring = inspect.getdoc(method) or f"Execute {method_name} operation"
116
+
117
+ # 提取简短描述(第一行)
118
+ first_line = docstring.split('\n')[0].strip()
119
+ schema_description = first_line if first_line else f"Execute {method_name} operation"
120
+
121
+ # 构建字段定义
122
+ field_definitions = {}
123
+
124
+ for param_name, param in sig.parameters.items():
125
+ # 跳过 self 参数
126
+ if param_name == 'self':
127
+ continue
128
+
129
+ # 获取参数类型并标准化
130
+ param_type = type_hints.get(param_name, Any)
131
+ param_type = _normalize_type(param_type)
132
+
133
+ # 获取默认值
134
+ has_default = param.default != inspect.Parameter.empty
135
+ default_value = param.default if has_default else ...
136
+
137
+ # 从文档字符串提取参数描述
138
+ field_description = _extract_param_description_from_docstring(docstring, param_name)
139
+ if not field_description:
140
+ field_description = f"Parameter {param_name}"
141
+
142
+ # 创建 Field
143
+ if has_default:
144
+ if default_value is None:
145
+ # Optional 参数
146
+ field_definitions[param_name] = (
147
+ param_type,
148
+ Field(default=None, description=field_description)
149
+ )
150
+ else:
151
+ field_definitions[param_name] = (
152
+ param_type,
153
+ Field(default=default_value, description=field_description)
154
+ )
155
+ else:
156
+ # 必需参数
157
+ field_definitions[param_name] = (
158
+ param_type,
159
+ Field(description=field_description)
160
+ )
161
+
162
+ # 如果没有参数(除了 self),返回 None
163
+ if not field_definitions:
164
+ logger.debug(f"No parameters found for {method_name}, skipping schema generation")
165
+ return None
166
+
167
+ # 生成 Schema 类名
168
+ schema_name = f"{method_name.title().replace('_', '')}Schema"
169
+
170
+ # 创建 Schema 类,允许任意类型
171
+ schema_class = create_model(
172
+ schema_name,
173
+ __base__=base_class,
174
+ __doc__=schema_description,
175
+ __config__=ConfigDict(arbitrary_types_allowed=True),
176
+ **field_definitions
177
+ )
178
+
179
+ logger.debug(f"Generated schema {schema_name} for method {method_name}")
180
+ return schema_class
181
+
182
+ except Exception as e:
183
+ logger.warning(f"Failed to generate schema for {method_name}: {e}")
184
+ return None
185
+
186
+
187
+ def generate_schemas_for_tool(tool_class: Type) -> Dict[str, Type[BaseModel]]:
188
+ """
189
+ 为工具类的所有方法生成 Schema
190
+
191
+ Args:
192
+ tool_class: 工具类
193
+
194
+ Returns:
195
+ 方法名到 Schema 类的映射
196
+ """
197
+ schemas = {}
198
+
199
+ for method_name in dir(tool_class):
200
+ # 跳过私有方法和特殊方法
201
+ if method_name.startswith('_'):
202
+ continue
203
+
204
+ # 跳过基类方法
205
+ if method_name in ['run', 'run_async', 'run_batch']:
206
+ continue
207
+
208
+ method = getattr(tool_class, method_name)
209
+
210
+ # 跳过非方法属性
211
+ if not callable(method):
212
+ continue
213
+
214
+ # 跳过类(如 Config, Schema 等)
215
+ if isinstance(method, type):
216
+ continue
217
+
218
+ # 生成 Schema
219
+ schema = generate_schema_from_method(method, method_name)
220
+
221
+ if schema:
222
+ # 标准化方法名(移除下划线,转小写)
223
+ normalized_name = method_name.replace('_', '').lower()
224
+ schemas[normalized_name] = schema
225
+ logger.info(f"Generated schema for {method_name}")
226
+
227
+ return schemas
228
+
229
+
230
+
231
+
232
+
233
+ # 使用示例
234
+ if __name__ == '__main__':
235
+ import sys
236
+ sys.path.insert(0, '/home/coder1/python-middleware-dev')
237
+
238
+ from aiecs.tools import discover_tools, TOOL_CLASSES
239
+
240
+ # 配置日志
241
+ logging.basicConfig(level=logging.INFO)
242
+
243
+ # 发现工具
244
+ discover_tools()
245
+
246
+ # 为 PandasTool 生成 Schema
247
+ print("为 PandasTool 生成 Schema:")
248
+ print("=" * 80)
249
+
250
+ pandas_tool = TOOL_CLASSES['pandas']
251
+ schemas = generate_schemas_for_tool(pandas_tool)
252
+
253
+ print(f"\n生成了 {len(schemas)} 个 Schema:\n")
254
+
255
+ # 显示前3个示例
256
+ for method_name, schema in list(schemas.items())[:3]:
257
+ print(f"{schema.__name__}:")
258
+ print(f" 描述: {schema.__doc__}")
259
+ print(f" 字段:")
260
+ for field_name, field_info in schema.model_fields.items():
261
+ required = "必需" if field_info.is_required() else "可选"
262
+ default = f" (默认: {field_info.default})" if not field_info.is_required() and field_info.default is not None else ""
263
+ print(f" - {field_name}: {field_info.description} [{required}]{default}")
264
+ print()
265
+
@@ -214,7 +214,7 @@ class ImageTool(BaseTool):
214
214
  """Clean up Tesseract processes on destruction."""
215
215
  self._tesseract_manager.cleanup()
216
216
 
217
- def update_settings(self, config: Dict):
217
+ def update_settings(self, config: Dict) -> None:
218
218
  """
219
219
  Update configuration settings dynamically.
220
220
 
@@ -1,11 +1,20 @@
1
1
  import os
2
2
  import logging
3
+ import warnings
3
4
  from typing import List, Dict, Optional, Any
4
5
 
5
6
  import pandas as pd
6
7
  import pdfplumber
7
8
  import pytesseract
8
9
  from PIL import Image
10
+
11
+ # Configure Tika log path to user-writable directory before importing
12
+ os.environ['TIKA_LOG_PATH'] = os.path.expanduser('~/.cache/tika')
13
+ os.makedirs(os.path.expanduser('~/.cache/tika'), exist_ok=True)
14
+
15
+ # Suppress pkg_resources deprecation warning from tika
16
+ warnings.filterwarnings('ignore', category=UserWarning, module='tika')
17
+
9
18
  from tika import parser
10
19
  from docx import Document as DocxDocument
11
20
  from docx.shared import Pt
@@ -46,7 +46,7 @@ class RenderEngine(str, Enum):
46
46
  PLAYWRIGHT = "playwright"
47
47
 
48
48
  # Global settings
49
- class ScraperSettings(BaseSettings):
49
+ class ScraperSettings(BaseModel):
50
50
  """
51
51
  Configuration for ScraperTool.
52
52
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiecs
3
- Version: 1.0.8
3
+ Version: 1.1.0
4
4
  Summary: AI Execute Services - A middleware framework for AI-powered task execution and tool orchestration
5
5
  Author-email: AIECS Team <iretbl@gmail.com>
6
6
  License-Expression: MIT