11 KiB
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(orsession/loadwhen resume is unavailable). - Failed prompts are never replayed automatically.
/newcancels the current turn, unbinds the current chat/role, and creates a native session on the next prompt. It does not delete Kimi history./cancelbypasses the per-chat lock and sends ACPsession/cancel; an unresponsive worker is force-recycled after the grace period.
Chat commands:
/help/roles/role <id>/status/cancel/new/agentsand/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;doctorprints 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. |
| 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 /platformsPOST /webhook/feishuPOST /webhook/wecomPOST /webhook/qqPOST /webhook/genericPOST /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.