服务默认监听 http://127.0.0.1:8000,客户端不需要传入真实 OpenAI 或 Anthropic API key,但可以通过 Authorization 指定 OpenCode 上游模式。
- 无
Authorization,或Bearer public- 走 public Zen 免费模型。
/v1/models只返回免费模型,且 ID 会去掉上游-free后缀(请求时会自动映射回-free)。
Bearer <opencode-api-key>- 默认走 Zen。
- 如果请求的是仅存在于 Go 目录中的模型,代理会自动切到 Go。
Bearer zen:<opencode-api-key>- 强制走 Zen。
Bearer go:<opencode-api-key>- 优先走 Go 订阅目录。
- 对同时存在于 Zen 和 Go 的模型,也会按 Go 路径请求。
| 路由 | 方法 | 说明 |
|---|---|---|
/v1/models |
GET |
返回权限范围内的模型;-free 后缀会隐藏,已配置别名会替换对应上游模型 ID |
/v1/chat/completions |
POST |
OpenAI Chat Completions 兼容入口 |
/v1/responses |
POST |
OpenAI Responses 兼容入口 |
/v1/messages |
POST |
Anthropic Messages 兼容入口 |
/v1/messages/count_tokens |
POST |
Anthropic token 计数入口:命中 anthropic 规则时直连上游 /zen/v1/messages/count_tokens,否则本地启发式估算 |
/v1/systemone |
POST |
TypeSafe System One 协议入口(state + typed questions → structured answers),直通上游 /zen/v1/systemone;仅 jev 系列模型可用——该模型不做文本生成,无法用 Chat / Responses / Messages 任何一条协议驱动。body 除 model 外原样透传,不走协议路由/协议转换,也不套用免费层指纹重做(该门禁只作用于 chat/completions/messages/responses 三个上游子路径) |
/health |
GET |
健康检查 |
/api/config |
GET/POST |
管理面板配置接口 |
/api/stats |
GET/DELETE |
token 统计接口 |
/api/reload |
POST |
刷新 OpenCode 会话和模型列表;并发请求共享一次刷新 |
GET /v1/models 的返回会随鉴权模式变化:
public只显示免费 Zen 模型。- 默认或
zen:模式显示 Zen 目录。 go:模式显示 Go 目录,并附带 public 可用的免费模型。
三个入站协议(/v1/chat/completions、/v1/responses、/v1/messages)默认经 Chat Completions 翻译后转发上游。配置 protocol_rules 后,按模型模式把请求分流到上游原生协议端点(anthropic → /zen/v1/messages、responses → /zen/v1/responses、chat_completions → /zen/v1/chat/completions),请求/响应由网关自动在入站与上游协议间转换,流式、工具调用、推理内容与 usage 统计均兼容。未命中规则时保持既有行为。规则语法、优先级与校验见 CONFIGURATION.md。
| 入口 | 合法范围(闭区间) |
|---|---|
/v1/messages |
0..1 |
/v1/chat/completions |
0..2 |
/v1/responses |
0..2 |
- 缺省(
nil)、0、上界均合法;负数、越上界、NaN/Inf在调用上游前被拒绝,不 clamp。 - 拒绝时返回 HTTP 400,
Content-Type: application/json,形状与入口协议一致:- Claude:
{"type":"error","error":{"type":"invalid_request_error","message":...}} - Chat/Responses:
{"error":{"type":"invalid_request_error","message":...,"param":"temperature"}}
- Claude:
- 流式请求同样先返回普通 JSON 400,不会开始 SSE。
document(Anthropic)/input_file(Responses)是 best-effort file part,映射为{type:"file",file:{...}}。并非所有上游模型支持 file 模态,上游拒绝时会透传明确错误。- 在受支持位置识别为文件输入但缺少任何可用 payload(无
file_data/file_id/file_url或 document 无可用source)时返回协议形状 HTTP 400invalid_request_error,不会把 wrapper JSON 伪装成文本。
modelmessagesstreamtemperature(闭区间0..2)max_tokensmax_completion_tokens(clamped 到[128, cap];已带该字段时不再注入max_tokens,遵循 OpenAI 二者互斥约束,避免上游 400,issue #35)top_pthinkingreasoning_effortextra_bodytoolstool_choice
流式响应会原样保留合法的 usage-only 尾块(choices: [])以及完整 usage details。
- 上游 Anthropic 响应会转换 stop reason、usage、reasoning、refusal 和工具调用。
- 不同上游模型对
thinking/reasoning_effort的支持可能不同。
- 本项目未声明支持的 Chat Completions beta 字段不会被合成或伪造。
model 通常会先经过 model_alias 解析;显式使用 go: 或 zen: 且原模型存在于对应目录时,同名的 模型 -> 模型-free 兼容别名会让位于对应目录中的原模型。reasoning_effort 会按 reasoning_effort_map 转换。
- 字符串
input;含input_text/input_image的 message item;函数及内置工具的 call/output item instructions、messages(使用 Chat content 形状,非 Responsesinputitem 形状)、previous_response_id- 显式零值的
temperature(闭区间0..2)、top_p、frequency_penalty、presence_penalty max_output_tokens、stop、user、parallel_tool_calls、stream_options、store- 函数工具、项目已有的内置工具、
tool_choice、reasoning、metadata - Chat 经
protocol_rules走原生 Responses 上游时:parallel_tool_calls/service_tier透传上游;response_format(json_schema展平 /json_object透传type)映射为text.format;custom_tool_call(custom/freeform 工具)的input增量与done按同一tool_callsindex 累积;incomplete按reason细分finish_reason(max_output_tokens→length,content_filter→content_filter);上游service_tier回写 chat 顶层;response.done(Realtime/WS 别名)与completed同等终结流 - Chat 经
protocol_rules走原生 Anthropic 上游时:thinking 生效即剥离temperature/top_p(与 Claude 入站同口径,避免上游 400) - Anthropic-style
tool_result(call_id,缺省时用tool_use_id;content支持 string、字符串数组、{type:"text"|"input_text"|"output_text",text}blocks;is_error:true加Error:前缀) - 正常终态
response.completed;长度截断终态response.incomplete,reason 为max_output_tokens
- Responses 会通过 Chat Completions 上游实现;内置工具被编码为函数工具后再还原。
- 已确认只支持原生上游
/responses端点的模型(静态预置、native_responses_models配置项、运行时探测记忆)跳过 Chat 翻译,直接保真透传,上游 4xx/5xx 状态码与错误体原样返回。 唯一例外:上游因回放的 reasoningencrypted_content不属于当前发起方而 400(was not issued to this caller,通常发生在 sticky 出口/域名改绑之后)时,网关会剥掉input中 reasoning item 的id与encrypted_content后重发一次;可见对话内容不变,仅不再回放旧推理密文。详见responses-compatibility-analysis.md§9.7。 - 仅在上游实际返回 reasoning 时生成 reasoning output item。
input中的 top-level item 或 message content 可使用input_file;支持 flat 字段file_data、file_id、file_url、filename以及 nestedinput_fileobject,并映射为{type:"file",file:{...}}。模型不支持 file 模态时上游可能拒绝。
include及未在上面列出的可选 Responses 字段;这些字段不会用占位值伪装成已支持。input中受支持位置的input_file若缺少任何可用 payload,会返回 HTTP 400,不会序列化为文本。
示例:
curl http://127.0.0.1:8000/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"input": "Write one short sentence.",
"stream": false
}'Authorization: Bearer <key>与x-api-key: <key>同权;Bearer 优先。- 转发上游原生
/zen/v1/messages时,网关同时发送Authorization: Bearer <key>与 Anthropic 原生x-api-key: <key>;上游/messages以x-api-key为准。 - 有效 opencode key:
sk-前缀且长度 > 15;go:/zen:前缀路由同样适用于两种头。 - Anthropic 真 key(
sk-ant-)不会转发上游,回落 public。 - 占位短 key(如 Claude Code 默认
sk-local)因长度不足走 public。
system(顶层)与消息内role=system合并为上游唯一首条 system(\n\n拼接,顶层在前);system 为 block 数组时启发式递归计入 tokenstop_sequences、temperature(闭区间0..1)/top_p/top_k(包括显式零值);开启 thinking 时这三个参数按上游 Anthropic 语义剥离(避免 400)max_tokens:Chat/Responses 直通与翻译同样收敛[128, cap](cap 来自max_tokens_cap/max_tokens_cap_per_model);count_tokens 命中 anthropic 规则时只降不补metadata.user_id:若为 JSON 串则只转发session_id(避免device_id外泄);否则原样转发- 文本、base64/URL image、
tool_use、tool_result(包括is_error);合法的 tool result 在普通用户内容之前的顺序会被保留 tool_result中的 image 转为紧随其后的role=user+image_url,tool 文本保留字符串并标注[image attached];tool_result中的 document 同样转为紧随其后的 user file part 并标注[document attached];orphantool_use(无 matching tool_result)在翻译路径由 Worker A/B 的配对归一化处理tool_choice的auto、any、tool、none;disable_parallel_tool_use:true映射为上游parallel_tool_calls=falseoutput_config.effort→ 上游reasoning_effort;thinking.type=adaptive视为 enabled- JSON Schema 约束字段(包括
additionalParameters、format) - stop reason、usage 以及流式 content block 配对
/v1/messages/count_tokens:protocol_rules命中 anthropic 上游时直连/zen/v1/messages/count_tokens透传取精确计数;未命中、仅命中 chat/responses 或上游失败时回落本地启发式(chat 上游对 thinking 的采样参数互斥剥参同样生效)
document(source.type=base64,默认application/pdf;source.type=url)映射为 Chat content part{type:"file",file:{...}},可保留 block/title 作为filename。模型不支持 file 模态时上游可能拒绝;document 缺少可用 payload 时返回 HTTP 400。- thinking 会在没有 signature 时继续输出,以提高客户端兼容性。代理不会伪造 signature 或发送假的
signature_delta。 - 请求历史中的 thinking
signature没有 Chat Completions 等价物,会被丢弃;代理仅统计历史中非空 signature block 数量到request_plan(history_signature_count),不记录签名内容。 redacted_thinking.data是不可解释的加密数据,无法无损转成请求侧 reasoning;请求历史中的 redacted data 会被丢弃。native Anthropic 响应中明确存在的 signature / redacted data 由第二批私有 roundtrip 字段(_opencode2api_anthropic_content)保留,仅用于 Claude Messages 往返,Chat/Responses 公共 payload 不会泄漏这些私有字段。- 无 Chat Completions 等价物的字段不进上游 body,但会绑定并记入
request_plan/ body summary:context_management、cache_control、anthropic-beta、带type且无input_schema的 server tools(如web_search_*)。 cache_controlbreakpoints 现在被保留:Claude 侧的system[].cache_control、messages[].content[].cache_control、tools[].cache_control会在转换到 Chat 上游时按文本/工具名重放到对应消息/工具上(config.cache_control_breakpoints默认开启,rejectsCacheControl列表内的 GLM/Zhipu 仍跳过),同时自动附加顶层cache_controlbreakpoint;cached_tokensusage 由上游返回时映射到prompt_tokens_details.cached_tokens并累计到本地 stats。请求中的cache_control也仍然计入cache_control_blocks供诊断。
- prompt caching、context management、server tools 的真实能力
- 转发
anthropic-beta到上游
示例:
curl http://127.0.0.1:8000/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: sk-your-opencode-key" \
-d '{
"model": "gpt-4o-mini",
"max_tokens": 256,
"messages": [{"role": "user", "content": "hello"}]
}'stream: true 时服务会使用 SSE 返回,并在内部清理空 delta、空 finish reason 和不需要的 reasoning 字段。Responses 和 Anthropic 流式接口会把上游 Chat Completions chunk 转换成对应事件。