npm package: @long_88/openclaw-aicc-channel
Description: OpenClaw AICC messaging channel plugin.
Latest version: 0.1.3

# aicc-channel

`aicc-channel` 是一个 OpenClaw 自定义消息渠道插件，用来把你自己的业务系统接入
OpenClaw。

它的设计目标很简单：

- 你的业务系统把入站消息转发到 bridge server
- `aicc-channel` 主动通过 WebSocket 连接 bridge server
- OpenClaw 通过这个插件处理消息、路由会话、生成回复
- 插件把 reply 通过 WebSocket 或 HTTP 回传到 bridge server
- 在 WS 模式下，插件现在会优先在 OpenClaw 本机连本地 Gateway，再把 `block/tool/final`
  事件流经已有的 bridge WebSocket 回传到公网 server
- 如果 bridge server 开启 `gateway-direct`，则 bridge 也可以自己直连 OpenClaw Gateway，
  但这更适合同机或可直连 Gateway 的部署
- 客户只需要安装插件和配置渠道，不需要修改 OpenClaw core

当前仓库同时包含三部分：

- OpenClaw 外部插件包 `@long_88/openclaw-aicc-channel`
- 一键安装器 `@long_88/openclaw-aicc-channel-cli`
- 一个独立的 `go-server/` bridge server，用于协议转换和本地联调

## 当前能力

目前已经支持：

- 作为外部插件安装到 OpenClaw
- 注册 `aicc-channel` 频道和配置 schema
- 在 OpenClaw Gateway 上自动注册入站 webhook 路由
- 文本消息的入站标准化和出站 HTTP 回调
- 通过 bridge WebSocket 回传 tool/block/final 多段回复
- 单账号和命名账号配置
- 本地 bridge server 联调

当前还不包含：

- 生产级验签、重放保护、幂等去重
- 群聊策略和 mention gating
- 附件、图片、文件、reaction 等富消息
- typing / thinking 指示和更细粒度的工具事件透出
- 飞书、Telegram、Slack 等具体平台适配器

## 整体架构

消息流分成两段：

1. 入站
   你的业务系统 -> bridge server -> `GET /ws` 已连接的 `aicc-channel` -> OpenClaw

2. 出站
   OpenClaw -> 插件 `bridgeUrl` -> bridge server -> 你的业务系统

默认情况下：

- OpenClaw Gateway webhook 路径是 `/webhooks/aicc-channel`
- bridge server 监听 `http://127.0.0.1:9090`
- `aicc-channel` 默认会主动连接 `ws://127.0.0.1:9090/ws`
- bridge server 仍然支持把入站请求转发到
  `http://127.0.0.1:18789/webhooks/aicc-channel` 作为 HTTP fallback
- `POST /mock/inbound` 现在要求请求里显式带 `metadata.aiccAccountId`，由 bridge 按这个账号命中在线的 `GET /ws` 会话
- 如果某个账号的 `secret` 为空，插件不会为该账号建立 bridge WebSocket 连接

对“公网 server + 内网 OpenClaw”这个更常见的拓扑，推荐模式现在是：

- `go-server/` 部署在公网
- OpenClaw 机器主动连接 `go-server` 提供的 `GET /ws`
- 插件收到 bridge `inbound` 后，会优先读取本机 `cfg.gateway.auth`
- 插件再直连本机 `ws://127.0.0.1:<gateway.port>` operator WS
- 插件把本地 Gateway 的流式事件重新映射成 `block / tool / final`
- 然后通过已有的 bridge WebSocket 把这些 reply 推回公网 `server`

`go-server gateway-direct` 仍然保留，但它适用于：

- `go-server` 与 OpenClaw 同机
- 或 `go-server` 能直接访问 OpenClaw Gateway WebSocket

所以当前仓库的主路径优先级是：

1. 插件本地 Gateway relay + bridge `GET /ws`
2. `server gateway-direct`，主要用于 `platform/webhook` 或可直连 Gateway 的部署
3. `OPENCLAW_WEBHOOK_URL` HTTP fallback，主要保留给非 `/mock/inbound` 的旧路径或兜底联调

如果你的 OpenClaw Gateway 端口不是 `18789`，需要同步修改 `OPENCLAW_WEBHOOK_URL`。

## 目录结构

- [src/index.ts](./src/index.ts)
  插件入口，注册 `channel` 和 HTTP route
- [src/channel.ts](./src/channel.ts)
  `aicc-channel` 插件定义
