Bridge API

TL;DR

本地运行的 AI Provider Runtime —— 一个 API,连接所有 AI 网页

本地运行的 AI Provider Runtime —— 一个 API,连接所有 AI 网页

Bridge API

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.tspromptForWebConversation
  • 协议自愈:若 DeepSeek 返回的工具指令不符合规范,Agent 会把它作为 assistant 消息连同修复提示再发一次,最多修复 2 次;仍失败则拒绝执行、不做任何文件修改。
  • 去重:模型可能在同一回答里以“规范信封 + 渲染兼容形式”重复同一动作,uniqueToolCalls 只执行一次,但会保留刻意不同的多次 Edit。
  • 写保护:Write/Edit 在默认配置下只生成“待批准变更”;仅当项目开启 autoApplyWrites 才直接落盘。

6. BRIDGE TOOL PROTOCOL V1

网页版模型无法直接调用函数,只能生成文本。Bridge 约定模型在需要工具时输出一个“信封”,Runtime 解析后本地执行。为兼容不同模型的输出风格,解析器支持多种形态(见 agent-engineparseToolCalls):

支持的信封格式

  • <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 回来的 BrowserEventdelta / 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.jscontent.js 负责在 DOM 中找到输入框(textarea#chat-input 或 contenteditable)、注入文本、点击发送按钮,并轮询页面直到回答稳定,再把 delta/complete 事件回传。选择器集中在 content.js,便于在 DeepSeek 改版时单点修复。

9. 安全模型

Bridge 的信任边界是 “本地、显式授权、最小权限”。所有文件 / Git 访问都经过以下层层关卡:

  • 路径越界保护ProjectEngine.resolvepath.resolve 后强制要求绝对路径以项目根开头,../outside 直接抛错。
  • 敏感文件拦截isSensitivePath 命中 .env**.pem/*.key/*.p12 时,读取返回 [REDACTED],写入直接拒绝。
  • 密钥脱敏redactapi_key / token / secret / password / authorization / cookie / private_key / jwt = … 的值替换为 [REDACTED],模型看到的是脱敏文本。
  • 写需审批:默认 Write/Edit 只生成待批准变更,需在控制台点击“批准并写入”才修改磁盘;开启 autoApplyWrites 的项目才会直写。
  • 尺寸上限:单文件写入 / 编辑拒绝超过 1MB 的内容。
  • 配置权限~/.bridge-api/config.json0o600 仅当前用户可读写;环境变量 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 已连接”。

KEEP READING