@mojieai/dsh-mojie-model-provider 0.0.0-stage → 0.2.0
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/LICENSE +21 -0
- package/README.md +327 -2
- package/cordis.patch.yml +22 -0
- package/docs/assets/mojie-logo.png +0 -0
- package/docs/assets/mojie-logo.svg +28 -0
- package/lib/adapter.d.ts +57 -0
- package/lib/adapter.js +172 -0
- package/lib/catalog.d.ts +68 -0
- package/lib/catalog.generated.d.ts +14 -0
- package/lib/catalog.generated.js +146 -0
- package/lib/catalog.js +144 -0
- package/lib/client.js +2042 -0
- package/lib/commands/image.d.ts +39 -0
- package/lib/commands/image.js +406 -0
- package/lib/config.d.ts +175 -0
- package/lib/config.js +144 -0
- package/lib/core/client.d.ts +152 -0
- package/lib/core/client.js +153 -0
- package/lib/core/endpoint.d.ts +25 -0
- package/lib/core/endpoint.js +49 -0
- package/lib/core/index.d.ts +18 -0
- package/lib/core/index.js +15 -0
- package/lib/core/stream.d.ts +48 -0
- package/lib/core/stream.js +138 -0
- package/lib/discovery.d.ts +51 -0
- package/lib/discovery.js +128 -0
- package/lib/index.d.ts +98 -0
- package/lib/index.js +192 -0
- package/lib/media/client.d.ts +128 -0
- package/lib/media/client.js +236 -0
- package/lib/media/dimensions.d.ts +23 -0
- package/lib/media/dimensions.js +114 -0
- package/lib/media/input-image.d.ts +75 -0
- package/lib/media/input-image.js +348 -0
- package/lib/media/model-memory.d.ts +48 -0
- package/lib/media/model-memory.js +64 -0
- package/lib/media/session-file.d.ts +33 -0
- package/lib/media/session-file.js +50 -0
- package/lib/media/task-store.d.ts +79 -0
- package/lib/media/task-store.js +149 -0
- package/lib/media/url-allowlist.d.ts +23 -0
- package/lib/media/url-allowlist.js +42 -0
- package/lib/order.d.ts +32 -0
- package/lib/order.js +71 -0
- package/lib/reasoning.d.ts +57 -0
- package/lib/reasoning.js +111 -0
- package/lib/serialize.d.ts +75 -0
- package/lib/serialize.js +210 -0
- package/lib/service.d.ts +102 -0
- package/lib/service.js +133 -0
- package/lib/sse.d.ts +18 -0
- package/lib/sse.js +74 -0
- package/lib/tools/image.d.ts +39 -0
- package/lib/tools/image.js +230 -0
- package/lib/translate.d.ts +32 -0
- package/lib/translate.js +445 -0
- package/lib/transport.d.ts +31 -0
- package/lib/transport.js +78 -0
- package/package.json +93 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MoJIeAIGC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,328 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://mojieaigc.com"><img src="docs/assets/mojie-logo.png" alt="Mojie" width="112" /></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Mojie dsh-mojie-model-provider</h1>
|
|
6
|
+
<p align="center">MojieAgentFlow全站模型deepseek-harness插件</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://github.com/MoJIeAIGC">GitHub</a> ·
|
|
10
|
+
<a href="https://space.bilibili.com/483532108">B站</a> ·
|
|
11
|
+
<a href="https://www.douyin.com/user/MS4wLjABAAAA3JbjlCqKd8WXklSYmO64wxWeMBg4efViyTg8Gz6VZdI">抖音</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
由MojieAI开发的deepseek-harness插件,用于将Mojieaigc.com的所有平台能力无缝接入到DSH中,无需多余配置,直接让你的DSH拥有原生多模型,生图生视频能力。
|
|
15
|
+
|
|
16
|
+
| 用一个 Key,聊全球主流模型 | 一句话,让 AI 出图 | 像原生模型一样用 |
|
|
17
|
+
| :-- | :-- | :-- |
|
|
18
|
+
| GPT、Claude、Gemini、Qwen、DeepSeek、豆包、Kimi、Grok、GLM 等主流模型,全部出现在 DSH 的模型下拉里。 | `/image 一只戴帽子的猫` 直接把图画进对话;也可以对 AI 说「帮我画……」,它自己调用画图工具。 | 全部沿用 DSH 原生能力,习惯不用改 |
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 快速开始
|
|
24
|
+
|
|
25
|
+
> 🚀 三步:装插件 → 填 Key → 开始使用。
|
|
26
|
+
|
|
27
|
+
## 安装前的准备
|
|
28
|
+
|
|
29
|
+
### 1. DSH 已经装好
|
|
30
|
+
|
|
31
|
+
桌面版或命令行版都行,能打开、能收发消息就可以。
|
|
32
|
+
|
|
33
|
+
- **桌面版**:在「设置 → 通用」里能看到「当前版本:x.x.x」;
|
|
34
|
+
- **命令行版**:在终端里执行:
|
|
35
|
+
|
|
36
|
+
```powershell
|
|
37
|
+
dsh --version
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
打印出 `0.2.1-rc.2` 或更高版本就可以继续。
|
|
41
|
+
|
|
42
|
+
### 1. 创建APIKEY
|
|
43
|
+
1. 登录 [mojieaigc.com](https://www.mojieaigc.com);
|
|
44
|
+
2. 点击右上角**个人头像**;
|
|
45
|
+
3. 进入 **我的APIKEY**;
|
|
46
|
+
4. 点击**新建密钥**,给 Key 起个名字(例如 `codex`),复制生成的那串。
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
进入后是 APIKEY 管理页,点右上角 **新建密钥**:
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
创建后回到列表,点 Key 后面的复制图标把它复制走:
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
> [!WARNING]
|
|
62
|
+
> APIKEY 是你与 MojieAgentFlow 通信的重要凭证,请妥善保管;如怀疑泄露,请及时删除并重新创建,
|
|
63
|
+
|
|
64
|
+
### 2. 安装插件
|
|
65
|
+
|
|
66
|
+
#### 方式 A · 插件市场(推荐)
|
|
67
|
+
|
|
68
|
+
1. 打开 DSH,进入 **设置**。
|
|
69
|
+
2. 找到 **插件 / 插件市场** 页面。
|
|
70
|
+
3. 搜索 **Mojie**(或包名 `@mojieai/dsh-mojie-model-provider`)。
|
|
71
|
+
4. 点**安装**,等它提示「已安装,请重启 DSH 加载它」,再点**完成**。
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+

|
|
77
|
+
|
|
78
|
+
#### 方式 B · 一行命令
|
|
79
|
+
|
|
80
|
+
打开终端(PowerShell / Terminal):
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
dsh plugin --profile desktop add https://github.com/MoJIeAIGC/dsh-mojie-model-provider/releases/latest/download/mojieai-dsh-mojie-model-provider-0.2.0.tgz
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> [!NOTE]
|
|
87
|
+
> URL 里的版本号要和发布页上的文件名一致。如果提示 404,请到 [Releases](https://github.com/MoJIeAIGC/dsh-mojie-model-provider/releases) 页面复制最新的 `.tgz` 链接替换。
|
|
88
|
+
|
|
89
|
+
#### 装完必须重启一次
|
|
90
|
+
|
|
91
|
+
新插件是在 DSH 启动时加载的,**不重启看不到效果**。
|
|
92
|
+
|
|
93
|
+
- **Windows 桌面版**:右键托盘图标 → **退出**(只关窗口不算退出),再双击 `DeepSeek Harness` 重新打开。
|
|
94
|
+
- **命令行版**:结束当前的 `dsh` 进程,重新启动。
|
|
95
|
+
|
|
96
|
+
### 3. 填入API Key(一次就好)
|
|
97
|
+
|
|
98
|
+
1. 重启后进入 **设置 → 模型**。
|
|
99
|
+
2. 找到 **Mojie** provider 行;卡片会显示「API 密钥」。
|
|
100
|
+
3. 在 **API 密钥** 输入框里粘贴第 1 步复制的 Key。
|
|
101
|
+
4. 点卡片底部的 **保存**,看到「已保存。」即可,以后不用再填。
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
### 4. 正确使用
|
|
105
|
+
|
|
106
|
+
**对话界面** —— 在 **设置 → 模型** 或聊天界面的模型下拉里,选一个 Mojie 提供的模型(例如 `claude-opus-5.5`、`gpt-6-astra`、`Kimi-k3.1-pro`),然后像平时一样发消息。它和原生模型一样支持:
|
|
107
|
+
|
|
108
|
+
- **工具调用**(读写文件、跑命令、搜索等)
|
|
109
|
+
- **看图**(把图片拖进输入框,选一个支持图片的模型)
|
|
110
|
+
|
|
111
|
+
**画图** —— 在输入框里敲:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
/image 一只戴帽子的猫,扁平插画风,白底
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
几秒到几十秒后,图片会直接出现在对话里,并附上模型名与尺寸。
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 画图手册
|
|
122
|
+
|
|
123
|
+
> 🎨 `/image` 是给人用的画图入口:提示词原样发给画图模型,不经过聊天模型改写,也不靠模型猜测要调哪个工具。
|
|
124
|
+
|
|
125
|
+
### 常用写法
|
|
126
|
+
|
|
127
|
+
| 想做什么 | 输入 |
|
|
128
|
+
| :-- | :-- |
|
|
129
|
+
| 画一张(用当前默认模型) | `/image 一只戴帽子的猫` |
|
|
130
|
+
| 编辑 / 融合(附带图片) | 把图片拖进输入框,输入 `/image 把这两张图融合成一张` |
|
|
131
|
+
| 本次换模型 | `/image 一只猫 --model mojie-nanobanana-2` |
|
|
132
|
+
| 指定分辨率与比例 | `/image 赛博朋克风的城市夜景 --resolution 2K --ratio 16:9` |
|
|
133
|
+
| 列出可用的画图模型 | `/image models` |
|
|
134
|
+
| 切换默认模型 | `/image model mojie-nanobanana-2` |
|
|
135
|
+
| 恢复内置默认 | `/image model auto` |
|
|
136
|
+
| 续查没跑完的任务 | `/image task <任务ID>` |
|
|
137
|
+
| 查看用法 | `/image help` |
|
|
138
|
+
|
|
139
|
+
> 🖼 只要这次 `/image` 带着图片附件,命令就自动走**编辑**:附件按上传顺序作为 `input_image_urls` 提交给上游,不需要 `/image edit` 语法。`--model` / `--resolution` / `--ratio` 依然可叠加;`models`、`model`、`task`、`help` 这些子命令照常可用,附带的图片会被静默忽略(不会报错,也不影响你暂存的原图)。
|
|
140
|
+
|
|
141
|
+
参数可以简写:`--model`/`-m`、`--resolution`/`-r`、`--ratio`/`--aspect-ratio`/`-a`,也支持 `--model=mojie-nanobanana-2` 这种等号写法。
|
|
142
|
+
|
|
143
|
+
### 任务没跑完怎么办
|
|
144
|
+
|
|
145
|
+
图片生成是异步任务。`/image` 提交后**立即返回**(输入框的附件和发送记录会马上清空),图片在后台完成后自动放进对话;如果提交后进程退出、或想手动取回,用 `/image task <任务ID>` 续查即可,**图不会丢**。
|
|
146
|
+
|
|
147
|
+
- 原图会写进当前会话的工作目录(文件名带任务 ID),重启 DSH 后对话里仍能看到图。
|
|
148
|
+
- 想要多张,就多敲几次 `/image`,每张都会单独落一个文件、单独发进对话。
|
|
149
|
+
|
|
150
|
+
### 设置默认画图模型
|
|
151
|
+
|
|
152
|
+
1. **设置 → 模型 → Mojie** 行,展开 **自定义设置**。
|
|
153
|
+
2. 找到 **图片生成默认模型** 下拉框;列表为空就点右侧 **刷新图片模型**。
|
|
154
|
+
3. 选一个(例如 `seedream-5-image`、`mojie-nanobanana-2`),点卡片底部的 **保存**。
|
|
155
|
+
|
|
156
|
+
之后 `/image …` 和 AI 自己画图都会用这个模型。也可以随时用 `/image model <模型名>` 切换——两处改的是同一个设置。
|
|
157
|
+
|
|
158
|
+
> [!IMPORTANT]
|
|
159
|
+
> 对话里 AI 调用画图工具时,**只有你明确点名某个模型**它才会传 `model` 参数;没点名就省略,使用这里设置的默认模型。
|
|
160
|
+
>
|
|
161
|
+
>
|
|
162
|
+
> 模型名可以模糊说(例如“用 image 2.5”):AI 会先用 `mojie_list_image_models` 把模糊名解析成唯一的确切 id;如果有多个模型都匹配,它会先问你要哪一个。
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
### 让 AI 自己画 / 改图
|
|
166
|
+
|
|
167
|
+
插件注册了 4 个原生工具,AI 会在需要时自己调用:
|
|
168
|
+
|
|
169
|
+
| 工具 | 用途 |
|
|
170
|
+
| :-- | :-- |
|
|
171
|
+
| `mojie_generate_image` | 文字生图,可指定模型、分辨率、比例 |
|
|
172
|
+
| `mojie_edit_image` | 改图 / 重绘 / 多图融合;所有参考图都放 `input_images` 数组(一张也传数组),按顺序提交 |
|
|
173
|
+
| `mojie_list_image_models` | 列出当前 Key 可用的画图模型 |
|
|
174
|
+
| `mojie_image_task` | 查询任务状态,完成后把图取回对话 |
|
|
175
|
+
|
|
176
|
+
- **画**:直接说「帮我画一张……」即可,AI 会把图画进对话。
|
|
177
|
+
- **改**:把图片拖进输入框,说「把这张图的背景换成沙滩」「改成蓝色电影色调」,AI 会把结果图发回来。
|
|
178
|
+
- **多图融合**:一句话里给多张参考图(对话里贴多张,或让 AI 用 `input_images` 传多个路径),按你给的顺序提交。
|
|
179
|
+
- **图在哪**:生成/编辑的原图按厂商字节直接写进**当前会话的工作目录**(`mojie-<任务ID>-<序号>.<扩展名>`,也会保存url在历史记录中,不覆盖、不压缩、Provider 返回几张就存几张);对话里显示的压缩副本(由 DSH 附件存储按默认规则规范化,仅用于看),原图路径在「查看详情」里。
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 模型清单
|
|
185
|
+
|
|
186
|
+
<details>
|
|
187
|
+
<summary><b>OpenAI · GPT</b>(11)</summary>
|
|
188
|
+
|
|
189
|
+
`gpt-6.1-sol`、`gpt-6-sol`、`gpt-6-luna`、`gpt-6-astra`、`gpt-5.6-terra-pro`、`gpt-5.6-terra`、`gpt-5.6-sol`、`gpt-5.6-luna-pro`、`gpt-5.6-luna`、`gpt-5.5`、`gpt-5.4`
|
|
190
|
+
|
|
191
|
+
</details>
|
|
192
|
+
|
|
193
|
+
<details>
|
|
194
|
+
<summary><b>Anthropic · Claude</b>(14)</summary>
|
|
195
|
+
|
|
196
|
+
`claude-opus-5.5`、`claude-sonnet-5.5`、`claude-haiku-5.5`、`claude-opus-5`、`claude-sonnet-5`、`claude-fable-5.1`、`claude-fable-5`、`claude-opus-4.8`、`claude-opus-4.7`、`claude-sonnet-4.6`、`claude-opus-4.6`、`claude-sonnet-4.5`、`claude-opus-4.5`、`claude-haiku-4.5`
|
|
197
|
+
|
|
198
|
+
</details>
|
|
199
|
+
|
|
200
|
+
<details>
|
|
201
|
+
<summary><b>Google · Gemini</b>(9)</summary>
|
|
202
|
+
|
|
203
|
+
`gemini-4-argon`、`gemini-3.8-flash`、`gemini-3.7-flash`、`gemini-3.6-flash`、`gemini-3.5-flash`、`gemini-3.5-flash-lite`、`gemini-3.1-pro-preview`、`gemini-3.1-flash-lite`、`gemini-3-flash-preview`
|
|
204
|
+
|
|
205
|
+
</details>
|
|
206
|
+
|
|
207
|
+
<details>
|
|
208
|
+
<summary><b>阿里 · Qwen</b>(8)</summary>
|
|
209
|
+
|
|
210
|
+
`qwen3.8-max`、`qwen3.8-omni-flash`、`qwen3.8-flash`、`qwen3.7-max`、`qwen3.7-plus`、`qwen3.7-flash`、`qwen3.6-plus`、`qwen3.6-flash`
|
|
211
|
+
|
|
212
|
+
</details>
|
|
213
|
+
|
|
214
|
+
<details>
|
|
215
|
+
<summary><b>字节 · 豆包</b>(7)</summary>
|
|
216
|
+
|
|
217
|
+
`doubao-seed-2-1-pro`、`doubao-seed-2-1-turbo`、`doubao-seed-2-1-lite`、`doubao-seed-2-0-lite`、`doubao-seed-2-0-mini`、`doubao-seed-2-0-code-preview`、`doubao-seed-character`
|
|
218
|
+
|
|
219
|
+
</details>
|
|
220
|
+
|
|
221
|
+
<details>
|
|
222
|
+
<summary><b>智谱 · GLM</b>(6)</summary>
|
|
223
|
+
|
|
224
|
+
`GLM-5.3`、`GLM-5.3-FlashX`、`GLM-5.3-Flash`、`GLM-5.2`、`GLM-5.1`、`GLM-5`
|
|
225
|
+
|
|
226
|
+
</details>
|
|
227
|
+
|
|
228
|
+
<details>
|
|
229
|
+
<summary><b>Moonshot · Kimi</b>(4)</summary>
|
|
230
|
+
|
|
231
|
+
`kimi-k3.1-pro`、`kimi-k3.1-pro-highspeed`、`kimi-k3`、`kimi-k2.7-code`
|
|
232
|
+
|
|
233
|
+
</details>
|
|
234
|
+
|
|
235
|
+
<details>
|
|
236
|
+
<summary><b>xAI · Grok</b>(4)</summary>
|
|
237
|
+
|
|
238
|
+
`grok-4.7`、`grok-4.6`、`grok-4.5`、`grok-4.3`
|
|
239
|
+
|
|
240
|
+
</details>
|
|
241
|
+
|
|
242
|
+
<details>
|
|
243
|
+
<summary><b>DeepSeek</b>(2)</summary>
|
|
244
|
+
|
|
245
|
+
`deepseek-v4-pro`、`deepseek-v4-flash`
|
|
246
|
+
|
|
247
|
+
</details>
|
|
248
|
+
|
|
249
|
+
> [!NOTE]
|
|
250
|
+
> 清单会随主站更新。每个模型的 **上下文窗口、最大输出 token 数、输入类型、推理等级** 会一并自动填写。点 **获取可用模型** 可以搜索、勾选并 **更新列表**;
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
## 常见问题
|
|
255
|
+
|
|
256
|
+
<details>
|
|
257
|
+
<summary><b>设置里模型目录是空的?</b></summary>
|
|
258
|
+
|
|
259
|
+
模型目录默认由内置快照自动填写,即使还没联网也能看到全部模型。要拿到主站最新清单,先确认 API Key 已保存(卡片上会显示「已配置凭据」),再展开 **自定义设置** 点 **获取可用模型**,勾选后点 **更新列表**;画图模型则点 **刷新图片模型**。如果仍然为空,检查主站余额是否用完,或 API 地址是否被改错。
|
|
260
|
+
|
|
261
|
+
</details>
|
|
262
|
+
|
|
263
|
+
<details>
|
|
264
|
+
<summary><b>画图报 AUTH / 401?</b></summary>
|
|
265
|
+
|
|
266
|
+
Key 复制错了或已失效。回主站「个人中心 → API-KEY」重新复制一次,粘进卡片保存即可。注意别把首尾空格一起粘进去。
|
|
267
|
+
|
|
268
|
+
</details>
|
|
269
|
+
|
|
270
|
+
<details>
|
|
271
|
+
<summary><b>提示 RATE_LIMIT / 上游繁忙?</b></summary>
|
|
272
|
+
|
|
273
|
+
主站临时限流,等几十秒再试。画图失败通常不会产生可用的创作结果,可以直接重发。
|
|
274
|
+
|
|
275
|
+
</details>
|
|
276
|
+
|
|
277
|
+
<details>
|
|
278
|
+
<summary><b>/image 命令打不出来?</b></summary>
|
|
279
|
+
|
|
280
|
+
按顺序自查:
|
|
281
|
+
|
|
282
|
+
1. 插件已安装,并且**重启过** DSH;
|
|
283
|
+
2. 设置 → 模型里能看到 **Mojie** 这一行(行内是 API 密钥 + 自定义设置);
|
|
284
|
+
3. 在输入框敲 `/`,菜单里能看到 **image**。
|
|
285
|
+
|
|
286
|
+
</details>
|
|
287
|
+
|
|
288
|
+
<details>
|
|
289
|
+
<summary><b>怎么升级插件?</b></summary>
|
|
290
|
+
|
|
291
|
+
在插件市场点更新;或先卸载再装新版 tarball,然后重启。。
|
|
292
|
+
|
|
293
|
+
</details>
|
|
294
|
+
|
|
295
|
+
<details>
|
|
296
|
+
<summary><b>怎么卸载?</b></summary>
|
|
297
|
+
|
|
298
|
+
在插件市场点卸载,或执行:
|
|
299
|
+
|
|
300
|
+
```sh
|
|
301
|
+
dsh plugin --profile desktop remove "@mojieai/dsh-mojie-model-provider"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
然后重启 DSH。已生成的原图仍在各会话的工作目录里,不会被删掉。
|
|
305
|
+
|
|
306
|
+
</details>
|
|
307
|
+
|
|
308
|
+
<details>
|
|
309
|
+
<summary><b>费用怎么算?</b></summary>
|
|
310
|
+
|
|
311
|
+
由 Mojie 主站按点数计费(聊天按 token、画图按张 / 分辨率),DSH 这边不额外收费。具体价格见主站。
|
|
312
|
+
余额不足请前往[Mojieaigc.com](https://www.mojieaigc.com) 充值
|
|
313
|
+
|
|
314
|
+
</details>
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## 隐私与安全
|
|
319
|
+
|
|
320
|
+
- **Key 只在本机**:保存在 DSH 的凭据存储里(或 `MOJIE_API_KEY` 环境变量),不写进插件配置,也不进入对话内容。
|
|
321
|
+
- **请求直连主站**:聊天与画图请求直接发往 `mojieaigc.com`,不经过第三方中转。
|
|
322
|
+
- **图片留在本地**:生成的原图(与厂商字节一致)写进当前会话的工作目录,方便之后继续查看或二次编辑;对话显示副本存放在本机附件目录。
|
|
323
|
+
- **别把 Key 贴出去**:不要贴进对话、截图或代码仓库;怀疑泄露时,去主站重置 Key 再改一遍设置。
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
遇到问题或想提需求,欢迎到 [MojieAgentflow](https://www.mojieaigc.com) 查看联系方式。
|
|
2
328
|
|
|
3
|
-
This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Bundle layer installed by `dsh plugin add`.
|
|
2
|
+
#
|
|
3
|
+
# This inserts the Mojie provider row under the settings namespace `mojie`.
|
|
4
|
+
# The API key is a credential reference: keep MOJIE_API_KEY in the launching
|
|
5
|
+
# environment, or store it under that reference through the Models page card.
|
|
6
|
+
# A profile's own cordis.patch.yml can override this row by id.
|
|
7
|
+
- insert:
|
|
8
|
+
- id: mojie
|
|
9
|
+
name: '@mojieai/dsh-mojie-model-provider'
|
|
10
|
+
config:
|
|
11
|
+
apiKeyEnv: MOJIE_API_KEY
|
|
12
|
+
baseURL: 'https://mojieaigc.com'
|
|
13
|
+
# Empty means: inherit /v1/models discovery plus the built-in catalog.
|
|
14
|
+
# The Models page card fills this list for you (model rows, context
|
|
15
|
+
# windows, input types, and thinking levels); hand-written entries here
|
|
16
|
+
# still win and pin the values. Thinking levels come from the per-vendor
|
|
17
|
+
# recommendation unless a row pins `reasoningEfforts`, and
|
|
18
|
+
# `reasoning: 'off'` declares a model that cannot think at all.
|
|
19
|
+
models: []
|
|
20
|
+
# Send `reasoning.effort` for every model that does not opt out, even
|
|
21
|
+
# though the site publishes no effort vocabulary. Set false to stop.
|
|
22
|
+
reasoningDefaults: true
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
2
|
+
viewBox="0 0 97.95 62.39">
|
|
3
|
+
<defs>
|
|
4
|
+
<style>
|
|
5
|
+
.cls-1{fill:url(#未命名的渐变_25);}.cls-2{fill:url(#未命名的渐变_25-2);}.cls-3{fill:url(#未命名的渐变_25-3);}.cls-4{fill:url(#未命名的渐变_25-4);}
|
|
6
|
+
</style>
|
|
7
|
+
<linearGradient id="未命名的渐变_25" x1="1.05" y1="33.11" x2="20.59" y2="33.11" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop offset="0" stop-color="#4d6bfe"/>
|
|
9
|
+
<stop offset="1" stop-color="#a035ff"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
<linearGradient id="未命名的渐变_25-2" x1="3.41" y1="24.77" x2="46.04" y2="24.77"
|
|
12
|
+
xlink:href="#未命名的渐变_25"/>
|
|
13
|
+
<linearGradient id="未命名的渐变_25-3" x1="69.44" y1="31.51" x2="99" y2="31.51" xlink:href="#未命名的渐变_25"/>
|
|
14
|
+
<linearGradient id="未命名的渐变_25-4" x1="36.61" y1="38.4" x2="72" y2="38.4" xlink:href="#未命名的渐变_25"/>
|
|
15
|
+
</defs>
|
|
16
|
+
<path class="cls-1"
|
|
17
|
+
d="M10.82,62.68h0a9.77,9.77,0,0,1-9.77-9.77V13.32a9.77,9.77,0,0,1,9.77-9.78h0a9.77,9.77,0,0,1,9.77,9.78V52.91A9.77,9.77,0,0,1,10.82,62.68Z"
|
|
18
|
+
transform="translate(-1.05 -0.29)"/>
|
|
19
|
+
<path class="cls-2"
|
|
20
|
+
d="M3.41,7C7,.89,16.39-1.7,23.22,2a23.17,23.17,0,0,1,8.1,7.32c5.17,8,9.75,16.29,14.48,24.52a2.78,2.78,0,0,1,0,2.31c-1.94,3.46-3.89,6.92-6.09,10.22-2.54,3.83-5.1,3.84-7.58-.07C28.74,41,25.66,35.49,22.47,30.05c-3-5.21-6-10.46-9.14-15.64C11.06,10.62,8.21,7.49,3.41,7Z"
|
|
21
|
+
transform="translate(-1.05 -0.29)"/>
|
|
22
|
+
<path class="cls-3"
|
|
23
|
+
d="M69.44,6.87A16.35,16.35,0,0,1,87.21,1c6.71,1.9,10.28,6.62,11.41,13.33A24.84,24.84,0,0,1,99,18.48c0,11.22.08,22.45,0,33.68,0,7.65-6.55,12.29-13.62,9.86-4.16-1.43-6.48-4.86-6.49-9.84,0-10.53,0-21.07,0-31.6,0-.78,0-1.56,0-2.34C78.69,11.89,75.79,8.32,69.44,6.87Z"
|
|
24
|
+
transform="translate(-1.05 -0.29)"/>
|
|
25
|
+
<path class="cls-4"
|
|
26
|
+
d="M36.61,56s4.53,2.11,12.11-10.51c4.18-7,11.19-19.33,16.63-29,2.1-3.74,6.65-2.25,6.65,2.05V41.44s-9.44,21-20.75,21S36.61,56,36.61,56Z"
|
|
27
|
+
transform="translate(-1.05 -0.29)"/>
|
|
28
|
+
</svg>
|
package/lib/adapter.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { LlmAdapter, type GenerateOptions, type ImageAttachmentAccessResolver, type LlmModelInfo, type LlmResolvedModelInfo, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
3
|
+
import { type ResolvedConfig } from './config.js';
|
|
4
|
+
/**
|
|
5
|
+
* Host-owned request-time services the adapter can read without depending on the harness repo.
|
|
6
|
+
*/
|
|
7
|
+
export interface MojieAdapterOptions {
|
|
8
|
+
/** Read the current live configuration for one request operation. */
|
|
9
|
+
readonly config: () => ResolvedConfig;
|
|
10
|
+
/** Resolve one credential reference through the host seam. */
|
|
11
|
+
readonly resolveApiKey: (ref: string) => Promise<string>;
|
|
12
|
+
readonly resolveAttachments?: () => AttachmentStore | undefined;
|
|
13
|
+
readonly resolveImageAccess?: ImageAttachmentAccessResolver;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Mojie Responses adapter.
|
|
17
|
+
*
|
|
18
|
+
* Timing model (one clock per failure mode, never a wall-clock cap on a live
|
|
19
|
+
* stream):
|
|
20
|
+
* - `firstByteTimeoutMs`: request sent → response headers. Catches a gateway
|
|
21
|
+
* that accepts the connection and never answers.
|
|
22
|
+
* - `streamIdleTimeoutMs`: silence between received bytes. SSE comment
|
|
23
|
+
* heartbeats reset it, so a generation that keeps streaming may run for
|
|
24
|
+
* hours.
|
|
25
|
+
* - `requestTimeoutMs`: optional operational backstop (`0` = off), never the
|
|
26
|
+
* liveness judge.
|
|
27
|
+
*/
|
|
28
|
+
export declare class MojieAdapter extends LlmAdapter {
|
|
29
|
+
private readonly dependencies;
|
|
30
|
+
private catalog;
|
|
31
|
+
private catalogRefresh;
|
|
32
|
+
constructor(dependencies: MojieAdapterOptions);
|
|
33
|
+
providerInfo(provider: string): {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
38
|
+
resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo>;
|
|
39
|
+
private resolveModelWith;
|
|
40
|
+
/** Discovery row for one model from the last successful listing, when it still matches the endpoint. */
|
|
41
|
+
private discoveredModel;
|
|
42
|
+
private loadCatalog;
|
|
43
|
+
/**
|
|
44
|
+
* Refresh the advisory catalog off the request path. Metadata only affects
|
|
45
|
+
* compaction and image handling, so a failed refresh must not fail a request.
|
|
46
|
+
*/
|
|
47
|
+
private ensureCatalog;
|
|
48
|
+
imageRequestTarget(_provider: string, _model: string, image: ImageAttachmentRef): {
|
|
49
|
+
maxBytes: number;
|
|
50
|
+
width: number;
|
|
51
|
+
height: number;
|
|
52
|
+
};
|
|
53
|
+
private imageTarget;
|
|
54
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
55
|
+
private prepareRequestImages;
|
|
56
|
+
private projectOffloaded;
|
|
57
|
+
}
|
package/lib/adapter.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { contentHasImage, LlmAdapter, LlmError, offloadedImageText, projectOffloadedImages, requiredImageOffload, } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { requestImageDimensions } from '@deepseek-ai/dsh-attachment';
|
|
3
|
+
import { fetchModelListing } from './discovery.js';
|
|
4
|
+
import { mergeCatalog, mergeResolvedModelInfo } from './catalog.js';
|
|
5
|
+
import { responsesURL } from './config.js';
|
|
6
|
+
import { serializeRequest } from './serialize.js';
|
|
7
|
+
import { streamResponses } from './core/stream.js';
|
|
8
|
+
/** How long one `/v1/models` listing answers advisory model metadata. */
|
|
9
|
+
const CATALOG_TTL_MS = 10 * 60_000;
|
|
10
|
+
/**
|
|
11
|
+
* Mojie Responses adapter.
|
|
12
|
+
*
|
|
13
|
+
* Timing model (one clock per failure mode, never a wall-clock cap on a live
|
|
14
|
+
* stream):
|
|
15
|
+
* - `firstByteTimeoutMs`: request sent → response headers. Catches a gateway
|
|
16
|
+
* that accepts the connection and never answers.
|
|
17
|
+
* - `streamIdleTimeoutMs`: silence between received bytes. SSE comment
|
|
18
|
+
* heartbeats reset it, so a generation that keeps streaming may run for
|
|
19
|
+
* hours.
|
|
20
|
+
* - `requestTimeoutMs`: optional operational backstop (`0` = off), never the
|
|
21
|
+
* liveness judge.
|
|
22
|
+
*/
|
|
23
|
+
export class MojieAdapter extends LlmAdapter {
|
|
24
|
+
dependencies;
|
|
25
|
+
catalog;
|
|
26
|
+
catalogRefresh;
|
|
27
|
+
constructor(dependencies) {
|
|
28
|
+
super();
|
|
29
|
+
this.dependencies = dependencies;
|
|
30
|
+
}
|
|
31
|
+
providerInfo(provider) {
|
|
32
|
+
return { id: provider, name: 'Mojie' };
|
|
33
|
+
}
|
|
34
|
+
async listModels(provider) {
|
|
35
|
+
const config = this.dependencies.config();
|
|
36
|
+
const apiKey = await this.dependencies.resolveApiKey(config.apiKeyEnv);
|
|
37
|
+
const discovered = await this.loadCatalog(config, apiKey, false);
|
|
38
|
+
return mergeCatalog(provider, config.models, discovered);
|
|
39
|
+
}
|
|
40
|
+
async resolveModel(provider, model) {
|
|
41
|
+
const config = this.dependencies.config();
|
|
42
|
+
return this.resolveModelWith(provider, model, config, this.discoveredModel(config, model));
|
|
43
|
+
}
|
|
44
|
+
resolveModelWith(provider, model, config, discovered) {
|
|
45
|
+
const configured = config.models.find((entry) => entry.id === model);
|
|
46
|
+
return mergeResolvedModelInfo(provider, model, configured, discovered, {
|
|
47
|
+
reasoningDefaults: config.reasoningDefaults,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Discovery row for one model from the last successful listing, when it still matches the endpoint. */
|
|
51
|
+
discoveredModel(config, model) {
|
|
52
|
+
const cached = this.catalog;
|
|
53
|
+
if (cached === undefined || cached.key !== config.baseURL)
|
|
54
|
+
return undefined;
|
|
55
|
+
return cached.models.find((entry) => entry.id === model);
|
|
56
|
+
}
|
|
57
|
+
async loadCatalog(config, apiKey, force) {
|
|
58
|
+
const cached = this.catalog;
|
|
59
|
+
if (!force
|
|
60
|
+
&& cached !== undefined
|
|
61
|
+
&& cached.key === config.baseURL
|
|
62
|
+
&& Date.now() - cached.at < CATALOG_TTL_MS) {
|
|
63
|
+
return cached.models;
|
|
64
|
+
}
|
|
65
|
+
const models = await fetchModelListing(config.baseURL, apiKey);
|
|
66
|
+
this.catalog = { key: config.baseURL, at: Date.now(), models };
|
|
67
|
+
return models;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Refresh the advisory catalog off the request path. Metadata only affects
|
|
71
|
+
* compaction and image handling, so a failed refresh must not fail a request.
|
|
72
|
+
*/
|
|
73
|
+
ensureCatalog(config) {
|
|
74
|
+
const cached = this.catalog;
|
|
75
|
+
if (cached !== undefined && cached.key === config.baseURL && Date.now() - cached.at < CATALOG_TTL_MS)
|
|
76
|
+
return;
|
|
77
|
+
if (this.catalogRefresh !== undefined)
|
|
78
|
+
return;
|
|
79
|
+
this.catalogRefresh = (async () => {
|
|
80
|
+
try {
|
|
81
|
+
const apiKey = await this.dependencies.resolveApiKey(config.apiKeyEnv);
|
|
82
|
+
await this.loadCatalog(config, apiKey, true);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Advisory metadata: keep serving built-in/configured values.
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
this.catalogRefresh = undefined;
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
}
|
|
92
|
+
imageRequestTarget(_provider, _model, image) {
|
|
93
|
+
return this.imageTarget(this.dependencies.config(), image);
|
|
94
|
+
}
|
|
95
|
+
imageTarget(config, image) {
|
|
96
|
+
return {
|
|
97
|
+
...requestImageDimensions(image.width, image.height, config.requestImagePixelBudget),
|
|
98
|
+
maxBytes: config.requestImageMaxBytes,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async *stream(options) {
|
|
102
|
+
if (options.stop !== undefined) {
|
|
103
|
+
throw new LlmError('Mojie Responses does not support GenerateOptions.stop', 'UNSUPPORTED_OPTION');
|
|
104
|
+
}
|
|
105
|
+
// One snapshot per request: a settings edit that lands mid-stream must not
|
|
106
|
+
// mix two generations of endpoint, limits, and model metadata.
|
|
107
|
+
const config = this.dependencies.config();
|
|
108
|
+
const provider = this.resolveModelWith(options.provider, options.model, config, this.discoveredModel(config, options.model));
|
|
109
|
+
if (options.reasoningEffort !== undefined && provider.reasoning === undefined) {
|
|
110
|
+
throw new LlmError(`provider "${options.provider}" model "${options.model}" does not support reasoning effort "${options.reasoningEffort}"`, 'UNSUPPORTED_REASONING_EFFORT');
|
|
111
|
+
}
|
|
112
|
+
this.ensureCatalog(config);
|
|
113
|
+
// The transport, clocks, SSE framing, and chunk translation are shared with
|
|
114
|
+
// standalone consumers (src/core/stream.ts); the adapter only contributes the
|
|
115
|
+
// DSH-specific image projection and request serialization.
|
|
116
|
+
const apiKey = await this.dependencies.resolveApiKey(config.apiKeyEnv);
|
|
117
|
+
yield* streamResponses({
|
|
118
|
+
endpoint: responsesURL(config.baseURL),
|
|
119
|
+
apiKey,
|
|
120
|
+
firstByteTimeoutMs: config.firstByteTimeoutMs,
|
|
121
|
+
streamIdleTimeoutMs: config.streamIdleTimeoutMs,
|
|
122
|
+
requestTimeoutMs: config.requestTimeoutMs,
|
|
123
|
+
...options.signal === undefined ? {} : { signal: options.signal },
|
|
124
|
+
prepareBody: async (signal) => {
|
|
125
|
+
const requestImages = await this.prepareRequestImages(options, provider, config, signal);
|
|
126
|
+
return serializeRequest({ ...options, messages: this.projectOffloaded(options, requestImages) }, requestImages === undefined ? undefined : {
|
|
127
|
+
requestImages,
|
|
128
|
+
...this.dependencies.resolveImageAccess === undefined ? {} : { resolveImageAccess: this.dependencies.resolveImageAccess },
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async prepareRequestImages(options, model, config, signal) {
|
|
134
|
+
if (!options.messages.some((message) => contentHasImage(message.content)))
|
|
135
|
+
return undefined;
|
|
136
|
+
if (!model.inputModalities?.includes('image'))
|
|
137
|
+
return undefined;
|
|
138
|
+
const attachments = this.dependencies.resolveAttachments?.();
|
|
139
|
+
if (attachments === undefined) {
|
|
140
|
+
throw new LlmError('Mojie image input requires the durable attachment service', 'UNSUPPORTED_CONTENT');
|
|
141
|
+
}
|
|
142
|
+
const refs = new Map();
|
|
143
|
+
for (const message of options.messages) {
|
|
144
|
+
for (const block of message.content) {
|
|
145
|
+
if (block.type !== 'image' || block.offloaded === true)
|
|
146
|
+
continue;
|
|
147
|
+
refs.set(block.attachment.attachmentId, block.attachment);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const versions = new Map();
|
|
151
|
+
for (const ref of refs.values()) {
|
|
152
|
+
versions.set(ref.attachmentId, await attachments.readImageRequest(ref, this.imageTarget(config, ref), signal));
|
|
153
|
+
}
|
|
154
|
+
const offloadImages = requiredImageOffload(options.messages, { representation: 'base64', maxBytes: config.maxRequestImageBytes }, block => {
|
|
155
|
+
const version = versions.get(block.attachment.attachmentId);
|
|
156
|
+
if (version === undefined)
|
|
157
|
+
return 0;
|
|
158
|
+
return version.bytes;
|
|
159
|
+
});
|
|
160
|
+
if (offloadImages > 0) {
|
|
161
|
+
throw new LlmError(`Mojie request images exceed the ${config.maxRequestImageBytes}-byte base64 budget; ${offloadImages} more oldest occurrence(s) must be offloaded.`, 'IMAGE_OFFLOAD_REQUIRED', { offloadImages });
|
|
162
|
+
}
|
|
163
|
+
return versions;
|
|
164
|
+
}
|
|
165
|
+
projectOffloaded(options, requestImages) {
|
|
166
|
+
if (requestImages === undefined)
|
|
167
|
+
return options.messages;
|
|
168
|
+
return projectOffloadedImages(options.messages, (ref) => {
|
|
169
|
+
return offloadedImageText(ref, this.dependencies.resolveImageAccess?.(ref));
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|