- [src/http-route.ts](./src/http-route.ts)
  在 OpenClaw Gateway 上注册 webhook 路由
- [src/inbound.ts](./src/inbound.ts)
  入站标准化、路由解析、回复分发
- [src/outbound.ts](./src/outbound.ts)
  出站消息转发到 bridge
- [go-server/main.go](../go-server/main.go)
  bridge server 入口

## 本地开发

```bash
npm install
npm test
npm run typecheck
npm run build
```

## 安装到 OpenClaw

### 1. 一键安装

最简单的方式是直接使用 CLI 安装器：

```bash
npx -y @long_88/openclaw-aicc-channel-cli install \
  --bridge-url http://127.0.0.1:9090 \
  --secret bridge-secret \
  --name "Default Bridge"
```

如果需要命名账号：

```bash
npx -y @long_88/openclaw-aicc-channel-cli install \
  --account cn \
  --bridge-url http://127.0.0.1:9091 \
  --secret bridge-secret-cn \
  --name "China Bridge"
```

CLI 会执行这些动作：

- `openclaw plugins install @long_88/openclaw-aicc-channel`
- 启用插件条目 `plugins.entries.aicc-channel.enabled`
- 写入 `channels.aicc-channel` 或 `channels.aicc-channel.accounts.<accountId>` 配置
- 默认重启 `openclaw gateway`

如果只想预览命令，不实际执行：

```bash
npx -y @long_88/openclaw-aicc-channel-cli install --dry-run
```

### 2. 手动安装

如果不想通过 CLI，可以直接用 OpenClaw 命令：

```bash
openclaw plugins install "@long_88/openclaw-aicc-channel"
openclaw config set plugins.entries.aicc-channel.enabled true
openclaw config set channels.aicc-channel.bridgeUrl "http://127.0.0.1:9090"
openclaw config set channels.aicc-channel.secret "bridge-secret"
openclaw config set channels.aicc-channel.name "Default Bridge"
openclaw config set channels.aicc-channel.enabled true
openclaw gateway restart
```

命名账号手动配置示例：

```bash
openclaw config set channels.aicc-channel.accounts.cn.bridgeUrl "http://127.0.0.1:9091"
openclaw config set channels.aicc-channel.accounts.cn.secret "bridge-secret-cn"
openclaw config set channels.aicc-channel.accounts.cn.name "China Bridge"
openclaw config set channels.aicc-channel.accounts.cn.enabled true
```

说明：

- 顶层字段作为默认账号
- `accounts` 里的命名账号只覆盖自己声明的字段
- 默认账号固定注册到 `/webhooks/aicc-channel`
- 命名账号会自动注册到 `/webhooks/aicc-channel/<accountId>`
- 配置面只保留 `bridgeUrl` 和 `secret`

### 3. 本地路径加载开发版

如果你还在本仓库里本地调试，也可以继续走路径加载：

```json
{
  "plugins": {
    "load": {
      "paths": ["/Users/long/projects/claw-dev/aicc-channel"]
    }
  }
}
```

### 4. 重启 OpenClaw

重启后，在 OpenClaw 的 Channels 页面里应该能看到 `AICC Channel`。

如果配置正确，通常会看到：

- `Configured: Yes`
- `Connected: true` 表示 bridge WebSocket 最近仍然存活
- `Last Connected At / Last Inbound At / Last Outbound At` 会随着 WS 握手和消息流更新
- `Last Error` 会在 WS stale、断开、鉴权失败，或账号缺少 bridge `secret` 时显示最近原因

如果你要判断远端 bridge WS 是否还活着，优先看 Channels 页面里的：

- `Connected`
- `Last Connected At`
- `Last Inbound At`
- `Last Outbound At`
- `Last Error`

### 5. 验证插件 webhook 是否可用

假设你的 OpenClaw Gateway 端口是 `18789`，可以直接这样测试：

```bash
curl -i -X POST http://127.0.0.1:18789/webhooks/aicc-channel \
  -H 'x-aicc-channel-secret: bridge-secret' \
  -H 'content-type: application/json' \
  -d '{
    "schemaVersion":"2026-03-12",
    "senderId":"user-1",
    "chatId":"dm-user-1",
    "chatType":"direct",
    "text":"hello",
    "timestamp":"2026-03-12T14:00:00.000Z"
  }'
```

如果链路正常，预期返回类似：

```json
{"ok":true,"accountId":"default","sessionKey":"agent:main:aicc-channel:direct:user-1"}
```

