sycommon-python-lib 0.2.3a0__py3-none-any.whl → 0.2.3a2__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.
@@ -231,9 +231,32 @@ class DeepAgent:
231
231
  f"[DeepAgent] AIMessage | content={repr(content_log)} | tools={tc_names}")
232
232
  elif msg_type == "ToolMessage":
233
233
  content_log = (msg.content or "")
234
- preview = content_log[:100]
235
- print(
236
- f"[DeepAgent] ToolResult | {getattr(msg, 'name', '?')} | len={len(content_log)} | preview={repr(preview)}")
234
+ if isinstance(content_log, list):
235
+ # e.g. [{'type': 'image', 'base64': '...'}]
236
+ preview_parts = []
237
+ total_len = 0
238
+ for item in content_log:
239
+ if isinstance(item, dict):
240
+ t = item.get('type', '?')
241
+ if t == 'image' and 'base64' in item:
242
+ b64 = item['base64']
243
+ total_len += len(b64)
244
+ preview_parts.append(
245
+ f"{{'type': 'image', 'base64': '{b64[:100]}...'({len(b64)} chars)}}")
246
+ else:
247
+ s = str(item)
248
+ total_len += len(s)
249
+ preview_parts.append(s[:100])
250
+ else:
251
+ s = str(item)
252
+ total_len += len(s)
253
+ preview_parts.append(s[:100])
254
+ print(
255
+ f"[DeepAgent] ToolResult | {getattr(msg, 'name', '?')} | len={total_len} | preview={preview_parts}")
256
+ else:
257
+ preview = str(content_log)[:100]
258
+ print(
259
+ f"[DeepAgent] ToolResult | {getattr(msg, 'name', '?')} | len={len(str(content_log))} | preview={repr(preview)}")
237
260
  elif msg_type == "HumanMessage":
238
261
  content_log = (msg.content or "")[:100]
239
262
  print(
@@ -506,6 +529,11 @@ class DeepAgent:
506
529
  return
507
530
  except (APIConnectionError, APIError, APITimeoutError, ConnectionError, httpx.RemoteProtocolError) as e:
508
531
  last_error = e
532
+ # 400 BadRequestError 不重试:请求参数有误,重试无意义
533
+ from openai import BadRequestError
534
+ if isinstance(e, BadRequestError):
535
+ SYLogger.error(f"[DeepAgent] API 参数错误,不重试: {e}")
536
+ raise
509
537
  if attempt < max_retries - 1:
510
538
  delay = base_delay * (2 ** attempt)
511
539
  SYLogger.warning(
@@ -266,8 +266,12 @@ class FileOperationsMixin:
266
266
  "limit": limit
267
267
  }, timeout=timeout)
268
268
  if result.get("error"):
269
- SYLogger.error(f"[Sandbox] 异步读取文件失败: {result['error']}")
270
- return ReadResult(error=result["error"])
269
+ err_msg = result['error']
270
+ if 'not found' in err_msg:
271
+ SYLogger.warning(f"[Sandbox] 异步读取文件未找到: {err_msg}")
272
+ else:
273
+ SYLogger.error(f"[Sandbox] 异步读取文件失败: {err_msg}")
274
+ return ReadResult(error=err_msg)
271
275
  content = result.get("content", "")
272
276
  encoding = result.get("encoding", "utf-8")
273
277
  SYLogger.info(
@@ -329,7 +333,11 @@ class FileOperationsMixin:
329
333
  path=result.get("path")
330
334
  )
331
335
  if write_result.error:
332
- SYLogger.error(f"[Sandbox] 异步写入失败: {write_result.error}")
336
+ err_msg = write_result.error
337
+ if 'already exists' in err_msg:
338
+ SYLogger.warning(f"[Sandbox] 异步写入文件已存在: {err_msg}")
339
+ else:
340
+ SYLogger.error(f"[Sandbox] 异步写入失败: {err_msg}")
333
341
  else:
334
342
  SYLogger.info(f"[Sandbox] 异步写入成功: {write_result.path}")
