适配opencode

This commit is contained in:
Sirius
2026-08-12 15:26:53 +08:00
parent 3b9454c787
commit cfece34a71
3 changed files with 65 additions and 4 deletions
+25 -3
View File
@@ -59,7 +59,8 @@ command-code-openai-bridge/
│ └── start.sh
└── examples/
├── node_client.mjs
── python_client.py
── python_client.py
└── opencode.json
```
## 安装
@@ -119,6 +120,26 @@ models:
Bridge 会直接响应浏览器 CORS 预检,包括 Copilot 和 OpenAI SDK 发送的自定义请求头及本机 Private Network Access。关闭 Copilot 的 CORS 绕过后,请求使用原生 `fetch`,可以读取 Bridge 返回的 SSE 流。将 `config.yaml` 中的 `stream_thinking` 设为 `true` 后,Bridge 会把实时思考事件作为 `<think>` 块发送,Copilot 将其显示为可折叠思考内容。思考中的 `Sources` 标记会被等效转义,避免 Copilot 把内部草稿误判为最终引用区并丢弃后续正文。
### OpenCode 自定义 provider
已在本机验证 **OpenCode 1.18.15** 通过 `@ai-sdk/openai-compatible` 自定义 provider 连接 Bridge,并完成真实工具循环(`glob` 单工具、并行 `glob`、流式 `tool_calls` 与工具结果后的文本轮次)。
1. 启动 Bridge(默认 `http://127.0.0.1:18000/v1`)。
2.`examples/opencode.json` 复制到项目根目录,或通过环境变量指向它:
```bash
export OPENCODE_CONFIG="/path/to/command-code-openai-bridge/examples/opencode.json"
```
3. OpenCode 仍需配置任意非空 API keyBridge 忽略 Authorization,但客户端要求填写)。示例配置使用 `options.apiKey: "local-bridge"`
4. 选择模型 `command-bridge/command-default`(与 `config.yaml` 中的 `models.command-default` 映射一致)。
OpenCode 1.18.15 实际发送的 Chat 请求包含 `stream: true``stream_options.include_usage: true``max_tokens`(默认约 32000)、`store: false``tools`(约 24 个内置工具)、`tool_choice: auto`。Bridge 接受 `store` 与采样/输出限制参数但不改变无状态行为;未映射参数通过 `X-Command-Code-Ignored-Parameters` 标出。工具 `parameters` 中的 JSON Schema `$schema`draft 2020-12)会在校验前剥离元数据字段,避免 AJV 拒绝 OpenCode 工具定义。
OpenCode 还会在会话标题生成等场景发送无 `tools` 的压缩/摘要请求(`stream: true`、较长 system 提示、无 `store``store: false`)。这些请求与主 agent 请求共用同一 provider。
已知限制:Bridge 不实现 OpenCode hosted tools、图片/音频输入、Computer Use 或 Responses `/v1/responses` 路径;OpenCode 自定义 provider 走 `/v1/chat/completions``temperature``max_tokens` 等采样参数不会传给 Command Code CLI。
## 启动、停止与重启
```bash
@@ -160,7 +181,7 @@ Chat 接口接受标准 function tools、`tool_choice` 和 `parallel_tool_calls`
`stream` 省略或设为 `false` 时返回普通 JSON。普通文本请求的 `stream: true` 会立即建立 SSE 连接并发送 assistant role 块,随后在 Command Code 的 `text_delta` 到达时立即发送对应 SSE chunk,最后发送 `finish_reason: "stop"`、可选 usage 块和 `[DONE]`。工具模式需要先解析和校验完整决策:最终文本会在校验后作为 content chunk 发送;工具调用会作为 `delta.tool_calls` 发送,并以 `finish_reason: "tool_calls"` 结束。`stream_thinking: true` 只作用于普通文本请求;该兼容格式不是原生 OpenAI reasoning item。传入 `stream_options.include_usage: true` 时,结束前返回 usage 块。
为兼容 Obsidian Copilot 和 LangChain OpenAI-format 客户端,Chat 接口还接受 `temperature``max_tokens``max_completion_tokens``top_p``frequency_penalty``presence_penalty``n: 1`。这些采样输出限制参数会按 OpenAI 取值范围严格校验。Command Code CLI 1.12.0 没有对应的 headless 参数,因此 Bridge 不会把它们伪装成已生效:服务终端会输出警告,HTTP 响应带 `X-Command-Code-Ignored-Parameters`。其他未实现字段仍返回 `400 unsupported_parameter`
为兼容 Obsidian Copilot、OpenCode 和 LangChain OpenAI-format 客户端,Chat 接口还接受 `temperature``max_tokens``max_completion_tokens``top_p``frequency_penalty``presence_penalty``n: 1``store`。这些采样输出限制与会话存储参数会按 OpenAI 取值范围严格校验。Command Code CLI 没有对应的 headless 参数,Chat Completions 也不保存跨请求会话;Bridge 不会把它们伪装成已生效:服务终端会输出警告,HTTP 响应带 `X-Command-Code-Ignored-Parameters`。其他未实现字段仍返回 `400 unsupported_parameter`
Chat Completions 和 Responses 共用 Command Code NDJSON 执行层。服务终端会在事件到达时立即显示状态、文本和 Command Code 自身的工具调用。普通文本 Chat 会把每个 `text_delta` 直接写入 SSE;外部 function calling 模式会缓存 `finalText`,避免内部 JSON 决策进入客户端正文。Responses 外部 function calling 同样缓存 `finalText`,工具轮次不向客户端输出 assistant 文本。
@@ -315,7 +336,7 @@ command-code \
## 本机实际检查结果
检查日期:Chat Completions 原有检查为 2026-08-04Responses 文本子集检查为 2026-08-05Chat function calling 协议检查为 2026-08-06Responses function calling 检查为 2026-08-12。没有编写测试用例。原有条目来自真实 CLI 和真实 HTTP/SDK 客户端;有限队列改动完成了类型检查、生产构建和协调器运行时冒烟检查,尚未重新运行真实 CLI 并发检查。Chat function calling 完成了内部协议冒烟检查、Obsidian Copilot 当前依赖 `@langchain/openai 1.2.2` 的双轮 wire compatibility 检查,以及真实 Command Code 与 OpenAI Node.js SDK 的双轮 HTTP/SSE 调用;尚未在 Obsidian UI 中运行完整检查。Responses function calling 完成了类型检查、生产构建、真实 HTTP 双轮检查、流式 function call SSE 检查和 OpenAI Node.js SDK 双轮检查。
检查日期:Chat Completions 原有检查为 2026-08-04Responses 文本子集检查为 2026-08-05Chat function calling 协议检查为 2026-08-06Responses function calling 检查为 2026-08-12OpenCode 1.18.15 Chat Completions E2E 检查为 2026-08-12。没有编写测试用例。原有条目来自真实 CLI 和真实 HTTP/SDK 客户端;有限队列改动完成了类型检查、生产构建和协调器运行时冒烟检查,尚未重新运行真实 CLI 并发检查。Chat function calling 完成了内部协议冒烟检查、Obsidian Copilot 当前依赖 `@langchain/openai 1.2.2` 的双轮 wire compatibility 检查,以及真实 Command Code 与 OpenAI Node.js SDK 的双轮 HTTP/SSE 调用;尚未在 Obsidian UI 中运行完整检查。Responses function calling 完成了类型检查、生产构建、真实 HTTP 双轮检查、流式 function call SSE 检查和 OpenAI Node.js SDK 双轮检查。OpenCode 1.18.15 完成了真实 `opencode run` 文本回复、`glob` 工具循环、并行 `glob`、流式 `tool_calls`/`stop` SSE、`store: false``max_tokens` 接受、工具 Schema `$schema` 兼容,以及客户端断开后的取消恢复检查。
- TypeScript 严格类型检查和生产构建通过。
- npm 生产依赖审计:0 个已知漏洞。
@@ -352,6 +373,7 @@ command-code \
- Responses 流式 function call 发送 `output_item.added``function_call_arguments.delta/done``output_item.done``completed`,无 `output_text.delta`
- OpenAI Node.js SDK 的 Responses 双轮检查:第一轮返回 `multiply` function call,第二轮消费 `function_call_output` 后返回最终文本。
- Responses 无效工具名、无效 arguments JSON、孤立 `function_call_output` 和 hosted tool 类型分别返回带 `param` 的 400 错误。
- OpenCode 1.18.15 自定义 provider`store: false``max_tokens: 32000` 返回 HTTP 200`stream: true` 工具轮次以 `finish_reason: tool_calls` 结束,文本轮次以 `stop` 结束;`glob` 单工具与并行 `glob` 完成完整工具循环;工具 `parameters.$schema`draft 2020-12)不再触发 400。
## 已知限制