"""run_python 语法预检:宿主侧 compile() 拦下语法坏码,返回中文感知的锐化诊断。 背景(2026-07,工具失败面板最大头:run_python/exit SyntaxError,20 条真实样本): 模型手写把中文正文硬拼进 Python 源码生成 docx/pptx(python-docx `T("中文…")`), 引号/标点崩坏 → SyntaxError → 改 → 再崩,同一文件一分钟内连撞 6 次烧 token。三类: - A 引号提前闭合(最多):中文串里用了 ASCII 引号 `"` 把外层字符串提前闭合, Python 却报 `Perhaps you forgot a comma?` / `unterminated string`(**主动误导** —— 模型照着加逗号越修越错)。 - B 全角标点漏进代码位:`center=True、`、`采购(` —— `invalid character 'X' (U+XXXX)`。 - C 括号/引号结构崩:mangled 内联命令、未闭合三引号。 预检零误伤:host 3.12 ≡ sandbox 3.12,compile() 只解析不执行(与依赖无关);compile 通过则原样放行、行为不变,不通过则本就跑不了 → 提前返更准的话 + 省一次 docker 往返。 另有协同:预检结果以 `[Error]` 前缀返回,run_python 语法失败从 `[stderr]…[exit 1]` 变成 `[Error]` 形态,loop._RepeatGuard 的 err-streak 得以兜住「反复交语法坏码」的循环 (旧的 `[exit 1]` 形态它按非错误放行、抓不到)。 不 import litellm/任何重依赖 —— 纯 stdlib,`tests/test_pysyntax.py` 本机可跑 (loop.py 顶层 import litellm 在本机导入期卡死,守卫逻辑单列才测得了)。 """ from __future__ import annotations from typing import Optional def _has_cjk(s: str) -> bool: return any("一" <= c <= "鿿" for c in s) def precheck_python(code: Optional[str]) -> Optional[str]: """对 Python 源码做语法预检。通过返回 None;不通过返回锐化的中文诊断([Error] 前缀)。""" if not isinstance(code, str) or not code.strip(): return None # 空/非字符串交给现有 bad-arguments 分支,不在此判 try: compile(code, "