dwgx/WindsurfAPIPublic

Turn Windsurf / Devin Desktop's 100+ AI models (Claude, GPT, Gemini, DeepSeek, Kimi, GLM, SWE) into OpenAI-, Anthropic- & Gemini-compatible APIs. Zero-dependency self-hosted reverse proxy for Claude Code, Cline & Cursor. 把 Windsurf/Devin 云端 100+ 模型变成三套兼容 API。

AI summary: A zero-dependency translation layer that converts Windsurf and Devin AI models into standard API formats.

Stars
2.9K
Forks
609
Watchers
14
Open issues
2
Open PRs
1
Contributors
~23
Commits
889
Branches
3

JavaScriptMITCreated Apr 9, 2026Last push 1d agoLatest release v3.9.4+7 stars this week+11 this month

Star history

since Apr 12, 2026
01K2KApr 2026May 2026Jun 2026Aug 2026
2.9K stars as of Aug 7, 2026, tracked back to Apr 12, 2026. Historical curve reconstructed from public GitHub event archives, calibrated to the current total.

Contribution activity

commits per day, last 52 weeks
AugSepOctNovDecJanFebMarAprMayJunJulMonWedFri2025-08-03: 0 commits2025-08-04: 0 commits2025-08-05: 0 commits2025-08-06: 0 commits2025-08-07: 0 commits2025-08-08: 0 commits2025-08-09: 0 commits2025-08-10: 0 commits2025-08-11: 0 commits2025-08-12: 0 commits2025-08-13: 0 commits2025-08-14: 0 commits2025-08-15: 0 commits2025-08-16: 0 commits2025-08-17: 0 commits2025-08-18: 0 commits2025-08-19: 0 commits2025-08-20: 0 commits2025-08-21: 0 commits2025-08-22: 0 commits2025-08-23: 0 commits2025-08-24: 0 commits2025-08-25: 0 commits2025-08-26: 0 commits2025-08-27: 0 commits2025-08-28: 0 commits2025-08-29: 0 commits2025-08-30: 0 commits2025-08-31: 0 commits2025-09-01: 0 commits2025-09-02: 0 commits2025-09-03: 0 commits2025-09-04: 0 commits2025-09-05: 0 commits2025-09-06: 0 commits2025-09-07: 0 commits2025-09-08: 0 commits2025-09-09: 0 commits2025-09-10: 0 commits2025-09-11: 0 commits2025-09-12: 0 commits2025-09-13: 0 commits2025-09-14: 0 commits2025-09-15: 0 commits2025-09-16: 0 commits2025-09-17: 0 commits2025-09-18: 0 commits2025-09-19: 0 commits2025-09-20: 0 commits2025-09-21: 0 commits2025-09-22: 0 commits2025-09-23: 0 commits2025-09-24: 0 commits2025-09-25: 0 commits2025-09-26: 0 commits2025-09-27: 0 commits2025-09-28: 0 commits2025-09-29: 0 commits2025-09-30: 0 commits2025-10-01: 0 commits2025-10-02: 0 commits2025-10-03: 0 commits2025-10-04: 0 commits2025-10-05: 0 commits2025-10-06: 0 commits2025-10-07: 0 commits2025-10-08: 0 commits2025-10-09: 0 commits2025-10-10: 0 commits2025-10-11: 0 commits2025-10-12: 0 commits2025-10-13: 0 commits2025-10-14: 0 commits2025-10-15: 0 commits2025-10-16: 0 commits2025-10-17: 0 commits2025-10-18: 0 commits2025-10-19: 0 commits2025-10-20: 0 commits2025-10-21: 0 commits2025-10-22: 0 commits2025-10-23: 0 commits2025-10-24: 0 commits2025-10-25: 0 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 0 commits2025-10-29: 0 commits2025-10-30: 0 commits2025-10-31: 0 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 0 commits2025-11-05: 0 commits2025-11-06: 0 commits2025-11-07: 0 commits2025-11-08: 0 commits2025-11-09: 0 commits2025-11-10: 0 commits2025-11-11: 0 commits2025-11-12: 0 commits2025-11-13: 0 commits2025-11-14: 0 commits2025-11-15: 0 commits2025-11-16: 0 commits2025-11-17: 0 commits2025-11-18: 0 commits2025-11-19: 0 commits2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 0 commits2025-11-26: 0 commits2025-11-27: 0 commits2025-11-28: 0 commits2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 0 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 0 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 0 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 0 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 0 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 0 commits2026-01-15: 0 commits2026-01-16: 0 commits2026-01-17: 0 commits2026-01-18: 0 commits2026-01-19: 0 commits2026-01-20: 0 commits2026-01-21: 0 commits2026-01-22: 0 commits2026-01-23: 0 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 0 commits2026-01-27: 0 commits2026-01-28: 0 commits2026-01-29: 0 commits2026-01-30: 0 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 0 commits2026-02-03: 0 commits2026-02-04: 0 commits2026-02-05: 0 commits2026-02-06: 0 commits2026-02-07: 0 commits2026-02-08: 0 commits2026-02-09: 0 commits2026-02-10: 0 commits2026-02-11: 0 commits2026-02-12: 0 commits2026-02-13: 0 commits2026-02-14: 0 commits2026-02-15: 0 commits2026-02-16: 0 commits2026-02-17: 0 commits2026-02-18: 0 commits2026-02-19: 0 commits2026-02-20: 0 commits2026-02-21: 0 commits2026-02-22: 0 commits2026-02-23: 0 commits2026-02-24: 0 commits2026-02-25: 0 commits2026-02-26: 0 commits2026-02-27: 0 commits2026-02-28: 0 commits2026-03-01: 0 commits2026-03-02: 0 commits2026-03-03: 0 commits2026-03-04: 0 commits2026-03-05: 0 commits2026-03-06: 0 commits2026-03-07: 0 commits2026-03-08: 0 commits2026-03-09: 0 commits2026-03-10: 0 commits2026-03-11: 0 commits2026-03-12: 0 commits2026-03-13: 0 commits2026-03-14: 0 commits2026-03-15: 0 commits2026-03-16: 0 commits2026-03-17: 0 commits2026-03-18: 0 commits2026-03-19: 0 commits2026-03-20: 0 commits2026-03-21: 0 commits2026-03-22: 0 commits2026-03-23: 0 commits2026-03-24: 0 commits2026-03-25: 0 commits2026-03-26: 0 commits2026-03-27: 0 commits2026-03-28: 0 commits2026-03-29: 0 commits2026-03-30: 0 commits2026-03-31: 0 commits2026-04-01: 0 commits2026-04-02: 0 commits2026-04-03: 0 commits2026-04-04: 0 commits2026-04-05: 0 commits2026-04-06: 0 commits2026-04-07: 0 commits2026-04-08: 0 commits2026-04-09: 6 commits2026-04-10: 4 commits2026-04-11: 0 commits2026-04-12: 5 commits2026-04-13: 0 commits2026-04-14: 1 commit2026-04-15: 2 commits2026-04-16: 2 commits2026-04-17: 1 commit2026-04-18: 2 commits2026-04-19: 0 commits2026-04-20: 16 commits2026-04-21: 37 commits2026-04-22: 22 commits2026-04-23: 50 commits2026-04-24: 49 commits2026-04-25: 14 commits2026-04-26: 30 commits2026-04-27: 22 commits2026-04-28: 13 commits2026-04-29: 24 commits2026-04-30: 16 commits2026-05-01: 5 commits2026-05-02: 18 commits2026-05-03: 20 commits2026-05-04: 7 commits2026-05-05: 1 commit2026-05-06: 1 commit2026-05-07: 9 commits2026-05-08: 7 commits2026-05-09: 1 commit2026-05-10: 4 commits2026-05-11: 0 commits2026-05-12: 5 commits2026-05-13: 2 commits2026-05-14: 0 commits2026-05-15: 0 commits2026-05-16: 0 commits2026-05-17: 0 commits2026-05-18: 0 commits2026-05-19: 0 commits2026-05-20: 0 commits2026-05-21: 0 commits2026-05-22: 4 commits2026-05-23: 0 commits2026-05-24: 0 commits2026-05-25: 11 commits2026-05-26: 1 commit2026-05-27: 0 commits2026-05-28: 0 commits2026-05-29: 2 commits2026-05-30: 0 commits2026-05-31: 0 commits2026-06-01: 0 commits2026-06-02: 0 commits2026-06-03: 3 commits2026-06-04: 0 commits2026-06-05: 30 commits2026-06-06: 18 commits2026-06-07: 13 commits2026-06-08: 2 commits2026-06-09: 0 commits2026-06-10: 2 commits2026-06-11: 0 commits2026-06-12: 0 commits2026-06-13: 4 commits2026-06-14: 0 commits2026-06-15: 0 commits2026-06-16: 0 commits2026-06-17: 1 commit2026-06-18: 1 commit2026-06-19: 0 commits2026-06-20: 0 commits2026-06-21: 0 commits2026-06-22: 1 commit2026-06-23: 11 commits2026-06-24: 0 commits2026-06-25: 0 commits2026-06-26: 0 commits2026-06-27: 0 commits2026-06-28: 0 commits2026-06-29: 26 commits2026-06-30: 27 commits2026-07-01: 0 commits2026-07-02: 0 commits2026-07-03: 8 commits2026-07-04: 23 commits2026-07-05: 7 commits2026-07-06: 3 commits2026-07-07: 15 commits2026-07-08: 34 commits2026-07-09: 27 commits2026-07-10: 10 commits2026-07-11: 22 commits2026-07-12: 25 commits2026-07-13: 25 commits2026-07-14: 2 commits2026-07-15: 15 commits2026-07-16: 4 commits2026-07-17: 4 commits2026-07-18: 0 commits2026-07-19: 0 commits2026-07-20: 0 commits2026-07-21: 0 commits2026-07-22: 0 commits2026-07-23: 0 commits2026-07-24: 10 commits2026-07-25: 14 commits2026-07-26: 7 commits2026-07-27: 25 commits2026-07-28: 18 commits2026-07-29: 3 commits2026-07-30: 0 commits2026-07-31: 0 commits2026-08-01: 0 commits
854 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Very active

    854 commits in 52 weeks

  • Well documented

    High community health score

  • Permissive license

    MIT

  • Continuous integration

    Automated checks passing

