常规归档
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
from __future__ import annotations
|
||||
|
||||
"""Codex review shim called by agents.py.
|
||||
|
||||
argv: task_path latest_discuss_path codex_session_id work_dir
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
def parse_jsonl(stdout: str) -> tuple[str, str]:
|
||||
session_id = ""
|
||||
final_message = ""
|
||||
text_parts: list[str] = []
|
||||
|
||||
for line in stdout.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
event: dict[str, Any] = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
text_parts.append(line)
|
||||
continue
|
||||
|
||||
for key in (
|
||||
"session_id",
|
||||
"sessionId",
|
||||
"thread_id",
|
||||
"threadId",
|
||||
"conversation_id",
|
||||
"conversationId",
|
||||
):
|
||||
value = event.get(key)
|
||||
if isinstance(value, str) and value:
|
||||
session_id = value
|
||||
|
||||
event_type = str(event.get("type", ""))
|
||||
if event_type in {"session.started", "session.created", "thread.started"}:
|
||||
value = event.get("id") or event.get("session_id") or event.get("thread_id")
|
||||
if isinstance(value, str) and value:
|
||||
session_id = value
|
||||
|
||||
if event_type == "item.completed":
|
||||
item = event.get("item")
|
||||
if isinstance(item, dict) and item.get("type") == "agent_message":
|
||||
value = item.get("text")
|
||||
if isinstance(value, str) and value:
|
||||
text_parts.append(value)
|
||||
|
||||
if event_type in {"agent_message", "message", "response.output_text.done"}:
|
||||
value = event.get("text") or event.get("message") or event.get("content")
|
||||
if isinstance(value, str) and value:
|
||||
text_parts.append(value)
|
||||
|
||||
if event_type in {"exec.completed", "turn.completed", "task.completed"}:
|
||||
value = event.get("last_message") or event.get("message") or event.get("output")
|
||||
if isinstance(value, str) and value:
|
||||
final_message = value
|
||||
|
||||
comment = (final_message or "\n".join(text_parts)).strip()
|
||||
return session_id, comment
|
||||
|
||||
|
||||
def resolve_codex() -> str:
|
||||
import shutil
|
||||
# 1. Explicit env var
|
||||
exe = os.environ.get("CODEX_EXE", "")
|
||||
if exe and Path(exe).exists():
|
||||
return exe
|
||||
# 2. PATH lookup
|
||||
found = shutil.which("codex") or shutil.which("codex.cmd")
|
||||
if found:
|
||||
return found
|
||||
# 3. Hardcoded fallback for the original developer machine
|
||||
fallback = r"C:\Users\bowei\.conda\envs\langgraph\codex.cmd"
|
||||
if Path(fallback).exists():
|
||||
return fallback
|
||||
raise FileNotFoundError(
|
||||
"Cannot find codex executable. Set CODEX_EXE environment variable or add codex to PATH."
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
task_path = sys.argv[1]
|
||||
latest_discuss = sys.argv[2] if len(sys.argv) > 2 and sys.argv[2] else ""
|
||||
codex_session_id = sys.argv[3] if len(sys.argv) > 3 and sys.argv[3] else ""
|
||||
work_dir = sys.argv[4] if len(sys.argv) > 4 and sys.argv[4] else str(Path.cwd())
|
||||
timeout = int(sys.argv[5]) if len(sys.argv) > 5 and sys.argv[5] else 300
|
||||
|
||||
prompt = (
|
||||
f"Working directory: {work_dir}\n"
|
||||
f"Review the plan document at {task_path}.\n"
|
||||
"Only report severe issues.\n"
|
||||
"Final answer rules: if there is no severe issue, output exactly NO_SERIOUS_ISSUE.\n"
|
||||
"If there is a severe issue, briefly describe it in one paragraph.\n"
|
||||
)
|
||||
if latest_discuss:
|
||||
prompt += f"Also verify that issues raised in {latest_discuss} were addressed.\n"
|
||||
|
||||
codex = resolve_codex()
|
||||
|
||||
fd, last_message_name = tempfile.mkstemp(
|
||||
prefix="codex-last-message-",
|
||||
suffix=".txt",
|
||||
dir=None,
|
||||
text=True,
|
||||
)
|
||||
os.close(fd)
|
||||
last_message_path = Path(last_message_name)
|
||||
try:
|
||||
flags = ["--json", "--skip-git-repo-check", "--output-last-message", str(last_message_path)]
|
||||
if codex_session_id:
|
||||
command_args = ["cmd", "/c", codex, "exec", "resume"] + flags + [codex_session_id, "-"]
|
||||
else:
|
||||
command_args = ["cmd", "/c", codex, "exec"] + flags + ["-"]
|
||||
logging.info("Invoking codex: %s", command_args[0] if command_args else "")
|
||||
t0 = time.monotonic()
|
||||
result = subprocess.run(
|
||||
command_args,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout,
|
||||
input=prompt,
|
||||
cwd=work_dir,
|
||||
)
|
||||
logging.info("Codex finished in %.1fs, exit=%d", time.monotonic() - t0, result.returncode)
|
||||
session_id, stream_comment = parse_jsonl(result.stdout)
|
||||
comment = last_message_path.read_text(encoding="utf-8").strip()
|
||||
if not comment:
|
||||
comment = stream_comment
|
||||
if comment.strip() == "NO_SERIOUS_ISSUE":
|
||||
comment = ""
|
||||
if codex_session_id:
|
||||
session_id = codex_session_id
|
||||
elif not session_id:
|
||||
session_id = codex_session_id
|
||||
finally:
|
||||
try:
|
||||
last_message_path.unlink()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
if result.returncode != 0 and not comment:
|
||||
sys.stderr.write(result.stderr)
|
||||
return result.returncode
|
||||
|
||||
print(json.dumps(
|
||||
{
|
||||
"has_serious_issue": bool(comment),
|
||||
"comment": comment,
|
||||
"codex_session_id": session_id,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user