@yfwu2020/dsh-selection-explain 0.7.1 → 0.9.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/README.md CHANGED
@@ -329,7 +329,9 @@ host 半注册了同源路由,可以单独调用:
329
329
  | --- | --- |
330
330
  | `POST /selection-explain/api/analyze` | 选中文字 + 上下文 → **SSE 流式**返回翻译与详解 |
331
331
  | `GET /selection-explain/api/ping` | 健康检查:当前模型路由、各阶段推理档位、限制 |
332
- | `GET /selection-explain/api/models` | 可选模型列表(面板里的模型选择器用) |
332
+ | `GET /selection-explain/api/models` | 可选模型列表(面板里的模型选择器用;带 `sessionId` 时 `current` 按该会话解析) |
333
+ | `GET/POST /selection-explain/api/settings` | 小窗设置页:`GET` 下发 `{ groups, values, defaults }`(字段声明即校验边界),`POST { values }` 合并写入、`{ reset: true }` 恢复默认 |
334
+ | `GET /selection-explain/api/route` | 极轻的"这一轮用哪个模型":`?sessionId=…` → `{ provider, model }`(设置页与模型胶囊按秒轮询它;带会话级短缓存,见下面「配置」一节) |
333
335
  | `GET/POST /selection-explain/api/history` | 小窗对话历史的读 / 写 / 删除 |
334
336
  | `POST /selection-explain/api/quote-context` | 引用上下文:`{ sessionId, text }` → 该引用所在的**一组对话 ± 一组**(`{ matched, context, rounds }`;定位不到时 `matched:false`,客户端退回自己采的局部上下文) |
335
337
  | `POST /selection-explain/api/promote` | 升格为正式会话 |
@@ -354,8 +356,107 @@ curl -s http://127.0.0.1:3080/selection-explain/api/ping
354
356
 
355
357
  ---
356
358
 
359
+ ## 档位兜底:「关」档不被支持时自动降级
360
+
361
+ 有些模型**不接受关闭推理**(上游直接 `400 invalid_request_error`)。首轮默认就是 `off`,
362
+ 撞上这种模型时整个划词解读会全挂。
363
+
364
+ 处理方式:
365
+
366
+ - 撞到一次就**记住这个 provider/model**(`${DSH_HOME:-~/.dsh}/selection-explain/leaky-off.json`
367
+ 的 `noOff` 字段),改用 **`low`**(最接近"关"的可接受档位)重试同一轮,并推一条 notice 说明。
368
+ - **下次不再尝试 `off`** —— 直接发 `low`,不再先失败一轮(省一个来回的时延,也不闪报错)。
369
+ - 重试只在"这一轮一个字都还没吐出来"时进行:已经出正文的失败不重试,避免把半截答案丢掉。
370
+ - 兜底覆盖**三种轮次**(首轮 / 详解 / 追问)。以前只对追问生效、而且要客户端显式传了档位才触发,
371
+ 所以首轮撞上这种模型时无人兜底。
372
+
373
+ ## 拖动与改大小
374
+
375
+ 小窗可以拖标题栏挪位置,拖右下角(或右/下边缘)改大小。
376
+
377
+ **位置和尺寸是两回事,只有尺寸会记住:**
378
+
379
+ - **位置不记**。每次开窗都按选区重新锚定:落在选区下方,下方放不下就翻到选区上方,
380
+ 再夹进视口。拖动只对这一次有效,关掉重开就回到划词的地方 —— 这是刻意的设计。
381
+ - **尺寸记**。拖角调过的大小存在 host 上(`${DSH_HOME:-~/.dsh}/selection-explain/panel.json`,
382
+ 接口 `GET/POST /selection-explain/api/panel`,载荷只有 `{w,h}`),
383
+ 刷新、换标签页、换浏览器 profile 都回到那个大小。
384
+ - **双击右下角角标**恢复默认尺寸(清掉存档)。
385
+
386
+ 其余约定:
387
+
388
+ - 尺寸下限 320×240,且始终夹在视口内(窗口缩小也不会超出)。上限是视口大小。
389
+ - 用户拉过大小后,设置页那条约 560px 的高度下限就**不再插手**(`data-resized` 标记)。
390
+ - 改动过程中不写盘,松手后防抖 300ms 再存 —— 不然每帧一个请求。
391
+ - 改大小用 **pointer 事件**(不是 mouse):触控板/触屏一样能拖,并且 `setPointerCapture`
392
+ 保证鼠标划出窗口也不会丢掉这一轮。
393
+ - 只有**真的拖动过**才会触发存档逻辑(点一下角标不算改了大小)。
394
+
357
395
  ## 配置
