"""按 email + 任务名 dump 一个 task 的完整对话记录(ASCII 标签,Windows GBK 安全)。""" import json import os import sys 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 import builtins # noqa: E402 _out = open(Path(__file__).resolve().parent / "_task_dump.txt", "w", encoding="utf-8") def print(*a, **k): # noqa: A001 - redirect to utf-8 file builtins.print(*a, **k, file=_out) engine = create_engine(os.environ["ZCBOT_DB_URL"]) email = sys.argv[1] if len(sys.argv) > 1 else "caoqianming@foxmail.com" name_like = sys.argv[2] if len(sys.argv) > 2 else "生图测试" def s(x, n=4000): t = str(x or "") return t if len(t) <= n else t[:n] + f"...[+{len(t)-n} chars]" with engine.connect() as conn: uid = conn.execute(text("select user_id from users where email=:e"), {"e": email}).fetchone() if not uid: print("[NO USER]", email) sys.exit(1) uid = uid[0] rows = conn.execute( text("select task_id,name,skill,model,model_profile,status,run_status,run_error," "tokens_prompt,tokens_completion,created_at,updated_at from tasks " "where user_id=:u and name like :n order by created_at"), {"u": uid, "n": "%" + name_like + "%"}, ).fetchall() print(f"[USER] {email} matched tasks: {len(rows)}") for r in rows: print(f" task={r[0]} name={r[1]!r} skill={r[2]!r} model={r[3]}/{r[4]} " f"status={r[5]} run={r[6]} tok={r[8]}/{r[9]} created={r[10]}") if r[7]: print(f" run_error: {s(r[7], 500)}") if not rows: sys.exit(0) tid = rows[-1][0] print(f"\n========== DUMP task {tid} ==========") msgs = conn.execute( text("select idx,payload,model_profile,tokens_in,tokens_out from messages " "where task_id=:t order by idx"), {"t": tid}, ).fetchall() print(f"messages: {len(msgs)}\n") for idx, p, mp, ti, to in msgs: role = p.get("role") head = f"[{idx}] {role}" if mp: head += f" ({mp})" if ti or to: head += f" tok={ti}/{to}" print(head) content = p.get("content") if content: print(" content:", s(content, 3000)) for tc in p.get("tool_calls") or []: fn = tc.get("function") or {} print(f" CALL {fn.get('name')}({s(fn.get('arguments'), 1500)})") if role == "tool": print(f" TOOL[{p.get('name')}]:", s(content, 2000)) print()