Architecture Review · 2026-06-17 · counts refreshed 2026-10-26

从启动入口读完整个 WindsurfAPI

这页把项目按运行路径拆开:Node 入口、HTTP 路由、OpenAI/Anthropic 兼容层、Windsurf Cascade 协议桥、账号池、LangServer 池、工具调用、Dashboard、部署与测试。它不是发布公告,而是给维护者和代码阅读者看的项目地图。

Position

项目定位

WindsurfAPI 是一个零依赖 Node.js 本地代理,把 Windsurf / Codeium 的本地 Language Server 和 Cascade 云端能力包装成常见 SDK 能直接接入的 API 面。

兼容 API 网关

同一进程暴露 OpenAI Chat Completions、OpenAI Responses 和 Anthropic Messages 三套入口,内部统一落到 chat handler 和 Cascade 请求模型。

/v1/chat/completions/v1/responses/v1/messages

账号与 LS 池

账号池负责 API key、token、限流、能力探测和模型可用性;LangServer 池按默认实例或代理实例启动、复用和回收本地 LS 进程。

src/auth.jssrc/langserver.js

协议翻译层

核心协议层把标准请求翻译成 RawGetChatMessage 或 Cascade trajectory,再把上游文本、thinking、tool calls、usage 和错误翻译回客户端格式。

src/client.jssrc/windsurf.jssrc/grpc.js
这个项目不在服务端直接操作调用方本地文件。标准路径是代理产生或转译 tool_use / tool_calls,由 Claude Code、Cline、Cursor、Aider 等客户端在调用方机器上执行工具并把结果送回下一轮。
Startup

启动链路

入口是 node src/index.js。启动路径先准备运行环境,再启动 HTTP 服务;LS 缺失时会告警并继续提供健康检查和管理面,关闭路径负责中止 SSE、保存账号状态和停止 LS。

加载 logger 与配置

src/index.js 首行导入 dashboard logger,然后读 config、版本信息和核心模块。

准备 workspace

当 LS binary 存在时,resetWorkspace() 清空临时 workspace,避免上次 Cascade 工具痕迹污染新会话。

准备 LangServer

缺二进制时按平台提示或自动安装;HTTP 仍会启动,LS 可预热 default 实例,也可按配置延迟到首个请求。

初始化账号池

initAuth() 读取和迁移账号状态,后台刷新 Firebase token、能力探测和 drought 摘要。

启动 HTTP

startServer() 注册路由、CORS、认证门和 Dashboard 静态页;信号处理和 graceful shutdown 留在 src/index.js。

Source: src/index.js, src/server.js, src/config.js

Cascade Flow

Windsurf / Cascade 协议链路

内部不是把 HTTP 请求直接转发到一个云 API,而是和本地 Language Server 说 gRPC。Cascade 路径先初始化 panel/workspace,再启动 cascade,发送用户消息,然后轮询 trajectory。

Panel warmup

InitializeCascadePanelState、AddTrackedWorkspace、UpdateWorkspaceTrust、Heartbeat 建立 LS 侧状态。

StartCascade

WindsurfClient.cascadeChat() 调用 buildStartCascadeRequest() 拿到 cascade_id。

Send message

buildSendCascadeMessageRequest() 拼装模型、history、tool preamble、native allowlist 和附加步骤。

Poll trajectory

循环读取 GetCascadeTrajectorySteps 和 GetCascadeTrajectory,只把新增 text/thinking/tool step 发给上层。

Reuse context

conversation-pool 复用 cascade_id,按 caller、model、tools、history、LS generation 做隔离。

Transport split

src/grpc.js 管 HTTP/2 gRPC session、unary 和 stream;src/connect.js 是可选 Connect envelope;src/proto.js 是 schema-less wire codec;src/windsurf.js 才是业务 protobuf builder/parser。

Trace boundary

WINDSURFAPI_PROTO_TRACE=1 才开启协议 trace。默认只记录长度、hash、字段树和语义摘要;字符串 preview 属于受控调试开关,不适合公网长期打开。

Repository Tree

目录树读法

这个仓库不是传统 MVC。更准确的读法是:入口层、兼容 handler、Cascade 协议层、账号/LS 运行时、Dashboard 管理面、测试与 docs。

WindsurfAPI ├─ src/index.js process entry, LS bootstrap, shutdown ├─ src/server.js HTTP route hub, auth gate, body limit ├─ src/handlers/ │ ├─ chat.js OpenAI Chat core pipeline │ ├─ responses.js Responses API adapter │ ├─ messages.js Anthropic Messages adapter │ ├─ tool-emulation.js prompt-level tool protocol │ └─ intent-extractor.js narrative tool-call recovery ├─ src/client.js WindsurfClient, Cascade loop, polling ├─ src/windsurf.js protobuf builders and parsers ├─ src/grpc.js / connect.js HTTP/2 gRPC and Connect transport ├─ src/auth.js account pool, rate limits, probes ├─ src/langserver.js LS process pool, memory guard, proxy keys ├─ src/cascade-native-bridge.js native tool bridge mapping and gates ├─ src/dashboard/ management API, UI, i18n, self-update ├─ scripts/ smoke tests, docs model generation, scans ├─ test/ focused unit/integration invariants └─ docs/ public site, maintainer docs, audits
HTTP Surface