这说明：

- OpenClaw 已经加载插件
- Gateway route 已经注册成功
- 入站消息已经进入 OpenClaw 的 channel 路由

## 启动 bridge server

bridge server 在 [go-server/](../go-server/README.md) 下，用来连接你的业务系统和
OpenClaw。

最简单的启动方式：

```bash
cd /Users/long/projects/claw-dev/go-server
OPENCLAW_INBOUND_SECRET=bridge-secret \
OPENCLAW_WEBHOOK_URL=http://127.0.0.1:18789/webhooks/aicc-channel \
go run .
```

默认暴露这些接口：

- `GET /health`
- `POST /outbound`
- `POST /platform/webhook`
- `POST /mock/inbound`

说明：

- `POST /outbound`
  接收 OpenClaw 的出站回复
- `POST /platform/webhook`
  接收你的业务系统原始消息并转换成标准入站结构
- `POST /mock/inbound`
  直接接收标准化后的入站 payload，适合联调

注意：

- 如果 OpenClaw 本机能读取 `cfg.gateway.auth.token/password`，插件会优先走
  “本地 Gateway relay + bridge websocket” 这条路
- `POST /mock/inbound` 现在必须带 `metadata.aiccAccountId`，bridge 会用它选择在线的
  `GET /ws` 会话；如果目标账号不在线，会直接返回错误
- 当 bridge 侧存在匹配的已连接 `GET /ws` 会话时，`POST /mock/inbound` 会返回
  `text/event-stream`
- 这个 SSE 响应会连续输出多个 `reply` 事件，最后再输出 `done`
- `metadata.weixinFanoutBundle` 只用于最终微信 fan-out，不决定 AICC 路由

如果没有设置 `PLATFORM_OUTBOUND_URL`，bridge 会进入 mock 模式，只记录日志，不把回复真正发回业务系统。

更多说明见 [go-server/README.md](../go-server/README.md)。

## 联调示例

### 1. 先确认 bridge 健康检查

```bash
curl http://127.0.0.1:9090/health
```

### 2. 通过 bridge 向 OpenClaw 注入一条测试消息

```bash
curl -N -X POST http://127.0.0.1:9090/mock/inbound \
  -H 'content-type: application/json' \
  -d '{
    "schemaVersion": "2026-03-12",
    "senderId": "user-1",
    "senderName": "Alice",
    "chatId": "dm-user-1",
    "chatType": "direct",
    "text": "hello from mock inbound",
    "messageId": "msg-1",
    "timestamp": "2026-03-12T14:00:00.000Z",
    "metadata": {
      "aiccAccountId": "default"
    }
  }'
```

如果当前走的是 WS 模式，输出会是 SSE，形态类似：

```text
event: reply
data: {"kind":"block","text":"第一段回复", ...}

event: reply
data: {"kind":"tool","text":"工具结果", ...}

event: reply
data: {"kind":"final","text":"最终回复", ...}

event: done
data: {"ok":true,"requestId":"ws-1"}
```

### 3. 统计请求耗时

如果你想看 webhook 的耗时，可以这样跑：

```bash
curl -s -o /dev/null \
  -X POST http://127.0.0.1:18789/webhooks/aicc-channel \
  -H 'x-aicc-channel-secret: bridge-secret' \
  -H 'content-type: application/json' \
  -d '{
    "schemaVersion":"2026-03-12",
    "senderId":"user-1",
    "chatId":"dm-user-1",
    "chatType":"direct",
    "text":"hello",
    "timestamp":"2026-03-12T14:00:00.000Z"
  }' \
  -w 'code=%{http_code} total=%{time_total}s connect=%{time_connect}s starttransfer=%{time_starttransfer}s\n'
```

## 入站消息协议

你的业务系统最终需要转成这个结构，再发给 `aicc-channel`：

```json
{
  "schemaVersion": "2026-03-12",
  "senderId": "user-123",
  "senderName": "Alice",
  "chatId": "dm-user-123",
  "chatType": "direct",
  "threadId": "optional-thread",
  "text": "hello",
  "messageId": "bridge-msg-1",
  "timestamp": "2026-03-12T12:00:00.000Z",
  "metadata": {
    "source": "custom-app"
  }
}
```

字段含义：

- `senderId`
  消息发送人 ID
- `chatId`
  会话 ID，私聊和群聊都靠它区分
- `chatType`
  目前支持 `direct` 或 `group`
