agents-bridge 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +20 -0
- package/LICENSE +21 -0
- package/README.md +259 -0
- package/bin/agent-bridge.mjs +12 -0
- package/config.example.json +117 -0
- package/dist/agents/cli-backends.d.ts +32 -0
- package/dist/agents/cli-backends.d.ts.map +1 -0
- package/dist/agents/cli-backends.js +217 -0
- package/dist/agents/cli-backends.js.map +1 -0
- package/dist/agents/cli-runner.d.ts.map +1 -0
- package/dist/agents/cli-runner.js +524 -0
- package/dist/agents/cli-runner.js.map +1 -0
- package/dist/agents/cli-session-store.d.ts.map +1 -0
- package/dist/agents/cli-session-store.js +127 -0
- package/dist/agents/cli-session-store.js.map +1 -0
- package/dist/agents/model-selection.d.ts +27 -0
- package/dist/agents/model-selection.d.ts.map +1 -0
- package/dist/agents/model-selection.js +40 -0
- package/dist/agents/model-selection.js.map +1 -0
- package/dist/agents/models-config.d.ts +28 -0
- package/dist/agents/models-config.d.ts.map +1 -0
- package/dist/agents/models-config.js +43 -0
- package/dist/agents/models-config.js.map +1 -0
- package/dist/channels/botlink.d.ts.map +1 -0
- package/dist/channels/botlink.js +320 -0
- package/dist/channels/botlink.js.map +1 -0
- package/dist/channels/command-gating.d.ts +20 -0
- package/dist/channels/command-gating.d.ts.map +1 -0
- package/dist/channels/command-gating.js +43 -0
- package/dist/channels/command-gating.js.map +1 -0
- package/dist/channels/draft-stream-controls.d.ts +21 -0
- package/dist/channels/draft-stream-controls.d.ts.map +1 -0
- package/dist/channels/draft-stream-controls.js +43 -0
- package/dist/channels/draft-stream-controls.js.map +1 -0
- package/dist/channels/draft-stream-loop.d.ts +31 -0
- package/dist/channels/draft-stream-loop.d.ts.map +1 -0
- package/dist/channels/draft-stream-loop.js +60 -0
- package/dist/channels/draft-stream-loop.js.map +1 -0
- package/dist/channels/mention-gating.d.ts +18 -0
- package/dist/channels/mention-gating.d.ts.map +1 -0
- package/dist/channels/mention-gating.js +20 -0
- package/dist/channels/mention-gating.js.map +1 -0
- package/dist/channels/registry.d.ts +5 -0
- package/dist/channels/registry.d.ts.map +1 -0
- package/dist/channels/registry.js +14 -0
- package/dist/channels/registry.js.map +1 -0
- package/dist/channels/run-state-machine.d.ts +21 -0
- package/dist/channels/run-state-machine.d.ts.map +1 -0
- package/dist/channels/run-state-machine.js +41 -0
- package/dist/channels/run-state-machine.js.map +1 -0
- package/dist/channels/session-envelope.d.ts +5 -0
- package/dist/channels/session-envelope.d.ts.map +1 -0
- package/dist/channels/session-envelope.js +13 -0
- package/dist/channels/session-envelope.js.map +1 -0
- package/dist/channels/session.d.ts +18 -0
- package/dist/channels/session.d.ts.map +1 -0
- package/dist/channels/session.js +35 -0
- package/dist/channels/session.js.map +1 -0
- package/dist/channels/typing-lifecycle.d.ts +16 -0
- package/dist/channels/typing-lifecycle.d.ts.map +1 -0
- package/dist/channels/typing-lifecycle.js +31 -0
- package/dist/channels/typing-lifecycle.js.map +1 -0
- package/dist/cli/cmd-config.d.ts +3 -0
- package/dist/cli/cmd-config.d.ts.map +1 -0
- package/dist/cli/cmd-config.js +15 -0
- package/dist/cli/cmd-config.js.map +1 -0
- package/dist/cli/cmd-doctor.d.ts +3 -0
- package/dist/cli/cmd-doctor.d.ts.map +1 -0
- package/dist/cli/cmd-doctor.js +80 -0
- package/dist/cli/cmd-doctor.js.map +1 -0
- package/dist/cli/cmd-logs.d.ts +3 -0
- package/dist/cli/cmd-logs.d.ts.map +1 -0
- package/dist/cli/cmd-logs.js +26 -0
- package/dist/cli/cmd-logs.js.map +1 -0
- package/dist/cli/cmd-onboard.d.ts +3 -0
- package/dist/cli/cmd-onboard.d.ts.map +1 -0
- package/dist/cli/cmd-onboard.js +103 -0
- package/dist/cli/cmd-onboard.js.map +1 -0
- package/dist/cli/cmd-start.d.ts +3 -0
- package/dist/cli/cmd-start.d.ts.map +1 -0
- package/dist/cli/cmd-start.js +155 -0
- package/dist/cli/cmd-start.js.map +1 -0
- package/dist/cli/cmd-status.d.ts +3 -0
- package/dist/cli/cmd-status.d.ts.map +1 -0
- package/dist/cli/cmd-status.js +16 -0
- package/dist/cli/cmd-status.js.map +1 -0
- package/dist/cli/cmd-stop.d.ts +3 -0
- package/dist/cli/cmd-stop.d.ts.map +1 -0
- package/dist/cli/cmd-stop.js +30 -0
- package/dist/cli/cmd-stop.js.map +1 -0
- package/dist/cli/pid-file.d.ts +7 -0
- package/dist/cli/pid-file.d.ts.map +1 -0
- package/dist/cli/pid-file.js +51 -0
- package/dist/cli/pid-file.js.map +1 -0
- package/dist/cli/run-main.d.ts +11 -0
- package/dist/cli/run-main.d.ts.map +1 -0
- package/dist/cli/run-main.js +64 -0
- package/dist/cli/run-main.js.map +1 -0
- package/dist/config/agent-dirs.d.ts +12 -0
- package/dist/config/agent-dirs.d.ts.map +1 -0
- package/dist/config/agent-dirs.js +30 -0
- package/dist/config/agent-dirs.js.map +1 -0
- package/dist/config/config.d.ts +3 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +40 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/env-vars.d.ts +15 -0
- package/dist/config/env-vars.d.ts.map +1 -0
- package/dist/config/env-vars.js +16 -0
- package/dist/config/env-vars.js.map +1 -0
- package/dist/config/merge-config.d.ts +7 -0
- package/dist/config/merge-config.d.ts.map +1 -0
- package/dist/config/merge-config.js +32 -0
- package/dist/config/merge-config.js.map +1 -0
- package/dist/config/paths.d.ts +19 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +22 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/zod-schema.d.ts +1192 -0
- package/dist/config/zod-schema.d.ts.map +1 -0
- package/dist/config/zod-schema.js +107 -0
- package/dist/config/zod-schema.js.map +1 -0
- package/dist/console-encoding.d.ts +6 -0
- package/dist/console-encoding.d.ts.map +1 -0
- package/dist/console-encoding.js +35 -0
- package/dist/console-encoding.js.map +1 -0
- package/dist/entry.d.ts +3 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +47 -0
- package/dist/entry.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +19 -0
- package/dist/logger.js.map +1 -0
- package/dist/types/index.d.ts +67 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +55 -0
package/.env.example
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# .env.example — agent-bridge 环境变量
|
|
2
|
+
#
|
|
3
|
+
# 环境变量可覆盖 config.json 中的对应值
|
|
4
|
+
|
|
5
|
+
# 配置文件路径(默认按搜索顺序:~/.agent-bridge/config.json → ./config.json)
|
|
6
|
+
# AGENT_BRIDGE_CONFIG=./config.json
|
|
7
|
+
|
|
8
|
+
# Botlink 连接(覆盖 channels.botlink)
|
|
9
|
+
# AGENT_BRIDGE_GATEWAY_URL=https://your-botlink-instance.com
|
|
10
|
+
# AGENT_BRIDGE_BOT_TOKEN=bot_xxxxxxxxxxxxxxxxxx
|
|
11
|
+
|
|
12
|
+
# 日志级别(覆盖 logging.level)
|
|
13
|
+
# AGENT_BRIDGE_LOG_LEVEL=info
|
|
14
|
+
|
|
15
|
+
# 临时文件目录(覆盖 files.temp_dir)
|
|
16
|
+
# AGENT_BRIDGE_TEMP_DIR=/tmp/agent-bridge/files
|
|
17
|
+
|
|
18
|
+
# LLM API Keys(用于 Pi Agent 模式)
|
|
19
|
+
# ANTHROPIC_API_KEY=sk-ant-xxx
|
|
20
|
+
# OPENAI_API_KEY=sk-xxx
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# agents-bridge
|
|
2
|
+
|
|
3
|
+
本地 Agent 网关,部署在客户本地机器上,通过长轮询连接云端 botlink 平台,驱动本地的 Claude Code / Codex 等 AI Agent。
|
|
4
|
+
|
|
5
|
+
## 架构概览
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
botlink 云端 客户本地
|
|
9
|
+
┌──────────────────────┐ ┌──────────────────────────┐
|
|
10
|
+
│ botlink-web │ │ agents-bridge │
|
|
11
|
+
│ client-gateway │ │ │
|
|
12
|
+
│ bot-gateway ◄───────┼── HTTP │ botlink channel │
|
|
13
|
+
│ message-svc │ 长轮询│ ↕ │
|
|
14
|
+
│ routing-svc │ │ Agent Runtime │
|
|
15
|
+
└──────────────────────┘ │ ├─ Claude Code (CLI) │
|
|
16
|
+
│ ├─ Codex (CLI) │
|
|
17
|
+
│ └─ Pi Agent (API) │
|
|
18
|
+
└──────────────────────────┘
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
agents-bridge 始终作为客户端主动外连云端,客户无需暴露任何端口。
|
|
22
|
+
|
|
23
|
+
## 快速开始
|
|
24
|
+
|
|
25
|
+
### 方式 A:npm 全局安装(推荐)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g agents-bridge@latest
|
|
29
|
+
|
|
30
|
+
# 交互式引导:输入 gateway URL、bot token、选择模型,自动生成配置
|
|
31
|
+
agents-bridge onboard
|
|
32
|
+
|
|
33
|
+
# 启动
|
|
34
|
+
agents-bridge start
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 方式 B:Docker
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
docker run -d --name agents-bridge \
|
|
41
|
+
-v /home/user/project:/workspace \
|
|
42
|
+
-v agents-bridge-data:/root/.agent-bridge \
|
|
43
|
+
-e AGENT_BRIDGE_GATEWAY_URL=https://your-botlink.com \
|
|
44
|
+
-e AGENT_BRIDGE_BOT_TOKEN=bot_xxx \
|
|
45
|
+
-e ANTHROPIC_API_KEY=sk-ant-xxx \
|
|
46
|
+
agents-bridge:latest
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
或使用 docker-compose:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cp .env.example .env
|
|
53
|
+
# 编辑 .env 填入实际值
|
|
54
|
+
docker compose up -d
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 方式 C:源码运行(开发者)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone <repo-url>
|
|
61
|
+
cd <repo-dir>
|
|
62
|
+
pnpm install
|
|
63
|
+
pnpm build
|
|
64
|
+
cp config.example.json config.json # 编辑配置
|
|
65
|
+
node dist/entry.js start
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
开发模式(自动重载):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pnpm dev
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## CLI 命令
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
agents-bridge start # 启动 gateway(前台)
|
|
78
|
+
agents-bridge start --daemon # 启动为后台守护进程
|
|
79
|
+
agents-bridge start -c <path> # 指定配置文件启动
|
|
80
|
+
agents-bridge stop # 停止守护进程
|
|
81
|
+
agents-bridge status # 查看运行状态
|
|
82
|
+
agents-bridge onboard # 交互式初始化引导
|
|
83
|
+
agents-bridge doctor # 诊断环境(Node.js、CLI 工具、API Key)
|
|
84
|
+
agents-bridge logs # 查看日志
|
|
85
|
+
agents-bridge config # 查看当前配置(脱敏显示)
|
|
86
|
+
agents-bridge help # 帮助
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 配置
|
|
90
|
+
|
|
91
|
+
### 配置文件
|
|
92
|
+
|
|
93
|
+
主配置文件为 JSON 格式,搜索顺序:
|
|
94
|
+
|
|
95
|
+
1. CLI 参数:`agents-bridge start -c /path/to/config.json`
|
|
96
|
+
2. 环境变量:`AGENT_BRIDGE_CONFIG=/path/to/config.json`
|
|
97
|
+
3. 用户目录:`~/.agent-bridge/config.json`
|
|
98
|
+
4. 当前目录:`./config.json`
|
|
99
|
+
|
|
100
|
+
完整示例见 [config.example.json](config.example.json)。
|
|
101
|
+
|
|
102
|
+
### 核心配置项
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"channels": {
|
|
107
|
+
"botlink": {
|
|
108
|
+
"gateway_url": "https://your-botlink-instance.com",
|
|
109
|
+
"bot_token": "bot_xxxxxxxxxxxxxxxxxx",
|
|
110
|
+
"poll_timeout": 30,
|
|
111
|
+
"retry_interval": 5,
|
|
112
|
+
"max_retry_interval": 60
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"agents": {
|
|
116
|
+
"defaults": {
|
|
117
|
+
"model": {
|
|
118
|
+
"primary": "claude-cli/opus-4.6",
|
|
119
|
+
"fallbacks": ["anthropic/claude-sonnet-4-6"]
|
|
120
|
+
},
|
|
121
|
+
"cliBackends": {
|
|
122
|
+
"claude-cli": {
|
|
123
|
+
"command": "claude",
|
|
124
|
+
"args": ["-p", "--output-format", "json", "--dangerously-skip-permissions"],
|
|
125
|
+
"resumeArgs": ["-p", "--output-format", "json", "--dangerously-skip-permissions", "--resume", "{sessionId}"],
|
|
126
|
+
"output": "json",
|
|
127
|
+
"modelArg": "--model",
|
|
128
|
+
"sessionArg": "--session-id",
|
|
129
|
+
"sessionIdFields": ["session_id", "sessionId", "conversation_id", "conversationId"],
|
|
130
|
+
"sessionMode": "always",
|
|
131
|
+
"serialize": true
|
|
132
|
+
},
|
|
133
|
+
"codex-cli": {
|
|
134
|
+
"command": "codex",
|
|
135
|
+
"args": ["exec", "--json", "..."],
|
|
136
|
+
"resumeArgs": ["exec", "resume", "{sessionId}", "..."],
|
|
137
|
+
"sessionMode": "existing",
|
|
138
|
+
"output": "jsonl",
|
|
139
|
+
"resumeOutput": "text",
|
|
140
|
+
"modelArg": "--model",
|
|
141
|
+
"sessionIdFields": ["thread_id"],
|
|
142
|
+
"serialize": true
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"logging": {
|
|
148
|
+
"level": "info"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 环境变量覆盖
|
|
154
|
+
|
|
155
|
+
环境变量可覆盖配置文件中的对应值:
|
|
156
|
+
|
|
157
|
+
| 环境变量 | 覆盖 | 说明 |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `AGENT_BRIDGE_CONFIG` | — | 配置文件路径 |
|
|
160
|
+
| `AGENT_BRIDGE_GATEWAY_URL` | `channels.botlink.gateway_url` | botlink 网关地址 |
|
|
161
|
+
| `AGENT_BRIDGE_BOT_TOKEN` | `channels.botlink.bot_token` | Bot Token |
|
|
162
|
+
| `AGENT_BRIDGE_LOG_LEVEL` | `logging.level` | 日志级别 |
|
|
163
|
+
| `AGENT_BRIDGE_TEMP_DIR` | `files.temp_dir` | 临时文件目录 |
|
|
164
|
+
|
|
165
|
+
## 数据目录
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
~/.agent-bridge/
|
|
169
|
+
├── config.json # 主配置(onboard 生成)
|
|
170
|
+
├── agent-bridge.pid # PID 文件(daemon 模式)
|
|
171
|
+
├── data/
|
|
172
|
+
│ ├── sessions/ # Agent 会话持久化
|
|
173
|
+
│ │ └── cli-sessions.json # botlink session -> CLI session id 映射
|
|
174
|
+
│ ├── files/ # 文件中转临时目录
|
|
175
|
+
│ └── logs/ # 日志文件
|
|
176
|
+
└── skills/ # 自定义技能
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## 项目结构
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
agents-bridge/
|
|
183
|
+
├── bin/
|
|
184
|
+
│ └── agent-bridge.mjs # CLI 入口(npm 全局安装)
|
|
185
|
+
├── src/
|
|
186
|
+
│ ├── entry.ts # 主入口,子命令路由
|
|
187
|
+
│ ├── cli/ # CLI 命令实现
|
|
188
|
+
│ │ ├── run-main.ts # 参数解析
|
|
189
|
+
│ │ ├── cmd-start.ts # start 命令
|
|
190
|
+
│ │ ├── cmd-stop.ts # stop 命令
|
|
191
|
+
│ │ ├── cmd-status.ts # status 命令
|
|
192
|
+
│ │ ├── cmd-onboard.ts # onboard 交互引导
|
|
193
|
+
│ │ ├── cmd-doctor.ts # doctor 环境诊断
|
|
194
|
+
│ │ ├── cmd-logs.ts # logs 查看
|
|
195
|
+
│ │ └── cmd-config.ts # config 查看
|
|
196
|
+
│ ├── config/ # 配置加载与校验
|
|
197
|
+
│ │ ├── config.ts # 主加载器
|
|
198
|
+
│ │ ├── zod-schema.ts # Zod schema
|
|
199
|
+
│ │ ├── paths.ts # 数据目录路径常量
|
|
200
|
+
│ │ ├── env-vars.ts # 环境变量读取
|
|
201
|
+
│ │ ├── merge-config.ts # 配置合并
|
|
202
|
+
│ │ └── agent-dirs.ts # 目录初始化
|
|
203
|
+
│ ├── channels/ # Channel 插件框架
|
|
204
|
+
│ │ ├── registry.ts # 插件注册表
|
|
205
|
+
│ │ ├── session.ts # 会话管理
|
|
206
|
+
│ │ └── ...
|
|
207
|
+
│ ├── agents/ # Agent 运行时
|
|
208
|
+
│ │ ├── cli-backends.ts # CLI backend provider id / 默认配置装配
|
|
209
|
+
│ │ ├── cli-session-store.ts # CLI session 映射持久化
|
|
210
|
+
│ │ ├── cli-runner.ts # Claude/Codex CLI 执行器
|
|
211
|
+
│ │ └── ...
|
|
212
|
+
│ ├── types/ # 类型定义
|
|
213
|
+
│ └── logger.ts # Pino 日志
|
|
214
|
+
├── extensions/ # Channel 插件(botlink)
|
|
215
|
+
├── skills/ # 技能定义
|
|
216
|
+
├── config.example.json # 配置示例
|
|
217
|
+
├── .env.example # 环境变量示例
|
|
218
|
+
├── Dockerfile
|
|
219
|
+
├── docker-compose.yml
|
|
220
|
+
├── package.json
|
|
221
|
+
└── tsconfig.json
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 三种 Agent 模式
|
|
225
|
+
|
|
226
|
+
| 模式 | 模型引用示例 | 说明 |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| Claude Code | `claude-cli/opus-4.6` | 通过 CLI backend 启动本地 `claude` 命令 |
|
|
229
|
+
| Codex | `codex-cli/gpt-5.3-codex` | 通过 CLI backend 启动本地 `codex` 命令 |
|
|
230
|
+
| Pi Agent | `anthropic/claude-sonnet-4-6` | 通过 LLM API 直连,内置工具执行 |
|
|
231
|
+
|
|
232
|
+
在 `config.json` 的 `agents.defaults.model.primary` 中选择。
|
|
233
|
+
|
|
234
|
+
## CLI Backend 约定
|
|
235
|
+
|
|
236
|
+
- 内置 provider id 固定为 `claude-cli`、`codex-cli`。
|
|
237
|
+
- `agents.defaults.cliBackends` 会覆盖内置默认值,不需要重复写全量字段。
|
|
238
|
+
- `SessionEnvelope.sessionId` 是 botlink 稳定会话键,不等于 Claude/Codex 自己的 session id。
|
|
239
|
+
- CLI backend session id 会持久化到 `~/.agent-bridge/data/sessions/cli-sessions.json` 的 `cliSessionIds[providerId]`。
|
|
240
|
+
- `serialize: true` 的语义是“同一 botlink session 串行、跨 session 可并发”。
|
|
241
|
+
- Claude CLI 走 JSON 输出;Codex CLI 首次运行走 JSONL,resume 走 text。
|
|
242
|
+
|
|
243
|
+
## 技术栈
|
|
244
|
+
|
|
245
|
+
- TypeScript + Node.js (>= 22.0.0)
|
|
246
|
+
- pnpm (>= 9.0.0)
|
|
247
|
+
- Pino(日志)
|
|
248
|
+
- Zod(配置校验)
|
|
249
|
+
- JSON(配置格式)
|
|
250
|
+
|
|
251
|
+
## 开发
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
pnpm install # 安装依赖
|
|
255
|
+
pnpm build # 编译
|
|
256
|
+
pnpm dev # 开发模式(自动重载)
|
|
257
|
+
pnpm typecheck # 类型检查
|
|
258
|
+
```
|
|
259
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// agents-bridge CLI entry point
|
|
4
|
+
// Used by: npm install -g agents-bridge / npx agents-bridge
|
|
5
|
+
|
|
6
|
+
import { fileURLToPath } from 'node:url'
|
|
7
|
+
import { dirname, resolve } from 'node:path'
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
|
|
11
|
+
// Import the compiled entry point
|
|
12
|
+
await import(resolve(__dirname, '..', 'dist', 'entry.js'))
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"channels": {
|
|
3
|
+
"botlink": {
|
|
4
|
+
"gateway_url": "https://test.51yzt.cn",
|
|
5
|
+
"bot_token": "bot_WEMU0m9NVxwOQIMVaNYskiSDTK-_1hA7dcCrQCzoxcU",
|
|
6
|
+
"poll_timeout": 30,
|
|
7
|
+
"retry_interval": 5,
|
|
8
|
+
"max_retry_interval": 60
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"agents": {
|
|
12
|
+
"defaults": {
|
|
13
|
+
"model": {
|
|
14
|
+
"primary": "claude-cli/opus-4.6",
|
|
15
|
+
"fallbacks": [
|
|
16
|
+
"anthropic/claude-sonnet-4-6"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"cliBackends": {
|
|
20
|
+
"claude-cli": {
|
|
21
|
+
"command": "claude",
|
|
22
|
+
"args": [
|
|
23
|
+
"-p",
|
|
24
|
+
"--output-format",
|
|
25
|
+
"json",
|
|
26
|
+
"--dangerously-skip-permissions"
|
|
27
|
+
],
|
|
28
|
+
"resumeArgs": [
|
|
29
|
+
"-p",
|
|
30
|
+
"--output-format",
|
|
31
|
+
"json",
|
|
32
|
+
"--dangerously-skip-permissions",
|
|
33
|
+
"--resume",
|
|
34
|
+
"{sessionId}"
|
|
35
|
+
],
|
|
36
|
+
"output": "json",
|
|
37
|
+
"modelArg": "--model",
|
|
38
|
+
"sessionArg": "--session-id",
|
|
39
|
+
"sessionIdFields": [
|
|
40
|
+
"session_id",
|
|
41
|
+
"sessionId",
|
|
42
|
+
"conversation_id",
|
|
43
|
+
"conversationId"
|
|
44
|
+
],
|
|
45
|
+
"systemPromptArg": "--append-system-prompt",
|
|
46
|
+
"systemPromptMode": "append",
|
|
47
|
+
"systemPromptWhen": "first",
|
|
48
|
+
"clearEnv": [
|
|
49
|
+
"ANTHROPIC_API_KEY",
|
|
50
|
+
"ANTHROPIC_API_KEY_OLD"
|
|
51
|
+
],
|
|
52
|
+
"sessionMode": "always",
|
|
53
|
+
"serialize": true,
|
|
54
|
+
"reliability": {
|
|
55
|
+
"watchdog": {
|
|
56
|
+
"fresh": {
|
|
57
|
+
"noOutputTimeoutRatio": 0.8,
|
|
58
|
+
"minMs": 180000,
|
|
59
|
+
"maxMs": 600000
|
|
60
|
+
},
|
|
61
|
+
"resume": {
|
|
62
|
+
"noOutputTimeoutRatio": 0.3,
|
|
63
|
+
"minMs": 60000,
|
|
64
|
+
"maxMs": 180000
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"codex-cli": {
|
|
70
|
+
"command": "codex",
|
|
71
|
+
"args": [
|
|
72
|
+
"exec", "--json", "--color", "never",
|
|
73
|
+
"--sandbox", "read-only", "--skip-git-repo-check"
|
|
74
|
+
],
|
|
75
|
+
"resumeArgs": [
|
|
76
|
+
"exec", "resume", "{sessionId}", "--color", "never",
|
|
77
|
+
"--sandbox", "read-only", "--skip-git-repo-check"
|
|
78
|
+
],
|
|
79
|
+
"output": "jsonl",
|
|
80
|
+
"resumeOutput": "text",
|
|
81
|
+
"modelArg": "--model",
|
|
82
|
+
"sessionIdFields": [
|
|
83
|
+
"thread_id"
|
|
84
|
+
],
|
|
85
|
+
"imageArg": "--image",
|
|
86
|
+
"imageMode": "repeat",
|
|
87
|
+
"sessionMode": "existing",
|
|
88
|
+
"serialize": true,
|
|
89
|
+
"reliability": {
|
|
90
|
+
"watchdog": {
|
|
91
|
+
"fresh": {
|
|
92
|
+
"noOutputTimeoutRatio": 0.8,
|
|
93
|
+
"minMs": 180000,
|
|
94
|
+
"maxMs": 600000
|
|
95
|
+
},
|
|
96
|
+
"resume": {
|
|
97
|
+
"noOutputTimeoutRatio": 0.3,
|
|
98
|
+
"minMs": 60000,
|
|
99
|
+
"maxMs": 180000
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"skills": {
|
|
108
|
+
"dirs": ["./skills"]
|
|
109
|
+
},
|
|
110
|
+
"files": {
|
|
111
|
+
"temp_dir": "/tmp/agent-bridge/files",
|
|
112
|
+
"max_file_size": 52428800
|
|
113
|
+
},
|
|
114
|
+
"logging": {
|
|
115
|
+
"level": "info"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Backend 装配 — 复用现有 cliBackends 机制
|
|
3
|
+
*
|
|
4
|
+
* 根据 agents.defaults.model 中的 provider 前缀(如 "claude-cli"、"codex-cli"),
|
|
5
|
+
* 从 agents.defaults.cliBackends 中查找对应配置,启动本地 CLI 命令。
|
|
6
|
+
*
|
|
7
|
+
* 首版不做 token 级流式,而是:
|
|
8
|
+
* - 运行期间周期性发 sendChatAction(typing)
|
|
9
|
+
* - 完成后一次性发送最终文本消息
|
|
10
|
+
*
|
|
11
|
+
* TODO: Phase 3 实现
|
|
12
|
+
*/
|
|
13
|
+
import type { CliBackendConfig } from '../types/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* 从 model reference 中提取 provider 名称
|
|
16
|
+
* e.g. "claude-cli/opus-4.6" → "claude-cli"
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractProvider(modelRef: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* 从 model reference 中提取 model 名称
|
|
21
|
+
* e.g. "claude-cli/opus-4.6" → "opus-4.6"
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractModel(modelRef: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* 判断 model reference 是否指向 CLI backend
|
|
26
|
+
*/
|
|
27
|
+
export declare function isCliBackend(modelRef: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* 根据 model reference 查找对应的 CLI backend 配置
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveCliBackend(modelRef: string, backends: Record<string, CliBackendConfig> | undefined): CliBackendConfig | undefined;
|
|
32
|
+
//# sourceMappingURL=cli-backends.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-backends.d.ts","sourceRoot":"","sources":["../../src/agents/cli-backends.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,gBAAgB,CAAA;CACzB;AAwBD,eAAO,MAAM,2BAA2B,OAAQ,CAAA;AAEhD,eAAO,MAAM,2BAA2B;;;;CAI9B,CAAA;AAEV,eAAO,MAAM,4BAA4B;;;;CAI/B,CAAA;AAkGV,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiB5D;AAkBD,wBAAgB,oBAAoB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAOjF;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAC1C,OAAO,CAYT;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,GAC9B,kBAAkB,GAAG,IAAI,CA6B3B;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,GACrD,gBAAgB,GAAG,SAAS,CAW9B"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
const CLAUDE_MODEL_ALIASES = {
|
|
2
|
+
opus: 'opus',
|
|
3
|
+
'opus-4.6': 'opus',
|
|
4
|
+
'opus-4.5': 'opus',
|
|
5
|
+
'opus-4': 'opus',
|
|
6
|
+
'claude-opus-4-6': 'opus',
|
|
7
|
+
'claude-opus-4-5': 'opus',
|
|
8
|
+
'claude-opus-4': 'opus',
|
|
9
|
+
sonnet: 'sonnet',
|
|
10
|
+
'sonnet-4.6': 'sonnet',
|
|
11
|
+
'sonnet-4.5': 'sonnet',
|
|
12
|
+
'sonnet-4.1': 'sonnet',
|
|
13
|
+
'sonnet-4.0': 'sonnet',
|
|
14
|
+
'claude-sonnet-4-6': 'sonnet',
|
|
15
|
+
'claude-sonnet-4-5': 'sonnet',
|
|
16
|
+
'claude-sonnet-4-1': 'sonnet',
|
|
17
|
+
'claude-sonnet-4-0': 'sonnet',
|
|
18
|
+
haiku: 'haiku',
|
|
19
|
+
'haiku-3.5': 'haiku',
|
|
20
|
+
'claude-haiku-3-5': 'haiku',
|
|
21
|
+
};
|
|
22
|
+
export const CLI_WATCHDOG_MIN_TIMEOUT_MS = 1_000;
|
|
23
|
+
export const CLI_FRESH_WATCHDOG_DEFAULTS = {
|
|
24
|
+
noOutputTimeoutRatio: 0.8,
|
|
25
|
+
minMs: 180_000,
|
|
26
|
+
maxMs: 600_000,
|
|
27
|
+
};
|
|
28
|
+
export const CLI_RESUME_WATCHDOG_DEFAULTS = {
|
|
29
|
+
noOutputTimeoutRatio: 0.3,
|
|
30
|
+
minMs: 60_000,
|
|
31
|
+
maxMs: 180_000,
|
|
32
|
+
};
|
|
33
|
+
const DEFAULT_CLAUDE_BACKEND = {
|
|
34
|
+
command: 'claude',
|
|
35
|
+
args: ['-p', '--verbose', '--output-format', 'stream-json', '--dangerously-skip-permissions'],
|
|
36
|
+
resumeArgs: [
|
|
37
|
+
'-p',
|
|
38
|
+
'--verbose',
|
|
39
|
+
'--output-format',
|
|
40
|
+
'stream-json',
|
|
41
|
+
'--dangerously-skip-permissions',
|
|
42
|
+
'--resume',
|
|
43
|
+
'{sessionId}',
|
|
44
|
+
],
|
|
45
|
+
output: 'jsonl',
|
|
46
|
+
resumeOutput: 'jsonl',
|
|
47
|
+
input: 'arg',
|
|
48
|
+
modelArg: '--model',
|
|
49
|
+
modelAliases: CLAUDE_MODEL_ALIASES,
|
|
50
|
+
sessionArg: '--session-id',
|
|
51
|
+
sessionMode: 'always',
|
|
52
|
+
sessionIdFields: ['session_id', 'sessionId', 'conversation_id', 'conversationId'],
|
|
53
|
+
systemPromptArg: '--append-system-prompt',
|
|
54
|
+
systemPromptMode: 'append',
|
|
55
|
+
systemPromptWhen: 'first',
|
|
56
|
+
clearEnv: ['ANTHROPIC_API_KEY', 'ANTHROPIC_API_KEY_OLD'],
|
|
57
|
+
reliability: {
|
|
58
|
+
watchdog: {
|
|
59
|
+
fresh: { ...CLI_FRESH_WATCHDOG_DEFAULTS },
|
|
60
|
+
resume: { ...CLI_RESUME_WATCHDOG_DEFAULTS },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
serialize: true,
|
|
64
|
+
};
|
|
65
|
+
const DEFAULT_CODEX_BACKEND = {
|
|
66
|
+
command: 'codex',
|
|
67
|
+
args: ['exec', '--json', '--color', 'never', '--sandbox', 'read-only', '--skip-git-repo-check'],
|
|
68
|
+
resumeArgs: [
|
|
69
|
+
'exec',
|
|
70
|
+
'resume',
|
|
71
|
+
'{sessionId}',
|
|
72
|
+
'--color',
|
|
73
|
+
'never',
|
|
74
|
+
'--sandbox',
|
|
75
|
+
'read-only',
|
|
76
|
+
'--skip-git-repo-check',
|
|
77
|
+
],
|
|
78
|
+
output: 'jsonl',
|
|
79
|
+
resumeOutput: 'text',
|
|
80
|
+
input: 'arg',
|
|
81
|
+
modelArg: '--model',
|
|
82
|
+
sessionIdFields: ['thread_id'],
|
|
83
|
+
sessionMode: 'existing',
|
|
84
|
+
imageArg: '--image',
|
|
85
|
+
imageMode: 'repeat',
|
|
86
|
+
reliability: {
|
|
87
|
+
watchdog: {
|
|
88
|
+
fresh: { ...CLI_FRESH_WATCHDOG_DEFAULTS },
|
|
89
|
+
resume: { ...CLI_RESUME_WATCHDOG_DEFAULTS },
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
serialize: true,
|
|
93
|
+
};
|
|
94
|
+
function mergeBackendConfig(base, override) {
|
|
95
|
+
if (!override) {
|
|
96
|
+
return { ...base };
|
|
97
|
+
}
|
|
98
|
+
const baseFresh = base.reliability?.watchdog?.fresh ?? {};
|
|
99
|
+
const baseResume = base.reliability?.watchdog?.resume ?? {};
|
|
100
|
+
const overrideFresh = override.reliability?.watchdog?.fresh ?? {};
|
|
101
|
+
const overrideResume = override.reliability?.watchdog?.resume ?? {};
|
|
102
|
+
return {
|
|
103
|
+
...base,
|
|
104
|
+
...override,
|
|
105
|
+
args: override.args ?? base.args,
|
|
106
|
+
env: { ...base.env, ...override.env },
|
|
107
|
+
modelAliases: { ...base.modelAliases, ...override.modelAliases },
|
|
108
|
+
clearEnv: Array.from(new Set([...(base.clearEnv ?? []), ...(override.clearEnv ?? [])])),
|
|
109
|
+
sessionIdFields: override.sessionIdFields ?? base.sessionIdFields,
|
|
110
|
+
sessionArgs: override.sessionArgs ?? base.sessionArgs,
|
|
111
|
+
resumeArgs: override.resumeArgs ?? base.resumeArgs,
|
|
112
|
+
reliability: {
|
|
113
|
+
...base.reliability,
|
|
114
|
+
...override.reliability,
|
|
115
|
+
watchdog: {
|
|
116
|
+
...base.reliability?.watchdog,
|
|
117
|
+
...override.reliability?.watchdog,
|
|
118
|
+
fresh: { ...baseFresh, ...overrideFresh },
|
|
119
|
+
resume: { ...baseResume, ...overrideResume },
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function normalizeProviderId(provider) {
|
|
125
|
+
const normalized = provider.trim().toLowerCase().replaceAll('_', '-');
|
|
126
|
+
if (normalized === 'claude' ||
|
|
127
|
+
normalized === 'claude-cli' ||
|
|
128
|
+
normalized === 'claudecli') {
|
|
129
|
+
return 'claude-cli';
|
|
130
|
+
}
|
|
131
|
+
if (normalized === 'codex' ||
|
|
132
|
+
normalized === 'codex-cli' ||
|
|
133
|
+
normalized === 'codexcli') {
|
|
134
|
+
return 'codex-cli';
|
|
135
|
+
}
|
|
136
|
+
return normalized;
|
|
137
|
+
}
|
|
138
|
+
function normalizeBackendKey(key) {
|
|
139
|
+
return normalizeProviderId(key);
|
|
140
|
+
}
|
|
141
|
+
function pickBackendConfig(config, normalizedId) {
|
|
142
|
+
for (const [key, entry] of Object.entries(config)) {
|
|
143
|
+
if (normalizeBackendKey(key) === normalizedId) {
|
|
144
|
+
return entry;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
export function resolveCliBackendIds(cfg) {
|
|
150
|
+
const ids = new Set(['claude-cli', 'codex-cli']);
|
|
151
|
+
const configured = cfg?.agents.defaults.cliBackends ?? {};
|
|
152
|
+
for (const key of Object.keys(configured)) {
|
|
153
|
+
ids.add(normalizeBackendKey(key));
|
|
154
|
+
}
|
|
155
|
+
return ids;
|
|
156
|
+
}
|
|
157
|
+
export function extractProvider(modelRef) {
|
|
158
|
+
const slashIdx = modelRef.indexOf('/');
|
|
159
|
+
return normalizeProviderId(slashIdx === -1 ? modelRef : modelRef.slice(0, slashIdx));
|
|
160
|
+
}
|
|
161
|
+
export function extractModel(modelRef) {
|
|
162
|
+
const slashIdx = modelRef.indexOf('/');
|
|
163
|
+
return slashIdx === -1 ? '' : modelRef.slice(slashIdx + 1);
|
|
164
|
+
}
|
|
165
|
+
export function isCliBackend(modelRef, backends) {
|
|
166
|
+
const provider = extractProvider(modelRef);
|
|
167
|
+
if (provider === 'claude-cli' || provider === 'codex-cli') {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
if (provider.endsWith('-cli')) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
if (!backends) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
return Object.keys(backends).some((key) => normalizeBackendKey(key) === provider);
|
|
177
|
+
}
|
|
178
|
+
export function resolveCliBackendConfig(provider, cfg) {
|
|
179
|
+
const normalized = normalizeBackendKey(provider);
|
|
180
|
+
const configured = cfg?.agents.defaults.cliBackends ?? {};
|
|
181
|
+
const override = pickBackendConfig(configured, normalized);
|
|
182
|
+
if (normalized === 'claude-cli') {
|
|
183
|
+
const merged = mergeBackendConfig(DEFAULT_CLAUDE_BACKEND, override);
|
|
184
|
+
const command = merged.command.trim();
|
|
185
|
+
if (!command)
|
|
186
|
+
return null;
|
|
187
|
+
return { id: normalized, config: { ...merged, command } };
|
|
188
|
+
}
|
|
189
|
+
if (normalized === 'codex-cli') {
|
|
190
|
+
const merged = mergeBackendConfig(DEFAULT_CODEX_BACKEND, override);
|
|
191
|
+
const command = merged.command.trim();
|
|
192
|
+
if (!command)
|
|
193
|
+
return null;
|
|
194
|
+
return { id: normalized, config: { ...merged, command } };
|
|
195
|
+
}
|
|
196
|
+
if (!override) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
const command = override.command.trim();
|
|
200
|
+
if (!command) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
return { id: normalized, config: { ...override, command } };
|
|
204
|
+
}
|
|
205
|
+
export function resolveCliBackend(modelRef, backends) {
|
|
206
|
+
if (!backends) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
const provider = extractProvider(modelRef);
|
|
210
|
+
for (const [key, config] of Object.entries(backends)) {
|
|
211
|
+
if (normalizeBackendKey(key) === provider) {
|
|
212
|
+
return config;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=cli-backends.js.map
|