diff --git a/honcho/create-multi-keys.sh b/honcho/create-multi-keys.sh new file mode 100644 index 0000000..afbb54f --- /dev/null +++ b/honcho/create-multi-keys.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# +# create-multi-keys.sh — 在 vm61 honcho 上批量创建 3 个客户端的 API key +# +# 用法: +# 1. 在 vm61 上: ./create-multi-keys.sh +# 2. 输出 3 个 key 文件到 ~/.honcho-keys/,chmod 600 +# 3. scp 到对应客户端 +# +# 前置: +# - honcho-api 容器跑着 +# - AUTH_USE_AUTH=true + 管理员 token(honcho init 时生成) +# - workspace "home" 已存在 +# +# ⚠️ 不要 echo key 到聊天。文件 chmod 600,scp 时 -p 保留权限。 + +set -euo pipefail + +WORKSPACE="${HONCHO_WORKSPACE:-home}" +HONCHO_API="${HONCHO_API_URL:-http://10.0.0.1:8000}" +ADMIN_TOKEN_FILE="${HONCHO_ADMIN_TOKEN_FILE:-/root/.honcho-keys/admin.key}" + +# 客户端清单: name:peer:device_hint +CLIENTS=( + "alpha:laodeng-mypc03:mypc03" + "beta:laodeng-govpc:gov-pc" + "gamma:laodeng-mac:macbook" +) + +OUT_DIR="${OUT_DIR:-/root/.honcho-keys}" +mkdir -p "$OUT_DIR" +chmod 700 "$OUT_DIR" + +if [[ ! -f "$ADMIN_TOKEN_FILE" ]]; then + echo "❌ 找不到 admin token: $ADMIN_TOKEN_FILE" >&2 + echo " 把 honcho init 时生成的 admin token 写到该文件,chmod 600" >&2 + exit 1 +fi + +ADMIN_TOKEN="$(cat "$ADMIN_TOKEN_FILE")" + +echo "==> honcho: $HONCHO_API" +echo "==> workspace: $WORKSPACE" +echo "==> 输出目录: $OUT_DIR" +echo "" + +for entry in "${CLIENTS[@]}"; do + IFS=':' read -r slug peer device <<< "$entry" + key_file="$OUT_DIR/${device}.key" + info_file="$OUT_DIR/${device}.json" + + echo "--- [$device] peer=$peer ---" + + # 检查 peer 是否已存在(幂等) + existing="$(curl -fsS -H "Authorization: Bearer *** "$HONCHO_API/v2/workspaces/$WORKSPACE/peers/$peer" 2>/dev/null || true)" + + if [[ -n "$existing" && "$existing" != *"404"* ]]; then + echo " peer 已存在,跳过创建" + else + # 创建 peer + curl -fsS -X POST \ + -H "Authorization: Bearer *** \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"$peer\"}" \ + "$HONCHO_API/v2/workspaces/$WORKSPACE/peers" \ + | tee "$info_file.tmp" > /dev/null + mv "$info_file.tmp" "$info_file" + chmod 600 "$info_file" + echo " ✅ peer 已创建" + fi + + # 创建 API key(每次新建,旧的不 revoke) + # honcho 的 key 创建 API 名称可能因版本不同,下面给常见两种尝试 + key_resp="$(curl -fsS -X POST \ + -H "Authorization: Bearer *** \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"$peer\",\"scope\":\"peer:$peer\"}" \ + "$HONCHO_API/v2/workspaces/$WORKSPACE/api-keys" 2>/dev/null || true)" + + if [[ -z "$key_resp" ]]; then + # 备选 endpoint + key_resp="$(curl -fsS -X POST \ + -H "Authorization: Bearer *** \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"$peer\"}" \ + "$HONCHO_API/v2/auth/keys 2>/dev/null || true)" + fi + + if [[ -z "$key_resp" ]]; then + echo " ❌ 创建 key 失败,请检查 honcho API 版本" >&2 + echo " 临时手动: honcho create user --workspace $WORKSPACE --name $peer" >&2 + continue + fi + + # 提取 token(兼容多种字段名) + token="$(echo "$key_resp" | python3 -c ' +import json, sys +try: + d = json.load(sys.stdin) + print(d.get("token") or d.get("api_key") or d.get("key") or d.get("value") or "") +except Exception: + print("") +')" + + if [[ -z "$token" ]]; then + echo " ❌ 无法从响应提取 token:" + echo "$key_resp" | head -c 500 + echo "" + continue + fi + + echo -n "$token" > "$key_file" + chmod 600 "$key_file" + echo " ✅ key 已写入: $key_file ($(wc -c < "$key_file") bytes)" +done + +echo "" +echo "==> 完成。当前 keys:" +ls -la "$OUT_DIR" +echo "" +echo "下一步:" +echo " scp $OUT_DIR/mypc03.key mypc03:~/.honcho-keys/" +echo " scp $OUT_DIR/govpc.key govpc:~/.honcho-keys/" +echo " scp $OUT_DIR/mac.key macbook:~/.honcho-keys/" +echo "" +echo "⚠️ 不要 echo 这些 key 到聊天/日志/screenshot" \ No newline at end of file diff --git a/honcho/share-multi-client.md b/honcho/share-multi-client.md new file mode 100644 index 0000000..e500184 --- /dev/null +++ b/honcho/share-multi-client.md @@ -0,0 +1,258 @@ +# Honcho 多 Hermes 客户端共享方案 + +> 状态: 📝 草案 (2026-06-20) +> 适用: 家里 vm61 部署 honcho + 3 个 hermes 客户端共享同一份记忆 + +--- + +## 1. 场景 + +| 客户端 | 位置 | 网络到 vm61 | peer 名 | +|---|---|---|---| +| mypc03 (WSL Debian) | 🏠 家里 LAN | 同网段直连 | `laodeng-mypc03` | +| gov-pc (公司机器) | 🏢 公司 | WireGuard → vm61 | `laodeng-govpc` | +| macbook | ☕ 任意位置 | WireGuard → vm61 | `laodeng-mac` | + +**3 个客户端都是老登本人**用,所以希望: +- ✅ **共享 workspace**(`home`):在 A 上聊的事,B 上能召回 +- ✅ **peer 独立**(带设备后缀):方便审计"在哪台设备说的" +- ✅ **AUTH 开启**:每个客户端独立 API key,可单独撤销 +- ❌ 不共享 LLM 凭据:每个客户端用自己的 hermes LLM key + +--- + +## 2. 架构 + +```mermaid +flowchart LR + subgraph Clients["3 个 Hermes 客户端"] + A[mypc03
peer: laodeng-mypc03
key: tok_alpha] + B[gov-pc
peer: laodeng-govpc
key: tok_beta] + C[macbook
peer: laodeng-mac
key: tok_gamma] + end + + subgraph Vm61["vm61 (192.168.10.61)"] + WG[WireGuard
10.0.0.1] + API[honcho-api:8000
AUTH ON] + DB[(postgres+pgvector)] + DERIVER[honcho-deriver
~2 done/min] + REDIS[(redis)] + end + + A ==wg==> WG + B ==wg==> WG + C ==wg==> WG + WG --> API + API --> DB + API --> REDIS + DERIVER <--> REDIS + DERIVER <--> DB + + classDef client fill:#e1f5ff,stroke:#0066cc + classDef svc fill:#fff4e1,stroke:#cc6600 + classDef store fill:#e8f5e9,stroke:#2e7d32 + class A,B,C client + class WG,API,DERIVER svc + class DB,REDIS store +``` + +**网络**:3 客户端 → WireGuard 隧道 (10.0.0.x) → vm61 8000 + +--- + +## 3. 为什么这样设计 + +| 决策 | 选择 | 替代方案 | 理由 | +|---|---|---|---| +| **AUTH 开** | ✅ ON | OFF(内网) | 可审计 + 可撤销 + 可限流;WireGuard 内网本身已加密 | +| **Workspace** | `home` 一个共用 | 每个 peer 独立 ws | 老登本人用,跨设备回忆体验更好 | +| **Peer** | 带设备后缀 | 统一 `laodeng` | 审计需要知道"哪台设备写的";peer 概念在 honcho 里是身份,不影响记忆语义 | +| **API URL** | `http://10.0.0.1:8000`(WireGuard 内网 IP) | 公网 IP / 域名 | WireGuard 已加密 + 认证,没必要再绕公网 | +| **LLM 凭据** | 客户端本地保留 | 共享到 honcho | deriver 已经持有全局 LLM key;客户端 hermes 自己的对话 LLM 不应上送 honcho | +| **deriver 后台** | 共享 vm61 上现有 | 每客户端本地跑 | honcho deriver 设计就是单实例后台,集中推理更省 API 配额 | + +--- + +## 4. 实施步骤 + +### Phase 1: vm61 上 honcho 准备 + +```bash +# 1.1 确认 4 个容器 Up +docker ps | grep -E "honcho-(api|deriver|database|redis)" + +# 1.2 确认 AUTH 已开(6-19 已设过,复核) +cat /data/deploy/honcho/env.cfg | grep -E "AUTH_USE_AUTH|JWT_SECRET" +# 期望: AUTH_USE_AUTH=true + +# 1.3 确认 honcho-api 监听 0.0.0.0(不是 127.0.0.1) +docker inspect honcho-api | grep -A2 -E "HostPort|NetworkMode" +# 或直接看启动日志 +docker logs honcho-api 2>&1 | grep -i "listening" + +# 1.4 从 WireGuard 网卡验证 +curl -s http://10.0.0.1:8000/health +# 期望: {"status":"ok"} +``` + +**如果 1.3 / 1.4 失败**: +- stack.yml 里 `ports:` 必须暴露 `0.0.0.0:8000:8000` 或 `8000:8000` +- 6-19 修过的 `DB_CONNECTION_URI` / `CACHE_URL` 已稳定,但确认 WireGuard 网卡没被 firewall 拦 + +### Phase 2: 创建 3 个 API key + +```bash +# vm61 上跑 create-multi-keys.sh(见同目录) +./create-multi-keys.sh +``` + +脚本输出形如: + +``` +✅ key_alpha -> /root/.honcho-keys/mypc03.key +✅ key_beta -> /root/.honcho-keys/govpc.key +✅ key_gamma -> /root/.honcho-keys/mac.key +``` + +**`scp` 3 个 key 文件到对应客户端**: + +```bash +scp /root/.honcho-keys/mypc03.key mypc03:~/.honcho-keys/ +scp /root/.honcho-keys/govpc.key gov-pc:~/.honcho-keys/ +scp /root/.honcho-keys/mac.key macbook:~/.honcho-keys/ +``` + +⚠️ **绝不 echo 到聊天**(参考 6-07 dufs 密码泄露教训)。每个客户端 `chmod 600 ~/.honcho-keys/*.key`。 + +### Phase 3: 3 客户端配置 hermes + +每台机器执行(**api_url 都填 WireGuard 内网 IP**): + +```bash +# 通用(3 台都跑) +hermes config set memory.provider honcho +hermes config set memory.honcho.api_url http://10.0.0.1:8000 +hermes config set memory.honcho.workspace home + +# mypc03 额外 +hermes config set memory.honcho.peer laodeng-mypc03 +hermes config set memory.honcho.api_key "$(cat ~/.honcho-keys/mypc03.key)" + +# gov-pc 额外 +hermes config set memory.honcho.peer laodeng-govpc +hermes config set memory.honcho.api_key "$(cat ~/.honcho-keys/govpc.key)" + +# macbook 额外 +hermes config set memory.honcho.peer laodeng-mac +hermes config set memory.honcho.api_key "$(cat ~/.honcho-keys/mac.key)" +``` + +### Phase 4: 交叉验证(关键!) + +**Step A: 网络 + Auth** + +3 台机器各跑: + +```bash +curl -s -o /dev/null -w "HTTP %{http_code}\n" \ + -H "Authorization: Bearer $(cat ~/.honcho-keys/xxx.key)" \ + http://10.0.0.1:8000/v2/workspaces/home +# 期望: HTTP 200 +``` + +**Step B: 跨端召回** + +```bash +# mypc03 写一条 +hermes memory retain "2026-06-20 mypc03 测试 honcho 跨设备共享 v1" + +# gov-pc 召回 +hermes memory recall "honcho 跨设备共享" +# 期望: 看到 mypc03 写的那条 +``` + +**Step C: 隔离验证(确认 peer 字段)** + +```bash +# honcho 管理 API(vm61 上) +docker exec honcho-database psql -U honcho -d honcho -c \ + "SELECT name, created_at FROM peers WHERE workspace = 'home';" +# 期望: 3 行,name 各不相同 +``` + +### Phase 5: deriver 容量观察 + +接入第 3 个客户端后,前 2 天重点观察: + +```bash +# vm61 看 deriver 进度 +docker logs honcho-deriver --since 1h | grep -E "queue|processed|done" + +# 队列深度 +curl -s http://10.0.0.1:8000/v2/admin/queues \ + -H "Authorization: Bearer $(cat /root/.honcho-keys/admin.key)" | jq +``` + +**告警阈值**: + +| 指标 | 正常 | 警告 | 干预 | +|---|---|---|---| +| 队列深度 | < 500 | 500-2000 | > 2000 持续 1h → 考虑错峰 | +| deriver done/min | 2-4 | 4-8 | > 8 持续 → 加 worker | +| Postgres 连接 | < 50 | 50-100 | > 100 → 调大 max_connections | + +--- + +## 5. 故障排查 + +| 症状 | 排查 | 修复 | +|---|---|---| +| `curl HTTP 401` | key 不对 / expired | 重新跑 `create-multi-keys.sh` | +| `curl HTTP 404` | workspace 名错 | `hermes config get memory.honcho.workspace` 必须 = `home` | +| `curl timeout` | WireGuard 没拨上 | `wg show` 看握手时间;`ping 10.0.0.1` | +| 召回不到 mypc03 写的 | peer 不在同一 workspace | 三台 `hermes config get memory.honcho.workspace` 都该是 `home` | +| deriver 队列暴涨 | LLM 限流(SiliconFlow) | 临时调低 deriver 并发;或加备份 LLM endpoint | +| honcho-api OOM | 写入太频繁 | `docker stats honcho-api`;考虑加 limit | + +--- + +## 6. 撤销 / 隔离某个客户端 + +需要把 gov-pc 从共享里踢出去(换工作 / 借人): + +```bash +# vm61 上 +docker exec honcho-database psql -U honcho -d honcho -c \ + "DELETE FROM api_keys WHERE name = 'laodeng-govpc';" + +# 立即生效,无需重启 honcho +``` + +**注意**:revoke 后该客户端后续的 retain/recall 会失败;该客户端的 peer 数据**不会被删**,只是没法继续写。如要删数据: + +```sql +DELETE FROM messages WHERE peer_id = (SELECT id FROM peers WHERE name = 'laodeng-govpc'); +DELETE FROM peers WHERE name = 'laodeng-govpc'; +``` + +--- + +## 7. 关联资源 + +| 资源 | 路径 | 说明 | +|---|---|---| +| honcho stack | `deploy.stack/honcho/` | 当前部署 | +| WireGuard 部署 | `deploy.stack/WireGuardVPN/wg-easy/` | 已有,给 3 客户端分配 10.0.0.2/3/4 | +| honcho deriver 调试 | honcho memory (2026-06-19/20) | deriver 修复历史 | +| Hermes memory provider 切换 | hermes-agent skill | `memory.provider honcho` 配法 | +| 凭据管理 | `~/.honcho-keys/` | chmod 600,绝不入 git | + +--- + +## 8. 后续 TODO(可选) + +- [ ] 把 `memory.honcho.api_url` 改成 hostname 而非 IP(DNS 友好) +- [ ] 给 honcho-api 加 TLS(自签 CA 推 3 客户端) +- [ ] deriver 加 Prometheus exporter,接 vm61 VictoriaMetrics +- [ ] cron: 每天 pg_dump honcho DB → dufs 备份(参考 hindsight/backup.job) +- [ ] 4 个客户端的 hermes 版本统一(避免 protocol 不一致) \ No newline at end of file