支持responses
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Command Code OpenAI Bridge
|
||||
|
||||
这是一个只绑定本机地址的 OpenAI 兼容转发服务。它实现 Chat Completions 文本与 function calling,并提供 Responses API 文本子集。每个生成请求启动一次独立的 Command Code headless agent,将完整消息历史通过 stdin 发送给 CLI,在当前终端显示运行过程,再把结构化事件和最终 `finalText` 转换成 OpenAI 风格的 JSON 或 SSE。
|
||||
这是一个只绑定本机地址的 OpenAI 兼容转发服务。它实现 Chat Completions 与 Responses API 的文本对话和外部 function calling。每个生成请求启动一次独立的 Command Code headless agent,将完整消息历史通过 stdin 发送给 CLI,在当前终端显示运行过程,再把结构化事件和最终 `finalText` 转换成 OpenAI 风格的 JSON 或 SSE。
|
||||
|
||||
默认地址:`http://127.0.0.1:18000/v1`
|
||||
|
||||
@@ -162,7 +162,7 @@ Chat 接口接受标准 function tools、`tool_choice` 和 `parallel_tool_calls`
|
||||
|
||||
为兼容 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`。
|
||||
|
||||
Chat Completions 和 Responses 共用 Command Code NDJSON 执行层。服务终端会在事件到达时立即显示状态、文本和 Command Code 自身的工具调用。普通文本 Chat 会把每个 `text_delta` 直接写入 SSE;外部 function calling 模式会缓存 `finalText`,避免内部 JSON 决策进入客户端正文。
|
||||
Chat Completions 和 Responses 共用 Command Code NDJSON 执行层。服务终端会在事件到达时立即显示状态、文本和 Command Code 自身的工具调用。普通文本 Chat 会把每个 `text_delta` 直接写入 SSE;外部 function calling 模式会缓存 `finalText`,避免内部 JSON 决策进入客户端正文。Responses 外部 function calling 同样缓存 `finalText`,工具轮次不向客户端输出 assistant 文本。
|
||||
|
||||
### Responses
|
||||
|
||||
@@ -177,32 +177,43 @@ Chat Completions 和 Responses 共用 Command Code NDJSON 执行层。服务终
|
||||
- `metadata`
|
||||
- `reasoning.effort`
|
||||
- `text.format`
|
||||
- `tools`
|
||||
- `tool_choice`
|
||||
- `parallel_tool_calls`
|
||||
|
||||
`input` 可以是字符串,也可以是 message item 数组。message 支持 `system`、`developer`、`user`、`assistant` 角色、字符串 content,以及 `input_text`、`output_text` part。
|
||||
`input` 可以是字符串,也可以是 item 数组。message 支持 `system`、`developer`、`user`、`assistant` 角色、字符串 content,以及 `input_text`、`output_text` part。工具轮次还支持 `function_call` 和 `function_call_output` item,分别携带 `call_id`、工具名、`arguments` 和工具执行结果 `output`。
|
||||
|
||||
普通响应包含 `id`、`object`、时间、状态、错误、instructions、model、标准 assistant message output item、`output_text`、响应链 ID、effective reasoning effort、store、metadata、text format 和 usage。usage 只使用 Command Code 实际提供的 input/output token;没有 usage 时返回 `null`,不生成 token 明细。
|
||||
Responses 接受标准 function tools、`tool_choice` 和 `parallel_tool_calls`。Bridge 把工具定义、完整历史(含先前 response 的完整 output items)和工具结果交给 Command Code 决定下一步,校验返回的工具名与 arguments JSON Schema;第一次不合格时在原请求总截止时间内执行一次修复。工具由 API 客户端执行,Bridge 不执行客户端工具,也不会让 Command Code 用自身文件、终端、网络等工具替代外部 tools。该流程适用于 OpenCode 等使用 `@ai-sdk/openai` 或 OpenAI Node.js SDK 的 Responses 客户端。
|
||||
|
||||
`stream: true` 会立即建立 SSE 连接并发送:
|
||||
普通文本响应包含标准 assistant message output item 和 `output_text`。工具调用轮次返回 `function_call` output item,包含 `id`、`call_id`、`name`、`arguments` 和 `status`,`output_text` 为空。最终文本轮次在有足够 `function_call_output` 后返回 message。响应还包含 `id`、`object`、时间、状态、错误、instructions、model、响应链 ID、effective reasoning effort、store、metadata、text format、tools、tool_choice、parallel_tool_calls 和 usage。usage 只使用 Command Code 实际提供的 input/output token;没有 usage 时返回 `null`,不生成 token 明细。
|
||||
|
||||
1. `response.created`
|
||||
2. `response.in_progress`
|
||||
3. `response.output_item.added`
|
||||
4. `response.content_part.added`
|
||||
5. 一个或多个 `response.output_text.delta`
|
||||
6. `response.output_text.done`
|
||||
7. `response.content_part.done`
|
||||
8. `response.output_item.done`
|
||||
9. `response.completed` 或 `response.incomplete`
|
||||
`stream: true` 会立即建立 SSE 连接并发送 `response.created` 和 `response.in_progress`。文本响应随后发送:
|
||||
|
||||
1. `response.output_item.added`
|
||||
2. `response.content_part.added`
|
||||
3. 一个或多个 `response.output_text.delta`
|
||||
4. `response.output_text.done`
|
||||
5. `response.content_part.done`
|
||||
6. `response.output_item.done`
|
||||
7. `response.completed` 或 `response.incomplete`
|
||||
|
||||
工具调用轮次发送:
|
||||
|
||||
1. `response.output_item.added`
|
||||
2. `response.function_call_arguments.delta`
|
||||
3. `response.function_call_arguments.done`
|
||||
4. `response.output_item.done`
|
||||
5. `response.completed`
|
||||
|
||||
所有事件都包含递增的 `sequence_number`。连接使用 `no-cache, no-transform`,收到客户端断开后会终止 Command Code 子进程组。
|
||||
|
||||
Responses API 仍按 turn 缓冲文本,丢弃 `hadToolCalls: true` 的中间轮次,在 `hadToolCalls: false` 时按原 delta 边界发送。文本 delta 会延迟到最终 turn 边界。结构化输出还会延迟到 JSON 校验完成,避免把随后需要修复的无效 JSON 发给客户端。
|
||||
Responses API 仍按 turn 缓冲文本,丢弃 `hadToolCalls: true` 的中间轮次,在 `hadToolCalls: false` 时按原 delta 边界发送。文本 delta 会延迟到最终 turn 边界。外部 function calling 和结构化输出还会延迟到 JSON 校验完成,避免把随后需要修复的无效 JSON 或内部决策发给客户端。
|
||||
|
||||
### 本地存储和响应链
|
||||
|
||||
`store` 默认是 `true`。完成、incomplete、failed 和 cancelled Response 会写入配置的本地目录;`store: false` 不写入当前 Response,因此它不能在后续作为 `previous_response_id` 使用。
|
||||
|
||||
收到 `previous_response_id` 时,Bridge 从本地文件沿链向前读取每个 Response,按原顺序重放历史 input 和 assistant output,再追加当前 input。可以从任意仍存在的旧 Response 创建分支。删除某个祖先后,依赖该祖先的链会返回 404。Response ID 使用固定本地格式并在拼接文件路径前校验。
|
||||
收到 `previous_response_id` 时,Bridge 从本地文件沿链向前读取每个 Response,按原顺序重放历史 input 和完整 assistant output items(含 `function_call` 与 message,不仅重放 `output_text`),再追加当前 input。可以从任意仍存在的旧 Response 创建分支。删除某个祖先后,依赖该祖先的链会返回 404。Response ID 使用固定本地格式并在拼接文件路径前校验。
|
||||
|
||||
input items 查询返回标准 `{ object: "list", data, first_id, last_id, has_more }`,支持 `after`、`limit` 和 `order`。删除成功返回 `{ id, object: "response", deleted: true }`。
|
||||
|
||||
@@ -304,7 +315,7 @@ command-code \
|
||||
|
||||
## 本机实际检查结果
|
||||
|
||||
检查日期:Chat Completions 原有检查为 2026-08-04;Responses 新增检查为 2026-08-05;function calling 协议检查为 2026-08-06。没有编写测试用例。原有条目来自真实 CLI 和真实 HTTP/SDK 客户端;有限队列改动完成了类型检查、生产构建和协调器运行时冒烟检查,尚未重新运行真实 CLI 并发检查。function calling 完成了内部协议冒烟检查、Obsidian Copilot 当前依赖 `@langchain/openai 1.2.2` 的双轮 wire compatibility 检查,以及真实 Command Code 与 OpenAI Node.js SDK 的双轮 HTTP/SSE 调用;尚未在 Obsidian UI 中运行完整检查。
|
||||
检查日期:Chat Completions 原有检查为 2026-08-04;Responses 文本子集检查为 2026-08-05;Chat function calling 协议检查为 2026-08-06;Responses 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 双轮检查。
|
||||
|
||||
- TypeScript 严格类型检查和生产构建通过。
|
||||
- npm 生产依赖审计:0 个已知漏洞。
|
||||
@@ -337,6 +348,10 @@ command-code \
|
||||
- `input_image` 返回 400 `unsupported_parameter`,并包含准确的参数路径。
|
||||
- 真实 `max_turns: 1` 工具请求返回 200 `incomplete/max_turns`;1 秒总超时返回 200 `incomplete/timeout`;主动取消返回 499 `cancelled`。
|
||||
- 取消后紧接着的旧 Chat Completions 请求返回 `Chat恢复成功`,证明共享执行状态和错误恢复正常。
|
||||
- Responses 第一轮 `tool_choice: required` 返回 `function_call`,`output_text` 为空;第二轮提交 `function_call_output` 和 `previous_response_id` 后返回最终 message 文本。
|
||||
- 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 错误。
|
||||
|
||||
## 已知限制
|
||||
|
||||
@@ -344,8 +359,8 @@ command-code \
|
||||
- headless 无法在服务终端进行批准、拒绝、选项选择或文字回答;`ask_user_question` 不能由等待中的 HTTP 客户端处理。
|
||||
- 终端事件渲染由本项目完成,格式接近日志,无法等同原始 TUI。
|
||||
- 普通文本 Chat Completions 会实时转发 Command Code 文本 delta;外部 function calling 和 Responses 结构化输出需要等待 Bridge 校验完成。
|
||||
- Chat Completions 只实现 function tools,不实现图片、音频、文件输入、Computer Use 或托管工具。Responses 仍是文本子集,不实现 function calling、原生 reasoning item、加密 reasoning 或隐藏思维过程。
|
||||
- Chat function calling 是 Bridge 通过提示协议、JSON 解析、工具参数 Schema 校验和一次修复实现的兼容层;Command Code CLI 没有公开原生 function calling 输出接口,因此连续两次输出不合格时返回 HTTP 502 `invalid_tool_decision`。
|
||||
- Chat Completions 和 Responses 都只实现外部 function tools,不实现图片、音频、文件输入、Computer Use、web search 等 hosted tools 或 MCP hosted tool。非 function 工具类型返回 400 `unsupported_parameter`。Responses 不实现原生 reasoning item、加密 reasoning 或隐藏思维过程。
|
||||
- Chat 与 Responses 的外部 function calling 都是 Bridge 通过提示协议、JSON 解析、工具参数 Schema 校验和一次修复实现的兼容层;Command Code CLI 没有公开原生 function calling 输出接口,因此连续两次输出不合格时返回 HTTP 502 `invalid_tool_decision`。
|
||||
- Responses 的本地文件存储只供本 Bridge 使用,没有跨进程锁、队列或多实例一致性保证。项目本身仍严格单并发。
|
||||
- Responses Structured Outputs 是 Bridge 层约束,底层 Command Code 模型仍可能连续两次输出不合格 JSON;此时状态为 incomplete。
|
||||
- `usage` 使用 Command Code 最终结果提供的真实 input/output token;Responses 缺失时返回 `null`,Chat Completions 为兼容旧行为返回 0。
|
||||
|
||||
Reference in New Issue
Block a user