Bridge API 是什么?
本地运行的 AI Provider Runtime —— 一个 API,连接所有 AI 网页

1. 概述与定位
Bridge API 是一个运行在用户本机的 AI Provider Runtime。它对外提供统一的 OpenAI Compatible API(/v1/chat/completions、/v1/models),并在内部通过 Chrome 扩展把请求转发给已经登录的 DeepSeek 网页。账号、Cookie 与项目文件全程不离开本机,Bridge 不保存账号、不代理账号、不托管 Cookie。
| 它“不是”什么 | 它“是”什么 |
|---|---|
| 不是 DeepSeek 官方 API(无需 API Key) | AI Provider Runtime,DeepSeek 只是第一个 Provider |
| 不是单纯浏览器插件(插件只控制网页) | 本地文件系统 / Git 能力的受保护网关 |
| 不是一个被绑定的模型(Provider 无关) | 让任意 OpenAI 客户端直接调用浏览器里的 AI |
核心设计原则:Provider 无关、本地优先、开放接口、模块化扩展、最小权限。所有项目读取、Git 分析、上下文构建均在本地完成。
2. 系统架构
Bridge API 由三层组成:左侧任意 OpenAI 客户端、中间本地 Runtime、右侧浏览器与本地项目。Runtime 是唯一的“大脑”,所有业务逻辑都收敛在这里;浏览器扩展只是 DOM 控制终端,Native Host 是最小权限的文件系统代理。
关键解耦点:扩展不持有文件系统权限,文件访问要么由 Runtime 直接执行(当前 MVP),要么经由 Native Host 的白名单协议;浏览器侧只负责把 Prompt 写进网页、把回答读出来,业务规则(鉴权、队列、路径安全、工具解析)全部在 Runtime 完成。
3. 技术栈与工程结构
项目是一个 npm workspaces 单仓(monorepo),包含 apps/*、packages/*、providers/* 三组包。运行时直接以 node --experimental-strip-types 执行 TypeScript(Node 22+),无需构建步骤;类型检查用 tsc --noEmit。
bridge-api/
├── apps/
│ ├── runtime/ # 核心 Runtime 入口(src/index.ts, server.ts, config.ts)
│ │ └── public/ # 本地图形控制台(index.html / app.js / styles.css)
│ ├── cli/ # bridge CLI(纯 HTTP 客户端)
│ ├── extension/ # Chrome MV3 扩展(background.js, content.js, popup.*)
│ └── native-host/ # 最小权限 Native Messaging Host(协议骨架)
├── packages/
│ ├── protocol/ # 类型契约:ChatMessage, ChatDelta, Provider, BrowserCommand/Event
│ ├── provider-manager/ # Provider 注册、切换、健康检查
│ ├── browser-bridge/ # Runtime ↔ 扩展的命令/事件桥
│ ├── agent-engine/ # 多轮代码代理 + 工具协议解析
│ ├── context-engine/ # ripgrep 检索 + 上下文构建
│ ├── project-engine/ # 多项目管理、路径保护、读写替身脱敏
│ ├── tool-engine/ # 工具执行、待批准变更
│ ├── git-engine/ # git status / diff 封装
│ ├── security-engine/ # 敏感路径判定、密钥脱敏
│ ├── queue/ # 单任务串行队列
│ └── shared/ # createId / toErrorMessage / expandHome
├── providers/
│ └── deepseek/ # DeepSeekWebProvider(实现 Provider 契约)
├── tests/ # core.test.ts(node --test)
├── PRD.md README.md progress.md package.json tsconfig.json
各 packages/* 之间是显式的依赖关系(通过相对 ../../packages/xxx/src/index.ts 导入),运行时由 apps/runtime/src/index.ts 统一实例化并注入:
const browser = new BrowserBridge();
const projects = new ProjectEngine(config.workspace, config.projects);
const git = new GitEngine();
const providers = new ProviderManager([new DeepSeekWebProvider(browser)], config.provider);
const context = new ContextEngine(projects, git);
const tools = new ToolEngine(projects, context, git);
const agent = new AgentEngine(providers, projects, tools);
const server = createRuntimeServer({ config, browser, providers, projects, context, git, queue, tools, agent });
4. 一次对话请求的完整生命周期
所有请求进入 createRuntimeServer 的单一 Node http 处理器。下面以 POST /v1/chat/completions 为主线,展示从鉴权到 SSE 输出的全过程。
SSE 通道约定:模型正文走
data:帧;Bridge 内部状态(队列位置、心跳)走 注释帧: bridge-status ...,避免被 OpenAI 客户端误并入回答。OpenAI 客户端会把每个data:帧当作模型输出,因此内部状态必须放在注释帧里,只有图形控制台会读取并展示。
5. 多轮本地代码代理
当请求被判定为“代码请求”(bridge.mode=code 或末条消息命中 code|repo|项目|文件|修改|… 等关键词)时,AgentEngine 接管,进入一个最多 16 轮的工具循环。核心目标是让网页版 DeepSeek 既能“读”本地项目,又不会未经授权地改文件。
实现要点:
- 状态页面复用:DeepSeek 网页本身是有状态的会话,所以每一轮只把“最新工具结果 / 修复指令”发给网页,绝不回放完整对话历史(否则它会重复回答早期问题)。见
providers/deepseek/src/index.ts的promptForWebConversation。 - 协议自愈:若 DeepSeek 返回的工具指令不符合规范,Agent 会把它作为
assistant消息连同修复提示再发一次,最多修复 2 次;仍失败则拒绝执行、不做任何文件修改。 - 去重:模型可能在同一回答里以“规范信封 + 渲染兼容形式”重复同一动作,
uniqueToolCalls只执行一次,但会保留刻意不同的多次 Edit。 - 写保护:Write/Edit 在默认配置下只生成“待批准变更”;仅当项目开启
autoApplyWrites才直接落盘。
6. BRIDGE TOOL PROTOCOL V1
网页版模型无法直接调用函数,只能生成文本。Bridge 约定模型在需要工具时输出一个“信封”,Runtime 解析后本地执行。为兼容不同模型的输出风格,解析器支持多种形态(见 agent-engine 的 parseToolCalls):
支持的信封格式
<bridge_tool>…</bridge_tool>[[BRIDGE_TOOL]] … [[/BRIDGE_TOOL]]- `Calling: …
```json ``` Tool: … Arguments: {…}Action: … Action Input: {…}【调用 xxx】{…}本地化形式<Glob>…</Glob>等 XML 标签<tool_call name="…">
规范信封(推荐)
[[BRIDGE_TOOL]]
{"name":"Write","arguments":{
"path":"index.html",
"content":"<!doctype html>..."
}}
[[/BRIDGE_TOOL]]
可用工具:Glob Read Grep Git_Status Git_Diff Write Edit。名称大小写敏感;Write 需非空 path+content;Edit 需 path+old_string+new_string。
工具分发表(ToolEngine.execute)
| 工具名(含别名) | 底层动作 | 越界 / 敏感保护 |
|---|---|---|
Glob / list_files / list_directory |
ripgrep --files(失败回退 Node 递归) |
过滤 node_modules/.git/敏感文件,限 300 条 |
Read / read_file / cat |
ProjectEngine.read |
敏感文件返回 [REDACTED],输出限 80KB |
Grep / search / search_files |
ContextEngine.search(ripgrep) |
同 Glob |
Git_Status / Git_Diff / diff |
GitEngine(git) |
必须在项目根 |
Write / write_file / propose_write |
ToolEngine.proposeWrite |
生成待批准变更(或直写),限 1MB |
Edit / replace / replace_text |
ProjectEngine.replaceText |
精确单处匹配,否则报错 |
7. Provider 抽象与 DeepSeek Web Provider
所有 AI 网页都通过统一的 Provider 契约接入(定义于 packages/protocol):
interface Provider {
readonly id: string;
readonly model: string;
health(): Promise<ProviderStatus>;
stream(request: ChatCompletionRequest, signal: AbortSignal): AsyncIterable<ChatDelta>;
}
ProviderManager 持有已注册 Provider 的映射,提供 active 访问器、switch(id) 与 status()。当前仅注册 DeepSeekWebProvider,但切换到 ChatGPT/Claude/Gemini 等无需改动其它模块——这正是“Provider 无关”的体现。
DeepSeekWebProvider 的工作方式
- 发 prompt:调用
browser.enqueuePrompt(provider, prompt),把消息压入命令队列,并返回异步事件流。 - 读回答:从扩展 POST 回来的
BrowserEvent(delta/complete/error)逐帧 yield 为ChatDelta。 - 超时保护:首字超时(默认 75s)与单轮超时(默认 120s)通过
AbortController中断;若页面有输出但读完无正文,提示刷新页面。 - 健康:
health()仅看扩展是否连上,不检查账号有效性。
8. 浏览器扩展与 Runtime 通信协议
Runtime 与 Chrome 扩展之间是一个 长轮询 + 事件回传 的 HTTP 协议(不依赖 WebSocket,部署更简单):
扩展侧实现细节:background.js 以约 400ms 间隔轮询 /bridge/browser/commands/next,拿到命令后定位 chat.deepseek.com 标签页,转发给 content.js;content.js 负责在 DOM 中找到输入框(textarea#chat-input 或 contenteditable)、注入文本、点击发送按钮,并轮询页面直到回答稳定,再把 delta/complete 事件回传。选择器集中在 content.js,便于在 DeepSeek 改版时单点修复。
9. 安全模型
Bridge 的信任边界是 “本地、显式授权、最小权限”。所有文件 / Git 访问都经过以下层层关卡:
- 路径越界保护:
ProjectEngine.resolve用path.resolve后强制要求绝对路径以项目根开头,../outside直接抛错。 - 敏感文件拦截:
isSensitivePath命中.env*、*.pem/*.key/*.p12时,读取返回[REDACTED],写入直接拒绝。 - 密钥脱敏:
redact把api_key / token / secret / password / authorization / cookie / private_key / jwt = …的值替换为[REDACTED],模型看到的是脱敏文本。 - 写需审批:默认 Write/Edit 只生成待批准变更,需在控制台点击“批准并写入”才修改磁盘;开启
autoApplyWrites的项目才会直写。 - 尺寸上限:单文件写入 / 编辑拒绝超过 1MB 的内容。
- 配置权限:
~/.bridge-api/config.json以0o600仅当前用户可读写;环境变量BRIDGE_*在下次启动时优先于已保存配置。
10. 模块清单
| 包 | 职责 | 关键类型 / 方法 |
|---|---|---|
packages/protocol |
跨模块类型契约 | ChatMessage ChatDelta Provider BrowserCommand BrowserEvent |
packages/provider-manager |
Provider 注册/切换/健康 | ProviderManager.active/switch/status |
packages/browser-bridge |
命令队列 + 事件桥 | BrowserBridge.enqueuePrompt/waitForCommand/accept |
packages/agent-engine |
多轮代码代理 + 协议解析 | AgentEngine.stream parseToolCalls validToolCall |
packages/context-engine |
ripgrep 检索 + 上下文构建 | ContextEngine.search/build |
packages/project-engine |
多项目、路径保护、读写 | ProjectEngine.add/read/write/replaceText/tree/resolve |
packages/tool-engine |
工具执行、待批准变更 | ToolEngine.execute/applyChange/discardChange |
packages/git-engine |
git 封装 | GitEngine.status/diff |
packages/security-engine |
敏感判定与脱敏 | isSensitivePath redact |
packages/queue |
单任务串行队列 | SingleTaskQueue.run/status |
packages/shared |
通用工具 | createId toErrorMessage expandHome |
providers/deepseek |
DeepSeek Web Provider | DeepSeekWebProvider.health/stream |
apps/runtime |
Runtime 入口 + HTTP 服务 + 控制台 | createRuntimeServer loadConfig/saveConfig |
apps/cli |
纯 HTTP 客户端 | bridge doctor|providers|ask|search|diff |
apps/extension |
Chrome MV3 扩展 | background.js content.js popup.* |
apps/native-host |
最小权限文件/Git 代理(骨架) | 白名单 action:project.add / file.read / file.tree / git.* |
11. API 速查
| 方法 | 路径 | 用途 |
|---|---|---|
GET |
/v1/models |
列出当前模型(如 deepseek-web) |
POST |
/v1/chat/completions |
对话补全(支持 OpenAI SSE;bridge.mode/projectKey 扩展字段) |
GET/POST/DELETE |
/bridge/projects |
管理本地项目 |
POST |
/bridge/search · /bridge/context |
检索 / 构建上下文 |
POST |
/bridge/git/status · /bridge/git/diff |
Git 信息 |
POST |
/bridge/file/read · /bridge/file/tree |
安全读取项目文件 |
GET/POST/DELETE |
/bridge/changes · …/:id/apply |
查看 / 批准 / 丢弃待写入变更 |
GET/POST |
/bridge/providers · /bridge/provider/* |
Provider 状态与切换 |
GET/POST |
/bridge/config |
读取 / 保存本地 Runtime 配置 |
GET |
/bridge/health |
Runtime 健康状态 |
GET |
/bridge/browser/commands/next |
扩展长轮询拉取指令 |
POST |
/bridge/browser/events |
扩展回传浏览器事件 |
鉴权:请求头
Authorization: Bearer <token>或x-bridge-token: <token>。代码任务可通过X-Bridge-Project-Key请求头或请求体bridge.projectKey指定跨机可移植的工作区。
12. 运行与验证
# 安装依赖
npm install
# 生成并导出 Bridge Token,启动 Runtime(默认 127.0.0.1:3210)
export BRIDGE_TOKEN="$(openssl rand -hex 32)"
npm run dev
# 打开控制台 http://127.0.0.1:3210/ ,输入同一 Token 即可使用图形界面
# 验证
npm test # node --test 单元测试(provider 切换、路径/密钥防护、队列、协议)
npm run typecheck
# CLI 示例
bridge doctor # 健康检查
bridge providers # 列出 Provider
bridge ask "解释这个项目" # 发起对话
bridge search <project> login # 检索
bridge diff <project> # Git diff
Chrome 扩展联调:chrome://extensions → 开发者模式 → 加载 apps/extension;粘贴 http://127.0.0.1:3210 与 Token,测试连接后登录 DeepSeek 网页,状态变为“DeepSeek 已连接”。


