🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

CPA 模型接入 TinyBOOOOM/dsh-cliproxyapi-pro

DeepSeek Harness
TinyBOOOOM12 天前有提交已提供中文文档扫描:含敏感能力

把 CLIProxyAPI 的模型目录同步进模型选择器

30.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add TinyBOOOOM/dsh-cliproxyapi-pro
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · model
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 12 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 79 处,展示前 75 条)
  • 发起网络请求
    lib/client.js:2438
    const res = await fetch(url, {
  • 发起网络请求
    lib/client.js:2496
    res = await fetch(url, {
  • 发起网络请求
    lib/client.js:2606
    const doFetch = io.fetch ?? ((url, init) => fetch(url, init));
  • 发起网络请求
    lib/client.js:3405
    const res = await fetch(API.status, { cache: "no-store" });
  • 发起网络请求
    lib/client.js:4696
    const res = await fetch(API.mediaStatus, { cache: "no-store", signal });
  • 写入剪贴板
    lib/client.js:4805
    await navigator.clipboard.writeText(JSON.stringify(diag, null, 2));
  • 发起网络请求
    lib/client.js:5424
    const fetchImpl = io.fetch ?? ((...args) => fetch(...args));
  • 写入剪贴板
    lib/client.js:6937
    await navigator.clipboard.write([new ClipboardItem({ "image/png": png })]);
  • 写入剪贴板
    lib/client.js:6942
    await navigator.clipboard.writeText(text);
  • 读取本地文件
    lib/host/state-store.js:23
    if (!existsSync(filePath)) return {};
  • 读取本地文件
    lib/host/state-store.js:24
    const raw = JSON.parse(readFileSync(filePath, "utf8"));
  • 写入本地文件
    lib/host/state-store.js:34
    mkdirSync(dir, { recursive: true });
  • 写入本地文件
    lib/host/state-store.js:36
    writeFileSync(tmp, JSON.stringify(state, null, 2), "utf8");
  • 写入本地文件
    lib/host/state-store.js:37
    renameSync(tmp, filePath);
  • 读取本地文件
    lib/host/apply/updates.js:22
    const currentVersion = JSON.parse(readFileSync(new URL("../../../package.json", import.meta.url), "utf8")).version;
  • 读取本地文件
    lib/host/apply/controller.js:62
    existsSync(join(updateDirectory, "media-sessions.json")) || existsSync(join(updateDirectory, "media-jobs.json"));
  • 读取本地文件
    lib/host/apply/controller.js:65
    if ((loaded.error !== undefined || !existsSync(mediaSettingsPath)) && mediaUsedBefore()) {
  • 读取本地文件
    lib/host/apply/quota-service.js:16
    read: () => (existsSync(quotaStatePath) ? JSON.parse(readFileSync(quotaStatePath, "utf8")) : undefined),
  • 读取本地文件
    lib/host/apply/quota-service.js:16
    read: () => (existsSync(quotaStatePath) ? JSON.parse(readFileSync(quotaStatePath, "utf8")) : undefined),
  • 写入本地文件
    lib/host/apply/quota-service.js:18
    mkdirSync(dirname(quotaStatePath), { recursive: true });
  • 写入本地文件
    lib/host/apply/quota-service.js:20
    writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8");
  • 写入本地文件
    lib/host/apply/quota-service.js:21
    renameSync(tmp, quotaStatePath);
  • 读取本地文件
    lib/host/apply/media-service.js:137
    .filter((r) => existsSync(r.file))
  • 读取本地文件
    lib/host/apply/image-jobs.js:116
    if (typeof cwd !== "string" || !isAbsolute(cwd) || !existsSync(cwd)) throw new MediaError("workspace-not-local");
  • 读取本地文件
    lib/host/apply/video-command.js:59
    if (typeof cwd !== "string" || !isAbsolute(cwd) || !existsSync(cwd)) throw new MediaError("workspace-not-local");
  • 读取本地文件
    lib/host/apply/video-edit.js:17
    return mediaSessions.get(sessionId).recent.find((r) => r.kind === "video" && (commandId === undefined || r.commandId === commandId) && existsSync(r.fi
  • 读取本地文件
    lib/host/apply/video-edit.js:35
    info = statSync(path);
  • 读取本地文件
    lib/host/apply/video-edit.js:41
    const data = new Uint8Array(readFileSync(path));
  • 读取本地文件
    lib/host/apply/video-edit.js:54
    if (typeof hostPath === "string" && existsSync(hostPath)) return readLocalVideo(hostPath, name);
  • 读取本地文件
    lib/host/apply/video-edit.js:88
    if (typeof cwd !== "string" || !isAbsolute(cwd) || !existsSync(cwd)) throw new MediaError("workspace-not-local");
  • 读取本地文件
    lib/host/apply/agent-tool.js:146
    info = statSync(path);
  • 读取本地文件
    lib/host/apply/agent-tool.js:152
    const data = new Uint8Array(readFileSync(path));
  • 读取本地文件
    lib/host/apply/agent-tool.js:182
    const data = new Uint8Array(readFileSync(path));
  • 读取本地文件
    lib/host/apply/agent-tool.js:235
    if (typeof cwd !== "string" || !isAbsolute(cwd) || !existsSync(cwd)) throw new Error(mediaFailureText(new MediaError("workspace-not-local"), t.kind));
  • 读取本地文件
    lib/host/apply/agent-tool.js:275
    const files = entry.recent.filter((r) => r.commandId === runId && existsSync(r.file)).map((r) => r.file);
  • 读取本地文件
    lib/host/apply/http-routes.js:156
    .filter((r) => r.commandId === commandId && existsSync(r.file))
  • 读取本地文件
    lib/host/apply/http-routes.js:178
    size = video === undefined ? undefined : statSync(video.path).size;
  • 读取本地文件
    lib/host/apply/http-routes.js:219
    if (record === undefined || type === undefined || !existsSync(record.file)) {
  • 读取本地文件
    lib/host/apply/http-routes.js:225
    const bytes = readFileSync(record.file);
  • 读取本地文件
    lib/host/apply/http-routes.js:236
    const size = statSync(record.file).size;
  • 读取本地文件
    lib/host/apply/http-routes.js:256
    const stream = createReadStream(record.file, { start, end });
  • 读取本地文件
    lib/media/settings.js:133
    if (!existsSync(filePath)) return { settings: defaultMediaSettings() };
  • 读取本地文件
    lib/media/settings.js:135
    const raw = JSON.parse(readFileSync(filePath, "utf8"));
  • 写入本地文件
    lib/media/settings.js:145
    mkdirSync(dirname(filePath), { recursive: true });
  • 读取本地文件
    lib/media/settings.js:146
    if (existsSync(filePath) && loadMediaSettings(filePath).error !== undefined) {
  • 写入本地文件
    lib/media/settings.js:147
    renameSync(filePath, filePath.replace(/ json$/, `.corrupt-${Date.now().toString(36)}.json`));
  • 写入本地文件
    lib/media/settings.js:150
    writeFileSync(tmp, `${JSON.stringify(normalizeMediaSettings(settings), null, 2)}\n`, "utf8");
  • 写入本地文件
    lib/media/settings.js:151
    renameSync(tmp, filePath);
  • 读取本地文件
    lib/media/session-store.js:242
    if (!existsSync(filePath)) return { data: normalizeMediaSessions({}) };
  • 读取本地文件
    lib/media/session-store.js:244
    const raw = JSON.parse(readFileSync(filePath, "utf8"));
  • 写入本地文件
    lib/media/session-store.js:266
    mkdirSync(dirname(filePath), { recursive: true });
  • 读取本地文件
    lib/media/session-store.js:267
    if (damaged && existsSync(filePath)) {
  • 写入本地文件
    lib/media/session-store.js:268
    renameSync(filePath, filePath.replace(/ json$/, `.corrupt-${Date.now().toString(36)}.json`));
  • 写入本地文件
    lib/media/session-store.js:271
    writeFileSync(tmp, `${JSON.stringify(next, null, 2)}\n`, "utf8");
  • 写入本地文件
    lib/media/session-store.js:272
    renameSync(tmp, filePath);
  • 写入本地文件
    lib/media/output-files.js:39
    mkdirSync(dir, { recursive: true });
  • 写入本地文件
    lib/media/output-files.js:47
    writeFileSync(path, file.bytes, { flag: "wx" });
  • 写入本地文件
    lib/media/video.js:248
    mkdirSync(dir, { recursive: true });
  • 删除本地文件
    lib/media/video.js:316
    unlinkSync(path);
  • 读取本地文件
    lib/media/job-store.js:63
    if (!existsSync(filePath)) return { data: normalizeMediaJobs({}, now()) };
  • 读取本地文件
    lib/media/job-store.js:65
    const raw = JSON.parse(readFileSync(filePath, "utf8"));
  • 写入本地文件
    lib/media/job-store.js:74
    mkdirSync(dirname(filePath), { recursive: true });
  • 读取本地文件
    lib/media/job-store.js:75
    if (damaged && existsSync(filePath)) renameSync(filePath, filePath.replace(/ json$/, `.corrupt-${Date.now().toString(36)}.json`));
  • 写入本地文件
    lib/media/job-store.js:75
    if (damaged && existsSync(filePath)) renameSync(filePath, filePath.replace(/ json$/, `.corrupt-${Date.now().toString(36)}.json`));
  • 写入本地文件
    lib/media/job-store.js:77
    writeFileSync(tmp, `${JSON.stringify(next, null, 2)}\n`, "utf8");
  • 写入本地文件
    lib/media/job-store.js:78
    renameSync(tmp, filePath);
  • 读取本地文件
    lib/updater/settings.js:21
    const raw = JSON.parse(readFileSync(file, "utf8"));
  • 写入本地文件
    lib/updater/settings.js:38
    mkdirSync(dirname(file), { recursive: true });
  • 写入本地文件
    lib/updater/settings.js:39
    writeFileSync(temporary, `${JSON.stringify({ version: 1, ...normalizeUpdateSettings(settings) }, null, 2)}\n`, { mode: 0o600, flag: "wx" });
  • 写入本地文件
    lib/updater/settings.js:40
    renameSync(temporary, file);
  • 删除本地文件
    lib/updater/settings.js:42
    try { unlinkSync(temporary); } catch {}
  • 写入本地文件
    lib/updater/store.js:15
    mkdirSync(directory, { recursive: true });
  • 写入本地文件
    lib/updater/store.js:16
    writeFileSync(temporary, bytes, { flag: "wx", mode: 0o600 });
  • 写入本地文件
    lib/updater/store.js:17
    renameSync(temporary, path);
  • 删除本地文件
    lib/updater/store.js:19
    try { unlinkSync(temporary); } catch {}
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DeepSeek Harness 的 CLIProxyAPI 服务商插件:支持多账号、模型发现并同步到 DSH 模型选择器、按模型覆盖配置。

README

由 DeepSeek 最新模型翻译生成
dsh-cliproxyapi-pro (v1.4.0) CLIProxyAPI 接入插件,适用于 DeepSeek Harness(DSH >=0.2.0-rc.1):自动发现 CPA 服务、同步模型目录与能力(上下文、视觉、推理档位)到 DSH 模型选择器,支持多个账号分别启用/停用、可视化勾选模型与单模型参数覆盖。 - 零运行时依赖,无需构建;仅使用 Node.js 内置模块与 DSH(Cordis)上下文服务。 - 密钥只存放在 DSH 凭证服务中,不会写入配置文件。 目录 - 功能 - 截图 - 安装 - 使用 - 设置面板 - 多账号 - Agent 工具 cliproxyapi - 斜杠命令 - HTTP 接口 - 协议路由 - 存储与配置 - AI Agent 安装与配置指南 - 开发 - 许可证 功能 1. 自动发现:可填写远程/本地地址(自动剥离 /v1、/v1/chat/completions、/v1/messages 等后缀),留空则依次尝试已有路由地址、环境变量 CLIPROXYAPI_BASE_URL 与本地 127.0.0.1:8317。读取 /v1/models?client_version=pi 富元数据目录(兼容 OpenAI data[] 格式),并用 /v1/models 的 owned_by 判断模型家族。
展开完整文档(README 剩余 1 节)
dsh-cliproxyapi-pro (v1.4.0)

CLIProxyAPI 接入插件,适用于 DeepSeek Harness(DSH >=0.2.0-rc.1):自动发现 CPA 服务、同步模型目录与能力(上下文、视觉、推理档位)到 DSH 模型选择器,支持多个账号分别启用/停用、可视化勾选模型与单模型参数覆盖。

- 零运行时依赖,无需构建;仅使用 Node.js 内置模块与 DSH(Cordis)上下文服务。
- 密钥只存放在 DSH 凭证服务中,不会写入配置文件。

目录

- 功能
- 截图
- 安装
- 使用
- 设置面板
- 多账号
- Agent 工具 cliproxyapi
- 斜杠命令
- HTTP 接口
- 协议路由
- 存储与配置
- AI Agent 安装与配置指南
- 开发
- 许可证

功能

1. 自动发现:可填写远程/本地地址(自动剥离 /v1、/v1/chat/completions、/v1/messages 等后缀),留空则依次尝试已有路由地址、环境变量 CLIPROXYAPI_BASE_URL 与本地 127.0.0.1:8317。读取 /v1/models?client_version=pi 富元数据目录(兼容 OpenAI data[] 格式),并用 /v1/models 的 owned_by 判断模型家族。
2. 模型勾选筛选:搜索、家族标签、全部/已勾选/未勾选切换、批量勾选;只有勾选的模型会出现在对话框模型选择器中。勾选为空表示不过滤;另可用包含/排除关键词规则。从未保存过勾选的账号,首次探测成功后会按该服务自己的模型目录,为每个模型家族勾选最新的一个(最多 12 个);「恢复推荐精选」可恢复这组勾选。
3. 单模型参数覆盖:上下文窗口、最大输出、图片输入、思考等级(off…max)、请求协议,可一键恢复自动探测值。
4. 按模型家族走原生协议(默认):见协议路由。
5. 多账号:每个账号独立的服务地址、密钥、路由、协议、勾选与覆盖,可单独启用/停用。见多账号。
6. 自动刷新:所有账号按统一间隔(默认 300 秒)刷新;数据无变化时不写入任何设置。

截图

面板位于 设置 → 内置插件 → CLIProxyAPI 标签页,界面语言跟随 DSH 设置。

1. 账号栏与账号状态。 顶部账号栏列出所有账号:绿点表示已连接,灰点加「未启用」标记表示已停用。图中刚用「+ 添加账号」新增了第二个账号「CLI Proxy API 2」:它默认停用,拥有独立的路由 cli-proxy-2;由于还没填写服务地址,探测提示本地没有找到 CPA 服务。

账号栏:一个已连接账号和一个刚添加、未启用的账号

2. 模型显示筛选。 从 CPA 服务发现的全部 168 个模型,支持全部发现 / 已勾选 / 未勾选切换、家族标签(GPT、CLAUDE、GEMINI、GROK……)、搜索与批量操作。只有勾选的模型会同步到 DSH 模型选择器;每个模型显示将使用的协议(图中为 OpenAI Responses)、图片输入、推理档位与上下文长度,「编辑参数」可打开单模型参数覆盖。

模型筛选:家族标签、已勾选模型、协议与能力标记

3. 连接与认证配置。 每个账号独立的设置:「启用此账号」开关、服务地址、保存在该账号独立引用名(CLI_PROXY_API_KEY_2)下的 API Key、接口协议、账号名称、可折叠的高级设置,以及「保存设置并应用」与「删除此账号」。

未启用账号的连接设置,使用独立的密钥引用名

安装

在 DSH 对话中让 Agent 调用 plugin_manager 安装,target 任选其一:

| 来源 | target |
| GitHub 最新 main | git+https://github.com/TinyBOOOOM/dsh-cliproxyapi-pro.git#main |
| GitHub 某个版本标签 | git+https://github.com/TinyBOOOOM/dsh-cliproxyapi-pro.git#v1.4.0(见 Releases) |
| GitHub Release 的 .tgz | 下载 dsh-cliproxyapi-pro.tgz(始终是最新版本),填写它的绝对路径 |
| 本地目录(开发用,链接安装) | 克隆后的仓库目录绝对路径 |
| npm(发布后) | dsh-cliproxyapi-pro |

{ "action": "install_bundle", "target": "<上表中的 target>", "enabled": true }

- 安装目录时为链接安装(source: link:<目录>),修改代码后重载插件即生效。
- 已安装旧版本时可直接重新安装;替换已安装的包后需要重启 DSH 才能加载新代码。
- 安装结果中的 application 为 restart-required 时需重启 DSH。

安装后入口:

- 左侧栏 → 插件 → CLIProxyAPI
- 设置 → 内置插件 → CLIProxyAPI 标签页

使用

设置面板

面板顶部是账号栏:点击切换账号(圆点表示状态,未启用的账号带「未启用」标记),「+ 添加账号」新增账号。下方针对当前账号:

| 区块 | 内容 |
| 状态卡片 | 连接状态、当前节点、选择器中的模型数 / 发现总数;「立即探测刷新」「保存设置并应用」 |
| 模型显示筛选 | 勾选模型、编辑单模型参数;修改后点「保存模型勾选」 |
| 连接与认证 | 「启用此账号」开关、服务地址、API Key(可清除)、接口协议、账号名称 |
| 高级路由与规则过滤 | 包含/排除关键词、路由 ID、密钥引用名、自动刷新间隔(所有账号共用);「删除此账号」 |

多账号

- 每个账号写入自己的一组 llm-pi-ai 路由:首个账号为 cli-proxy / cli-proxy-responses / cli-proxy-messages,新增账号依次为 cli-proxy-2、cli-proxy-3……;密钥引用名依次为 CLI_PROXY_API_KEY、CLI_PROXY_API_KEY_2……。模型选择器中按账号名称分组。
- 路由 ID 不能重叠(例如另一个账号不能使用 cli-proxy-messages),保存时会拒绝。
- 停用账号:保留全部配置,但删除它的路由,模型从选择器中消失;其他账号不受影响。
- 新增账号默认停用。填写地址与密钥后可先「立即探测刷新」预览模型并勾选,再打开「启用此账号」保存。
- 填写了服务地址的账号只探测该地址,连不上就报错,不会回退到本地 :8317,避免多个账号指向同一服务。
- 删除账号会移除它的路由,但保留凭证服务中的密钥。

Agent 工具 cliproxyapi

| action | 作用 |
| status | 查看所有账号(或 account 指定的账号)状态与模型 |
| refresh | 立即探测并同步;不带 account 时刷新全部账号 |
| configure | 修改一个账号(默认第一个),保存后立即刷新 |
| add_account | 新增账号;给了 baseURL 时默认启用,否则停用 |
| remove_account | 删除 account 及其路由 |

参数(除 action 外均可选):

| 参数 | 说明 |
| account | 账号 id(如 default、account-2),也可用路由 ID 或账号名称 |
| enabled | 启用 / 停用该账号 |
| baseURL | CPA 地址,如 http://127.0.0.1:8317;空字符串表示自动发现 |
| apiKey | Bearer 密钥,保存到该账号的 apiKeyEnv 引用名下 |
| apiKeyEnv | 密钥引用名([A-Za-z_][A-Za-z0-9_]) |
| provider | llm-pi-ai 路由 ID,每个账号唯一 |
| displayName | 账号名称 / 模型选择器分组名 |
| protocolMode | auto(按家族原生协议,默认)或 fixed |
| protocol | fixed 时使用的协议:openai-completions / openai-responses / anthropic-messages |
| selectedModels | 显示在选择器中的模型 id 列表;[] 表示全部 |
| includePrefix / excludePrefix | 逗号分隔的模型 id 关键词 |
| modelOverrides | { [modelId]: { contextWindow?, maxTokens?, image?, reasoningLevels?, protocol? } },整体替换 |

示例:

{ "action": "configure", "baseURL": "http://127.0.0.1:8317", "apiKey": "sk-...", "selectedModels": ["gpt-6.1-sol", "claude-opus-5-5"] }
{ "action": "add_account", "displayName": "Backup CPA", "baseURL": "https://other-cpa:8317", "apiKey": "sk-...", "selectedModels": ["gpt-6-astra"] }
{ "action": "configure", "account": "account-2", "enabled": false }
{ "action": "remove_account", "account": "account-2" }

输出包含 accounts[](每个账号的 id、displayName、provider、enabled、state、endpoint、modelCount、totalDiscovered、error)与文字摘要 summary。state 取值:idle、probing、connected、disabled、error。

斜杠命令

- /cpa-status:显示所有账号的状态。
- /cpa-refresh:立即刷新所有账号(包括探测停用账号的模型列表)。

HTTP 接口

供设置面板使用,需要 DSH Web 会话认证;POST 仅接受本机/受信任主机的同源请求。

| 方法 | 路径 | 请求体 | 说明 |
| GET | /api/dsh-cliproxyapi/status | — | { ok, global, accounts[] } |
| POST | /api/dsh-cliproxyapi/refresh | { accountId? } | 刷新一个或全部账号 |
| POST | /api/dsh-cliproxyapi/save | { accountId?, …账号字段, apiKey?, clearApiKey?, refreshIntervalSeconds?, probeTimeoutMs? } | 保存账号(缺省为第一个);只有全局字段时只保存全局设置 |
| POST | /api/dsh-cliproxyapi/accounts/add | 账号字段(可选) | 新增账号,默认停用;返回 createdId |
| POST | /api/dsh-cliproxyapi/accounts/remove | { accountId } | 删除账号及其路由 |

协议路由

CLIProxyAPI 对每个模型同时提供 OpenAI Chat、OpenAI Responses、Anthropic Messages 三种入口,入口协议与上游不一致时会做转换。自动模式(protocolMode: "auto")让每个模型直接使用上游协议:

| 模型家族(依据 owned_by 与模型 id) | 协议 | 路由(以 cli-proxy 为例) |
| Claude(含 devin/claude-、Antigravity Claude) | Anthropic Messages /v1/messages | cli-proxy-messages |
| OpenAI / Codex / GPT、xAI Grok | OpenAI Responses /v1/responses | cli-proxy-responses |
| Gemini、DeepSeek、Kimi、GLM、SWE、gpt-oss 等 | OpenAI Chat /v1/chat/completions | cli-proxy |

- DSH 自定义路由不支持 Gemini 原生 generateContent,Gemini 走 OpenAI Chat。
- DSH 每条路由只有一种协议,模型按协议拆入三条路由;没有模型的路由会被移除。默认模型因此换路由时,agent-default-model 自动跟随。
- Claude 4.6+ / 5.x / Fable 使用自适应思考(effort),更早的 Claude 使用 token 预算。
- 可改为「统一使用」某一协议(fixed),或在单个模型的「编辑参数」中指定协议。
- 路由上你手动添加的其他字段(如 retryPolicy)会被保留。

存储与配置

- 状态文件:<Profile 目录>/.dsh-cliproxyapi/state.json

{
"version": 2,
"refreshIntervalSeconds": 300,
"probeTimeoutMs": 5000,
"accounts": [
{
"id": "default", "enabled": true, "provider": "cli-proxy", "displayName": "CLI Proxy API",
"baseURL": "https://cpa.example.com", "apiKeyEnv": "CLI_PROXY_API_KEY",
"protocol": "openai-completions", "protocolMode": "auto",
"includePrefix": "", "excludePrefix": "", "selectedModels": ["gpt-6.1-sol"], "modelOverrides": {}
}
]
}

文件每次读取时都会重新加载,手动修改后点「立即探测刷新」即可生效。v1 单账号文件会自动迁移为 id default 的账号(路由、密钥、勾选不变),原文件备份为 state.v1.json。

- 密钥:通过 DSH credentials 服务按引用名存取;未存储时回退读取同名环境变量。本地免密的 CPA 可以不填密钥。
- 环境变量:CLIPROXYAPI_BASE_URL 仅用于服务地址留空的账号的自动发现。
- Bundle 行配置:cordis.patch.yml 中插件行的 config 会在启动时叠加到状态文件上:含 accounts 时替换账号列表,否则平铺字段作用于第一个账号。通常保持 {},使用面板或工具配置即可。

AI Agent 安装与配置指南

给 DeepSeek Harness 中的 AI Agent:用户要求安装或配置本插件时按以下步骤执行。本包没有 npm 依赖,也没有构建脚本。

1. 安装:调用 plugin_manager,{"action": "install_bundle", "target": "<见安装一节>", "enabled": true}。查看结果中的 application 与 warnings;restart-required 表示需重启 DSH 后新代码才会运行。
2. 配置:使用 cliproxyapi 工具。
- 本地 http://127.0.0.1:8317 且无鉴权:无需配置,调用 {"action": "refresh"}。
- 远程地址或密钥:{"action": "configure", "baseURL": "...", "apiKey": "..."}(第一个账号),额外账号用 {"action": "add_account", ...};指定账号时传 "account": "<id>"。
- 用 selectedModels(取自 status 输出的精确 id)精简模型选择器。
3. 验证:{"action": "status"} 中每个启用的账号 state 为 connected 且 modelCount > 0。告诉用户模型已出现在 DSH 模型选择器中(以账号名称分组),可在 左侧栏 → 插件 → CLIProxyAPI 或 设置 → 内置插件 → CLIProxyAPI 管理账号。

不要把 API Key 回显给用户或写入任何文件。

开发

lib/index.js Host 插件(发现、同步、多账号控制器、工具、命令、HTTP 接口) lib/client.js Web 设置面板(ModuleLoader 格式,手写,无需构建) locale/*.json 插件管理器中显示的标题与描述 cordis.patch.yml Bundle patch,插入 dsh-cliproxyapi-pro 行 tests/ node:test 单元与集成测试 .github/workflows/ CI(测试)与发版(Release .tgz,可选 npm 发布) assets/screenshots/ README 截图(同时登记在 screenshots.json 中供插件市场展示) AGENTS.md 给编码 Agent 的开发约定、架构与不变量

git clone https://github.com/TinyBOOOOM/dsh-cliproxyapi-pro.git
cd dsh-cliproxyapi-pro
npm test # 运行测试
npm run check # 语法检查 + 测试
npm run pack:check # 查看打包文件列表

修改代码前请阅读 AGENTS.md;变更记录见 CHANGELOG.md。欢迎提交 Issue 与 Pull Request,修改说明文档时请同时更新中英文两份。

许可证

MIT
预览分享卡片长什么样 ↓TinyBOOOOM/dsh-cliproxyapi-pro
分享 · DeepSeek Harness Hub
TinyBOOOOM/dsh-cliproxyapi-pro

把 CLIProxyAPI 的模型目录同步进模型选择器

回到顶部