Skip to content

Releases: jcleng/opencode-free-provider

v1.0.3 — 修复 429(Bun 运行时 + <env> 块)并新增 API_KEY

Choose a tag to compare

@jcleng jcleng released this 29 Oct 08:21

更新内容

1. 修复 429 FreeUsageLimitError(免费层的第二道门)

问题现象:所有请求都返回

429 {"type":"error","error":{"type":"FreeUsageLimitError",
     "message":"Free usage limit reached. Free models work in OpenCode …"}}

根因不是 IP 限流。实测(同一 IP、同一时间段、同一份请求字节)定位到第二道客户端门:

  • 运行时 TLS 指纹:同一请求经本地 TLS 终结隧道转发,Bun 的 TLS 发出 → 200,Node/OpenSSL 发出 → 429;调整 Node 的 ciphers/ecdhCurve/sigalgs/ALPN/TLS1.2-vs-1.3 均无效;换其它出口 IP 同样 429。
  • system prompt 指纹:给任意 system prompt 追加 OpenCode 的 <env> 块 → 200;删掉或截断 → 回到 429(请求头与该门无关)。

修复:

  • 镜像改用 Bun(oven/bun:1.4.4,CMD ["bun","server.js"]),npm start / scripts/deploy.sh 同样使用 Bun;node server.js 仍可启动但会打印警告(客户端门必然 429)。
  • 新增 injectOpencodeSystemEnv() / opencodeEnvBlock()(src/conversions.js),在 finalizeBody() 中为 system prompt 追加 OpenCode 的 <env> 块:保留 agent 原有指令、幂等(真实 OpenCode 已带 <env> 时不重复注入)、初始请求与每个 follow-up turn 全覆盖。
  • src/routes.js 读取 x-opencode-directory(回退 OPENCODE_ENV_CWD)填入块内目录;OPENCODE_SYSTEM_FP=0 可关闭注入。
  • 上游端点统一为 https://opencode.ai/inference/openai/v1;429 错误文案改为真实原因(不再误导为 “per-IP 配额”)。

