coze-coding-utils 0.1.11__tar.gz → 0.2.0__tar.gz

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.
Files changed (38) hide show
  1. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/PKG-INFO +17 -2
  2. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/README.md +1 -1
  3. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/pyproject.toml +18 -1
  4. coze_coding_utils-0.2.0/src/coze_coding_utils/error/__init__.py +31 -0
  5. coze_coding_utils-0.2.0/src/coze_coding_utils/error/classifier.py +320 -0
  6. coze_coding_utils-0.2.0/src/coze_coding_utils/error/codes.py +356 -0
  7. coze_coding_utils-0.2.0/src/coze_coding_utils/error/exceptions.py +439 -0
  8. coze_coding_utils-0.2.0/src/coze_coding_utils/error/patterns.py +939 -0
  9. coze_coding_utils-0.2.0/src/coze_coding_utils/error/test_classifier.py +0 -0
  10. coze_coding_utils-0.2.0/src/coze_coding_utils/file/__init__.py +0 -0
  11. coze_coding_utils-0.2.0/src/coze_coding_utils/file/file.py +327 -0
  12. coze_coding_utils-0.2.0/src/coze_coding_utils/helper/__init__.py +0 -0
  13. coze_coding_utils-0.2.0/src/coze_coding_utils/helper/agent_helper.py +599 -0
  14. coze_coding_utils-0.2.0/src/coze_coding_utils/helper/graph_helper.py +231 -0
  15. coze_coding_utils-0.2.0/src/coze_coding_utils/log/__init__.py +0 -0
  16. coze_coding_utils-0.2.0/src/coze_coding_utils/log/common.py +8 -0
  17. coze_coding_utils-0.2.0/src/coze_coding_utils/log/config.py +10 -0
  18. coze_coding_utils-0.2.0/src/coze_coding_utils/log/err_trace.py +88 -0
  19. coze_coding_utils-0.2.0/src/coze_coding_utils/log/loop_trace.py +72 -0
  20. coze_coding_utils-0.2.0/src/coze_coding_utils/log/node_log.py +487 -0
  21. coze_coding_utils-0.2.0/src/coze_coding_utils/log/parser.py +255 -0
  22. coze_coding_utils-0.2.0/src/coze_coding_utils/log/write_log.py +183 -0
  23. coze_coding_utils-0.2.0/src/coze_coding_utils/messages/__init__.py +0 -0
  24. coze_coding_utils-0.2.0/src/coze_coding_utils/messages/client.py +48 -0
  25. coze_coding_utils-0.2.0/src/coze_coding_utils/messages/server.py +173 -0
  26. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/__init__.py +5 -0
  27. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/converter/__init__.py +6 -0
  28. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/converter/request_converter.py +165 -0
  29. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/converter/response_converter.py +467 -0
  30. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/handler.py +298 -0
  31. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/types/__init__.py +37 -0
  32. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/types/request.py +24 -0
  33. coze_coding_utils-0.2.0/src/coze_coding_utils/openai/types/response.py +178 -0
  34. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/.gitignore +0 -0
  35. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/LICENSE +0 -0
  36. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/src/coze_coding_utils/__init__.py +0 -0
  37. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/src/coze_coding_utils/runtime_ctx/__init__.py +0 -0
  38. {coze_coding_utils-0.1.11 → coze_coding_utils-0.2.0}/src/coze_coding_utils/runtime_ctx/context.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coze-coding-utils
3
- Version: 0.1.11
3
+ Version: 0.2.0
4
4
  Summary: Utilities for Coze coding client runtime context and helpers.
5
5
  Project-URL: Homepage, https://code.byted.org/stone/coze-coding-client
6
6
  Author: Bytedance Stone Team
@@ -12,6 +12,21 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Requires-Python: >=3.10
15
+ Requires-Dist: docx2python==3.5.0
16
+ Requires-Dist: fastapi==0.121.2
17
+ Requires-Dist: langchain-core==1.0.2
18
+ Requires-Dist: langchain-openai==1.0.1
19
+ Requires-Dist: langchain==1.0.3
20
+ Requires-Dist: langgraph-checkpoint==3.0.0
21
+ Requires-Dist: langgraph-prebuilt==1.0.2
22
+ Requires-Dist: langgraph-sdk==0.2.9
23
+ Requires-Dist: langgraph==1.0.2
24
+ Requires-Dist: langsmith==0.4.39
25
+ Requires-Dist: openpyxl==3.1.5
26
+ Requires-Dist: pydantic-core==2.41.4
27
+ Requires-Dist: pydantic==2.12.3
28
+ Requires-Dist: pypdf==6.4.1
29
+ Requires-Dist: python-pptx==1.0.2
15
30
  Description-Content-Type: text/markdown
16
31
 
17
32
  # coze-coding-utils
