Files
gori-agent/README.md
T

257 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# gori-agent
`gori-agent` 是一个 Node.js 20+ / TypeScript 网关:从一个 IM 平台接收消息,通过官方 Agent Client Protocol(ACP)驱动一个 Coding Agent。
```text
用户 → 单个平台 Adapter → Gateway → ACP Session Manager → 单个 ACP Agent
```
## Config v3 实例模型
Config v3 只支持以下边界:
- 一份运行配置对应一个固定 Bot 身份。
- 一个 Bot 只有一个 workspace、persona、ACP agent、skill 列表和 permission policy。
- 一个实例只绑定一个平台;多平台使用多个实例。
- 不再有 `roles[]`、`defaultRole`、`backends[]`、动态 `/role` 切换或 Config v1/v2 迁移。
- `configVersion` 非 `3` 会明确失败,旧 state v1 也不会自动改写。
一台机器上的实例统一位于:
```text
${GORI_AGENT_ROOT:-$HOME/.gori-agent}/instances/<bot-id>/
├── config.json
├── logs/gori-agent.log
└── state/
├── acp-sessions.json
└── gori-agent.pid
```
实例目录就是该进程的 `GORI_AGENT_HOME`。实例目录、`state/`、`logs/` 使用 `0700`,配置与状态文件使用 `0600`。
## 构建与安装
```bash
npm install
npm run build
./install.sh
```
安装器只安装一个 launcher;不会为每个 Bot 复制源码或 `dist/`。默认 launcher 位于 `$HOME/.gori-agent/bin/gori-agent`。
确认 ACP agent 可用:
```bash
kimi --version
kimi doctor
kimi acp --help
gori-agent discover-backends
```
模型和 provider 由 ACP agent 自身配置,例如 Kimi Code 使用 `~/.kimi-code/config.toml`。gori-agent 不复制模型凭据。
## 实例管理
```bash
gori-agent instance init <bot-id>
gori-agent instance doctor <bot-id>
gori-agent instance start <bot-id>
gori-agent instance status <bot-id>
gori-agent instance logs <bot-id>
gori-agent instance restart <bot-id>
gori-agent instance stop <bot-id>
gori-agent instance list
```
- `init` 交互生成 Config v3,本身不启动 Bot;它会询问并校验 `gateway.server.host/port`,扫描统一实例目录中其他 Config v3 的声明端口,并在默认端口冲突时建议下一个未占用端口。已有配置通过 `setup` 重跑时可保留或修改 host/port,不会静默改端口。
- 平台 secret/token 使用不回显输入,空 generic webhook/weixin secret 会随机生成。
- `start` 会检查配置存在、目录名匹配 `bot.id`、目录/配置权限、模板占位符、workspace、agent executable、PID identity 和端口,并等待 `/health` 返回匹配的 Bot/platform identity;任一不满足即 fail closed。
- `status` 核对 PID 对应的完整 `start --config` 身份以及 `/health` 返回的 Bot/platform identity。
- 每个实例必须使用不同的 `gateway.server.port` 和平台凭据;setup 的声明冲突提示不替代 `start` 的实际端口检查。
- `stop` 发送 `SIGTERM` 并等待最多 10 秒,不会自动 `SIGKILL`。
可用 `GORI_AGENT_ROOT` 改变统一根目录:
```bash
GORI_AGENT_ROOT=/srv/gori-agent gori-agent instance list
```
## `config.example.json` 的定位
`config.example.json` 是仓库内唯一可提交、无密钥的配置说明,不是运行配置。它可被 Config v3 schema 解析,但保留 `BOT_ID`、`QQ_APP_ID` 等明显占位符。
`start`、`status`、`doctor`、`print` 找不到本地配置时会失败,绝不会回退到 example。只有 `setup` 和 `instance init` 会读取 example 作为初始化种子。
底层调试入口仍可使用:
```bash
gori-agent setup --config /absolute/path/config.json
gori-agent start --config /absolute/path/config.json
gori-agent status --config /absolute/path/config.json
gori-agent doctor --config /absolute/path/config.json
gori-agent print feishu --config /absolute/path/config.json
```
`writeConfigFile()` 使用同目录临时文件、`fsync` 和原子 rename,并强制最终文件为 `0600`。
## Config v3
完整说明见 `config.example.json`。顶层只有:
```text
configVersion 固定为 3
bot Bot、workspace、persona、agent、skills、permissions
gateway HTTP server、入站 policy、唯一 platform
runtime.acp ACP state、timeout 和 worker pool
```
### Bot 与 ACP agent
```json
{
"bot": {
"id": "my-bot",
"workspace": "/absolute/workspace",
"persona": "Describe responsibilities, boundaries, and confirmation points.",
"agent": {
"id": "kimi",
"command": "/home/USER/.kimi-code/bin/kimi",
"args": ["acp"],
"env": {}
},
"skills": [],
"permissions": {
"mode": "deny",
"allowedTools": [],
"allowedCommandPatterns": []
}
}
}
```
- `bot.id` 只允许小写字母、数字和连字符,最长 63 字符。
- `workspace` 与每个 skill `file` 必须是绝对路径。
- `bot.skills[]` 直接声明 `{ id, file, maxBytes }`;ID 必须唯一。
- agent 使用 `shell: false` 在 `bot.workspace` 启动。
- agent env 可能包含 secret,不能进入可提交模板、日志或 diff。
### Permission policy
ACP permission request 由 `bot.permissions` 决策,persona 不是安全边界:
- `deny`:拒绝所有 permission request,默认值。
- `allowlist`:`toolCall.name` 必须与 `allowedTools` 精确匹配;bash/terminal 还必须由至少一个 `allowedCommandPatterns` 正则完整覆盖整条 raw command。名称或 command 缺失时拒绝。
- `auto`:自动允许,风险等价于 yolo;`doctor` 会告警。
`allowedTools` 只控制 ACP 审批,不会注册或创造工具。skills、agent 与 permission policy 是三个独立概念。
### 单平台配置
`gateway.platform` 是按 `type` 区分的 union,只能选择一个:
- `qq`:WebSocket 或 webhook。
- `feishu`:`/webhook/feishu`。
- `wecom`:`/webhook/wecom`;入站仍是 501 scaffold。
- `webhook`:`/webhook/generic`,同步 JSON + HMAC-SHA256。
- `weixin`:`/webhook/weixin`,外部 bridge scaffold。
对象存在即启用,不再使用 `enabled`。Server 只构造所选 adapter,也只挂载需要的 webhook route。QQ WebSocket 仅在 `type=qq` 且 `connectionMode=websocket` 时启动,此模式不挂载 `/webhook/qq`。
QQ websocket 示例:
```json
{
"type": "qq",
"connectionMode": "websocket",
"appId": "QQ_APP_ID",
"clientSecret": "QQ_CLIENT_SECRET",
"botSecret": "",
"verifySignature": true,
"botNames": ["QQ_BOT_NAME"],
"intents": 33554432,
"shard": [0, 1]
}
```
正式 Bot 应通过 `gateway.policy.allowedUsers` / `allowedChats` 限制入口。QQ 群 chat ID 为 `group:<group_openid>`。
### ACP 生命周期
默认 `runtime.acp.promptTimeoutMs` 是 `7200000`(2 小时),适合长构建/部署任务。其他默认值:
- initialize:10 秒
- cancel grace:5 秒
- idle worker:30 分钟
- sweep:60 秒
- max processes:8
`stateFile` 为空时使用当前实例的 `$GORI_AGENT_HOME/state/acp-sessions.json`。
## Session 与 state v2
每个绑定由当前实例固定的 `platform + chatId` 唯一确定。state v2 header 保存 `botId` 与 platform type;打开 state 时身份不匹配会拒绝启动,避免错误复用另一个实例目录。
Binding 保存:
- chat key
- agent ID
- native ACP session ID
- workspace
- Bot fingerprint
- 创建与更新时间
Bot fingerprint 包含 Bot ID、workspace、persona、agent、permissions、skill 路径/内容 hash 和 bootstrap schema version。任一语义变化后,下一条消息创建新 native session,不恢复旧身份上下文。
首次 prompt 会创建 native session,发送隐藏 bootstrap,bootstrap 成功后才保存 binding。worker 空闲回收后优先 `session/resume`,否则回退 `session/load`。失败 prompt 不会自动重放,因为工具操作可能已有副作用。
旧 state v1 会被原样保留并明确拒绝;使用新的实例目录开始 state v2,不要手工改写运行中的 state。
## IM 命令
```text
/help
/status
/cancel
/new
```
- `/status` 显示固定 Bot、agent、workspace 和 session persisted/running 状态。
- `/cancel` 绕过 per-chat lock,发送 ACP cancel。
- `/new` 清除当前 chat binding;下一条普通消息创建新 native session。
- `/roles`、`/role`、`/agents`、`/agent` 会返回固定 retired 提示,不会转发给 ACP。
同一 chat 串行执行,不同 chat 可并发。
## HTTP 端点
- `GET /health`:`configVersion`、`botId`、platform 和 aggregate ACP counters,不暴露凭据/native session ID。
- `GET /platforms`:当前单一 Bot/platform 概览。
- `POST /webhook/<selected-platform>`:只存在所选平台路由;generic 使用 `/webhook/generic`。
## Doctor 与安全纪律
`instance doctor` / `doctor --config` 检查:
- Config v3 与 example placeholder。
- 配置权限 `0600`。
- Bot ID、workspace、skills 与 permissions。
- ACP initialize 与 session restore capability。
- state 目录可读写。
- 单平台必需字段,但不打印 credential 值。
自动测试不会启动真实 Bot、发送平台消息、pull、部署或访问远程机器。真实 `config.json`、备份、state 和日志不得提交。
## 开发验收
```bash
npm run typecheck
npm test
npm run build
git diff --check
bash -n install.sh gori-agent.sh bin/gori-agent
```
测试使用 Node `node:test` + `tsx` 和本地 fake ACP 子进程,覆盖 Config v3、permission、bootstrap、timeout/cancel、冷恢复、fingerprint mismatch、state v2 identity、原子配置/state 写入、Gateway retired commands、QQ normalization 和单平台 route。
`src/agents/*` 与 `src/core/session-store.ts` 仅为 legacy compatibility/reference,不在当前运行链路。运行时没有单轮 CLI fallback。