dsh-any-deepseek 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +133 -0
- package/README.en.md +137 -197
- package/README.md +121 -170
- package/docs/screenshot-add-channel.png +0 -0
- package/package.json +2 -1
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# 参与改进 dsh-any-deepseek
|
|
2
|
+
|
|
3
|
+
这是个实用小工具,改动从「一个字段的文案」到「接一家新渠道」都欢迎。
|
|
4
|
+
|
|
5
|
+
**先读 [README.md](README.md)** —— 那里讲的是怎么用;这一份讲怎么改。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 最有价值的三种贡献
|
|
10
|
+
|
|
11
|
+
### 1. 接一个新渠道
|
|
12
|
+
|
|
13
|
+
内置 5 家,接别家通常只改 [`src/presets.ts`](src/presets.ts) 一个文件。
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
'your-relay': {
|
|
17
|
+
displayName: 'Your Relay',
|
|
18
|
+
api: 'openai-completions',
|
|
19
|
+
baseURL: 'https://your-relay.example/v1',
|
|
20
|
+
// 🔴 用**这家自己的**拼写。各家模型名不同:
|
|
21
|
+
// deepseek-v4.1-flash / deepseek/deepseek-v4.1-flash / deepseek-flash
|
|
22
|
+
// 抄错不会在本地报错 —— 会在第一次真请求时被上游拒。
|
|
23
|
+
model: 'deepseek-v4.1-flash',
|
|
24
|
+
...V41_FLASH_CAPS,
|
|
25
|
+
// 可选:这家有没有余额接口、是哪种形状(见 src/balance.ts 的四种 shape)
|
|
26
|
+
// balance: { shape: 'openai-billing' },
|
|
27
|
+
},
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
加完这一条,面板的规格下拉里就有它了 —— 不需要改别处。
|
|
31
|
+
|
|
32
|
+
**两条硬规矩**(都是付过代价的):
|
|
33
|
+
|
|
34
|
+
1. **注释里不要写「我探过了」,除非真的探过。**
|
|
35
|
+
这个仓里曾经有一条 `Probed live: the billing pair answers` 的注释,而那个路由**从没被调用过**,
|
|
36
|
+
第一次真调用就 404。**假证据比没有注释更坏** —— 它让下一个读者不再去查。
|
|
37
|
+
|
|
38
|
+
2. **`model` 填上游的拼写,不是我们的 id。**
|
|
39
|
+
我们对外只暴露 `deepseek-v4.1-flash` 一个 id,各家的拼写由预设吸收。
|
|
40
|
+
**这正是这个插件存在的理由** —— 所以别在预设里图省事写我们的 id。
|
|
41
|
+
|
|
42
|
+
### 2. 修一处文案
|
|
43
|
+
|
|
44
|
+
面板上的每一句都应该是一个**能在页面上验证的事实**。读到含糊、过时、或替宿主猜原因的,直接改。
|
|
45
|
+
|
|
46
|
+
判断标准(本项目一直在用):
|
|
47
|
+
|
|
48
|
+
- ❌ 「已安全保存」—— 读者无法验证。
|
|
49
|
+
- ✅ 「存在 `channels.<id>.apiKey`,会出现在 `--dump-config` 输出里」—— 可验证。
|
|
50
|
+
- ❌ 「只读部署,或设置服务未启用」—— 替宿主猜了两个**没查过**的原因。
|
|
51
|
+
- ✅ 「宿主拒绝了这个修改」+ 宿主自己的错误信息 —— 只说知道的事。
|
|
52
|
+
|
|
53
|
+
### 3. 报一个「装了但没反应」
|
|
54
|
+
|
|
55
|
+
**静默失效是本项目最贵的一类缺陷** —— 装了不生效、写了没保存、功能存在但不可达,
|
|
56
|
+
全都零报错。复现步骤比任何猜测都值钱。
|
|
57
|
+
|
|
58
|
+
这类问题通常有这几个藏身处,如果你能指出是哪一处,修起来会快很多:
|
|
59
|
+
|
|
60
|
+
| 现象 | 可能的位置 |
|
|
61
|
+
|---|---|
|
|
62
|
+
| 面板整块不出现,控制台零错误 | `SETTINGS_NS` 与 `cordis.patch.yml` 的条目 id 不一致 |
|
|
63
|
+
| 面板在,但每次请求都失败、表格显示「还没有渠道」 | `inject` 里少了 `webServer`,路由被静默跳过 |
|
|
64
|
+
| 设置写不进去,但看不出原因 | schema 少了 `.volatile()`,或写入被 `.catch` 吞了 |
|
|
65
|
+
| provider 装了但模型选择器里没有 | 注册元数据(`inputModalities` / `reasoning`)没声明 |
|
|
66
|
+
|
|
67
|
+
## 加一种余额形状(少见)
|
|
68
|
+
|
|
69
|
+
如果某家有余额接口但形状是新的,改 [`src/balance.ts`](src/balance.ts):
|
|
70
|
+
|
|
71
|
+
1. 给 `BalanceProbe.shape` 加一个值;
|
|
72
|
+
2. 写一个 `parseXxx()`;
|
|
73
|
+
3. 在 `balanceUrls()` 里给它路径;
|
|
74
|
+
4. 在 `readBalance()` 里分发。
|
|
75
|
+
|
|
76
|
+
`balanceUrls()` 是**唯一**知道路径的地方 —— 这样预设就不可能和传输层意见相左。
|
|
77
|
+
|
|
78
|
+
还有一条底线:**缺数字就报缺,绝不填 0。**
|
|
79
|
+
「读不到」和「是空的」导致相反的行动,而只有一个是真的。
|
|
80
|
+
|
|
81
|
+
## 开发
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pnpm install
|
|
85
|
+
pnpm run typecheck # 两个 tsconfig:node 半 + client 半
|
|
86
|
+
pnpm run test # 纯函数层,不需要装上 harness
|
|
87
|
+
pnpm run build # lib/index.js + lib/client.js
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
纯函数层(`presets` / `channels` / `route` / `usage-ledger` / `balance`)不 import harness,
|
|
91
|
+
所以单测跑得很快。适配器与面板只通过宿主的公开接缝和它说话。
|
|
92
|
+
|
|
93
|
+
## 判据必须承重
|
|
94
|
+
|
|
95
|
+
**每条新判据都要附一次「把它弄红」的实验结果。**
|
|
96
|
+
|
|
97
|
+
把修复回滚,那条用例必须红;否则它只是装饰。这个仓的 CHANGELOG 里每个结论都带着它的负控制读数
|
|
98
|
+
(例如「去掉 `percent` 取反 ⇒ 精确红 3 条」)。
|
|
99
|
+
|
|
100
|
+
三种特别容易写成**假判据**的形态,本项目都踩过:
|
|
101
|
+
|
|
102
|
+
1. **判据与被判对象同源**。例:`bump` 改的是 CHANGELOG 首个标题,而 `version` 只读首个标题 ⇒
|
|
103
|
+
永远读绿。要抓这类缺陷,判据必须碰**别的不变式**(现在是「集合包含」:原有每个标题都在,且恰好多一个)。
|
|
104
|
+
2. **假传输层掩盖走错协议**。测试里传输层是假的,走错协议照样「通」。
|
|
105
|
+
分发决策要用**结构判据**钉住(断言 `api: apiImplementations()` 存在、旧形态不回来)。
|
|
106
|
+
3. **自写抽取器出错时不喊**。手写的 YAML 正则抽空了,用例照样绿。
|
|
107
|
+
⇒ 抽取要**如实落盘原文**再看,不要在抽取器里顺手「清洗」。
|
|
108
|
+
|
|
109
|
+
## 截图怎么更新
|
|
110
|
+
|
|
111
|
+
README 里的三张图来自 `scripts/screenshot-harness.tsx`,它渲染**真实面板组件**
|
|
112
|
+
(假数据、真 CSS/JSX/文案)—— 面板本身在 token 保护的 Web UI 后面,干净 profile 打开是空白页,
|
|
113
|
+
所以直拍拿不到。
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
msm("any-deepseek-develop", ["shot"]) # 打包成单文件页面
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
生成的页面在 `_tmp/shot/screenshot-harness.html`,用浏览器打开后截图即可。
|
|
120
|
+
加 `?variant=add` 可以拍「添加渠道」表单那一种状态。
|
|
121
|
+
|
|
122
|
+
> ⚠️ 打包时有两个坑,都会让页面**空白且零报错**:产物里残留 `import`(内联模块无法解析)、
|
|
123
|
+
> 或外部 `<script src>` 在 `file://` 下被 CORS 拒。`shot` 已自带「不许有残留 import」的判据。
|
|
124
|
+
|
|
125
|
+
## 发布
|
|
126
|
+
|
|
127
|
+
维护者用的开发通道是 CCC 的 MSM `any-deepseek-develop`(safe-mode 下没有 bash)。
|
|
128
|
+
`stage check` 是「能不能装」的唯一判据 —— **`npm publish` 的退出码 0 不代表可安装**,
|
|
129
|
+
新版本要一两分钟后才在 registry 上出现。
|
|
130
|
+
|
|
131
|
+
## 许可
|
|
132
|
+
|
|
133
|
+
MIT
|
package/README.en.md
CHANGED
|
@@ -1,277 +1,217 @@
|
|
|
1
1
|
# dsh-any-deepseek
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
**Use DeepSeek credit from several providers inside DeepSeek Harness — with one extra row in the
|
|
4
|
+
model list, not N.**
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
You bought DeepSeek credit in several places: the official API, a relay, a cloud vendor, a cheap
|
|
7
|
+
one a friend recommended. This plugin collects them into **one** provider: paste a few keys, click
|
|
8
|
+
to switch — and usage is booked per real upstream, so you can see what each one cost this month.
|
|
8
9
|
|
|
9
|
-
[
|
|
10
|
+

|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
[中文](README.md) · English (this page)
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
15
|
-
##
|
|
16
|
+
## Before you install: is this for you?
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
colleague's cheap recommendation. In DeepSeek Harness, that would normally become **N entries in
|
|
19
|
-
the model picker**, and every switch means editing configuration, changing the model id, changing
|
|
20
|
-
the key — plus you have to remember yourself which relay spent how many tokens this month.
|
|
18
|
+
**Yes**, if any of these is true:
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
- You have **more than one** DeepSeek endpoint and want to switch between them without editing
|
|
21
|
+
configuration.
|
|
22
|
+
- You want **per-channel usage accounting** instead of one blended total.
|
|
23
|
+
- You use relays whose model ids differ (`deepseek-v4.1-flash` / `deepseek/deepseek-v4.1-flash` /
|
|
24
|
+
`deepseek-flash`) and don't want to keep track yourself.
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
- Any number of **channels** hang off it; each is an endpoint + a key + a display name.
|
|
26
|
-
- Click a channel's dot and requests go there. **No automatic switching** (see
|
|
27
|
-
[Why no failover](#why-no-failover)).
|
|
28
|
-
- Usage is booked **per real upstream**.
|
|
26
|
+
**No**, if:
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
any-deepseek
|
|
36
|
-
/ deepseek-v4.1-flash
|
|
37
|
-
(the only model exposed)
|
|
38
|
-
```
|
|
28
|
+
- You have a single endpoint and it is the official one — the built-in `deepseek-official` already
|
|
29
|
+
covers you; this plugin is unnecessary.
|
|
30
|
+
- You want **automatic failover** (one endpoint dies, requests move to the next). v1 does not do
|
|
31
|
+
that — see [Why no failover](#why-no-failover).
|
|
32
|
+
- You want to **switch between models**. This is "one model, many sources", not a model router.
|
|
39
33
|
|
|
40
34
|
## Install
|
|
41
35
|
|
|
36
|
+
Requires DeepSeek Harness to be installed already. In a terminal:
|
|
37
|
+
|
|
42
38
|
```bash
|
|
43
39
|
dsh plugin --profile web add dsh-any-deepseek
|
|
44
40
|
```
|
|
45
41
|
|
|
46
42
|
Then **restart DSH** and open Settings → **Any DeepSeek**.
|
|
47
43
|
|
|
48
|
-
> **
|
|
49
|
-
>
|
|
50
|
-
>
|
|
51
|
-
>
|
|
52
|
-
> `dsh plugin` forwards its arguments to pnpm, so `add <spec>` accepts a registry name, a tarball
|
|
53
|
-
> path, or a local directory (installed as a symlink).
|
|
44
|
+
> **Why the restart**: the plugin is added to the profile's load list, which is read only at
|
|
45
|
+
> startup. Afterwards, changing this plugin's UI half needs only a browser refresh — but the
|
|
46
|
+
> **first install** needs the restart.
|
|
54
47
|
|
|
55
|
-
##
|
|
48
|
+
## First run: three steps
|
|
56
49
|
|
|
57
|
-
### Add a channel
|
|
50
|
+
### 1. Add a channel
|
|
58
51
|
|
|
59
|
-
Click
|
|
52
|
+
Click **添加渠道** (Add channel). Two fields are required:
|
|
60
53
|
|
|
61
|
-
|
|
62
|
-
|---|---|---|
|
|
63
|
-
| **规格** (preset) | ✅ | Determines endpoint, upstream model id, and protocol — so you don't type them. |
|
|
64
|
-
| **渠道 id** (channel id) | ✅ | The configuration key, `[a-z0-9][a-z0-9_-]*`. The same preset can be added twice; the second becomes `-2`. |
|
|
65
|
-
| **显示名** (display name) | — | Display only. Tells two accounts on the same relay apart. **Renaming never touches the id.** |
|
|
66
|
-
| **密钥** (key) | ✅ | The key itself. There is no name to invent. |
|
|
54
|
+

|
|
67
55
|
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
| Field | What it means |
|
|
57
|
+
|---|---|
|
|
58
|
+
| **规格** (preset) | Pick your provider. It determines the endpoint, model id, and protocol — so you don't type them. |
|
|
59
|
+
| **密钥** (key) | The key that provider gave you. Paste it. There is no name to invent. |
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
**渠道 id** (channel id) is filled in for you — it is just the configuration key, and you can
|
|
62
|
+
change it. **显示名** (display name) defaults to the preset name; when you run two accounts on the
|
|
63
|
+
same provider, set something like "main" / "backup".
|
|
72
64
|
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
Bundled presets: DeepSeek Official, OpenCode Go, Ollama Cloud, Open Design, CommandCode.
|
|
66
|
+
For another provider, see [Adding a provider](#adding-a-provider).
|
|
75
67
|
|
|
76
|
-
|
|
77
|
-
boundary or start a new session.
|
|
68
|
+
### 2. Make sure it is selected
|
|
78
69
|
|
|
79
|
-
|
|
70
|
+
The first channel you add **becomes the current channel automatically** — its row gets a radio
|
|
71
|
+
dot, a colour bar down the left edge, and a 「当前」 badge.
|
|
80
72
|
|
|
81
|
-
|
|
82
|
-
strictly apart, because each calls for a different action:
|
|
73
|
+
To switch later: click the dot at the left of a row.
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
|---|---|
|
|
86
|
-
| `642.44 CNY` / `55.48 USD` | An amount was read |
|
|
87
|
-
| `rolling 100% · weekly 81% · monthly 75%` | This relay reports **usage windows**, not money |
|
|
88
|
-
| **余额未尽** (no balance API; verified live: …) | No balance API, but a live request **succeeded** ⇒ the account is not blocked for lack of credit. **Not an amount** (see below) |
|
|
89
|
-
| 不支持查询 / 读取失败 / 未配置密钥 | Three different kinds of "nothing" |
|
|
75
|
+
### 3. Start using it
|
|
90
76
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
> works, and the account is not blocked for lack of credit (an exhausted account answers
|
|
94
|
-
> 402/quota, not 200). So the panel says only 「未尽」 and **never fabricates an amount** —
|
|
95
|
-
> printing `0.00` would read as "you are out of credit", the opposite of the truth.
|
|
77
|
+
In the model picker, choose **DeepSeek V4.1 Flash** (the provider is `any-deepseek`).
|
|
78
|
+
Every request then goes to whichever channel you selected.
|
|
96
79
|
|
|
97
|
-
|
|
98
|
-
> to opposite actions.
|
|
80
|
+
## Three things you will actually do
|
|
99
81
|
|
|
100
|
-
###
|
|
82
|
+
### Switch channels
|
|
101
83
|
|
|
102
|
-
|
|
84
|
+
Click the dot at the left of a row.
|
|
103
85
|
|
|
104
|
-
|
|
86
|
+
> ⚠️ **Switching invalidates the prompt cache for the running conversation**, so switch at a topic
|
|
87
|
+
> boundary, or just start a new session.
|
|
105
88
|
|
|
106
|
-
|
|
107
|
-
**input** is uncached input only, cache reads and writes are separate columns, and the three
|
|
108
|
-
together are the **billable input**. Treating "input" as the total makes it look under-reported.
|
|
89
|
+
### See how much credit is left
|
|
109
90
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
identically, and those two call for opposite fixes. `—` means unmeasured, **not zero**.
|
|
91
|
+
Click **查询余额** (Check balance). It does not run when the panel opens — each check calls every
|
|
92
|
+
provider's server.
|
|
113
93
|
|
|
114
|
-
|
|
94
|
+
Different providers can report different things, and the panel keeps them apart:
|
|
115
95
|
|
|
116
|
-
|
|
117
|
-
|
|
96
|
+
| What you see | Meaning |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `642.44 CNY`, `55.48 USD` | This provider reports an amount |
|
|
99
|
+
| `rolling 100% · weekly 81% · monthly 75%` | This provider reports **subscription usage percentages**, not money |
|
|
100
|
+
| **余额未尽** (verified live: …) | This provider has **no balance API**, but a minimal live request **succeeded** ⇒ the account is not blocked |
|
|
101
|
+
| 不支持查询 / 读取失败 / 未配置密钥 | Three different kinds of "nothing" |
|
|
118
102
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
opencode-go:
|
|
124
|
-
apiKey: sk-… # the key itself
|
|
125
|
-
open-design:
|
|
126
|
-
preset: open-design
|
|
127
|
-
label: Open Design (main) # optional display name
|
|
128
|
-
usage:
|
|
129
|
-
enabled: true
|
|
130
|
-
```
|
|
103
|
+
> **"Not exhausted" is not "how much is left".** One successful request proves exactly three
|
|
104
|
+
> things: the endpoint is reachable, the key is valid, and the account is not blocked for lack of
|
|
105
|
+
> credit (an exhausted account answers 402, not 200). So the panel says only 「未尽」 and **never
|
|
106
|
+
> invents an amount**.
|
|
131
107
|
|
|
132
|
-
|
|
108
|
+
### See what this month cost
|
|
133
109
|
|
|
134
|
-
|
|
135
|
-
- **fully declared** — `baseURL` + `model` required, `api` defaults to `openai-completions`,
|
|
136
|
-
and `contextWindow` / `maxTokens` fall back to documented defaults (the panel shows ⚠ on the
|
|
137
|
-
row when a default was applied rather than declared).
|
|
110
|
+
Switch to the **用量** (Usage) tab.
|
|
138
111
|
|
|
139
|
-
|
|
112
|
+

|
|
140
113
|
|
|
141
|
-
|
|
142
|
-
|
|
114
|
+
Group by channel or by day. "Input" counts only cache misses; cache reads and writes are separate
|
|
115
|
+
columns, and the three together are the billable input. In the speed column, `—` means
|
|
116
|
+
**unmeasured — not zero**.
|
|
143
117
|
|
|
144
|
-
|
|
145
|
-
layers verbatim and does **not** redact, so a diagnostic dump or a `git diff` of the profile
|
|
146
|
-
includes it. **Do not share the profile document.** Environment-variable injection
|
|
147
|
-
(`-e SOME_KEY=…`) is not consulted — nothing resolves a name.
|
|
118
|
+
## Is my key safe
|
|
148
119
|
|
|
149
|
-
|
|
150
|
-
> the credential centre" — a UI that does not exist. The current design is one field, one store,
|
|
151
|
-
> one write.
|
|
120
|
+
**It is stored in your local configuration file, in plaintext.**
|
|
152
121
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
does not, it cannot be one, so it is adopted as the key itself. `apiKey` always wins when both are
|
|
156
|
-
present, so re-entering the key once in the panel migrates an entry.
|
|
122
|
+
The path is `channels.<channel-id>.apiKey` inside the profile. The plugin never sends it to any
|
|
123
|
+
third party, but:
|
|
157
124
|
|
|
158
|
-
|
|
159
|
-
|
|
125
|
+
> ⚠️ `dsh --dump-config` prints the configuration verbatim and does **not** redact it. So:
|
|
126
|
+
> **do not share your profile configuration**, and do not paste its `git diff` anywhere public.
|
|
160
127
|
|
|
161
|
-
|
|
128
|
+
If you need to share config for troubleshooting, delete the `apiKey` lines first.
|
|
162
129
|
|
|
163
|
-
|
|
164
|
-
exposes the largest compatibility surface (~20 switches), and its usage normalization already
|
|
165
|
-
reconciles the three cache-token spellings relays use
|
|
166
|
-
(`prompt_tokens_details.cached_tokens`, `prompt_cache_hit_tokens`, top-level `cached_tokens`).
|
|
130
|
+
## Troubleshooting
|
|
167
131
|
|
|
168
|
-
|
|
169
|
-
|
|
132
|
+
**The model list has no DeepSeek V4.1 Flash.**
|
|
133
|
+
→ You have not restarted since installing. Restart DSH.
|
|
170
134
|
|
|
171
|
-
|
|
135
|
+
**Settings has no "Any DeepSeek".**
|
|
136
|
+
→ Same; or check you installed into the `web` profile: `dsh plugin --profile web list`.
|
|
172
137
|
|
|
173
|
-
|
|
174
|
-
|
|
138
|
+
**`MISSING_CREDENTIAL`.**
|
|
139
|
+
→ That channel has no key yet. Its status dot is hollow; click 「填写密钥」 to add one.
|
|
175
140
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
```
|
|
141
|
+
**`NO_CHANNEL_SELECTED`.**
|
|
142
|
+
→ No channel is selected. The panel shows a hint at the bottom; click any row's dot.
|
|
179
143
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
144
|
+
**「查询余额」 shows 「读取失败」.**
|
|
145
|
+
→ That provider did not answer properly just now; retry. If it never works, your network may not
|
|
146
|
+
reach it.
|
|
183
147
|
|
|
184
|
-
|
|
148
|
+
**401 / 403 / out of credit.**
|
|
149
|
+
→ The key is wrong or expired, or that account really is out of money.
|
|
185
150
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
151
|
+
**Answers got slower or worse after switching.**
|
|
152
|
+
→ Providers do not behave identically. Use the 测试 (Test) button per channel, and the 用量 tab to
|
|
153
|
+
compare speeds.
|
|
189
154
|
|
|
190
155
|
## Why no failover
|
|
191
156
|
|
|
192
|
-
|
|
193
|
-
to another:
|
|
157
|
+
A failing channel reports its own error; it never silently moves to another. Three reasons:
|
|
194
158
|
|
|
195
159
|
- Silent failover makes "who answered this?" unknowable, while the usage table honestly records
|
|
196
|
-
the other
|
|
160
|
+
the other provider — the two parts would disagree.
|
|
197
161
|
- Switching mid-conversation invalidates the prompt cache, costing more than the failure saved.
|
|
198
|
-
- Failure is information.
|
|
199
|
-
|
|
200
|
-
## Adding a channel
|
|
201
|
-
|
|
202
|
-
This is a **small practical plugin**, and adding a relay is the most valuable contribution —
|
|
203
|
-
usually it touches one file.
|
|
204
|
-
|
|
205
|
-
### Add a preset (the common case)
|
|
206
|
-
|
|
207
|
-
Edit [`src/presets.ts`](src/presets.ts) and add an entry to `CHANNEL_PRESETS`:
|
|
208
|
-
|
|
209
|
-
```ts
|
|
210
|
-
'your-relay': {
|
|
211
|
-
displayName: 'Your Relay',
|
|
212
|
-
api: 'openai-completions',
|
|
213
|
-
baseURL: 'https://your-relay.example/v1',
|
|
214
|
-
// 🔴 Use THIS relay's spelling. Model ids differ per relay:
|
|
215
|
-
// deepseek-v4.1-flash / deepseek/deepseek-v4.1-flash / deepseek-flash …
|
|
216
|
-
// A wrong spelling does not error here — the upstream rejects it on the first request.
|
|
217
|
-
model: 'deepseek-v4.1-flash',
|
|
218
|
-
...V41_FLASH_CAPS,
|
|
219
|
-
// Optional: does this relay expose a balance surface, and which shape?
|
|
220
|
-
// balance: { shape: 'openai-billing' },
|
|
221
|
-
},
|
|
222
|
-
```
|
|
162
|
+
- Failure is information. Hide it and you never learn a provider is degrading.
|
|
223
163
|
|
|
224
|
-
|
|
164
|
+
## Adding a provider
|
|
225
165
|
|
|
226
|
-
|
|
166
|
+
Five are bundled; adding another usually touches one file. See
|
|
167
|
+
**[CONTRIBUTING.md](CONTRIBUTING.md)**.
|
|
227
168
|
|
|
228
|
-
|
|
229
|
-
carried a `Probed live: the billing pair answers` comment for a route that had never been
|
|
230
|
-
called; the first real call returned 404. **A false claim is worse than no comment**, because
|
|
231
|
-
it stops the next reader from checking.
|
|
232
|
-
2. **`model` is the upstream spelling, not our id.** We expose exactly one id,
|
|
233
|
-
`deepseek-v4.1-flash`; per-relay spellings are absorbed by presets — that is the whole point
|
|
234
|
-
of this plugin.
|
|
169
|
+
## Configuration reference (advanced)
|
|
235
170
|
|
|
236
|
-
|
|
171
|
+
Everything lives under the `dsh-any-deepseek` namespace:
|
|
237
172
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
173
|
+
```yaml
|
|
174
|
+
dsh-any-deepseek:
|
|
175
|
+
current: opencode-go # the current channel
|
|
176
|
+
channels:
|
|
177
|
+
opencode-go:
|
|
178
|
+
apiKey: sk-… # the key itself
|
|
179
|
+
open-design:
|
|
180
|
+
preset: open-design # use a bundled preset
|
|
181
|
+
label: Open Design (main) # optional display name
|
|
182
|
+
my-relay:
|
|
183
|
+
baseURL: https://relay.example/v1 # or declare it fully
|
|
184
|
+
model: deepseek-v4.1-flash
|
|
185
|
+
apiKey: sk-…
|
|
186
|
+
usage:
|
|
187
|
+
enabled: true
|
|
249
188
|
```
|
|
250
189
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
190
|
+
**Protocol**: defaults to `openai-completions` (almost every relay speaks it). Set `api:
|
|
191
|
+
openai-responses` or `api: anthropic-messages` on **that one channel** only when it really speaks
|
|
192
|
+
something else.
|
|
254
193
|
|
|
255
|
-
|
|
194
|
+
**Thinking level**: each channel declares which levels it supports, and the level you pick in the
|
|
195
|
+
UI is the one sent upstream. Unsupported levels are not offered in the picker.
|
|
256
196
|
|
|
257
|
-
|
|
258
|
-
- Exposes exactly one model id. Upstream ids differ per relay and are mapped in presets.
|
|
259
|
-
- **No cost estimation** (there is no price table).
|
|
260
|
-
- **No automatic failover** (v1, see above).
|
|
261
|
-
- **No multi-model aggregation** — this is "one model, many sources", not a model router.
|
|
197
|
+
**Images**: sending and receiving images is supported.
|
|
262
198
|
|
|
263
|
-
|
|
199
|
+
**Legacy config**: early versions stored the key in `apiKeyEnv`. That field is still read — a value
|
|
200
|
+
that looks like an environment-variable name is resolved as one, otherwise it is used as the key
|
|
201
|
+
itself. `apiKey` always wins, so re-entering the key once in the panel migrates the entry.
|
|
264
202
|
|
|
265
|
-
|
|
203
|
+
## Boundaries
|
|
266
204
|
|
|
267
|
-
-
|
|
268
|
-
-
|
|
269
|
-
|
|
270
|
-
- **
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
Source: <https://github.com/tellmewhattodo/dsh-any-deepseek>
|
|
205
|
+
- Does not modify Harness itself, and does not replace the built-in `deepseek-official` route.
|
|
206
|
+
- Exposes exactly one model id (`deepseek-v4.1-flash`); per-provider upstream ids are mapped by
|
|
207
|
+
presets.
|
|
208
|
+
- **No cost estimation** — there is no price table, only token counts.
|
|
209
|
+
- **No automatic failover** (v1).
|
|
210
|
+
- **No multi-model aggregation**.
|
|
274
211
|
|
|
275
212
|
## License
|
|
276
213
|
|
|
277
|
-
MIT
|
|
214
|
+
MIT. This is a small practical tool — forks, issues and PRs are welcome. See
|
|
215
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
216
|
+
|
|
217
|
+
<https://github.com/tellmewhattodo/dsh-any-deepseek>
|
package/README.md
CHANGED
|
@@ -1,248 +1,199 @@
|
|
|
1
1
|
# dsh-any-deepseek
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**在 DeepSeek Harness 里,用多家渠道的 DeepSeek 额度,而模型列表里只多出一行。**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
你在好几处买过 DeepSeek 的额度:官方、某家中转、某个云厂商、朋友推荐的便宜渠道。
|
|
6
|
+
这个插件把它们收进**一个** provider,你粘几个 key、点一下就能换 —— 同时按真实渠道分开记账,
|
|
7
|
+
你知道这个月每一家各花了多少 token。
|
|
6
8
|
|
|
7
|
-
[
|
|
9
|
+

|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
[English](README.en.md) · 中文(本页)
|
|
10
12
|
|
|
11
13
|
---
|
|
12
14
|
|
|
13
|
-
##
|
|
15
|
+
## 装之前先看一眼:它适合你吗
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
在 DeepSeek Harness 里,它们本来会变成**模型选择器里的 N 个条目**,而每次换渠道都要改配置、
|
|
17
|
-
换模型名、换 key,还得自己记住这个月哪个渠道花了多少 token。
|
|
17
|
+
**适合**,如果你符合下面任意一条:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
- 你有**不止一个** DeepSeek 渠道,并且想在 Harness 里随意切换而不用改配置。
|
|
20
|
+
- 你想要**按渠道分开的用量统计**,而不是所有请求混成一个总数。
|
|
21
|
+
- 你用中转站,而它们的模型名各不相同(`deepseek-v4.1-flash` / `deepseek/deepseek-v4.1-flash` /
|
|
22
|
+
`deepseek-flash`),懒得每次自己对应。
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
- 下面挂**任意多个渠道**,每个渠道 = 一个端点 + 一个 key + 一个显示名。
|
|
23
|
-
- 点哪个渠道的圆点,请求就发到哪个。**不会自动切换**(见 [为什么不做自动切换](#为什么不做自动切换))。
|
|
24
|
-
- 用量按**真实上游**分别记账。
|
|
24
|
+
**不适合**,如果:
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
│ ├── 渠道 B(某中转)
|
|
30
|
-
▼ └── 渠道 C(另一家)
|
|
31
|
-
any-deepseek
|
|
32
|
-
/ deepseek-v4.1-flash
|
|
33
|
-
(唯一对外模型)
|
|
34
|
-
```
|
|
26
|
+
- 你只有一个渠道,且它就是官方 —— Harness 自带的 `deepseek-official` 已经够用,不必装。
|
|
27
|
+
- 你想要**自动故障转移**(一家挂了自动换下一家)。本插件 v1 不做,见 [为什么不做自动切换](#为什么不做自动切换)。
|
|
28
|
+
- 你想要**多模型切换**。这个插件是「一个模型、多个来源」,不是模型路由器。
|
|
35
29
|
|
|
36
30
|
## 安装
|
|
37
31
|
|
|
32
|
+
需要已经装好 DeepSeek Harness。在终端执行:
|
|
33
|
+
|
|
38
34
|
```bash
|
|
39
35
|
dsh plugin --profile web add dsh-any-deepseek
|
|
40
36
|
```
|
|
41
37
|
|
|
42
38
|
然后**重启 DSH**,打开 设置 → **Any DeepSeek**。
|
|
43
39
|
|
|
44
|
-
>
|
|
45
|
-
>
|
|
46
|
-
>
|
|
47
|
-
> `dsh plugin` 会把参数转给 pnpm,所以 `add` 后面可以是 registry 名、tarball 路径或本地目录。
|
|
48
|
-
|
|
49
|
-
## 用法
|
|
50
|
-
|
|
51
|
-
### 加一个渠道
|
|
52
|
-
|
|
53
|
-
点 **添加渠道**,只有两样东西是必填的:
|
|
54
|
-
|
|
55
|
-
| 字段 | 必填 | 说明 |
|
|
56
|
-
|---|---|---|
|
|
57
|
-
| **规格** | ✅ | 决定端点地址、上游模型名、协议。选它这三样就不用填了。 |
|
|
58
|
-
| **渠道 id** | ✅ | 配置里的键名,`[a-z0-9][a-z0-9_-]*`。同规格可加多次,第二个自动变成 `-2`。 |
|
|
59
|
-
| **显示名** | — | 只影响界面显示。同一家开两个号时靠它区分。**改名不动 id。** |
|
|
60
|
-
| **密钥** | ✅ | 服务商给你的那串 key 本体,不需要先起名字。 |
|
|
61
|
-
|
|
62
|
-
内置规格:**DeepSeek 官方**、**OpenCode Go**、**Ollama Cloud**、**Open Design**、**CommandCode**。
|
|
63
|
-
想接别的中转,见 [加一个新渠道](#加一个新渠道要改什么)。
|
|
64
|
-
|
|
65
|
-
### 切换渠道
|
|
40
|
+
> **为什么必须重启**:插件被加进了 profile 的加载列表,而这份列表只在 DSH 启动时读取。
|
|
41
|
+
> 之后改这个插件的界面部分只需刷新浏览器,但**第一次装**一定要重启。
|
|
66
42
|
|
|
67
|
-
|
|
43
|
+
## 第一次用:三步
|
|
68
44
|
|
|
69
|
-
|
|
45
|
+
### 第 1 步:加一个渠道
|
|
70
46
|
|
|
71
|
-
|
|
47
|
+
点 **添加渠道**,填两个必填项就能用:
|
|
72
48
|
|
|
73
|
-
|
|
49
|
+

|
|
74
50
|
|
|
75
|
-
|
|
|
51
|
+
| 填什么 | 说明 |
|
|
76
52
|
|---|---|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
| **余额未尽**(无余额接口,实测可用:…) | 这家没有余额接口,但**实测能用** ⇒ 账户没欠费。**不代表余额数字**(见下) |
|
|
80
|
-
| 不支持查询 / 读取失败 / 未配置密钥 | 三种不同的"没有" |
|
|
53
|
+
| **规格** | 选你用的那家。它决定地址、模型名、协议,所以这三样你不用管。 |
|
|
54
|
+
| **密钥** | 那家给你的 key,直接粘。不需要先起名字。 |
|
|
81
55
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
> 所以面板只写「未尽」,**绝不编一个金额**——写 `0.00` 会被读成"你没钱了",与事实正相反。
|
|
56
|
+
**渠道 id** 会自动填好(可以改,只是配置里的键名)。**显示名**留空的话用规格的默认名 ——
|
|
57
|
+
同一家开两个号时,填上「主号」「备号」之类会好认。
|
|
85
58
|
|
|
86
|
-
|
|
59
|
+
内置规格:DeepSeek Official、OpenCode Go、Ollama Cloud、Open Design、CommandCode
|
|
60
|
+
(这些名字与下拉框里显示的完全一致)。
|
|
61
|
+
要接别家,见 [接一个新渠道](#接一个新渠道)。
|
|
87
62
|
|
|
88
|
-
###
|
|
63
|
+
### 第 2 步:确认它选中了
|
|
89
64
|
|
|
90
|
-
|
|
65
|
+
第一个加进去的渠道会**自动成为当前渠道**,行首有圆点、左侧有色条、右侧有「当前」标记。
|
|
91
66
|
|
|
92
|
-
|
|
67
|
+
以后想换:点那一行左边的圆点即可。
|
|
93
68
|
|
|
94
|
-
|
|
95
|
-
**缓存读** / **缓存写**单独成列,三者相加才是**计费输入**。把「输入」直接当总量会得出
|
|
96
|
-
"输入被少报了"的错误结论。
|
|
69
|
+
### 第 3 步:开始用
|
|
97
70
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
`—` 表示没测到,**不是 0**。
|
|
71
|
+
在模型的对话界面里选模型,选 **DeepSeek V4.1 Flash**(provider 名是 `any-deepseek`)。
|
|
72
|
+
之后所有请求都会发到你选中的那个渠道。
|
|
101
73
|
|
|
102
|
-
##
|
|
74
|
+
## 日常会用到的三件事
|
|
103
75
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
```yaml
|
|
107
|
-
dsh-any-deepseek:
|
|
108
|
-
current: opencode-go # 当前渠道
|
|
109
|
-
channels:
|
|
110
|
-
opencode-go:
|
|
111
|
-
apiKey: sk-… # key 本体
|
|
112
|
-
open-design:
|
|
113
|
-
preset: open-design
|
|
114
|
-
label: Open Design(主号) # 可选,显示名
|
|
115
|
-
usage:
|
|
116
|
-
enabled: true
|
|
117
|
-
```
|
|
76
|
+
### 换一个渠道
|
|
118
77
|
|
|
119
|
-
|
|
78
|
+
点行首的圆点。
|
|
120
79
|
|
|
121
|
-
|
|
122
|
-
- **完全手写** — `baseURL` + `model` 必填,`api` 默认 `openai-completions`,
|
|
123
|
-
`contextWindow` / `maxTokens` 有文档值兜底(走兜底时面板会在该行显示 ⚠)。
|
|
80
|
+
> ⚠️ **换渠道会让当前对话的 prompt 缓存失效**,所以尽量在话题切换时换,或者干脆新开一个会话。
|
|
124
81
|
|
|
125
|
-
###
|
|
82
|
+
### 看还剩多少钱
|
|
126
83
|
|
|
127
|
-
|
|
84
|
+
点 **查询余额**。它不会在打开面板时自动跑 —— 因为每次都要请求每一家的服务器。
|
|
128
85
|
|
|
129
|
-
|
|
130
|
-
**不脱敏**,所以一次诊断输出、一次 `git diff` 都会带上它。**别把 profile 文件发给别人。**
|
|
131
|
-
环境变量注入(`-e SOME_KEY=…`)不会被查询 —— 没有任何地方去解析一个名字。
|
|
86
|
+
不同家能给出的东西不一样,面板会如实区分:
|
|
132
87
|
|
|
133
|
-
|
|
134
|
-
|
|
88
|
+
| 你看到的 | 意思 |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `642.44 CNY`、`55.48 USD` | 这家能报金额 |
|
|
91
|
+
| `rolling 100% · weekly 81% · monthly 75%` | 这家只给**订阅用量百分比**,不给钱 |
|
|
92
|
+
| **余额未尽**(实测可用:…) | 这家**没有余额接口**,但我发了一次最小请求,**它答了** ⇒ 账户没停 |
|
|
93
|
+
| 不支持查询 / 读取失败 / 未配置密钥 | 三种不同的「没拿到」 |
|
|
135
94
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
就把旧条目迁移完了。
|
|
95
|
+
> **「余额未尽」不等于「还剩多少」。** 一次成功的请求只证明三件事:地址通、key 对、账户没因为欠费被拒
|
|
96
|
+
> (欠费的账户会回 402,不会回 200)。所以这里只写「未尽」,**不会编一个金额给你**。
|
|
139
97
|
|
|
140
|
-
|
|
141
|
-
(`MISSING_CREDENTIAL`),该行的状态点是空心的。
|
|
98
|
+
### 看这个月花了多少
|
|
142
99
|
|
|
143
|
-
|
|
100
|
+
切到 **用量** 分页。
|
|
144
101
|
|
|
145
|
-
|
|
146
|
-
且 usage 的三种缓存字段拼写(`prompt_tokens_details.cached_tokens` /
|
|
147
|
-
`prompt_cache_hit_tokens` / 顶层 `cached_tokens`)已由传输层归一。
|
|
102
|
+

|
|
148
103
|
|
|
149
|
-
|
|
150
|
-
|
|
104
|
+
可以按渠道看,也可以按天看。「输入」只算没命中缓存的部分,缓存读/写单独列出 ——
|
|
105
|
+
三者相加才是计费输入。速度一栏的 `—` 表示没测到,**不是 0**。
|
|
151
106
|
|
|
152
|
-
|
|
107
|
+
## 我的 key 安全吗
|
|
153
108
|
|
|
154
|
-
|
|
109
|
+
**它存在你本机的配置文件里,明文。**
|
|
155
110
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
```
|
|
111
|
+
位置是 profile 的 `channels.<渠道id>.apiKey`。它不会被这个插件发到任何第三方,
|
|
112
|
+
但是:
|
|
159
113
|
|
|
160
|
-
|
|
161
|
-
|
|
114
|
+
> ⚠️ `dsh --dump-config` 会把配置原样打印出来、**不做脱敏**。所以:
|
|
115
|
+
> **别把 profile 配置文件发给别人**,也别把它的 `git diff` 贴到公开的地方。
|
|
162
116
|
|
|
163
|
-
|
|
117
|
+
如果你需要分享配置做排查,先把 `apiKey` 那几行删掉。
|
|
164
118
|
|
|
165
|
-
|
|
166
|
-
(`inputModalities`),不是写在请求处理里。这是个踩过的坑:能力是 provider 的属性,
|
|
167
|
-
不是某条渠道或某次请求的属性。
|
|
119
|
+
## 出问题了
|
|
168
120
|
|
|
169
|
-
|
|
121
|
+
**模型列表里没有 DeepSeek V4.1 Flash。**
|
|
122
|
+
→ 装完还没重启。重启 DSH。
|
|
170
123
|
|
|
171
|
-
|
|
124
|
+
**设置里找不到「Any DeepSeek」。**
|
|
125
|
+
→ 同上;或确认装的是 `web` 这个 profile:`dsh plugin --profile web list`。
|
|
172
126
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
- 失败是信息。把它藏起来,你就不知道某个渠道正在坏掉。
|
|
127
|
+
**报 `MISSING_CREDENTIAL`。**
|
|
128
|
+
→ 这个渠道还没填 key。面板里那一行的状态点是空心的,点「填写密钥」补上。
|
|
176
129
|
|
|
177
|
-
|
|
130
|
+
**报 `NO_CHANNEL_SELECTED`。**
|
|
131
|
+
→ 一个渠道都没选中。面板底部会有提示,点任意一行的圆点即可。
|
|
178
132
|
|
|
179
|
-
|
|
133
|
+
**「查询余额」显示「读取失败」。**
|
|
134
|
+
→ 这家服务器这会儿没答好,稍后再试。如果一直这样,可能是网络到不了它。
|
|
180
135
|
|
|
181
|
-
|
|
136
|
+
**报 401 / 403 / 余额不足。**
|
|
137
|
+
→ key 不对或过期,或者那家账户真的没钱了。
|
|
182
138
|
|
|
183
|
-
|
|
139
|
+
**换渠道以后回答变慢/变差。**
|
|
140
|
+
→ 不同家的模型行为不完全一样。用「测试」按钮逐家试,用「用量」分页看各家的速度。
|
|
184
141
|
|
|
185
|
-
|
|
186
|
-
'your-relay': {
|
|
187
|
-
displayName: 'Your Relay',
|
|
188
|
-
api: 'openai-completions',
|
|
189
|
-
baseURL: 'https://your-relay.example/v1',
|
|
190
|
-
// 🔴 用**这家自己的**拼写。各家中转的模型名不同:
|
|
191
|
-
// deepseek-v4.1-flash / deepseek/deepseek-v4.1-flash / deepseek-flash …
|
|
192
|
-
// 抄错不会报错,只会在第一次请求时被上游拒。
|
|
193
|
-
model: 'deepseek-v4.1-flash',
|
|
194
|
-
...V41_FLASH_CAPS,
|
|
195
|
-
// 可选:这家有没有余额接口、是什么形状(见 src/balance.ts 的四种 shape)
|
|
196
|
-
// balance: { shape: 'openai-billing' },
|
|
197
|
-
},
|
|
198
|
-
```
|
|
142
|
+
## 为什么不做自动切换
|
|
199
143
|
|
|
200
|
-
|
|
144
|
+
一个渠道失败就**报它自己的错**,不会静默换到另一家。三个理由:
|
|
201
145
|
|
|
202
|
-
|
|
146
|
+
- 静默切换会让「这次答案是谁给的」变得不可知,而用量表会照实记另一家 —— 两处对不上。
|
|
147
|
+
- 半路换渠道会让 prompt 缓存失效,成本比你省下的那次失败更高。
|
|
148
|
+
- 失败是信息。藏起来,你就不知道某家正在坏掉。
|
|
203
149
|
|
|
204
|
-
|
|
205
|
-
`Probed live: the billing pair answers` 的注释,而它从没被调用过,第一次真调用就 404。
|
|
206
|
-
**假证据比没有注释更坏**,因为它让下一个读者不再去查。
|
|
207
|
-
2. **`model` 用上游的拼写,不是我们的 id。** 我们对外只暴露 `deepseek-v4.1-flash` 一个 id,
|
|
208
|
-
上游拼写由预设吸收 —— 这正是这个插件存在的理由。
|
|
150
|
+
## 接一个新渠道
|
|
209
151
|
|
|
210
|
-
|
|
152
|
+
内置了 5 家,接别家通常只需要改一个文件。见 **[CONTRIBUTING.md](CONTRIBUTING.md)**。
|
|
211
153
|
|
|
212
|
-
|
|
213
|
-
加一个 `shape`、加一个 `parseXxx()`、在 `balanceUrls()` 里给路径、在 `readBalance()` 里分发。
|
|
214
|
-
`balanceUrls()` 是**唯一**知道路径的地方,所以预设无法与传输层意见相左。
|
|
154
|
+
## 配置参考(进阶)
|
|
215
155
|
|
|
216
|
-
|
|
156
|
+
设置都在 `dsh-any-deepseek` 这个命名空间下:
|
|
217
157
|
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
158
|
+
```yaml
|
|
159
|
+
dsh-any-deepseek:
|
|
160
|
+
current: opencode-go # 当前渠道
|
|
161
|
+
channels:
|
|
162
|
+
opencode-go:
|
|
163
|
+
apiKey: sk-… # key 本体
|
|
164
|
+
open-design:
|
|
165
|
+
preset: open-design # 用内置规格
|
|
166
|
+
label: Open Design(主号) # 可选,显示名
|
|
167
|
+
my-relay:
|
|
168
|
+
baseURL: https://relay.example/v1 # 或者完全手写
|
|
169
|
+
model: deepseek-v4.1-flash
|
|
170
|
+
apiKey: sk-…
|
|
171
|
+
usage:
|
|
172
|
+
enabled: true
|
|
222
173
|
```
|
|
223
174
|
|
|
224
|
-
|
|
225
|
-
|
|
175
|
+
**协议**:默认 `openai-completions`(几乎所有中转都说它)。只有当某家真的说别的协议时,
|
|
176
|
+
在**那一个**渠道上设 `api: openai-responses` 或 `api: anthropic-messages`。
|
|
226
177
|
|
|
227
|
-
|
|
178
|
+
**思考强度**:每个渠道声明自己支持哪些档位,你在界面上选哪档就传到哪档。
|
|
179
|
+
声明成不支持的档位不会出现在选择器里。
|
|
228
180
|
|
|
229
|
-
|
|
230
|
-
- 只暴露一个模型 id。上游模型 id 各家不同,由预设映射。
|
|
231
|
-
- **不做费用估算**(没有价目表)。
|
|
232
|
-
- **不做自动故障转移**(v1,见上)。
|
|
233
|
-
- **不做多模型聚合** —— 这个插件就是"一个模型、多个来源",不是模型路由器。
|
|
181
|
+
**图片**:支持收发图片。
|
|
234
182
|
|
|
235
|
-
|
|
183
|
+
**兼容旧配置**:早期版本把 key 存在 `apiKeyEnv` 里。这个字段仍会被读:
|
|
184
|
+
值像环境变量名就当名字解析,不像就直接当 key 用。`apiKey` 存在时永远优先 ——
|
|
185
|
+
所以在面板里重填一次 key 就迁移完了。
|
|
236
186
|
|
|
237
|
-
|
|
187
|
+
## 边界
|
|
238
188
|
|
|
239
|
-
-
|
|
240
|
-
-
|
|
241
|
-
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
源码:<https://github.com/tellmewhattodo/dsh-any-deepseek>
|
|
189
|
+
- 不修改 Harness 本体,也不替代自带的 `deepseek-official` 路由。
|
|
190
|
+
- 只暴露一个模型 id(`deepseek-v4.1-flash`);各家的上游模型名由规格映射。
|
|
191
|
+
- **不做费用估算** —— 没有价目表,只有 token 数。
|
|
192
|
+
- **不做自动故障转移**(v1)。
|
|
193
|
+
- **不做多模型聚合**。
|
|
245
194
|
|
|
246
195
|
## 许可
|
|
247
196
|
|
|
248
|
-
MIT
|
|
197
|
+
MIT。这是个实用小工具,欢迎 fork、提 issue、发 PR —— 见 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
|
198
|
+
|
|
199
|
+
<https://github.com/tellmewhattodo/dsh-any-deepseek>
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-any-deepseek",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "One DeepSeek V4.1 Flash provider for DeepSeek Harness: paste a key per channel, switch channels manually, token usage booked per real upstream.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"cordis.patch.yml",
|
|
31
31
|
"README.md",
|
|
32
32
|
"README.en.md",
|
|
33
|
+
"CONTRIBUTING.md",
|
|
33
34
|
"docs/*.png",
|
|
34
35
|
"LICENSE"
|
|
35
36
|
],
|