@@ -39,4 +54,4 @@ Requires Python 3.10+.
39
54
 
40
55
  ## License
41
56
 
42
- MIT
57
+ MIT
@@ -23,4 +23,4 @@ Requires Python 3.10+.
23
23
 
24
24
  ## License
25
25
 
26
- MIT
26
+ MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "coze-coding-utils"
7
- version = "0.1.11"
7
+ version = "0.2.0"
8
8
  description = "Utilities for Coze coding client runtime context and helpers."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -17,6 +17,23 @@ classifiers = [
17
17
  "License :: OSI Approved :: MIT License",
18
18
  "Operating System :: OS Independent",
19
19
  ]
20
+ dependencies = [
21
+ "pydantic==2.12.3",
22
+ "pydantic-core==2.41.4",
23
+ "pypdf==6.4.1",
24
+ "docx2python==3.5.0",
25
+ "openpyxl==3.1.5",
26
+ "python-pptx==1.0.2",
27
+ "langchain==1.0.3",
28
+ "langchain-core==1.0.2",
29
+ "langchain-openai==1.0.1",
30
+ "langgraph==1.0.2",
31
+ "langgraph-checkpoint==3.0.0",
32
+ "langgraph-prebuilt==1.0.2",
33
+ "langgraph-sdk==0.2.9",
34
+ "langsmith==0.4.39",
35
+ "fastapi==0.121.2"
36
+ ]
20
37
 
21
38
  [project.urls]
22
39
  Homepage = "https://code.byted.org/stone/coze-coding-client"
