sync: WIN10-I9-64G 2026-07-20
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""In-process driver for the plan-review graph — NO langgraph dev server.
|
||||
|
||||
Builds the compiled graph in-process (workflow.build_workflow) with a SqliteSaver so
|
||||
state survives between invocations, and drives interrupts directly. Sets HTTP(S)_PROXY
|
||||
from the Windows system proxy (or PLAN_REVIEW_PROXY) so the codex subprocess spawned by
|
||||
the review node can reach its backend through the proxy.
|
||||
|
||||
CLI (mirrors the old run_workflow.py):
|
||||
--task-id 10 [--work-dir DIR] [--notes-dir Notes] [--prompt "..."]
|
||||
[--resume-b64 <b64 json>] [--codex-review-command-b64 <b64 json>] [--timeout 600]
|
||||
Prints one JSON line: {"status":"waiting","action_required":{...}} or {"status":"done",...}.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import os, sys, json, base64, argparse, sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPTS = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(SCRIPTS))
|
||||
|
||||
|
||||
def resolve_proxy() -> str:
|
||||
px = os.environ.get("PLAN_REVIEW_PROXY", "").strip()
|
||||
if not px:
|
||||
try:
|
||||
import winreg
|
||||
k = winreg.OpenKey(
|
||||
winreg.HKEY_CURRENT_USER,
|
||||
r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
|
||||
)
|
||||
enable, _ = winreg.QueryValueEx(k, "ProxyEnable")
|
||||
server, _ = winreg.QueryValueEx(k, "ProxyServer")
|
||||
if enable and server and "=" not in str(server): # simple host:port, not per-scheme
|
||||
px = "http://" + str(server)
|
||||
except Exception:
|
||||
px = ""
|
||||
if px:
|
||||
for v in ("HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY",
|
||||
"http_proxy", "https_proxy", "all_proxy"):
|
||||
os.environ[v] = px
|
||||
return px
|
||||
|
||||
|
||||
def open_saver(db_path: str):
|
||||
from langgraph.checkpoint.sqlite import SqliteSaver
|
||||
conn = sqlite3.connect(db_path, check_same_thread=False)
|
||||
saver = SqliteSaver(conn)
|
||||
try:
|
||||
saver.setup()
|
||||
except Exception:
|
||||
pass
|
||||
return saver
|
||||
|
||||
|
||||
def extract_interrupt(result):
|
||||
if not isinstance(result, dict):
|
||||
return None
|
||||
ints = result.get("__interrupt__")
|
||||
if not ints:
|
||||
return None
|
||||
first = ints[0] if isinstance(ints, (list, tuple)) else ints
|
||||
return getattr(first, "value", first)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--task-id", required=True)
|
||||
ap.add_argument("--work-dir", default=".")
|
||||
ap.add_argument("--notes-dir", default="Notes")
|
||||
ap.add_argument("--prompt", default="")
|
||||
ap.add_argument("--resume-b64", default="")
|
||||
ap.add_argument("--codex-review-command-b64", default="")
|
||||
ap.add_argument("--timeout", type=int, default=600)
|
||||
ap.add_argument("--db", default=str(SCRIPTS / ".plan_review_state.sqlite"))
|
||||
args = ap.parse_args()
|
||||
|
||||
proxy = resolve_proxy()
|
||||
|
||||
from workflow import build_workflow
|
||||
from langgraph.types import Command
|
||||
|
||||
codex_cmd = None
|
||||
if args.codex_review_command_b64:
|
||||
codex_cmd = json.loads(base64.b64decode(args.codex_review_command_b64).decode("utf-8"))
|
||||
|
||||
saver = open_saver(args.db)
|
||||
graph = build_workflow(checkpointer=saver)
|
||||
|
||||
config = {"configurable": {"thread_id": str(args.task_id), "codex_timeout": args.timeout}}
|
||||
if codex_cmd:
|
||||
config["configurable"]["codex_review_command"] = codex_cmd
|
||||
|
||||
if args.resume_b64:
|
||||
resume_val = json.loads(base64.b64decode(args.resume_b64).decode("utf-8"))
|
||||
result = graph.invoke(Command(resume=resume_val), config)
|
||||
else:
|
||||
init = {
|
||||
"task_id": str(args.task_id),
|
||||
"user_prompt": args.prompt,
|
||||
"work_dir": args.work_dir,
|
||||
"notes_dir": args.notes_dir,
|
||||
"codex_session_id": "",
|
||||
}
|
||||
result = graph.invoke(init, config)
|
||||
|
||||
payload = extract_interrupt(result)
|
||||
if payload is not None:
|
||||
out = {"status": "waiting", "thread_id": str(args.task_id),
|
||||
"action_required": payload, "proxy": proxy}
|
||||
else:
|
||||
out = {"status": "done", "thread_id": str(args.task_id),
|
||||
"has_serious_issue": bool(result.get("has_serious_issue")),
|
||||
"review_comment": result.get("review_comment", ""),
|
||||
"proxy": proxy}
|
||||
print(json.dumps(out, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user