358
396
 
397
+ ### 方式一:在小窗里改(推荐)
398
+
399
+ 小窗头部有一枚 **⚙ 设置**(和「最近」「升格」同款的文字键),点开是一个从右侧滑入的抽屉,
400
+ 六个分类按任务分组:
401
+
402
+ | 分类 | 管什么 |
403
+ | --- | --- |
404
+ | 模型 | 一个模型选择,首轮、次轮与追问各自的思考强度 |
405
+ | 解读 | 选中文字与上下文的长度上限、限流、超时(秒) |
406
+ | 背景 | 解读附带的会话消息数、引用上下文的轮数与字符上限 |
407
+ | 联网 | 联网开关、检索轮数、工具白名单、文件读取边界 |
408
+ | 界面 | 侧边栏划词桥、右下角悬浮胶囊、静置收球时长(秒) |
409
+ | 数据 | 保留最近对话数量,每条包含所选文字、模型回答及后续追问 |
410
+
411
+ - **改完即时生效,无需重启。** 改动会**自动保存**(防抖 400ms),底部那行只有脏了才报
412
+ 「未保存 · N 项」,不弹 toast、不打断。
413
+ - **模型是一个下拉**,不用自己拼 provider 与 model:选项来自 host 已有的模型清单
414
+ (`GET /selection-explain/api/models?sessionId=…`,含每个 provider 下的全部模型)。
415
+ 写配置时展开成 `provider` + `model` 两个字段。
416
+ - **「跟随主会话」是名副其实的**:不选具体模型时,插件按**小窗所属会话**的模型解析路由 ——
417
+ 从会话原始事件里取最后一条 `model/selection`(`sessionModelOf`),
418
+ 所以两个会话用不同模型时各用各的,下拉里「(当前:…)」报的也是本会话那一个。
419
+ 会话没记过模型选择时落回 DSH 的全局默认模型。优先级:
420
+ 小窗与设置页的统一选择 → **本会话的模型** → 全局默认 → 第一个可用。
421
+ - **「小窗所属会话」= 划词那一刻的会话**(`panelSessionId`),不是"当前正在看的会话"。
422
+ 新版 DSH 从 `uiSession.adapter.current` 的主视图绑定读取会话 ID;会话目录不再提供 `current`。
423
+ 小窗开着时切走会话,解读 / 追问 / 升格与模型解析仍按原来那个会话算 ——
424
+ 否则背景会取错会话,模型也会跟着变。
425
+ 模型清单请求使用这个会话 ID,并保留各自的响应快照,避免切换时较慢的旧请求覆盖新会话。
426
+ - **模型名是实时的(小窗开着就在跟)**:**小窗或设置抽屉任意一个开着**时按 2 秒轮询那条轻量接口
427
+ `GET /selection-explain/api/route?sessionId=…`,主会话里换了模型,设置页括号里和**小窗输入框那枚
428
+ 模型胶囊**自己就跟着变,不用关掉重开(`/models` 要列全部模型、`/ping` 要枚举工具表,都不适合按秒轮询)。
429
+ 两个都收起来即停。host 侧这条接口带**会话级短缓存**:live 会话的事件数(`seq`)没涨就直接回上次的结论,
430
+ 涨了也至少隔 3 秒才重读一次 —— 否则"小窗一直开着"会变成每 2 秒把整份会话日志重放一遍
431
+ (实测 1.5MB 的会话一次 80~125ms)。用户动作路径(解读 / 追问 / 升格 / 模型清单 / ping)不吃这份缓存,
432
+ 拿到的永远是此刻那一份。
433
+ - **胶囊上显示的是模型名,不是 id**。跟随态也一样:开窗时顺手拉一次模型清单(60 秒缓存),
434
+ 按 **provider + model 两个键**换成清单里的显示名 —— 同一个 model id 在多个 provider 下是不同模型、
435
+ 不同名字(实测 `deepseek-flash` 在 opencode-go 叫「DeepSeek Flash」、在 deepseek-official /
436
+ deepseek-account 叫「DeepSeek-V41-Flash」),只按 id 查会张冠李戴。清单还没回来时先显示 id,
437
+ 回来后再画一次;provider 全名在胶囊的 hover 提示里。
438
+ - **输入框那枚胶囊点开的模型列表里,当前在用的那个会打勾**(跟随态也一样,并在名字后面带一枚
439
+ 「跟随」小标 —— 说明这个勾来自主会话、不是你选的);下面「推理等级」列的是**在用模型**声明的
440
+ 档位。名字过长时收窄名字显示省略号,保证一行里放得下 勾 + 名字 + 小标 + provider。
441
+ - **首轮、次轮和追问采用同一个模型**。小窗输入框与设置页双向同步,任一处修改均自动保存。
442
+ 旧版独立追问配置与浏览器模型缓存不再覆盖这一选择;三个阶段的思考强度仍分别设置。
443
+ - **「恢复默认」立即生效**:恢复各项配置,同时更新模型选择、控件禁用状态与悬浮入口。
444
+ - **时间一律按「秒」填**。配置里仍是毫秒(schema 与既有 yml 值不动),
445
+ 换算由 spec 上的 `scale: 1000` 声明 —— 边界的唯一事实来源还是 Config schema。
446
+ - 写完落在插件自己的目录,**不碰 `cordis.patch.yml`**:
447
+
448
+ ```
449
+ ${DSH_HOME:-~/.dsh}/selection-explain/settings.json
450
+ ```
451
+
452
+ 只存**改过的键**;「恢复默认」就是把它清空,回到下面表里的 yml/出厂值。
453
+ 那个 yml 是**装配清单**,让 UI 去改它既要人肉重启、又可能把 YAML 结构写坏,所以不碰。
454
+
455
+ > 字段的标题 / 说明 / 边界由 host 通过 `GET /selection-explain/api/settings` 下发,
456
+ > 客户端只负责画(见 `src/settings.ts`)。这样 UI 的边界和 host 的 clamp 不会各写一份、久了互相漂。
457
+
458
+ ### 方式二:写 `cordis.patch.yml`
459
+
359
460
  配置写在 profile 的 `cordis.patch.yml` 里同 id 的行上(`dsh plugin add` 装好后,包自带的 `cordis.patch.yml` 里已有可改的样板):
