sycommon-python-lib 0.2.7a20__py3-none-any.whl → 0.2.7a22__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.
@@ -61,7 +61,13 @@ _PATH_TOOLS = {
61
61
 
62
62
  # 宿主沙箱根前缀(用于 execute 命令串扫描;shell 里无法安全改写,只能拦)。
63
63
  # 命中即视为「引用了宿主沙箱真实路径」,一律拦。
64
- _HOST_SANDBOX_RE = re.compile(re.escape(_WORKSPACE_ROOT) + r'(?:/|\\)')
64
+ # 注意:要拦到「根目录本身」和「根下子路径」两种形式。原来要求尾斜杠
65
+ # (_WORKSPACE_ROOT/),会漏过 `find /data/sycommon_sandbox -name x`(后跟空格,
66
+ # 没有尾斜杠)这种「拿沙箱根当 find 起点」的越权扫描。改为允许「尾斜杠」或
67
+ # 「词边界(后跟空白/行尾/引号)」,根目录本身与任意子路径都能命中。
68
+ _HOST_SANDBOX_RE = re.compile(
69
+ re.escape(_WORKSPACE_ROOT) + r'(?:[/\\]|(?=\s|$|["\']))'
70
+ )
65
71
 
66
72
  _DENIED_MSG = (
67
73
  "Error: 不允许使用宿主机绝对路径访问沙箱文件。"
@@ -351,6 +351,46 @@ def _kill_process_tree(process):
351
351
  pass
352
352
 
353
353
 
354
+ def _translate_virtual_prefixes(command: str) -> str:
355
+ """把 execute 命令里的沙箱虚拟路径前缀翻译成 $SANDBOX_ROOT 前缀。
356
+
357
+ 根因:read_file/ls 等文件工具认虚拟路径(/skills/...、/output/...,由服务端
358
+ resolve_sandbox_path 映射);但 execute 里的 shell(cat/ls/cp/python 等)把
359
+ /skills/ 当真·文件系统绝对路径,沙箱根 / 下没有 /skills → "No such file"。
360
+ agent 因此误判「execute 受限」改走 read_file。
361
+
362
+ 这里在命令交给 shell 前,把"作为路径参数出现"的虚拟前缀替换成 $SANDBOX_ROOT。
363
+ 关键是**只替换 token 边界**(前导是空格/引号/行首/重定向符/`=`),不替换
364
+ 字符串中间出现的,避免误伤(如命令里恰好有形如片段的普通字符串)。
365
+
366
+ 仅替换这些已知虚拟前缀;其余路径(用户工作目录下的相对路径、真绝对路径)不动。
367
+ 对已是 $SANDBOX_ROOT/... 形式的不重复处理(无 /skills/ token)。
368
+ """
369
+ if not command or "$SANDBOX_ROOT" in command:
370
+ # 用户已显式用 $SANDBOX_ROOT 时,尊重其写法,不再二次翻译
371
+ # (避免把命令里独立出现的 /skills/ 等误改,多数情况一次替换就够)
372
+ return command
373
+
374
+ import re
375
+ # 虚拟前缀 → 沙箱子目录(与 resolve_sandbox_path 的映射保持一致)
376
+ # 顺序无关紧要,前缀互不互为子串(skills/ vs memory/ vs output/ ...)。
377
+ prefixes = [
378
+ "skills", "memory", "output", "projects", "data",
379
+ "conversation_history", "large_tool_results", "tmp",
380
+ ]
381
+
382
+ # token 边界:前导是 空白/引号/重定向(|<>)/行首/=,后接虚拟前缀名再接 /
383
+ # 用负向零宽断言匹配边界,避免命中 "my-skills/"、"some/output/" 这种子串。
384
+ out = command
385
+ for pfx in prefixes:
386
+ pattern = re.compile(
387
+ r'(?:(?<=\s)|(?<=\")|(?<=\')|(?<=^)|(?<==)|(?<=\|)|(?<=<)|(?<=>))'
388
+ + re.escape("/" + pfx + "/")
389
+ )
390
+ out = pattern.sub("$SANDBOX_ROOT/" + pfx + "/", out)
391
+ return out
392
+
393
+
354
394
  def _build_execute_command(init_script: str, user_command: str) -> tuple[str, dict]:
355
395
  """构建跨平台的执行命令。
356
396
 
@@ -458,8 +498,15 @@ def setup_sandbox_handler(app: FastAPI, config: dict = None):
458
498
  # 使用统一初始化脚本
459
499
  init_script = _build_init_script(workspace)
460
500
 
501
+ # 把命令里的虚拟路径前缀(/skills/、/output/...)翻译成 $SANDBOX_ROOT,
502
+ # 让 cat/ls/cp/python 等 shell 命令能访问到技能/产物文件(否则 No such file)。
503
+ translated_command = _translate_virtual_prefixes(req.command)
504
+ if translated_command != req.command:
505
+ SYLogger.info(
506
+ f"[Sandbox Server] 虚拟前缀翻译: {req.command!r} -> {translated_command!r}")
507
+
461
508
  # 构建跨平台执行命令
462
- full_command, _ = _build_execute_command(init_script, req.command)
509
+ full_command, _ = _build_execute_command(init_script, translated_command)
463
510
 
464
511
  # 设置环境变量
465
512
  env = os.environ.copy()
@@ -588,6 +635,27 @@ def setup_sandbox_handler(app: FastAPI, config: dict = None):
588
635
  SYLogger.info(f"[Sandbox Server] 目录内容: {len(result)} 项")
589
636
  return result
590
637
 
638
+ def _looks_like_text(raw_prefix: bytes) -> bool:
639
+ """粗判一段字节是否为文本(用于 /read 决定按文本还是二进制返回)。
640
+
641
+ 对齐 deepagents BaseSandbox.read 的检测协议(backends/sandbox.py:315-325):
642
+ 用增量 UTF-8 解码器,8192 字节前缀若正好截断在多字节字符(中文 3 字节、
643
+ emoji 4 字节)中间,增量解码器会缓存尾部半截序列、不报错;只有真遇到
644
+ 非法字节序列才抛 UnicodeDecodeError。
645
+
646
+ 旧实现 raw_prefix.decode('utf-8')(strict)会在「中文被 8192 腰斩」时
647
+ 必抛 UnicodeDecodeError,把正常的中文文本文件误判成「二进制」,导致
648
+ /read 返回 base64 乱码、agent 只能退而用 grep 兜底。
649
+ """
650
+ if not raw_prefix:
651
+ return True
652
+ import codecs
653
+ try:
654
+ codecs.getincrementaldecoder('utf-8')().decode(raw_prefix, final=False)
655
+ return True
656
+ except UnicodeDecodeError:
657
+ return False
658
+
591
659
  @sandbox_router.post("/read", response_model=ReadResponse)
592
660
  async def read_file(req: ReadRequest):
593
661
  """读取文件内容"""
@@ -628,11 +696,10 @@ def setup_sandbox_handler(app: FastAPI, config: dict = None):
628
696
  with open(file_path, 'rb') as f:
629
697
  raw_prefix = f.read(8192)
630
698
 
631
- try:
632
- raw_prefix.decode('utf-8')
633
- is_text = True
634
- except UnicodeDecodeError:
635
- is_text = False
699
+ # 文本/二进制判定:旧版整段 strict decode 会在「中文被 8192 截断在
700
+ # 多字节边界」时误判为二进制。改用 _looks_like_text(errors='ignore' +
701
+ # 控制字符占比),既修截断 bug 又能挡住真二进制。
702
+ is_text = _looks_like_text(raw_prefix)
636
703
 
637
704
  if is_text:
638
705
  lines = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.7a20
3
+ Version: 0.2.7a22
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -147,7 +147,7 @@ sycommon/agent/acp/tool.py,sha256=yt6ohKL2y7wIZMNiLv-m5oCg5u1p5GAbqgjzQVt285Y,10
147
147
  sycommon/agent/mcp/__init__.py,sha256=iKrdDhIrFsNIkqG_kgcwNe-nOiM6uVfolKv44LfQ-FQ,636
148
148
  sycommon/agent/mcp/models.py,sha256=zda4ho-UTYOJ5oPAZPZ-vxhfDRLghUCsMroHnA2A2QQ,1490
149
149
  sycommon/agent/mcp/tool_loader.py,sha256=OQa-lE7RL2s3Lqh-kNOKaUrb130hvorB_HjyFBqZBZs,10960
150
- sycommon/agent/middleware/sandbox_path_guard.py,sha256=5hgtf-9aqJ16BQuDwda3gXL12RbwPcexhYQPEV6H33M,7684
150
+ sycommon/agent/middleware/sandbox_path_guard.py,sha256=K1SnxA8pDxkCSucOkranwUvC9_8rd3l_-TIR8gMMTK8,8102
151
151
  sycommon/agent/middleware/sensitive_guard.py,sha256=ApmC094ogG4jIwEWRaUawTpQSDs722k0OTjdeAEQ7Qc,22159
152
152
  sycommon/agent/middleware/sitecustomize.py,sha256=Bt7XFnWV_LJo89l858AGp5VUkXwefpLGmjkCtLe-CMw,4800
153
153
  sycommon/agent/middleware/skill_api_whitelist.py,sha256=h3CntW-FIdAfrKMo4QoC6lA35f8Y1iH7hcHldYMi4lw,10946
@@ -234,7 +234,7 @@ sycommon/middleware/exception.py,sha256=UAy0tKijI_2JoKjwT3h62aL-tybftP3IETvcr26N
234
234
  sycommon/middleware/middleware.py,sha256=1qA_0rT7pv1xTfuvA0kdYkxVOHYT6roSSNO7Cmf2wYg,1778
235
235
  sycommon/middleware/monitor_memory.py,sha256=pYRK-wRuDd6enSg9Pf8tQxPdYQS6S0AyjyXeKFRLKEs,628
236
236
  sycommon/middleware/mq.py,sha256=9X6KKtadFjBXKS5L3kEKujYio9wwGfWgXwWOAHO-HDg,254
237
- sycommon/middleware/sandbox.py,sha256=-yjqpW_qI4AukS-0w9xgjHPQ7IOYm4AwUv_acfZaFqI,50543
237
+ sycommon/middleware/sandbox.py,sha256=BfbVYeYgzbndOc60Cu0ZJbUby1YFOT-q0G_h5AhxVjw,54340
238
238
  sycommon/middleware/timeout.py,sha256=KlxOPa8xl2dg6yuRi_EzkVJG8bX4stb5ueYxctzzGM8,1433
239
239
  sycommon/middleware/token_tracking.py,sha256=rEbgV1bgWMdzAERx4aq5XAvOIT6jTY_tK1P0xHJnL3o,6609
240
240
  sycommon/middleware/tool_result_truncation.py,sha256=SREo6tb_RDHxqiQdO0N82pio-Cpo0YSrHNa1sASUafM,12429
@@ -308,8 +308,8 @@ sycommon/tools/syemail.py,sha256=BDFhgf7WDOQeTcjxJEQdu0dQhnHFPO_p3eI0-Ni3LhQ,561
308
308
  sycommon/tools/timing.py,sha256=OiiE7P07lRoMzX9kzb8sZU9cDb0zNnqIlY5pWqHcnkY,2064
309
309
  sycommon/xxljob/__init__.py,sha256=7eoBlQxv-B39IfRSCY2bkqdGYs1QRe1umAWd88VMEEM,86
310
310
  sycommon/xxljob/xxljob_service.py,sha256=1yifwIBNGsCIxLnQjHKiBlbsigc_zvPH-dMTZcNxe-Q,7649
311
- sycommon_python_lib-0.2.7a20.dist-info/METADATA,sha256=34Y3tVpqqgzuEpvEynWkcxmfpd3XzzuR_CcGBWgsVyU,7962
312
- sycommon_python_lib-0.2.7a20.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
313
- sycommon_python_lib-0.2.7a20.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
314
- sycommon_python_lib-0.2.7a20.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
315
- sycommon_python_lib-0.2.7a20.dist-info/RECORD,,
311
+ sycommon_python_lib-0.2.7a22.dist-info/METADATA,sha256=O2pYEf0WwGJmrL74b_5LZ9TWxd1JBt5xsQo0yQZ3SV4,7962
312
+ sycommon_python_lib-0.2.7a22.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
313
+ sycommon_python_lib-0.2.7a22.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
314
+ sycommon_python_lib-0.2.7a22.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
315
+ sycommon_python_lib-0.2.7a22.dist-info/RECORD,,