sycommon-python-lib 0.2.2a1__py3-none-any.whl → 0.2.2a3__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.
@@ -408,21 +408,83 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
408
408
  """用户ID"""
409
409
  return self._user_id
410
410
 
411
- # 沙箱容器内用户数据的实际根目录(与 sandbox server file_ops 路径对齐)
412
- # 线上 Linux 沙箱容器固定为 /data/sycommon_sandbox
413
- # 本地调试(macOS/Windows)使用环境变量 SANDBOX_WORKSPACE 或系统临时目录
414
- _WORKSPACE_ROOT = os.environ.get(
415
- "SANDBOX_WORKSPACE",
416
- "/data/sycommon_sandbox" if sys.platform != "darwin" and sys.platform != "win32"
417
- else os.path.join(tempfile.gettempdir(), "sycommon_sandbox")
418
- )
411
+ # 沙箱容器内用户数据的实际根目录,通过 health 接口从沙箱服务端动态获取。
412
+ # 初始化为 None,首次执行命令时通过 _resolve_workspace_root() 延迟获取。
413
+ _workspace_root: Optional[str] = None
414
+
415
+ def _resolve_workspace_root(self) -> str:
416
+ """同步获取沙箱服务端的 WORKSPACE_BASE,并缓存到实例"""
417
+ if self._workspace_root is not None:
418
+ return self._workspace_root
419
+
420
+ # 优先使用环境变量覆盖
421
+ env_workspace = os.environ.get("SANDBOX_WORKSPACE")
422
+ if env_workspace:
423
+ self._workspace_root = env_workspace
424
+ SYLogger.info(f"[Sandbox] 使用环境变量 SANDBOX_WORKSPACE={env_workspace}")
425
+ return self._workspace_root
426
+
427
+ # 从沙箱服务端 health 接口获取
428
+ try:
429
+ url = f"{self._base_url}{SANDBOX_API_PREFIX}/health"
430
+ resp = requests.get(url, timeout=10)
431
+ if resp.status_code == 200:
432
+ workspace = resp.json().get("workspace", "")
433
+ if workspace:
434
+ self._workspace_root = workspace
435
+ SYLogger.info(f"[Sandbox] 从沙箱服务端获取 WORKSPACE_ROOT={workspace}")
436
+ return self._workspace_root
437
+ except Exception as e:
438
+ SYLogger.warning(f"[Sandbox] 获取沙箱 workspace 失败: {e}")
439
+
440
+ # 兜底:根据平台猜测
441
+ self._workspace_root = "/data/sycommon_sandbox" if sys.platform != "darwin" and sys.platform != "win32" else os.path.join(tempfile.gettempdir(), "sycommon_sandbox")
442
+ SYLogger.warning(f"[Sandbox] 无法获取沙箱 workspace,使用兜底值: {self._workspace_root}")
443
+ return self._workspace_root
444
+
445
+ async def _aresolve_workspace_root(self) -> str:
446
+ """异步获取沙箱服务端的 WORKSPACE_BASE,并缓存到实例"""
447
+ if self._workspace_root is not None:
448
+ return self._workspace_root
449
+
450
+ # 优先使用环境变量覆盖
451
+ env_workspace = os.environ.get("SANDBOX_WORKSPACE")
452
+ if env_workspace:
453
+ self._workspace_root = env_workspace
454
+ SYLogger.info(f"[Sandbox] 使用环境变量 SANDBOX_WORKSPACE={env_workspace}")
455
+ return self._workspace_root
456
+
457
+ # 从沙箱服务端 health 接口获取(aiohttp 异步)
458
+ try:
459
+ url = f"{self._base_url}{SANDBOX_API_PREFIX}/health"
460
+ timeout_obj = aiohttp.ClientTimeout(total=10)
461
+ async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=_SSL_CONTEXT), timeout=timeout_obj) as session:
462
+ async with session.get(url) as resp:
463
+ if resp.status == 200:
464
+ data = await resp.json()
465
+ workspace = data.get("workspace", "")
466
+ if workspace:
467
+ self._workspace_root = workspace
468
+ SYLogger.info(f"[Sandbox] 从沙箱服务端获取 WORKSPACE_ROOT={workspace}")
469
+ return self._workspace_root
470
+ except Exception as e:
471
+ SYLogger.warning(f"[Sandbox] 异步获取沙箱 workspace 失败: {e}")
472
+
473
+ # 兜底
474
+ self._workspace_root = "/data/sycommon_sandbox" if sys.platform != "darwin" and sys.platform != "win32" else os.path.join(tempfile.gettempdir(), "sycommon_sandbox")
475
+ SYLogger.warning(f"[Sandbox] 无法获取沙箱 workspace,使用兜底值: {self._workspace_root}")
476
+ return self._workspace_root
419
477
 
