Files
gori-agent/README.md
T
2026-08-16 10:44:03 +08:00

11 KiB
Raw Blame History

gori-agent

通过 QQ 等 IM 调用 ACP Coding Agent。当前默认后端是 Kimi Code:

用户 → QQ → gori-agent Gateway → ACP → Kimi Code → 工具/脚本 → QQ

五分钟上手

1. 准备 Kimi Code

确认 Kimi Code 已登录且 ACP 可用:

kimi --version
kimi doctor
kimi acp --help

ACP 使用 ~/.kimi-code/config.toml 中的 default_model。模型切换应先在 Kimi Code 中完成,再重启 gori-agent;已有聊天要使用新模型时,在 QQ 中发送 /new 创建新 session。

2. 构建并迁移配置

cd /home/ubuntu/gori-space/gori-agent
npm install
npm run build
./gori-agent.sh setup --config ./config.json

建议向导选择:

Assistant workspace: /home/ubuntu/gori-space/gori-agent
Include ops role with the existing gori-update skill: yes
Write config: yes

迁移会把旧的 kimi -p 改为 kimi acp,并完整保留已有 QQ appId、secret 和连接模式。

3. 检查配置

./gori-agent.sh discover-backends --config ./config.json
./gori-agent.sh doctor --config ./config.json

预期看到 Kimi ACP ready,并支持 session load/resume。

4. 前台启动并从 QQ 验收

./gori-agent.sh start --config ./config.json

启动日志应包含:

QQ websocket connected
QQ websocket ready

在 QQ 群中 @bot 并发送:

/status
/roles
/role assistant
只读回答当前工作目录,不要修改文件

运维角色先做只读测试:

/role ops
/status
请只读取并概述 gori-update skill,不要 pull、构建或部署

常用聊天命令:

/roles          列出角色
/role <id>      切换角色
/status         查看当前 role/workspace/session 状态
/cancel         取消正在执行的任务
/new            为当前角色创建新的 Agent session

同一个 平台 + chat + role 会持续使用同一个 Kimi session;Gateway 或 ACP 子进程重启后会恢复。不同 role 的 session 相互独立。

5. 后台运行

前台验收通过后:

export GORI_AGENT_HOME=/home/ubuntu/.gori-agent
./gori-agent.sh start-daemon --config ./config.json
./gori-agent.sh status --config ./config.json
./gori-agent.sh logs
./gori-agent.sh stop

运行状态和日志位于:

/home/ubuntu/.gori-agent/state/
/home/ubuntu/.gori-agent/logs/gori-agent.log

config.json 包含 IM secret,不要提交,建议执行:

chmod 600 config.json

配置角色

角色定义在 config.json 的 roles[] 中:

{
  "id": "ops",
  "backend": "kimi",
  "workspace": "/home/ubuntu/gori-space",
  "persona": "你是 Gori 团队运维角色,严格遵循 gori-update skill。",
  "skills": ["gori-update"],
  "policy": {
    "permissionMode": "allowlist",
    "allowedTools": ["read", "grep", "glob", "bash"],
    "allowedCommandPatterns": ["允许的命令正则"]
  }
}
  • backend:ACP 后端 ID,默认 kimi。
  • workspace:该角色的工作目录,必须是绝对路径。
  • persona:角色职责。
  • skills:引用顶层 skills[] 中的 SKILL.md。
  • permissionMode:deny 全拒绝;allowlist 按工具和命令规则放行;auto 全放行(高风险)。

修改 persona、workspace、skill 内容或 policy 后,角色 fingerprint 会变化;下一条消息会创建新的 native session,避免沿用旧角色上下文。

配置 QQ

config.json 的最小 QQ websocket 配置:

{
  "policy": {
    "allowedUsers": [],
    "allowedChats": [],
    "requireMentionInGroup": true
  },
  "platforms": {
    "qq": {
      "enabled": true,
      "connectionMode": "websocket",
      "appId": "你的 AppID",
      "clientSecret": "你的 ClientSecret",
      "botSecret": "",
      "verifySignature": true,
      "botNames": ["你的机器人名称"],
      "intents": 33554432,
      "shard": [0, 1]
    }
  }
}

初次测试可让 allowedUsers 和 allowedChats 为空;正式运维 bot 应限制到指定用户或群。群聊 chat ID 的格式为 group:<group_openid>。


Detailed reference

Multi-IM gateway that drives coding agents through the official Agent Client Protocol (ACP):

IM Adapter -> Gateway -> Role/Session Manager -> ACP Client -> kimi acp

The MVP backend is Kimi Code ACP. Gateway code contains no Kimi CLI prompt fallback and no Pi/Codex private protocol. Future agents must enter through an ACP adapter such as codex-acp or a Pi ACP adapter.

Requirements and quick start

Requires Node.js 20+ and an authenticated Kimi Code installation.

npm install
npm run build
./install.sh
gori-agent setup
gori-agent doctor --config ./config.json
gori-agent start --config ./config.json

setup probes ACP backends, creates an assistant role, optionally creates the ops role, preserves all existing platform settings, prints a migration summary, and only writes after confirmation. A v1 config is accepted at runtime only when its default agent is Kimi; other CLI agents require an explicit ACP backend.

Convenience wrapper commands:

./gori-agent.sh start
./gori-agent.sh start-daemon
./gori-agent.sh status
./gori-agent.sh logs
./gori-agent.sh stop

stop sends SIGTERM and waits up to 10 seconds for graceful shutdown. For production, use systemd with Restart=always and KillMode=control-group so an unexpected gateway crash also cleans up ACP children.

CLI

