Files
gori-agent/README.md
T

9.4 KiB
Raw Blame History

gori-agent

gori-agent 是一个 Node.js 20+ / TypeScript 网关:从一个 IM 平台接收消息,通过官方 Agent Client Protocol(ACP)驱动一个 Coding Agent。

用户 → 单个平台 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 也不会自动改写。

一台机器上的实例统一位于:

${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。

构建与安装

npm install
npm run build
./install.sh

安装器只安装一个 launcher;不会为每个 Bot 复制源码或 dist/。默认 launcher 位于 $HOME/.gori-agent/bin/gori-agent。

确认 ACP agent 可用:

kimi --version
kimi doctor
kimi acp --help
gori-agent discover-backends

模型和 provider 由 ACP agent 自身配置,例如 Kimi Code 使用 ~/.kimi-code/config.toml。gori-agent 不复制模型凭据。

实例管理

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 改变统一根目录:

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 作为初始化种子。

底层调试入口仍可使用:

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。顶层只有:

configVersion  固定为 3
bot            Bot、workspace、persona、agent、skills、permissions
gateway        HTTP server、入站 policy、唯一 platform
runtime.acp    ACP state、timeout 和 worker pool

Bot 与 ACP agent

{
  "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 示例:

{
  "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 命令

/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 和日志不得提交。

开发验收

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。