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.
Files changed (139) hide show
  1. package/.env.example +20 -0
  2. package/LICENSE +21 -0
  3. package/README.md +259 -0
  4. package/bin/agent-bridge.mjs +12 -0
  5. package/config.example.json +117 -0
  6. package/dist/agents/cli-backends.d.ts +32 -0
  7. package/dist/agents/cli-backends.d.ts.map +1 -0
  8. package/dist/agents/cli-backends.js +217 -0
  9. package/dist/agents/cli-backends.js.map +1 -0
  10. package/dist/agents/cli-runner.d.ts.map +1 -0
  11. package/dist/agents/cli-runner.js +524 -0
  12. package/dist/agents/cli-runner.js.map +1 -0
  13. package/dist/agents/cli-session-store.d.ts.map +1 -0
  14. package/dist/agents/cli-session-store.js +127 -0
  15. package/dist/agents/cli-session-store.js.map +1 -0
  16. package/dist/agents/model-selection.d.ts +27 -0
  17. package/dist/agents/model-selection.d.ts.map +1 -0
  18. package/dist/agents/model-selection.js +40 -0
  19. package/dist/agents/model-selection.js.map +1 -0
  20. package/dist/agents/models-config.d.ts +28 -0
  21. package/dist/agents/models-config.d.ts.map +1 -0
  22. package/dist/agents/models-config.js +43 -0
  23. package/dist/agents/models-config.js.map +1 -0
  24. package/dist/channels/botlink.d.ts.map +1 -0
  25. package/dist/channels/botlink.js +320 -0
  26. package/dist/channels/botlink.js.map +1 -0
  27. package/dist/channels/command-gating.d.ts +20 -0
  28. package/dist/channels/command-gating.d.ts.map +1 -0
  29. package/dist/channels/command-gating.js +43 -0
  30. package/dist/channels/command-gating.js.map +1 -0
  31. package/dist/channels/draft-stream-controls.d.ts +21 -0
  32. package/dist/channels/draft-stream-controls.d.ts.map +1 -0
  33. package/dist/channels/draft-stream-controls.js +43 -0
  34. package/dist/channels/draft-stream-controls.js.map +1 -0
  35. package/dist/channels/draft-stream-loop.d.ts +31 -0
  36. package/dist/channels/draft-stream-loop.d.ts.map +1 -0
  37. package/dist/channels/draft-stream-loop.js +60 -0
  38. package/dist/channels/draft-stream-loop.js.map +1 -0
  39. package/dist/channels/mention-gating.d.ts +18 -0
  40. package/dist/channels/mention-gating.d.ts.map +1 -0
  41. package/dist/channels/mention-gating.js +20 -0
  42. package/dist/channels/mention-gating.js.map +1 -0
  43. package/dist/channels/registry.d.ts +5 -0
  44. package/dist/channels/registry.d.ts.map +1 -0
  45. package/dist/channels/registry.js +14 -0
  46. package/dist/channels/registry.js.map +1 -0
  47. package/dist/channels/run-state-machine.d.ts +21 -0
  48. package/dist/channels/run-state-machine.d.ts.map +1 -0
  49. package/dist/channels/run-state-machine.js +41 -0
  50. package/dist/channels/run-state-machine.js.map +1 -0
  51. package/dist/channels/session-envelope.d.ts +5 -0
  52. package/dist/channels/session-envelope.d.ts.map +1 -0
  53. package/dist/channels/session-envelope.js +13 -0
  54. package/dist/channels/session-envelope.js.map +1 -0
  55. package/dist/channels/session.d.ts +18 -0
  56. package/dist/channels/session.d.ts.map +1 -0
  57. package/dist/channels/session.js +35 -0
  58. package/dist/channels/session.js.map +1 -0
  59. package/dist/channels/typing-lifecycle.d.ts +16 -0
  60. package/dist/channels/typing-lifecycle.d.ts.map +1 -0
  61. package/dist/channels/typing-lifecycle.js +31 -0
  62. package/dist/channels/typing-lifecycle.js.map +1 -0
  63. package/dist/cli/cmd-config.d.ts +3 -0
  64. package/dist/cli/cmd-config.d.ts.map +1 -0
  65. package/dist/cli/cmd-config.js +15 -0
  66. package/dist/cli/cmd-config.js.map +1 -0
  67. package/dist/cli/cmd-doctor.d.ts +3 -0
  68. package/dist/cli/cmd-doctor.d.ts.map +1 -0
  69. package/dist/cli/cmd-doctor.js +80 -0
  70. package/dist/cli/cmd-doctor.js.map +1 -0
  71. package/dist/cli/cmd-logs.d.ts +3 -0
  72. package/dist/cli/cmd-logs.d.ts.map +1 -0
  73. package/dist/cli/cmd-logs.js +26 -0
  74. package/dist/cli/cmd-logs.js.map +1 -0
  75. package/dist/cli/cmd-onboard.d.ts +3 -0
  76. package/dist/cli/cmd-onboard.d.ts.map +1 -0
  77. package/dist/cli/cmd-onboard.js +103 -0
  78. package/dist/cli/cmd-onboard.js.map +1 -0
  79. package/dist/cli/cmd-start.d.ts +3 -0
  80. package/dist/cli/cmd-start.d.ts.map +1 -0
  81. package/dist/cli/cmd-start.js +155 -0
  82. package/dist/cli/cmd-start.js.map +1 -0
  83. package/dist/cli/cmd-status.d.ts +3 -0
  84. package/dist/cli/cmd-status.d.ts.map +1 -0
  85. package/dist/cli/cmd-status.js +16 -0
  86. package/dist/cli/cmd-status.js.map +1 -0
  87. package/dist/cli/cmd-stop.d.ts +3 -0
  88. package/dist/cli/cmd-stop.d.ts.map +1 -0
  89. package/dist/cli/cmd-stop.js +30 -0
  90. package/dist/cli/cmd-stop.js.map +1 -0
  91. package/dist/cli/pid-file.d.ts +7 -0
  92. package/dist/cli/pid-file.d.ts.map +1 -0
  93. package/dist/cli/pid-file.js +51 -0
  94. package/dist/cli/pid-file.js.map +1 -0
  95. package/dist/cli/run-main.d.ts +11 -0
  96. package/dist/cli/run-main.d.ts.map +1 -0
  97. package/dist/cli/run-main.js +64 -0
  98. package/dist/cli/run-main.js.map +1 -0
  99. package/dist/config/agent-dirs.d.ts +12 -0
  100. package/dist/config/agent-dirs.d.ts.map +1 -0
  101. package/dist/config/agent-dirs.js +30 -0
  102. package/dist/config/agent-dirs.js.map +1 -0
  103. package/dist/config/config.d.ts +3 -0
  104. package/dist/config/config.d.ts.map +1 -0
  105. package/dist/config/config.js +40 -0
  106. package/dist/config/config.js.map +1 -0
  107. package/dist/config/env-vars.d.ts +15 -0
  108. package/dist/config/env-vars.d.ts.map +1 -0
  109. package/dist/config/env-vars.js +16 -0
  110. package/dist/config/env-vars.js.map +1 -0
  111. package/dist/config/merge-config.d.ts +7 -0
  112. package/dist/config/merge-config.d.ts.map +1 -0
  113. package/dist/config/merge-config.js +32 -0
  114. package/dist/config/merge-config.js.map +1 -0
  115. package/dist/config/paths.d.ts +19 -0
  116. package/dist/config/paths.d.ts.map +1 -0
  117. package/dist/config/paths.js +22 -0
  118. package/dist/config/paths.js.map +1 -0
  119. package/dist/config/zod-schema.d.ts +1192 -0
  120. package/dist/config/zod-schema.d.ts.map +1 -0
  121. package/dist/config/zod-schema.js +107 -0
  122. package/dist/config/zod-schema.js.map +1 -0
  123. package/dist/console-encoding.d.ts +6 -0
  124. package/dist/console-encoding.d.ts.map +1 -0
  125. package/dist/console-encoding.js +35 -0
  126. package/dist/console-encoding.js.map +1 -0
  127. package/dist/entry.d.ts +3 -0
  128. package/dist/entry.d.ts.map +1 -0
  129. package/dist/entry.js +47 -0
  130. package/dist/entry.js.map +1 -0
  131. package/dist/logger.d.ts +4 -0
  132. package/dist/logger.d.ts.map +1 -0
  133. package/dist/logger.js +19 -0
  134. package/dist/logger.js.map +1 -0
  135. package/dist/types/index.d.ts +67 -0
  136. package/dist/types/index.d.ts.map +1 -0
  137. package/dist/types/index.js +2 -0
  138. package/dist/types/index.js.map +1 -0
  139. 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