#!/usr/bin/env python3 """ Phase I dogfood — AgentPack end-to-end script with real LLM. Usage: # Start the server in another terminal first: AGENTPAAS_DEPLOYMENT_MODE=desktop uvicorn agentpaas.api.app:app --port 8000 # Run the dogfood script: python scripts/dogfood_agentpack.py # Or point at a non-default host/key: python scripts/dogfood_agentpack.py --url http://127.0.0.1:8000 --key ap_xxxx The script: 1. Zips the built-in research.top-journal-reviewer pack from the repo 2. Installs it via POST /api/v1/agentpacks/install 3. Creates an agent via POST /api/v1/agentpacks/{id}/create-agent 4. Runs the agent with a short test abstract 5. Prints the workspace path and verifies review_report.md exists Requirements: - Server running with ANTHROPIC_API_KEY or DASHSCOPE_API_KEY set - pip install requests (standard, usually present) """ from __future__ import annotations import argparse import json import os import subprocess import sys import tempfile import time import zipfile from pathlib import Path # ── Config ──────────────────────────────────────────────────────────────────── REVIEWER_PACK_ID = "research.top-journal-reviewer" TEST_ABSTRACT = """\ Title: Quantum Speedup for Dense Matrix Multiplication via Phase Estimation. Abstract: We present a quantum algorithm that computes dense n×n matrix products in O(n^{1.5} log n) time using quantum phase estimation and amplitude amplification, outperforming the classical Strassen barrier O(n^{2.37}). We provide a gate-level circuit of depth O(n^{0.75} polylog n) with error probability δ < 0.01. Experiments on 16×16 matrices on a simulated 40-qubit processor confirm a 3.2× speedup. 请审阅这篇论文的核心贡献声明、技术正确性和实验充分性,生成完整的审稿报告。 """ # ── Helpers ─────────────────────────────────────────────────────────────────── def _print(label: str, msg: str = "", ok: bool = True) -> None: status = "✓" if ok else "✗" color = "\033[32m" if ok else "\033[31m" reset = "\033[0m" print(f" {color}{status}{reset} {label}: {msg}") def _zip_pack(repo_root: Path, pack_id: str, dest_dir: Path) -> str: pack_dir = repo_root / "agentexample" / "agentpacks" / pack_id if not pack_dir.is_dir(): sys.exit(f"Pack not found on disk: {pack_dir}") zip_path = str(dest_dir / f"{pack_id}.zip") with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf: for p in pack_dir.rglob("*"): if p.is_file(): zf.write(p, p.relative_to(pack_dir)) return zip_path def _read_api_key_from_config() -> str: """Read the auto-bootstrapped API key from ~/.agentpaas/config.json.""" cfg_path = Path.home() / ".agentpaas" / "config.json" try: with open(cfg_path) as f: return (json.load(f) or {}).get("api_key", "") except Exception: return "" # ── Main flow ───────────────────────────────────────────────────────────────── def run_dogfood(base_url: str, api_key: str, verbose: bool = False) -> bool: try: import requests except ImportError: sys.exit("Missing dependency: pip install requests") session = requests.Session() session.headers.update({"Authorization": f"Bearer {api_key}"}) repo_root = Path(__file__).parent.parent.resolve() ok = True print(f"\n{'─'*60}") print(f" AgentPack Dogfood — {base_url}") print(f"{'─'*60}") # Step 0: health check print("\n[0] 服务健康检查") try: r = session.get(f"{base_url}/health", timeout=5) r.raise_for_status() _print("health", r.json().get("status", "?")) except Exception as e: _print("health", str(e), ok=False) print("\n 服务未响应。请先启动:\n uvicorn agentpaas.api.app:app --port 8000\n") return False # Step 1: zip + install pack print(f"\n[1] 安装内置 Pack: {REVIEWER_PACK_ID}") with tempfile.TemporaryDirectory() as td: zip_path = _zip_pack(repo_root, REVIEWER_PACK_ID, Path(td)) _print("zip", f"{Path(zip_path).stat().st_size // 1024} KB") # install is loopback-only — works when server is on localhost r = session.post( f"{base_url}/api/v1/agentpacks/install", json={"zip_path": zip_path}, timeout=30, ) if r.status_code == 200: pack = r.json()["installed"] _print("install", f"{pack['id']} v{pack['version']}") elif r.status_code == 400 and "already installed" in r.text.lower(): _print("install", "已安装,跳过") else: _print("install", f"HTTP {r.status_code}: {r.text[:200]}", ok=False) ok = False # Step 2: verify pack is listed print(f"\n[2] 列出已安装 packs") r = session.get(f"{base_url}/api/v1/agentpacks", timeout=10) packs = r.json().get("agentpacks", []) found = any(p["id"] == REVIEWER_PACK_ID for p in packs) _print("list", f"{len(packs)} pack(s),reviewer={'✓' if found else '✗'}", ok=found) if not found: ok = False # Step 3: create agent from pack print(f"\n[3] 从 Pack 创建智能体") r = session.post( f"{base_url}/api/v1/agentpacks/{REVIEWER_PACK_ID}/create-agent", json={"name": "Dogfood 审稿助手", "description": "Phase I dogfood"}, timeout=15, ) if r.status_code == 201: body = r.json() agent_id = body["agent_id"] _print("create-agent", f"id={agent_id}") else: _print("create-agent", f"HTTP {r.status_code}: {r.text[:200]}", ok=False) ok = False return ok # Step 4: verify agent in list print(f"\n[4] 验证智能体出现在 /agents") r = session.get(f"{base_url}/api/v1/agents", timeout=10) agent_ids = [a["id"] for a in r.json().get("agents", [])] found = agent_id in agent_ids _print("agents list", f"agent_id in list: {'✓' if found else '✗'}", ok=found) if not found: ok = False # Step 5: verify config._config_dir print(f"\n[5] 验证 agent config._config_dir") r = session.get(f"{base_url}/api/v1/agents/{agent_id}", timeout=10) agent = r.json() config_dir = agent.get("config", {}).get("_config_dir", "") agent_dir = agent.get("agent_dir", "") match = config_dir == agent_dir _print("_config_dir", f"{'matches agent_dir ✓' if match else f'MISMATCH: {config_dir!r} != {agent_dir!r}'}", ok=match) if not match: ok = False # Step 6: run agent print(f"\n[6] 运行审稿智能体(LLM 调用,可能需要 1-3 分钟)") t0 = time.time() r = session.post( f"{base_url}/api/v1/agents/{agent_id}/run", json={"input": TEST_ABSTRACT}, timeout=300, ) elapsed = int(time.time() - t0) if r.status_code != 200: _print("run", f"HTTP {r.status_code}: {r.text[:300]}", ok=False) ok = False return ok run_body = r.json() workspace = run_body.get("workspace_path", "") _print("run", f"完成 ({elapsed}s), status={run_body.get('status', '?')}") _print("workspace", workspace or "(未设置)") # Step 7: verify workspace files print(f"\n[7] 验证 workspace 产出物") if not workspace: _print("workspace_path", "run response 中未包含", ok=False) ok = False else: for fname in ("review_report.md", "review_result.json"): fpath = os.path.join(workspace, fname) exists = os.path.isfile(fpath) size = os.path.getsize(fpath) if exists else 0 _print(fname, f"{'存在' if exists else '不存在'} ({size} bytes)", ok=exists) if not exists: ok = False if verbose and workspace and os.path.isfile(os.path.join(workspace, "review_report.md")): print("\n ── review_report.md (前 20 行) ──") with open(os.path.join(workspace, "review_report.md"), encoding="utf-8") as f: lines = f.readlines()[:20] for line in lines: print(" ", line, end="") # Step 8: cleanup print(f"\n[8] 清理(删除 dogfood agent)") r = session.delete(f"{base_url}/api/v1/agents/{agent_id}", timeout=10) _print("delete agent", f"HTTP {r.status_code}") print(f"\n{'─'*60}") result_str = "PASS ✓" if ok else "FAIL ✗" color = "\033[32m" if ok else "\033[31m" print(f" {color}Dogfood result: {result_str}\033[0m") print(f"{'─'*60}\n") return ok # ── CLI ─────────────────────────────────────────────────────────────────────── def main() -> None: parser = argparse.ArgumentParser(description="AgentPack dogfood E2E script") parser.add_argument( "--url", default="http://127.0.0.1:8000", help="Base URL of the running agentpaas server (default: http://127.0.0.1:8000)", ) parser.add_argument( "--key", default="", help="API key (Bearer). Reads from ~/.agentpaas/config.json if omitted.", ) parser.add_argument( "--verbose", "-v", action="store_true", help="Print first 20 lines of review_report.md", ) args = parser.parse_args() api_key = args.key or _read_api_key_from_config() if not api_key: sys.exit( "No API key found. Pass --key ap_xxx or run the server in desktop mode " "to auto-generate one at ~/.agentpaas/config.json" ) success = run_dogfood(args.url, api_key, verbose=args.verbose) sys.exit(0 if success else 1) if __name__ == "__main__": main()