路由表

src/server.js 直接按路径分发。/health 基础响应公开且包含部署指纹;verbose health、API 路由和管理读写动作分别经过 API key 或 dashboard password 边界。

RouteHandlerRoleBoundary
GET /healthroute()版本、commit、branch、uptime、账号计数;带合法 key 和 verbose=1 时附加池/缓存/native 状态。基础公开;公网可在反代层限制。
GET /v1/modelshandleModels()返回 OpenAI 格式模型目录。API key gate。
POST /v1/chat/completionshandleChatCompletions()主 OpenAI Chat 路径,处理模型解析、账号选择、Cascade、stream、tool calls、usage。API key + account pool。
POST /v1/responseshandleResponses()把 Responses input/tool/text format 转成 chat,再把 SSE/非流式结果转回 Responses 事件;/v1/response 是兼容别名。API key + account pool + input validation。
POST /v1/messageshandleMessages()Anthropic Messages 兼容层,转换 system/content/tool_use/tool_result/thinking/cache policy。API key + Anthropic error shape。
/auth/*auth.js helpers账号添加、列表、删除、状态。API key gate。
GET /dashboard, /dashboard/i18n/*, /dashboard/data/*route()Dashboard shell、翻译 JSON、贡献者等静态数据。公开静态资源;文件名白名单。
/dashboard/api/*handleDashboardApi()账号、代理、模型访问、自更新、日志、运行时凭证等 operator 管理动作。X-Dashboard-Password;公网无密码 fail closed。
Core Methods

核心模块与方法

SubsystemFilesKey methodsWhat to know before editing
Chat pipelinesrc/handlers/chat.jshandleChatCompletions, buildToolRoutingPlan, filterToolCallsByAllowlist这是最大文件,也是语义中心。改动会影响 stream、non-stream、tool calls、cache、account retry 和 conversation reuse。
Protocol bridgesrc/client.js, src/windsurf.jsWindsurfClient.cascadeChat, buildSendCascadeMessageRequest, parseTrajectoryStepsCascade 是 StartCascade -> SendUserCascadeMessage -> poll trajectory/generator metadata 的状态机,timeout 和 retry 不是普通 HTTP retry。
Transportsrc/grpc.js, src/connect.js, src/proto.jsgrpcUnary, grpcStream, StreamingFrameParser, parseFieldsgRPC 是默认路径,Connect 可用环境变量切换;proto 层是手写最小编码/解析器。
Accountssrc/auth.js, src/account/sticky-session.jsinitAuth, getApiKey, releaseAccount, probeAccount账号选择同时看模型权限、RPM、错误状态、drought、sticky caller 和后台维护状态。
LangServer poolsrc/langserver.jsensureLs, getLsAdmissionStatus, getLsMemoryGuardStatus每个代理可以有独立 LS,池容量受内存、空闲回收、pending start reservation 和进程健康影响。
Toolstool-emulation.js, intent-extractor.js, cascade-native-bridge.jsbuildToolPreamble, extractIntentFromNarrative, getNativeBridgeDecision默认安全路径是 prompt-level emulation;native bridge 只在显式 gate 下把映射工具送进 Cascade planner。
Dashboardsrc/dashboard/api.js, src/dashboard/index.htmlhandleDashboardApi, checkAuth, parseProxyUrl管理面可改凭证、代理、LS、自更新、模型访问;公网绑定必须有明确 dashboard password。
Compatibility

三套 API 如何收敛

OpenAI Chat

handleChatCompletions() 是内部主干,负责模型解析、账号选择、LS 获取、Cascade/legacy 分流、stream/non-stream、cache、tool routing 和错误响应。

handleChatCompletionsstreamResponsenonStreamResponse

Anthropic Messages

handleMessages() 先把 system、content blocks、tool_use、tool_result、thinking 和 cache policy 转成内部 Chat 形态,再把结果转回 Anthropic event/message。

anthropicToOpenAIopenAIToAnthropicAnthropicStreamTranslator

OpenAI Responses

handleResponses() 把 instructions、input items、function_call、custom tool、web_search 和 text.format 归一成 Chat 请求,再把 SSE 转成 Responses 生命周期事件。

responsesToChatflattenResponseToolresponse.completed
Responses 的 file_search、computer_use_preview、mcp 这类 server-side tools 当前不会被伪装成已实现能力;适配层会丢弃无法桥接的 server-side tool 类型,保留普通 function tool 路径。
State Flow

数据与状态

持久化状态

DATA_DIR 收敛账号、运行时配置、统计、日志等 JSON/日志状态。Docker 默认挂载到 /data,本地默认使用项目根或配置目录。

accounts.jsonruntime-config.jsonstats.jsonlogs/

运行时池

请求进入 handler 后先解析模型和调用方 key,再从账号池取一个可用账号,按账号代理确保 LS 实例,最后用对应 port/csrfToken 调用 WindsurfClient。

callerKeyaccount reservationLS keycascade id

账号选择

账号池不是简单 round-robin。选择会综合 active 状态、模型 entitlement、per-model cooldown、RPM、inflight、quota score、sticky binding 和 caller hash。

getApiKeyquotaScoresticky-session

LS admission

LangServer 池按 default/proxy key 隔离,启动前检查 pool 容量、pending start reservation、内存水位和 idle non-default 可驱逐实例。

ensureLsgetLsAdmissionStatusmemory guard
Native bridge、local Windsurf import、Dashboard self-update、runtime credential rotation 都是管理面或实验能力。公开说明里应把这些写成有边界的 operator features,而不是默认推荐路径。
Tool Routing

工具调用路径

默认:prompt-level emulation

Cascade 请求没有 OpenAI tools[] 原生槽位,代理把工具 schema 压缩成文本协议,让模型输出 tool marker,再解析回 OpenAI/Anthropic tool call。

buildToolPreambleForProtoToolCallStreamParser

恢复:NLU recovery

当模型用自然语言说“我要调用工具”但没有按协议输出 marker,intent-extractor 会在声明工具 allowlist 内做保守恢复,非流式路径还可二次 correction。

extractIntentFromNarrativedetectToolIntentInNarrative

实验:native bridge

显式开启后,映射且 allowlist 的工具可进入 Cascade native planner;未映射工具继续走 emulation。默认不把本地 IDE 工具改成远端执行。

getNativeBridgeDecisionpartitionToolsTOOL_MAP
Special-agent 是另一条旁路:swe-1.6、adaptive、arena-* 等需要显式 WINDSURFAPI_SPECIAL_AGENT_BACKEND=devin-cli,默认拒绝 caller-local tools 和 media。
Security Boundaries

安全边界

Fail closed auth
API 路由使用 Authorization: Bearer 或 x-api-key;API_KEY 持有者等同账号池管理员,公网 Dashboard API 仍必须单独设置 DASHBOARD_PASSWORD。
Bounded ingress
HTTP body 上限是 10MB;Dashboard 静态 JSON 文件名有 basename regex;日志和 key 输出走 masking/redaction。
Opt-in remote tools
native bridge 默认不作为本地 IDE 工具修复开关;映射、allowlist、模型/账号/API key gate 都需要谨慎配置。

Dashboard operator surface

Dashboard shell 可以公开加载,真正的管理读写动作在 /dashboard/api/*。公开部署时必须把 API_KEY 与 DASHBOARD_PASSWORD 都当成高权限 secret;localhost-only 部署才保留便利 fallback。

SSRF and secret posture

Dashboard proxy test、账号添加、batch import、/auth/login 与 proxy setters 默认拒绝本机、私网、metadata 地址,除非显式设置 ALLOW_PRIVATE_PROXY_HOSTS=1;导出日志前仍应复核敏感上下文。

Docker self-update 只在 git 不可用且部署显式挂载 /var/run/docker.sock 时进入 fallback;docker socket 等价于把宿主机 Docker 控制权交给管理面,只适合可信单操作者环境。

Health metadata

基础 /health 公开返回版本、Git 和账号计数等部署指纹;公网部署若不希望暴露这些字段,应在反向代理层限制访问。

Secret handling

Secret scan 只打印 path/rule,不打印命中的 secret 值;核心日志路径使用 hash/masking 引用账号、邮箱和 key,但日志导出仍属于管理面数据。

Relevant tests: dashboard-auth-fail-closed.test.js, dashboard-brute-force.test.js, secret-scan.test.js, ssrf.test.js, log-safety.test.js, native-tool-routing.test.js.

Test Coverage

测试覆盖地图

npm test 当前覆盖根层 test/*.test.js 的 593 个测试文件(2026-10-26 最终树实测),集中覆盖 handler/tool/native/account/dashboard 等风险面。下面按文件名归类的是 2026-06-17 的 114 文件样本,实际 CI 以 npm test 和 npm run test:release 为准。

22API handlers, stream, cache, tools
18auth, accounts, rate limits
12dashboard and deploy
12protocol and LangServer
9native bridge and special agent
5explicit security tests
36compatibility and regressions
分类框保留 2026-06-17 的 114 文件快照;当前根层测试文件为 593(2026-10-26 最终树实测)。

Release gate

npm run test:release focuses on cache, dashboard API/syntax, native bridge docs, proto trace, secret scan, shard script, release workflow and version checks.

Broad gate

npm test runs the test files under test/*.test.js with Node's built-in test runner and force-exit behavior for long-running handles.

这些测试不等同于真实上游 smoke:真实 Windsurf LS、真实网络登录、浏览器端完整交互和 Docker socket 自更新仍需要按部署环境单独验证。