| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
将 qodercli 的模型推理能力中转为标准 API 的本地代理服务。
通过对 qodercli-1.1.5 二进制逆向(还原其 OAuth 认证与推理协议,见逆向工程), 用 Golang 实现并内嵌官方加密 WASM,对外提供三种兼容端点:
| 端点 | 协议 | 适用客户端 |
|---|---|---|
| POST /v1/messages | Anthropic Messages(SSE/非流式) | Claude Code |
| POST /v1/chat/completions | OpenAI Chat(SSE/非流式) | 任意 OpenAI 客户端 |
| POST /v1/responses | OpenAI Responses(SSE/非流式) | Codex CLI |
特性:sk 鉴权 · 15 个上游模型可切换(含 1M 上下文)· thinking/effort 映射 · 工具调用双向转换 · token 自动刷新 · 内嵌设备流登录。
仅供学习研究用途;调用的是你自己账号的额度。
# 构建(官方加密 WASM 已 go:embed,单文件分发)
cd qodercli2api && go build -o qodercli2api .
# 登录(三选一)
# ① 本机已登录过 qodercli —— 无需任何操作,自动复用 ~/.qoder/.auth
# ② 设备流登录(浏览器授权)
./qodercli2api -login
# ③ Personal Access Token
./qodercli2api -login-pat "<PAT>"
# 启动
QODER2API_SK=sk-your-secret ./qodercli2api -addr :8377验证:
curl http://127.0.0.1:8377/health # {"ok":true,"authenticated":true}
curl -X POST http://127.0.0.1:8377/v1/chat/completions \
-H "content-type: application/json" -H "Authorization: Bearer sk-your-secret" \
-d '{"model":"auto","max_tokens":64,"messages":[{"role":"user","content":"hi"}]}'export ANTHROPIC_BASE_URL=http://127.0.0.1:8377
export ANTHROPIC_AUTH_TOKEN=sk-your-secret
export ANTHROPIC_MODEL=auto # 或 kmodel_latest / ultimate / ...
claude -p "hello"codex-cli ≥0.145 仅支持 wire_api = "responses"(chat 已移除)。
# ~/.codex/config.toml
model = "auto"
model_provider = "q2a"
[model_providers.q2a]
name = "qoder2api"
base_url = "http://127.0.0.1:8377/v1"
wire_api = "responses"
env_key = "Q2A_API_KEY"Q2A_API_KEY=sk-your-secret codex exec "say hi"
codex exec -m kmodel_latest "..." # 切换模型项目级配置(已实测):codex 读取 <项目根>/.codex/config.toml,但有信任门槛—— 未信任项目的配置被静默忽略。需在用户配置中声明信任(项目配置里写 trust_level 无效):
# ~/.codex/config.toml
[projects."/abs/path/to/project"]
trust_level = "trusted"# <项目根>/.codex/config.toml —— 本项目专用设置
model = "kmodel_latest"
model_provider = "q2a"
[model_providers.q2a]
name = "qoder2api"
base_url = "http://127.0.0.1:8377/v1"
wire_api = "responses"
env_key = "Q2A_API_KEY"层级:session(-c) > project(cwd 到 repo root 可有多层,深优先) > user > system。
# Anthropic 流式
curl -N -X POST http://127.0.0.1:8377/v1/messages \
-H "content-type: application/json" -H "x-api-key: sk-your-secret" \
-d '{"model":"auto","max_tokens":256,"stream":true,"messages":[{"role":"user","content":"hi"}]}'
# Anthropic thinking/effort
... -d '{"model":"auto","max_tokens":2048,"thinking":{"type":"enabled","budget_tokens":8192},"messages":[...]}'
# OpenAI Chat 流式(上游 chunk 直通 + [DONE])
curl -N -X POST http://127.0.0.1:8377/v1/chat/completions \
-H "content-type: application/json" -H "Authorization: Bearer sk-your-secret" \
-d '{"model":"auto","stream":true,"messages":[{"role":"user","content":"hi"}]}'
# OpenAI Responses 流式
curl -N -X POST http://127.0.0.1:8377/v1/responses \
-H "content-type: application/json" -H "Authorization: Bearer sk-your-secret" \
-d '{"model":"auto","stream":true,"input":"hi","reasoning":{"effort":"medium"}}'鉴权:客户端需带 x-api-key: <sk> 或 Authorization: Bearer <sk>,缺失/错误返回 401。
| flag | 环境变量 | 默认 | 说明 |
|---|---|---|---|
| -addr | QODER2API_ADDR | :8377 | 监听地址 |
| -sk | QODER2API_SK | 空 | 客户端 sk 密钥;为空关闭鉴权(打印警告) |
| -auth-dir | QODER2API_AUTH_DIR | ~/.qoder/.auth | 凭证目录 |
| -endpoint | QODER2API_INFER_ENDPOINT | https://api2.qoder.sh | 推理端点 |
| -openapi-endpoint | QODER2API_OPENAPI_ENDPOINT | https://openapi.qoder.sh | OpenAPI 端点 |
| -web-endpoint | QODER2API_WEB_ENDPOINT | https://qoder.com | 设备流授权页端点 |
| -model-map | QODER2API_MODEL_MAP | 空 | JSON 映射 {"claude-sonnet-4-5":"auto","*":"auto"} |
| -default-model | QODER2API_DEFAULT_MODEL | auto | 兜底模型 key |
| -model-1m | QODER2API_MODEL_1M | ultimate | [1m] 后缀请求的 1M 模型 key |
| -catalog | QODER2API_CATALOG | 自动 | 模型目录 JSON(默认自动解密 CLI 缓存) |
| -login | — | — | 设备流登录后退出 |
| -login-pat | — | — | PAT 登录后退出 |
| -v | QODER2API_LOG=debug | off | 详细日志 |
| 端点 | 说明 |
|---|---|
| POST /v1/messages | Anthropic Messages(SSE/非流式) |
| POST /v1/messages/count_tokens | 粗估 token(Claude Code 压缩上下文用) |
| POST /v1/chat/completions | OpenAI Chat(SSE/非流式/工具调用/reasoning_effort) |
| POST /v1/responses | OpenAI Responses(SSE/非流式,Codex 适用) |
| GET /v1/models | 模型列表 |
| GET /health | 健康检查 |
本机存在 qodercli2api.service(~/.config/systemd/user/,Restart=always), 环境文件 qodercli2api.env,重新构建二进制后 systemctl --user restart qodercli2api 即可生效。
| key | 名称 | 推理 | 视觉 | 上下文 |
|---|---|---|---|---|
| auto | Auto(默认) | - | ✓ | 180k |
| ultimate | Ultimate | ✓ | ✓ | 1M |
| performance | Performance | - | ✓ | 1M |
| efficient | Efficient | - | ✓ | 180k |
| lite | Lite | - | ✗ | 180k |
| cmodel | Cantus | ✓ | ✓ | 1M |
| qmodel_38max | Qwen3.8-Max | ✓ | ✓ | 1M |
| qmodel_latest | Qwen3.7-Max | - | ✓ | 1M |
| qmodel | Qwen3.7-Plus | - | ✓ | 1M |
| kmodel_latest | Kimi-K3 | - | ✓ | 1M |
| kmodel | Kimi-K2.7-Code | - | ✓ | 256k |
| gm51model | GLM-5.2 | ✓ | ✓ | 1M |
| dmodel | DeepSeek-V4-Pro | ✓ | ✓ | 1M |
| dfmodel | DeepSeek-V4-Flash | ✓ | ✓ | 1M |
| mmodel | MiniMax-M3 | - | ✓ | 1M |
模型选择优先级:-model-map 精确匹配 > 客户端 model 即 qoder key > [1m] 后缀处理 > -default-model 兜底。
| 客户端参数 | 上游 |
|---|---|
| Anthropic thinking.budget_tokens | 按官方 CHL 映射为 reasoning_effort:≤0→none, ≤1024→low, ≤8192→medium, ≤24576→high, ≤49152→xhigh, >49152→max |
| OpenAI reasoning_effort | 直接透传(minimal→low) |
| Responses reasoning.effort | 直接透传 |
上游的思考增量(reasoning_content)→ Anthropic thinking block / Responses reasoning item / Chat 非流式按 deepseek 风格 reasoning_content 字段返回。
需要客户端与代理两侧配合:
代理侧(已实现)
Claude Code 侧:ANTHROPIC_MODEL=auto[1m]([1m] 后缀即其 1M 窗口约定)
Codex 侧(config.toml,已实测):
model = "ultimate"
model_context_window = 1000000
model_auto_compact_token_limit = 900000 # 可选,自动压缩阈值Claude Code / Codex / 任意客户端
│ Anthropic / OpenAI Chat / OpenAI Responses
▼
qodercli2api
├── sk 鉴权中间件
├── 客户端请求 → RemoteChatAsk 转换
├── wazero 内嵌官方 WASM:prepareInferRequest(URL / 22 个签名头 / 加密 body)
├── token 自动刷新(提前 1h + 401 重试 + 30min 定时)
└── 上游 SSE 信封解析 → 客户端协议事件序列
▼
https://api2.qoder.sh(生产推理端点)
| 客户端 | 上游(RemoteChatAsk) |
|---|---|
| model | model_config.key(映射/[1m]/兜底,见 §4.1) |
| system / instructions | 顶层 system 字符串 |
| 文本/图片消息 | OpenAI 消息(image→image_url data:URL) |
| tool_use / function_call | tool_calls[{id,type:function,function:{name,arguments}}] |
| tool_result / function_call_output | role:"tool" + tool_call_id |
| tools | OpenAI function 格式(input_schema→parameters) |
| thinking / effort | parameters.reasoning_effort(见 §4.2) |
| tool_choice | parameters.tool_choice(auto/any→required/none/tool) |
| max_tokens 等 | parameters.{max_tokens,context_length,temperature,top_p,stop} |
| 上游 chunk | Anthropic | OpenAI Chat | OpenAI Responses |
|---|---|---|---|
| delta.reasoning_content | thinking block | (直通) | reasoning item + summary delta |
| delta.content | text block + text_delta | (直通) | message item + output_text.delta |
| delta.tool_calls | tool_use block | (直通) | function_call item + args delta |
| finish_reason+usage | message_delta+message_stop | 末帧+[DONE] | response.completed(含 usage) |
| 信封 statusCodeValue≠200 | error 事件 | error data+[DONE] | response.failed |
stop 映射:stop→end_turn, tool_calls→tool_use, length→max_tokens, content_filter→refusal。
完整细节:docs/oauth.md、docs/inference-protocol.md。此处为摘要。
| 问题 | 答案 |
|---|---|
| OAuth 机制 | 自定义设备授权流:浏览器开 qoder.com/device/selectAccounts(PKCE 风格 challenge),每秒轮询 openapi.qoder.sh/api/v1/deviceToken/poll 换 device token;凭证 WASM 加密存于 ~/.qoder/.auth/user |
| 推理调用 | POST api2.qoder.sh/algo/api/v2/service/pro/sse/agent_chat_generation,22 个 Cosy-* 头 + Bearer COSY.<base64>.<签名>,请求体 WASM 加密;响应明文 SSE(信封包裹 OpenAI chunk) |
| 加密/签名 | 内嵌 Rust→WASM 模块 qoder_auth_wasm_bg.wasm(297KB),不可绕过,本项目用 wazero 复用 |
qodercli-1.1.5(133MB ELF,未 strip)不是 Go 程序,而是 Bun 1.3.14 打包的 Node.js 单文件可执行程序 (napi_* 符号 + bun/node_modules 字符串)。完整 JS bundle(16.9MB minified)以明文内嵌, 可直接 carve(产物 re/extracted/bundle.js);bundle 内 base64 解码出 4 个模块:
| 文件 | 大小 | 内容 |
|---|---|---|
| re/extracted/wasm_0.wasm | 297KB | qoder_auth_wasm(认证/加密核心) |
| (ELF) | 652KB | 原生 addon |
| re/extracted/wasm_2.wasm | 205KB | tree-sitter |
| re/extracted/wasm_3.wasm | 1.38MB | tree-sitter-bash |
WASM 导出(wasm-bindgen ABI):qodercontext_new / qodercontext_prepareInferRequest(推理打包)/ prepareRequest(通用打包)/ credential_storage_encrypt|decrypt(凭证)/ generate_runtime_auth_fields(运行时签名字段)/ model_cache_decrypt(目录)/ decrypt_server_response。
分析方法(本项目原创):Python + wasmtime 手写完整 wasm-bindgen host glue (堆从 index 1028 起、free-list、IEA(ptr,len) 内存视图、getRandomValues 直写内存等), 直接驱动真实 WASM——解密本机凭证、观察 22 个请求头与加密 body、 并用生成的 headers/body 对生产端点 curl 验证成功。代码见 re/wasm_harness.py; Go 侧在 wasm.go 用 wazero 实现同等 glue。
| 测试 | 结果 |
|---|---|
| WASM harness 解密 ~/.qoder/.auth/user | ✅ 拿到完整 UserInfo |
| WASM 生成请求 + curl 直打生产推理端点 | ✅ SSE 流(text/reasoning/tool_calls/usage/event:finish) |
| 相同 request_id 重放 | ✅ 403 {"code":"103","message":"Duplicate request"} |
| Anthropic 非流式 / 流式事件序列 | ✅ thinking+text blocks、message_start→…→message_stop、usage 正确 |
| 无 sk / 错 sk | ✅ 401 authentication_error |
| 工具调用(非流式+流式+多轮回传) | ✅ tool_use blocks、stop_reason=tool_use |
| thinking budget → reasoning_effort | ✅ 上游返回 reasoning_content 并转为 thinking block |
| Claude Code 对话 / Bash 工具回合 / 模型切换 | ✅ PROXY_OK / 正确执行 / 自述 Kimi |
| Chat 非流式/流式/工具调用 | ✅ OpenAI 格式 + usage + [DONE] |
| Responses 流式事件序列 | ✅ created→item.added→delta→done→completed 完整 |
| Codex exec 对话 / shell 工具回合 / 模型切换 | ✅ CODEX_RESP_OK / 正确执行 / 自述 Kimi |
| [1m] 后缀路由(auto[1m]、ultimate[1m]) | ✅ 正常返回 |
| Codex 1M 配置(model_context_window=1000000) | ✅ CTX1M_OK |
| Codex 项目级配置 + 信任门槛 | ✅ 未信任被忽略;用户配置声明信任后生效 |
qodercli2api/ ├── qodercli-1.1.5 # 逆向目标二进制(Bun 单文件) ├── main.go # 入口/flags/启动/目录加载/PAT登录 ├── wasm.go # wazero host glue + QoderContext API(★核心) ├── auth.go # 凭证读写/刷新/设备流登录 ├── convert.go # Anthropic ↔ RemoteChatAsk 类型转换 ├── proxy.go # Anthropic handlers + SSE 解析 + 模型解析 ├── openai.go # /v1/chat/completions(OpenAI 直通转换) ├── responses.go # /v1/responses(Responses API 转换) ├── go.mod / go.sum # 依赖:仅 wazero + x/sys ├── assets/ │ └── qoder_auth_wasm_bg.wasm # qoder_auth_wasm(go:embed 进二进制) ├── docs/ │ ├── oauth.md # OAuth 机制完整逆向文档 │ └── inference-protocol.md # 推理协议完整逆向文档 ├── re/ │ ├── extracted/ # carve 产物(bundle.js / wasm,gitignore 可再生) │ ├── wasm_harness.py # Python+wasmtime 分析 harness(可独立复用) │ ├── q2a-settings.json # Claude Code 隔离 settings 示例 │ ├── codex-home/config.toml # Codex 配置示例 │ └── secrets/ # 本地凭证/抓包(gitignore,勿提交) └── README.md # 本文件
| Back | FazBrowse Home | New Git URL |