# WxAgent Control Plane Go 1.23 控制面与 React 管理端。节点只主动出站连接,控制面不暴露节点端口。 ## 本地启动 ```bash cd control-plane npm --prefix web ci --no-audit --no-fund npm --prefix web run build go run ./cmd/wxagent-control-plane ``` 启动前设置(单节点兼容写法): ```bash export WXAGENT_NODE_ID=local-node export WXAGENT_NODE_TOKEN='local-node-token' export WXAGENT_WEB_USER=admin export WXAGENT_WEB_PASSWORD='change-me' ``` 多节点/多用户使用 JSON map: ```bash export WXAGENT_NODE_TOKENS='{"node-a":"token-a","node-b":"token-b"}' export WXAGENT_WEB_USERS='{"admin":"change-me","auditor":"read-only-password"}' ``` 可选:`WXAGENT_CONTROL_PLANE_ADDR`(默认 `127.0.0.1:8090`)、`WXAGENT_CONTROL_PLANE_DATA`(默认 `control-plane-data.json`)。凭据可通过环境变量或 `*_FILE` Secret 文件读取,不写入控制面数据文件和日志。节点的 `remoteConfigurationFile` 仅用于读取预置配置;Windows Agent 不提供命令行修改配置,启动和本机配置必须通过双击 `WxAgent.Tray.exe` 后的“服务设置...”窗口完成。 生产控制面可直接启用 TLS 和节点 mTLS: 可选的 AI Provider 使用 OpenAI-compatible `chat/completions` 接口;密钥只从环境或 Secret 文件读取: ```text WXAGENT_AI_BASE_URL=https://api.openai.com/v1 WXAGENT_AI_API_KEY_FILE=/run/secrets/ai_api_key WXAGENT_AI_MODEL=gpt-4o-mini WXAGENT_AI_TIMEOUT=60s WXAGENT_AI_SCHEDULER_INTERVAL=5s ``` ```text WXAGENT_CONTROL_PLANE_TLS_CERT_FILE WXAGENT_CONTROL_PLANE_TLS_KEY_FILE WXAGENT_MTLS_CLIENT_CA_FILE WXAGENT_MTLS_REQUIRE_NODE_CERT=true WXAGENT_MTLS_REVOKED_CERTS_FILE WXAGENT_NODE_TOKENS_FILE=/run/secrets/node_tokens WXAGENT_WEB_USERS_FILE=/run/secrets/web_users ``` 节点证书按证书原始 DER 的 SHA-256 指纹逐行写入撤销文件;文件读取失败时节点认证拒绝。控制面还提供 `/readyz`,并对数据文件使用单写入者锁、自动轮转备份和任务/事件/审计保留期限。生产示例见 [`compose.production.yml`](./compose.production.yml)。 浏览器访问 `http://127.0.0.1:8090/`,登录后管理节点、任务、白名单事件和审计记录。生产部署必须使用 HTTPS、节点 mTLS 和外部 Secret 文件;本地 HTTP 仅用于显式的私有网络/loopback 集成测试。 远程只读查询使用同一持久化任务队列,返回 `task_id` 后通过 `GET /v1/tasks/{task_id}` 取结果: ```text POST /v1/reads/sessions { node_id, account_id, idempotency_key, limit?, offset? } POST /v1/reads/contacts { node_id, account_id, idempotency_key, groups_only, contains?, limit?, offset? } POST /v1/reads/messages { node_id, account_id, idempotency_key, chat_id, include_content?, limit?, offset? } ``` 节点只返回本地已启用且 `identityVerified` 的白名单会话;未授权范围在节点读取前拒绝。`chat_id` 必须使用会话列表返回的稳定会话标识,消息结果是当前微信 UI 可见历史,不是数据库全量历史。联系人查询中的 `chat_id` 使用联系人数据库稳定 ID;所有响应仍受任务结果大小和分页上限约束。 ### AI 消息处理 Web 端的“AI 处理”页面用于创建消息处理流程。每个流程绑定一个或多个 `node_id + account_id + chat_id + chat_type` 目标,支持: - `realtime`:由节点已授权的实时消息事件触发; - `interval`:由控制面按秒间隔创建 `read-messages` 只读任务; - `output_schema`:根节点为 `object` 的 JSON Schema,AI 输出会在控制面再次校验; - `read_message_context`:读取本次有限消息上下文; - `reply_text`:在流程显式授权后,向来源群聊/私聊创建一个受控 `send-text` 任务。 相关接口: ```text GET /v1/ai/tools GET /v1/ai/flows POST /v1/ai/flows GET /v1/ai/flows/{flow_id} PUT /v1/ai/flows/{flow_id} DELETE /v1/ai/flows/{flow_id} POST /v1/ai/flows/{flow_id}/run GET /v1/ai/runs?flow_id=&limit= ``` AI 处理仍受节点本地白名单约束。定时读取的消息范围与普通 `read-messages` 相同,只是当前微信 UI 可见历史,不是数据库全量历史。AI Provider 未配置时流程可以保存,但执行记录会明确失败,不会把消息内容写入普通日志。 ## 验证 ```bash cd control-plane go test ./... go vet ./... cd ../control-plane/web npm run build cd ../.. ./scripts/remote-control-smoke.sh ``` `remote-control-smoke.sh` 会启动一次临时控制面,运行 .NET 节点协议客户端,验证注册、心跳、任务租约、幂等、结果回传和白名单拒绝;不会操作真实微信联系人。 控制面并发/读取任务基线(使用已注册的测试节点,不执行写任务): ```bash WXAGENT_SCALE_WEB_PASSWORD='' \ scripts/control-plane-scale-smoke.py --base-url http://127.0.0.1:8090 \ --node-id node-a --account-id account-a --requests 100 --workers 10 ``` `control-plane-data.sh backup`/`restore` 用于停机前后的手工备份和原子恢复;自动备份由 Store 按 `WXAGENT_CONTROL_PLANE_BACKUP_INTERVAL`(默认 5 分钟)产生。当前 JSON 存储使用 active/passive 单写锁,不支持 active-active 多实例共享写入。 ## Windows 手工验收 1. 在已登录且未锁定的微信桌面会话中双击 `WxAgent.Tray.exe`;首次运行或托盘菜单“服务设置...”打开后,配置本机监听、凭据、验证模式和自动锁屏。 2. 不使用 `WxAgent.Host serve`、`--config`、`remote auth set`、`remote reporting enable/allow` 或其他命令行配置。`WxAgent.Host doctor`、`inspect-ui`、`remote ... show/probe` 仅用于只读诊断。 3. 远程配置若已由部署系统预置,托盘服务读取 `remoteConfigurationFile`;当前不通过命令行修改远程地址、Token、节点 ID 或 reporting 白名单。 4. 仅使用文件传输助手、`Hao 豪`、`吉祥三宝`、`消息测试专用群组`做发送/接收验证:先确认目标账号、稳定 chat ID 和文本;Web/HTTP/MCP 写操作仍必须通过现有确认门禁。 5. 在控制面取消任务并验证节点不执行;断开网络后恢复,确认未完成副作用任务显示 `ResultUnconfirmed`,不会自动重放。 未解锁的 Session 0、昵称、PID、窗口句柄和未确认的运行时身份都应视为验收失败;手工验收不得改写微信数据库或绕过安全机制。 ## 容器镜像 `.gitea/workflows/build-web-image.yml` 会构建并推送 `git.ipao.vip//` 镜像:主分支额外更新 `latest`,`v*` 标签额外更新对应版本标签。请在 Gitea 账号级 Secrets 配置 `REGISTRY_TOKEN`;登录用户名使用仓库所有者。 生产环境不要提交 `compose.production.yml` 所引用的 `secrets/` 文件。将节点 Token map、Web 用户 map、TLS 私钥、客户端 CA 和撤销指纹列表放入外部 Secret 管理或受 ACL 保护的部署目录,再运行 `docker compose -f compose.production.yml up -d`。证书泄露时可用 `scripts/revoke-client-certificate.sh` 更新指纹列表,并重建 Docker Secret 挂载的容器。