420
478
  def _wrap_command_isolation(self, command: str) -> str:
421
- """包裹命令,确保在用户工作目录下执行
479
+ """同步版本:包裹命令,确保在用户工作目录下执行"""
480
+ workspace_root = self._resolve_workspace_root()
481
+ user_dir = f"{workspace_root}/{self._user_id}"
482
+ return f"mkdir -p {user_dir} && cd {user_dir} && {command.strip()}"
422
483
 
423
- 仅负责工作目录定位,文件系统隔离由沙箱服务端保证。
424
- """
425
- user_dir = f"{self._WORKSPACE_ROOT}/{self._user_id}"
484
+ async def _awrap_command_isolation(self, command: str) -> str:
485
+ """异步版本:包裹命令,确保在用户工作目录下执行"""
486
+ workspace_root = await self._aresolve_workspace_root()
487
+ user_dir = f"{workspace_root}/{self._user_id}"
426
488
  return f"mkdir -p {user_dir} && cd {user_dir} && {command.strip()}"
427
489
 
428
490
  # ============== 执行命令 ==============
@@ -456,7 +518,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
456
518
 
457
519
  async def aexecute(self, command: str, *, timeout: int = None) -> ExecuteResponse:
458
520
  """异步执行 shell 命令(真正的异步实现,带文件系统隔离)"""
459
- isolated_command = self._wrap_command_isolation(command)
521
+ isolated_command = await self._awrap_command_isolation(command)
460
522
  SYLogger.info(f"[Sandbox] aexecute 开始: command={command}")
461
523
  await self._ensure_synced_async()
462
524
  SYLogger.info(f"[Sandbox] _ensure_synced_async 完成,开始执行命令: {command}")
@@ -715,7 +777,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
715
777
  async def aexecute_background(self, command: str, *, timeout: int = 600) -> dict:
716
778
  """异步后台执行 shell 命令(真正的异步实现,带文件系统隔离)"""
717
779
  await self._ensure_synced_async()
718
- isolated_command = self._wrap_command_isolation(command)
780
+ isolated_command = await self._awrap_command_isolation(command)
719
781
  SYLogger.info(f"[Sandbox] 异步后台执行: {command}")
720
782
  try:
721
783
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/execute_background", {
sycommon/llm/get_llm.py CHANGED
@@ -7,13 +7,15 @@ from sycommon.llm.usage_token import LLMWithAutoTokenUsage
7
7
  from typing import Any, Optional, Union
8
8
  from langchain_core.language_models import BaseChatModel
9
9
 
10
+ _TIMEOUT_UNSET = object()
11
+
10
12
 
