Files
gori-agent/AGENTS.md
T
2026-08-16 11:07:33 +08:00

354 lines
13 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 项目施工指南
本文件供 Kimi Code 等 Coding Agent 在本仓库中施工时使用。目标是让后续 Agent 先理解架构和配置契约,再做最小、可验证的修改。
## 1. 项目定位
`gori-agent` 是一个 Node.js 20+ / TypeScript 项目,通过 IM 接收用户请求,并通过官方 Agent Client Protocol(ACP)驱动 Coding Agent。
当前主链路:
```text
用户
→ QQ / 其他 IM
→ Platform Adapter
→ Gateway
→ AcpSessionManager
→ AcpWorker
→ ACP Coding Agent(默认 Kimi Code)
→ 工具、脚本和工作目录
→ 原路返回用户
```
当前运行时只使用 ACP。不要重新引入“一句话启动一次 CLI”的单轮调用方式,也不要把 legacy `CliAgent` 当作运行时 fallback。
模型和 provider 属于 ACP 后端自身的配置。例如 Kimi Code 使用其自己的 `config.toml`;`gori-agent/config.json` 只配置如何启动 ACP backend,不负责复制或管理模型凭据。
## 2. 核心设计原则
- **Role 是业务身份**:定义职责、workspace、skills 和权限策略。
- **Backend 是执行后端**:定义 ACP 子进程的 command、args 和 env。
- **Skill 是可注入知识**:顶层声明 SKILL.md,role 按 ID 引用。
- **Session 是连续对话**:同一 `platform + chat + role` 复用同一 native ACP session。
- **权限由 ACP policy 约束**:persona 不是安全边界,不能替代 permission policy。
- **默认 fail closed**:不确定时拒绝权限,不自动扩大工具或命令范围。
- **一个进程只登录一个 QQ Bot**:多 Bot 使用多个进程和独立配置、端口、状态目录。
## 3. 代码结构
- `src/server.ts`
- 组装 store、role registry、ACP session manager、Gateway 和平台 adapter。
- 挂载 health/platform/webhook 路由,按配置启动 QQ WebSocket。
- `src/config.ts`
- config v2 的 Zod schema、默认值、交叉引用校验和 v1 Kimi 配置迁移。
- 新增配置字段时,必须先更新 schema,再更新模板、setup/doctor、测试和文档。
- `src/core/gateway.ts`
- 入站 allowlist、群聊 mention 规则、命令分发、per-chat 串行锁和回复发送。
- `/cancel` 必须能绕过 chat lock,避免无法取消长任务。
- `src/core/command-router.ts`
- `/help`、`/roles`、`/role`、`/status`、`/cancel`、`/new`。
- `src/core/durable-session-store.ts`
- 持久化 role 选择和 ACP session binding。
- 使用单 writer lock 和原子写入;不要绕过或手改运行中的 state。
- `src/roles/role-registry.ts`
- 读取 role、加载 skill、生成 fingerprint 和隐藏 bootstrap prompt。
- `src/roles/skill-loader.ts`
- 校验 skill 文件、大小限制并计算内容 hash。
- `src/acp/client.ts`
- ACP initialize、session new/resume/load、prompt、cancel 和 permission request。
- `src/acp/worker.ts`
- 在 `role.workspace` 中启动 ACP 子进程,处理超时、取消和异常退出。
- `src/acp/session-manager.ts`
- 管理 chat/role binding、worker 池、冷恢复、idle sweep、容量淘汰和 reset。
- `src/platforms/qq/`
- QQ WebSocket、webhook、验签、消息标准化和发送。
- `src/cli.ts`、`src/cli/`
- setup、doctor、status 和 backend discovery。
- `src/agents/`、`src/core/session-store.ts`
- legacy compatibility/reference,不是当前运行链路。除非需求明确,不要在这里扩展新能力。
- `dist/`
- TypeScript 构建产物。只修改 `src/`,不要手改 `dist/`。
## 4. Config v2 契约
唯一可提交的配置模板是 `config.example.json`。真实部署配置复制为本地 `config.json`:
```bash
cp config.example.json config.json
chmod 600 config.json
```
`config.json` 和备份包含 IM credentials,不得提交。
### 4.1 顶层字段
```text
configVersion 必须为 2
server HTTP 服务配置
policy IM 入站访问策略
acp ACP 生命周期、状态和进程池配置
backends[] ACP 后端启动定义,至少一个
skills[] 可选 SKILL.md 定义
defaultRole 默认 role ID
roles[] 业务角色定义,至少一个
platforms QQ、Feishu、WeCom、Webhook、Weixin 配置
```
Zod 会剥离 schema 未声明的字段。因此不能只在 JSON 中增加字段而不修改 `src/config.ts`。
### 4.2 `server`
- `host`:默认 `0.0.0.0`。
- `port`:1–65535;多实例必须使用不同端口。
- `publicBaseUrl`:反向代理或公开 webhook 基础地址;不需要时为空。
### 4.3 顶层 `policy`
- `allowedUsers: string[]`:空数组表示不按用户限制;非空时精确匹配。
- `allowedChats: string[]`:空数组表示不按会话限制;非空时精确匹配。
- `requireMentionInGroup: boolean`:群聊是否必须 @bot。
- QQ 群 chat ID 形式为 `group:<group_openid>`。
- 正式运维 Bot 应配置 allowlist,不要长期保持完全开放。
### 4.4 `acp`
- `stateFile`:空字符串时使用 `$GORI_AGENT_HOME/state/acp-sessions.json`。
- `initializeTimeoutMs`:ACP 初始化超时。
- `promptTimeoutMs`:单轮 prompt 超时。
- `cancelGraceMs`:取消后等待时间,超时才终止 worker。
- `idleTimeoutMs`:空闲 worker 回收时间;session binding 仍可持久化恢复。
- `sweepIntervalMs`:空闲扫描周期。
- `maxProcesses`:最大 ACP 子进程数。
不同实例不得共享 `stateFile` 或 `GORI_AGENT_HOME`。持久 store 有单 writer lock,共享会使第二个实例启动失败。
### 4.5 `backends[]`
每项字段:
```json
{
"id": "kimi",
"command": "/home/USER/.kimi-code/bin/kimi",
"args": ["acp"],
"env": {}
}
```
约束:
- `id` 必须唯一。
- `command` 必须是可执行程序。
- Kimi Code backend 应使用 `args: ["acp"]`。
- 子进程以 `shell: false`、`cwd: role.workspace` 启动。
- `env` 会覆盖同名进程环境变量;不得把 token 或 API key 写入可提交模板。
- 新增其他 Coding Agent 前,必须确认它提供兼容 ACP,或提供独立且有测试的 ACP adapter;不要假设普通 CLI 等同 ACP。
### 4.6 `skills[]`
每项字段:
```json
{
"id": "SKILL_ID",
"file": "/absolute/path/to/SKILL.md",
"maxBytes": 256000
}
```
约束:
- `id` 必须唯一。
- 建议使用绝对路径,避免不同启动目录导致解析变化。
- 文件必须存在、可读、是普通文件且不超过 `maxBytes`。
- Role 只能引用已在顶层声明的 skill ID。
- Skill 内容会发送给 ACP backend,也参与 role fingerprint;不要在 skill 中放 secret。
### 4.7 `roles[]`
推荐一个 Bot 实例只保留它自己的一个 role:
```json
{
"id": "ROLE_ID",
"backend": "kimi",
"workspace": "/absolute/path/to/workspace",
"persona": "明确描述职责、边界和何时停止请求确认。",
"skills": [],
"policy": {
"permissionMode": "deny",
"allowedTools": [],
"allowedCommandPatterns": []
}
}
```
约束:
- Role `id` 必须唯一,`defaultRole` 必须引用存在的 role。
- `workspace` 必须是绝对路径,并应在 `doctor` 时真实存在。
- `backend` 和 `skills` 引用必须存在。
- 修改 role ID、backend、workspace、persona、policy 或 skill 内容会改变 fingerprint;下一条消息会创建新 native session,避免沿用旧身份上下文。
权限模式:
- `deny`:拒绝所有 ACP permission request;新角色默认使用此模式。
- `allowlist`:只允许 `allowedTools`;bash/terminal 还必须匹配至少一个 `allowedCommandPatterns` 正则。
- `auto`:自动允许,等价于高风险/yolo;只有用户明确要求、workspace 与 Bot 访问范围都可控时才能配置。
配置 `allowlist` 时:
- 使用最小工具集合。
- 命令正则应锚定开头并限制参数,不要使用 `.*` 放行所有命令。
- 删除、部署、推送、发送消息等不可逆或外部操作仍应在 persona 中要求确认。
- permission request 信息不足时必须拒绝,不能猜测。
### 4.8 `platforms.qq`
```json
{
"enabled": true,
"connectionMode": "websocket",
"appId": "QQ_APP_ID",
"clientSecret": "QQ_CLIENT_SECRET",
"botSecret": "",
"verifySignature": true,
"botNames": ["QQ_BOT_NAME"],
"intents": 33554432,
"shard": [0, 1]
}
```
- WebSocket 登录需要有效的 `appId` 和 `clientSecret`。
- Webhook 验签使用 `botSecret || clientSecret`。
- `botNames` 用于 mention 识别,应与平台上的机器人名称一致。
- 一个 config 只有一个 QQ 对象,因此一个进程只能登录一个 QQ Bot。
- 不要把 QQ 注销、群注销、无权限等平台 4xx 错误误判成 ACP session 错误;先检查错误码、目标 chat/user openid 和消息发送 endpoint。
其他平台字段以 `src/config.ts` schema 为准。平台 `enabled` 不一定会统一禁用所有 HTTP 路由;公开 webhook 时仍需检查路由和验签实现。
## 5. Role 与 Session 行为
- Binding key 是 `platform + chatId + roleId`。
- 同一 chat 的不同 role 拥有不同 native ACP session。
- 首次 prompt 会创建 session、发送隐藏 bootstrap,成功后保存 binding,再发送用户请求。
- Gateway 或 ACP worker 重启后,使用持久 binding 尝试 `session/resume`,必要时回退 `session/load`。
- `/new` 删除当前 chat/role binding;下一条普通消息再创建新 session。
- `/cancel` 取消当前 turn,不应等待正在执行的 chat lock。
- Prompt 失败不能擅自重放,因为工具操作可能已经产生副作用。
- Session 上下文由 native ACP Agent 维护;gori-agent 维护角色选择、binding、生命周期和恢复信息,不应每轮把完整历史重新拼给 CLI。
## 6. 多机器、多 Bot 部署规范
每个 Bot 使用一份位于部署机器上的本地 `config.json`,不要在仓库中创建 `config.ops.json`、`config.developer.json` 等带真实凭据的文件。
每个实例至少要唯一:
- QQ `appId`、`clientSecret`、`botNames`
- `server.port`
- `GORI_AGENT_HOME`,或显式且独立的 `acp.stateFile`
- role ID、workspace、persona 和 policy
示例:
```bash
GORI_AGENT_HOME=/home/USER/.gori-agent-ROLE_ID \
./gori-agent.sh start-daemon --config ./config.json
```
`GORI_AGENT_HOME` 隔离:
- PID
- 日志
- 默认 ACP session state
- 单实例锁
同一机器启动多个实例时,每个实例应从各自部署目录运行,或明确指定独立配置路径和 `GORI_AGENT_HOME`。
## 7. 配置施工流程
当用户让 Agent 配置一个新角色或新 Bot 时,按以下顺序执行:
1. 读取 `AGENTS.md`、`config.example.json` 和相关 schema;不要先读取或展示真实 secrets。
2. 明确 role 的职责、workspace、所需 skills、允许的工具和命令。
3. 确认 backend 可执行路径以及 `kimi acp` 可用。
4. 从唯一模板复制本地 `config.json`,不另建可提交的具体 Bot 模板。
5. 填写本机 QQ credentials;不要在回复、日志、diff 或测试输出中回显。
6. 默认先用 `deny`;需要施工能力时配置最小 `allowlist`;只有明确授权才使用 `auto`。
7. 设置文件权限为 `0600`。
8. 运行配置和 backend 检查:
```bash
./gori-agent.sh discover-backends --config ./config.json
./gori-agent.sh doctor --config ./config.json
```
9. 前台启动,确认 QQ WebSocket ready,再从 IM 执行只读验收。
10. 前台通过后,使用唯一 `GORI_AGENT_HOME` 后台启动。
11. 任何包含 secret 的配置、备份和日志都不得加入 Git。
若缺少真实凭据,可以完成无密钥模板和规范,但不得虚构 credentials,也不得声称真实 QQ 登录已验证。
## 8. 常用命令
```bash
npm install
npm run typecheck
npm test
npm run build
gori-agent setup --config ./config.json
gori-agent discover-backends --config ./config.json
gori-agent doctor --config ./config.json
gori-agent start --config ./config.json
./gori-agent.sh start --config ./config.json
./gori-agent.sh start-daemon --config ./config.json
./gori-agent.sh status --config ./config.json
./gori-agent.sh logs
./gori-agent.sh stop
```
`gori-agent.sh` 不会检测源码是否比 `dist/` 新。修改 TypeScript 后必须显式运行 `npm run build`。
## 9. 修改与验收规则
- 做最小、局部、可审查的修改,不做无关重构。
- 先修改 `src/`,不要直接修改 `dist/`。
- 行为变化应补对应测试;不要通过削弱测试来适配实现。
- 配置 schema 变化必须同步:
- `src/config.ts`
- `config.example.json`
- setup/doctor(如适用)
- README 和本文件
- 配置测试
- 平台错误必须保留足够的错误码和 trace ID 用于诊断,但不得输出 secret。
- 修改后运行:
```bash
npm run typecheck
npm test
npm run build
git diff --check
```
- 测试未通过时不能宣称完成。
- 不执行真实 QQ 消息、pull、部署、push、创建 PR 等外部操作,除非用户明确要求并授权。
- 不自动执行 Git commit/push;需要时按用户当次指令处理。
## 10. 敏感信息与禁止提交内容
不得提交或粘贴:
- `config.json`
- `config.json.*.bak`
- 任意包含真实 Bot/App credentials 的自定义配置
- `.env`
- `backends[].env` 中的 token/API key
- ACP state、PID、lock 和 session metadata
- 日志中的真实 chat ID、user ID、message ID、消息正文或 ACP stderr 敏感内容
唯一可提交配置模板:`config.example.json`。其中只能使用明显占位符。
当前 `.gitignore` 已覆盖 `config.json`、备份、日志、`dist/`、`node_modules/` 和 coverage。新增其他具体配置文件名时,不要依赖命名约定判断安全;只要包含真实凭据,就必须留在仓库外或明确忽略。