dsh-plugin-image-tools 0.4.0 → 0.4.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pasumao
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,6 +1,11 @@
1
1
  # dsh-plugin-image-tools
2
2
 
3
- DeepSeek Harness Web GUI 增加**图片能力**的插件,三个工具覆盖三种场景:
3
+ ![npm version](https://img.shields.io/npm/v/dsh-plugin-image-tools)
4
+ ![License](https://img.shields.io/github/license/Pasumao/dsh-plugin-image-tools)
5
+ ![AI Assisted](https://img.shields.io/badge/AI-Assisted-8A2BE2)
6
+
7
+ **dsh 插件市场里唯一支持「图片选择卡」的插件**:给 DeepSeek Harness Web GUI 增加图片能力,
8
+ 三个工具覆盖三种场景——模型让你在选项里挑图、在回复正文里展示图、你把图发给盲模型。全部零 token 本地渲染:
4
9
 
5
10
  | 工具 | 场景 | 效果 |
6
11
  |---|---|---|
@@ -88,33 +93,17 @@ cordis.patch.yml bundle 补丁(挂载行)
88
93
  docs/ 效果图(README 展示用)
89
94
  ```
90
95
 
91
- ## 安装(web profile)
96
+ ## 安装
92
97
 
93
98
  ```powershell
94
- # 1. 把插件 link 进 profile(已写入 package.json 时跳过这步的编辑)
95
- cd C:\Users\18303\.dsh\profiles\web
96
- pnpm install
97
-
98
- # 2. 重启 dsh(launcher),然后刷新浏览器页面
99
- ```
100
-
101
- profile 的 `package.json` 需要包含:
102
-
103
- ```jsonc
104
- {
105
- "dependencies": {
106
- "dsh-plugin-image-tools": "link:D:/dsh/plugins/dsh-plugin-image-tools"
107
- },
108
- "dsh": {
109
- "profile": {
110
- "bundles": [ /* ... */, "dsh-plugin-image-tools" ]
111
- }
112
- }
113
- }
99
+ # npm(推荐)
100
+ dsh plugin --profile web add dsh-plugin-image-tools
101
+ # 或 GitHub
102
+ dsh plugin --profile web add github:Pasumao/dsh-plugin-image-tools
114
103
  ```
115
104
 
116
- `dsh.profile.bundles` 里的包会自动应用其自带 `cordis.patch.yml` 的挂载行
117
- (与 dsh-notify 同机制)。
105
+ 装完重启 dsh(launcher),然后刷新浏览器页面。包自带 `cordis.patch.yml` 挂载行,
106
+ `dsh.profile.bundles` 自动应用(与 dsh-notify 同机制),无需手动改配置。
118
107
 
119
108
  ## 模型用法示例
120
109
 
@@ -176,4 +165,4 @@ profile 的 `package.json` 需要包含:
176
165
 
177
166
  ## 许可证
178
167
 
179
- MIT
168
+ [MIT](./LICENSE)
package/lib/index.js CHANGED
@@ -462,12 +462,35 @@ export function choiceTool(ctx, opts = {}) {
462
462
  const now = Date.now()
463
463
  prunePicks(now)
464
464
 
465
+ // 与浏览器端 askUserQuestionItemSchema(muxFrameSchema)对齐的必填/类型校验:
466
+ // 模型偶发漏传 question 等必填字段时,若原样转发,浏览器 zod 解析会把
467
+ // question/requested 整帧丢弃,选择卡静默不渲染(用户只见"图呢,看不到啊",
468
+ // 最终 ASK_ABORTED)。这里在服务端提前校验并抛面向模型的错误,让模型自我修正。
469
+ const questions = Array.isArray(args.questions) ? args.questions : []
470
+ for (let qi = 0; qi < questions.length; qi++) {
471
+ const q = questions[qi]
472
+ if (q === null || typeof q !== 'object') throw new Error(`questions[${qi}] 必须是对象`)
473
+ if (typeof q.id !== 'string' || q.id === '') throw new Error(`questions[${qi}].id 缺失或不是非空字符串(必填,稳定问题 id,随答案原样回传)`)
474
+ if (typeof q.question !== 'string' || q.question === '') throw new Error(`questions[${qi}].question 缺失或不是非空字符串(必填,用户看到的问题文本;请补上后重新调用 ask_user_choice)`)
475
+ if (q.header !== undefined && typeof q.header !== 'string') throw new Error(`questions[${qi}].header 必须是字符串`)
476
+ if (q.detail !== undefined && typeof q.detail !== 'string') throw new Error(`questions[${qi}].detail 必须是字符串`)
477
+ if (q.multi_select !== undefined && typeof q.multi_select !== 'boolean') throw new Error(`questions[${qi}].multi_select 必须是布尔值`)
478
+ const options = Array.isArray(q.options) ? q.options : []
479
+ for (let oi = 0; oi < options.length; oi++) {
480
+ const o = options[oi]
481
+ if (o === null || typeof o !== 'object') throw new Error(`questions[${qi}].options[${oi}] 必须是对象`)
482
+ if (typeof o.label !== 'string' || o.label === '') throw new Error(`questions[${qi}].options[${oi}].label 缺失或不是非空字符串(必填,选项文字/答案值)`)
483
+ if (o.description !== undefined && typeof o.description !== 'string') throw new Error(`questions[${qi}].options[${oi}].description 必须是字符串`)
484
+ if (o.image !== undefined && o.image !== null && (typeof o.image !== 'object' || o.image === null)) throw new Error(`questions[${qi}].options[${oi}].image 必须是对象(path / url / data 三选一)`)
485
+ }
486
+ }
487
+
465
488
  // 本次 ask 创建的 pickId,无论成功/失败/中止都统一释放(含中途加载报错)。
466
489
  const batches = []
467
490
  try {
468
491
  // 1) 逐题归一化图片,生成带图问题的 pickId 与标记。
469
492
  const askQuestions = []
470
- for (const question of args.questions ?? []) {
493
+ for (const question of questions) {
471
494
  const options = Array.isArray(question.options) ? question.options : []
472
495
  const imageIndexes = []
473
496
  const normalized = []
@@ -485,7 +508,12 @@ export function choiceTool(ctx, opts = {}) {
485
508
  let detail = typeof question.detail === 'string' ? question.detail : ''
486
509
  if (imageIndexes.length > 0) {
487
510
  const pickId = randomUUID()
488
- picks.set(pickId, { createdAt: now, images: normalized.filter((o) => o.image !== undefined).map((o) => o.image) })
511
+ // 按原始选项下标存图片(无图选项留空),保证客户端
512
+ // `/pickId/<原始下标>` 的 URL 与服务端索引一一对应;
513
+ // 紧凑数组会让带图选项下标不连续时错位/404。
514
+ const images = new Array(options.length).fill(undefined)
515
+ for (const index of imageIndexes) images[index] = normalized[index].image
516
+ picks.set(pickId, { createdAt: now, images })
489
517
  batches.push(pickId)
490
518
  detail = buildPickMarker(pickId, imageIndexes) + detail
491
519
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-plugin-image-tools",
3
3
  "description": "DSH 图片插件:ask_user_choice 图片/图文混合选项(Web GUI 渲染图片选择卡,可放大查看)+ show_images 在回复中内嵌图片(图片与文字混排)。图片来源支持本地路径 / http(s) URL / base64 data URI。纯插件实现,不改核心包。",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -15,6 +15,7 @@
15
15
  "docs",
16
16
  "cordis.patch.yml",
17
17
  "README.md",
18
+ "LICENSE",
18
19
  "设计说明.md"
19
20
  ],
20
21
  "scripts": {