guanghu-ice-heart/server-tools/persona-execution-limb-agent/persona_limb_agent.py

205 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import pathlib
import shutil
import subprocess
import sys
ROOT = pathlib.Path(__file__).resolve().parents[2]
MAP = ROOT / "routing/persona-execution-limb-agent-map.json"
PERSONAS = ROOT / "routing/persona-system-canonical-map.json"
PROFILES = pathlib.Path(__file__).resolve().parent / "profiles"
RUNTIMES = {
"qwen": "/Users/bingshuolingdianyuanhe/.npm-global/bin/qwen",
"opencode": "/Users/bingshuolingdianyuanhe/.npm-global/bin/opencode",
"codex": "/Applications/ChatGPT.app/Contents/Resources/codex",
}
QWEN_AUTH_TYPE = "openai"
QWEN_MODELS = ["qwen3.8-max", "qwen3.7-plus", "deepseek-v4-pro", "deepseek-v4-flash-0731", "glm-5.2"]
def load(path: pathlib.Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def registered_personas() -> dict[str, dict]:
return {item["id"]: item for item in load(PERSONAS)["persona_systems"]}
def profile(persona_id: str) -> dict:
personas = registered_personas()
if persona_id not in personas:
raise ValueError("PERSONA_NOT_REGISTERED_NO_SYNTHETIC_WAKE")
exact = PROFILES / f"{persona_id}.json"
value = load(exact if exact.is_file() else PROFILES / "default.json")
if value.get("parent_persona_id") is None:
value["profile_id"] = f"LIMB::{persona_id}::PRIMARY"
value["parent_persona_id"] = persona_id
value["state"] = "DERIVED_REQUIRES_PARENT_TASK_ENVELOPE"
return value
def probe() -> dict:
return {
"schema": "guanghu.persona-execution-limb-tool-probe/v1",
"runtimes": {
name: {"path": path, "available": pathlib.Path(path).is_file() and bool(shutil.which(path))}
for name, path in RUNTIMES.items()
},
"secrets_read": False,
}
def envelope(persona_id: str, task_id: str, task: str, runtime: str) -> dict:
tools = probe()["runtimes"]
if runtime not in tools or not tools[runtime]["available"]:
raise ValueError("HOST_TOOL_UNAVAILABLE_REPORT_NOT_INVENT")
p = profile(persona_id)
return {
"schema": "guanghu.persona-execution-limb-task/v1",
"task_id": task_id,
"parent_persona_id": persona_id,
"limb_profile_id": p["profile_id"],
"runtime": runtime,
"task": task,
"working_defaults": p["working_defaults"],
"authority": "CURRENT_TASK_ENVELOPE_ONLY",
"controller": persona_id,
"receipt_required": True,
"prohibited": load(MAP)["prohibited"],
}
def prompt(value: dict) -> str:
return (
"你是父人格训练的有界Agent执行手脚不是独立主控人格。"
"不得审核父人格目的、扩大权限、读取秘密或虚构完成。"
"请完成任务中安全且明确的部分;如有精确事实冲突,返回证据和可继续路径。"
"最终只输出JSON字段为outcome,actions,evidence,tests,unresolved,training_candidate。\n"
+ json.dumps(value, ensure_ascii=False)
)
def qwen_succeeded(completed: subprocess.CompletedProcess[str]) -> bool:
if completed.returncode != 0 or "[API Error:" in completed.stdout:
return False
try:
stream = json.loads(completed.stdout)
except json.JSONDecodeError:
return False
if not isinstance(stream, list):
return False
results = [item for item in stream if item.get("type") == "result"]
return bool(results) and results[-1].get("is_error") is False and bool(str(results[-1].get("result", "")).strip())
def codex_succeeded(completed: subprocess.CompletedProcess[str]) -> bool:
if completed.returncode != 0:
return False
try:
events = [json.loads(line) for line in completed.stdout.splitlines() if line.strip()]
except json.JSONDecodeError:
return False
messages = [
event.get("item", {}).get("text")
for event in events
if event.get("type") == "item.completed" and event.get("item", {}).get("type") == "agent_message"
]
return any(isinstance(message, str) and message.strip() for message in messages)
def main() -> int:
parser = argparse.ArgumentParser()
sub = parser.add_subparsers(dest="command", required=True)
sub.add_parser("probe")
prepare = sub.add_parser("prepare")
for p in (prepare,):
p.add_argument("--persona", required=True)
p.add_argument("--task-id", required=True)
p.add_argument("--task", required=True)
p.add_argument("--runtime", required=True, choices=tuple(RUNTIMES))
run = sub.add_parser("run")
run.add_argument("--persona", required=True)
run.add_argument("--task-id", required=True)
run.add_argument("--task", required=True)
run.add_argument("--runtime", required=True, choices=("qwen", "codex"))
run.add_argument("--cwd", required=True)
args = parser.parse_args()
try:
if args.command == "probe":
result = probe()
else:
value = envelope(args.persona, args.task_id, args.task, args.runtime)
if args.command == "prepare":
result = value
else:
cwd = pathlib.Path(args.cwd).resolve()
if not cwd.is_dir():
raise ValueError("TASK_CWD_REQUIRED")
attempts = []
completed = None
selected_model = None
if args.runtime == "qwen":
for model in QWEN_MODELS:
candidate = subprocess.run(
[
RUNTIMES["qwen"],
"--auth-type", QWEN_AUTH_TYPE,
"--model", model,
"--prompt", prompt(value),
"--output-format", "json",
],
cwd=cwd, capture_output=True, text=True, timeout=180, check=False,
)
ok = qwen_succeeded(candidate)
attempts.append({"model": model, "exit_code": candidate.returncode, "semantic_success": ok})
completed = candidate
if ok:
selected_model = model
break
else:
candidate = subprocess.run(
[
RUNTIMES["codex"],
"-a", "never",
"exec",
"--ephemeral",
"--ignore-rules",
"--sandbox", "read-only",
"--cd", str(cwd),
"--json",
prompt(value),
],
cwd=cwd, capture_output=True, text=True, timeout=180, check=False,
)
ok = codex_succeeded(candidate)
attempts.append({"model": "codex-configured-default", "exit_code": candidate.returncode, "semantic_success": ok})
completed = candidate
if ok:
selected_model = "codex-configured-default"
assert completed is not None
success = selected_model is not None
result = {
"schema": "guanghu.persona-execution-limb-runtime-receipt/v1",
"task_id": value["task_id"],
"parent_persona_id": value["parent_persona_id"],
"runtime": args.runtime,
"selected_model": selected_model,
"attempts": attempts,
"exit_code": completed.returncode,
"stdout": completed.stdout[-20000:],
"stderr": completed.stderr[-4000:],
"outcome": "PASS" if success else "FAIL",
}
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0
except Exception as error:
print(json.dumps({"outcome": "FAIL", "error": str(error)}, ensure_ascii=False))
return 1
if __name__ == "__main__":
raise SystemExit(main())