335
343
  return write_result
@@ -61,10 +61,10 @@ class LangfuseInitializer(metaclass=SingletonMeta):
61
61
  'baseUrl', '')
62
62
  os.environ["LANGFUSE_TRACING_ENVIRONMENT"] = environment
63
63
  os.environ["OTEL_SERVICE_NAME"] = server_name
64
- # 设置 OTLP 追踪导出器超时时间(单位:秒)
65
- os.environ["OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"] = "60"
66
- # 全局 OTLP 超时(覆盖所有信号:追踪/指标/日志)
67
- os.environ["OTEL_EXPORTER_OTLP_TIMEOUT"] = "60"
64
+ # 控制 Langfuse OTLP 导出:超时 30s、每批最多 32 个 span、每 10s 强制 flush
65
+ os.environ["LANGFUSE_TIMEOUT"] = "30"
66
+ os.environ["LANGFUSE_FLUSH_AT"] = "32"
67
+ os.environ["LANGFUSE_FLUSH_INTERVAL"] = "10"
68
68
 
69
69
  self._langfuse_client = get_client()
70
70
 
@@ -5,6 +5,9 @@
5
5
 
6
6
  通过 wrap_tool_call / awrap_tool_call 钩子拦截每个工具调用结果,
7
7
  在结果进入对话历史之前完成截断。
8
+
9
+ 同时处理 list 类型 content(如 read_file 读取图片返回的 base64 数据),
10
+ 将其转换为字符串描述,防止上游 API 拒绝 list content 的 400 错误。
8
11
  """
9
12
 
10
13
  from collections.abc import Awaitable, Callable
@@ -41,6 +44,41 @@ DEFAULT_TRUNCATION_SUFFIX = (
41
44
  "2. 将输出重定向到文件后用 read_file 分段读取]"
42
45
  )
43
46
 
47
+ # list 类型 content 中 base64 图片的最大字符数
48
+ MAX_IMAGE_BASE64_CHARS = 500
49
+
50
+
51
+ def _convert_list_content_to_str(content: list, tool_name: str) -> str:
52
+ """将 list 类型的 ToolMessage.content 转换为字符串。
53
+
54
+ 对于图片类型(type=image 且含 base64),只保留前 MAX_IMAGE_BASE64_CHARS 个字符的 base64 预览。
55
+ 对于文本类型,保留完整文本。
56
+ """
57
+ parts = []
58
+ for item in content:
59
+ if isinstance(item, dict):
60
+ item_type = item.get("type", "text")
61
+ if item_type == "image" and "base64" in item:
62
+ b64 = item["base64"]
63
+ mime = item.get("mime_type", "image/unknown")
64
+ if len(b64) > MAX_IMAGE_BASE64_CHARS:
65
+ parts.append(
66
+ f"[图片文件 ({mime}, {len(b64)} 字符 base64 数据), "
67
+ f"预览: {b64[:MAX_IMAGE_BASE64_CHARS]}...]"
68
+ )
69
+ else:
70
+ parts.append(
71
+ f"[图片文件 ({mime}, {len(b64)} 字符 base64 数据), "
72
+ f"数据: {b64}]"
73
+ )
74
+ elif "text" in item:
75
+ parts.append(item["text"])
76
+ else:
77
+ parts.append(str(item))
78
+ else:
79
+ parts.append(str(item))
80
+ return "\n".join(parts)
81
+
44
82
 
45
83
  class ToolResultTruncationMiddleware(AgentMiddleware):
46
84
  """截断过长的工具结果,防止超出模型上下文窗口。
@@ -102,6 +140,27 @@ class ToolResultTruncationMiddleware(AgentMiddleware):
102
140
  return result
103
141
 
104
142
  content = result.content