What WindsurfAPI does

WindsurfAPI is a lightweight utility that acts as a translation layer for over 100 different AI models available through platforms like Windsurf and Devin. It takes the proprietary interfaces of these platforms and exposes them as standard OpenAI, Anthropic, or Gemini APIs. This allows developers to use various underlying models (like Claude, DeepSeek, or GLM) seamlessly with existing tools and libraries that expect standard API schemas. It features zero npm runtime dependencies, making it incredibly easy to deploy and integrate. The project significantly lowers the friction of testing and switching between different AI models.

AI developers and researchers who need to test or integrate multiple different language models without rewriting their application's API handling code.

  • Standardized API translation: Converts proprietary model endpoints into OpenAI, Anthropic, and Gemini standard formats.
  • Massive model support: Provides access to over 100 AI models (including Claude, GPT, DeepSeek, etc.) through a single interface.
  • Zero runtime dependencies: Built without heavy npm packages, ensuring fast execution and easy deployment.
  • Drop-in replacement: Can be used immediately with existing SDKs and tools by simply changing the base URL.
  • Cross-platform compatibility: Supports models from various regions and providers including Chinese LLMs like Kimi and GLM.

Where teams use it

Model benchmarking

Easily swapping between different LLMs (e.g., Claude vs. DeepSeek) in an application to test performance and cost.

Tool integration

Connecting proprietary models to applications like Chatbox or typingmind that only support standard OpenAI/Anthropic APIs.

Simplified development

Writing code against a single, familiar API standard while accessing a wide variety of backend models.

Proxying requests

Setting up a local server to handle API translation and route requests to the most appropriate provider.

Getting started: Clone the repository and run the server script to start the local API translation proxy.

README

master branch

WindsurfAPI · DevinAPI

把 Windsurf / Devin 的 100+ AI 模型(Claude、GPT、Gemini、DeepSeek、Kimi、GLM、SWE…)变成 OpenAI / Anthropic / Gemini 三套标准 API。零 npm 运行时依赖。

Stars  Follow  ·  English

声明

没点 Star 和 Follow 的:严禁商业使用、转售、代部署、挂后台对外提供服务、包装成中转服务出售。 点了 Star 和 Follow 的:随便用,我睁一只眼闭一只眼。

代码本体按 MIT License 开源(见 LICENSE),上面这段是作者个人态度。


