dsh-magpie-connect 0.2.0 → 0.2.1
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/README.md +110 -83
- package/cordis.patch.yml +4 -4
- package/dsh.plugin.json +1 -1
- package/lib/client.js +2 -2
- package/lib/index.js +6 -6
- package/lib/index.js.map +2 -2
- package/lib/types/adapter/catalog.d.ts +4 -5
- package/lib/types/adapter/magpie-adapter.d.ts +2 -2
- package/lib/types/config.d.ts +12 -8
- package/package.json +16 -1
package/README.md
CHANGED
|
@@ -1,76 +1,98 @@
|
|
|
1
1
|
# dsh-magpie-connect
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
把 Magpie 局域网网关上的模型接进 DeepSeek Harness(DSH)的模型选择器。
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
every model from the gateway's `GET …/models` in the DSH model picker as provider
|
|
7
|
-
`dsh-magpie-connect` (picker label `magpie`).
|
|
5
|
+
装好之后,你就能在 DSH 里直接选用网关提供的模型,不需要额外跑进程,也不用配代理。
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
> API key on the Settings → Magpie page (or via `cordis.patch.yml`). Both
|
|
11
|
-
> are required — until then the picker stays empty and calls fail fast with
|
|
12
|
-
> a "not configured" error.
|
|
7
|
+
## 功能
|
|
13
8
|
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
`ultra` 扩展档),直通网关不截断;过期档位按就近原则收敛,不会 400
|
|
9
|
+
- **模型自动同步** — 网关列出的模型全部进入 DSH 模型选择器,想显示哪些由你决定。
|
|
10
|
+
- **图片识别** — 网关声明支持图片的模型可以直接发图。
|
|
11
|
+
- **思考档位** — 网关支持的思考档位(含 `none`、`ultra`)原样出现在选择器里。
|
|
12
|
+
- **接口自动分流** — 网关需要哪种接口就自动用哪种,你不用管。
|
|
13
|
+
- **网关不通也能用** — 选择器用本地缓存兜底,不会整个空掉。
|
|
20
14
|
|
|
21
|
-
##
|
|
15
|
+
## 安装
|
|
22
16
|
|
|
23
17
|
```sh
|
|
24
18
|
dsh plugin --profile web add dsh-magpie-connect
|
|
25
19
|
```
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
Node.js ≥ 20; LAN route to `http://api.lan`.
|
|
21
|
+
安装后重启 `dsh web`。
|
|
29
22
|
|
|
30
|
-
|
|
23
|
+
已有安装用同一条命令即可更新到最新版本。
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
connection (reports how many models the endpoint serves), and choose which
|
|
34
|
-
models appear in the model picker. Everything saves to
|
|
35
|
-
`~/.dsh-magpie-connect/settings.json` and applies immediately — no restart.
|
|
25
|
+
**需要**:DSH 的 web profile、Node.js ≥ 20、能访问网关所在局域网。
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
增删会自动保存**,不需要、也没有保存按钮。因为模型卡片在连接卡片下方,一个管全部
|
|
39
|
-
的保存按钮会让"删了一行"看起来已经生效——它其实没有。自动保存通过队列串行化,
|
|
40
|
-
连点多次删除不会因为响应乱序而把旧集合写回磁盘。
|
|
27
|
+
## 使用
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
(`/models`、`/chat/completions`、`/responses`),**绝不自己补版本号**。网关以后
|
|
44
|
-
上 `/v2`、`/v3` 时,只改这一个字符串即可,不会拼成 `/v2/v1/models`。尾斜杠会被
|
|
45
|
-
去掉,路径原样保留。
|
|
29
|
+
### 第一步:填网关地址和 Key
|
|
46
30
|
|
|
47
|
-
|
|
48
|
-
保存的),所以填一个新网关是一趟而不是"保存—返回—再看"。弹窗里可搜索、可全选/
|
|
49
|
-
取消全选、逐个勾选,**应用选择**把勾选结果换算成隐藏集合。列表只显示已启用的模型,
|
|
50
|
-
隐藏的只在弹窗里;行尾的「删除」即隐藏,重新加回也在弹窗。保存时会清掉网关已经
|
|
51
|
-
不再提供的陈旧 id。查不通不会卡死——失败信息就显示在列表下方,行仍然可以手改。
|
|
31
|
+
打开 **设置 → Magpie 网关**,确认两项:
|
|
52
32
|
|
|
53
|
-
|
|
54
|
-
|
|
33
|
+
- **API 地址** — 网关地址,**要带版本号**。默认已填好 `http://127.0.0.1:3425/v1`,网关不在本机时改成实际地址。
|
|
34
|
+
- **API Key** — 网关凭据,必填。
|
|
55
35
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
to — the browser caches one catalog read per Host generation, so without it
|
|
59
|
-
the picker keeps the stale list until `dsh web` restarts.
|
|
36
|
+
点「保存」后,可以点「测试连接」确认通不通(会告诉你网关上有多少模型)。两项都齐了才会生效——
|
|
37
|
+
地址有默认值,Key 没有,所以没填 Key 之前模型选择器是空的。
|
|
60
38
|
|
|
61
|
-
|
|
39
|
+
> **地址一定要带版本段**(如 `/v1`)。插件只在你填的地址后面接资源名,不会自己补
|
|
40
|
+
> 版本号——所以网关以后升级到 `/v2`、`/v3`,你只要改这一个字符串。
|
|
62
41
|
|
|
63
|
-
|
|
64
|
-
|
|
42
|
+
### 第二步:选择要显示的模型
|
|
43
|
+
|
|
44
|
+
点 **获取可用模型**,会弹出网关当前的模型列表:勾选你想要的,再点「应用选择」。
|
|
45
|
+
弹窗里可以搜索、全选、取消全选。
|
|
46
|
+
|
|
47
|
+
主列表只显示已启用的模型。不想要的点该行末尾的「删除」,它就会从选择器里消失;
|
|
48
|
+
想加回来,再回到弹窗里勾选。
|
|
49
|
+
|
|
50
|
+
> 弹窗查的是**你当前填的地址和 Key**(哪怕还没保存),所以换网关是一趟的事。
|
|
51
|
+
> 连不上也不会卡住——失败原因会显示在列表下方,已列出的行仍然可以操作。
|
|
52
|
+
|
|
53
|
+
### 什么时候需要保存
|
|
54
|
+
|
|
55
|
+
- **地址和 Key**:点「保存」才生效。
|
|
56
|
+
- **模型增删**:**自动保存**,不用点任何按钮。
|
|
57
|
+
|
|
58
|
+
## 常见问题
|
|
59
|
+
|
|
60
|
+
**模型选择器是空的?**
|
|
61
|
+
|
|
62
|
+
先确认地址和 Key 都填了并且已经保存,再点「测试连接」。最常见的原因是地址缺了版本段
|
|
63
|
+
(比如填成 `http://127.0.0.1:3425`,而应该是 `http://127.0.0.1:3425/v1`)。
|
|
64
|
+
|
|
65
|
+
**删掉的模型怎么加回来?**
|
|
66
|
+
|
|
67
|
+
点「获取可用模型」,在弹窗里重新勾上,再点「应用选择」。
|
|
68
|
+
|
|
69
|
+
**改了网关地址,模型列表没变?**
|
|
70
|
+
|
|
71
|
+
保存后列表会重新拉取。如果新网关暂时不通,会先用本地缓存。
|
|
72
|
+
|
|
73
|
+
**页面提示「未配置」?**
|
|
74
|
+
|
|
75
|
+
地址和 Key 缺任意一项都会这样——此时选择器是空的,调用也会直接失败并给出提示。
|
|
76
|
+
|
|
77
|
+
**发图失败?**
|
|
78
|
+
|
|
79
|
+
只有网关声明支持图片的模型才能收图。如果给纯文本模型发图,会直接报错而不是静默丢弃。
|
|
80
|
+
另外,图片需要通过 harness 的附件服务读取,在没有该服务的组合里也会失败。
|
|
81
|
+
|
|
82
|
+
## 进阶用法
|
|
83
|
+
|
|
84
|
+
### 用配置文件代替设置页
|
|
85
|
+
|
|
86
|
+
除了设置页,也可以在 profile 的 `cordis.patch.yml` 里配置:
|
|
65
87
|
|
|
66
88
|
```yaml
|
|
67
89
|
- id: dsh-magpie-connect
|
|
68
90
|
name: 'dsh-magpie-connect'
|
|
69
91
|
config:
|
|
70
92
|
providerId: dsh-magpie-connect
|
|
71
|
-
displayName:
|
|
72
|
-
baseUrl: http://
|
|
73
|
-
apiKey: not-needed
|
|
93
|
+
displayName: Magpie
|
|
94
|
+
baseUrl: http://127.0.0.1:3425/v1 # 带版本号的完整地址
|
|
95
|
+
apiKey: not-needed # 局域网网关通常不校验,但必须非空
|
|
74
96
|
refreshSeconds: 300
|
|
75
97
|
maxRetries: 2
|
|
76
98
|
timeoutMs: 300000
|
|
@@ -78,56 +100,61 @@ applies instantly) or via the profile's `cordis.patch.yml`:
|
|
|
78
100
|
idleTimeoutMs: 60000
|
|
79
101
|
```
|
|
80
102
|
|
|
81
|
-
|
|
|
103
|
+
| 配置项 | 默认值 | 说明 |
|
|
82
104
|
| --- | --- | --- |
|
|
83
|
-
| `providerId` | `dsh-magpie-connect` |
|
|
84
|
-
| `displayName` | `
|
|
85
|
-
| `baseUrl` | `
|
|
86
|
-
| `apiKey` | `''
|
|
87
|
-
| `dataDir` | `~/.dsh-magpie-connect` |
|
|
88
|
-
| `refreshSeconds` | `300` |
|
|
89
|
-
| `maxRetries` | `2` |
|
|
90
|
-
| `timeoutMs` | `300000` |
|
|
91
|
-
| `firstEventTimeoutMs` | `90000` |
|
|
92
|
-
| `idleTimeoutMs` | `60000` |
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
| `providerId` | `dsh-magpie-connect` | 注册到 DSH 的 provider 名称。 |
|
|
106
|
+
| `displayName` | `Magpie` | 模型选择器里的分组名。 |
|
|
107
|
+
| `baseUrl` | `http://127.0.0.1:3425/v1` | 带版本号的 API 地址。 |
|
|
108
|
+
| `apiKey` | `''`(未配置) | 网关凭据。必填,即使网关不校验——地址有默认值,Key 没有。 |
|
|
109
|
+
| `dataDir` | `~/.dsh-magpie-connect` | 状态目录(状态快照、设置文件、模型缓存)。 |
|
|
110
|
+
| `refreshSeconds` | `300` | 模型目录刷新间隔(秒)。 |
|
|
111
|
+
| `maxRetries` | `2` | 遇到 429/5xx 时的连接重试次数。 |
|
|
112
|
+
| `timeoutMs` | `300000` | 单次请求的总超时(毫秒)。 |
|
|
113
|
+
| `firstEventTimeoutMs` | `90000` | 等待首个上游事件的超时(毫秒)。 |
|
|
114
|
+
| `idleTimeoutMs` | `60000` | 上游事件之间的静默超时(毫秒)。 |
|
|
115
|
+
|
|
116
|
+
优先级:设置页 > `cordis.patch.yml` > 默认值。设置页只覆盖你保存过的字段。
|
|
117
|
+
|
|
118
|
+
### 工作原理
|
|
95
119
|
|
|
96
120
|
```
|
|
97
|
-
DSH
|
|
98
|
-
│ harness
|
|
121
|
+
DSH 会话
|
|
122
|
+
│ harness 数据块(block-start / text-delta / usage / finish …)
|
|
99
123
|
▼
|
|
100
|
-
MagpieAdapter
|
|
101
|
-
│ pi-ai openai-completions
|
|
102
|
-
│ openai-responses
|
|
124
|
+
MagpieAdapter(注册为 DSH 的 LlmAdapter)
|
|
125
|
+
│ pi-ai openai-completions 流(默认)/
|
|
126
|
+
│ openai-responses 流(仅支持 responses 的模型)
|
|
103
127
|
▼
|
|
104
|
-
http://
|
|
128
|
+
http://127.0.0.1:3425/v1 ← 按 native_endpoints 选择 chat/completions 或 responses
|
|
105
129
|
```
|
|
106
130
|
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
挂起快速失败为 `TIMEOUT`;`length` 截断如实上抛,不做自动续写。
|
|
131
|
+
- **模型目录** — 全量接入网关 `GET {baseUrl}/models`,不做付费过滤;磁盘缓存加编译期
|
|
132
|
+
静态快照兜底,网关宕机时选择器仍可用。暴露集合一旦变化(隐藏/显示、换网关地址、
|
|
133
|
+
刷新后模型增删),会发出 `llm/adapters-updated` 让浏览器重读缓存——否则选择器会
|
|
134
|
+
一直显示旧列表直到下次重启。
|
|
135
|
+
- **思考档位** — 有档位阶梯的模型进入选择器;没有阶梯但可思考的模型保持可思考
|
|
136
|
+
(显式档位直通网关);`none` 关闭思考,`ultra` 直通网关,不在本地截断。
|
|
137
|
+
- **图片** — 带图的请求经 harness 附件服务取字节后上行;文本模型收到图片会直接
|
|
138
|
+
失败(harness 已按模型声明的输入类型做过门控)。
|
|
139
|
+
- **容错** — 启动即注册,目录在后台预热;静默挂起会被看门狗快速判为超时;
|
|
140
|
+
上游截断如实上报,不做自动续写。
|
|
118
141
|
|
|
119
|
-
|
|
142
|
+
运行状态快照写在 `~/.dsh-magpie-connect/adapter-status.json`,设置与缓存在同一目录。
|
|
120
143
|
|
|
121
|
-
##
|
|
144
|
+
## 开发
|
|
122
145
|
|
|
123
146
|
```sh
|
|
124
147
|
pnpm install
|
|
125
|
-
pnpm run check
|
|
148
|
+
pnpm run check # 类型检查 + 测试 + 构建
|
|
149
|
+
pnpm run deploy:local # 构建并同步到 web profile
|
|
126
150
|
```
|
|
127
151
|
|
|
128
|
-
|
|
129
|
-
|
|
152
|
+
`lib/` 是提交进仓库的构建产物,所以 profile 安装时不需要现场构建。
|
|
153
|
+
|
|
154
|
+
发布由 `.github/workflows/release.yml` 负责:把 `package.json` 和
|
|
155
|
+
`dsh.plugin.json` 的版本号改成一致后提交推送,流水线会打 tag、建 GitHub Release
|
|
156
|
+
并发布到 npm。版本号带 `-`(如 `0.3.0-rc.1`)时自动标记为预发布。
|
|
130
157
|
|
|
131
|
-
##
|
|
158
|
+
## 许可证
|
|
132
159
|
|
|
133
160
|
[MIT](./LICENSE)
|
package/cordis.patch.yml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# dsh-magpie-connect DSH plugin — bundle patch: insert the plugin row (deployment-global).
|
|
2
2
|
#
|
|
3
|
-
# The gateway
|
|
4
|
-
# sidebar page ("Magpie") or via the config object below (see
|
|
5
|
-
# Until
|
|
3
|
+
# The gateway ships with the conventional local address but no key: set the key
|
|
4
|
+
# on the Settings sidebar page ("Magpie") or via the config object below (see
|
|
5
|
+
# src/config.ts). Until a key is set the picker stays empty and calls fail fast.
|
|
6
6
|
#
|
|
7
7
|
# The Settings sidebar page can override baseUrl/apiKey at runtime
|
|
8
8
|
# (saved to <dataDir>/settings.json, applied without restart) and hides models
|
|
9
9
|
# from the picker. Page values win per-field; the patch config below stays as
|
|
10
10
|
# fallback (e.g. headless compositions without the settings page).
|
|
11
11
|
#
|
|
12
|
-
# - baseUrl: versioned API root
|
|
12
|
+
# - baseUrl: versioned API root (default http://127.0.0.1:3425/v1). Include the
|
|
13
13
|
# version segment: the plugin appends only the resource (/models, /responses),
|
|
14
14
|
# so a gateway on /v2 or /v3 is reached by changing this one string.
|
|
15
15
|
# - apiKey: gateway credential (required, even if /models needs none).
|
package/dsh.plugin.json
CHANGED
package/lib/client.js
CHANGED
|
@@ -41,7 +41,7 @@ var EN = {
|
|
|
41
41
|
intro: "Connect DSH to the Magpie LAN model gateway. Changes save to this machine and apply immediately \u2014 no restart needed.",
|
|
42
42
|
connection: "Connection",
|
|
43
43
|
baseUrl: "API URL",
|
|
44
|
-
baseUrlPlaceholder: "http://
|
|
44
|
+
baseUrlPlaceholder: "http://127.0.0.1:3425/v1",
|
|
45
45
|
apiKey: "API key",
|
|
46
46
|
apiKeyPlaceholder: "required",
|
|
47
47
|
requiredNote: "API URL and API key are both required. Include the version segment (e.g. /v1) \u2014 the URL is used exactly as written.",
|
|
@@ -90,7 +90,7 @@ var ZH = {
|
|
|
90
90
|
intro: "\u628A DSH \u63A5\u5165 Magpie \u5C40\u57DF\u7F51\u6A21\u578B\u7F51\u5173\u3002\u4FEE\u6539\u4FDD\u5B58\u5728\u672C\u673A\u5E76\u7ACB\u5373\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\u3002",
|
|
91
91
|
connection: "\u8FDE\u63A5",
|
|
92
92
|
baseUrl: "API \u5730\u5740",
|
|
93
|
-
baseUrlPlaceholder: "http://
|
|
93
|
+
baseUrlPlaceholder: "http://127.0.0.1:3425/v1",
|
|
94
94
|
apiKey: "API Key",
|
|
95
95
|
apiKeyPlaceholder: "\u5FC5\u586B",
|
|
96
96
|
requiredNote: "API \u5730\u5740\u4E0E Key \u5747\u4E3A\u5FC5\u586B\u3002\u5730\u5740\u9700\u5305\u542B\u7248\u672C\u6BB5\uFF08\u5982 /v1\uFF09\uFF0C\u63D2\u4EF6\u6309\u4F60\u586B\u5199\u7684\u539F\u6837\u4F7F\u7528\u3002",
|
package/lib/index.js
CHANGED
|
@@ -217,7 +217,7 @@ var ModelCatalog = class {
|
|
|
217
217
|
}
|
|
218
218
|
async refreshModels() {
|
|
219
219
|
if (!this.configured) {
|
|
220
|
-
this.#lastError = "magpie gateway
|
|
220
|
+
this.#lastError = "magpie gateway API URL or key is not configured \u2014 set both on the Magpie settings page";
|
|
221
221
|
return;
|
|
222
222
|
}
|
|
223
223
|
try {
|
|
@@ -282,7 +282,7 @@ var ModelCatalog = class {
|
|
|
282
282
|
this.#baseUrl = root;
|
|
283
283
|
this.#entries = /* @__PURE__ */ new Map();
|
|
284
284
|
this.#updatedAt = 0;
|
|
285
|
-
this.#lastError = root === "" ? "magpie gateway
|
|
285
|
+
this.#lastError = root === "" ? "magpie gateway API URL or key is not configured \u2014 set both on the Magpie settings page" : "";
|
|
286
286
|
this.#announce();
|
|
287
287
|
}
|
|
288
288
|
get baseUrl() {
|
|
@@ -895,7 +895,7 @@ async function* withStallTimeout(events, timeouts, options = {}) {
|
|
|
895
895
|
|
|
896
896
|
// src/adapter/magpie-adapter.ts
|
|
897
897
|
var PROVIDER_ID = "dsh-magpie-connect";
|
|
898
|
-
var DEFAULT_DISPLAY_NAME = "
|
|
898
|
+
var DEFAULT_DISPLAY_NAME = "Magpie";
|
|
899
899
|
var DEFAULT_CONTEXT_WINDOW = 262144;
|
|
900
900
|
var DEFAULT_MAX_TOKENS = 32768;
|
|
901
901
|
var DEFAULT_API_KEY = "not-needed";
|
|
@@ -1070,7 +1070,7 @@ var MagpieAdapter = class {
|
|
|
1070
1070
|
const raw = this.#runtime?.baseUrl() ?? this.#fallbackBaseUrl;
|
|
1071
1071
|
const baseUrl = raw.replace(/\/+$/, "");
|
|
1072
1072
|
if (baseUrl === "") {
|
|
1073
|
-
throw new Error("dsh-magpie-connect: Magpie gateway API URL is not configured \u2014 open Settings \u2192 Magpie and
|
|
1073
|
+
throw new Error("dsh-magpie-connect: Magpie gateway API URL or key is not configured \u2014 open Settings \u2192 Magpie and fill in both");
|
|
1074
1074
|
}
|
|
1075
1075
|
return baseUrl;
|
|
1076
1076
|
}
|
|
@@ -1150,8 +1150,8 @@ import { homedir } from "node:os";
|
|
|
1150
1150
|
import { join as join2 } from "node:path";
|
|
1151
1151
|
var defaults = {
|
|
1152
1152
|
providerId: "dsh-magpie-connect",
|
|
1153
|
-
displayName: "
|
|
1154
|
-
baseUrl: "",
|
|
1153
|
+
displayName: "Magpie",
|
|
1154
|
+
baseUrl: "http://127.0.0.1:3425/v1",
|
|
1155
1155
|
apiKey: "",
|
|
1156
1156
|
refreshSeconds: 300,
|
|
1157
1157
|
maxRetries: 2,
|