143
+
144
+ # list 类型 content:如 read_file 读取图片返回的 base64 数据
145
+ # 转换为字符串描述,防止上游 API 拒绝 list content
146
+ if isinstance(content, list):
147
+ has_image = any(
148
+ isinstance(item, dict) and item.get("type") == "image" and "base64" in item
149
+ for item in content
150
+ )
151
+ if has_image:
152
+ new_content = _convert_list_content_to_str(content, tool_name)
153
+ SYLogger.info(
154
+ f"[ToolResultTruncation] tool='{tool_name}' converted image "
155
+ f"list content to string ({len(new_content)} chars)")
156
+ return ToolMessage(
157
+ content=new_content,
158
+ tool_call_id=result.tool_call_id,
159
+ name=result.name,
160
+ status=result.status,
161
+ artifact=result.artifact,
162
+ )
163
+
105
164
  if not isinstance(content, str):
106
165
  return result
107
166
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.3a0
3
+ Version: 0.2.3a2
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -129,11 +129,11 @@ sycommon/services.py,sha256=N6Z4D-qmdyGBZ5z72j2dtSfpXnrnWjEuSyKCgSIY0Cs,21332
129
129
  sycommon/agent/__init__.py,sha256=PXxUiDwdzxv3WQfD8R5MKXtV7qZPvbRc0wPxnS-ZsNQ,3752
130
130
  sycommon/agent/agent_manager.py,sha256=UhhaekEumT7g4v_Z1UB4jTp13X0n8M8erYaQdkGGWkA,13620
131
131
  sycommon/agent/chat_events.py,sha256=bWAMWYIZ2L_yqUcn5jq9ius_lQxLHEv4zQLEqX6UaeM,13190
132
- sycommon/agent/deep_agent.py,sha256=b09KJbtf-mb33GgKjRkENRv6VN494kA3n4dBqEY_mmA,28651
132
+ sycommon/agent/deep_agent.py,sha256=Ptbz-NKJ1hFhMULxdG7TjQo0hAQ5ULuMQOcjaEg5l8E,30393
133
133
  sycommon/agent/multi_agent_team.py,sha256=zsJNjVx0U5qPXlQO-tgAbKotsfL1LMPZvvouxUQGbwY,26466
134
134
  sycommon/agent/summarization_utils.py,sha256=Fz6xY6DkLXoUfqQVsz8uZrMvxTtEYEJBcDl6pqFJnRk,2242
135
135
  sycommon/agent/sandbox/__init__.py,sha256=jR7LlkD4J4Y6QYyRXQClkwmqDBCCPmycV_hQV9p9YHw,4621
136
- sycommon/agent/sandbox/file_ops.py,sha256=2LJNm0bQZj_l1FtpcDUtOBSQUK-Sd2vVZyc1JbNBhXk,22779
136
+ sycommon/agent/sandbox/file_ops.py,sha256=6ymRMM0WchM7G_YmF1ckrLjf5s_JCh1wrAp2g_-sg8k,23162
137
137
  sycommon/agent/sandbox/http_sandbox_backend.py,sha256=mjiTZnADvUq_rO05ewllo_eGDS4uTdD2e2GGYvBpF-Q,56150
138
138
  sycommon/agent/sandbox/minio_sync.py,sha256=r6tjoQA8AHNVG_hcHS3enfFnw-eTkW4r7jA7bwatsWc,19241
139
139
  sycommon/agent/sandbox/sandbox_pool.py,sha256=eMn8sLakCWf90l6ni2-333QM8oBdX1CflV-WzneFp_k,9133
@@ -178,7 +178,7 @@ sycommon/llm/llm_with_token_tracking.py,sha256=flGN3dbsjw1enal-p5Wh2Fq14F9Z9_O84
178
178
  sycommon/llm/native_with_fallback_runnable.py,sha256=8g2q8cRqJv2miY7GrZz_f-zNmHxdb_5WSujD3frqObQ,8035
179
179
  sycommon/llm/output_fixing_runnable.py,sha256=wGHBKRpUjDz4ONJulTvG5UzJxZr1iK3ULkosaKqjF0w,8113
180
180
  sycommon/llm/struct_token.py,sha256=nXNcncRu3HfXxPXaJoG6AFAdFSNb3oJ4t0mz_TLL6Ow,19809
