Architecture Review · 2026-06-17

从启动入口读完整个 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

InitializeCascadePanelStateAddTrackedWorkspaceUpdateWorkspaceTrustHeartbeat 建立 LS 侧状态。

StartCascade

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

Send message

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

Poll trajectory

循环读取 GetCascadeTrajectoryStepsGetCascadeTrajectory,只把新增 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_usetool_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_searchcomputer_use_previewmcp 这类 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.6adaptivearena-* 等需要显式 WINDSURFAPI_SPECIAL_AGENT_BACKEND=devin-cli,默认拒绝 caller-local tools 和 media。
Security Boundaries

安全边界

Fail closed auth
API 路由使用 Authorization: Bearerx-api-keyAPI_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_KEYDASHBOARD_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 的 114 个测试文件,集中覆盖 handler/tool/native/account/dashboard 等风险面。下面按文件名归类,实际 CI 以 npm testnpm 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

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 自更新仍需要按部署环境单独验证。