mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 22:01:58 +00:00
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 并注明理由
107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
"""给沙箱挑一个看不见后端依赖的 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(标准库仍可用,第三方包不可见)"
|
||
),
|
||
}
|