@@ -0,0 +1,31 @@
1
+ """
2
+ VibeCoding Error Module
3
+
4
+ 6位错误码体系设计:
5
+ - 第1位: 错误大类 (1-9)
6
+ - 第2-3位: 错误子类 (01-99)
7
+ - 第4-6位: 具体错误 (001-999)
8
+
9
+ 错误大类:
10
+ 1xxxxx - 代码语法/类型错误 (Code Syntax/Type Errors)
11
+ 2xxxxx - 输入验证错误 (Input Validation Errors)
12
+ 3xxxxx - 外部API错误 (External API Errors)
13
+ 4xxxxx - 资源/文件错误 (Resource/File Errors)
14
+ 5xxxxx - 集成服务错误 (Integration Service Errors)
15
+ 6xxxxx - 业务逻辑错误 (Business Logic Errors)
16
+ 7xxxxx - 运行时错误 (Runtime Errors)
17
+ 8xxxxx - 配置错误 (Configuration Errors)
18
+ 9xxxxx - 未知错误 (Unknown Errors)
19
+ """
20
+
21
+ from .codes import ErrorCode, ErrorCategory
22
+ from .exceptions import VibeCodingError, classify_error
23
+ from .classifier import ErrorClassifier
24
+
25
+ __all__ = [
26
+ "ErrorCode",
27
+ "ErrorCategory",
28
+ "VibeCodingError",
29
+ "classify_error",
30
+ "ErrorClassifier",
31
+ ]
@@ -0,0 +1,320 @@
1
+ """
2
+ 错误分类器 - 提供高层API用于错误分析和统计
3
+ """
4
+
5
+ import logging
6
+ import re
7
+ from collections import defaultdict
8
+ from dataclasses import dataclass, field
9
+ from typing import Optional, Dict, Any, List
10
+
11
+ from .codes import ErrorCategory, get_error_description
12
+ from .exceptions import VibeCodingError, classify_error
13
+ from ..log.err_trace import extract_core_stack
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class ErrorInfo:
20
+ """错误信息结构"""
21
+ code: int
22
+ message: str
23
+ category: ErrorCategory
24
+ category_name: str
25
+ description: str
26
+ original_type: str = ""
27
+ original_message: str = ""
28
+ node_name: str = ""
29
+ task_id: str = ""
30
+
31
+ def to_dict(self) -> Dict[str, Any]:
32
+ return {
33
+ "code": self.code,
34
+ "message": self.message,
35
+ "category": self.category.value,
36
+ "category_name": self.category_name,
37
+ "description": self.description,
38
+ "original_type": self.original_type,
39
+ "node_name": self.node_name,
40
+ "task_id": self.task_id,
41
+ }
42
+
43
+
44
+ @dataclass
45
+ class ErrorStats:
46
+ """错误统计结构"""
47
+ total_count: int = 0
48
+ by_category: Dict[str, int] = field(default_factory=lambda: defaultdict(int))
49
+ by_code: Dict[int, int] = field(default_factory=lambda: defaultdict(int))
50
+ by_node: Dict[str, int] = field(default_factory=lambda: defaultdict(int))
51
+ recent_errors: List[ErrorInfo] = field(default_factory=list)
52
+
53
+ def to_dict(self) -> Dict[str, Any]:
54
+ return {
55
+ "total_count": self.total_count,
56
+ "by_category": dict(self.by_category),
57
+ "by_code": {str(k): v for k, v in self.by_code.items()},
58
+ "by_node": dict(self.by_node),
59
+ "recent_errors": [e.to_dict() for e in self.recent_errors[-10:]], # 最近10个错误
60
+ }
61
+
62
+
63
+ class ErrorClassifier:
64
+ """
65
+ 错误分类器
66
+
67
+ 提供:
68
+ 1. 异常分类: classify() - 将异常转换为带错误码的VibeCodingError
69
+ 2. 错误信息提取: extract_error_info() - 从异常提取结构化错误信息
70
+ 3. 错误统计: 记录和统计错误分布
71
+ """
72
+
73
+ def __init__(self, max_recent_errors: int = 100):
74
+ self._stats = ErrorStats()
75
+ self._max_recent_errors = max_recent_errors
76
+
77
+ def classify(
78
+ self,
79
+ error: BaseException,
80
+ context: Optional[Dict[str, Any]] = None
81
+ ) -> VibeCodingError:
82
+ """
83
+ 分类错误并返回VibeCodingError
84
+
85
+ Args:
86
+ error: 原始异常
87
+ context: 额外上下文 (如 node_name, task_id 等)
88
+
89
+ Returns:
90
+ VibeCodingError: 带有6位错误码的异常
91
+ """
92
+ err = classify_error(error, context)
93
+
94
+ # 更新统计
95
+ self._update_stats(err, context)
96
+
97
+ return err
98
+
99
+ def extract_error_info(
100
+ self,
101
+ error: BaseException,
102
+ context: Optional[Dict[str, Any]] = None
103
+ ) -> ErrorInfo:
104
+ """
105
+ 从异常提取结构化错误信息
106
+
107
+ Args:
108
+ error: 原始异常
109
+ context: 额外上下文
110
+
111
+ Returns:
112
+ ErrorInfo: 结构化错误信息
113
+ """
114
+ err = classify_error(error, context)
115
+ ctx = context or {}
116
+
117
+ return ErrorInfo(
118
+ code=err.code,
119
+ message=err.message,
120
+ category=err.category,
121
+ category_name=err.category.name,
122
+ description=get_error_description(err.code),
123
+ original_type=type(error).__name__,
124
+ original_message=str(error)[:500],
125
+ node_name=ctx.get("node_name", ""),
126
+ task_id=ctx.get("task_id", ""),
127
+ )
128
+
129
+ def get_error_code(
130
+ self,
131
+ error: BaseException,
132
+ context: Optional[Dict[str, Any]] = None
133
+ ) -> int:
134
+ """
135
+ 获取错误码 (简化接口)
136
+
137
+ Args:
138
+ error: 原始异常
139
+ context: 额外上下文
140
+
141
+ Returns:
142
+ int: 6位错误码
143
+ """
144
+ err = classify_error(error, context)
145
+ return err.code
146
+
147
+ def get_error_response(
148
+ self,
149
+ error: BaseException,
150
+ context: Optional[Dict[str, Any]] = None
151
+ ) -> Dict[str, Any]:
152
+ """
153
+ 获取用于API响应的错误信息
154
+
155
+ Args:
156
+ error: 原始异常
157
+ context: 额外上下文
158
+
159
+ Returns:
160
+ dict: 包含 code, message, category 的字典
161
+ """
162
+ err = self.classify(error, context)
163
+ logger.error(f"Error classifier classify error: {error}, traceback: {extract_core_stack()}, get error code: {err.code}, error message: {err.message}, error category: {err.category.name}")
164
+
165
+ return {
166
+ "error_code": err.code,
167
+ "error_message": err.message,
168
+ "error_category": err.category.name,
169
+ }
170
+
171
+ def _update_stats(
172
+ self,
173
+ error: VibeCodingError,
174
+ context: Optional[Dict[str, Any]] = None
175
+ ):
176
+ """更新错误统计"""
177
+ ctx = context or {}
178
+
179
+ self._stats.total_count += 1
180
+ self._stats.by_category[error.category.name] += 1
181
+ self._stats.by_code[error.code] += 1
182
+
183
+ node_name = ctx.get("node_name", "unknown")
184
+ if node_name:
185
+ self._stats.by_node[node_name] += 1
186
+
187
+ # 记录最近的错误
188
+ error_info = ErrorInfo(
189
+ code=error.code,
190
+ message=error.message,
191
+ category=error.category,
192
+ category_name=error.category.name,
193
+ description=get_error_description(error.code),
194
+ original_type=ctx.get("original_type", ""),
195
+ original_message=ctx.get("original_message", "")[:200],
196
+ node_name=node_name,
197
+ task_id=ctx.get("task_id", ""),
198
+ )
199
+ self._stats.recent_errors.append(error_info)
200
+
201
+ # 限制最近错误数量
202
+ if len(self._stats.recent_errors) > self._max_recent_errors:
203
+ self._stats.recent_errors = self._stats.recent_errors[-self._max_recent_errors:]
204
+
205
+ def get_stats(self) -> ErrorStats:
206
+ """获取错误统计"""
207
+ return self._stats
208
+
209
+ def reset_stats(self):
210
+ """重置统计"""
211
+ self._stats = ErrorStats()
212
+
213
+ @staticmethod
214
+ def parse_error_from_log(log_line: str) -> Optional[ErrorInfo]:
215
+ """
216
+ 从日志行解析错误信息
217
+
218
+ 支持解析格式:
219
+ - "During task with name 'xxx' and id 'xxx'"
220
+ - "Before task with name 'xxx'"
221
+ - 标准 Python Traceback
222
+
223
+ Args:
224
+ log_line: 日志行
225
+
226
+ Returns:
227
+ ErrorInfo: 解析出的错误信息,解析失败返回None
228
+ """
229
+ try:
230
+ # 提取任务名称
231
+ node_match = re.search(r"(?:During|Before) task with name '(\w+)'", log_line)
232
+ node_name = node_match.group(1) if node_match else ""
233
+
234
+ # 提取任务ID
235
+ task_match = re.search(r"id '([a-f0-9-]+)'", log_line)
236
+ task_id = task_match.group(1) if task_match else ""
237
+
238
+ # 提取错误类型和消息
239
+ # 格式1: "ExceptionType: message"
240
+ error_match = re.search(r"(\w+Error|\w+Exception): (.+?)(?:\"|\]|$)", log_line)
241
+ if not error_match:
242
+ # 格式2: 在 Traceback 列表中
243
+ error_match = re.search(r"'(\w+Error|\w+Exception): (.+?)'", log_line)
244
+
245
+ if error_match:
246
+ error_type = error_match.group(1)
247
+ error_message = error_match.group(2)
248
+
249
+ # 创建模拟异常进行分类
250
+ mock_error = _create_mock_exception(error_type, error_message)
251
+ err = classify_error(mock_error, {"node_name": node_name, "task_id": task_id})
252
+
253
+ return ErrorInfo(
254
+ code=err.code,
255
+ message=err.message,
256
+ category=err.category,
257
+ category_name=err.category.name,
258
+ description=get_error_description(err.code),
259
+ original_type=error_type,
260
+ original_message=error_message[:200],
261
+ node_name=node_name,
262
+ task_id=task_id,
263
+ )
264
+
265
+ return None
266
+
267
+ except Exception as e:
268
+ logger.warning(f"Failed to parse error from log: {e}")
269
+ return None
270
+
271
+
272
+ def _create_mock_exception(error_type: str, error_message: str) -> BaseException:
273
+ """创建模拟异常用于分类"""
274
+ exception_map = {
275
+ "AttributeError": AttributeError,
276
+ "TypeError": TypeError,
277
+ "ValueError": ValueError,
278
+ "KeyError": KeyError,
279
+ "IndexError": IndexError,
280
+ "NameError": NameError,
281
+ "ImportError": ImportError,
282
+ "ModuleNotFoundError": ModuleNotFoundError,
283
+ "SyntaxError": SyntaxError,
284
+ "IndentationError": IndentationError,
285
+ "RuntimeError": RuntimeError,
286
+ "NotImplementedError": NotImplementedError,
287
+ "TimeoutError": TimeoutError,
288
+ "FileNotFoundError": FileNotFoundError,
289
+ "IOError": IOError,
290
+ "OSError": OSError,
291
+ "MemoryError": MemoryError,
292
+ "RecursionError": RecursionError,
293
+ }
294
+
295
+ # Pydantic ValidationError 特殊处理
296
+ if "ValidationError" in error_type:
297
+ return Exception(f"ValidationError: {error_message}")
298
+
299
+ # API Error 特殊处理
300
+ if "APIError" in error_type:
301
+ return Exception(f"APIError: {error_message}")
302
+
303
+ exception_class = exception_map.get(error_type, Exception)
304
+
305
+ try:
306
+ return exception_class(error_message)
307
+ except Exception:
308
+ return Exception(f"{error_type}: {error_message}")
309
+
310
+
311
+ # 全局分类器实例 (单例模式)
312
+ _global_classifier: Optional[ErrorClassifier] = None
313
+
314
+
315
+ def get_classifier() -> ErrorClassifier:
316
+ """获取全局错误分类器实例"""
317
+ global _global_classifier
318
+ if _global_classifier is None:
319
+ _global_classifier = ErrorClassifier()
320
+ return _global_classifier