11
13
  def get_llm(
12
14
  model: Optional[str] = None,
13
15
  *,
14
16
  streaming: bool = False,
15
17
  temperature: Optional[float] = None,
16
- timeout: float = 180,
18
+ timeout: Optional[float] = _TIMEOUT_UNSET,
17
19
  max_retries: int = 3,
18
20
  wrap_structured: bool = True,
19
21
  thinking: bool = False,
@@ -26,7 +28,9 @@ def get_llm(
26
28
  model: 模型名称,如果为 None 则使用配置中 default=True 的模型
27
29
  streaming: 是否启用流式输出
28
30
  temperature: 温度参数,如果为 None 则根据 thinking 模式自动设置
29
- timeout: 请求超时时间(秒),默认180秒
31
+ timeout: 请求超时时间(秒),不传则根据 wrap_structured 自动决定:
32
+ - wrap_structured=True(结构化输出):默认 180 秒
33
+ - wrap_structured=False(普通调用):默认不设超时
30
34
  max_retries: 最大重试次数,默认3次
31
35
  wrap_structured: 是否包装为结构化输出实例,默认True
32
36
  - True: 返回 LLMWithAutoTokenUsage,支持 with_structured_output()
@@ -147,6 +151,10 @@ def get_llm(
147
151
  langfuse_callbacks, langfuse = LangfuseInitializer.get()
148
152
  callbacks = [LLMLogger()] + langfuse_callbacks
149
153
 
154
+ # 根据 wrap_structured 决定默认超时
155
+ if timeout is _TIMEOUT_UNSET:
156
+ timeout = 180 if wrap_structured else None
157
+
150
158
  init_params = {
151
159
  "model_provider": llmConfig.provider,
152
160
  "model": llmConfig.model,
@@ -158,7 +166,6 @@ def get_llm(
158
166
  "timeout": timeout,
159
167
  "max_retries": max_retries,
160
168
  "stream_chunk_timeout": None,
161
- # "model_kwargs": {"response_format": {"type": "json_object"}},
162
169
  }
163
170
 
164
171
  # 合并其他透传参数(包括 presence_penalty, extra_body, top_p 等)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.2a1
3
+ Version: 0.2.2a3
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -126,7 +126,7 @@ sycommon/agent/deep_agent.py,sha256=PUJpvGQNEIgE2TXBvb2i_ux_iDCIl-sQ8iqIS1skXRo,
126
126
  sycommon/agent/multi_agent_team.py,sha256=VIV4r_lxXB6ciLOsoFeF-99l8Rv1jWg4G6QpE5J4cBc,26106
127
127
  sycommon/agent/sandbox/__init__.py,sha256=qEgMJ2FFw0xJsA53M1Ji8kP6wIi_QkTICQYbWN-1h3M,4514
128
128
  sycommon/agent/sandbox/file_ops.py,sha256=eek_hk-hxpLc4cnWzF9cvrtBoSGKhemSsCXKYifMyZY,24622
129
- sycommon/agent/sandbox/http_sandbox_backend.py,sha256=C9jUM68Uo3XgMndQXyw2KeioduD8MC9p0ikj2epJQ1M,47056
129
+ sycommon/agent/sandbox/http_sandbox_backend.py,sha256=Ve_IdycHaq08UpUO0Eq8ffgynPQOipfmkBGZTq3l1Y0,50426
130
130
  sycommon/agent/sandbox/sandbox_pool.py,sha256=eMn8sLakCWf90l6ni2-333QM8oBdX1CflV-WzneFp_k,9133
131
131
  sycommon/agent/sandbox/sandbox_recovery.py,sha256=VDhFI1q9DzSs5B3s2gee1mTmXQoxs0UCXzDrqNQ7VBY,7295
132
132
  sycommon/agent/sandbox/session.py,sha256=TjzC3yFC-VaJ75UwCyL26QX4PRTGNNfQae1FKFuOsYI,2365
@@ -162,7 +162,7 @@ sycommon/heartbeat_process/heartbeat_process_manager.py,sha256=24qUKs8qegdWHqcox
162
162
  sycommon/heartbeat_process/heartbeat_process_worker.py,sha256=duuAEFwda43Y6pZE8tOOspitlyxecaFsg1n1iH9jQDQ,16863
163
163
  sycommon/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
164
  sycommon/llm/embedding.py,sha256=Xwmg1HcgbdW7OcpYyzu8k7U-27rC5lzjIqbg221CcyY,19129
165
- sycommon/llm/get_llm.py,sha256=zMZCGfyRjFnImMdwWNy9b11VyBsCX3S0hyf7SE1iF1Q,7085
165
+ sycommon/llm/get_llm.py,sha256=472LbzRH6TGCz2p3MH1UH2BE0PJ33knSKSY6s2JNs70,7378
166
166
  sycommon/llm/llm_logger.py,sha256=LLXiESwDP5f8dB50nFabShVoLKv8UCf2ll69zo1FOso,3365
167
167
  sycommon/llm/llm_tokens.py,sha256=yGEessxfk5wRMrPGyWHhiiIIQFDVT23FSaqnwqHGCoY,4712
168
168
  sycommon/llm/llm_with_token_tracking.py,sha256=flGN3dbsjw1enal-p5Wh2Fq14F9Z9_O84aOd6kdq4kc,12377
@@ -246,8 +246,8 @@ sycommon/tools/syemail.py,sha256=BDFhgf7WDOQeTcjxJEQdu0dQhnHFPO_p3eI0-Ni3LhQ,561
246
246
  sycommon/tools/timing.py,sha256=OiiE7P07lRoMzX9kzb8sZU9cDb0zNnqIlY5pWqHcnkY,2064
247
247
  sycommon/xxljob/__init__.py,sha256=7eoBlQxv-B39IfRSCY2bkqdGYs1QRe1umAWd88VMEEM,86
248
248
  sycommon/xxljob/xxljob_service.py,sha256=JIEJaGXhqrTLcyxlyynSrsHg9bBnDNzX-D4qIWLRPUE,6815
249
- sycommon_python_lib-0.2.2a1.dist-info/METADATA,sha256=NoQ3Ax44ByOaVYghTZr4cvaPn01OsCtmbBCyFYyLn8I,7683
250
- sycommon_python_lib-0.2.2a1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
251
- sycommon_python_lib-0.2.2a1.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
252
- sycommon_python_lib-0.2.2a1.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
253
- sycommon_python_lib-0.2.2a1.dist-info/RECORD,,
249
+ sycommon_python_lib-0.2.2a3.dist-info/METADATA,sha256=JzdlgU0tqIPnpanKWQWPVrHCKAtpd_gq-8noMxPKdRo,7683
250
+ sycommon_python_lib-0.2.2a3.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
251
+ sycommon_python_lib-0.2.2a3.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
252
+ sycommon_python_lib-0.2.2a3.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
253
+ sycommon_python_lib-0.2.2a3.dist-info/RECORD,,