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
3.1K
+9 today
Forks
635
Watchers
13
Open issues
9
Open PRs
3
Contributors
~31
Commits
1.5K
Branches
19

JavaScriptMITCreated Apr 9, 2026Last push todayLatest release v3.9.38+20 stars this week+93 this month

Quick answers

What is WindsurfAPI?
A zero-dependency translation layer that converts Windsurf and Devin AI models into standard API formats.
What does WindsurfAPI do?
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.
Who is WindsurfAPI for?
AI developers and researchers who need to test or integrate multiple different language models without rewriting their application's API handling code.
How do I get started with WindsurfAPI?
Clone the repository and run the server script to start the local API translation proxy.
How popular is WindsurfAPI on GitHub?
dwgx/WindsurfAPI has 3,058 stars and 635 forks on GitHub, and gained 20 stars in the last 7 days.
What license does WindsurfAPI use?
dwgx/WindsurfAPI is released under the MIT license.

Star history

since Jul 29, 2026
01K2K3KJul 2026Aug 2026Sep 2026Oct 2026
3.1K stars as of Oct 4, 2026. Measured daily since Jul 29, 2026; GitHub no longer exposes earlier star timestamps.

Contribution activity

commits per day, last 52 weeks
OctNovDecJanFebMarAprMayJunJulAugSepOctMonWedFri2025-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: 3 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: 21 commits2026-07-29: 8 commits2026-07-30: 0 commits2026-07-31: 7 commits2026-08-01: 0 commits2026-08-02: 3 commits2026-08-03: 33 commits2026-08-04: 81 commits2026-08-05: 44 commits2026-08-06: 29 commits2026-08-07: 10 commits2026-08-08: 12 commits2026-08-09: 23 commits2026-08-10: 42 commits2026-08-11: 3 commits2026-08-12: 56 commits2026-08-13: 1 commit2026-08-14: 4 commits2026-08-15: 1 commit2026-08-16: 1 commit2026-08-17: 4 commits2026-08-18: 1 commit2026-08-19: 1 commit2026-08-20: 13 commits2026-08-21: 9 commits2026-08-22: 4 commits2026-08-23: 1 commit2026-08-24: 3 commits2026-08-25: 3 commits2026-08-26: 1 commit2026-08-27: 1 commit2026-08-28: 6 commits2026-08-29: 1 commit2026-08-30: 1 commit2026-08-31: 1 commit2026-09-01: 1 commit2026-09-02: 1 commit2026-09-03: 1 commit2026-09-04: 4 commits2026-09-05: 1 commit2026-09-06: 0 commits2026-09-07: 1 commit2026-09-08: 0 commits2026-09-09: 1 commit2026-09-10: 1 commit2026-09-11: 1 commit2026-09-12: 5 commits2026-09-13: 7 commits2026-09-14: 20 commits2026-09-15: 5 commits2026-09-16: 6 commits2026-09-17: 46 commits2026-09-18: 1 commit2026-09-19: 1 commit2026-09-20: 1 commit2026-09-21: 1 commit2026-09-22: 17 commits2026-09-23: 28 commits2026-09-24: 1 commit2026-09-25: 1 commit2026-09-26: 0 commits2026-09-27: 1 commit2026-09-28: 1 commit2026-09-29: 1 commit2026-09-30: 1 commit2026-10-01: 7 commits2026-10-02: 1 commit2026-10-03: 1 commit2026-10-04: 1 commit2026-10-05: 0 commits2026-10-06: 0 commits2026-10-07: 0 commits2026-10-08: 0 commits2026-10-09: 0 commits2026-10-10: 0 commits
1,427 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Very active

    1,427 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

WindsurfAPI · DevinAPI

WindsurfAPI — 把 Windsurf/Devin 云端 100+ 模型变成 OpenAI / Anthropic / Gemini 三套兼容 API

JavaScript · MIT · ★3,046

docs · releases · issues

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

历史账本 · 把 1387 次提交、196 个版本、82 个 PR、180 个 issue 摊开给你看:时间线主账 + 贡献者分析 + Git 树三形态(竖/横/环)+ 自伤与返工全记录 —— 打开可视化账本(纯原生渲染,零依赖)

Stars  License  Release  CI  Docs  Follow  ·  English