gori-agent setup [--config path]
gori-agent discover-backends [--json]
gori-agent start [--config path]
gori-agent status [--config path]
gori-agent doctor [--config path]
gori-agent print feishu [--config path]

discover-agents remains a deprecated alias for discover-backends. Discovery does not send a prompt. Kimi is ready when kimi acp is available; Codex and Pi report needs-adapter unless their ACP adapter executable exists.

Roles, sessions, and commands

A conversation binding is keyed by platform + chatId + role. Each binding stores the ACP backend, native session ID, workspace, and role fingerprint. The selected role and bindings survive gateway restart.

  • A new session receives a hidden bootstrap prompt containing persona, workspace, skill content, and policy. The binding is saved only after bootstrap succeeds.
  • A role persona, workspace, policy, or skill-content change changes its fingerprint and causes a new native session.
  • Idle workers are stopped and later cold-resumed with session/resume (or session/load when resume is unavailable).
  • Failed prompts are never replayed automatically.
  • /new cancels the current turn, unbinds the current chat/role, and creates a native session on the next prompt. It does not delete Kimi history.
  • /cancel bypasses the per-chat lock and sends ACP session/cancel; an unresponsive worker is force-recycled after the grace period.

Chat commands:

  • /help
  • /roles
  • /role <id>
  • /status
  • /cancel
  • /new
  • /agents and /agent <id> (deprecated aliases)

Messages in one chat are serialized; different chats run concurrently.

Configuration v2

See config.example.json. Important sections:

  • backends[]: ACP spawn command and arguments. The default is /home/ubuntu/.kimi-code/bin/kimi acp.
  • roles[]: backend, absolute workspace, persona, skills, and permission policy.
  • skills[]: readable skill files with a byte limit. Skill contents participate in the role fingerprint.
  • acp.stateFile: defaults to $GORI_AGENT_HOME/state/acp-sessions.json.
  • acp.initializeTimeoutMs, promptTimeoutMs, cancelGraceMs: request lifecycle limits.
  • acp.idleTimeoutMs, sweepIntervalMs, maxProcesses: worker pool limits.
  • policy.allowedUsers, allowedChats, requireMentionInGroup: inbound IM policy.
  • platforms: Feishu, WeCom, QQ, generic webhook, and Weixin settings. Migration preserves this object, including credentials.

State writes use a serial promise queue, temporary file, fsync, and atomic rename. A single-instance lock protects the state file. Corrupt state is preserved and startup fails explicitly instead of overwriting it.

Permission policy

ACP permission requests are decided by role policy, not by persona:

  • deny: reject every permission request.
  • allowlist: require both an allowed tool name and, for bash/terminal, a matching raw command pattern. If the ACP request lacks enough command detail, it is denied.
  • auto: approve everything; doctor prints a high-risk warning.

The example ops role loads the existing read-only skill file at /home/ubuntu/gori-space/gori-deploy/.kimi-code/skills/gori-update/SKILL.md. Its allowlist covers selected git, build/deploy entry scripts, and read-only Docker status/log commands. sudo, force push, and arbitrary deletion are not allowed. Script-internal operations cannot be inspected by ACP once an explicitly allowed deployment script starts, so script paths must remain trusted.

Kimi 0.36.1 does not advertise a generic model config option during ACP initialize; this MVP uses the model configured as Kimi's default and doctor reports that limitation.

Platform behavior

Platform Inbound Outbound Notes
Feishu/Lark Implemented Implemented im.message.receive_v1 and message reply API.
WeCom 501 scaffold Implemented Inbound verification/encryption is not implemented.
Weixin External webhook scaffold Synchronous Native personal WeChat is not included.
QQ Implemented Implemented WebSocket gateway and HTTP callback modes.
Generic webhook Implemented Synchronous JSON HMAC-SHA256 signed JSON.

QQ WebSocket mode uses intent 33554432 for GROUP_AT_MESSAGE_CREATE and C2C_MESSAGE_CREATE. The adapter supports top-level and nested author.user_openid fields, preserves callback ACK { "op": 12 } even if ACP work later fails, and logs receive/send routing. No external QQ message is sent by the automated tests.

Endpoints:

  • GET /health — aggregate ACP counters only; native session IDs are not exposed.
  • GET /platforms
  • POST /webhook/feishu
  • POST /webhook/wecom
  • POST /webhook/qq
  • POST /webhook/generic
  • POST /webhook/weixin

Generic webhook payload:

{
  "chat_id": "demo-chat",
  "user_id": "demo-user",
  "text": "/status",
  "message_id": "optional",
  "is_group": false,
  "mentions_bot": true
}

When platforms.webhook.secret is set, provide X-Gori-Signature: sha256=<HMAC-SHA256 hex> over the exact JSON body.

Lifecycle and diagnostics

Shutdown order is QQ WebSocket stop, active ACP cancellation, worker termination, state flush/unlock. SIGINT and SIGTERM share the same idempotent shutdown path. Health statistics include active workers, in-flight turns, worker crashes, persisted bindings, and locked chats.

doctor checks role/workspace/skill validity, ACP initialize and restore capabilities, state directory access, permission warnings, configured platforms, and QQ requirements. It performs no prompt and no external QQ test.

Development

npm run typecheck
npm test
npm run build
git diff --check

Tests use Node node:test through tsx. The fake ACP subprocess covers initialize/new/resume/prompt/cancel, persistence, idle cold resume, Gateway commands, and QQ normalization/ACK behavior.

Legacy src/agents/* source remains only for compatibility/reference and is not imported by Gateway or Server. There is no runtime CliAgent fallback.