Files
gori-agent/AGENTS.md
T

263 lines
9.9 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 项目施工指南
本文件供 Coding Agent 在本仓库施工时使用。先理解 Config v3 和实例隔离契约,再做最小、可验证的修改。
## 1. 项目定位与固定边界
`gori-agent` 是 Node.js 20+ / TypeScript 项目,通过单个 IM 平台接收请求,并通过官方 Agent Client Protocol(ACP)驱动一个 Coding Agent。
```text
用户 → Platform Adapter → Gateway → AcpSessionManager → AcpWorker → ACP Agent
```
每个运行实例是一个完整且固定的 Bot:
- 一个 Gateway 进程。
- 一份 Config v3 本地配置。
- 一个 `bot.id`、workspace、persona。
- 一个 ACP agent。
- 一组直接声明的 skills 与一个 permission policy。
- 一个平台身份。
- 独立 PID、日志和 ACP state。
不要重新引入 Config v1/v2 migration、`roles[]`、动态 role selection、`backends[]`、多平台同时启用或单轮 CLI fallback。
## 2. 实例目录契约
统一实例根:
```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`。约束:
- `bot.id` 只允许小写字母、数字和连字符,拒绝 `/`、`..` 等路径穿越。
- CLI 加载后必须校验目录名与 `config.bot.id` 相同。
- 实例目录、`logs/`、`state/` 为 `0700`。
- `config.json`、PID、state 为 `0600`。
- 多实例必须使用不同 `gateway.server.port` 和平台 credentials。
- `instance init` / `setup` 必须交互询问并校验 server host/port;扫描其他 Config v3 的声明端口,冲突时警告,新实例建议下一个未声明端口,已有配置不得静默改端口。
- setup 的声明冲突提示不替代实际 bind 检查;`start` 对缺配置、ID 不匹配、错误权限、占位符、运行 PID、端口冲突 fail closed。
日常入口:
```bash
gori-agent instance init <bot-id>
gori-agent instance start <bot-id>
gori-agent instance stop <bot-id>
gori-agent instance restart <bot-id>
gori-agent instance status <bot-id>
gori-agent instance logs <bot-id>
gori-agent instance list
gori-agent instance doctor <bot-id>
```
保留 `start --config`、`status --config`、`doctor --config` 等用于本地调试,但运行配置不存在时不得回退 example。
## 3. 核心代码结构
- `src/config.ts`
- Config v3 Zod schema、类型、交叉校验和 state 默认路径。
- 只接受 `configVersion: 3`。
- `src/server.ts`
- 组装 fixed Bot、state store、ACP manager、Gateway 和唯一 platform adapter。
- 只挂载所选平台 route。
- `src/roles/role-registry.ts`
- 历史路径名保留,但实现是 `BotProfileResolver`,不是 role registry。
- 加载当前 Bot skills、计算 fingerprint、生成版本化 bootstrap。
- `src/acp/client.ts`
- ACP initialize/new/resume/load/prompt/cancel 和 permission request。
- `src/acp/worker.ts`
- 直接使用 resolved Bot 的 agent,在 `bot.workspace` 启动。
- `src/acp/session-manager.ts`
- 固定 Bot 的 binding、worker pool、恢复、idle sweep、capacity、cancel/reset。
- `src/core/durable-session-store.ts`
- state v2,保存 bot/platform identity 和 chat binding。
- 单 writer lock、串行持久化、临时文件、fsync、原子 rename。
- `src/core/gateway.ts`
- 入站 allowlist、群 mention、命令、per-chat lock 和回复。
- `/cancel` 必须绕过 chat lock。
- `src/core/command-router.ts`
- `/help`、`/status`、`/cancel`、`/new`;旧 role 命令返回 retired 提示。
- `src/platforms/*`
- Adapter 依赖独立平台 config type,不依赖完整 AppConfig 路径。
- `src/cli/config-file.ts`
- fail-closed 加载、example seed 与原子 `0600` 配置写入。
- `src/cli/instance.ts`
- 实例目录、PID/log、端口和 lifecycle 管理。
- `src/cli/doctor.ts`
- v3、Bot、agent、platform、state、permission 和 placeholder 检查。
- `src/agents/*`、`src/core/session-store.ts`
- legacy compatibility/reference,不是当前运行链路。
- `dist/`
- 构建产物;不手改,修改 TypeScript 后运行 `npm run build`。
## 4. Config v3 契约
仓库中唯一可提交配置说明是 `config.example.json`。它含明显占位符,可通过 schema,但不能启动实际 Bot。
顶层:
```text
configVersion 固定 3
bot 固定 Bot、agent、skills、permissions
gateway server、入站 policy、唯一 platform
runtime.acp state 和 ACP 生命周期
```
### 4.1 `bot`
```json
{
"id": "bot-id",
"workspace": "/absolute/path",
"persona": "明确职责、边界和确认点。",
"agent": {
"id": "kimi",
"command": "/absolute/path/to/kimi",
"args": ["acp"],
"env": {}
},
"skills": [],
"permissions": {
"mode": "deny",
"allowedTools": [],
"allowedCommandPatterns": []
}
}
```
- workspace 必须绝对。
- 一个 Bot 只有一个 agent;不要添加 registry/reference。
- Kimi Code 应使用 `args: ["acp"]`。
- agent `shell: false`,cwd 为 workspace。
- 模型/provider 属于 ACP agent 自己的配置,不写入 gori-agent config。
- `env` 不得在模板、日志、diff 中泄漏 token。
### 4.2 Skills
`bot.skills[]` 每项直接声明:
```json
{ "id": "skill-id", "file": "/absolute/SKILL.md", "maxBytes": 256000 }
```
ID 唯一;文件须存在、可读、普通文件且未超限。skill 内容发送给 ACP,也进入 fingerprint;不得放 secret。
### 4.3 Permissions
- `deny`:默认,拒绝全部 permission request。
- `allowlist`:`toolCall.name` 与 `allowedTools` 精确匹配;bash/terminal 的 raw command 还要被 `allowedCommandPatterns` 完整覆盖。
- `auto`:高风险/yolo,只有用户明确授权才能设置。
permission policy 只审批 ACP request,不会注册工具。persona 不是安全边界。请求信息不足时拒绝。命令 regex 应锚定并限制参数,不使用任意 `.*` 全放行。
### 4.4 Gateway
- `gateway.server`: host、port、publicBaseUrl。
- `gateway.policy`: allowedUsers、allowedChats、requireMentionInGroup。
- `gateway.platform`: `type` discriminated union,只能是 qq、feishu、wecom、webhook、weixin 之一。
- 对象存在即启用,无 `enabled` 字段。
QQ 群 chat ID 为 `group:<group_openid>`。正式运维 Bot 应配置入口 allowlist。
### 4.5 Runtime ACP
- `stateFile` 为空时为 `$GORI_AGENT_HOME/state/acp-sessions.json`。
- `initializeTimeoutMs`: 默认 10000。
- `promptTimeoutMs`: 默认 7200000(2 小时)。
- `cancelGraceMs`: 默认 5000。
- `idleTimeoutMs`: 默认 1800000。
- `sweepIntervalMs`: 默认 60000。
- `maxProcesses`: 默认 8。
## 5. Session 与 state v2
Binding key 是当前实例固定的 `platform + chatId`。不再包含 role。
state v2 header 保存 `botId` 和 platform。打开时不匹配必须拒绝,不能清空、迁移或覆盖。旧 state v1 也明确拒绝并保留原文件。
Binding 保存 agent ID、workspace、native session ID、Bot fingerprint 和时间戳。fingerprint 包含:
- bootstrap schema version
- Bot ID
- workspace/persona
- agent 定义
- permission policy
- skill 路径和内容 hash
首次消息创建 native session,发送隐藏 bootstrap,成功后保存 binding。重启/idle 后优先 resume,再 fallback load。prompt 失败不重放。
`/new` 删除当前 chat binding;下一条消息创建新 session。`/cancel` 不等待 chat lock。
## 6. 单平台装配
Server 只构造 `gateway.platform.type` 对应 adapter,只挂载对应 webhook:
- qq webhook 模式 → `/webhook/qq`;QQ WebSocket 模式不挂载该 route
- feishu → `/webhook/feishu`
- wecom → `/webhook/wecom`
- weixin → `/webhook/weixin`
- webhook → `/webhook/generic`
QQ WebSocket 仅在 qq + websocket 模式启动。`GET /health` 只输出 configVersion、botId、platform 和 aggregate ACP counters,不得输出 credentials 或 native session ID。`GET /platforms` 返回单 Bot/platform 概览。
## 7. 配置与实例施工流程
1. 读取本文件、`config.example.json` 和 `src/config.ts`。
2. 明确 Bot ID、workspace、persona、平台、skills 和最小 permission policy。
3. 确认 ACP agent executable 与 ACP 可用。
4. 使用 `instance init` 或 Coding Agent 生成实例 `config.json`;不要把 example 当运行配置。
5. 交互确认并严格校验 `gateway.server.host/port`;对其他实例的声明端口冲突给出警告和建议,但仍由 `start` 做实际 bind 检查。
6. 写配置必须同目录临时文件 + fsync + atomic rename,最终 `0600`;目录 `0700`。
7. setup 的 secret/token 输入必须不回显;secrets 不在对话、日志、测试输出、diff 中回显。
8. 运行 `instance doctor`,不发送真实平台消息。
9. 只有用户明确授权时才启动/停止真实 Bot。
旧仓库本地 `config.json`、备份和 state 可供人工回退;改造实例时不要删除或覆盖。
## 8. 测试与验收
行为变化补测试,不削弱测试。配置 schema 变化同步:
- `src/config.ts`
- `config.example.json`
- setup/doctor/instance CLI
- README 和本文件
- config、session、store、Gateway、server 测试
最终运行:
```bash
npm run typecheck
npm test
npm run build
git diff --check
bash -n install.sh gori-agent.sh bin/gori-agent
```
额外检查:
- example 可 parse,doctor 识别 placeholder。
- 不存在的运行配置明确失败。
- tracked diff 无 config、backup、state、log、credentials 或手改 dist。
- 不执行真实平台消息、pull、部署、远程机器修改或 Git mutation,除非用户当次明确授权。
## 9. 敏感信息与禁止提交
不得提交或粘贴:
- 任何真实 `config.json` 或备份
- `.env`、agent env token/API key
- platform credentials
- ACP state、PID、lock、session metadata
- 含真实 chat/user/message ID 或消息正文的日志
`.gitignore` 已覆盖仓库本地 `config.json`、备份、日志、`dist`、`node_modules` 和 coverage。实例默认在仓库外。安全性按内容判断,不能只依赖文件名。