dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
一句话定位:把 Codex / Claude Code / OpenCode / Generic OpenAI / Hermes / Cursor / DSH 等 AI 编程代理当作「员工」,统一管住它们的配置、记忆、技能与健康,把任务调度到最合适的代理上——不是再做一个模型切换器,切的是「活」,不是「模型」。
English: Project-level orchestration for coding agents — not a model switcher.
cc-switch、Codex++ 这一类工具解决的是「切模型」;本仓库解决的是上一层:项目 → 任务 → 分派 → 验收 → 记忆复用。它站在本地私有栈(Ollama / MiniMax H3 / 自托管 API)之上,把多个 coding agent 编排成一条可验收的工作流,全程非侵入——agent 感知不到中枢的存在。
**第一次使用:**还没安装,从快速开始开始;已经装好且服务全绿,直接跳到接入你的 agent,30 秒完成「改出口 → 验证」。
多 agent 工具分两类:一类做编排框架(CrewAI / LangGraph——你把任务交给它的抽象),一类做云端沙箱编排。multi-proxy 都不做,它做管理层:Codex / Claude Code / Cursor 照原来怎么用还怎么用,multi-proxy 站在中间,管住四件天天出事的小事:
| 差异点 | 具体是什么 | 在哪 |
|---|---|---|
| 让你的 AI 编码代理不再打架(签名能力) | 开代理前读各 agent 自己配置文件里的 base_url 实际指向,被 cc-switch 等其它工具占着就拒开;桌面壳开壳前 + Web 面板各查一次 | multi-proxy-manager/lib/agent-owner.js、GET /api/conflicts、tools/agent-proxy-switch |
| 只读接入,绝不写回 | 适配器只读 agent 的状态与结果,不改 agent 任何配置文件;编排路由默认影子模式——先记账,不动真实流量 | l2/adapters/(5 个)、l2/observe-shadow-run.js |
| 成本台账按 agent 归因 | 每个代理、每个模型、每个客户端(Cline / Aider / OpenHands 可区分)单独记账;上游单价 unknown 时不回落瞎估,宁可记「未知」 | generic-openai-proxy 按 UA 归因、l2/relay-ledger.js、l2/savings-gateway/ |
| 本地是一等公民 | Ollama 本地推理与云端 API 同台路由;路由规则打上 privacy=true,请求架构性只落本机端点,不上云 | cursor-proxy/src/providers/ollama.ts、路由表见下 |
不绑定任何 agent 厂商,也不替代任何一个——这是 multi-proxy 的中立位。
| 场景 | 对应能力 |
|---|---|
| 本机同时有 cc-switch、Cursor 自带代理等多个工具,base_url 打架 | 所有权冲突检测:开代理前读各 agent 配置文件的 base_url 实际指向,被占用就拒开(第八节) |
| 一个任务要拆给多个 agent 分头做,结果再汇合 | 编排引擎:拆解 → 路由 → 执行 → 聚合,影子模式默认只记录不改真实路由(第五节) |
| 多个 agent 共享同一份项目记忆 / 技能,但隔离个性 | 记忆服务 + 技能服务:公共层跨 agent 复用,个性层 per-agent(第五节) |
| 本地模型 / 本地视频产线(MiniMax H3)也要当「员工」调度 | 5 个适配器:codex·hermes / h3web / aigc / claude / memory-align,只读接入、绝不写回(第五节) |
| 3 个代理进程谁来管、日志谁来看、端口漂移怎么办 | 进程管理 + Web 管理台 + Electron 桌面壳,端口全动态探测(第二、四节) |
3 分钟跑一遍全部核心 demo:bash scripts/demo-tour.sh(零副作用,影子模式,不碰任何 agent 文件)。
它们是组织治理层:合规分账、密钥托管、内容过滤、全链路日志,跑在远端。multi-proxy 是本地层:卡在你机器上的 agent 与上游之间。两层按需叠加,不是二选一。
叠着跑的时候你手上会有两本账,云网关一本、本地一本。本地那本不是重复建设,是你对账的底稿。
文中提及火山引擎 AgentKit、阿里云 AI 网关、LiteLLM、one-api、New-API、TierFlow 仅作品类对照,不代表任何合作、背书或关联关系;其性能与成本数字均引用官方口径,非本仓库实测。
┌──────────────────────────────────────────────────────────┐
│ 桌面壳层(Electron) │
│ 开壳前先跑所有权冲突检测 · Dock 图标 · 双击即用 │
├──────────────────────────────────────────────────────────┤
│ 管理界面层(L2) │
│ Web 管理台 (18792) · 代理看板 · 日志 · 健康 · 配置 · 登录 │
├──────────────────────────────────────────────────────────┤
│ 中台层(L2·核心) │
│ 10+ 能力内核:Registry · 编排 · 路由(影子) · 拆解 · 插件 │
│ 记忆 · 技能 · 告警 · 成本 · 熔断 · 限流 · 提示词缓存 · MCP │
│ 5 适配器(非侵入):codex·hermes · h3web · aigc · claude · memory-align │
├──────────────────────────────────────────────────────────┤
│ 网关层(L1·增强) │
│ API 网关 · 协议转换(Responses↔ChatCompletions) │
│ 负载均衡(Failover/RoundRobin/成本优化) · 路由热插拔 │
├──────────────────────────────────────────────────────────┤
│ 代理层(L1·核心) │
│ Codex (18790) · Claude (18791) · OpenCode (18798) │
│ Hermes (18793) · Cursor (18794) · DSH · Generic (18799) │
└──────────────────────────────────────────────────────────┘
核心思想:网关拦截各 Agent 的模型请求做协议转换与路由;中台把 Agent 的「全生命周期」(Profile / 记忆 / 技能 / 健康 / 调度)统一起来。Agent 全程感知不到中枢存在——这是「非侵入」与「记忆复用」同时成立的前提。
| 模块 | 技术栈 | 端口 | 说明 |
|---|---|---|---|
workbuddy-shim/ | Node.js 原生 HTTP | 18789 | 可选:WorkBuddy → OpenAI 兼容 shim |
codex-proxy/ | Node.js + Express | 18790 | Codex CLI / OpenAI 兼容代理 |
claude-proxy/ | Node.js + Express | 18791 | Claude Code 代理(Anthropic Messages 协议 + 模型别名映射) |
multi-proxy-manager/ | Node.js + Express + Electron 桌面壳 | 18792 | Web 管理界面(前端 + 后端 + L2 内核) |
hermes-proxy/ | Python + Flask | 18793 | Hermes Agent 代理 |
cursor-proxy/ | TypeScript + Express + SQLite | 18794 | Cursor IDE 代理 |
tools/token-policy-bridge.js | Node.js 原生 HTTP | 18795 | 可选:token 策略透明桥,上游为 18790 |
l2/savings-gateway/ | Node.js | 18796 | 省钱台账 + failover 网关,上游为 18790 |
dsh-proxy/ | Node.js + Express | 18797 | DeepSeek Harness 专属 OpenAI 兼容 lane |
opencode-proxy/ | Node.js + Express | 18798 | opencode 代理(OpenAI 兼容透传 + 成本台账 + 熔断) |
generic-openai-proxy/ | Node.js + Express | 18799 | Cline / Aider / OpenHands 共用代理 |
opencode-free/ | Node.js | 18800 | 可选:opencode.ai 模型 OpenAI 兼容插件 |
unified-ingress/ | Node.js 原生 HTTP | 18880 | 统一入口:按路径分发到 18790 / 18791 / 18792 |
端口表按 2026-10-22 本机
/usr/sbin/lsof -nP -iTCP -sTCP:LISTEN的 13 个项目监听端口补齐;其中 18789、18795、18800 为可选 shim / bridge / 插件,install.sh --all不会安装全部 13 个监听服务。
网关层能力:协议转换(OpenAI Responses ↔ Chat Completions)、负载均衡(Failover / Round Robin)、成本优化路由、路由规则热插拔。
10+ 能力内核模块(l2/*.js),配套 E2E demo(l2/*.demo.js;当前真跑基线见第十四节):
| 内核模块 | 能力 |
|---|---|
agent-registry | Agent 注册中枢:Profile / 标签 / 能力 / 健康 / 版本 |
orchestrator | 编排引擎:任务拆解 → 路由 → 执行 → 结果聚合 |
route-engine | 路由引擎 + shadow 影子模式(默认只记日志、不改真实路由) |
decomposer / llm-decomposer | 任务拆解:规则拆解 / LLM 拆解子能力 |
plugin-runtime | 一切皆插件:路由规则、适配器、健康检查器、UI 面板运行时加载 |
memory-merge | 记忆服务:公共层(跨 Agent)+ 个性层(per-Agent),经环境变量注入 |
skill-service | 技能服务:跨 Agent 技能复用 |
alert / cost | 健康告警 · 成本跟踪 |
circuit-breaker / rate-limiter / prompt-cache / health-monitor | 熔断 · 限流 · 提示词缓存 · 资源探针 |
mcp-server / token-policy | MCP 服务 · token 策略(Curator pack 驱动,见 packs/curator/) |
5 个适配器(非侵入):l1-agent(codex-proxy / hermes-proxy)· h3web(本地 MiniMax H3 视频产线)· aigc(本地 AIGC 服务)· claude· memory-align(跨 agent 记忆对齐:hermes↔workbuddy 水位拉齐,门控默认关、shadow 默认开)——按 l2/adapter-protocol.md 开放协议接入,下游 Agent 只读、绝不写回。
/v1/models、/health、供应商状态、路由模式、切换历史、余额查询、流式传输/v1/messages 协议入口(Claude Code 主链路)、claude-* 模型别名映射(opus/sonnet → deepseek-v4-pro、haiku → agnes-3.0-flash,CLAUDE_ALIAS_* 可覆盖)、/v1/messages/count_tokens、供应商 CRUD、路由模式、余额查询/v1/chat/completions 与 /v1/responses 双入口、per-provider 熔断、预算预检、模型目录同步、成本台账/v1/chat/completions 与 /v1/responses 双入口、per-provider 熔断、预算预检、模型目录同步、成本台账、瞬态故障有界兜底(fallback 链:5xx/429/408/网络错才切下一个、确定性 4xx 不切、深度上限 5、链耗尽 fail-loud),按客户端(cline / aider / openhands 或 x-agent 头)归因成本/api/switch-model、路由模式、健康检查、余额查询、切换历史本机常见的状况:cc-switch 占着 15721,Cursor 自带代理,某个 agent 的 base_url 同时被两个工具「认领」——结果就是流量去向不可预期、日志里全是 502。
本项目用一条结构化解法:同一时刻,一个 agent 的 base_url 只能有一个所有者。
multi-proxy-manager/lib/agent-owner.js — 读各 agent 自己的配置文件(~/.codex/config.toml、~/.hermes/config.yaml)里的 base_url 实际指向,而非只看端口(端口在听 ≠ 正在代理这个 agent)。占用者端口表 OCCUPANT_PORTS 默认 15721(cc-switch),可用环境变量扩展desktop/main.js)开壳前调用 detectAll():检测到目标 agent 的 base_url 被其他工具占用 → 该 agent 的开关置关并提示,不抢、不覆写tools/agent-proxy-switch — 跨所有者的安全切换器:切前确认目标端口真的在听(不死链),只改该 agent 自己的配置(不误伤其他 agent)bash tools/agent-proxy-switch # 各 agent 当前所有者 + 端口状态总览
bash tools/agent-proxy-switch codex # 单 agent 状态
bash tools/agent-proxy-switch codex cc-switch # 切换(结构上杜绝双工具同时认领)
这条能力来自一次真实事故:某次往全局 launchd 注入了带裸
*的NO_PROXY,导致本机所有走代理的 GUI 应用把「所有域名」判定为不走代理,全部直连超时。此后立下铁律(见第七节),冲突检测是把同一教训固化成代码。
云端 provider 和本地端点在这套东西里是同一张路由表里的平等候选。本地不是「另一套降级方案」,是路由条件里实打实的一档——差别只在什么时候派给谁,不在开关上。
| 环节 | 本地路径 | 代码位置 |
|---|---|---|
| 拉本地模型列表 | 供应商类型选 ollama,走 Ollama 原生 /api/tags,取 m.name 当模型 ID | multi-proxy-manager/routes/proxy-api.js:102-121 |
| 原生 provider 适配器 | cursor-proxy/src/providers/ollama.ts(wireApi: 'ollama') | 同目录 base.ts:2 |
| Anthropic wire 转发(codex 侧) | 本地上游走根路径 ${base}/messages,不走 /anthropic/v1 | codex-proxy/proxy.js:820-836 |
| 本地上游无 key | 一律不带 x-api-key:传 undefined 会让 undici 抛 Invalid value,也不该把入站 token 顶上去 | codex-proxy/proxy.js:845-850 |
| 推理链读取 | Ollama 系思维链在 message.reasoning、content 为空 → 兜底取 reasoning | multi-proxy-manager/tests/unit/executor-bind.test.js:177 |
| 真跑验证 | node l2/step2-canary-run.js --real-local,三档真连本地端点 | l2/step2-canary-run.js:135 |
路由表里有一条 privacy == true → 本地模型,定位是「数据不出本机」。这是架构性保证——下游地址就是 127.0.0.1,不是调参数调出来的效果。路由规则一旦打上隐私条件,请求只落本机端点,不上云。
(本地视频产线那一类走的是另一条路,走第四节的 5 个适配器,不在这张路由表里。)
/v1/chat/completions 带 max_tokens、把客户端 timeout 放大,别并发打本地大模型。出处 l2/memory-alignment-protocol.md:151provider.anthropicBaseUrl 显式指定优先 → /anthropic 前缀型(DeepSeek / moonshot)→ 根路径(Agnes / Ollama)。要换上游挂载位置,走 anthropicBaseUrl 这个逃生口。出处 codex-proxy/proxy.js:815-836| 铁律 | 含义 |
|---|---|
| 不写 Agent 文件 | 对下游 Agent 只读,绝不写 ~/.codex / ~/.hermes 等 |
| 不注入全局 env | 不执行 launchctl setenv / export 到全局;env 走 plist 局部配置 |
| 不写死端口 | 各 Agent 端口动态探测(如 h3web 8731↔8732 实测漂移,谁在 LISTEN 用谁) |
| 门控默认关 / shadow 默认开 | 新增能力默认 gate: closed 或 shadow: true,不改变现有行为 |
NO_PROXY 铁律:全局 launchd 绝不注入裸
*通配——HTTP 客户端按逗号拆项做hostname.endsWith(项),*去通配符后为空串,endsWith('')恒真、所有请求绕过系统代理(曾把本机全部走代理的工具带崩)。仅在代理自身 plist 的<EnvironmentVariables>内放127.0.0.1,localhost,::1。
MULTI_PROXY_CONTENT_GUARD)
SideEffectGuard.beforeAction(动作执行前,目标劫持 ASI01 + 注入);② run-history.append(事件落盘前,记忆污染 ASI06);③ profiles-store.save(长期记忆快照落盘前,记忆污染 ASI06)。命中即拦截不落盘(隔离而非静默存);不注入 contentGuard 或门控关 = 零行为变更egress 策略,见 Portico/schemas/tenant-registry.schema.json),不在路由内核实现详见 docs/04-tech/security-whitepaper.md。
.dsh/skills/ 注册两个 Skill,使 DSH(DeepSeek Harness,官方 dsh-plugin 生态,"Everything is a Plugin")的 Agent 能加载本项目:
| DSH Skill | 用途 |
|---|---|
l2-orchestrator | 面向 L2 内核(10+ 模块 + demo 流程)的开发指南 |
multi-proxy | 项目操作入口:3 代理端口、诊断、管理台、冲突检测、全套测试 |
术语:DSH 全称 DeepSeek Harness(官方仓库
deepseek-ai/deepseek-harness,dsh-plugin生态)。本项目.dsh/skills/下两个 SKILL.md 即按官方dsh-plugin规范(name+Use when…)编写。
跨平台安装(macOS / Linux / Windows 三端均支持):
# ── macOS / Linux(bash) ──
bash install.sh --all # 当前只安装 codex / hermes / cursor / manager
# 编辑已安装代理的配置,填写实际使用的 API Key
nano codex-proxy/.env
nano cursor-proxy/.env
# Hermes 用 YAML:cp hermes-proxy/config.yaml.example hermes-proxy/config.yaml 后编辑
bash manage.sh start
bash manage.sh status
# 管理面板 → http://127.0.0.1:18792
当前安装边界:
install.sh --all只覆盖 codex / hermes / cursor / manager,脚本内没有 claude / opencode / generic 的 install 函数。要使用后三者,先按USER-GUIDE.md「方式 C:逐个安装」手动安装依赖并准备各自.env;这是安装脚本的代码层缺口,不在本文档修复范围内。
# ── Windows(PowerShell,原生,无需 WSL) ──
.\install.ps1 # 安装依赖 + 启动 + 配置登录自启
.\manage.ps1 status # 查看状态
服务全绿只代表代理已经运行;还要把 agent 的模型出口指向本机代理。以下 export 只影响当前 shell,不写全局环境。
Codex CLI / OpenAI SDK / OpenAI 兼容工具:
export OPENAI_BASE_URL=http://127.0.0.1:18790/v1
也可以在统一入口已运行时改用 http://127.0.0.1:18880/v1。18880 按路径自动分发:/v1/messages → claude-proxy(18791),/v1/responses、/v1/chat/completions 和 /v1/models → codex-proxy(18790),/api/* → manager(18792)。
Claude Code:
export ANTHROPIC_BASE_URL=http://127.0.0.1:18880
export ANTHROPIC_MODEL=deepseek-v4-pro
统一入口未运行时,把 ANTHROPIC_BASE_URL 改为 http://127.0.0.1:18791 直连 claude-proxy。ANTHROPIC_MODEL 必须填写你的上游实际模型名;示例 deepseek-v4-pro 已出现在本机 /v1/models 返回中。claude-proxy(18791)与 codex-proxy(18790)自 2026-10-02 起均已实现 Anthropic /v1/messages 路由。
Cursor:
Cursor → Settings → Models → Override OpenAI Base URL。Base URL 填 http://127.0.0.1:18794;API Key 填任意非空值(18794 的 /v1 端点不校验该值)。/v1/models 返回的真实名称,例如 agnes-3.0-flash;不要选 Cursor 默认的 gpt-5 / claude-3.7-sonnet / claude-sonnet-4,这些名称实测会返回 404。一行验证:
curl --noproxy '*' http://127.0.0.1:18790/v1/models
bash manage.sh status
当前仓库中的
manage.sh文件模式为100644,因此应通过bash manage.sh status运行;字面执行./manage.sh status会得到permission denied。本文档不越权修改脚本权限。
开机自启(按平台):
bash install.sh --autostart(launchd,写 ~/Library/LaunchAgents/com.multi-proxy-manager.plist)bash install.sh --autostart(systemd 用户服务,写 ~/.config/systemd/user/multi-proxy-manager.service;systemctl --user status multi-proxy-manager 查看).\install.ps1 默认配置登录自启(计划任务 MultiProxyManager);移除 .\install.ps1 -Uninstall常用命令:manage.sh {start|stop|restart|status} · manage.sh logs {all|codex|claude|opencode|hermes|cursor|dsh|generic|manager} · 单服务 manage.sh <agent> {start|stop|restart} · 自启 install.sh --autostart · 桌面壳 desktop/(Electron,壳 = 启动器 + 窗口,业务代码不进 .app)。Windows 对应 manage.ps1 / install.ps1。
前置:Node.js 20+(cursor-proxy 的 TypeScript 测试需 Node 24 + ESM runner);Python3(Hermes)。端口检测已跨平台(优先 lsof,回退 ss / /proc/net/tcp)。支持 macOS(launchd)/ Linux(systemd --user)/ Windows(PowerShell + 计划任务)。Linux 装依赖:sudo apt install nodejs npm python3;Windows 需先装 Node.js 与 Python3。
完整上手流程见 docs/quickstart.md。
启动顺序与端口依赖:代理相互独立可单独起停;18790(codex) 是核心网关,savings-gateway(18796) 反向依赖它(upstream: 127.0.0.1:18790)。一键 bash manage.sh start 按依赖顺序拉起;单服务 bash manage.sh <agent> start。所有端口默认绑 127.0.0.1,仅 Docker/跨机显式 BIND_HOST=0.0.0.0。运行状态一键核对:bash tools/health-all.sh。
这一节写的是代码里真实跑的那条链,不是设计图。每一跳都给了文件路径与行号。
| # | 跳 | 代码位置与行为 |
|---|---|---|
| 1 | 入站 | codex-proxy/proxy.js:20 端口 18790;proxy.js:1015 默认只 bind 127.0.0.1 |
| 2 | 认证 | proxy.js:31-36 requireAuth 只校 x-proxy-auth;未设 PROXY_AUTH_TOKEN 时 fail-open 并 WARN |
| 3 | 选 provider | proxy.js:192-218 findProvider(model) 三级:providers.json 精确命中 → provider_id 子串 → 内置 env-key 上游。只选一个,没有重试 |
| 4a | 转发(OpenAI wire) | /v1/chat/completions 与 /v1/responses 是同协议直通::698-768 原样 JSON.stringify 转发,:779-819 仅 normalizeTools 解包工具参数 |
| 4b | 转发(Anthropic wire) | /v1/messages 走 anthropicMessagesUrl()(proxy.js:940-947)三级挂载判定:provider.anthropicBaseUrl 显式指定优先 → deepseek/moonshot 走 /anthropic/v1/messages → 其余 ${base}/messages |
| 5 | 攒字节防丢账 | pipeUpstreamBytes()(proxy.js:820-880)PassThrough tee 一份副本,为的是流末 usage 不被丢掉 |
| 6 | 报用量 | reportUsage()(proxy.js:892-912)旁路 POST 到 manager 的 /api/cost/report;manager 侧 lib/usage-probe.js:113-125 按 wire 自动归一 |
| 7 | 归一 wire | usage-probe.js:21-30 detectWire():从 usage 字段形态认——有 output_tokens_details / input_tokens 是 Anthropic,有 prompt_tokens 是 OpenAI,有 usage_metadata 是 Gemini,都不是则兜底 custom |
| 8 | 落账 | lib/cost-track.js:217-219 算钱(cacheHit 单独计价、thinking 只计数不计费);:302-310 追加写 ~/.multi-proxy-manager/cost-ledger.jsonl |
三条不能写死的边界(2026-10-06 grep 核过):
fetch,失败直透上游状态码。路由模式里的 failover 在 cursor-proxy/src/server/handlers/chatHandler.ts:21-24(18794,round-robin / failover 两档);l2/circuit-breaker.js 目前唯一的消费者是 codex-proxy/tests/circuit-integration.test.js。raw,不必声明 wire,wire 由 manager 侧认。证据在 usage-probe.js:8-13、proxy.js:988、routes/cost-report.js:41。token-control-plane 是设计文档 docs/03-token-control-plane.md 的名字,不是模块;链路上的真实载体是 l2/token-policy.js 与 tools/token-policy-bridge.js。0.06 与 28.7% 不是实测值。 前者出自 l2/README.md:153 的手喂冒烟算式,后者是 tests/unit/cost-track.test.js:83-91 的单测断言。真实流量下是多少,代码里没有产出点。别拿这两个数当效果数字。先说清楚什么不值钱:多模型路由聚合这件事本身不稀缺,LiteLLM / one-api / New-API 都在做;TierFlow 也在做(它 README 自述 "Self-hosted AI router",配置里 "ollama": { "baseUrl": "http://localhost:11434/v1", "auth": { "type": "none" } } 直接当 primary)。「支持本地模型」不是本项目的差异项,别拿它当卖点。
真正难抄的是三笔工程账,都是踩坑换来的:
lib/usage-probe.js:21-30 只靠 usage 字段名形态就能认出三家供应商的记账口径,接入方贴一段上游原样 JSON 就够了。三家字段各不相同、Anthropic 的流式还在末事件里包一层,硬写三份解析器的写法在跨版本升级上会反复返工。base_url 同一时刻只有一个所有者。 lib/agent-owner.js 读的是各 agent 自己配置里 base_url 的实际指向,而不是谁在听端口;cc-switch 占着 15721 时桌面壳开壳前先 detectAll(),撞了就把该 agent 的开关置关并提示,不抢、不覆写。这块来自一次真实事故(裸 * 污染 NO_PROXY 把本机所有走代理的 GUI 应用带崩,见第七节),上下文不在代码里。privacy == true → 本地模型,下游地址就是 127.0.0.1,是架构性保证而不是调参调出来的效果。也讲一句该讲的:如果只想省 API 的钱、要一个两分钟跑起来的网关,这个 repo 过重。 它是为「本机多个 agent 同时在跑、数据不能出这台机器」这一层做重的;单端口轻量网关在满足前面那个需求上更合适。如果你的场景正是多 agent 协作或本地隐私路由,直接从接入你的 agent开始,不必先读完后面的实现细节。
bash scripts/demo-tour.sh # 全量(含测试基线,约 3 分钟)
bash scripts/demo-tour.sh --quick # 只看 demo 不跑测试(约 30 秒)
脚本零副作用:L2 demo 默认影子模式、历史写 os.tmpdir()、绝不写任何 agent 文件。
| 模块 | 真实命令 | 2026-10-22 结果 |
|---|---|---|
| multi-proxy-manager | cd multi-proxy-manager && npx jest --silent --forceExit | 1579 pass / 1 fail |
| codex-proxy | cd codex-proxy && npx jest --silent --forceExit | 179 pass |
| claude-proxy | cd claude-proxy && npx jest --silent --forceExit --worker=1 | 174 pass |
| generic-openai-proxy | cd generic-openai-proxy && npx jest --silent --forceExit --worker=1 | 207 pass / 3 timeout |
| cursor-proxy | cd cursor-proxy && NODE_OPTIONS=--experimental-vm-modules npx jest --silent --forceExit | 258 pass |
| hermes-proxy | cd hermes-proxy && python3 -m pytest tests/ -q | 80 pass |
| L2 demo | find l2 -name '*.demo.js' -print0 | xargs -0 -n1 node | 55 pass / 1 fail |
以上数字是 2026-10-22 的命令真跑快照,失败与超时均原样保留,不写成“全绿”。opencode / dsh / shell 未纳入本次真跑基线,不沿用旧数字冒充当前结果。
历史修复记录见 P0-FIXES.md(11 项 P0)。
multi-proxy/
├── multi-proxy-manager/ # Web 后台 + L2 内核调用 + agent-owner 冲突检测
│ ├── lib/agent-owner.js # 所有权冲突检测(base_url 实指向,非端口)
│ ├── src/ # 后端 server.js / routes / lib
│ ├── public/ # 前端页面
│ └── tests/ # Jest 测试
├── codex-proxy/ # Node.js 代理(18790)
├── claude-proxy/ # Node.js 代理(18791,Claude Code)
├── opencode-proxy/ # Node.js 代理(18798,opencode)
├── generic-openai-proxy/ # Node.js 代理(18799,Cline/Aider/OpenHands 共用)
├── hermes-proxy/ # Python/Flask 代理(18793)
├── cursor-proxy/ # TypeScript/SQLite 代理(18794)
├── dsh-proxy/ # Node.js 代理(DeepSeek Harness,PORT 可配)
├── desktop/ # Electron 桌面壳(启动器 + 窗口)
├── l2/ # L2 编排中枢:10+ 内核 + 5 adapter + 配套 demo
│ ├── adapters/ # codex·hermes / h3web / aigc / claude / memory-align 适配器
│ ├── adapter-protocol.md # 开放接入协议
│ ├── savings-gateway/ # 省钱网关 + 成本看门狗
│ └── specs/ # agent-memory / agent-profile 契约 + schema
├── packs/curator/ # Curator pack(token 策略包,M1-M6)
├── tools/agent-proxy-switch # 跨所有者安全切换器
├── scripts/demo-tour.sh # 3 分钟演示脚本
├── .dsh/skills/ # DSH 生态 Skill
├── docs/ # 结构化文档(架构 / 部署 / 验收 / 用户)
├── tests/shell/ # manage.sh 行为测试(bats)
├── Dockerfile.* / docker-compose.yml
└── manage.sh # 进程管理(非侵入)
* 污染全局 NO_PROXY旧版部署脚本含 launchctl setenv no_proxy "127.0.0.1,localhost,*",使所有走系统代理的 GUI 应用直连超时。当前源码已无此写法(autostart plist 仅设 PATH + 代理自身局部 env),修复写法 * → ::1。
install.sh --uninstall 卸载不完整历史:只删 com.multi-proxy-manager.plist,不清理其余 com.multi-proxy.* plist 与用户级残留。
修复(2026-10-13):
uninstall_launchd 改用 plist_label(plutil 优先 + python 兜底 + grep 终极兜底),修掉含特殊字符注释的 plist(如 savings-gateway)被 expat 解析失败而跳过的问题;uninstall_residues:卸载时一并清理 ~/.multi-proxy-manager、codex-proxy/{logs,trace}、hermes-proxy/.env、multi-proxy-manager/.env、~/.local/bin/dsh-curator(第三方 ~/.dsh 主目录只警告不自动删);install.sh --uninstall --dry-run 预览,确认无误再实跑。无机制天然防止 proxy 与 cc-switch 同时认领同一 agent 的 base_url。已用 tools/agent-proxy-switch + lib/agent-owner.js 提供结构化防护(见第五节),桌面壳开壳前强制检测。
manage.sh stop 停不掉 launchd 托管实例 + 返回码误报现象:stop all 对 launchd KeepAlive 托管的实例(实测 codex 18790 / manager 18792)kill 后立刻被拉活,报「未能正常停止」;且 kill -9 打在已自行退出的进程上返回 1,被 set -e 放大为整个 stop all FAIL。
修复:
stop_service kill 后复验端口、显式 return 0、kill 加 || true,返回码不再冒充停止结果;launchctl bootout」,不再误报;tools/verify/verify.sh 清理段先 bootout ~/Library/LaunchAgents/com.multi-proxy.*.plist 再 stop,修掉其自身 WORK: unbound variable 崩溃(2026-10-15 真跑复验 EXIT=0)。lsof 端口检测,确保 /usr/sbin/lsof 可用(Node 子进程 PATH 不含 /usr/sbin 会误判,必须完整路径)。manage.sh logs <agent> 看日志,或 cd <agent>-proxy && node proxy.js 手动启动看错误。cd cursor-proxy && npm run build 2>&1 | tee logs/cursor-build.log。rm ~/.multi-proxy-manager/password && bash manage.sh restart manager。install.sh --autostart;检查 ~/Library/LaunchAgents/com.multi-proxy-manager.plist。nano plist 加路径。更多见 docs/08-user/faq.md。
findProvider 选 provider,单次 fetch,不重试。多出来的是成本记账这条旁路——报用量只贴上游原样 JSON,wire 由 manager 侧自动认(lib/usage-probe.js),账落 cost-ledger.jsonl,热路径与跨进程共用同一套公式(cost-track.js:190-191)。顺带把话说明白:tests/unit/cost-track.test.js:83-91 里的 28.7 与 l2/README.md:153 里的 0.06,都是喂固定 token 数算出来的,不是真实流量的实测值。base_url 所有权检测(它不碰 agent 文件,所以根本不存在这一块面)、privacy 档位(下游地址写死 127.0.0.1)、四条非侵入铁律(见第七节)。只想要省钱的那一层,用前者;要的是「本机多个 agent 一起跑、数据不出这台机器」,这才是这个项目的位置。⚠️ 顺带核一个容易记错的:TierFlow 是 MIT 许可,不是 AGPL(2026-10-06 核 frdaniel76/tierflow)。categories.simple_chat.primary = ollama/llama3.2),判据是钱;在这边,本地模型是 privacy 条件命中的唯一去处(见第六节),判据是数据去向,跟便宜不便宜无关。两个设计都站得住,答的是两个不同的问题,说「谁做不到谁」是错的。个人是流量入口,企业版才是收入主体(含基于 savings-gateway 定价表的真实省钱测算与多租户缺口清单,归 Portico 企业版,内部价值主张文档不进公开仓)。一句话分工:
当前 multi-proxy 是单用户 / 单机 / 单成本池设计;企业化的多租户、网关层部署、审计留痕等能力不在本仓库内核,由 Portico 企业版承载,走商业授权(见
LICENSE-COMMERCIAL.md),不污染 AGPL 开源版。
| 里程碑 | 状态 |
|---|---|
| L1 代理层(7 代理:codex / claude / opencode / generic-openai / hermes / cursor / dsh + 管理台 + 进程管理) | 完成 |
| L2 中台内核(10+ 模块 + 4 adapter) | 完成 |
| 所有权冲突检测(agent-owner |