Files
AgentLab/backend/app/sandbox/interpreter.py
ThearchyHelios 03c18c4d78 界面文案整改:口语改书面、术语统一、不再露出实现细节;修掉几处说错的提示;新增文案检查防回潮
一、文案(前端约 1600 处,后端传到界面的约 880 处)
- 术语统一:工作流层面用「运行」(继续运行、重新运行、试运行),节点和工具层面用「执行」,不再用「跑」;
  总时长 / 执行时长 / 等待审批;服务端;助手;Agent;token;工作流;固定版本;模型接入;系统提示;批准 / 驳回;受管级别
- 口语改书面:取不到、没取回来、读不懂、连不上、多半、照样、兜底、揉成这类说法改成「无法 / 未能 / 失败 / 请」;去掉拟人写法
- 不再露出实现细节:界面上不写 checkpoint、同一拍、哈希(凭证处除外),不写改版历史(「以前…」「老数据」);
  报错、校验、门禁、自动修复里裸写的配置键名和枚举值换成界面上的中文标签,由新的 backend/app/engine/labels.py 统一提供;
  发布弹窗里结论句的选项不再是 off / require_citation
- 同一件事只留一种说法:生成阶段文案、出具档位说明、画布锁定提示各合成一份
- 去掉界面上的工业场景示例(MES、ERP、「张工」「王工」)和真实产品名,换成通用示例

二、说错的提示(都有测试证明)
- 数据库测连接失败时的专用提示以前从不出现(按报错文字全等比较,永远比不上):改为按错误类型判断,不再拼出重复的前缀
- 「设置 → 供应商」改指「设置 → 模型接入」;「在设置里建数据源」改指「数据」页
- 缺少 API Key、模型接入已停用的报错不再夹英文,写明去哪里填
- 两处原因说错(「这种引用在后续版本支持」「这一版还不支持」)改成真实原因
- 节点说明里不准确的说法改正:代码节点在 microVM 或系统沙箱中执行;报告撰写、口径卡的说明不再说过头
- 导出的证据 CSV 里两列同名,第三列改为「片段编号」

三、前后端对齐
- 前端按后端原文识别日志、报错的地方,新旧两种写法都认得(历史运行里存的是旧文字),逐条补了新旧原文的核对
- 后端交回模型的原指令放进单独的 for_model 字段,前端在解析响应时去掉,不会显示到界面上

四、检查
- 检查脚本里按原文匹配的断言改成新文案;改完会变成永远成立的反向断言逐条修正,并做了变异验证
- 新增 check-copy(静态扫描前端界面字符串和后端上界面的文案):再出现「跑」「后端」「多半」「令牌」、
  界面上的 Copilot、裸写的配置键名、半角标点等就报错;确需保留的写进 scripts/copy-allow.json 并注明理由
2026-09-30 08:05:15 +08:00

107 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""给沙箱挑一个看不见后端依赖的 Python 解释器。
原先的做法是「用 `sys.base_prefix` 下的那个」,理由是 venv 会把 FastAPI、
SQLAlchemy、凭据处理那一套挂进 sys.path,而 base_prefix 是干净的标准库环境。
这个假设在 venv 下成立,在 conda 下不成立:conda 环境没有 venv 那层分离,
`sys.prefix == sys.base_prefix`,于是"干净解释器"挑出来的就是项目环境本身,
沙箱代码能直接 `import cryptography` 去解密落库的 API Key。
所以这里不再假设,而是**实际验证**:挨个候选跑一下,看敏感包是否可见。
都不干净时退回当前解释器并加 `-S` 关掉 site-packages —— 标准库照常可用,
第三方包一个也看不见。
"""
from __future__ import annotations
import subprocess
import sys
from functools import lru_cache
from pathlib import Path
# 沙箱里绝不该出现的包。看得见任何一个,这个解释器就不算干净。
# anthropic/openai 带着 provider 客户端,cryptography 能解密落库的 Key,
# sqlalchemy 能直接连库,fastapi 则说明整个后端环境都在。
_SENSITIVE = ("fastapi", "sqlalchemy", "cryptography", "anthropic", "openai")
_PROBE = (
"import importlib.util as u;"
f"print(int(any(u.find_spec(m) for m in {_SENSITIVE!r})))"
)
def _is_clean(exe: str) -> bool:
"""跑一下这个解释器,看敏感包是否可见。探测失败就当它不干净。"""
try:
out = subprocess.run(
[exe, "-c", _PROBE],
capture_output=True, text=True, timeout=10,
)
return out.returncode == 0 and out.stdout.strip() == "0"
except (OSError, subprocess.SubprocessError):
return False
def _candidates() -> list[str]:
"""按优先级列出候选,重复的去掉。
先试 base_prefix(venv 下这就是对的),再试系统自带的 python3
(macOS/Linux 都有,且不会装项目依赖),最后是 Homebrew 的。
"""
base = Path(sys.base_prefix) / "bin"
major, minor = sys.version_info.major, sys.version_info.minor
raw = [
base / f"python{major}.{minor}",
base / f"python{major}",
base / "python",
Path("/usr/bin/python3"),
Path("/usr/local/bin/python3"),
Path("/opt/homebrew/bin/python3"),
]
seen, out = set(), []
for p in raw:
try:
real = str(p.resolve())
except OSError:
continue
if real in seen or not p.exists():
continue
seen.add(real)
out.append(real)
return out
@lru_cache(maxsize=1)
def resolve() -> tuple[str, bool]:
"""返回 (解释器路径, 是否干净)。探测有子进程开销,所以缓存。"""
for exe in _candidates():
if _is_clean(exe):
return exe, True
return str(Path(sys.executable).resolve()), False
def python_argv() -> list[str]:
"""沙箱执行 Python 时的命令前缀(不含脚本名)。
刻意**不用** `-I`:它在 3.11+ 隐含 `-P`,脚本所在目录不会进 sys.path,
于是代码节点的 files 参数(多文件)整个失效 —— `import helper` 报
ModuleNotFoundError。用 `-s -E` 拿到同样的隔离意图(不加 user site、
忽略 PYTHONPATH 之类的环境变量),又不影响同目录 import。
"""
exe, clean = resolve()
flags = ["-s", "-E", "-u"] if clean else ["-S", "-s", "-E", "-u"]
return [exe, *flags]
def describe() -> dict[str, object]:
"""给 health 用:说清楚沙箱到底在用哪个解释器、干不干净。"""
exe, clean = resolve()
return {
"python": exe,
"clean": clean,
"note": (
"解释器无法访问服务端的依赖包"
if clean else
"未找到独立的解释器,已改用 -S 关闭 site-packages(标准库仍可用,第三方包不可见)"
),
}