Windsurf(原 Codeium,现 Devin Desktop)的 AI 模型变成三套标准 API 同时兼容

  • POST /v1/chat/completionsOpenAI 兼容 任何 OpenAI SDK 直接用
  • POST /v1/responsesOpenAI Responses 兼容(另有 GET / DELETE /v1/responses/{id} 读取与删除已存响应,需带身份参数,见下)
  • POST /v1/messagesAnthropic 兼容 Claude Code / Cline / Cursor 直接连
  • POST /v1beta/models/*Gemini 兼容 直接对接 Gemini SDK

100+ 模型:Claude 4.5/4.6/Opus 4.7 · GPT-5/5.1/5.2/5.4 全系 · Gemini 2.5/3.0/3.1 · Grok · Qwen · Kimi K2.x · GLM 4.7/5/5.1/5.2 · MiniMax · SWE 1.5/1.6 · Arena 等。零 npm 依赖 纯 Node.js。

关键词:Windsurf 逆向 · Devin 代理 · Claude Code 中转 · Cursor 镜像 · AI 中转 API · OpenAI 兼容接口 · 免费 Claude/GPT/Gemini · 大模型反代 · Codeium 逆向

它到底在干嘛

     ┌─────────────┐   /v1/chat/completions   ┌────────────┐
     │ OpenAI SDK  │ ──────────────────────→  │            │
     │ curl / 前端 │ ←──────────────────────  │            │
     └─────────────┘   OpenAI JSON + SSE      │ WindsurfAPI│
                                              │ Node.js    │      ┌──────────────┐       ┌─────────────────┐
     ┌─────────────┐   /v1/messages           │ (本服务)   │ gRPC │ Language     │ HTTPS │ Windsurf 云端   │
     │ Claude Code │ ──────────────────────→  │            │ ───→ │ Server (LS)  │ ────→ │ server.self-    │
     │ Cline       │ ←──────────────────────  │            │ ←─── │ (Windsurf    │ ←─── │ serve.windsurf  │
     │ Cursor      │   Anthropic SSE          │            │      │  binary)     │       │ .com            │
     └─────────────┘                          └────────────┘      └──────────────┘       └─────────────────┘
                                                    ↑
                                                账号池轮询
                                                速率限制隔离
                                                故障转移

它做了什么

  1. 一个 HTTP 服务(端口 3003)同时暴露 OpenAI 和 Anthropic 两套 API
  2. 把请求翻译成 Windsurf 内部 gRPC 协议,通过本地 Language Server 发给 Windsurf 云
  3. 维护账号池,自动轮询 + 速率限制 + 故障转移
  4. 返回前把上游 Windsurf 身份剥掉,模型自称"我是 Claude Opus 4.6 由 Anthropic 开发"

Claude Code / Cline / Cursor 怎么用

模型本身不会操作文件 — 文件操作是 IDE Agent 客户端(Claude Code / Cline 等)在本地执行的:

 你 "帮我改 bug"                Claude Code                    WindsurfAPI               Windsurf Cloud
   │                                │                               │                          │
   │────────────────────────────→  │                               │                          │
   │                                │  POST /v1/messages            │                          │
   │                                │  messages + tools + system    │                          │
   │                                │ ─────────────────────────────→│ 打包成 Cascade 请求      │
   │                                │                               │ ──────────────────────→  │
   │                                │                               │                          │
   │                                │                               │               模型思考 → 返回
   │                                │                               │               tool_use(edit_file)
   │                                │                               │ ←──────────────────────  │
   │                                │ ←── Anthropic SSE ────────────│                          │
   │                                │   content_block=tool_use      │                          │
   │                                │                               │                          │
   │                                │ 本地执行 edit_file()          │                          │
   │                                │ (读写本地文件)                │                          │
   │                                │                               │                          │
   │                                │ 带 tool_result 再发一轮       │                          │
   │                                │ ─────────────────────────────→│ ──────────────────────→  │
   │                                │                                             ... (循环) ...
   │                                │                               │                          │
   │  ← 最终答案                    │                               │                          │

重点:WindsurfAPI 只负责传递 tool_use / tool_result,真正改文件的是客户端 CLI。

快速开始

一键部署

git clone https://github.com/dwgx/WindsurfAPI.git
cd WindsurfAPI
bash setup.sh          # 建目录 · 配权限 · 生成 .env
node src/index.js

Dashboard:http://你的IP:3003/dashboard

Docker 部署

cp .env.example .env

# 可选:提前把 language_server_linux_x64 放到 .docker-data/opt/windsurf/ 下
# 不放也行,容器首次启动时会自动下载到 /opt/windsurf/

docker compose up -d --build
docker compose logs -f

默认挂载:

  • ./.docker-data/data:持久化 accounts.jsonproxy.jsonstats.jsonruntime-config.jsonmodel-access.jsonlogs/
  • ./.docker-data/opt/windsurf:Language Server 二进制与数据目录
  • ./.docker-data/tmp/windsurf-workspace:临时工作区

如果想改持久化目录,可在 .env 里设置 DATA_DIR。Docker 默认已设为 /data

一键更新

部署过之后要拉最新修复,一条命令搞定:

cd ~/WindsurfAPI && bash update.sh

update.sh 做了:git pull → 通过 install-ls.sh 更新 LS binary → 停 PM2 → kill 3003 端口残留 → 重启 → 健康检查。

如果你用的是我们的公网实例(skiapi.dev 之类),不用管,我们已经推过了。

手动安装

git clone https://github.com/dwgx/WindsurfAPI.git
cd WindsurfAPI

# Language Server 二进制 —— 自动检测 Linux/macOS,一键下载 + chmod
bash install-ls.sh

# 下载链:WindsurfAPI release → 公开 LS mirror
#   https://github.com/dwgx/windsurf-ls-release/releases/latest/download
# → Exafunction/codeium fallback。需要私有镜像或回滚时可设置:
#   WINDSURFAPI_LS_RELEASE=https://github.com/<owner>/<repo>/releases/latest/download bash install-ls.sh

# 默认安装路径:
#   Linux x64:          /opt/windsurf/language_server_linux_x64
#   Linux arm64:        /opt/windsurf/language_server_linux_arm
#   macOS Apple Silicon: $HOME/.windsurf/language_server_macos_arm
#   macOS Intel:        $HOME/.windsurf/language_server_macos_x64

# 如果想用本地已下好的 binary:
#   bash install-ls.sh /path/to/language_server_linux_x64
# 或者指定 URL:
#   bash install-ls.sh --url https://example.com/language_server_linux_x64

# ⚠️ 看不到 opus-4.7 / 其他新模型?
# 默认下载链已接入 dwgx/windsurf-ls-release 公开 mirror。
# 如果 mirror 暂未覆盖你的平台,仍可把 Windsurf 桌面端本体里的 LS binary 拷过来:
#
#   macOS:   "$HOME/Library/Application Support/Windsurf/resources/app/extensions/windsurf/bin/language_server_macos_arm"
#   Linux:   "$HOME/.windsurf/bin/language_server_linux_x64"
#            或  /opt/Windsurf/resources/app/extensions/windsurf/bin/language_server_linux_x64
#   Windows: %APPDATA%\Windsurf\bin\language_server_windows_x64.exe
#
#   # 从本地桌面端装:
#   bash install-ls.sh /path/to/language_server_linux_x64
#
# LS binary 一换,/v1/models 立刻就能看到最新模型目录了(云端自动发现)。

cat > .env << 'EOF'
PORT=3003
API_KEY=
DEFAULT_MODEL=claude-4.5-sonnet-thinking
MAX_TOKENS=8192
LOG_LEVEL=info
LS_BINARY_PATH=/opt/windsurf/language_server_linux_x64
LS_DATA_DIR=/opt/windsurf/data
LS_PORT=42100
DASHBOARD_PASSWORD=
EOF

# macOS 本地部署时,使用 install-ls.sh 打印的 LS_BINARY_PATH,
# 并把 LS_DATA_DIR 设到用户可写目录,例如 /Users/you/.windsurf/data。

node src/index.js

加账号

服务跑起来之后要先加 Windsurf 账号才能用,三种方式:

方式 1 Dashboard 一键登录(推荐)

打开 http://你的IP:3003/dashboard → 登录取号 → 点 Google 登录GitHub 登录(OAuth 弹窗)或直接填邮箱密码。所有方式都会自动入池。

方式 2 Token(任何登录方式都能用)

windsurf.com/show-auth-token 复制 Token:

curl -X POST http://localhost:3003/auth/login \
  -H "Content-Type: application/json" \
  -d '{"token": "你的token"}'

方式 3 批量

curl -X POST http://localhost:3003/auth/login \
  -H "Content-Type: application/json" \
  -d '{"accounts": [{"token": "t1"}, {"token": "t2"}]}'

调用示例

OpenAI 格式(Python / JS / curl)

from openai import OpenAI
client = OpenAI(base_url="http://你的IP:3003/v1", api_key="你设的API_KEY")
r = client.chat.completions.create(
    model="claude-sonnet-4.6",
    messages=[{"role": "user", "content": "你好"}]
)
print(r.choices[0].message.content)

Anthropic 格式(Claude Code 直接连)

export ANTHROPIC_BASE_URL=http://你的IP:3003
export ANTHROPIC_API_KEY=你设的API_KEY
claude                # 正常用 Claude Code 即可
# 裸 curl 测试
curl http://localhost:3003/v1/messages \
  -H "Authorization: Bearer 你的key" \
  -H "anthropic-version: 2023-06-01" \
  -d '{"model":"claude-opus-4.6","max_tokens":100,"messages":[{"role":"user","content":"你好"}]}'

Cline / Cursor / Aider

在客户端配置里 Custom OpenAI Compatible

  • Base URL: http://你的IP:3003/v1
  • API Key: 你设的 API_KEY
  • Model: 任选我们支持的模型

Cursor 用户注意:Cursor 客户端白名单会拦截含 claude 的模型名(请求根本不到后端)。用以下别名绕过:

在 Cursor 填 实际模型
opus-4.6 claude-opus-4.6
opus-4.6-thinking claude-opus-4.6-thinking
opus-4.7 claude-opus-4-7-medium
sonnet-4.6 claude-sonnet-4.6
sonnet-4.5 claude-4.5-sonnet
haiku-4.5 claude-4.5-haiku
ws-opus claude-opus-4.6
ws-sonnet claude-sonnet-4.6

GPT / Gemini / DeepSeek 等不受 Cursor 白名单限制,直接填原名。

环境变量

变量 默认值 干嘛的
PORT 3003 服务端口
API_KEY 调 API 要带的密钥 留空就不验证
DATA_DIR 项目根目录 持久化 JSON 状态和 logs/ 的目录,Docker 推荐设成 /data
DEFAULT_MODEL claude-4.5-sonnet-thinking 不传 model 用哪个
MAX_TOKENS 8192 默认最大回复 token 数
LOG_LEVEL info debug / info / warn / error
LS_BINARY_PATH /opt/windsurf/language_server_linux_x64 LS 二进制位置
LS_DATA_DIR Linux: /opt/windsurf/data;macOS: ~/.windsurf/data 每个 proxy 独立的 LS 数据根目录
LS_PORT 42100 LS gRPC 端口
LS_MAX_INSTANCES 内存自适应,最多 20 LS 池最大实例数;2GB VPS 建议 2
LS_POOL_WAIT_MS 30000 LS 池满且全部 active 时,新 proxy LS 最多等待这么久再返回 LS_POOL_EXHAUSTED
LS_SPAWN_MIN_AVAILABLE_BYTES 700MB 新增非 default LS 前要求的可用内存水位;低于该值会排队/拒绝,避免 OOM
LS_MEMORY_GUARD 1 0 可关闭 LS 内存护栏(仅在你有外部 memory limit/监控时考虑)
LS_IDLE_TTL_MS 1200000 非 default LS 空闲超过该时间自动停止;0 关闭
LS_IDLE_SWEEP_MS 自动推导 LS 空闲回收扫描间隔
LS_PREWARM_DEFAULT 1 设为 0 可跳过启动时 default LS 预热,低内存/全 proxy 池改为首个真实请求再懒启动
LS_PREWARM_PROXIES 0 设为 1 才在启动时预热所有 proxy LS;默认按需启动。后台 scheduled probe / 预测 prewarm 只复用空闲常驻 LS,不会为了探测新开/等待/驱逐 LS
LS_PREWARM_ON_ACCOUNT_ADD 0 设为 1 才在 Dashboard/批量导入/OAuth 添加账号后立即预热对应 LS;默认避免批量录入打爆内存
WINDSURFAPI_NATIVE_TOOL_BRIDGE 仅用于 lab/远程执行灰度。all_mapped 仅在已 allowlist 的工具全部可映射时走 native bridge;1 为混合工具 partition 模式。不要把它当成本地 IDE 工具调用的通用修复
WINDSURFAPI_NATIVE_TOOL_BRIDGE_TOOLS Bash/shell_command/run_command 语义族 native bridge 工具 allowlist。默认只包含成熟的 Bash/run_command 路径;Read/Grep/Glob 和 WebSearch/WebFetch 必须显式加入 allowlist,再配合模型/账号/API key gate 小流量实测,仍不是生产默认
WINDSURFAPI_NATIVE_TOOL_BRIDGE_MODELS / PROVIDERS / ROUTES / CALLERS / ACCOUNTS / API_KEYS native bridge 灰度门。为空表示不限;设置后必须匹配才启用。ACCOUNTS 可填账号 id/email,API_KEYS 匹配调用方 API key 但不会把明文 key 传进 chat 逻辑
WINDSURFAPI_NATIVE_TOOL_BRIDGE_OFF 设为 1 强制关闭 native tool bridge,优先级高于上面的开关
WINDSURFAPI_SPECIAL_AGENT_BACKEND 可选 lab-only special-agent 后端。设为 devin-cli 后,swe-1.6 / swe-1.6-fast / adaptive / arena-* 不再走 direct Cascade,而是走 Devin CLI PoC;这不是普通 catalog 模型修复
DEVIN_CLI_PATH devin Devin CLI 可执行文件路径;Docker/macOS 都需要自己安装或挂载,不是基础镜像硬依赖
DEVIN_CLI_MODE print printdevin -p 保守模式;acp 为实验 ACP stdio 后端,使用账号池上游 Windsurf apiKey 认证,默认不全量启用
DEVIN_MAX_PROCS 1 Devin CLI 最大并发进程数,避免 special-agent 路径把内存打爆
DEVIN_CLI_USE_ACCOUNT_POOL 1 默认从 WindsurfAPI 账号池取一个账号并把 apiKey 注入 WINDSURF_API_KEY;设 0 表示 Devin CLI 自己管理登录态
DASHBOARD_PASSWORD 后台密码 留空不设密码
ALLOW_PRIVATE_PROXY_HOSTS 设为 1 允许在代理测试和登录时使用内网 IP(如 192.168.x.x10.x.x.x)。默认留空仅允许公网地址
CASCADE_REUSE_BY_CALLER 0 设为 1 启用 caller 级别回退复用。指纹未命中时,按 callerKey+model 回退到最近的 cascade。适合单用户 Claude Code 场景
CASCADE_POOL_MAX 500 对话池最大条目数。单用户场景设 15 即可,减少资源占用
STICKY_SESSION_ENABLED 0 设为 1 把同一会话固定在同一上游账号。DEVIN_CONNECT 上强烈建议开启:上游 prompt cache 按账号隔离且写入约为读取 10 倍单价,不固定则每轮换号、整段上下文重写。需要 caller 有 per-user 信号(user / safety_identifier / prompt_cache_key / Claude Code metadata.user_id);单用户自部署无这些信号时配 WINDSURFAPI_SINGLE_TENANT_CACHE=1。观测:/dashboard/api/connect-metricssticky 字段
STICKY_SESSION_TTL_MS 1800000 绑定 TTL(30 分钟);活跃会话每轮自动续期
STICKY_SESSION_MAX 10000 绑定表上限,LRU 驱逐
RESPONSE_STORE_ENABLED 1 Responses API 服务端会话状态。开启时 previous_response_id 可续接上下文(客户端只发新一轮);设 0 关闭后带该字段的请求返回 400,GET/DELETE /v1/responses/{id} 同样返回 400。按 callerKey 隔离,租户间不可互读:读取与删除与续接同一套作用域,别人的 id 一律 404(不泄漏是否存在)。检索/删除没有请求体,身份信号走 query:GET /v1/responses/{id}?prompt_cache_key=<你 POST 时用的值>(user / safety_identifier 同样支持)—— 必须与创建该响应时用的值一致,否则 404
RESPONSE_STORE_TTL_MS 3600000 会话保留时长(1 小时),每轮访问自动续期
RESPONSE_STORE_MAX 2000 最多保留多少个会话,LRU 驱逐 + 租户公平配额
RESPONSE_STORE_MAX_BYTES 128m 会话总字节预算(支持 b/k/kb/m/mb/g/gb)。条数上限约束的是数量不是内存 —— 实测真实 agent 会话每条约 167KB,2000 条约 327MB。按条数与字节两个维度中先触发的那个驱逐

Dashboard 功能面板

打开 http://你的IP:3003/dashboard

面板 功能
总览 运行状态 · 账号池 · LS 健康 · 成功率
登录取号 Google / GitHub OAuth 一键登录 · 邮箱密码登录 · 测试代理 按钮(实测出口 IP)
账号管理 加 / 删 / 停用 · 探测订阅等级 · 看余额 · 封禁模型黑名单
模型控制 全局模型黑白名单
代理配置 全局或单账号的 HTTP / SOCKS5 代理
日志 实时 SSE 串流 · 按级别筛 · 每条 turns=N chars=M 诊断多轮
统计分析 时间范围 6h / 24h / 72h · 账号维度 · p50 / p95 延迟
实验性 Cascade 对话复用 · 模型身份注入(每厂商可自定义 prompt)

支持的模型

主线 100+ 个静态模型 + Windsurf 雲端動態下發(mergeCloudModels 啟動時拉取最新)。完整列表查 GET /v1/models,或看 GitHub Pages 模型清单(同步生成於 src/models.js)。

Claude(Anthropic) — 21 个

claude-3.5-sonnet / 3.7-sonnet / thinking · claude-4-sonnet / opus / thinking · claude-4.1-opus · claude-4.5-haiku / sonnet / opus · claude-sonnet-4.6(含 1m / thinking / thinking-1m) · claude-opus-4.6 / thinking · claude-opus-4.7-medium

GPT(OpenAI) — 55 个

gpt-4o · gpt-4.1 · gpt-5 全系(含 medium / high / codex) · gpt-5.1 全系(base / low / medium / high + fast + codex 全 6 變體) · gpt-5.2 全系(none / low / medium / high / xhigh + fast + codex 全 5 變體) · gpt-5.4 全系(base / mini × low/medium/high/xhigh) · o3 全系(base / mini / pro) · o4-mini

Gemini(Google) — 9 个

gemini-2.5-pro / flash · gemini-3.0-pro / flash(minimal / low / medium / high 4 個 reasoning 等級) · gemini-3.1-pro(low / high)

开源 / 国产

Kimi: kimi-k2 / k2.5 / k2-6 / k2-7 · GLM: glm-4.7 / 5 / 5.1 / 5.2 · Qwen: qwen-3 · Grok: grok-3 / grok-3-mini-thinking / grok-code-fast-1 · MiniMax: minimax-m2.5

Windsurf 自家 + Arena

swe-1.5 / 1.5-fast / 1.6 / 1.6-fast · arena-fast · arena-smart

swe-1.6 / swe-1.6-fast / adaptive / arena-* 属于 special-agent 路径。direct Cascade 会报 unknown model UID / route 不通;默认不会假装可用。需要测试时显式开启 WINDSURFAPI_SPECIAL_AGENT_BACKEND=devin-cli,并安装/挂载 Devin CLI。当前 PoC 是 devin -p print 模式,默认拒绝 caller-local tools/media;ACP 工具桥接另做。

免费账号 entitled 模型主要是 gemini-2.5-flashglm-4.7glm-5 / 5.1kimi-k2 / k2.5 / k2-6qwen-3 等开源系列;Claude / GPT 全系 + Opus 系列要 Pro。具体每个账号的 entitled 清单看 dashboard。

工具调用稳定性(v2.0.82+ 实测):Claude family 走 <tool_use> 协议最稳;GLM-4.7 / Kimi-K2.5 走 NLU 兜底 + 可选 retry 大部分 case 能调;GLM-5.1 在 cascade 后端不稳(经常空回复 textLen=0),proxy 救不动;GPT 在 cascade 协议层不传 tools[] schema 也救不全。Claude Code 调本地工具优先 claude-haiku-4.5 / claude-sonnet-4.6

架构要点

  • 零 npm 依赖 全走 node:* 内置 · protobuf 手搓(src/proto.js)· 图片编解码 vendored(src/vendor/,BSD-3 jpeg-js + 自研纯-Node PNG 解码)· 下载即跑
  • 账号池 + LS 池 每个独立 proxy 一个 LS 实例 不混用
  • NO_TOOL 模式 planner_mode=3 关掉 Cascade 内置工具循环,避免 /tmp/windsurf-workspace/ 路径泄漏
  • 三层 sanitize LS 内建工具结果过滤 · <tool_call> 文本解析 · 输出路径清洗
  • 真实 token 计量CortexStepMetadata.model_usage 抓 Cascade 真实 inputTokens / outputTokens / cacheRead / cacheWriteprompt_tokens 含 cacheWrite

PM2 部署

npm install -g pm2
pm2 start src/index.js --name windsurf-api
pm2 save && pm2 startup

不要pm2 restart(会出僵尸进程),用一键更新脚本 bash update.sh

防火墙

# Ubuntu
ufw allow 3003/tcp

# CentOS
firewall-cmd --add-port=3003/tcp --permanent && firewall-cmd --reload

云服务器记得去安全组开 3003。

常见问题

Q: 登录报"邮箱或密码错误" A: 你是用 Google/GitHub 登录的 Windsurf 吧 那种账号没有密码。Dashboard 的登录取号面板现在直接支持 Google / GitHub OAuth 一键登录。

Q: 模型说"我无法操作文件系统" A: 这是 chat API,不是 IDE agent。要让模型真的改文件,用 Claude Code / Cline / Cursor / Aider 之类的客户端 CLI,把它们的 API base URL 指向本服务就行。模型出 tool_use,客户端本地执行,再把 tool_result 发回来。上面的图有详细流程。

Q: 上下文丢失 / 模型忘了前面说的 A: 多账号轮询不会丢上下文 — 每次请求都重新打包完整 history 发给 Cascade。真正的原因通常是中转层(new-api 等)没把完整 messages[] 透传过来。在 Dashboard 日志面板看 turns=N:如果多轮对话但 turns=1,就是中转层在你之前就把历史丢了。

Q: 长 prompt 超时 A: 已修。cold stall 检测按输入长度自适应,长输入最多给 90s。

Q: Claude Code 能用吗 A: 能。export ANTHROPIC_BASE_URL=http://你的API + export ANTHROPIC_API_KEY=你的key/v1/messages 支持 system + tools + tool_use + tool_result + stream + multi-turn 全套,已实测通过。

Q: 免费账号能用什么模型 A: 主要是 gemini-2.5-flashglm-4.7 / 5 / 5.1kimi-k2 / k2.5 / k2-6qwen-3 这些开源系列。Claude family + GPT 全系 + Opus / Max / Thinking 高阶模型要 Pro entitlement。具体每个账号的 entitled 清单 dashboard 里看 — model_not_entitled 错误返回的 available_in_pool 字段也会列出账号池能用的。

Q: 免费账号调工具稳吗 A: 看模型。Claude family <tool_use> 协议训练扎实最稳(free 账号若 entitled 也是优选);GLM-4.7 / Kimi-K2.5 走 NLU 兜底 + WINDSURFAPI_NLU_RETRY=1 retry-with-correction 多数 case 能调;GLM-5.1 在 cascade 后端经常空回复 proxy 救不动;GPT 系列受 cascade 协议层限制(不传 OpenAI tools[] schema)也不稳。Claude Code / Cline / Codex 调本地文件 / 跑命令优先 claude-haiku-4.5claude-sonnet-4.6

Q: 客户端显示“没有调用工具”,怎么排查 A: 先看日志里的 ToolRoute[...]。它会列出客户端声明的工具、tool_choice 过滤后的有效工具、native bridge 映射/未映射工具、preamble 降级层级,以及 tool_choice_none / forced_tool_not_declared / preamble_compacted / native_bridge_* 等原因。/v1/messages/v1/responses 的 server-side 工具(如 Anthropic advisor/code_execution,OpenAI file_search/mcp/computer_use)如果代理没有实现,会在翻译层丢弃;这类工具不是普通 function tool,不等于 WindsurfAPI 已经能替客户端执行。native bridge 也不是“本地 IDE 工具修复开关”:默认安全路径仍是 prompt/tool emulation,由客户端本地执行工具;native bridge 是让 Windsurf 远端 workspace 执行 Cascade 内置工具,只适合有模型/账号/API key gate 的小流量实验。

Q: 31 个 trial 账号一会儿就全 unavailable A: 八成是用了周限模型 — claude-opus-4-7-max / gpt-5.5-xhigh / claude-sonnet-4-7-thinking 这类高 reasoning effort 变体每个账号每周只有 5 次配额,31 号 × 5 次 ≈ 150 次就到顶。换 claude-sonnet-4.6 / claude-haiku-4.5 daily 配额比较宽松。docker logs windsurfapi-windsurf-api-1 | grep rate_limit 看每个账号的 cooldown 字段验证。

Q: All accounts temporarily rate-limited / IP-level cooldown 是不是代理坏了 A: 通常不是。Windsurf 上游会对同一出口 IP + 同一模型的密集请求施加 cooldown,多个账号绑在同一出口时会一起被限流。WindsurfAPI 会停止继续烧账号并返回 429 + Retry-After;v2.0.140 起这个等待时间会按上游 Resets in: 27m12s 这类真实值返回,而不是固定提示 30 秒。解决方向是降并发、换更宽松模型、给账号绑定不同出口 IP,或者等上游 cooldown 到期。

Q: free 账号是不是本地限制成 1 分钟 1 次 A: 不是。本地 free tier RPM 默认是 10/min。你看到的 1/min 或一段时间后恢复,通常是 Windsurf 上游 free-tier 动态限频或模型 entitlement 限制。Dashboard 里看账号状态和模型可用清单;请求无权限模型时错误里的 available_in_pool 会列出当前账号池能用的模型。

Q: context deadline exceeded / Client.Timeout 能靠调大 .env timeout 解决吗 A: 不能。长 thinking / 长输出在约 236-243 秒断流,是 Windsurf provider/Cascade 单次 stream 窗口。WindsurfAPI 会把它标成 upstream_deadline_exceeded / windsurf_provider_deadline,并丢弃半截 Cascade 复用轨迹,避免下一轮上下文错乱。实际规避只能拆任务、降低 reasoning/max output,或换更快模型。

贡献者

特别感谢下面的朋友,他们提交过 PR 或系统性地审了代码,让这个项目变得更稳:

  • @dd373156PR #1 修复 Pro 层级的模型合并逻辑:原本只看硬编码清单,云端动态拉回来的模型没进 tier 表,Pro 账号在 Cursor / Cherry Studio 里看不到新上线的模型。
  • @colin1112aPR #13 一次性审了 15 个安全 / 并发 / 资源管理 bug:XSS 转义、shell 注入、OOM 防护、auth 路由位置、gRPC 双回调、LS pool 竞态、HTTP/2 帧大小上限等。后续我们在这个基础上又加固了 JS-level escJsAttr_pending 合并并发 ensureLs、LS 退出时释放 pooled session,并延伸修了 Antigravity 审计发现的 6 个问题。
  • @baily-zhangPR #36 + PR #45 Cascade reuse 的核心修复:stableTurns 指纹匹配 (#36) 解决了 0% 命中率;trajectory offset 增量拉取 (#45) 消除了多轮复用时的上下文膨胀。
  • @aict666PR #44 修复 chat 调用后 inferTier 把 Pro/Trial 账号降级为 free 的 bug,保护了 GetUserStatus 设定的权威 tier。
  • @smeineckePR #43 Dashboard 完整国际化:14 个 commit 覆盖中英文翻译、I18n 系统、check-i18n.js 校验工具。
  • @you922PR #162 + PR #163 Sticky session 机制从零搭建(callerKey + modelKey → accountId 绑定)+ LS 崩溃指数退避自动重启。另外在 #164 提供了 SectionOverrideConfig 工具调用失效的源码级根因分析。
  • @FermizPR #181 Cascade 复用优化(单用户场景跳过轮询)+ HTTPS 代理层 + conversation-pool 大小可配置化。
  • @linqichengggPR #175 Windows / macOS / Linux 三平台 LS 路径统一:二进制路径、数据目录、安装脚本全部对齐。
  • @lauvwwPR #182 Dashboard 批量导入解析器重写:支持 JSON / CSV / 纯文本混合粘贴,自动检测分隔符。
  • @ucloudnb666PR #184 Astraflow 第三方提供商接入。
  • @datfooldivePR #173 Dashboard UI 大扫除:统一组件风格、优化卡片布局和响应式适配。
  • @The-five-stoogesPR #188 Sticky session 流式路径修复 + body.user 多用户隔离机制 + stickyNoFallback / stickyBindByUserOnly 双开关。
  • @andya1lanPR #192 update.sh 通过 install-ls.sh 更新 LS binary,统一 WindsurfAPI release / 公开 LS mirror / Exafunction 下载链,并修复 macOS grep -P 兼容性。
  • @MatrixNeoKozakPR #195 Dashboard API malformed JSON 现在返回 HTTP 400,不再用 200 包着 ok:false,让前端和自动化调用方能按状态码正确处理请求体格式错误。
  • @brandonedleyPR #201 新增 GLM 5.2 和 Kimi K2.7 模型目录项,并同步 README / 英文 README / package 描述 / 模型 catalog 测试,给后续模型新增留下了代码、文档、测试一起更新的样板。
  • @forrinzhaoPR #219 定位到 codex apply_patch 工具描述里的 FREEFORM tool, so do not wrap the patch in JSON. 会触发 Devin content policy(飞书 codex bot 全量被拦),live-bisect 7/7 确定性复现,并做了关键的双片段 A/B —— 只改一处仍拦、两处都改才过。这个发现顺带暴露出更深的结构缺陷:工具描述 preamble 注入在 neutralizeClientIdentity 之后,导致 native 路径上任何经由工具描述进来的触发词都绕过 a1-a6 整条防线。落地版把中和移到 preamble 注入之后,并把两条改写做成 (a7) 规则进既有序列(复用主开关与测试体系),因此覆盖所有客户端、所有触发词。另采纳其 responses.js 修复:Codex 发的 input item 是裸 {role, content} 不带 type:'message',此前被静默丢弃导致上游收到空 messages → UPSTREAM_INTERNAL。
  • @warelikPR #224 #225 #226 #227 #228 #229 一轮六连,覆盖账号池、限流、身份中和、协议规范四个子系统。429 reset window 双链根因:上游给的 3h 重置窗口在传输层被丢(只解构 {code, message}),且 model-scoped 冷却对 getApiKey(modelKey=null) 的池选择结构上不可见 —— 两条只修一条都毫无效果,刚被 429 的账号几秒内被重选、一路撞到硬封(#224)。客户端断连不再当成账号故障:统一识别 abort(兼容 undici 与 AbortController 两种形态),流式/非流式全部退出路径不再罚 error budget、不再 failover 烧配额、不再往死 socket 写(#225)。Grok CLI 的 You are Grok … released by xAI self-ID 触发 content policy,补进 a1-a5 同族规则并整块剥离 <executing_actions_with_care>(#227)。thinking 块 signature: "" 改为省略,修严格客户端拒收(#228)。Responses usage 补齐 input/output_tokens_details,与 DEVIN_CONNECT 缓存 wire tag 校准正好凑成一条链的两半(#229)。另有 600 行零依赖的 pair-chain 会话连续性模块,从对话自身已完成的请求/响应对推导稳定 session_id,默认关、开关闭合时字节等价(#226)。
  • @warelikPR #216 + PR #215 中和上游 MCP-gate:server.codeium.com 对工具描述做指纹匹配,Cursor 21 个工具里 8 个被 permission_denied 拒掉;把 native #10 ToolDef 顶层描述换成工具名 + 递归剥参数 schema 的描述注解(保留结构和名叫 description 的参数),再把描述-only preamble 注入 system prompt 补回选工具上下文,21/21 全过(#216)。另修 Node 20+ IPv6 Happy Eyeballs 导致的 ETIMEDOUT:关掉 autoSelectFamily + 本地 HTTP/2 连接改用 127.0.0.1(#215)。

想加入这份名单?欢迎提 issuepull request。Dashboard 左侧有"致谢"面板 能看到同样的信息。

授权

MIT License. See LICENSE.

Release and Secret Boundary

Release automation may publish Docker images and GitHub Releases. Keep tokens, API keys, cookies, and provider credentials out of issues, pull requests, logs, and committed config. If a report needs authentication details, share only redacted metadata and reproduction steps.

Star History

https://www.star-history.com/?type=date&repos=dwgx/WindsurfAPI

View on GitHub

Recent activity

commits and pull requests

Recent open issues

view all

Releases and announcements

158 total
  1. v3.9.4v3.9.4Jul 28, 20263 downloads

    # v3.9.4 `GET` / `DELETE /v1/responses/{id}` **自 v3.9.1 发布起对所有客户端都不可用** —— 任何客户端形态都必然 404。用到这两个端点的部署需要升级;其余部分无变化。 升级无需改配置(但这两个端点的调用方式有一处新增,见下)。 --- ## 用户可感知 ### 检索/删除端点从发布起就是死的 无请求体的 `GET`/`DELETE` 用 `callerKeyFromRequest(req, token, null)` 派生身份, 而这在**每种**客户端形态下都得不到能命中的 callerKey: - **能链式续接的客户端**都会发 `user` / `prompt_cache_key` / `safety_identifier`, 所以它 `POST` 时的 callerKey 带 `:user:<hash>` 段;而无 body 的 `GET` 派生 `:client:<ip+ua>` —— 键不同,查询必然 miss。 - **什么身份都不发的客户端**两边键相同,但过不了 `hasPerUserScope` —— 同样 404。 - 连 `WINDSURFAPI_SINGLE_TENANT_CACHE=1` 也救不了:身份不匹配是先决问题,那个开关 只影响信任判定。 实测:`POST` 存下 id 后,同一客户端 `GET`/`DELETE` 全部 404,而用它自己的 `POST` 身份查同一 id 返回 200 —— 记录确实在,只是它自己读不到。 ### 调用方式:身份信号走 query Responses 检索 API 没有请求体,所以身份信号改走查询串,词汇与 `POST` body 完全一致 (并且走**同一条**提取路径,所以调用方能精确复现自己的作用域): ``` GET /v1/responses/{id}?prompt_cache_key=<你 POST 时用的值> DELETE /v1/responses/{id}?user=<你 POST 时用的值> ``` `user` / `prompt_cache_key` / `safety_identifier` 三者都支持,取值**必须与创建该响应 时用的一致**,否则 404。不带这些参数时行为与之前一致(仍然 404)。 跨租户隔离未被削弱:别人的身份参数一律 404 且不泄漏内容,这一点有独立守卫。 --- ## 工程 **这个缺陷之所以能带着全绿的测试发布,是因为我当时写的测试把 bug 固化成了契约。** 那条路由层测试断言"bodyless GET 必须 404",还在注释里称之为 *"the documented contract … the scopin

  2. v3.9.3v3.9.3Jul 28, 2026

    # v3.9.3 v3.9.2 的补丁版。它修的那条 blocker **只修了 3 条内部路由里的 1 条** —— `/v1/messages` 和 `/v1beta`(Gemini)上,中途断开的流照旧被报成正常完成。 用 Claude Code / Cline / Cursor(走 `/v1/messages`)或 Gemini SDK 的部署建议升级。 升级无需改配置。 --- ## 用户可感知 ### 中途断开的流在 `/v1/messages` 与 Gemini 路由上仍被报成完成 v3.9.2 的修法是:Cascade 流已发出内容后死掉时,代理补发的那个**合成** `finish_reason:'stop'` 带一个内部标记,translator 不再把它当真实终止信号。 问题是**只有 `/v1/responses` 认这个标记**。另两条内部路由各自都有为同一场景写的 守卫(`messages.js` 的 BUG1、`gemini.js` 的同构守卫,注释明确写着"截断必须报 error 而不是伪造 stop_reason"),两者都被同一个合成帧骗过: ``` /v1/messages : stop_reason = end_turn | 无 error 帧 /v1beta gemini: finishReason = STOP | 无 error 帧 ``` 对 Claude Code 这类客户端,这意味着一个被网络中断截断的答案会被当作**完整回复** 接受,而不是触发 SDK 重试。 现在两条路由都会把它作为 `error` 事件报出(502 → 可重试的 529 / UNAVAILABLE), 正常流则完全不受影响(`end_turn` / `STOP` 照旧)。 ### 根因比标记更深一层 修这条时发现,`finishPartialStreamAfterError` 除了合成 `finish_reason`,**还会写 `[DONE]`** —— 而 `messages.js` 与 `gemini.js` 都把裸 `[DONE]` 当权威终止信号。 所以这两条路由有**两个**入口被骗,只堵 `finish_reason` 那一个是无效的。第一次尝试 修复时我正是只堵了一个,验证"看起来没生效"因而一度误判并回滚 —— 直到把两个入口 一起折价才真正生效。(`/v1/responses` 没有这个问题:它对 `[DONE]` 是 `continue`, 本就不当终止信号。) --- ## 工程 **这是本仓库"修复只覆盖部分路由"陷阱的第 4 次 —— 而且这次的不完整修复就在 上一个修复本身里。** 前三次是 #188(sticky 漏 connect)、O1(`include_u

  3. v3.9.2v3.9.2Jul 28, 2026

    # v3.9.2 v3.9.1 的补丁版。发版后做了一轮对抗复核,查出 3 条缺陷 —— **全部是 v3.9.1 自己的 修复引入的**,其中 1 条 blocker 让 v3.9.1 的主打修复在**默认后端**上完全失效。 建议从 v3.9.1 升级。升级无需改配置。 --- ## 用户可感知 ### (blocker) 流式截断守卫在默认后端上被绕过 v3.9.1 声称修好了"流式回复中途断开被报成完成"。**实际只在 connect 路径修好了。** Cascade 流在**已经发出内容之后**中途死掉时,代理会补发一个**合成的** `finish_reason:'stop'` 收尾 —— 这个 wire 形态本身是对的(把错误当 content delta 注入会污染 assistant 消息)。但 v3.9.1 的守卫问的是"有没有收到终止 chunk", 而合成的那一帧正好满足它。 **Cascade 是默认后端**,所以对多数部署来说,v3.9.1 的这条修复等于没生效:半截 回复照旧报成 `response.completed`,并写进 response store 成为下一轮上下文。 复核用三种真实错误形态实测复现:HTTP/2 `pending stream has been canceled`、 provider `context deadline exceeded`、`ECONNRESET`。带 tool_call 的变体还会在 store 里留下一条永远不会有结果的 `tool_calls`。 现在合成帧带内部标记,translator 不再把它计为终止 chunk。标记**只在内部 translator 路由**(messages / gemini / responses)发出 —— 直连 `/v1/chat/completions` 的客户端看到的 wire 逐字节不变。 ### 合法截断的一轮重新可以链式续接 v3.9.1 把 store 提交门写成了"非 truncated",于是 `length` / `content_filter` 这种**合法**截断的流式轮次也被踢出 store。但那是一次完整、且客户端确实收到了的 回复:模型停下的原因客户端看得见、也能据此续写,OpenAI 允许从它链式续接,而 **非流式路径一直是照旧提交的**。 实测:流式 `length` 不可链、非流式 `length` 可链 —— 同一个 `finish_reason` 在两条 路径上行为分叉。这是本仓库"修复只覆盖部分路径"陷阱的又一次复发。门改为只挡 "上游从未给出终止信号"这一种情况。 ### response store 不再静默删除超额消息 `capEntryBytes` 的反向游走在"已保

  4. v3.9.1v3.9.1Jul 28, 2026

    # v3.9.1 修 v3.9.0 的一批缺陷。**主线是一类反复出现的错误模式:把"不知道"当成"没事"** —— 缺失的流终止帧当成正常结束、未校准的枚举值当成已知语义、缺失的 `finish_reason` 当成良性完成。三处都在信息不足时选了乐观解释,代价都是把坏结果报成好结果。 升级无需改配置。 --- ## 用户可感知 ### 流式回复中途断开,不再被报成"完成" 上游 socket 在答到一半时断开(缺 Connect-RPC 强制的 end-of-stream 帧)时, 连接层原本把它当成**正常抽干** —— generator 正常返回、`reason=null`,而 `null` 默认落到 `'stop'`。于是被截断的回复以"完整一轮"的身份到达全部四条协议路由。 在 `/v1/responses` 上后果更重一层:那半截回复不但被报成 `response.completed`, 还会**写进 response store 成为下一轮的上下文** —— 一个活得比引发它的那个请求 更久的静默污染,客户端无从发现。 - 连接层现在抛 `STREAM_TRUNCATED`(可重试:与 `ECONNRESET` 同类;流式路径只在 尚未 emit 任何字节时重放,不会重复内容)。抛出点在 tail flush 之后,已发出的 字节不受影响 - `/v1/responses` 关成 `incomplete`,理由用独立的 `upstream_incomplete` —— 断连不是 token 上限,报成 `max_output_tokens` 会让自动续写的客户端去接一轮 上游根本没写完的话 - 截断的一轮不再进 store - `length` / `content_filter` / `tool_calls` 的既有语义逐条回归守住 - 新增 `stream_truncated` 计数器(`GET /dashboard/api/connect-metrics`): 它的尖峰是"上游链路在丢连接"的直接信号 ### 付费账号上的正常完成不再被报成截断或拒答 `StopReason` 枚举里只有 `2` 和 `4` 由实测钉住(`4` 是 v3.9.0 那轮用付费账号 校准的)。`3 → length`、`5 → content_filter` 一直是照 protobuf 变体**名字顺序** 猜的 —— 和已被推翻的 `4 → length` 同源。猜错的代价不对称: - 假 `length` / `content_filter` 把 `/v1/responses` 一轮关成 `response.incomplete`, 对 Codex 类客户端是整轮硬失败 - `content_filter`

  5. v3.9.0v3.9.0Jul 27, 20269 downloads

    # v3.9.0 Responses API 拿到真正的服务端会话状态,账号池少了一条会误伤健康账号的路径, 并首次用**付费账号**把挂了几个月的 wire 校准问题跑通。 本轮的验证方式和以往不同:除单元/回归测试外,用一个真实 agent 循环 (`/v1/responses` + 工具调用 + 多轮链式)端到端压测,并对运行实例做了 30+ 次 鉴权绕过探测。下面每条"实测"都出自这些运行,不是推断。 升级无需改配置。 --- ## 用户可感知 ### `/v1/responses` 真正支持服务端会话(`previous_response_id`) 此前 `previous_response_id` **在代码里零命中** —— 从未被读取。Responses API 的 核心特性就是服务端持有对话:客户端只发新一轮 + 该 id。于是链式客户端每轮只有 1 条消息到达上游,**模型每轮盲答,既不报错也不告警**,产出通顺但完全没有上下文 的回答,调用方无从发现。 真上游实测:第 1 轮告知数字 `84317`,第 2 轮只发新问题 + `previous_response_id` → 模型正确答出 `84317`。修复前必然失败。 - 每条记录存该轮**完整**累积消息,而非父指针 —— 解析是 O(1),且中途被驱逐不会 静默截断历史(要么全有,要么明确失败) - 按 `callerKey` 隔离:某租户铸的 id 对其他租户不可解析,否则重放 id 即可读到 对方对话。失配 fail-closed,统一报 404(不让人探测哪些 id 存在) - 未知/过期/跨租户 → **404 `response_not_found`**;store 被关 → 400 并提示改发 完整 `input`。**任何情况下都不静默按新一轮发出** - 遵守 `store: false` 契约;有界(TTL 1 小时 + 上限 + LRU + 租户公平配额); 截断时保留开头的 system 消息 - 流式仅在完整完成时提交 —— 中途出错或客户端断连都不入库,避免用客户端从未 收到的半轮回复污染下一轮 新开关:`RESPONSE_STORE_ENABLED`(默认开)/ `RESPONSE_STORE_TTL_MS` / `RESPONSE_STORE_MAX` / `RESPONSE_STORE_MAX_MESSAGES`。 观测:`GET /dashboard/api/connect-metrics` → `responseStore`。 ### 链式工具循环:客户端重发 tool_calls 不再挂 按契约链式客户端只该回传 `function_call_output`(call 本身已在服务端存储的 resp

Commits per week

last 52 weeks
1880Week of 2025-08-03: 0 commitsWeek of 2025-08-10: 0 commitsWeek of 2025-08-17: 0 commitsWeek of 2025-08-24: 0 commitsWeek of 2025-08-31: 0 commitsWeek of 2025-09-07: 0 commitsWeek of 2025-09-14: 0 commitsWeek of 2025-09-21: 0 commitsWeek of 2025-09-28: 0 commitsWeek of 2025-10-05: 0 commitsWeek of 2025-10-12: 0 commitsWeek of 2025-10-19: 0 commitsWeek of 2025-10-26: 0 commitsWeek of 2025-11-02: 0 commitsWeek of 2025-11-09: 0 commitsWeek of 2025-11-16: 0 commitsWeek of 2025-11-23: 0 commitsWeek of 2025-11-30: 0 commitsWeek of 2025-12-07: 0 commitsWeek of 2025-12-14: 0 commitsWeek of 2025-12-21: 0 commitsWeek of 2025-12-28: 0 commitsWeek of 2026-01-04: 0 commitsWeek of 2026-01-11: 0 commitsWeek of 2026-01-18: 0 commitsWeek of 2026-01-25: 0 commitsWeek of 2026-02-01: 0 commitsWeek of 2026-02-08: 0 commitsWeek of 2026-02-15: 0 commitsWeek of 2026-02-22: 0 commitsWeek of 2026-03-01: 0 commitsWeek of 2026-03-08: 0 commitsWeek of 2026-03-15: 0 commitsWeek of 2026-03-22: 0 commitsWeek of 2026-03-29: 0 commitsWeek of 2026-04-05: 10 commitsWeek of 2026-04-12: 13 commitsWeek of 2026-04-19: 188 commitsWeek of 2026-04-26: 128 commitsWeek of 2026-05-03: 46 commitsWeek of 2026-05-10: 11 commitsWeek of 2026-05-17: 4 commitsWeek of 2026-05-24: 14 commitsWeek of 2026-05-31: 51 commitsWeek of 2026-06-07: 21 commitsWeek of 2026-06-14: 2 commitsWeek of 2026-06-21: 12 commitsWeek of 2026-06-28: 84 commitsWeek of 2026-07-05: 118 commitsWeek of 2026-07-12: 75 commitsWeek of 2026-07-19: 24 commitsWeek of 2026-07-26: 53 commitsAug 3, 2025Jul 26, 2026
854 commits in the last 52 weeks.

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 9 commitsSun 1:00 — 11 commitsSun 2:00 — 9 commitsSun 3:00 — 6 commitsSun 4:00 — 2 commitsSun 5:00 — 2 commitsSun 6:00 — 5 commitsSun 7:00 — 2 commitsSun 8:00 — 3 commitsSun 9:00 — 2 commitsSun 10:00 — 3 commitsSun 11:00 — 0 commitsSun 12:00 — 2 commitsSun 13:00 — 3 commitsSun 14:00 — 3 commitsSun 15:00 — 10 commitsSun 16:00 — 1 commitsSun 17:00 — 3 commitsSun 18:00 — 4 commitsSun 19:00 — 1 commitsSun 20:00 — 1 commitsSun 21:00 — 5 commitsSun 22:00 — 9 commitsSun 23:00 — 15 commitsMon 0:00 — 7 commitsMon 1:00 — 4 commitsMon 2:00 — 6 commitsMon 3:00 — 14 commitsMon 4:00 — 2 commitsMon 5:00 — 1 commitsMon 6:00 — 0 commitsMon 7:00 — 7 commitsMon 8:00 — 7 commitsMon 9:00 — 6 commitsMon 10:00 — 1 commitsMon 11:00 — 0 commitsMon 12:00 — 1 commitsMon 13:00 — 4 commitsMon 14:00 — 4 commitsMon 15:00 — 3 commitsMon 16:00 — 13 commitsMon 17:00 — 5 commitsMon 18:00 — 5 commitsMon 19:00 — 5 commitsMon 20:00 — 12 commitsMon 21:00 — 14 commitsMon 22:00 — 9 commitsMon 23:00 — 8 commitsTue 0:00 — 5 commitsTue 1:00 — 3 commitsTue 2:00 — 1 commitsTue 3:00 — 5 commitsTue 4:00 — 2 commitsTue 5:00 — 8 commitsTue 6:00 — 1 commitsTue 7:00 — 13 commitsTue 8:00 — 8 commitsTue 9:00 — 4 commitsTue 10:00 — 6 commitsTue 11:00 — 3 commitsTue 12:00 — 12 commitsTue 13:00 — 0 commitsTue 14:00 — 0 commitsTue 15:00 — 1 commitsTue 16:00 — 10 commitsTue 17:00 — 6 commitsTue 18:00 — 2 commitsTue 19:00 — 10 commitsTue 20:00 — 11 commitsTue 21:00 — 9 commitsTue 22:00 — 6 commitsTue 23:00 — 5 commitsWed 0:00 — 2 commitsWed 1:00 — 2 commitsWed 2:00 — 0 commitsWed 3:00 — 3 commitsWed 4:00 — 2 commitsWed 5:00 — 9 commitsWed 6:00 — 2 commitsWed 7:00 — 4 commitsWed 8:00 — 2 commitsWed 9:00 — 7 commitsWed 10:00 — 3 commitsWed 11:00 — 11 commitsWed 12:00 — 8 commitsWed 13:00 — 1 commitsWed 14:00 — 5 commitsWed 15:00 — 4 commitsWed 16:00 — 6 commitsWed 17:00 — 7 commitsWed 18:00 — 4 commitsWed 19:00 — 12 commitsWed 20:00 — 6 commitsWed 21:00 — 5 commitsWed 22:00 — 2 commitsWed 23:00 — 2 commitsThu 0:00 — 7 commitsThu 1:00 — 5 commitsThu 2:00 — 4 commitsThu 3:00 — 5 commitsThu 4:00 — 7 commitsThu 5:00 — 1 commitsThu 6:00 — 10 commitsThu 7:00 — 3 commitsThu 8:00 — 3 commitsThu 9:00 — 0 commitsThu 10:00 — 6 commitsThu 11:00 — 5 commitsThu 12:00 — 3 commitsThu 13:00 — 5 commitsThu 14:00 — 4 commitsThu 15:00 — 8 commitsThu 16:00 — 7 commitsThu 17:00 — 8 commitsThu 18:00 — 2 commitsThu 19:00 — 7 commitsThu 20:00 — 5 commitsThu 21:00 — 1 commitsThu 22:00 — 5 commitsThu 23:00 — 4 commitsFri 0:00 — 2 commitsFri 1:00 — 1 commitsFri 2:00 — 6 commitsFri 3:00 — 2 commitsFri 4:00 — 3 commitsFri 5:00 — 10 commitsFri 6:00 — 5 commitsFri 7:00 — 3 commitsFri 8:00 — 1 commitsFri 9:00 — 5 commitsFri 10:00 — 0 commitsFri 11:00 — 7 commitsFri 12:00 — 3 commitsFri 13:00 — 10 commitsFri 14:00 — 5 commitsFri 15:00 — 1 commitsFri 16:00 — 7 commitsFri 17:00 — 12 commitsFri 18:00 — 19 commitsFri 19:00 — 6 commitsFri 20:00 — 10 commitsFri 21:00 — 4 commitsFri 22:00 — 2 commitsFri 23:00 — 10 commitsSat 0:00 — 4 commitsSat 1:00 — 3 commitsSat 2:00 — 8 commitsSat 3:00 — 5 commitsSat 4:00 — 2 commitsSat 5:00 — 8 commitsSat 6:00 — 3 commitsSat 7:00 — 5 commitsSat 8:00 — 1 commitsSat 9:00 — 4 commitsSat 10:00 — 2 commitsSat 11:00 — 9 commitsSat 12:00 — 3 commitsSat 13:00 — 2 commitsSat 14:00 — 9 commitsSat 15:00 — 1 commitsSat 16:00 — 6 commitsSat 17:00 — 6 commitsSat 18:00 — 2 commitsSat 19:00 — 12 commitsSat 20:00 — 4 commitsSat 21:00 — 2 commitsSat 22:00 — 11 commitsSat 23:00 — 4 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.

Who is committing

last 52 weeks
Maintainer commits476 (54%)
Community commits413 (46%)

889 commits in total over the last year.

DateListRankStars gained
May 9, 2026daily#24+105
  • awesome-selfhosted/awesome-selfhosted

    A list of Free Software network services and web applications which can be hosted on your own servers

    311.2K stars

  • react/react

    The library for web and native user interfaces.

    247.1K stars · JavaScript

  • affaan-m/ECC

    The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

    238.5K stars · JavaScript

  • affaan-m/ECC

    The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

    234.7K stars · JavaScript

  • NousResearch/hermes-agent

    The agent that grows with you

    227K stars · Python

  • Significant-Gravitas/AutoGPT

    AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.

    186.2K stars · Python