zcbot/scripts/diag_run_python_noent.py

82 lines
3.2 KiB
Python

"""诊断 run_python 失败聚集: python: can't open file '<path>': No such file or directory
捞近 7 天 role=tool & name=run_python & content 含 "can't open file" 的消息,
关联 assistant tool_call 的 arguments,看 script_path 形态;并回看同 task 前文
有没有 write/run_python(code) 生成过该文件,判断是「没写就跑」还是「路径基准错」。
"""
import json
import os
from pathlib import Path
env = Path(__file__).resolve().parent.parent / ".env"
for line in env.read_text(encoding="utf-8").splitlines():
if line.strip().startswith("ZCBOT_DB_URL="):
os.environ["ZCBOT_DB_URL"] = line.split("=", 1)[1].strip()
from sqlalchemy import create_engine, text # noqa: E402
engine = create_engine(os.environ["ZCBOT_DB_URL"])
with engine.connect() as conn:
rows = conn.execute(
text(
"select m.task_id, t.user_id, m.idx, m.created_at, "
" m.payload->>'tool_call_id' as tcid, "
" m.payload->>'content' as content "
"from messages m join tasks t on t.task_id = m.task_id "
"where m.created_at >= now() - interval '7 days' "
" and m.payload->>'role' = 'tool' "
" and m.payload->>'name' = 'run_python' "
" and m.payload->>'content' like '%can''t open file%' "
"order by m.created_at"
)
).fetchall()
print(f"[hits] {len(rows)} tool-result messages\n")
for task_id, user_id, idx, created, tcid, content in rows:
tid8 = str(task_id)[:8]
# 找对应 assistant 调用的 arguments
call_row = conn.execute(
text(
"select payload from messages "
"where task_id=:t and payload->>'role'='assistant' and idx < :i "
"order by idx desc limit 20"
),
{"t": task_id, "i": idx},
).fetchall()
args_repr = "?"
for (payload,) in call_row:
for tc in payload.get("tool_calls") or []:
if tc.get("id") == tcid:
args_repr = (tc.get("function") or {}).get("arguments") or "?"
break
if args_repr != "?":
break
# 提取 script_path
sp = None
try:
sp = json.loads(args_repr).get("script_path")
except Exception:
pass
# 回看同 task 前文: 有没有 write 过这个文件 (basename 匹配)
wrote = "?"
if sp:
base = sp.replace("\\", "/").split("/")[-1]
w = conn.execute(
text(
"select count(*) from messages "
"where task_id=:t and idx < :i "
" and payload->>'role'='assistant' "
" and payload::text like :pat"
),
{"t": task_id, "i": idx, "pat": f"%{base}%"},
).scalar()
wrote = f"prior-mentions={w}"
first_line = (content or "").strip().splitlines()
err_line = next((ln for ln in first_line if "can't open file" in ln), "")
print(f"[{tid8}] user={str(user_id)[:8]} idx={idx} {str(created)[:19]}")
print(f" args: {args_repr[:220]}")
print(f" err : {err_line[:220]}")
print(f" ctx : {wrote}")
print()