{"id":49194256,"url":"https://github.com/dwgx/windsurfapi","last_synced_at":"2026-06-05T20:00:59.193Z","repository":{"id":351513582,"uuid":"1205803474","full_name":"dwgx/WindsurfAPI","owner":"dwgx","description":"Windsurf-to-OpenAI compatible API proxy","archived":false,"fork":false,"pushed_at":"2026-04-26T14:30:12.000Z","size":834,"stargazers_count":824,"open_issues_count":9,"forks_count":226,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-04-26T14:34:58.326Z","etag":null,"topics":["api-proxy","llm-gateway","openai-compatible","reverse-engineering","windsurf"],"latest_commit_sha":null,"homepage":"https://dwgx.github.io/WindsurfAPI/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dwgx.png","metadata":{"files":{"readme":"README.en.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-09T09:42:05.000Z","updated_at":"2026-04-26T14:30:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dwgx/WindsurfAPI","commit_stats":null,"previous_names":["dwgx/windsurfapi"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/dwgx/WindsurfAPI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwgx%2FWindsurfAPI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwgx%2FWindsurfAPI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwgx%2FWindsurfAPI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwgx%2FWindsurfAPI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dwgx","download_url":"https://codeload.github.com/dwgx/WindsurfAPI/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwgx%2FWindsurfAPI/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32514340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-proxy","llm-gateway","openai-compatible","reverse-engineering","windsurf"],"created_at":"2026-04-23T09:01:13.093Z","updated_at":"2026-06-05T20:00:59.180Z","avatar_url":"https://github.com/dwgx.png","language":"JavaScript","funding_links":[],"categories":["Openai"],"sub_categories":[],"readme":"# Star \u0026 Follow me and I'll leave you alone\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/dwgx/WindsurfAPI/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/dwgx/WindsurfAPI?style=for-the-badge\u0026logo=github\u0026color=f5c518\" alt=\"Stars\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://github.com/dwgx\"\u003e\u003cimg src=\"https://img.shields.io/github/followers/dwgx?label=Follow\u0026style=for-the-badge\u0026logo=github\u0026color=181717\" alt=\"Follow\"\u003e\u003c/a\u003e\n  \u0026nbsp;·\u0026nbsp;\n  \u003ca href=\"README.md\"\u003e中文/简体中文\u003c/a\u003e\n\u003c/p\u003e\n\n# Notice\n\n\u003e **If you haven't starred and followed**: commercial use, resale, paid deployment, hosting as a backend for public services, or reselling as a relay service is strictly prohibited.\n\u003e **If you have starred and followed**: go ahead, I'll look the other way.\n\u003e\n\u003e The code itself is MIT-licensed (see [LICENSE](LICENSE)); the above is the author's personal stance.\n\n---\n\nTurns [Windsurf](https://windsurf.com) (formerly Codeium)'s AI models into **two standard, compatible APIs**:\n\n- `POST /v1/chat/completions` — **OpenAI Compatible** for any OpenAI SDK.\n- `POST /v1/messages` — **Anthropic Compatible** for direct connection with Claude Code / Cline / Cursor.\n\n**100+ Models**: Claude 4.5/4.6/Opus 4.7 · GPT-5/5.1/5.2/5.4 series · Gemini 2.5/3.0/3.1 · Grok · Qwen · Kimi K2.x · GLM 4.7/5/5.1 · MiniMax · SWE 1.5/1.6 · Arena, etc. Zero npm dependencies, pure Node.js.\n\n## What is it doing?\n\n```mermaid\nflowchart LR\n    subgraph Clients\n        A[OpenAI SDK\u003cbr\u003ecurl / Frontend]\n        B[Claude Code\u003cbr\u003eCline\u003cbr\u003eCursor]\n    end\n\n    subgraph WindsurfAPI[\"WindsurfAPI (Node.js)\"]\n        C[HTTP Service\u003cbr\u003ePort 3003]\n        D[Account Pool\u003cbr\u003eRound-Robin\u003cbr\u003eRate Limit\u003cbr\u003eFailover]\n    end\n\n    E[\"Language Server\u003cbr\u003e(Windsurf binary)\"]\n    F[Windsurf Cloud\u003cbr\u003eserver.self-serve.windsurf.com]\n\n    A --\u003e|\"/v1/chat/completions\"\u003cbr\u003eOpenAI JSON + SSE| C\n    B --\u003e|\"/v1/messages\"\u003cbr\u003eAnthropic SSE| C\n    C \u003c--\u003e|gRPC| E\n    E \u003c--\u003e|HTTPS| F\n    D -.-\u003e C\n```\n\n**What it does**:\n1. An HTTP service (port 3003) exposing both OpenAI and Anthropic APIs simultaneously.\n2. Translates requests into Windsurf's internal gRPC protocol and sends them to the Windsurf cloud via a local Language Server.\n3. Manages an account pool with automatic round-robin, rate limiting, and failover.\n4. Strips the upstream Windsurf identity before returning, making the model identify as \"I am Claude Opus 4.6, developed by Anthropic.\"\n\n## How to use with Claude Code / Cline / Cursor\n\nThe model itself does **not** operate on files — file operations are executed locally by the IDE Agent client (Claude Code, Cline, etc.):\n\n```mermaid\nsequenceDiagram\n    actor U as You\n    participant CC as Claude Code\n    participant WA as WindsurfAPI\n    participant WC as Windsurf Cloud\n\n    U-\u003e\u003eCC: \"Help me fix a bug\"\n    CC-\u003e\u003eWA: POST /v1/messages\u003cbr\u003emessages + tools + system\n    WA-\u003e\u003eWC: Package into Cascade request\n    WC--\u003e\u003eWA: Model thinks → returns\u003cbr\u003etool_use(edit_file)\n    WA--\u003e\u003eCC: Anthropic SSE\u003cbr\u003econtent_block=tool_use\n    CC-\u003e\u003eCC: Execute edit_file() locally\u003cbr\u003e(Read/write local files)\n    CC-\u003e\u003eWA: Send tool_result\n    WA-\u003e\u003eWC: Continue conversation...\n    loop Conversation Loop\n        WC--\u003e\u003eWA: Response\n        WA--\u003e\u003eCC: SSE stream\n    end\n    CC--\u003e\u003eU: Final answer\n```\n\n**Key Point**: WindsurfAPI is only responsible for **passing** `tool_use` / `tool_result`. The client CLI is what actually modifies the files.\n\n## Quick Start\n\n### One-Click Deployment\n\n```bash\ngit clone https://github.com/dwgx/WindsurfAPI.git\ncd WindsurfAPI\nbash setup.sh          # Create directories · Set permissions · Generate .env\nnode src/index.js\n```\n\nDashboard: `http://YOUR_IP:3003/dashboard`\n\n### Docker Deployment\n\n```bash\ncp .env.example .env\n\n# Optional: place language_server_linux_x64 under .docker-data/opt/windsurf/\n# If omitted, the container will auto-download it into /opt/windsurf/ on first boot.\n\ndocker compose up -d --build\ndocker compose logs -f\n```\n\nDefault mounts:\n\n- `./.docker-data/data`: persisted `accounts.json`, `proxy.json`, `stats.json`, `runtime-config.json`, `model-access.json`, and `logs/`\n- `./.docker-data/opt/windsurf`: Language Server binary and its data directory\n- `./.docker-data/tmp/windsurf-workspace`: temporary workspace\n\nIf you want a different persistence location, set `DATA_DIR` in `.env`. The Docker setup defaults it to `/data`.\n\n### One-Click Update\n\nTo pull the latest fixes after deployment, just run one command:\n\n```bash\ncd ~/WindsurfAPI \u0026\u0026 bash update.sh\n```\n\n`update.sh` does: `git pull` → updates the LS binary via `install-ls.sh` → stops PM2 → kills any residual process on port 3003 → restarts → health check.\n\nIf you are using our public instances (`skiapi.dev`, etc.), you don't need to do anything; we've already pushed the updates.\n\n### Manual Installation\n\n```bash\ngit clone https://github.com/dwgx/WindsurfAPI.git\ncd WindsurfAPI\n\n# Language Server binary — auto-detects Linux/macOS, one-click download + chmod\nbash install-ls.sh\n\n# Default install paths:\n#   Linux x64:           /opt/windsurf/language_server_linux_x64\n#   Linux arm64:         /opt/windsurf/language_server_linux_arm\n#   macOS Apple Silicon: $HOME/.windsurf/language_server_macos_arm\n#   macOS Intel:         $HOME/.windsurf/language_server_macos_x64\n\n# Or use a local binary you already have:\n#   bash install-ls.sh /path/to/language_server_linux_x64\n# Or specify a custom URL:\n#   bash install-ls.sh --url https://example.com/language_server_linux_x64\n\n# ⚠️ Can't see opus-4.7 / other new models?\n# The public Exafunction/codeium release is stuck at v2.12.5 (Jan 2026)\n# and does not ship 4.7. To get 4.7, copy the LS binary out of the\n# Windsurf desktop app bundle:\n#\n#   macOS:   \"$HOME/Library/Application Support/Windsurf/resources/app/extensions/windsurf/bin/language_server_macos_arm\"\n#   Linux:   \"$HOME/.windsurf/bin/language_server_linux_x64\"\n#            or /opt/Windsurf/resources/app/extensions/windsurf/bin/language_server_linux_x64\n#   Windows: %APPDATA%\\Windsurf\\bin\\language_server_windows_x64.exe\n#\n#   # Install from the local desktop copy:\n#   bash install-ls.sh /path/to/language_server_linux_x64\n#\n# Once swapped, /v1/models will auto-discover the newer catalog from the cloud.\n\ncat \u003e .env \u003c\u003c 'EOF'\nPORT=3003\nAPI_KEY=\nDEFAULT_MODEL=claude-4.5-sonnet-thinking\nMAX_TOKENS=8192\nLOG_LEVEL=info\nLS_BINARY_PATH=/opt/windsurf/language_server_linux_x64\nLS_DATA_DIR=/opt/windsurf/data\nLS_PORT=42100\nDASHBOARD_PASSWORD=\nEOF\n\n# For a local macOS run, use the LS_BINARY_PATH printed by install-ls.sh\n# and set LS_DATA_DIR to a user-writable path such as /Users/you/.windsurf/data.\n\n# Note: Inline comments are supported in .env for unquoted values:\n#   PORT=3003  # Service port\n# Quoted values preserve everything inside the quotes.\n\nnode src/index.js\n```\n\n## Add Accounts\n\nAfter the service is running, you need to add Windsurf accounts. There are three ways:\n\n**Method 1: Dashboard One-Click Login (Recommended)**\n\nOpen `http://YOUR_IP:3003/dashboard` → Login to get token → Click **Sign in with Google** or **Sign in with GitHub** (OAuth popup) or fill in email/password directly. All methods will automatically add the account to the pool.\n\n**Method 2: Token (Works with any login method)**\n\nGo to [windsurf.com/show-auth-token](https://windsurf.com/show-auth-token) to copy your token:\n\n```bash\ncurl -X POST http://localhost:3003/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"token\": \"YOUR_TOKEN\"}'\n```\n\n**Method 3: Batch**\n\n```bash\ncurl -X POST http://localhost:3003/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"accounts\": [{\"token\": \"t1\"}, {\"token\": \"t2\"}]}'\n```\n\n## Usage Examples\n\n### OpenAI Format (Python / JS / curl)\n\n```python\nfrom openai import OpenAI\nclient = OpenAI(base_url=\"http://YOUR_IP:3003/v1\", api_key=\"YOUR_API_KEY\")\nr = client.chat.completions.create(\n    model=\"claude-sonnet-4.6\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}]\n)\nprint(r.choices[0].message.content)\n```\n\n### Anthropic Format (Directly with Claude Code)\n\n```bash\nexport ANTHROPIC_BASE_URL=http://YOUR_IP:3003\nexport ANTHROPIC_API_KEY=YOUR_API_KEY\nclaude                # Use Claude Code as usual\n```\n\n```bash\n# Raw curl test\ncurl http://localhost:3003/v1/messages \\\n  -H \"Authorization: Bearer YOUR_KEY\" \\\n  -H \"anthropic-version: 2023-06-01\" \\\n  -d '{\"model\":\"claude-opus-4.6\",\"max_tokens\":100,\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'\n```\n\n### Cline / Cursor / Aider\n\nIn your client's settings for **Custom OpenAI Compatible**:\n- Base URL: `http://YOUR_IP:3003/v1`\n- API Key: YOUR_API_KEY\n- Model: Choose any supported model.\n\n\u003e **Cursor users**: Cursor's client-side whitelist blocks model names containing `claude` (the request never reaches the backend). Use these aliases instead:\n\u003e\n\u003e | Type in Cursor | Actual model |\n\u003e |---|---|\n\u003e | `opus-4.6` | claude-opus-4.6 |\n\u003e | `sonnet-4.6` | claude-sonnet-4.6 |\n\u003e | `opus-4.7` | claude-opus-4-7-medium |\n\u003e | `ws-opus` | claude-opus-4.6 |\n\u003e | `ws-sonnet` | claude-sonnet-4.6 |\n\u003e\n\u003e GPT / Gemini / DeepSeek models are not affected by Cursor's filter — use their original names.\n\n## Environment Variables\n\n| Variable | Default | Description |\n|---|---|---|\n| `PORT` | `3003` | Service port |\n| `API_KEY` | empty | API key required for requests. Leave empty to disable validation. |\n| `DATA_DIR` | project root | Directory for persisted JSON state and `logs/`. Docker deployments should usually use `/data`. |\n| `CODEIUM_API_KEY` | empty | Direct API key from Windsurf (alternative to token-based auth). |\n| `CODEIUM_AUTH_TOKEN` | empty | Token from [windsurf.com/show-auth-token](https://windsurf.com/show-auth-token). |\n| `CODEIUM_EMAIL` | empty | Email for Windsurf account authentication. |\n| `CODEIUM_PASSWORD` | empty | Password for Windsurf account authentication. |\n| `CODEIUM_API_URL` | `https://server.self-serve.windsurf.com` | Windsurf cloud API endpoint. |\n| `DEFAULT_MODEL` | `claude-4.5-sonnet-thinking` | The model to use if `model` is not specified. |\n| `MAX_TOKENS` | `8192` | Default maximum number of response tokens. |\n| `LOG_LEVEL` | `info` | debug / info / warn / error |\n| `LS_BINARY_PATH` | `/opt/windsurf/language_server_linux_x64` | Path to the LS binary. |\n| `LS_PORT` | `42100` | LS gRPC port. |\n| `LS_DATA_DIR` | Linux: `/opt/windsurf/data`; macOS: `~/.windsurf/data` | Per-proxy LS data directory root. |\n| `LS_MAX_INSTANCES` | adaptive, max `20` | Maximum LS pool size. The adaptive default reserves at least one non-default proxy slot on small hosts. |\n| `LS_SPAWN_MIN_AVAILABLE_BYTES` | `700MB` | Minimum available memory required before starting a new non-default LS. |\n| `LS_PREWARM_DEFAULT` | `1` | Set to `0` to skip startup default-LS prewarm and start LS lazily on first request. Useful for low-memory, all-proxy pools. |\n| `LS_PREWARM_PROXIES` | `0` | Set to `1` to prewarm all proxy LS instances on startup. Scheduled probes and predictive prewarm only reuse idle resident LS instances. |\n| `LS_PREWARM_ON_ACCOUNT_ADD` | `0` | Set to `1` to prewarm LS immediately after dashboard/import/OAuth account add. Default avoids memory spikes during bulk import. |\n| `WINDSURFAPI_NATIVE_TOOL_BRIDGE` | empty | `all_mapped` enables native bridge only when every tool is in the Read/Bash/Grep/Glob semantic families; `1` enables partition mode for mixed toolsets. WebSearch/WebFetch stay on prompt emulation unless explicitly allowlisted. |\n| `WINDSURFAPI_NATIVE_TOOL_BRIDGE_TOOLS` | Read/Bash/Grep/Glob families | Tool allowlist for native bridge. Defaults include aliases such as `read_file`, `view_file`, `shell_command`, `run_command`, `grep_search_v2`, and `find`; excludes WebSearch/WebFetch. |\n| `WINDSURFAPI_NATIVE_TOOL_BRIDGE_MODELS` / `PROVIDERS` / `ROUTES` / `CALLERS` / `ACCOUNTS` / `API_KEYS` | empty | Optional native-bridge gray gates. Empty means unrestricted; when set, the request must match. `ACCOUNTS` accepts upstream account id/email. `API_KEYS` matches caller API keys without passing plaintext tokens into chat logic. |\n| `WINDSURFAPI_NATIVE_TOOL_BRIDGE_OFF` | empty | Set to `1` to force native bridge off. |\n| `WINDSURFAPI_SPECIAL_AGENT_BACKEND` | empty | Optional special-agent backend. Set `devin-cli` to route `swe-1.6`, `swe-1.6-fast`, `adaptive`, and `arena-*` through Devin CLI instead of direct Cascade. |\n| `DEVIN_CLI_PATH` | `devin` | Devin CLI executable path. Docker/macOS deployments must install or mount it themselves. |\n| `DEVIN_CLI_MODE` | `print` | `print` uses conservative `devin -p`; `acp` is an experimental ACP stdio backend using upstream Windsurf account-pool apiKeys. |\n| `DEVIN_MAX_PROCS` | `1` | Maximum concurrent Devin CLI processes. |\n| `DASHBOARD_PASSWORD` | empty | Dashboard password. Leave empty for no password. |\n| `ALLOW_PRIVATE_PROXY_HOSTS` | empty | Set to `1` to allow private/internal IPs (e.g., `192.168.x.x`, `10.x.x.x`) in proxy tests and login. Leave empty to only allow public addresses (default). |\n| `CASCADE_REUSE_STRICT` | `0` | Set to `1` for strict conversation reuse mode (waits for same fingerprint). |\n| `CASCADE_REUSE_STRICT_RETRY_MS` | `60000` | Retry delay in ms for strict reuse mode. |\n| `CASCADE_REUSE_HASH_SYSTEM` | `0` | Set to `1` to include system messages in conversation reuse hash. |\n| `CASCADE_REUSE_BY_CALLER` | `0` | Set to `1` to enable caller-based fallback reuse. When fingerprint misses, falls back to the latest cascade for the same caller+model. Best for single-user Claude Code setups. |\n| `CASCADE_POOL_MAX` | `500` | Max conversation pool entries. Set to `1`–`5` for single-user setups to minimize resource usage. |\n\n## Dashboard Features\n\nOpen `http://YOUR_IP:3003/dashboard`:\n\n| Panel | Features |\n|---|---|\n| **Overview** | Runtime status · Account pool · LS health · Success rate |\n| **Login/Get Token** | Google / GitHub OAuth one-click login · Email/password login · **Test Proxy** button (tests egress IP) |\n| **Account Management** | Add / Delete / Disable · Detect subscription level · Check balance · Ban models via blacklist |\n| **Model Control** | Global model whitelist/blacklist |\n| **Proxy Config** | Global or per-account HTTP / SOCKS5 proxy |\n| **Logs** | Real-time SSE streaming · Filter by level · `turns=N chars=M` diagnostics per turn |\n| **Stats \u0026 Analytics** | Time range 6h / 24h / 72h · Per-account dimensions · p50 / p95 latency |\n| **Experimental** | Cascade conversation reuse · **Model Identity Injection (custom prompt per vendor)** |\n\n## Supported Models\n\n100+ static models in the main catalog plus dynamic cloud-side models added at startup via `mergeCloudModels`. Full list: `GET /v1/models`, or browse the [GitHub Pages model catalog](https://dwgx.github.io/WindsurfAPI/#models) (auto-generated from `src/models.js`).\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eClaude (Anthropic)\u003c/b\u003e — 21 models\u003c/summary\u003e\n\nclaude-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 (incl. 1m / thinking / thinking-1m) · claude-opus-4.6 / thinking · **claude-opus-4.7-medium**\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eGPT (OpenAI)\u003c/b\u003e — 55 models\u003c/summary\u003e\n\ngpt-4o · gpt-4.1 · gpt-5 series (incl. medium / high / codex) · **gpt-5.1 series** (base / low / medium / high + fast + codex, all 6 variants) · **gpt-5.2 series** (none / low / medium / high / xhigh + fast + codex) · **gpt-5.4 series** (base / mini × low/medium/high/xhigh) · o3 series (base / mini / pro) · o4-mini\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eGemini (Google)\u003c/b\u003e — 9 models\u003c/summary\u003e\n\ngemini-2.5-pro / flash · gemini-3.0-pro / flash (minimal / low / medium / high — 4 reasoning levels) · gemini-3.1-pro (low / high)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eOpen source / Chinese providers\u003c/b\u003e\u003c/summary\u003e\n\n**Kimi**: kimi-k2 / k2.5 / k2-6 · **GLM**: glm-4.7 / 5 / 5.1 · **Qwen**: qwen-3 · **Grok**: grok-3 / grok-3-mini-thinking / grok-code-fast-1 · **MiniMax**: minimax-m2.5\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eWindsurf in-house + Arena\u003c/b\u003e\u003c/summary\u003e\n\nswe-1.5 / 1.5-fast / 1.6 / 1.6-fast · arena-fast · arena-smart\n\n\u003c/details\u003e\n\n\u003e **Free-account entitlements** typically include `gemini-2.5-flash`, `glm-4.7` / `glm-5` / `5.1`, `kimi-k2` / `k2.5` / `k2-6`, `qwen-3` and similar open-source models; Claude family, GPT family, and Opus / thinking variants require Pro. Each account's exact list shows up in the dashboard.\n\u003e\n\u003e **Tool-calling reliability (measured v2.0.82+):** Claude family is the most reliable (their training covered prompt-level tool protocols); GLM-4.7 / Kimi-K2.5 work for most cases via NLU fallback + optional retry-with-correction; GLM-5.1 is unreliable on the cascade backend (it often returns empty responses, no narration to recover from); GPT family is also limited because the cascade upstream doesn't carry `tools[]` schema. For Claude Code / Cline / Codex doing local tool calls, prefer `claude-haiku-4.5` or `claude-sonnet-4.6`.\n\n### Language-Following for CJK Users\n\nThe service automatically detects Chinese, Japanese, or Korean characters in your messages and injects a language-following hint to ensure the model responds in the same language. This fixes the issue where Claude Code's large English system prompt would override the communication language.\n\n## Architecture Highlights\n\n- **Zero npm dependencies** Everything uses `node:*` built-ins · Protobuf is handcrafted (`src/proto.js`) · Download and run.\n- **Account Pool + LS Pool** Each independent proxy gets its own LS instance, no mixing.\n- **NO_TOOL Mode** `planner_mode=3` disables Cascade's built-in tool loop to prevent `/tmp/windsurf-workspace/` path leakage.\n- **Three-layer sanitization** LS built-in tool result filtering · `\u003ctool_call\u003e` text parsing · Output path cleaning.\n- **Real token counting** Fetches real `inputTokens` / `outputTokens` / `cacheRead` / `cacheWrite` from `CortexStepMetadata.model_usage`. `prompt_tokens` includes cacheWrite.\n\n## PM2 Deployment\n\n```bash\nnpm install -g pm2\npm2 start src/index.js --name windsurf-api\npm2 save \u0026\u0026 pm2 startup\n```\n\n**Do not** use `pm2 restart` (it can create zombie processes). Use the one-click update script `bash update.sh`.\n\n## Firewall\n\n```bash\n# Ubuntu\nufw allow 3003/tcp\n\n# CentOS\nfirewall-cmd --add-port=3003/tcp --permanent \u0026\u0026 firewall-cmd --reload\n```\n\nRemember to open port 3003 in your cloud provider's security group.\n\n## FAQ\n\n**Q: Login fails with \"Invalid email or password\"**\nA: You probably signed up for Windsurf using Google/GitHub, which means your account doesn't have a password. The Dashboard's login panel now directly supports one-click login via Google / GitHub OAuth.\n\n**Q: The model says \"I cannot operate on the file system\"**\nA: This is a **chat API**, not an IDE agent. To have the model actually modify files, use a client CLI like **Claude Code / Cline / Cursor / Aider** and point their API base URL to this service. The model will produce `tool_use`, the client executes it locally, and sends the `tool_result` back. The diagram above shows the detailed flow.\n\n**Q: Context is lost / The model forgets previous parts of the conversation**\nA: Multi-account round-robin will **not** lose context — every request repackages the full history and sends it to Cascade. The real reason is usually a relay layer (like new-api) not passing the full `messages[]` array. Check `turns=N` in the Dashboard logs: if it's a multi-turn conversation but `turns=1`, then a layer before you has already dropped the history.\n\n**Q: Long prompts are timing out**\nA: This has been fixed. Cold stall detection is now adaptive to input length, with a max timeout of 90s for long inputs.\n\n**Q: Can I use Claude Code?**\nA: Yes. `export ANTHROPIC_BASE_URL=http://YOUR_API` + `export ANTHROPIC_API_KEY=YOUR_KEY`. `/v1/messages` supports the full suite: system, tools, tool_use, tool_result, stream, and multi-turn, all tested and working.\n\n**Q: What models can free accounts use?**\nA: Mostly `gemini-2.5-flash`, `glm-4.7` / `5` / `5.1`, `kimi-k2` / `k2.5` / `k2-6`, `qwen-3` (open-source series). Claude family, GPT family, and Opus / Max / -thinking variants need Pro entitlement. The dashboard shows each account's entitled list, and `model_not_entitled` error responses include an `available_in_pool` field with the names you can switch to.\n\n**Q: Are tool calls reliable on free accounts?**\nA: Depends on the model. Claude family is rock-solid (also free-account-entitled when available). GLM-4.7 / Kimi-K2.5 work in most cases via NLU recovery + `WINDSURFAPI_NLU_RETRY=1` retry-with-correction. GLM-5.1 is unreliable on the cascade backend (frequent empty responses) — proxy can't fix this. GPT family is similarly limited by the cascade protocol layer not passing `tools[]` schema. **For Claude Code / Cline / Codex doing local file/shell ops prefer `claude-haiku-4.5` or `claude-sonnet-4.6`.**\n\n**Q: 31 trial accounts go unavailable after a few hundred calls**\nA: Likely the model is a weekly-quota variant — `claude-opus-4-7-max` / `gpt-5.5-xhigh` / `claude-sonnet-4-7-thinking` etc. cap at 5 calls per week per account, so 31 accounts × 5 ≈ 150 calls hit the wall fast. Switch to `claude-sonnet-4.6` / `claude-haiku-4.5` (daily quotas are much wider). Verify with `docker logs windsurfapi-windsurf-api-1 | grep rate_limit` — the per-account cooldown reason is in the log.\n\n## Contributors\n\nHuge thanks to the following folks who sent pull requests or systematically audited the code:\n\n- [@dd373156](https://github.com/dd373156) — [PR #1](https://github.com/dwgx/WindsurfAPI/pull/1)\n  Fixed the Pro tier model-merge logic: the hardcoded table wasn't picking up dynamically-fetched cloud models, so Pro accounts couldn't see newly-released models in Cursor / Cherry Studio.\n- [@colin1112a](https://github.com/colin1112a) — [PR #13](https://github.com/dwgx/WindsurfAPI/pull/13)\n  A single-shot audit that flagged 15 security / concurrency / resource bugs: XSS escaping, shell injection, OOM guards, auth route placement, gRPC double-callback, LS pool race, HTTP/2 frame size caps, and more. On top of this we later added a JS-level `escJsAttr`, coalesced concurrent `ensureLs` calls via `_pending`, released pooled sessions on LS exit, and fixed 6 more issues surfaced by a follow-up Antigravity audit.\n- [@baily-zhang](https://github.com/baily-zhang) — [PR #36](https://github.com/dwgx/WindsurfAPI/pull/36) + [PR #45](https://github.com/dwgx/WindsurfAPI/pull/45)\n  Core Cascade reuse fixes: stableTurns fingerprinting (#36) solved 0% hit rate; trajectory offset tracking (#45) eliminated context bloat during multi-turn reuse.\n- [@aict666](https://github.com/aict666) — [PR #44](https://github.com/dwgx/WindsurfAPI/pull/44)\n  Fixed inferTier demoting Pro/Trial accounts to free after every chat call, preserving the authoritative tier from GetUserStatus.\n- [@smeinecke](https://github.com/smeinecke) — [PR #43](https://github.com/dwgx/WindsurfAPI/pull/43)\n  Full Dashboard i18n: 14 commits covering Chinese/English translations, I18n system, and check-i18n.js validation tool.\n- [@you922](https://github.com/you922) — [PR #162](https://github.com/dwgx/WindsurfAPI/pull/162) + [PR #163](https://github.com/dwgx/WindsurfAPI/pull/163)\n  Built sticky session from scratch (callerKey + modelKey → accountId binding) + LS crash auto-restart with exponential backoff. Also provided root-cause analysis of SectionOverrideConfig tool-call suppression in #164.\n- [@Fermiz](https://github.com/Fermiz) — [PR #181](https://github.com/dwgx/WindsurfAPI/pull/181)\n  Cascade reuse optimization for single-user setups (skip unnecessary rotation) + HTTPS proxy layer + configurable conversation-pool size.\n- [@linqichenggg](https://github.com/linqichenggg) — [PR #175](https://github.com/dwgx/WindsurfAPI/pull/175)\n  Cross-platform LS path alignment: unified binary paths, data dirs, and install scripts across Windows / macOS / Linux.\n- [@lauvww](https://github.com/lauvww) — [PR #182](https://github.com/dwgx/WindsurfAPI/pull/182)\n  Rewrote dashboard batch import parser: supports JSON / CSV / plain text mixed paste with auto-detection.\n- [@ucloudnb666](https://github.com/ucloudnb666) — [PR #184](https://github.com/dwgx/WindsurfAPI/pull/184)\n  Added Astraflow as a third-party provider.\n- [@datfooldive](https://github.com/datfooldive) — [PR #173](https://github.com/dwgx/WindsurfAPI/pull/173)\n  Dashboard UI overhaul: unified component styles, improved card layouts and responsive design.\n- [@The-five-stooges](https://github.com/The-five-stooges) — [PR #188](https://github.com/dwgx/WindsurfAPI/pull/188)\n  Sticky session streaming-path fix + body.user multi-user isolation + stickyNoFallback / stickyBindByUserOnly toggles.\n- [@andya1lan](https://github.com/andya1lan) — [PR #192](https://github.com/dwgx/WindsurfAPI/pull/192)\n  Routed `update.sh` LS binary updates through `install-ls.sh`, aligned the WindsurfAPI / Windsurf desktop LS / Exafunction source chain, and fixed macOS `grep -P` compatibility.\n\nWant to be on this list? Open an [issue](https://github.com/dwgx/WindsurfAPI/issues) or a [pull request](https://github.com/dwgx/WindsurfAPI/pulls). The dashboard has a Credits panel on the left that shows the same info.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwgx%2Fwindsurfapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdwgx%2Fwindsurfapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwgx%2Fwindsurfapi/lists"}