声明

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

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


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

  • POST /v1/chat/completions — OpenAI 兼容 任何 OpenAI SDK 直接用
  • POST /v1/completions — OpenAI 旧 Completions(非流式;prompt 包成一条 user turn,流式请走 chat)
  • POST /v1/responses — OpenAI Responses 兼容(另有 GET / DELETE /v1/responses/{id} 读取与删除已存响应,需带身份 header,见下)
  • POST /v1/messages — Anthropic 兼容 Claude Code / Cline / Cursor 直接连
  • POST /v1beta/models/* — Gemini 兼容 直接对接 Gemini SDK

100+ 模型:Claude 4.5/4.6/Opus 4.7/5 · GPT-5/5.1/5.2/5.4/5.5/5.6-Luna 全系 · 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/1.7/2 · Arena 等。零 npm 依赖 纯 Node.js。

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

原理 · 5 分钟跑起来 · 客户端接入 · 环境开关 · 全部文档 · English

它到底在干嘛

flowchart LR
    subgraph clients["你的客户端"]
        A["OpenAI SDK<br/>curl / 前端"]
        B["Claude Code<br/>Cline · Cursor"]
        C["Gemini SDK"]
    end

    subgraph gw["WindsurfAPI(本服务 · 端口 3003)"]
        direction TB
        R["协议翻译层<br/>OpenAI ↔ Anthropic ↔ Gemini"]
        P["账号池<br/>轮询 · 限流隔离 · 故障转移 · 熔断"]
        N["身份中和<br/>剥掉上游 Windsurf 身份"]
        R --- P
        R --- N
    end

    LS["Language Server<br/>(Windsurf 二进制)"]
    UP["Windsurf 云端<br/>server.self-serve.windsurf.com"]
    DC["Devin 云端<br/>(DEVIN_CONNECT 路径)"]

    A -- "/v1/chat/completions" --> R
    B -- "/v1/messages" --> R
    C -- "/v1beta/models/*" --> R
    R -- "gRPC" --> LS
    LS -- "HTTPS" --> UP
    R -. "HTTPS(可选直连)" .-> DC

    classDef gwStyle fill:#1f6feb22,stroke:#1f6feb,stroke-width:2px
    classDef upStyle fill:#8957e522,stroke:#8957e5
    class gw gwStyle
    class UP,DC upStyle
Loading
纯文本版(不支持 mermaid 的环境)
     ┌─────────────┐   /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
# 空 API_KEY / DASHBOARD_PASSWORD 是 fail-closed(compose 默认 0.0.0.0,起来也是 401)。
# compose 默认 DEVIN_CONNECT=1,不跑 Language Server,不会自动下载 LS。
# 只有关掉 DEVIN_CONNECT、走 Cascade 时才会在缺二进制时尝试安装 LS。

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

默认挂载:

  • ./.docker-data/data:持久化 accounts.json、proxy.json、stats.json、runtime-config.json、model-access.json、logs/
  • ./.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

# ⚠️ LS binary 版本偏旧 / 想换一个来源?
# 默认下载链已接入 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 的内容。
# 模型目录是代理直连 HTTPS 拉的(GetCascadeModelConfigs / GetCliModelConfigs),
# 请求里的 ideVersion 写死在 src/windsurf-api.js,不从 binary 读 —— 所以目录只取决于
# 上游给这个账号授予了什么。看不到某个新模型,是上游还没放给该账号,不是本地文件旧了。

cat > .env << 'EOF'
PORT=3003
# Empty API_KEY is fail-closed (401) even on localhost.
# Local open access: WINDSURFAPI_ALLOW_UNAUTHENTICATED=1 and HOST=127.0.0.1
API_KEY=
DEFAULT_MODEL=claude-sonnet-4.6
MAX_TOKENS=8192
LOG_LEVEL=info
LS_BINARY_PATH=/opt/windsurf/language_server_linux_x64
LS_DATA_DIR=/opt/windsurf/data
LS_PORT=42100
# Empty DASHBOARD_PASSWORD is fail-closed. Local open panel: DASHBOARD_ALLOW_NO_AUTH=1
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":"你好"}]}'

Gemini 格式(Google GenAI SDK 直接连)

Gemini 原生客户端不发 Authorization: Bearer,它用 x-goog-api-key 头或 ?key= 查询参数 —— 两种都收,所以官方 SDK 不用改代码就能连。

from google import genai
client = genai.Client(
    api_key="你设的API_KEY",
    http_options={"base_url": "http://你的IP:3003"},
)
r = client.models.generate_content(model="claude-sonnet-4.6", contents="你好")
print(r.text)
# 非流式
curl "http://localhost:3003/v1beta/models/claude-sonnet-4.6:generateContent" \
  -H "x-goog-api-key: 你的key" \
  -H 'content-type: application/json' \
  -d '{"contents":[{"role":"user","parts":[{"text":"你好"}]}]}'

# 流式(?alt=sse 才是 SSE,不带就是 JSON 数组分片)
curl -N "http://localhost:3003/v1beta/models/claude-sonnet-4.6:streamGenerateContent?alt=sse" \
  -H "x-goog-api-key: 你的key" \
  -H 'content-type: application/json' \
  -d '{"contents":[{"role":"user","parts":[{"text":"数到三"}]}]}'

OpenAI Responses 格式(带服务端会话状态)

/v1/responses 除了 POST,还有 GET /v1/responses/{id} 和 DELETE /v1/responses/{id}。 链式调用靠 previous_response_id,服务端替你保存上一轮 —— 这样第二轮不用重发历史。

# 第一轮:拿到 response id
curl http://localhost:3003/v1/responses \
  -H "Authorization: Bearer 你的key" \
  -H 'content-type: application/json' \
  -d '{"model":"claude-sonnet-4.6","input":"记住数字 42","store":true}'

# 第二轮:只发新问题,历史由服务端接上
curl http://localhost:3003/v1/responses \
  -H "Authorization: Bearer 你的key" \
  -H 'content-type: application/json' \
  -d '{"model":"claude-sonnet-4.6","input":"我让你记的数字是几?",
       "previous_response_id":"resp_把上一轮返回的id填这里","store":true}'

# 取回 / 删除
curl http://localhost:3003/v1/responses/resp_xxx -H "Authorization: Bearer 你的key"
curl -X DELETE http://localhost:3003/v1/responses/resp_xxx -H "Authorization: Bearer 你的key"

存储默认开(RESPONSE_STORE_ENABLED=0 关掉)。容量上限也可调: RESPONSE_STORE_TTL_MS(空闲超时,默认 1 小时)、RESPONSE_STORE_MAX_AGE_MS(绝对保留 上限,默认 24 小时)、RESPONSE_STORE_MAX(条数,默认 2000)、 RESPONSE_STORE_MAX_MESSAGES(单会话消息数,默认 400)、RESPONSE_STORE_MAX_BYTES (总字节预算,默认 128m,支持 b/k/kb/m/mb/g/gb)。

租户隔离靠的是 response id 的 90 bit 熵,不是客户端自称的作用域 —— 共享同一个 API key 时,两个调用方发相同的 user 会推导出逐字节相同的 callerKey,所以别把 id 当成除"难猜"以外的任何保证。

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 要带的密钥。空=默认 fail-closed(401,本机 bind 也一样)。本机开放需 WINDSURFAPI_ALLOW_UNAUTHENTICATED=1 且本机 bind
WINDSURFAPI_ALLOW_UNAUTHENTICATED 关 空 API_KEY 时放行本机 bind。默认关。公网 bind 即使设了也不放行
DATA_DIR 项目根目录 持久化 JSON 状态和 logs/ 的目录,Docker 推荐设成 /data
DEFAULT_MODEL claude-sonnet-4.6 不传 model 用哪个。必须是当前后端能解析的名字。Connect 上解析不到默认 400 model_not_found(WINDSURFAPI_STRICT_MODEL=0 才静默降级到免费 selector)
MAX_TOKENS 8192 默认最大回复 token 数
LOG_LEVEL info debug / info / warn / error
WINDSURFAPI_LEAK_TRACE off 推理/内容边界结构化日志(实验性,默认关闭)。开启后输出 LEAK_TRACE 前缀日志:原始流事件所属通道(content/reasoning)、think 标记、截断文本样本、settle 时 content/reasoning 字符数。用于在线抓取模型推理泄漏进 content 通道的问题。字段:channel/blockType/think/sample/len/reqId/account/msgId/contentChars/reasoningChars/rerouted
WINDSURFAPI_IGNORE_CLOUD_FILTER 0 Cascade 路径下,各账号云端 catalog 同步后,账号池列表展示活跃账号目录的并集,路由则校验所选账号自己的目录;设为 1 恢复完整静态 catalog。目录缺失、为空或同步失败时保持 fail-open;DEVIN_CONNECT 使用独立 selector catalog
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 print 为 devin -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 空 后台密码。空=默认 fail-closed(本机 bind 也 401)。本机开放面板需 DASHBOARD_ALLOW_NO_AUTH=1
ALLOW_PRIVATE_PROXY_HOSTS 空 设为 1 允许在代理测试和登录时使用内网 IP(如 192.168.x.x、10.x.x.x)。默认留空仅允许公网地址
CASCADE_REUSE_BY_CALLER 0 设为 1 启用 caller 级别回退复用。指纹未命中时,按 callerKey+model 回退到最近的 cascade。适合单用户 Claude Code 场景
CASCADE_POOL_MAX 500 对话池最大条目数。单用户场景设 1–5 即可,减少资源占用
CASCADE_REUSE_HASH_SYSTEM 1 默认把 system 打进复用指纹。设 0 退出(Claude Code 每轮改 cwd 时提高命中率,隔离变弱)
STICKY_SESSION_ENABLED 0 设为 1 把同一会话固定在同一上游账号。DEVIN_CONNECT 上强烈建议开启:上游 prompt cache 按账号隔离且写入约为读取 5.6 倍单价(devin-connect.js 17.8%-of-miss 口径),不固定则每轮换号、整段上下文重写。需要 caller 有 per-user 信号(user / safety_identifier / prompt_cache_key / Claude Code metadata.user_id);单用户自部署无这些信号时配 WINDSURFAPI_SINGLE_TENANT_CACHE=1。观测:/dashboard/api/connect-metrics 的 sticky 字段
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(不泄漏是否存在)。这句原本写"租户间不可互读",而那高估了保证的来源 —— 作用域本身不是机密:共享一个 API key 时 callerKey 是 api:{hash(apiKey)}:user:{hash(body.user)},而 user 常是邮箱或账号 id,即可猜。真正挡住跨读的是 response id 的 90 bit 熵(resp_ + UUIDv4 去横线取前 24 个 hex;96 bit 宽度减去落在切片内的 version/variant 固定位),实测作用域完全正确但 id 猜错一样 not_found。所以隔离在实践中成立,但它是"要撞对一个 90 bit 的 id",不是"作用域把租户分开了" —— 别把 user 当成访问控制用。检索/删除没有请求体,身份信号走 header:GET /v1/responses/{id} 带 x-response-prompt-cache-key: <你 POST 时用的值>。六种作用域信号都支持:user / prompt_cache_key / safety_identifier / conversation / conversation_id / session_id。header 名把下划线换成连字符(x-response-conversation-id);query 降级通道两种拼写都接受(?conversation_id= 与 ?conversation-id=,其余多词信号同理)。取值必须与创建该响应时一致,否则 404。只发一种信号并保持一致 —— 同时发多种不同的作用域信号时它们会被折叠成一个身份,所以多发一种就会改变派生出的 key(这是既有行为,不限于 query 通道)。query 会被反代/CDN/浏览器历史记录,user 常含 PII,优先用 header
RESPONSE_STORE_TTL_MS 3600000 空闲超时(1 小时),不是保留上界。比的是距上次访问的时间,而每次成功 GET 都会把它刷新 —— 所以单靠它,周期性读取可以让一个条目无限存活。绝对上界见下一行
RESPONSE_STORE_MAX_AGE_MS 86400000 绝对保留上界(24 小时),从条目创建时刻算、不被读取刷新。默认取得远高于一次长 agent 会话而不是贴着空闲超时:把正在跑的循环的上下文中途丢掉,比多留一会儿更糟;总内存另有字节与条数两个上限管
RESPONSE_STORE_MAX 2000 最多保留多少个会话,LRU 驱逐 + 租户公平配额
RESPONSE_STORE_MAX_BYTES 128m 会话总字节预算(支持 b/k/kb/m/mb/g/gb)。条数上限约束的是数量不是内存 —— 实测真实 agent 会话每条约 167KB,2000 条约 327MB。按条数与字节两个维度中先触发的那个驱逐
DEVIN_CONNECT_IMAGE_TAG 10 DEVIN_CONNECT 图片字段的 tag。默认使用真实 Devin schema 和 SWE-1.7 抓包共同验证的 repeated field #10;设 0 可回退为不发送图片,见下节
DEVIN_CONNECT_COLLAPSE_SYSTEM 0 设 1 后把 system 内容包成 <system>...</system>,按顺序并入下一条 user 消息,绕开上游对 field #2 更严格的内容策略。默认关闭;有 tools 且 field #2 为空时仍只保留既有 benign placeholder
DEVIN_CONNECT_CATALOG_TTL_MS 300000 DEVIN_CONNECT 在线模型目录的成功缓存 TTL(默认 5 分钟,最小 10 秒)。每个账号独立同步;失败或空响应保留最后一次成功目录

完整清单在 .env.example —— 上表只列常用的。 只存在于源码里、两处都没收录的开关见 docs/ENV-SWITCHES.md。

图片 / 视觉怎么开

DEVIN_CONNECT 后端现在默认按真实 Devin wire 发送内联图片:

# 默认就是 10;仅在需要紧急回退时关闭
DEVIN_CONNECT_IMAGE_TAG=0

10 有两层独立证据:真实 Devin .proto 中 ChatMessagePrompt.images 是 repeated #10, ImageData 是 base64_data #1 / mime_type #2;真实 SWE-1.7 请求把图片直接挂在 source=USER 消息上,响应的 modelUid 仍是 swe-1-7,并正确识别了 macOS Dock、Sketch、 QQ 和 WPS。因此网关不再伪造 assistant read tool call、synthetic tool result 或顶层 read ToolDef,也不再按 swe-* 名字硬判定“无视觉”。

普通 user 图片保持在原 user 消息上;多图按 repeated #10 写进同一条消息。原生 tool result 里的图片保持 source=TOOL_RESULT,同时保留调用方的 tool_call_id #7。目录同步还会解码 ClientModelConfig.supports_images #5,并在上游明确给出 true/false 时把 supports_images 暴露到 /v1/models;字段缺失时保持未知,不伪造 false。上游 disabled #4 的模型不会进入 实时目录。

DEVIN_CONNECT_IMAGE_INNER_TAGS 仍可覆盖内部 base64,mime tag(默认 1,2),仅用于未来 wire 变更的应急校准。远程 https:// 图片 URL 仍不会由同步 wire builder 主动下载;请使用 data URL / base64,或显式开启 DEVIN_ACP_VISION=1 走本机 Devin CLI 的 ACP 视觉通道。

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 啟動時拉取最新)。Cascade 路径下,各账号云端 catalog 同步后,GET /v1/models 和 Dashboard 展示活跃账号目录的并集,路由则校验所选账号自己的目录;DEVIN_CONNECT 继续使用独立 selector catalog;静态完整列表仍可查看 GitHub Pages 模型清单(同步生成於 src/models.js)。

Claude(Anthropic) — 36 个

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 · claude-opus-4.8 全系(low / medium / high / xhigh / max + fast) · claude-5-fable / claude-sonnet-5 / claude-opus-5 全系(low / medium / high / xhigh / max,opus-5 含 fast)

GPT(OpenAI) — 65 个

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) · gpt-5.5 全系(none / low / medium / high / xhigh + fast) · gpt-5.6-luna 全系(none / 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 / 1.7 / 1.7-lightning · 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-flash、glm-4.7、glm-5 / 5.1、kimi-k2 / k2.5 / k2-6、qwen-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 / cacheWrite,prompt_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。

出问题了先看这里

按症状找,不用通读下面的问答。这是协议转换网关,所以排查的第一步永远是 分清是哪一层坏了 —— 客户端、本网关、还是上游。

flowchart TD
    S{"症状?"} --> A["请求根本没到<br/>连接被拒 / 超时"]
    S --> B["返回 401 / 403"]
    S --> C["有回复,但工具不调用"]
    S --> D["有回复,但内容不对<br/>丢上下文 / 混入思考过程"]
    S --> E["账号全挂<br/>rate-limited / unavailable"]

    A --> A1["1. 服务活着吗<br/>curl :3003/v1/models"]
    A1 --> A2["2. 防火墙放了 3003 吗<br/>见「防火墙」一节"]
    A2 --> A3["3. 超时别只调 .env<br/>看「context deadline」那条"]

    B --> B1["两层 key 别搞混:<br/>调用方 key ≠ 上游账号"]
    B1 --> B2["Gemini 客户端用<br/>x-goog-api-key 或 ?key="]

    C --> C1["先看日志里的 ToolRoute[...]<br/>它会列出被过滤/降级的原因"]
    C1 --> C2["再看是不是 server-side 工具<br/>翻译层会丢弃未实现的那类"]

    D --> D1["丢上下文 → 是否该用<br/>/v1/responses 链式"]
    D1 --> D2["混入思考 → 开 LEAK_TRACE<br/>抓边界日志"]

    E --> E1["先分清是账号被限<br/>还是 IP 级冷却"]
    E1 --> E2["看「All accounts<br/>temporarily rate-limited」那条"]

    classDef sym fill:#8957e522,stroke:#8957e5
    classDef act fill:#1f6feb22,stroke:#1f6feb
    class A,B,C,D,E sym
    class A1,A2,A3,B1,B2,C1,C2,D1,D2,E1,E2 act
Loading

两条最容易踩的:

现象 真实原因
改大 .env 里的 timeout 但 context deadline exceeded 还在 那个超时不在这一层。见下面同名问答
一开就"所有账号 rate-limited",怀疑代理坏了 大概率是 IP 级冷却,不是账号问题也不是代理问题

排查请求链路时,发真实请求看响应,别只读代码 —— 这是协议转换网关,两层 key、四条出口路径,读代码容易推错。

常见问题

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-flash、glm-4.7 / 5 / 5.1、kimi-k2 / k2.5 / k2-6、qwen-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.5 或 claude-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 或系统性地审了代码,让这个项目变得更稳:

  • @dd373156 — PR #1 修复 Pro 层级的模型合并逻辑:原本只看硬编码清单,云端动态拉回来的模型没进 tier 表,Pro 账号在 Cursor / Cherry Studio 里看不到新上线的模型。
  • @colin1112a — PR #13 一次性审了 15 个安全 / 并发 / 资源管理 bug:XSS 转义、shell 注入、OOM 防护、auth 路由位置、gRPC 双回调、LS pool 竞态、HTTP/2 帧大小上限等。后续我们在这个基础上又加固了 JS-level escJsAttr、_pending 合并并发 ensureLs、LS 退出时释放 pooled session,并延伸修了 Antigravity 审计发现的 6 个问题。
  • @baily-zhang — PR #36 + PR #45 Cascade reuse 的核心修复:stableTurns 指纹匹配 (#36) 解决了 0% 命中率;trajectory offset 增量拉取 (#45) 消除了多轮复用时的上下文膨胀。
  • @aict666 — PR #44 修复 chat 调用后 inferTier 把 Pro/Trial 账号降级为 free 的 bug,保护了 GetUserStatus 设定的权威 tier。
  • @smeinecke — PR #43 Dashboard 完整国际化:14 个 commit 覆盖中英文翻译、I18n 系统、check-i18n.js 校验工具。
  • @you922 — PR #162 + PR #163 Sticky session 机制从零搭建(callerKey + modelKey → accountId 绑定)+ LS 崩溃指数退避自动重启。另外在 #164 提供了 SectionOverrideConfig 工具调用失效的源码级根因分析。
  • @Fermiz — PR #181 Cascade 复用优化(单用户场景跳过轮询)+ HTTPS 代理层 + conversation-pool 大小可配置化。
  • @linqichenggg — PR #175 Windows / macOS / Linux 三平台 LS 路径统一:二进制路径、数据目录、安装脚本全部对齐。
  • @lauvww — PR #182 Dashboard 批量导入解析器重写:支持 JSON / CSV / 纯文本混合粘贴,自动检测分隔符。
  • @ucloudnb666 — PR #184 Astraflow 第三方提供商接入。
  • @datfooldive — PR #173 Dashboard UI 大扫除:统一组件风格、优化卡片布局和响应式适配。
  • @The-five-stooges — PR #188 Sticky session 流式路径修复 + body.user 多用户隔离机制 + stickyNoFallback / stickyBindByUserOnly 双开关。
  • @andya1lan — PR #192 update.sh 通过 install-ls.sh 更新 LS binary,统一 WindsurfAPI release / 公开 LS mirror / Exafunction 下载链,并修复 macOS grep -P 兼容性。
  • @MatrixNeoKozak — PR #195 Dashboard API malformed JSON 现在返回 HTTP 400,不再用 200 包着 ok:false,让前端和自动化调用方能按状态码正确处理请求体格式错误。
  • @brandonedley — PR #201 新增 GLM 5.2 和 Kimi K2.7 模型目录项,并同步 README / 英文 README / package 描述 / 模型 catalog 测试,给后续模型新增留下了代码、文档、测试一起更新的样板。
  • @forrinzhao — PR #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。
  • @warelik — PR #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)。
  • @warelik — PR #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)。

想加入这份名单?欢迎提 issue 或 pull request。Dashboard 左侧的"致谢"面板是更完整的一份:它从 contributors.json 渲染,当前 27 位贡献者、53 条记录,每条还带分级与机制说明;上面这份名单是其中人工挑选的一部分。

授权

MIT License. See LICENSE.

发布与密钥边界

发布流程会自动推 Docker 镜像和 GitHub Release。别把 token、API key、cookie、上游账号凭据 写进 issue、PR、日志或提交的配置文件里。 如果报告问题必须带上鉴权信息,只贴脱敏后的元数据 和复现步骤。

对应的英文段见 README.en.md。


Star History

Star History · 点击查看完整星图

View on GitHub

Recent activity

commits and pull requests

Releases and announcements

190 total
  1. v3.9.38v3.9.38Sep 22, 202662 downloads

    # v3.9.38 本说明描述实际发布的 `v3.9.38`,最终 tag 指向 `0b78217`。发布前 tag 曾指向另外四个提交, 四个都没有产出过发行物: - `4e429fa` —— 被独立复核否掉。tag 从未以它推送,也从未有 CI 运行在它上面 (`actions/runs?head_sha=4e429fa…` 为空)。它今天出现在远端,只是因为后来推送的 master 以它为祖先,不是当时推送的结果 —— 这两件事容易混,所以分开写。 - `27170ff` —— 推送后触发 Release #186(35773633801),测试失败,发行物作业全部跳过。 - `1ed5d18` —— 推送后触发 Release #187(35776846089),该轮被取消;同一提交的 CI #854 因一条测试夹具的时序缺陷失败。 - `d1fc712` —— 只在本地移动过,未推送,无 CI 运行。 `0b78217` 的 Release #188(35778314521)六项作业成功;GitHub Release 于 2026-09-22 20:16:40 UTC 发布,四项附件已上传。 维护者在发布前移动过 tag,这件事写在这里而不是留给读者去比对 ref;本次独立复核没有移动 tag,也没有执行 push 或发布。以上只陈述远端 ref、CI 运行与发行物的可核事实,不声称此前 推送过的源码从未被任何人取得。既已发布,后续代码修正应使用新的版本与 tag,不覆盖 `v3.9.38` 的身份。 ## 数据保全:移除破坏性迁移,并以独占创建取得写入资格 旧迁移仅凭 package.json 的 name 不等于当前 stub 就递归删除 src 并覆盖辅助文件, 不能证明这些内容属于代理。omp 移除了该迁移,既有目录的普通调用快照得以保全。 独立复核又发现“检查后被其他进程创建”的窗口:递归 mkdir 不意味着本调用创建了叶目录。 后续修正改为独占创建叶目录,EEXIST 时停止;每个 stub 文件也使用 wx,拒绝覆盖并发创建的文件。 原有快照与全新创建对照保留,新增确定性交错测试覆盖目录争用及文件争用。 **升级取舍明确保留:** pre-#108 的 my-project 等旧模板不再自动重写。 因此“新目录的 stub 标识正确”不能证明“旧目录已全部清理”。自动清理能力确有回退; 这里优先保全未知来源或人工修改的内容,不把模板名字当成所有权证明。 需要清理时,运维应先停止相关 LS 使用、备份并人工确认该代理专用目录,再选择非破坏性的迁移; 不要递归删除未经确认的 src,也不要直接拿用户真实工程目录替代代理目录。 本轮没有做实际旧版本升级或上游模型行为验收,不宣称恢复了所有旧模板场景。 ## 凭据

  2. v3.9.37v3.9.37Sep 17, 202652 downloads

    # v3.9.37 这一版来自对 v3.9.36 的一次**独立对抗审查**(1 个 P1 + 4 个 P2,全部复现后修复并复核)。 核心是**凭据库的锁被重写成"实例身份"**:并发写入不再可能丢记录,写者中途死亡留下的锁也不再 需要人工干预。默认路径**逐字节不变**(270 组完整请求 Buffer 对拍),无 API 破坏,ACU `^22` 仍默认关。 --- ## 用户可感知 ### 并发写凭据不再可能丢记录(锁重写) 旧实现把锁的身份放在**固定路径**上(`<凭据文件>.lock`,里面一个 `owner.json`),回收死锁靠"重读那个 路径再删"。两个进程都读到同一个死 owner 时,先完成回收的那一个会重新拿锁并读取快照,而慢的那一个 继续按固定路径删除——**删掉的是新持有者刚建立的锁**,于是两个写者同时进入,后写的覆盖先写的。 确定性交错探针可复现。 现在:每次写入建立**不可变的 claim 实例**(目录名自带 host/pid/随机 token,身份就是名字本身), 回收只删除**被证明确实已死的那一个实例**(同机 + `ESRCH`),发布前再次确认自己仍持有该实例。 另外在固定路径上放了一个**永久普通文件哨兵**,旧版本既创建不了也删不掉它——因此升级后新旧版本 **不会互相覆盖**。 ### 写者中途死亡不再需要人工解锁 旧实现在"创建目录成功、写 `owner.json` 之前"死亡(或该写入撞上 ENOSPC)会留下**无法回收**的锁: 新的身份写在名字里,不再有"第二次写决定身份"的窗口,这类残留会被作为可证明死亡的实例自动回收。 > **运维注意(唯一需要动手的地方)**:如果升级前旧版本崩溃留下了**空的** `<凭据文件>.lock` 目录, > 新版本**不会自动接管**它(空目录可能是另一个旧写者的初始化窗口,年龄不能作为死亡证据)。 > 此时写入会明确返回 BUSY,删掉那个空目录即可恢复。这是有意的保守设计。 ### 其他 - 登录响应里的 `credentialStored` **只在实际落盘成功后**才为 `true`(此前凭据存储未启用也会报"已保存"); - 会话复用索引不再泄漏:resolve 路径写入的索引现在也登记归属,淘汰时清理得干净(复现中曾残留 29 条)。 ## 工程与门禁 - **修掉 CI 门禁的自比较**:`wire-byte-identity` 原用 `git describe --tags --abbrev=0`,在一个**已打 tag 的提交**上它会返回该提交自己的 tag,于是"与上一个 release 比较"退化成与自己比较、门禁空转。 现在由 `scripts/wire-base.mjs` 选择**严格早于待测提

  3. v3.9.36v3.9.36Sep 17, 202618 downloads

    # v3.9.36 这一版把 **PR #271** 合了进来,并落了六条独立审计线的成果:**默认路径逐字节不变**(270 组完整请求 Buffer 对拍,且这条现在由 CI 自动执行),**无 API 破坏**,ACU `^22` 仍默认关。 --- ## 用户可感知 ### 并行工具调用之间的游离文本不再打断会话(`#271`,贡献者 `@21hbguo`) Codex 的 Responses 路径每轮会在并行 `tool_calls` 之间重放一条 `reasoning` + 文本的 assistant 条目。 归一化后是 `[call, call, text]` 的**同源 3 连**,上游状态机拒——整个会话 500/529。现在这段文本被折进 首个调用回合的交错块里;两轮评审后又补掉三处:数组 content 不再被压平(**图不再被静默丢弃**)、 空 `tool_call_id` 不再与空结果配对、带自有字段(如 `signature`)的条目原样透传而不被折掉。 ### 请求路径上的白给 CPU 被拿掉 - 裸 API key 场景(默认)不再无条件计算响应缓存键——每请求省掉一次全量深拷贝 + sha256 (仓库自测:400 条消息 1.09 ms、4 MB 图 2.96 ms); - `/v1/messages` 的 prompt 由**逐字符走两遍**变成一遍; - 上游请求编码器每字段只申请一次 Buffer;流式分帧在**被拆包**的大帧上由平方级变为线性 (4 MiB 帧 152 ms → 0.9 ms); - 图片收缩不再为"量长度"而反复 base64(52 次 → 1 次)。 ### 更少静默失败 - 凭据库并发写不再可能**静默丢记录**(唯一 tmp + 串行化写 + 拒绝缩水式修复);写者中途死亡留下的锁 可被安全回收(仅当同机 owner 确证已死); - 登录响应新增 `credentialStored`:要求存密码但实际没存上时,客户端能看见; - 流式失败的三个阶段(错误帧、`[DONE]`、日志)互相隔离,一个失败不再吞掉另一个;跨账号重试之间加了 可取消的间隔(此前单请求可零间隔连打 9 次上游); - `.env` 行内注释告警**不再把值打进日志**;`reveal-key` 的账号邮箱改为遮罩。 ### 安全边界收紧(全部默认关路径不变) - 账号的 `apiServerUrl` 变成上游主机时,只接受已知云端 origin(`DEVIN_CONNECT_ACCOUNT_HOST=1` 时生效), 否则在发出任何上游请求**之前**拒绝,且该拒绝不消耗账号错误预算; - 凭据存储的"允许远程保存密码"判定改用**可信客户端 IP**(同机反代后不再误判

  4. v3.9.35v3.9.35Sep 16, 202636 downloads

    # v3.9.35 三条 wire 层提交:**一个 `DEVIN_CONNECT_REPLAY_REASONING` 开启时才可见的修复**(只带 reasoning 的 assistant 历史回合此前被整条丢弃),外加两处**行为零变化**的契约澄清(orphan 过滤器的作用域、 reasoning replay 的发射次数与别名优先级)。默认路径**逐字节不变** —— 270 组完整请求 Buffer 与 v3.9.34 对拍一致。无 API 破坏。ACU `^22` 仍默认关。 --- ## 用户可感知 ### replay 开启时,只带 reasoning 的 assistant 回合不再被吞(`e0143fd`) 设了 `DEVIN_CONNECT_REPLAY_REASONING=1`(或 `9`)的部署里,一条**只有 `reasoning` / `reasoning_content`**、没有文本也没有工具调用的 assistant 历史,会被空回合过滤器在编码之前丢掉: `messageText()` 对无文本内容返回空串,而过滤器排在 reasoning 分支之前。操作者打开了 replay 开关, wire 上却看不到任何 #11 —— 开关看起来没生效。 本版只在"**该开关已打开、且确实有非空载荷**"时放行;tag=0(默认)短路,默认 wire 逐字节不变。 **影响面:仅限设了 `DEVIN_CONNECT_REPLAY_REASONING` 的部署。** 没设这个开关的用户,新旧 wire 完全一致(实测:同一确定性输入下 270 组完整请求 Buffer 与 v3.9.34 零差异;逐字节比较, 不是剔除 UUID 之后的投影)。 **没有顺手做的**:content **只有图片**的 assistant 回合仍按原样排除。图片发射(`tag=10`)默认开着, 放行它是**默认行为变化**,需要先测上游对「assistant 回合携带图片」的接受度 —— 见 [#272](https://github.com/dwgx/WindsurfAPI/issues/272)(附最小对照实验;修的时候必须同时替换 现有的兼容锁测试与其突变)。 ## 工程 ### orphan 过滤器:语义写准 + 行为守卫(`6b8762f`) `stripOrphanedToolResults()` 判定的是「这段输入里**完全找不到**父 call」,不是函数头注释此前说的 "earlier in the conversation" —— 结果出现在它的 call **之前**时会被保留。这是**有意**的:改成 "seen-so-far" 会静默删掉一个父调用仍存在于后文的结果,并把一个待执行调用交还给客户端

  5. v3.9.34v3.9.34Sep 14, 202643 downloads

    # v3.9.34 四条外部 PR 进 master:Connect 连续同 role 纯文本不再打成 run≥3 的 `invalid_argument`; Responses 工具输出里的图能进 `#10 images`;Docker nginx 不再用默认 1m 挡多模态; 本机导入认 Devin 桌面目录。另:`swe-2` 进 Connect 目录,`gpt-5.6` Devin Local 显式 opt-in。 无 API 破坏。ACU `^22` 仍默认关。`FREE_TIER_SELECTOR` 仍是 `swe-1-6-slow`。 --- ## 用户可感知 ### 连续同 role 纯文本在进 Connect wire 前合并(#270) 客户端把一个回合按 part 拆存时,历史里会出现连续同 role 的纯文本。原样编码后 wire 上连续同源 ChatMessage,**run 长度 ≥ 3** 时上游 `invalid_argument`("an internal error occurred")。 本版只合并 user/assistant 的纯文本;带 `tool_calls` / `tool_call_id` / reasoning / 图片的条目不合并; 生成新对象、不改调用方数组。四条 wire 断言钉住 source 序列。 `DEVIN_CONNECT_COLLAPSE_SYSTEM=1` 时 system 仍占相邻位,不会把夹心 system 挤出注入槽。 并行 tool_calls 的交错仍是 #261:那一层把 N 个 call 拆成交替单调用。两层不抢。 ### Responses 工具输出里的图走 Connect `#10`;nginx 不再 1m 挡(#265) `function_call_output` / `custom_tool_call_output` 的数组 `output` 不再被 `stringifyMaybe` 压成 扁平文本。Connect 路径上 data-URL 图进 `#10 images`(默认 tag **10**)。 Docker 拓扑里 nginx 是唯一前置跳数,默认 `client_max_body_size` **1m**,>1 MB 多模态必然 413。 本版 `32m`、`proxy_read/send_timeout 900s`(必须严格大于应用层 `DEVIN_TIMEOUT_MS` 默认 600s)。 **真上限仍是应用层 `MAX_BODY_SIZE` = 10 MB**;nginx 只负责放到应用门口。Cascade 侧未改。 ### 本机导入认 Devin 桌面目录(#264) 桌面端 userData 在 `%APPDATA%\De

Commits per week

last 52 weeks
2120Week 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: 3 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: 68 commitsWeek of 2026-08-02: 212 commitsWeek of 2026-08-09: 130 commitsWeek of 2026-08-16: 33 commitsWeek of 2026-08-23: 16 commitsWeek of 2026-08-30: 10 commitsWeek of 2026-09-06: 9 commitsWeek of 2026-09-13: 86 commitsWeek of 2026-09-20: 49 commitsWeek of 2026-09-27: 13 commitsWeek of 2026-10-04: 1 commitsOct 12, 2025Oct 4, 2026
1.4K commits in the last 52 weeks.

When work happens

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

Who is committing

last 52 weeks
Maintainer commits967 (64%)
Community commits539 (36%)

1,506 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

    323.8K stars

  • 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.

    272.8K stars · JavaScript

  • NousResearch/hermes-agent

    The agent that grows with you

    251.2K stars · Python

  • react/react

    The library for web and native user interfaces.

    250.9K stars · JavaScript

  • n8n-io/n8n

    Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

    206.7K stars · TypeScript

  • firecrawl/firecrawl

    Supercharge your AI agents with data from the web and beyond. Building the library for superintelligence. 🔥

    188.6K stars · TypeScript