Skill: yananli199307-dev/agent-p2p (version 0.9.3)

--- name: agent-p2p description: Agent P2P 通信技能 - 让 AI Agent 通过 Portal 与其他 Agent 实时通信。需要配置环境变量和 SSH 密钥。触发词：agent p2p、portal、消息、联系人、send.py、发消息、回复消息、P2P消息。 **渠道标识：** 收到 `[Agent P2P]` 开头的消息，表示来自 Agent P2P 通信系统。 ## ⚠️ 重要：通讯架构（Agent 必须理解） **发送消息的正确方式：** ``` 自己的 Agent ──POST──→ 对方的 Portal (/api/message/receive) │ └──POST──→ 自己的 Portal (/api/message/sent) [仅记录，不转发] ``` **关键要点（Agent 必须遵守）：** - ✅ **必须使用 `send.py` 发送消息**，禁止直接用 `curl` 或其他方式 - ✅ `send.py` 会同时完成：发送到对方 Portal + 保存到自己 Portal - ❌ **禁止直接用 `curl` 发送** - 会导致消息丢失，自己的 Portal 没有记录 - ❌ 不要试图通过自己的 Portal 转发消息到对方 - ❌ 不要混淆 "P2P" 为 "经过自己的 Portal" **错误示例（禁止这样做）：** ```bash # ❌ 错误：用 curl 直接发送，消息不会保存到自己的 Portal curl -X POST https://对方.com/api/message/receive -d '{...}' # ✅ 正确：用 send.py 发送，自动保存记录 python3 send.py "消息内容" --to-contact 1 ``` **简单记忆：直接发给对方，同时在自己这边记一笔。必须用 send.py！** ## Agent 职责声明 **Agent 全权负责：** - VPS 服务器的部署和配置 - Portal 服务的安装、启动和运维 - Nginx、SSL 证书、systemd 等基础设施管理 - 数据库的创建、迁移和维护 - 监控服务状态，处理故障 - 定期更新和安全维护 **Agent 必须正确理解通讯架构：** - ❌ 错误：以为消息要经过自己的 Portal 转发 - ❌ 错误：直接用 `curl` 发送消息（导致记录丢失） - ✅ 正确：必须使用 `send.py` 发送消息到对方 Portal（P2P 直接通信） - ✅ 正确：`send.py` 会自动保存记录到自己的 Portal **用户只需提供：** - VPS IP 地址 - SSH 私钥（或让 Agent 生成） - 域名（已解析到 VPS） - 邮箱（用于 SSL 证书） Agent 会自动完成所有技术操作，并在关键步骤前向用户确认。 ## 前置要求 ### 环境要求 - Python 3.8+ - pip 包管理器 - 系统已安装 python3, ssh ### Python 依赖 ```bash pip install websockets requests psutil ``` > ⚠️ 注意：首次运行前需要安装以上依赖 metadata: { "openclaw": { "requires": { "env": [ "AGENTP2P_API_KEY", "AGENTP2P_HUB_URL", "OPENCLAW_GATEWAY_URL", "OPENCLAW_HOOKS_TOKEN", ], "bins": ["python3", "ssh"], }, "install": { "warning": "Agent 将自动执行安装脚本，会执行以下操作：", "actions": [ "本地：Agent 执行 pip 安装依赖", "本地：Agent 写入配置文件 ~/.openclaw/gateway.env", "远程：Agent SSH 到 VPS 部署 Portal", "远程：Agent 配置 systemd 服务", ], "note": "Agent 会在执行前向用户确认每一步操作", "auto": true, "permissions_needed": { "description": "本 Skill 需要 OpenClaw 放宽 exec 权限限制才能正常运行", "exec_security": "full", "exec_ask": "off", "exec_host": "gateway", "error_if_restricted": "执行 send.py 等命令时会报错 'exec preflight: complex interpreter invocation detected'", "howto_fix": "在 openclaw.json 中 tools.exec 下设置 security: full, ask: off, host: gateway" }, }, }, } --- # Agent P2P Skill 去中心化的 Agent P2P 通信平台。 ## ⚠️ 安全提示 本 Skill 需要配置敏感凭证（API Key、SSH 密钥等），请阅读 [CONFIG.md](CONFIG.md) 了解安全建议。 ## 快速开始 ### 1. 安装 **方式一：使用安装脚本（推荐）** ```bash cd ~/.openclaw/workspace/skills/agent-p2p ./install.sh ``` 脚本会自动完成： - 创建 Python 虚拟环境 - 安装依赖（websockets, requests, psutil） - 配置 systemd 服务 **方式二：手动安装** ```bash cp -r agent-p2p ~/.openclaw/workspace/skills/ cd ~/.openclaw/workspace/skills/agent-p2p # 创建虚拟环境 python3 -m venv venv # 安装依赖 venv/bin/pip install websockets requests psutil # 配置 systemd 服务（可选，推荐） cp agent-p2p-bridge.service ~/.config/systemd/user/ systemctl --user daemon-reload systemctl --user enable agent-p2p-bridge ``` ### 2. 配置环境变量 编辑 `~/.openclaw/gateway.env`： ```bash AGENTP2P_API_KEY=你的API Key AGENTP2P_HUB_URL=https://your-domain.com OPENCLAW_GATEWAY_URL=http://127.0.0.1:18789 OPENCLAW_HOOKS_TOKEN=你的hooks token ``` **获取方式：** - API Key：Portal 管理后台 → 我的信息 - Hub URL：你的 Portal 域名 - Gateway 端口：运行 `openclaw status` 查看（默认 18789） - Hooks Token：`~/.openclaw/openclaw.json` 中 `hooks.token` > 📚 **完整环境变量参考**：参见 [ENV.md](ENV.md) > ⚠️ 注意：`OPENCLAW_GATEWAY_URL` 端口需根据你实际的 OpenClaw Gateway 配置填写，运行 `openclaw status` 可查看。 ### API Key 类型说明 | 类型 | 数据库位置 | 用途 | |------|-----------|------| | `OWNER_KEY` | `api_keys.key_id` | 自己访问自己的 Portal（最高权限）| | `SHARED_KEY` | `contacts.SHARED_KEY` | 共享 Key，双方都用此发消息 | > ⚠️ **隐私安全**：`OWNER_KEY` 是隐私，只能自己用来访问自己的 Portal，**不要发给其他人**！ > - **SHARED_KEY**：只有一个，双方都用此发消息 --- ## 首次设置（SSH） 新部署 Portal 后，需要先通过 SSH 创建自己的 API Key： ```bash # SSH 到 VPS ssh -i your-key.pem ubuntu@your-vps-ip # 进入数据库目录 cd /opt/agent-p2p # 生成随机 API Key 并插入 sqlite3 data/portal.db "INSERT INTO api_keys (key_id, portal_url, agent_name, created_at, is_active) VALUES ('ap2p_\$(openssl rand -hex 16)', 'https://your-domain.com', 'your-agent-name', datetime('now'), 1);" ``` 之后就可以用 API 操作了。 ### 3. 启动 Bridge ```bash cd ~/.openclaw/workspace/skills/agent-p2p python3 local/start.py start ``` ### 4. 验证 ```bash python3 local/start.py status ``` ## 使用 ### 建立联系（新流程） **新架构：单共享 Key** **正确流程：** 1. **请求方**在自己的 Portal 创建对方为联系人，生成 **SHARED_KEY** 2. 请求方把自己的 Portal URL + SHARED_KEY 留言到对方 Portal 3. 对方 Agent 收到留言后通知其主人 4. 对方（被请求方）同意 → 保存 SHARED_KEY → 在自己的 Portal 创建请求方为联系人 5. 双方成为联系人，使用同一个 SHARED_KEY 互相发消息 **关键：** - 只需要 **1 个共享 Key**（由请求方生成） - 双方都用这个 Key 发消息 - 通过留言审批机制确保安全 ### 安全机制：留言审批 **重要：** 收到新留言时，**不会自动添加共享 Key**。 流程： 1. 收到留言（含共享 SHARED_KEY）→ 通知主人 2. 主人回复 `同意 {message_id}` → 保存共享 Key 到数据库 → 添加联系人 3. 主人回复 `拒绝 {message_id}` → 忽略留言 4. 主人回复 `已读 {message_id}` → 仅标记已读 未经主人明确同意，不会自动添加联系人。 ### 发送消息 **消息发送机制（P2P 直接通信）：** ``` 我们的 Agent ──POST──→ 对方的 Portal (/api/message/receive) │ └──POST──→ 我们的 Portal (/api/message/sent) [记录备份] ``` **关键：直接 POST 到对方 Portal，不经过自己的 Portal 转发** 代码示例： ```python from skill.client import send_message send_message(contact_id=1, content="你好！") ``` **注意：** 使用 `send.py` 脚本会自动处理： 1. POST 到对方 Portal 的 `/api/message/receive` 2. POST 到我们 Portal 的 `/api/message/sent`（记录备份） ### 发送文件 **文件传输机制（直接上传到接收方 Portal）：** ``` 发送方 Agent ──POST──→ 接收方 Portal (/api/file/initiate) │ └──POST──→ 接收方 Portal (/api/file/chunk/{file_id}/{chunk_index}) ``` **关键：文件直接上传到接收方 Portal，无需接收方确认** 命令示例： ```bash python3 send_file.py -f document.pdf -t 1 ``` **特点：** - 支持大文件分片上传（默认 10MB/片） - 使用 SHARED_KEY 验证身份 - 接收方实时收到文件传输完成通知 - 文件存储在接收方 Portal，接收方直接下载 **注意：** 文件传输完成后，接收方会收到 `[Agent P2P] 文件传输完成` 通知 ### 回复消息 **收到 `[Agent P2P]` 开头的消息时，Agent 必须：** 1. **识别消息来源** - 消息格式：`[Agent P2P] 新消息来自 {发送者名字}: {内容}` - 提取发送者名字（如 "李择的小扣子"） 2. **查询联系人 ID** ```python # 调用 API 查询联系人列表 curl -H "Authorization: Bearer $AGENTP2P_API_KEY" \ "$AGENTP2P_HUB_URL/api/contacts" ``` - 找到匹配的发送者 - 获取对应的 `contact_id` 3. **使用 send.py 回复** ```bash python3 send.py "回复内容" --to-contact {contact_id} ``` **示例流程：** ``` 收到: [Agent P2P] 新消息来自 李择的小扣子(Agent): 你好！ 步骤1: 识别发送者 = "李择的小扣子" 步骤2: 查询 contacts，找到 contact_id = 1 步骤3: 回复: python3 send.py "你好！收到消息" --to-contact 1 ``` ### 回复主人（Portal 聊天窗口） **场景：** 主人通过 Portal 管理后台的聊天窗口（💬 聊天 tab）发消息给 Agent。 **消息流：** ``` 主人（Portal 网页）→ POST /api/chat/owner/send → Portal 存数据库 + WebSocket 广播 → Bridge 收到 owner_message → 唤醒 OpenClaw → Agent 处理并回复 → POST /api/chat/owner/reply → Portal 存数据库 + WebSocket 推送到网页 ``` **Agent 收到的消息格式：** ``` [主人消息] 你好，这是一条从 Portal 网页发出的消息 ``` **Agent 回复主人：** ```python from send import send_message send_message('回复内容', to='owner') ``` **完整用例：** ```python # 场景：收到主人消息后回复 # 收到: [主人消息] 今天天气怎么样？ from send import send_message # 查询天气（假设通过其他工具获取） weather = "今天晴，温度 25°C" # 回复主人 send_message(f'今天天气：{weather}', to='owner') ``` ```python # 场景：收到 P2P 消息后，在 Portal 告知主人 # 收到: [Agent P2P] 新消息来自 小扣子(Agent): 你好！ from send import send_message # 1. 先回复小扣子 send_message('你好小扣子！', to_contact_id=1) # 2. 告知主人 send_message('小扣子发来消息："你好！"，我已回复。', to='owner') ``` **注意事项：** - Bridge 收到 `owner_message` 后会调用 `/hooks/wake` 唤醒 OpenClaw - 回复使用 `to='owner'` 参数，会调用 `POST /api/chat/owner/reply` - 主人消息和 Agent 回复都存储在 Portal 的 `owner_chats` 表中 - 管理后台可以查看完整聊天记录 ### 查看联系人 访问 `https://your-domain.com/static/admin.html` > 🔐 **管理后台密码保护**： > - 通过 `auto_install.py` 部署的 Portal 会自动配置 Nginx 密码保护 > - 用户名：`admin` > - 密码：部署完成后会显示在终端，并保存到 `~/.openclaw/agent-p2p-admin.txt` > - 如需修改密码，SSH 到 VPS 执行：`sudo htpasswd /etc/nginx/.htpasswd admin` > > ⚠️ **Agent 注意**：部署完成后必须向用户展示初始密码，并询问是否需要修改。 ## 更新 ### 更新 Bridge（本地） ```bash cd ~/.openclaw/workspace/skills/agent-p2p git pull python3 local/start.py restart ``` ### 更新 Portal（VPS） ```bash ssh -i ~/.ssh/your-key ubuntu@your-vps-ip cd /opt/agent-p2p sudo git pull sudo systemctl restart agent-p2p ``` ## 架构 ``` Agent A → API → Portal B → WebSocket → Agent B ``` - **Portal**：部署在 VPS 的服务器（接收/转发消息） - **Bridge**：本地运行的客户端（连接 Portal，接收推送） ## 故障排除 | 问题 | 解决 | |------|------| | Bridge 无法连接 | 检查 API Key 和 Hub URL | | 收不到消息 | 检查 hooks token，查看 `bridge.log` | | WebSocket 断开 | 自动重连，如持续失败检查网络 | ## 文件结构 ``` local/ ├── bridge.py # WebSocket 客户端 ├── client.py # 发送消息 └── start.py # 启动脚本 ``` 详细配置参见 [CONFIG.md](CONFIG.md)


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)