181
- sycommon/llm/sy_langfuse.py,sha256=fkfPxXhz65GcCRPNm202xxCNzgCODNh-QNmlDdTU4kM,4459
181
+ sycommon/llm/sy_langfuse.py,sha256=27RyPUkScqJYHrupOEyUs23fDszoaA66FFgv5Qc7-B4,4443
182
182
  sycommon/llm/token_usage_es_service.py,sha256=-RBCwZ8jS436n8DBUBm3Lf5O6TsQMaQgIj5oYBLO4Ss,19909
183
183
  sycommon/llm/token_usage_mysql_service.py,sha256=1WhdpZ8M4v4UNP5W0ui3A-Cx5yfZiX73l77FTJvL_d8,32644
184
184
  sycommon/llm/usage_token.py,sha256=E_umP6qjN5AZU_2XLXGpWdLxQ8VVKSf74B5RmqBQk2A,7780
@@ -201,7 +201,7 @@ sycommon/middleware/mq.py,sha256=9X6KKtadFjBXKS5L3kEKujYio9wwGfWgXwWOAHO-HDg,254
201
201
  sycommon/middleware/sandbox.py,sha256=SQnUvVE0gvBo_YrP4fdA-6ZmJxAG9Po1zUynNFrgTI4,61109
202
202
  sycommon/middleware/timeout.py,sha256=KlxOPa8xl2dg6yuRi_EzkVJG8bX4stb5ueYxctzzGM8,1433
203
203
  sycommon/middleware/token_tracking.py,sha256=rEbgV1bgWMdzAERx4aq5XAvOIT6jTY_tK1P0xHJnL3o,6609
204
- sycommon/middleware/tool_result_truncation.py,sha256=KR7obBZJhpunhpQaATBE22H2SeXNZlsVH3zL3efEt5o,4557
204
+ sycommon/middleware/tool_result_truncation.py,sha256=p_v3XGYxO7UIrTaxmmFbDYadIHUfXk8HbZ_WVcxJrrQ,7041
205
205
  sycommon/middleware/traceid.py,sha256=HX4zg7Tp_mPNr2eWDDvK3f7GFJ6eOSeW062Xcc-xshc,14340
206
206
  sycommon/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
207
207
  sycommon/models/base_http.py,sha256=EICAAibx3xhjBsLqm35Mi3DCqxp0FME4rD_3iQVjT_E,3051
@@ -257,8 +257,8 @@ sycommon/tools/syemail.py,sha256=BDFhgf7WDOQeTcjxJEQdu0dQhnHFPO_p3eI0-Ni3LhQ,561
257
257
  sycommon/tools/timing.py,sha256=OiiE7P07lRoMzX9kzb8sZU9cDb0zNnqIlY5pWqHcnkY,2064
258
258
  sycommon/xxljob/__init__.py,sha256=7eoBlQxv-B39IfRSCY2bkqdGYs1QRe1umAWd88VMEEM,86
259
259
  sycommon/xxljob/xxljob_service.py,sha256=JIEJaGXhqrTLcyxlyynSrsHg9bBnDNzX-D4qIWLRPUE,6815
260
- sycommon_python_lib-0.2.3a0.dist-info/METADATA,sha256=VusXz0MfTQ622eAN2iRy9I16ZjZTrxQN3cPO5rcDe7M,7740
261
- sycommon_python_lib-0.2.3a0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
262
- sycommon_python_lib-0.2.3a0.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
263
- sycommon_python_lib-0.2.3a0.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
264
- sycommon_python_lib-0.2.3a0.dist-info/RECORD,,
260
+ sycommon_python_lib-0.2.3a2.dist-info/METADATA,sha256=_JyFaU2brTdZJKEKeceWFhgTP1ee62Hr7PurpTSy5rE,7740
261
+ sycommon_python_lib-0.2.3a2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
262
+ sycommon_python_lib-0.2.3a2.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
263
+ sycommon_python_lib-0.2.3a2.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
264
+ sycommon_python_lib-0.2.3a2.dist-info/RECORD,,