360
461
 
361
462
  ```yaml
@@ -374,15 +475,17 @@ curl -s http://127.0.0.1:3080/selection-explain/api/ping
374
475
  | 字段 | 默认 | 说明 |
375
476
  | --- | --- | --- |
376
477
  | `provider` | `''` | 固定 provider 路由;留空 = 跟随「设置 → 默认模型」 |
377
- | `model` | `''` | 固定 model id;留空 = 跟随默认模型 |
478
+ | `model` | `''` | 固定 model id;留空 = 跟随主会话 |
378
479
  | `reasoningEffort` | `high` | **详解**阶段推理档位(`off` / `low` / `high` / `max`) |
379
- | `translationReasoningEffort` | `low` | **首轮翻译**单独一档。这一轮只需挑英文片段,压低换首字速度 |
480
+ | `translationReasoningEffort` | `off` | **首轮**翻译、解读或注释单独一档,默认关闭思考 |
380
481
  | `chatReasoningEffort` | `high` | **追问**档位(追问要准不要快;想更快可调 `low`) |
381
482
  | `temperature` | `-1` | 采样温度。**`-1` = 不传**,交给供应商默认(与主会话一致);`0`~`2` 之间才真的传 |
382
483
  | `maxTokens` | `0` | 单次输出上限(tokens)。**`0` = 不限制**。填正数可控成本 / 控时延 |
383
484
  | `timeoutMs` | `300000` | 单次调用超时(含工具轮;客户端断开即中止上游) |
384
485
 
385
- > 推理档位三档分开是有原因的:翻译不需要深度推理,详解需要。默认 `translationReasoningEffort: low` 让首字快、`reasoningEffort: high` 让详解细。
486
+ > 三个阶段的思考强度可分别设置。默认 `translationReasoningEffort: off` 优先让首轮快速回答;代码中的详解初始值为 `reasoningEffort: high`,安装配置为 `off`,追问默认 `high`。
487
+
488
+ 输出上限、采样温度和结果缓存不在设置页展示;既有底层配置继续兼容。
386
489
 
387
490
  ### 上下文与缓存
388
491
 
@@ -398,9 +501,13 @@ curl -s http://127.0.0.1:3080/selection-explain/api/ping
398
501
  | `quoteContextMaxCharsPerTurn` | `2000` | 引用上下文里单条消息的上限(超了**围绕引用**截断,不裁掉引用本身) |
399
502
  | `quoteContextMaxChars` | `6000` | 引用上下文整段上限(超了先丢最早的、再丢引用之后的) |
400
503
  | `resultCacheTtlMs` | `600000` | 共享结果缓存 TTL(毫秒);`0` = 关闭 |
401
- | `historyMaxEntries` | `20` | 小窗对话历史保留多少个划词条目;`0` = 关闭历史 |
504
+ | `historyMaxEntries` | `20` | 保留最近对话数量;`0` = 不保存新对话,已有对话保留 |
402
505
  | `maxRequestsPerMinute` | `40` | 本地限流,防误触发刷爆额度 |
403
506
  | `bridgeSidebarPreview` | `true` | 侧边栏 HTML 预览里的划词桥。关掉 = 预览网页里选中文字不再弹按钮(预览帧不再补 `allow-scripts`,也不注入桥脚本) |
507
+ | `chatProvider` | `''` | 旧版兼容字段,不再参与模型选择 |
508
+ | `chatModel` | `''` | 旧版兼容字段,不再参与模型选择 |
509
+ | `pillEnabled` | `true` | 右下角悬浮胶囊(最近一次划词的状态入口)。关掉 = 右下角不再出现胶囊 |
510
+ | `pillIdleMs` | `10000` | 静置多久把胶囊收成小球(毫秒,2000~600000)。只在**没装费用胶囊**时生效(有费用胶囊时两者并排,收球会让它们错位) |
404
511
 
405
512
  ### 工具(联网 / 文件)
406
513
 
package/cordis.patch.yml CHANGED
@@ -9,8 +9,7 @@
9
9
  # 可调参数(改 profile 的 cordis.patch.yml 里同 id 行即可覆盖):
10
10
  # provider / model 固定模型路由;留空 = 跟随「默认模型」设置
11
11
  # reasoningEffort 详解阶段的推理档位:off / low / high / max
12
- # translationReasoningEffort 首轮「翻译」单独一档(默认 low);实测 low≈high 都要 8~11s,
13
- # 只有 off 是 1.7s(不思考)——想秒出就改成 off
12
+ # translationReasoningEffort 首轮单独一档(默认 off);需要思考时可改 low / high / max
14
13
  # chatReasoningEffort 追问档位(默认 high;想更快就调 low)
15
14
  # historyMaxEntries 小窗对话历史保留多少个「划词条目」(默认 20,0 = 关闭);
16
15
  # 每个条目内含它自己的全部追问轮次,升格过的不参与 LRU 淘汰
@@ -29,6 +28,7 @@
29
28
  - id: selection-explain
30
29
  name: '@yfwu2020/dsh-selection-explain'
31
30
  config:
31
+ translationReasoningEffort: off
32
32
  # 首字约 1.9s(实测,off 不思考);要更深可改 low / high / max
33
33
  reasoningEffort: off
34
34
  # 想再快:把背景窗口调小(少 prefill)