#!/usr/bin/env python3 """ 安装仓库内置的 AgentPack 到本地 agentpacks 目录。 用法(server 必须先运行): python scripts/install_builtin_packs.py 也可以不启动 server,直接写入 agentpacks_dir: python scripts/install_builtin_packs.py --offline 内置 pack 位置:agentexample/agentpacks/ 安装目标: ~/.agentpaas/data/agentpacks/ (desktop 模式) ~/LambdAgentDesktop/agentpacks/ (如果是 desktop 模式且未改数据目录) """ from __future__ import annotations import argparse import json import os import sys import zipfile import tempfile from pathlib import Path REPO_ROOT = Path(__file__).parent.parent.resolve() PACKS_SRC = REPO_ROOT / "agentexample" / "agentpacks" BUILTIN_PACKS = [ "research.top-journal-reviewer", "research.literature-mapper", "research.grant-planner", ] def _zip_pack(pack_id: str, dest_dir: Path) -> str: pack_dir = PACKS_SRC / pack_id if not pack_dir.is_dir(): sys.exit(f"❌ Pack 目录不存在: {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 _default_packs_dir() -> str: """读取 ~/.agentpaas/config.json 或按 desktop 模式默认值推断 agentpacks_dir。""" cfg = Path.home() / ".agentpaas" / "config.json" try: with open(cfg) as f: data = json.load(f) or {} data_dir = data.get("data_dir", "") except Exception: data_dir = "" if not data_dir: # desktop 默认 data_dir = str(Path.home() / "LambdAgentDesktop") return os.path.join(data_dir, "agentpacks") # ── 离线模式:直接调用 install_from_zip ────────────────────────────────────── def install_offline(packs_dir: str, packs: list[str]) -> None: from agentpaas.engine.agentpack_store import install_from_zip, get_installed os.makedirs(packs_dir, exist_ok=True) print(f"\n安装目标目录: {packs_dir}\n") with tempfile.TemporaryDirectory() as td: for pack_id in packs: existing = get_installed(packs_dir, pack_id) if existing: print(f" ✓ {pack_id} v{existing.version} — 已安装,跳过") continue zip_path = _zip_pack(pack_id, Path(td)) try: pack = install_from_zip(zip_path, packs_dir) print(f" ✓ {pack_id} v{pack.version} — 安装完成") except Exception as e: print(f" ✗ {pack_id} — 失败: {e}", file=sys.stderr) # ── 在线模式:通过 HTTP API 安装(需要 server 运行)─────────────────────────── def install_online(base_url: str, api_key: str, packs: list[str]) -> None: try: import requests except ImportError: sys.exit("缺少依赖: pip install requests") session = requests.Session() if api_key: session.headers["Authorization"] = f"Bearer {api_key}" print(f"\n连接 server: {base_url}\n") # 先列出已安装 try: r = session.get(f"{base_url}/api/v1/agentpacks", timeout=5) r.raise_for_status() already = {p["id"] for p in r.json().get("agentpacks", [])} except Exception as e: sys.exit(f"❌ 无法连接 server: {e}\n 请先启动: uvicorn agentpaas.api.app:app --port 8000") with tempfile.TemporaryDirectory() as td: for pack_id in packs: if pack_id in already: print(f" ✓ {pack_id} — 已安装,跳过") continue zip_path = _zip_pack(pack_id, Path(td)) 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(f" ✓ {pack['id']} v{pack['version']} — 安装完成") else: print(f" ✗ {pack_id} — HTTP {r.status_code}: {r.text[:120]}", file=sys.stderr) # ── CLI ─────────────────────────────────────────────────────────────────────── def main() -> None: parser = argparse.ArgumentParser( description="安装仓库内置 AgentPack (research.* 三个 pack)", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" 示例: # 离线安装(不需要 server 运行,推荐) python scripts/install_builtin_packs.py --offline # 在线安装(需要 server 先跑起来) python scripts/install_builtin_packs.py # 指定安装目录 python scripts/install_builtin_packs.py --offline --packs-dir /data/agentpacks """, ) parser.add_argument( "--offline", action="store_true", help="直接写入 agentpacks_dir,不需要 server 运行(推荐)", ) parser.add_argument( "--packs-dir", default="", help="安装目标目录(默认:从 ~/.agentpaas/config.json 推断)", ) parser.add_argument( "--url", default="http://127.0.0.1:8000", help="Server URL(在线模式,默认 http://127.0.0.1:8000)", ) parser.add_argument( "--key", default="", help="API key(在线模式,默认从 ~/.agentpaas/config.json 读取)", ) parser.add_argument( "--pack", action="append", dest="packs", help="只安装指定 pack(可多次指定,默认全部三个)", ) args = parser.parse_args() packs = args.packs or BUILTIN_PACKS print(f"内置 Pack 源目录: {PACKS_SRC}") if args.offline: packs_dir = args.packs_dir or _default_packs_dir() install_offline(packs_dir, packs) else: # 读取 api_key api_key = args.key if not api_key: cfg = Path.home() / ".agentpaas" / "config.json" try: api_key = (json.load(open(cfg)) or {}).get("api_key", "") except Exception: pass install_online(args.url, api_key, packs) print('\n完成。在 webui 的"智能体包"页面可以看到已安装的 pack,点击"创建智能体"即可使用。\n') if __name__ == "__main__": main()