2. 新增 API_KEY(客户端 → 代理鉴权)

  • Dockerfile 新增 ENV API_KEY=public:
    • -e API_KEY=<secret> 覆盖为私有密钥;
    • -e API_KEY=(空值)关闭客户端鉴权;
    • 默认 public 保持历史配置 "apiKey": "public" 继续可用。
  • 新增 src/auth.js:接受 Authorization: Bearer <API_KEY>(OpenAI 客户端标准写法)与 x-api-key,使用 timing-safe 比较。
  • 鉴权失败返回 401 {"error":{"code":"invalid_api_key",…}} + WWW-Authenticate: Bearer;CORS 允许 x-api-key。
  • 保护范围:/v1/* 与 /__*(调试端点会暴露 session id);/、/health、/v1 保持公开。GET /__session 返回 auth.required。

客户端把同一个值填到 provider 的 apiKey:

"opencode-zen-server": {
  "baseUrl": "http://<host>:48391/v1",
  "api": "openai-completions",
  "apiKey": "<API_KEY>",
  "models": [
    { "id": "big-pickle", "contextWindow": 200000 }
  ]
}
docker run -d --name opencode-free-provider --restart unless-stopped \
  -p 48391:8791 -e API_KEY='sk-ofp-<your-secret>' \
  ghcr.nju.edu.cn/jcleng/opencode-free-provider:latest

3. 其它

  • 单元测试 66 → 72 个(新增 <env> 块注入、鉴权/401/公开路径等用例),全部通过。
  • README.md / agents.md 记录「两道门」(403 = 头/会话/工具;429 = 运行时 + system prompt)、API_KEY 用法与排障映射。

镜像:ghcr.io/jcleng/opencode-free-provider:latest(Dockerfile 运行时为 Bun 1.4.4)

完整变更:8bcda41...v1.0.3

v1.0.2

Choose a tag to compare

@jcleng jcleng released this 15 Oct 12:38

opencode-free-provider v1.0.2

热修复版本:将免费档上游默认端点从已失效的 /zen/v1 切换为 OpenCode 官方客户端实际使用的 /inference/v1。

本版本重点:解决升级前必然出现的 403 FreeTierError: OpenCode's free tier can only be used from within OpenCode。

修复

  • Fix: OPENCODE_BASE_OVERRIDE /inference/v1 (e987934)
    • src/config.js 的 getOpencodeBase() 默认值由 https://opencode.ai/zen/v1 改为 https://opencode.ai/inference/v1。

背景

/zen/v1 路由已被 OpenCode 停止服务——对免费档请求一律返回 403 FreeTierError。OpenCode 自有客户端实际请求的端点是 https://opencode.ai/inference/v1(可从 https://models.opencode.ai/api.json 确认)。本版本让代理默认打到该端点,与官方客户端行为一致。

指纹机制(纯 JS 生成 x-opencode-session,无需 opencode CLI / MITM)与 v1.0.1 相同,未改动。

升级

# Docker(推荐,ghcr.io 最新镜像已含本修复)
docker pull ghcr.io/jcleng/opencode-free-provider:latest
docker run -d --name opencode-free-provider -p 8791:8791 \
  ghcr.io/jcleng/opencode-free-provider:latest

# 旧镜像(默认 /zen/v1,会 403)不必重拉,也可用环境变量强制指向可用端点:
docker run -d --name opencode-free-provider -p 8791:8791 \
  -e OPENCODE_BASE_OVERRIDE='https://opencode.ai/inference/v1' \
  opencode-free-provider

Agent 配置不变:

baseURL: http://127.0.0.1:8791/v1
apiKey:  public
model:   opencode-free/big-pickle

验证

  • 50 个单元测试全部通过(mock upstream,无网络)。
  • GitHub Actions 构建 ghcr.io/jcleng/opencode-free-provider:latest 成功(run 38733861667)。

完整变更:v1.0.1...v1.0.2

v1.0.1

Choose a tag to compare

@jcleng jcleng released this 13 Oct 12:12

opencode-free-provider v1.0.1

本地 OpenAI 兼容代理,将聊天请求转发到 OpenCode Zen 免费档,无需 API key 即可使用 big-pickle 等免费模型。

本版本重点:指纹改为纯 JS 生成,不再需要安装 / 运行真实的 opencode CLI。 Docker 镜像从约 2.4GB 降到约 245MB。

核心特性

纯 JS 指纹(推翻 v1.0.0 的「无法伪造」结论)

v1.0.0 认为免费档的 x-opencode-session 有服务端校验和、无法伪造,因此必须 spawn 真实 opencode 并用 MITM 拦截抓取。该结论已证伪。

经反编译 opencode 源码 + 对真实端点做逐位 ablation 实测,确认该 id 就是 opencode 普通的 descending 标识符:

ses_ + 12 位小写 hex + 14 位 base62      // 共 30 字符
hex = ~(Date.now() * 0x1000 + counter) 的 48 位

服务端实际只校验:

  • 低 12 bit 编码的计数器 0xfff - counter 必须 counter ≤ 63(64+ → 403);
  • 前 12 位必须为小写 hex;tail 必须恰好 14 位;
  • 时间戳大小 / 新旧不校验(高 36 bit 随便填);
  • x-opencode-session-id 若存在须等于 x-opencode-session。

没有任何校验和。 本版本在 src/fingerprint.js 里直接复刻该算法(counter 超过 63 自动进位到下一毫秒),因此:

  • 不再 spawn opencode,不再 MITM/TLS 拦截,不再需要 openssl 与一次性 CA;
  • 每个请求都生成一个全新合法的 ses_...(默认 ZEN_SESSION_MODE=per-request);
  • 相关文件:src/fingerprint.js(encodeIdentifier() / newSessionId() / newMessageId() / buildFingerprintHeaders()),/__session 暴露 fingerprint.source == "generated"。

Docker 不再需要装 opencode

指纹改为纯 JS 后,镜像不再安装 @opencode/cli(约 200MB 原生二进制)与 openssl:

  • 体积从约 2.4GB → 约 245MB;
  • 基础镜像仍为 node:24-bookworm-slim(Node ≥ 24 才有 NODE_USE_ENV_PROXY)。

模型列表从上游动态发现

GET /v1/models 会实时请求上游 /models,只保留 id 含 big-pickle 或 -free 的模型,并带 TTL 缓存(ZEN_MODELS_TTL_SECONDS,默认 600s),失败时回退到上次良好列表 / 内置 big-pickle。

使用方法

# 本地
npm start            # http://127.0.0.1:8791/v1

# Docker
docker build -t opencode-free-provider .
docker run -d --name opencode-free-provider -p 8791:8791 opencode-free-provider

Agent 配置:

baseURL: http://127.0.0.1:8791/v1
apiKey:  public
model:   opencode-free/big-pickle

验证指纹为纯 JS 生成:

curl http://127.0.0.1:8791/__session        # 期望 fingerprint.source == "generated"

环境变量

变量 默认 说明
ZEN_SESSION_MODE per-request per-request(每次请求新 ses_)或 sticky(进程内复用)
ZEN_SESSION_ROTATE_SECONDS 0 sticky 模式下每隔 N 秒轮换 session
OPENCODE_UA opencode/latest/2.0.22/cli 发给 gate 的 User-Agent
ZEN_MODELS_TTL_SECONDS 600 模型列表缓存时长(秒)
ZEN_MODELS_TIMEOUT_MS 5000 上游 /models 发现超时(毫秒)
NODE_IMAGE node:24-bookworm-slim 仅构建时:Docker 基础镜像

已移除:OPENCODE_FP_DISABLE / OPENCODE_FP_TTL_MS / OPENCODE_FP_TIMEOUT_MS / OPENCODE_VERSION(不再有 CLI 抓取)。

验证

  • 50 个单元测试全部通过(mock upstream,无网络)。
  • 真实端点:纯 JS 生成的指纹直接 POST opencode.ai/zen/v1/chat/completions → HTTP 200。
  • 本地代理端到端:fingerprint.source == "generated",非流式与流式(以 [DONE] 收尾)均正常。
  • 拉取 Actions 构建的镜像实测:容器内同样是 generated,端到端 HTTP 200。
  • GitHub Actions 已成功构建并推送镜像到 ghcr.io/jcleng/opencode-free-provider:latest。

注意

  • 客户端若有 ALL_PROXY(如 socks5://127.0.0.1:20170),curl 会把 localhost 请求也走代理导致空响应,请用 curl --noproxy '*' 测试;Node 的 fetch 默认不读 ALL_PROXY,代理服务端不受影响。

变更

  • feat(fingerprint): generate the OpenCode free-tier fingerprint in pure JS (drop CLI/MITM) (285498c)

完整变更:v1.0.0...v1.0.1

v1.0.0

Choose a tag to compare

@jcleng jcleng released this 13 Oct 07:14

opencode-free-provider v1.0.0

本地 OpenAI 兼容代理,将聊天请求转发到 OpenCode Zen 免费档,无需 API key 即可使用 big-pickle 等免费模型。

核心特性

动态指纹(绕过免费档 client-fingerprint gate)

OpenCode 免费档服务端会校验请求指纹,其中 x-opencode-session 的 id 结构/校验和由服务端验证,无法伪造——只有真正的 opencode 二进制生成的 ses_... 才通过。

本版本改为:每次需要时 spawn 真实的 opencode 命令,通过本地 MITM/TLS 拦截代理捕获它真正发往 opencode.ai 的请求的 fingerprint headers(user-agent、x-opencode-session、x-opencode-client、x-opencode-project 等),并缓存复用(OPENCODE_FP_TTL_MS,默认 30 分钟)。

  • 相关文件:src/fingerprint.js(getFingerprint() / fingerprintHeaders()),server.js 启动预热,/__session 暴露 fingerprint.source(opencode-cli = 实时抓到;fallback* = 静态回退)。
  • 若 opencode 不可用或设 OPENCODE_FP_DISABLE=1,回退到内置静态指纹,保证代理仍能启动。

Docker 镜像必须安装 opencode

修正了原 Dockerfile 的问题(基于 node:24-alpine 且根本没装 opencode,容器内 opencode: not found):

  • 基础镜像 node:24-alpine(musl)→ node:24-bookworm-slim(glibc):opencode 是 Bun 编译的原生 ELF,链接 glibc,Alpine 跑不了。
  • npm install -g @opencode/cli@2.0.22(可用 OPENCODE_VERSION build-arg 升级)。
  • 安装 openssl(生成 MITM CA 用)。
  • 支持 NODE_IMAGE build-arg 指向私有镜像源。

使用方法

# 本地
npm start            # http://127.0.0.1:8791/v1

# Docker
docker build -t opencode-free-provider .
docker run -d --name opencode-free-provider -p 8791:8791 opencode-free-provider

Agent 配置:

baseURL: http://127.0.0.1:8791/v1
apiKey:  public
model:   opencode-free/big-pickle

验证指纹已动态获取:

curl http://127.0.0.1:8791/__session        # 期望 fingerprint.source == "opencode-cli"
docker exec opencode-free-provider opencode --version

环境变量

变量 默认 说明
OPENCODE_FP_DISABLE 未设 设 1 跳过 spawn,用静态回退指纹
OPENCODE_FP_TTL_MS 1800000 抓到的指纹缓存时长(毫秒)
OPENCODE_FP_TIMEOUT_MS 15000 spawn / MITM 抓取超时(毫秒)
OPENCODE_VERSION 2.0.22 仅构建时:Docker 内 opencode 版本
NODE_IMAGE node:24-bookworm-slim 仅构建时:Docker 基础镜像

验证

  • 47 个单元测试全部通过。
  • 本地端到端:真实动态指纹成功绕过验证,HTTP 200 且返回真实模型回复。
  • GitHub Actions 已成功构建并推送镜像到 ghcr.io/jcleng/opencode-free-provider:latest。

注意

  • 客户端若有 ALL_PROXY(如 socks5://127.0.0.1:20170),curl 会把 localhost 请求也走代理导致空响应,请用 curl --noproxy '*' 测试;Node 的 fetch 默认不读 ALL_PROXY,代理服务端不受影响。
  • 新镜像体积比旧的 Alpine 版大(含完整 opencode CLI 原生二进制,约 200MB)。