- `threadId`
  可选，用于线程或子会话
- `messageId`
  外部系统消息 ID，建议保持可追踪

## 出站消息协议

当 OpenClaw 通过这个插件发回复时，bridge 会收到：

```json
{
  "accountId": "default",
  "to": "dm-user-123",
  "text": "hello",
  "replyToId": null,
  "threadId": null
}
```

bridge 应返回：

```json
{
  "messageId": "bridge-msg-2",
  "chatId": "dm-user-123"
}
```

## 手动调用 `handleInboundWebhook`

正常情况下不需要手动调用，插件会自动通过 `registerHttpRoute(...)` 接到 Gateway。

如果你有宿主级特殊接入需求，也可以直接调用：

```ts
import { handleInboundWebhook } from "@long_88/openclaw-aicc-channel";

await handleInboundWebhook({
  cfg,
  path: "/webhooks/aicc-channel",
  headers: request.headers,
  body: request.body,
  channelRuntime: runtime.channel
});
```

`channelRuntime` 需要至少具备这些能力：

- `routing.resolveAgentRoute(...)`
- `reply.finalizeInboundContext(...)`
- `reply.dispatchReplyFromConfig(...)`

## 生产环境还需要做什么

当前仓库已经可以用于 MVP 验证，但离真实生产环境还差一层工程化工作。

### 已经具备

- OpenClaw 外部插件打包和清单
- `aicc-channel` 频道注册和配置 schema
- Gateway HTTP route 自动注册
- 文本消息入站标准化和出站 HTTP 投递
- 独立 bridge server
- 配置、路由、入站、出站、bridge 的自动化测试

### 还需要补的内容

#### 1. 安全

- 把当前共享密钥升级成生产级验签机制
- 增加时间戳校验、重放保护和请求幂等
- 设计 `secret`、平台 token 的轮换机制
- 明确是只用 plugin auth，还是 gateway auth + plugin auth 双层鉴权
- 评估哪些密钥应该放在 OpenClaw 配置里，哪些应该交给外部密钥系统

#### 2. 可靠性

- 为出站消息增加重试和退避
- 对不可投递消息增加死信或错误队列
- 把入站去重做成可持久化，避免重启后重复消费
- 明确业务系统、bridge、OpenClaw 之间的超时策略
- 决定 bridge 是直连模式、mock 模式，还是后面演进到队列模式

#### 3. 协议和业务映射

- 定义真实业务里的用户、群、线程、租户如何映射到 `senderId`、`chatId`、`threadId`
- 定义多租户或多客户场景下的账号隔离策略
- 建立业务消息 ID、bridge 消息 ID、OpenClaw sessionKey 的关联
- 明确编辑、撤回、附件、reaction、系统事件要不要进入 channel 模型

#### 4. 用户体验

- 如果嫌现在 webhook 回调模式慢，需要补 streaming 或 block-level 回传
- 增加 typing / thinking 状态
- 提供更明确的用户侧失败提示
- 明确群聊、mention、thread reply 是否进入 v1

#### 5. 可观测性

- 加结构化日志，并贯穿稳定 requestId
- 加耗时、成功率、重试次数、模型时延等指标
- 给 bridge 的下游依赖补健康检查
- 对 OpenClaw 或你的业务系统的持续 4xx / 5xx 做告警

#### 6. 部署和运维

- 决定 bridge server 的交付方式：sidecar、客户自托管，还是集中式 SaaS
- 给 bridge 增加正式配置方案，不只靠环境变量
- 提供 systemd、Docker、pm2 等常见部署样例
- 明确 OpenClaw、插件、业务系统三者的版本兼容矩阵
- 制定插件和 bridge 的升级、回滚流程

#### 7. 测试

- 增加真实 OpenClaw Gateway 的端到端测试
- 增加真实业务系统或平台 API 的集成测试
- 增加并发、压测和高峰流量测试
- 增加超时、重复投递、部分故障等故障注入测试

### 建议的推进顺序

1. 先把真实业务消息模型和多租户映射定下来
2. 再补安全、重试、去重和可观测性
3. 然后做 E2E 测试和部署打包
4. 最后再做流式输出、群聊规则和富消息能力

## 相关文件

- [openclaw.plugin.json](./openclaw.plugin.json)
- [package.json](./package.json)
- [go-server/README.md](../go-server/README.md)
- [docs/examples/openclaw-host-integration.md](./docs/examples/openclaw-host-integration.md)