@mokuyoaxis/dsh-iris 0.2.4 → 0.2.6

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.
Files changed (53) hide show
  1. package/.dsh/skills/iris-use/SKILL.md +2 -2
  2. package/.dsh/skills/iris-use/references/media-contract.md +2 -2
  3. package/CHANGELOG.md +38 -1
  4. package/README.en.md +34 -41
  5. package/README.md +35 -40
  6. package/bin/dsh-iris.js +29 -12
  7. package/docs/AGENT_QUICKSTART.md +11 -13
  8. package/docs/ARCHITECTURE.md +1 -1
  9. package/docs/CLI_MANAGEMENT.md +5 -1
  10. package/docs/DSH_COMPATIBILITY.md +38 -8
  11. package/docs/DSH_PROVIDER_CONNECTIONS.md +34 -0
  12. package/docs/DSH_RC2_ADAPTATION.md +1 -1
  13. package/docs/FUNCTION_MODEL_ASSIGNMENTS.md +2 -0
  14. package/docs/FUNCTION_MODEL_POOLS.md +84 -0
  15. package/docs/HEADLESS_CLI.md +7 -7
  16. package/docs/HOST_ADAPTER_CONTRACT.md +8 -2
  17. package/docs/HOST_DOCTOR.md +3 -3
  18. package/docs/MUSIC.md +2 -2
  19. package/docs/PROVIDER_HEALTH.md +26 -2
  20. package/docs/ROADMAP.md +8 -4
  21. package/docs/SECURITY.md +12 -2
  22. package/docs/VISION_CLI.md +2 -2
  23. package/docs/releases/0.2.5.md +33 -0
  24. package/docs/releases/0.2.6.md +50 -0
  25. package/lib/actions.js +137 -30
  26. package/lib/adapters.js +36 -9
  27. package/lib/api.js +2 -1
  28. package/lib/client.js +717 -180
  29. package/lib/composite-vision-routing.js +6 -6
  30. package/lib/config.js +140 -29
  31. package/lib/doctor.js +9 -2
  32. package/lib/dsh-compatibility.js +7 -1
  33. package/lib/dsh-core-adapter.js +22 -11
  34. package/lib/dsh-host-adapter.js +32 -29
  35. package/lib/dsh-provider-config.js +35 -0
  36. package/lib/dsh-provider-source.js +102 -0
  37. package/lib/headless-vision.js +5 -5
  38. package/lib/host-contract.js +1 -0
  39. package/lib/http-vision-model-adapter.js +5 -2
  40. package/lib/index.js +54 -35
  41. package/lib/model-directory-service.js +53 -0
  42. package/lib/model-directory.js +103 -0
  43. package/lib/models.js +71 -6
  44. package/lib/ocr-model-routing.js +2 -2
  45. package/lib/provider-adapters.js +42 -9
  46. package/lib/provider-catalog.js +14 -9
  47. package/lib/provider-config-scope.js +16 -0
  48. package/lib/provider-config-service.js +82 -13
  49. package/lib/provider-health.js +33 -0
  50. package/lib/provider-protocol.js +30 -0
  51. package/lib/vision-model-routing.js +25 -12
  52. package/package.json +9 -9
  53. package/user_guide.md +28 -29
@@ -5,7 +5,7 @@ description: "Use dsh-iris for a single media operation or an existing task: ima
5
5
 
6
6
  # 使用 Iris 媒体能力
7
7
 
8
- 把用户要求交给对应的 Iris 功能,使用当前配置分配的模型,并交付实际产物。单独生成一首音乐、修改一张图片、识别文字或查询已有任务都适用本 skill。
8
+ 把用户要求交给对应的 Iris 功能,使用当前功能允许的模型,并交付实际产物。单独生成一首音乐、修改一张图片、识别文字或查询已有任务都适用本 skill。
9
9
 
10
10
  ## 选择入口
11
11
 
@@ -28,7 +28,7 @@ description: "Use dsh-iris for a single media operation or an existing task: ima
28
28
  ## 按当前能力执行
29
29
 
30
30
  - 当前工具列表是可调用入口的依据;skill 可见不代表插件已经装载新工具。工具缺失、服务端/客户端不一致或模型未配置时,说明具体缺口。必要时查看 Iris 工作台的宿主诊断与能力分配,不以生成请求探测配置。
31
- - 模型名称、供应商名称和模型目录不能证明能力。尊重用户指定的 `providerId::modelId`,其余按功能配置选择;Music 必须有明确分配,并绑定音乐协议。
31
+ - 模型名称、供应商名称和模型目录不能证明能力。仅在用户明确指定时传 `providerId::modelId`,其余省略模型参数,按当前功能策略选择;不要默认填首个候选。Music 必须在当前功能允许范围内,并绑定音乐协议。
32
32
  - 参数与输入输出的详细区别见[共享能力和产物说明](references/media-contract.md)。仅阅读当前操作相关部分。
33
33
  - 请求歌曲或配乐时调用 Music;TTS 用于说话声音。音乐未配置或调用失败时报告原因,不擅自用 NumPy、节拍合成或 TTS 替代。用户明确要求程序化合成时按该要求处理。
34
34
  - 音乐生成的时长、歌词、演唱语言和风格当前由 prompt 表达;不把它们当作保证生效的结构化控制。
@@ -28,9 +28,9 @@
28
28
 
29
29
  ## 功能与模型选择
30
30
 
31
- 生图、视频、TTS、Music、转写和视觉只使用各自明确分配的有序名单;空名单不调用,临时指定须已分配且只用该项。DSH默认视觉须明确加入视觉名单,不能在指定模型失败后隐式回退。手动实测独立于生产分配,旧任务查询/补交付仍绑定原模型。改图复用生图名单,接受 `openai-chat-images` 或 `dashscope` 原生 Qwen edit/max/plus、2.0/pro及日期快照;其他原生Qwen版本尚未接入。源图为一个Core静态PNG/JPEG/WebP,最多20 MiB;不提供蒙版或多张参考图输入。默认发送预算8 MiB,可按账号/模型调整;原生Qwen发送副本另限10 MiB,原作品保留。
31
+ 生图、视频、TTS、Music、转写和视觉按当前功能允许范围选择。0.2.4/0.2.5仅使用明确有序名单;0.2.6另支持已确认用途的自动池及显式停用,旧缺失/空分配不自动启用。仅在用户指定时传模型参数,只调用该项;默认省略,保留完整候选链。DSH默认视觉须明确加入名单或开启自动池的宿主视觉选项,不能在指定模型失败后隐式回退。手动实测独立于生产范围,旧任务查询/补交付仍绑定原模型。改图复用图片功能池,接受 `openai-chat-images` 或 `dashscope` 原生 Qwen edit/max/plus、2.0/pro及日期快照;其他原生Qwen版本尚未接入。源图为一个Core静态PNG/JPEG/WebP,最多20 MiB;不提供蒙版或多张参考图输入。默认发送预算8 MiB,可按账号/模型调整;原生Qwen发送副本另限10 MiB,原作品保留。
32
32
 
33
- Music 为独立 `music-gen` 功能,仅使用明确分配名单。模型须配置 `musicProtocol: gemini-web-music`;它不改变账号图片默认协议。其他 Music Adapter 尚未实现。当前正式参数控制客户端超时与502重试;曲长、人声、歌词、语言等是描述意图。
33
+ Music 为独立 `music-gen` 功能,仅使用其当前允许范围。模型须配置 `musicProtocol: gemini-web-music`;它不改变账号图片默认协议。其他 Music Adapter 尚未实现。当前正式参数控制客户端超时与502重试;曲长、人声、歌词、语言等是描述意图。
34
34
 
35
35
  通用候选仅在明确未受理时切换。Music 的HTTP502策略是按配置重新生成同一模型,不是换供应商:默认额外2次、间隔5000ms,每次新Task并记录retriedFrom,可能额外消耗额度。Agent 调用一次工具后消费其结果;工具失败不授权另一层自动重试。已有完整结果优先补交付,详见各 skill 链接的任务恢复说明。
36
36
 
package/CHANGELOG.md CHANGED
@@ -4,6 +4,41 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.6] - 2026-10-19
8
+
9
+ 0.2.6 的重点是减少重复配置,并让模型候选与当前连接保持一致:复用 DSH 连接、可选功能自动池、按需目录同步和能力检测。旧名单、空配置及任务恢复边界保持。升级后需重载 DSH 服务端并刷新页面,见 [发布说明](docs/releases/0.2.6.md)。
10
+
11
+ ### Added
12
+
13
+ - DSH供应商连接引用:工作台可选择已有连接,地址和API Key在操作时由宿主解析,避免重复保存密钥;协议、模型用途及功能策略仍需明确确认。支持公开API Key凭据来源,缺少宿主接口、OAuth或自定义认证时说明限制。见 [连接复用](docs/DSH_PROVIDER_CONNECTIONS.md)。
14
+ - 六类功能可选择自动池、仅用所选模型或停用。自动池按稳定顺序使用已确认用途的合格模型,明确未受理时安全切换;显式指定只调用该项,未增加跨请求轮转。旧名单与缺失/空分配保持原行为。见 [功能模型池](docs/FUNCTION_MODEL_POOLS.md)。
15
+ - 首次配置可在确认模型用途时同时启用所选功能的自动池,免去二次分配;工作台展示候选数和配置缺口。后续发现条目待确认,不静默扩池;配置与候选预览不发起生成。
16
+ - 功能池切换采用页面内确认与逐项保存反馈;慢响应时防止重复提交,保存结果不明时可只读核对。识别尚未加载新策略的服务端并暂停切换,避免旧接口返回成功却未启用自动池。
17
+ - 工作台新增“能力状态与检测”:六项能力卡、中文检测直达入口、只读配置检查与单模型实测详情;页面内确认、逐项进度、防重复提交和未知结果提示。视频、音乐、转写引导到真实任务,适配深浅主题及手机布局。见 [能力健康](docs/PROVIDER_HEALTH.md)。
18
+ - 工作台统一分区卡片、标题、按钮及表单样式,收紧卡片留白和控件间距,保留手机点击尺寸。能力检测默认折叠保留摘要,功能池、创作工具、偏好、诊断和历史默认收起,入口显示“展开/收起”。检测跳转自动展开目标分区,折叠期间保留正在执行的请求和结果。
19
+ - 模型目录采用完整快照,自动请求前按需刷新、成功缓存 10 分钟,失败保留旧目录。工作台新增默认折叠的同步摘要与变更信息;新增模型仍需确认用途,不删除旧模型。见 [目录与候选规则](docs/FUNCTION_MODEL_POOLS.md#目录更新与候选可用性)。
20
+
21
+ ### Fixed
22
+
23
+ - 工作台折叠提示改为只渲染当前状态的一条文案,关闭显示“展开”、打开显示“收起”;重新加载客户端时原位更新旧样式,修复旧样式残留导致两个提示同时显示的问题。
24
+ - TTS 不再把已知实时语音及尚未接入的语音系列当作普通 HTTP 模型检测或自动选用;缺少专用音色的复刻/设计模型跳过空样本检测,保留历史证据。`Model not exist` 提示具体模型、请求域名及地域/协议排查方向;不自动修改个人模型或重试。
25
+ - 当前连接明确返回模型不存在后,按模型与能力隔离后续候选,保留历史成功和手工配置,支持单项实测恢复。CLI、DSH 与 Agent 共用判断;目录发现不再把视频混合音频或音频理解误判为独立 TTS/转写能力。
26
+
27
+ ### Security
28
+
29
+ - 媒体 Provider Adapter 在错误截断前移除本次已知 API Key,覆盖无厂商前缀的密钥及错误码回显,避免进入公开错误与任务记录。
30
+ - `sharp` 最低版本升至 `0.35.5` 并同步锁文件,处理预编译 librsvg 的高危公告 [GHSA-wq5f-xc86-pv6w](https://github.com/lovell/sharp/security/advisories/GHSA-wq5f-xc86-pv6w)。自定义系统库的部署仍需单独检查。
31
+
32
+ ## [0.2.5] - 2026-10-16
33
+
34
+ ### Changed
35
+
36
+ - 恢复当前功能在旧DSH上的支持:准确覆盖0.1.2-rc.1、0.1.5-rc.1/rc.2/rc.3、0.1.7-rc.1/rc.2、0.2.0-rc.1/rc.2及0.2.1-alpha.1/alpha.2/alpha.3/alpha.4;同步engines、可选客户端peers与Doctor。旧宿主共用当前Core、Music、图片导入和原生Qwen改图,Node最低仍为22。见 [兼容矩阵与验证范围](docs/DSH_COMPATIBILITY.md)。
37
+
38
+ ### Fixed
39
+
40
+ - 默认视觉按宿主接口能力启用精确路由,修复旧SDK已有相同API却被版本号判断送入历史路径、可能返回空结果或忽略失败终态的问题。
41
+
7
42
  ## [0.2.4] - 2026-10-15
8
43
 
9
44
  ### Added
@@ -325,7 +360,9 @@ Iris 0.2.0 要求 Node.js ≥ 22.0.0,DSH 插件仅支持 `0.2.0-rc.2`;旧宿
325
360
  - 上传采用流式限额、临时 `.part` 文件和原子落盘,失败时会清理未完成文件。
326
361
  - 修改状态的路由拒绝明确的跨站请求,媒体文件继续使用随机能力令牌访问。
327
362
 
328
- [Unreleased]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.2.4...HEAD
363
+ [Unreleased]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.2.6...HEAD
364
+ [0.2.6]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.2.5...v0.2.6
365
+ [0.2.5]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.2.4...v0.2.5
329
366
  [0.2.4]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.2.3...v0.2.4
330
367
  [0.2.3]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.2.2...v0.2.3
331
368
  [0.2.2]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.2.1...v0.2.2
package/README.en.md CHANGED
@@ -20,7 +20,11 @@
20
20
 
21
21
  dsh-iris gives agents, the Iris workbench and a standalone CLI image, video, music, speech and visual understanding capabilities. Each image model can use DashScope, OpenAI Images, chat image generation or Responses. Shared Core Artifacts connect generation, vision, OCR and chat editing. The DSH workbench provides configuration and task management, while the 🫧 bubble offers draft optimization in the composer.
22
22
 
23
- Music uses a Chat Completions interface with inline audio, explicit model assignment, configurable 502 retries, and playback/export. See [Music setup and usage](docs/MUSIC.md) (Chinese).
23
+ Music uses a Chat Completions interface with inline audio, confirmed model uses and function policies, configurable 502 retries, and playback/export. See [Music setup and usage](docs/MUSIC.md) (Chinese).
24
+
25
+ Iris 0.2.6 can [reference an existing DSH provider connection](docs/DSH_PROVIDER_CONNECTIONS.md) (Chinese), resolving its endpoint and API key per operation without storing a second key. It adds [automatic, selected-only, and disabled function pools](docs/FUNCTION_MODEL_POOLS.md) (Chinese): confirming a model's uses can enable automatic selection without a second assignment step. Discovery alone never expands the pool; existing lists and empty configurations retain their behavior. Selection uses stable priority with safe failover, without a round-robin cursor.
26
+
27
+ Provider directories refresh on demand with a 10-minute successful cache. Confirmed model-not-found failures exclude that connection's model and capability from subsequent requests while preserving configured models and historical success. Directory details start collapsed; failed refreshes retain the last complete snapshot, and new models still require approval of their uses.
24
28
 
25
29
  ## A real generation example
26
30
 
@@ -46,22 +50,25 @@ These captures come from an Android browser connected to DSH under Termux/PRoot
46
50
 
47
51
  The project is at an early stage; interfaces and configuration formats may still change between releases.
48
52
 
49
- Iris 0.2.4 provides a DSH plugin and a headless CLI sharing tasks, artifacts and model routing, with persistent image import, native Qwen editing, and explicit function assignments. Music, three agent skills, and synchronous delivery recovery remain available. Core internals have not been frozen as a public SDK.
53
+ This documentation covers **Iris 0.2.6**. Pin the version when installing or upgrading, and check the host compatibility range below first.
50
54
 
51
- > Version support: Iris 0.2.4 supports DSH `0.2.0-rc.2` or `0.2.1-alpha.4`; Iris 0.2.0–0.2.3 supports rc.2 only. Node.js must be at least 22.0.0 and meet any higher host requirement. Older DSH hosts should pin Iris 0.1.4. See the [compatibility matrix](docs/DSH_COMPATIBILITY.md).
55
+ Iris 0.2.6 provides a DSH plugin and a headless CLI sharing tasks, artifacts and model routing. It adds connection reuse, optional automatic function pools, directory synchronization and capability checks. Image import, native Qwen editing, music, three agent skills and synchronous delivery recovery remain available. Core internals have not been frozen as a public SDK.
52
56
 
53
- ## What's new in 0.2.4
57
+ > Version support: Iris 0.2.6 retains the 12 exact DSH versions declared in 0.2.5; see the [compatibility matrix](docs/DSH_COMPATIBILITY.md). Node.js must be at least 22.0.0 and meet any higher host requirement. Connection reuse also requires the relevant public host services.
54
58
 
55
- **Image reuse, explicit function assignments, and support for the newer host.**
59
+ ## What's new in 0.2.6 and existing features
60
+
61
+ **Choose a connection, confirm model uses, then call a function.** Automatic pools use stable priority and safe failover, without cross-request round-robin.
56
62
 
57
63
  - **Persistent image import:** save an existing image through the workbench, agent, or CLI for later vision, editing, and export. The source file stays intact and no model is called.
58
64
  - **Native Qwen editing:** use supported DashScope Qwen image editing models as well as chat image models; edited images retain a link to their source.
59
- - **Explicit assignments:** image, video, TTS, music, transcription, and vision use only their assigned ordered lists. Explicit overrides must also be assigned.
60
- - **Two host versions:** DSH rc.2 and alpha.4 use the same manifest, client peer, and Doctor compatibility boundary.
65
+ - **Connection reuse and function pools:** reference a DSH API-key connection, and choose automatic, selected-only or disabled mode for each function. Confirming uses can also enable its automatic pool.
66
+ - **Directories and checks:** refresh directories before automatic requests and exclude confirmed missing models from later requests. Capability checks and advanced sections start collapsed; paid probes require separate confirmation.
67
+ - **Older and transitional hosts:** the twelve exact versions in the matrix share current features and use the same manifest, client peer and Doctor compatibility boundary.
61
68
 
62
- **Check assignments before upgrading:** empty lists stop new calls instead of adding models from the pool. Existing tasks retain their original bindings. Add the DSH default model explicitly to vision when needed. See the [upgrade guide](docs/FUNCTION_MODEL_ASSIGNMENTS.md).
69
+ **Upgrades preserve your allowed scope:** existing lists and missing or empty assignments do not become automatic. New directory entries still require confirmation of their uses; absence alone does not prove a model unavailable. Explicitly add host vision or enable it in the automatic vision pool. Existing tasks retain their bindings. See [function pools](docs/FUNCTION_MODEL_POOLS.md).
63
70
 
64
- See the [0.2.4 release notes](docs/releases/0.2.4.md) and [CHANGELOG](CHANGELOG.md); music and Skills from the previous release are documented in [0.2.3](docs/releases/0.2.3.md).
71
+ See the [0.2.6 release notes](docs/releases/0.2.6.md) for upgrade steps and validation limits, and the [CHANGELOG](CHANGELOG.md). Older-host support was restored in [0.2.5](docs/releases/0.2.5.md); image import arrived in [0.2.4](docs/releases/0.2.4.md), and music and Skills in [0.2.3](docs/releases/0.2.3.md).
65
72
 
66
73
  Future work includes additional protocol adapters and creative workflows; see the [roadmap](docs/ROADMAP.md#后续功能方向).
67
74
 
@@ -73,7 +80,7 @@ Future work includes additional protocol adapters and creative workflows; see th
73
80
  | Entry point | Choose a pinned release under "Quickest start" below | `dsh-iris run ...` — see [Headless CLI](docs/HEADLESS_CLI.md) |
74
81
  | Data location | `$DSH_HOME/iris/v1/` (Core data root `core-v0`) | Any absolute path passed via `--data-root` |
75
82
  | Automatic observation | Yes (bounded DSH host ticks + restart takeover) | Explicit `task observe`; 0.2.2 also offers bounded `task wait` |
76
- | Dependencies | DSH rc.2 or alpha.4, and Node.js ≥ 22 meeting host requirements | Node.js ≥ 22 and `sharp` only (`ffmpeg` for video frames) |
83
+ | Dependencies | A DSH version in the compatibility matrix, and Node.js ≥ 22 meeting host requirements | Node.js ≥ 22 and `sharp` only (`ffmpeg` for video frames) |
77
84
 
78
85
  Both paths read and write the same Core Task/Artifact facts: point the CLI at the `core-v0` data root of a DSH profile to inspect/export DSH-generated artifacts, and vice versa. Only one writer is allowed per data root.
79
86
 
@@ -81,64 +88,48 @@ Both paths read and write the same Core Task/Artifact facts: point the CLI at th
81
88
 
82
89
  ## Optional legacy configuration import
83
90
 
84
- For a new installation, add providers in the Iris workbench. Iris uses its own configuration and does not scan other projects by default.
91
+ For a new installation, add a provider or reference a DSH connection in the Iris workbench. Iris uses its own configuration and does not scan other projects by default.
85
92
 
86
93
  If you already have an ai-paint configuration, set `IRIS_IMPORT_WORKBENCH_CONFIG` to its absolute file path for a one-time provider import. Iris leaves the source untouched and does not keep configurations synchronized. The variable holds a file path, not an API key. See the [user guide](user_guide.md) for details.
87
94
 
88
95
  ## Quickest start
89
96
 
90
- Check the host with `dsh --version` and ensure `pnpm` is on your PATH. Iris and DSH have independent version numbers; choose a matching combination:
97
+ Check the host with `dsh --version` and ensure `pnpm` is on your PATH. Iris and DSH have independent version numbers; Iris 0.2.6 retains the twelve exact hosts listed in the [compatibility matrix](docs/DSH_COMPATIBILITY.md).
91
98
 
92
99
  | Your DSH | Iris choice | Source |
93
100
  |---|---|---|
94
- | `0.2.0-rc.2` or `0.2.1-alpha.4` | `0.2.4` | Pinned npm release |
95
- | `>=0.1.2-rc.1 <0.1.3-0` or `0.1.5-rc.1` | Stable `0.1.4` | Pinned npm release |
96
- | Other versions | No current support claim | Check host adaptation before installing |
97
-
98
- ### Older DSH: install stable 0.1.4
101
+ | Exact 0.1.2 / 0.1.5 / 0.1.7 / 0.2 versions in the matrix | `0.2.6` | Pinned npm version |
102
+ | Versions outside the matrix | Not yet validated | Check the actual host interfaces |
99
103
 
100
- For the older DSH range above, add the pinned release to the Web profile:
101
-
102
- ```bash
103
- dsh plugin --profile web add @mokuyoaxis/dsh-iris@0.1.4
104
- dsh web
105
- ```
106
-
107
- To download the published npm package separately:
108
-
109
- ```bash
110
- npm pack @mokuyoaxis/dsh-iris@0.1.4
111
- ```
112
-
113
- This writes a `.tgz` to the current directory. Use `npm install @mokuyoaxis/dsh-iris@0.1.4` if you only want a regular npm dependency; that does not add a DSH profile layer. Pinning `@0.1.4` keeps selecting the old stable release after latest changes. See [npm pack](https://docs.npmjs.com/cli/v11/commands/npm-pack/). Version 0.1.4 does not contain the 0.2.0 Core media CLI or the later DSH rc.2 adaptation.
114
-
115
- ### DSH rc.2 or alpha.4: install 0.2.4
104
+ ### DSH plugin: install 0.2.6
116
105
 
117
106
  Install the pinned release into your Web profile:
118
107
 
119
108
  ```bash
120
- dsh plugin --profile web add @mokuyoaxis/dsh-iris@0.2.4
109
+ dsh plugin --profile web add @mokuyoaxis/dsh-iris@0.2.6
121
110
  dsh web
122
111
  ```
123
112
 
124
113
  The plugin loads on the next DSH start. The web UI defaults to `http://127.0.0.1:3080`; open the complete URL if startup output includes authentication parameters. Reload the backend and refresh the web client after updating.
125
114
 
126
- ### Standalone CLI: install 0.2.4
115
+ ### Standalone CLI: install 0.2.6
127
116
 
128
117
  Install in your own project without DSH:
129
118
 
130
119
  ```bash
131
- npm install @mokuyoaxis/dsh-iris@0.2.4
120
+ npm install @mokuyoaxis/dsh-iris@0.2.6
132
121
  npx dsh-iris --help
133
122
  ```
134
123
 
124
+ Download the package separately with `npm pack @mokuyoaxis/dsh-iris@0.2.6`. Users who need historical Iris0.1.4 can still pin it; see the matrix for its DSH/Node requirements. It lacks the current Core media CLI and later features.
125
+
135
126
  ### Choosing a version in dsh-market
136
127
 
137
- The marketplace entry should resolve to the full package name `@mokuyoaxis/dsh-iris`. Check its Iris version and your local `dsh --version` against the [compatibility matrix](docs/DSH_COMPATIBILITY.md); older hosts should pin `@0.1.4`. Catalog and npm data may be cached. The actual package's top-level `engines.dsh`, Node requirement, and client peers define its requirements; a visible listing does not imply support for every DSH release.
128
+ The marketplace entry should resolve to the full package name `@mokuyoaxis/dsh-iris`. Check its Iris version and your local `dsh --version` against the [compatibility matrix](docs/DSH_COMPATIBILITY.md) for that release. Catalog and npm data may be cached. The actual package's top-level `engines.dsh`, Node requirement, and client peers define its requirements; a visible listing does not imply support for every DSH release.
138
129
 
139
130
  > The unscoped `dsh-iris` on npm belongs to a different plugin. Always keep the fully scoped name `@mokuyoaxis/dsh-iris` when installing or updating Iris Media.
140
131
 
141
- After the first start, open "Settings → Iris workbench → + Add provider", enter your provider base URL and API key, discover models, label their capabilities, and assign them to each function. Version 0.2.4 uses explicit ordered lists for all functions; see [assignment rules and upgrade impact](docs/FUNCTION_MODEL_ASSIGNMENTS.md) (Chinese). Full steps and protocol selection are in the [user guide](user_guide.md) (Chinese).
132
+ After the first start, open "Settings → Iris workbench → + Add provider", reference a DSH connection or enter your endpoint and key, and choose the media protocol. Synchronize the directory and confirm model uses; first-time setup can enable automatic selection in the same step. Selected-only mode still requires a list. See [function pools](docs/FUNCTION_MODEL_POOLS.md) and the [user guide](user_guide.md) (Chinese).
142
133
 
143
134
  Once configured, minimal instructions can be as simple as:
144
135
 
@@ -177,7 +168,7 @@ After installing the plugin, add a provider in the Iris workbench and assign mod
177
168
 
178
169
  ## DeepSeek Harness adaptation
179
170
 
180
- dsh-iris remains a native DSH plugin. Iris 0.2.4 registers 17 agent tools, including import, editing, and music, and uses host routing, attachments, models, and lifecycle services. The web client contributes settings, composer, and global-overlay UI. Iris does not start another service or listen on an extra port.
171
+ dsh-iris remains a native DSH plugin. Iris 0.2.6 registers 17 agent tools, including import, editing, and music, and uses host routing, attachments, models, and lifecycle services. The web client contributes settings, composer, and global-overlay UI. Iris does not start another service or listen on an extra port.
181
172
 
182
173
  Save an uploaded or local image as a persistent Artifact for viewing, editing and export; see [image import](docs/IMAGE_IMPORT.md) (Chinese).
183
174
 
@@ -189,10 +180,12 @@ Save an uploaded or local image as a persistent Artifact for viewing, editing an
189
180
  | `0.2.2` | Only `0.2.0-rc.2` | Installed-service checks cover 15 tools and 31 boundaries; complete browser/mobile and real asynchronous restart acceptance remain pending |
190
181
  | `0.2.3` | Only `0.2.0-rc.2` | Adds music and a third skill; check actual loading with Host Doctor after upgrading |
191
182
  | `0.2.4` | `0.2.0-rc.2` or `0.2.1-alpha.4` | 17 tools / 3 skills; actual SDK, loader, and client slot isolation checks; full browser and hot reload checks remain separate |
183
+ | `0.2.5` | 12 exact versions across the 0.1.2 / 0.1.5 / 0.1.7 / 0.2 lines; see the matrix | Official SDK isolation checks including Music and Qwen dispatch; old profiles also load the actual installed package |
184
+ | `0.2.6` | Retains the 12 exact versions declared in 0.2.5 | Adds connection reuse, function pools and directories; connection reuse requires public host services; see this version's release notes |
192
185
 
193
186
  See the [compatibility matrix](docs/DSH_COMPATIBILITY.md) for the current scope and [rc.2 adaptation notes](docs/DSH_RC2_ADAPTATION.md) for historical changes. npm 0.1.4 does not contain these later adaptations.
194
187
 
195
- Iris 0.2.x no longer claims older DSH support; historical validation does not automatically cover this version. DSH `0.2.0` stable and other rc versions are also outside its support range. Automated checks cover server loading, tool and Skill registration, routes, the client bundle, and UI slots separately so Doctor can identify which boundary failed.
188
+ Version 0.2.5 adapts to host API capabilities and declares support for the exact versions tested. Other versions need separate validation. Checks cover loading, tools, Skills, routes and client slots; full browser interaction and old-data upgrades remain separate. Doctor identifies the boundaries it can observe at runtime.
196
189
 
197
190
  Core and the DSH Adapter are being separated: DSH keeps loading the same npm package, while the Adapter maps host capabilities into Core. A DSH API change should require an Adapter or client-bridge fix, not a rewrite of Task or Artifact semantics. Version 0.2.0 includes the headless CLI. The `dsh` prefix will be removed after a second real Host Adapter is implemented and accepted, with a new npm package at that point; see the [roadmap](docs/ROADMAP.md).
198
191
 
@@ -285,7 +278,7 @@ npx @mokuyoaxis/dsh-iris doctor --json
285
278
 
286
279
  The installed binary is `dsh-iris`. Exit code `0` is healthy, `1` means warnings, and `2` means hard errors. Offline Doctor checks Node.js, sharp, ffmpeg/ffprobe, a real but cleaned-up storage write probe, configuration, models/assignments, task semantics, temporary files, and orphaned or missing artifacts.
287
280
 
288
- A running DSH instance also provides a “Host diagnostics” card and authenticated `/iris/api/doctor` JSON. It checks the host version, plugin, 17 tools and three skills, four route groups, host capabilities, client version, and four UI slots. It reads safe registration evidence without calling Browser, models, or providers. See [Host Doctor](docs/HOST_DOCTOR.md).
281
+ A running DSH instance also provides a “Host diagnostics” card and `/iris/api/doctor` JSON protected by Iris's Host and browser-origin guards. These guards do not authenticate users. Doctor checks the host version, plugin, 17 tools and three skills, four route groups, host capabilities, client version, and four UI slots. It reads safe registration evidence without calling Browser, models, or providers. See [Host Doctor](docs/HOST_DOCTOR.md).
289
282
 
290
283
  ## Composed workflow example
291
284
 
package/README.md CHANGED
@@ -44,22 +44,25 @@ dsh-iris 为 Agent、Iris 工作台和独立 CLI 提供图像、视频、音乐
44
44
 
45
45
  项目目前处于早期版本,接口和配置格式仍可能随版本迭代调整。
46
46
 
47
- Iris 0.2.4 同时提供 DSH 插件与无 DSH 的 CLI,共用任务、产物和模型路由,支持图片导入、原生 Qwen 改图及统一功能分配。音乐、三项 Agent Skills 和同步媒体交付恢复继续可用。Core 内部接口尚未冻结为公共 SDK。
47
+ 当前文档对应 **Iris 0.2.6**。安装与升级请固定版本,并先核对下方的宿主兼容范围。
48
48
 
49
- > 版本支持:Iris 0.2.4支持DSH `0.2.0-rc.2` 或 `0.2.1-alpha.4`,Iris 0.2.0–0.2.3仅支持rc.2。Node.js最低22.0.0;宿主若要求更高,以宿主为准。旧DSH固定使用Iris0.1.4,详见 [兼容矩阵](docs/DSH_COMPATIBILITY.md)。
49
+ Iris 0.2.6 同时提供 DSH 插件与无 DSH 的 CLI,共用任务、产物和模型路由。新增连接复用、可选功能自动池、目录同步和能力检测;图片导入、原生 Qwen 改图、音乐、三项 Agent Skills 和同步交付恢复继续可用。Core 内部接口尚未冻结为公共 SDK。
50
50
 
51
- ## 0.2.4 更新重点
51
+ > 版本支持:Iris 0.2.6 沿用 0.2.5 的 12 个准确 DSH 版本,见 [兼容矩阵](docs/DSH_COMPATIBILITY.md)。保留旧 DSH 时仍需 Node.js ≥22.0.0,宿主若要求更高,以宿主为准。连接复用另需宿主提供对应公开接口。
52
52
 
53
- **图片续作、明确的功能模型分配与新版宿主兼容**。
53
+ ## 0.2.6 更新重点与现有能力
54
+
55
+ **选一次连接、确认模型用途,再按功能调用。** 自动池采用稳定顺序和安全切换,没有跨请求轮转。
54
56
 
55
57
  - **图片导入**:通过工作台、Agent或CLI把已有图片保存为持久作品,继续看图、改图和导出;保留源文件,不调用模型。
56
58
  - **原生 Qwen 改图**:除聊天生图外,支持DashScope Qwen带图编辑,修改版另存为关联原图的新作品。
57
- - **统一功能分配**:生图、视频、TTS、Music、转写和视觉只使用各自明确分配的有序名单;临时指定也须已分配。
58
- - **双版本宿主**:兼容DSH rc.2及alpha.4,manifest、客户端peer和Doctor使用相同范围。
59
+ - **连接复用与功能池**:可引用 DSH 已有 API Key 连接;六类功能可选自动池、仅用所选模型或停用,确认用途时可同时启用自动池。
60
+ - **目录与检测**:自动请求前按需同步目录,明确模型不存在后隔离后续候选;能力检测、目录及高级分区默认折叠,实测单独确认费用。
61
+ - **旧宿主与过渡版本**:兼容矩阵中的12个准确版本共用当前功能,manifest、客户端peer和Doctor使用相同范围。
59
62
 
60
- **升级前请检查功能分配**:空名单会停止新调用,不再自动补入模型池;已有任务仍可按原绑定查询和恢复。DSH默认视觉须明确加入视觉名单。详见 [升级说明](docs/FUNCTION_MODEL_ASSIGNMENTS.md)。
63
+ **升级保持已有调用范围**:旧名单和缺失/空分配不会自动启用;需主动选择自动池。新发现模型仍要确认用途,目录未列出不等于下线。DSH 默认视觉需明确加入名单或开启自动池的宿主视觉选项;已有任务按原绑定恢复。详见 [功能模型池](docs/FUNCTION_MODEL_POOLS.md)。
61
64
 
62
- 完整变化见 [0.2.4 发布说明](docs/releases/0.2.4.md) 与 [CHANGELOG](CHANGELOG.md);上一版音乐与Skills见 [0.2.3](docs/releases/0.2.3.md)。
65
+ 升级与验证边界见 [0.2.6 发布说明](docs/releases/0.2.6.md) 和 [CHANGELOG](CHANGELOG.md)。旧宿主支持见 [0.2.5](docs/releases/0.2.5.md),图片续作见 [0.2.4](docs/releases/0.2.4.md),音乐与 Skills 见 [0.2.3](docs/releases/0.2.3.md)。
63
66
 
64
67
  音乐的接口格式、模型分配与使用示例见 [Music](docs/MUSIC.md)。其他协议与后续能力见 [路线图](docs/ROADMAP.md#后续功能方向)。
65
68
 
@@ -71,7 +74,7 @@ Iris 0.2.4 同时提供 DSH 插件与无 DSH 的 CLI,共用任务、产物和
71
74
  | 入口 | 按下文「最快开始」选择固定版本 | `dsh-iris run ...`,见 [Headless CLI](docs/HEADLESS_CLI.md) |
72
75
  | 数据位置 | `$DSH_HOME/iris/v1/`(Core 数据根 `core-v0`) | 显式 `--data-root` 指定的任意绝对路径 |
73
76
  | 自动观察 | 有(DSH Host 有界节拍 + 重启接管) | 显式 `task observe`;0.2.2 另提供有界 `task wait` |
74
- | 依赖 | DSH rc.2或alpha.4、Node.js ≥ 22(满足宿主要求) | 仅 Node.js ≥ 22 与 `sharp`(视频抽帧另需 `ffmpeg`) |
77
+ | 依赖 | 兼容矩阵中的DSH、Node.js ≥22(满足宿主要求) | 仅 Node.js ≥22与`sharp`(视频抽帧另需`ffmpeg`) |
75
78
 
76
79
  两条路径读写同一份 Core Task/Artifact 事实:CLI 指向 DSH profile 的 `core-v0` 数据根即可 inspect/export DSH 生成的作品,反之亦然。同一数据根只允许一个写者。
77
80
 
@@ -79,64 +82,54 @@ Iris 0.2.4 同时提供 DSH 插件与无 DSH 的 CLI,共用任务、产物和
79
82
 
80
83
  ## 可选的旧配置导入
81
84
 
82
- 首次使用时,直接在 Iris 工作台添加供应商。Iris 使用自己的配置,不会默认扫描其他项目。
85
+ 首次使用时,在 Iris 工作台添加供应商或引用 DSH 已有连接。Iris 使用自己的配置,不会默认扫描其他项目。
86
+
87
+ [引用 DSH 已有连接](docs/DSH_PROVIDER_CONNECTIONS.md)只保存连接标识,在操作时读取宿主管理的地址和密钥;无可复用连接时可手动填写供应商信息。
88
+
89
+ [功能自动池、手选与停用](docs/FUNCTION_MODEL_POOLS.md):确认模型用途时可直接启用自动池,免去再次逐项分配。旧名单和空分配保持原行为。
90
+
91
+ 自动池按需同步模型目录(成功缓存 10 分钟),并隔离当前连接已明确返回“模型不存在”的条目。供应商详情默认折叠展示同步结果;失败保留旧目录,新增条目仍待确认用途,手工配置与历史成功保留。
83
92
 
84
93
  已有旧 ai-paint 配置时,可通过 `IRIS_IMPORT_WORKBENCH_CONFIG` 显式指定来源文件的绝对路径,一次性导入供应商;不修改来源文件、不持续同步。该变量保存文件路径,不包含 API Key。具体操作见[用户指南](user_guide.md#从旧工作台显式导入)。
85
94
 
86
95
  ## 最快开始
87
96
 
88
- 先用 `dsh --version` 核对宿主版本,并确认 `pnpm` 在 PATH 中。Iris 版本与 DSH 版本独立,按以下组合选择:
97
+ 先用 `dsh --version` 核对宿主版本,并确认 `pnpm` 在 PATH 中。Iris 与 DSH 的版本号独立;0.2.6 沿用 [兼容矩阵](docs/DSH_COMPATIBILITY.md) 列出的 12 个准确版本。
89
98
 
90
99
  | 你的 DSH | Iris 选择 | 安装来源 |
91
100
  |---|---|---|
92
- | `0.2.0-rc.2` 或 `0.2.1-alpha.4` | `0.2.4` | 固定 npm 版本 |
93
- | `>=0.1.2-rc.1 <0.1.3-0` 或 `0.1.5-rc.1` | 稳定版 `0.1.4` | 固定 npm 版本 |
94
- | 其他版本 | 暂无当前支持声明 | 先核对宿主适配,不能按相邻版本推定兼容 |
95
-
96
- ### 旧 DSH:安装稳定版 0.1.4
97
-
98
- 在上述旧 DSH 范围内,将固定版本加入 Web profile:
99
-
100
- ```bash
101
- dsh plugin --profile web add @mokuyoaxis/dsh-iris@0.1.4
102
- dsh web
103
- ```
104
-
105
- 需要单独下载 npm 发布包时:
106
-
107
- ```bash
108
- npm pack @mokuyoaxis/dsh-iris@0.1.4
109
- ```
101
+ | 矩阵中的0.1.2/0.1.5/0.1.7/0.2线准确版本 | `0.2.6` | 固定 npm 版本 |
102
+ | 未列入矩阵的版本 | 尚未验收 | 按实际宿主接口另行检查 |
110
103
 
111
- 命令会在当前目录生成 `.tgz`。只需安装为普通 npm 依赖时可使用 `npm install @mokuyoaxis/dsh-iris@0.1.4`;这不会自动把插件加入 DSH profile。固定 `@0.1.4` 可在 latest 更新后继续取得旧稳定版本,见 [npm pack 文档](https://docs.npmjs.com/cli/v11/commands/npm-pack/)。0.1.4 不包含 0.2.0 的 Core 媒体 CLI,也不包含 DSH rc.2 的后续适配。
112
-
113
- ### DSH rc.2或alpha.4:安装 0.2.4
104
+ ### DSH插件:安装0.2.6
114
105
 
115
106
  安装固定版本到 Web profile:
116
107
 
117
108
  ```bash
118
- dsh plugin --profile web add @mokuyoaxis/dsh-iris@0.2.4
109
+ dsh plugin --profile web add @mokuyoaxis/dsh-iris@0.2.6
119
110
  dsh web
120
111
  ```
121
112
 
122
113
  插件在下一次 DSH 启动时装载。Web UI 默认位于 `http://127.0.0.1:3080`;启动输出带认证参数时请打开完整 URL。更新后需重新加载后端并刷新客户端。
123
114
 
124
- ### 独立 CLI:安装 0.2.4
115
+ ### 独立CLI:安装0.2.6
125
116
 
126
117
  在自己的项目中安装,无需 DSH:
127
118
 
128
119
  ```bash
129
- npm install @mokuyoaxis/dsh-iris@0.2.4
120
+ npm install @mokuyoaxis/dsh-iris@0.2.6
130
121
  npx dsh-iris --help
131
122
  ```
132
123
 
124
+ 需要单独下载时运行`npm pack @mokuyoaxis/dsh-iris@0.2.6`。仍需保留历史Iris0.1.4时可以固定其版本;历史DSH/Node范围见兼容矩阵,0.1.4不包含当前Core媒体CLI及后续新功能。
125
+
133
126
  ### dsh-market 安装时的版本选择
134
127
 
135
- 市场条目应对应完整包名 `@mokuyoaxis/dsh-iris`。安装前同时核对市场显示的Iris版本与本机 `dsh --version`,按 [兼容矩阵](docs/DSH_COMPATIBILITY.md) 选择;旧宿主使用固定 `@0.1.4`。市场目录与npm信息可能有缓存,以实际包的顶层 `engines.dsh`、Node要求及客户端peer为准;市场中可见不代表任意DSH版本兼容。
128
+ 市场条目应对应完整包名 `@mokuyoaxis/dsh-iris`。安装前同时核对市场显示的Iris版本与本机 `dsh --version`,按 [兼容矩阵](docs/DSH_COMPATIBILITY.md) 选择对应发行版。市场目录与npm信息可能有缓存,以实际包的顶层 `engines.dsh`、Node要求及客户端peer为准;市场中可见不代表任意DSH版本兼容。
136
129
 
137
130
  > npm 上无 scope 的 `dsh-iris` 属于另一款插件。安装和更新 Iris Media 时必须保留完整包名 `@mokuyoaxis/dsh-iris`。
138
131
 
139
- 首次启动后,打开“设置 → Iris 工作台 → + 添加供应商”,填入供应商Base URL和API Key,再点“发现模型”,标注能力并为所需功能分配模型。0.2.4统一严格名单,升级差异见 [功能模型分配](docs/FUNCTION_MODEL_ASSIGNMENTS.md);完整步骤和协议选择见 [用户指南](user_guide.md)。
132
+ 首次启动后,打开“设置 → Iris 工作台 → + 添加供应商”,引用 DSH 连接或手动填写地址与密钥,明确媒体协议,再同步目录并确认模型用途。首次配置可同时启用所选功能的自动池;保留手选模式时需选择模型。完整步骤见 [用户指南](user_guide.md) 和 [功能模型池](docs/FUNCTION_MODEL_POOLS.md)。
140
133
 
141
134
  配置完成后,最小指令可以是:
142
135
 
@@ -176,7 +169,7 @@ DSH 的 profile 与插件命令由[官方安装说明](https://github.com/deepse
176
169
 
177
170
  ## DeepSeek Harness 适配
178
171
 
179
- dsh-iris仍按DSH原生插件装载。0.2.4服务端注册17个Agent工具,包含图片导入、改图与音乐;使用宿主提供的路由、附件、模型和生命周期能力。Web客户端接入设置页、会话输入区与全局悬浮层,不启动额外服务或监听端口。
172
+ dsh-iris仍按DSH原生插件装载。0.2.6服务端注册17个Agent工具,包含图片导入、改图与音乐;使用宿主提供的路由、附件、模型和生命周期能力。Web客户端接入设置页、会话输入区与全局悬浮层,不启动额外服务或监听端口。
180
173
 
181
174
  上传图片或本地图片可保存为持久作品,继续看图、改图及导出,见 [图片导入](docs/IMAGE_IMPORT.md)。
182
175
 
@@ -188,10 +181,12 @@ dsh-iris仍按DSH原生插件装载。0.2.4服务端注册17个Agent工具,包
188
181
  | `0.2.2` | 仅 `0.2.0-rc.2` | 真实安装服务隔离检查覆盖 15 个工具与 31 项边界;完整浏览器/移动端及真实异步重启验收仍待完成 |
189
182
  | `0.2.3` | 仅 `0.2.0-rc.2` | 增加音乐工具和第三项 Skill;升级后用宿主诊断检查实际装载 |
190
183
  | `0.2.4` | `0.2.0-rc.2` 或 `0.2.1-alpha.4` | 17工具/3项Skill;两版实际SDK、加载器与界面插槽隔离验收,完整浏览器/热更新另验 |
184
+ | `0.2.5` | 0.1.2/0.1.5/0.1.7/0.2线的12个准确版本,见兼容矩阵 | 每版官方SDK隔离检查,包含Music与Qwen工具链;旧profile另通过实际安装包装载 |
185
+ | `0.2.6` | 沿用0.2.5的12个准确版本 | 新增连接复用、功能池与目录;连接引用按宿主公开服务检测,具体边界见本版发布说明 |
191
186
 
192
187
  当前声明与验收范围见 [版本兼容](docs/DSH_COMPATIBILITY.md),早期rc.2修正见 [历史适配记录](docs/DSH_RC2_ADAPTATION.md);npm0.1.4不包含这些后续适配。
193
188
 
194
- Iris 0.2.x 不再声明支持旧 DSH;旧版的历史验收不自动覆盖当前版本。DSH `0.2.0` 正式版及其他 rc 同样未列入支持范围。自动化测试分别检查服务端装载、工具与 Skill 注册、路由、客户端 bundle 和 Slot;其中一层失效时,Doctor 应指出具体边界。
189
+ 0.2.5按宿主实际接口能力适配,按已验证的准确版本声明支持。未列出的版本需另行验收。自动化检查分别覆盖服务端装载、工具与Skill注册、路由及客户端Slot;完整浏览器操作与旧数据升级另行验收。Doctor会指出当前可观察到的具体边界。
195
190
 
196
191
  Core 与 DSH Adapter 正在分离,DSH 继续加载同一个 npm 包,Adapter 把宿主能力映射给 Core。若 DSH 修改 API,修复应限制在 Adapter 和客户端桥接;Core 的任务和产物语义不随宿主版本改变。0.2.0 已提供无 DSH CLI;第二个真实 Host Adapter 完成并验收后再移除名称中的 `dsh` 前缀,届时发布新的 npm 包,见[路线图](docs/ROADMAP.md)。
197
192
 
@@ -284,7 +279,7 @@ npx @mokuyoaxis/dsh-iris doctor --json
284
279
 
285
280
  安装后的二进制名是 `dsh-iris`。退出码 `0` 表示正常、`1` 表示有警告、`2` 表示有硬错误。离线 Doctor 检查 Node、sharp、ffmpeg/ffprobe、数据目录真实写入、配置、模型/分配、任务语义、临时文件和孤儿/缺失产物。
286
281
 
287
- 运行中的DSH另在Iris工作台提供“宿主诊断”卡片及已认证的 `/iris/api/doctor` JSON,检查宿主版本、插件、17工具/3项Skill、四组路由、宿主能力、客户端版本和四个UI Slot。它只读取安全快照与注册证据,不调用Browser、模型或Provider,详见 [Host Doctor](docs/HOST_DOCTOR.md)。
282
+ 运行中的 DSH 另在 Iris 工作台提供“宿主诊断”卡片及受 Host/浏览器来源守卫保护的 `/iris/api/doctor` JSON,检查宿主版本、插件、17 工具/3 项 Skill、四组路由、宿主能力、客户端版本和四个 UI Slot。该守卫不提供身份认证。诊断只读取安全快照与注册证据,不调用 Browser、模型或 Provider,详见 [Host Doctor](docs/HOST_DOCTOR.md)。
288
283
 
289
284
  ## 组合工作流示例
290
285
 
package/bin/dsh-iris.js CHANGED
@@ -7,7 +7,7 @@ import { recoverCoreWriterLease } from '../lib/core-lease-recovery.js';
7
7
  import { doctor, formatDoctorReport } from '../lib/doctor.js';
8
8
  import { loadProviderCatalog, providerCatalogSnapshot, catalogCapabilitySnapshot, imageCandidatesFromCatalog, musicCandidatesFromCatalog, providerForTaskFromCatalog, providerTaskBinding, transcribeCandidatesFromCatalog, ttsCandidatesFromCatalog, videoCandidatesFromCatalog } from '../lib/provider-catalog.js';
9
9
  import { createConfiguredProviderAdapter } from '../lib/provider-adapters.js';
10
- import { providerForImageModel } from '../lib/provider-protocol.js';
10
+ import { providerForImageModel, selectMediaProtocol, dashscopeTtsInputIssue } from '../lib/provider-protocol.js';
11
11
  import { prepareProviderInput } from '../lib/provider-adapter.js';
12
12
  import { createProviderTaskRunner } from '../lib/provider-task-runner.js';
13
13
  import { generateMusicTask } from '../lib/music-generation.js';
@@ -15,7 +15,7 @@ import { GenerationInputError, normalizeGenerationInput } from '../lib/generatio
15
15
  import { executeVisionCommand, normalizeVisionInput } from '../lib/headless-vision.js';
16
16
  import { videoTaskCandidates } from '../lib/video-input.js';
17
17
  import { createChromiumBrowser } from '../lib/chromium-browser.js';
18
- import { executeConfigCommand, recordCatalogRateLimit } from '../lib/provider-config-service.js';
18
+ import { executeConfigCommand, recordCatalogRateLimit, recordCatalogAvailability, refreshCatalogDirectories } from '../lib/provider-config-service.js';
19
19
  import { probeVisionModel } from '../lib/vision-model-routing.js';
20
20
  import { RED_TEST_IMAGE } from '../lib/vision.js';
21
21
  import { parseModelRef, modelRef as qualifiedModelRef } from '../lib/models.js';
@@ -24,10 +24,18 @@ import { coreTaskWaitFinished } from '../lib/task-wait.js';
24
24
  function trackedProviderAdapter(provider, options, task) {
25
25
  return createConfiguredProviderAdapter(provider, {
26
26
  modelId: parseModelRef(task?.modelRef)?.modelId,
27
+ onModelAvailability: event => recordCatalogAvailability(options['provider-config'], event),
27
28
  onRateLimit: event => recordCatalogRateLimit(options['provider-config'], event)
28
29
  });
29
30
  }
30
31
 
32
+ async function generationCatalog(options, capability, modelRef) {
33
+ const file = required(options['provider-config'], 'provider-config');
34
+ const catalog = loadProviderCatalog(file);
35
+ if (!modelRef) await refreshCatalogDirectories(file, catalog, capability, { signal: cliAbortController.signal });
36
+ return catalog;
37
+ }
38
+
31
39
  class CliUsageError extends Error {
32
40
  constructor(message) {
33
41
  super(message);
@@ -258,6 +266,10 @@ async function main(args) {
258
266
  if (['video-gen', 'transcribe'].includes(capability) && !options.input) return {
259
267
  skipped: true, ok: false, reason: '请用 models test --input 提供与 run video/transcribe 相同的真实素材;未发起请求'
260
268
  };
269
+ if (capability === 'tts' && selectMediaProtocol(provider).mediaProtocol === 'dashscope') {
270
+ const issue = dashscopeTtsInputIssue(modelId, probeInput.voice || provider.ttsVoice);
271
+ if (issue) return { skipped: true, ok: false, reason: issue };
272
+ }
261
273
  return withRawRuntime('writer', options['data-root'], async runtime => {
262
274
  const mediaCapability = capability === 'image-gen' ? 'image' : capability === 'video-gen' ? 'video' : capability;
263
275
  if (mediaCapability === 'image') provider = providerForImageModel(provider, modelId);
@@ -266,7 +278,7 @@ async function main(args) {
266
278
  ? { prompt: 'red circle', n: 1, ...(['openai-chat-images', 'openai-responses-images'].includes(adapter.protocol) ? {} : {
267
279
  size: adapter.protocol === 'openai-images' ? '256x256' : '512*512'
268
280
  }) }
269
- : { text: '你好', voice: provider.ttsVoice || 'Cherry' };
281
+ : { text: '你好', voice: probeInput.voice || provider.ttsVoice || 'Cherry' };
270
282
  let candidates = [{ adapter, model: qualifiedModelRef(provider.id, modelId), selectionReason: 'explicit', providerBinding: providerTaskBinding(provider) }];
271
283
  if (['video', 'transcribe'].includes(mediaCapability)) {
272
284
  const normalized = generationInput(mediaCapability, { ...probeInput, model_ref: qualifiedModelRef(provider.id, modelId) },
@@ -284,7 +296,7 @@ async function main(args) {
284
296
  task_id: submitted.task.id, timeout_ms: 60000, poll_interval_ms: 1000 });
285
297
  const task = waited.task;
286
298
  return { ok: task.outcome === 'succeeded' && task.deliveryState === 'ready', taskId: task.id,
287
- category: task.lastError?.category, httpStatus: task.lastError?.httpStatus };
299
+ category: task.lastError?.category, httpStatus: task.lastError?.httpStatus, providerCode: task.lastError?.providerCode };
288
300
  });
289
301
  }
290
302
  });
@@ -307,9 +319,11 @@ async function main(args) {
307
319
  fs.accessSync(path.dirname(file), fs.constants.W_OK);
308
320
  } catch (_) { throw new CliUsageError('输出文件已存在或父目录不可写'); }
309
321
  }
310
- const catalog = loadProviderCatalog(required(options['provider-config'], 'provider-config'));
322
+ const catalog = await generationCatalog(options, 'vision', options['model-ref'] || input.model_ref);
323
+ if (input.transcribe && !input.transcribe_model_ref) await refreshCatalogDirectories(options['provider-config'], catalog, 'transcribe', { signal: cliAbortController.signal });
311
324
  const execute = runtime => executeVisionCommand({ command, input, catalog, runtime,
312
325
  onRateLimit: event => recordCatalogRateLimit(options['provider-config'], event),
326
+ onModelAvailability: event => recordCatalogAvailability(options['provider-config'], event),
313
327
  modelRef: options['model-ref'] || '', signal: cliAbortController.signal,
314
328
  ...(options['timeout-ms'] !== undefined ? { timeoutMs: Number(options['timeout-ms']) } : {}) });
315
329
  const completed = input.transcribe
@@ -362,7 +376,7 @@ async function main(args) {
362
376
  if (args[0] === 'run' && args[1] === 'image') {
363
377
  const options = flags(args.slice(2), ['data-root', 'provider-config', 'input']);
364
378
  const { providerInput, modelRef, sourceArtifactId } = generationInput('image', jsonInput(options.input));
365
- const catalog = loadProviderCatalog(required(options['provider-config'], 'provider-config'));
379
+ const catalog = await generationCatalog(options, 'image-gen', modelRef);
366
380
  const routes = imageCandidatesFromCatalog(catalog, modelRef);
367
381
  await withRawRuntime('writer', options['data-root'], async (runtime) => {
368
382
  const candidates = routes.map((route) => ({
@@ -384,7 +398,7 @@ async function main(args) {
384
398
  const options = flags(args.slice(2), ['data-root', 'provider-config', 'input']);
385
399
  const normalized = generationInput('video', jsonInput(options.input), { allowVideoPaths: true });
386
400
  const { providerInput, modelRef } = normalized;
387
- const catalog = loadProviderCatalog(required(options['provider-config'], 'provider-config'));
401
+ const catalog = await generationCatalog(options, 'video-gen', modelRef);
388
402
  const routes = videoCandidatesFromCatalog(catalog, modelRef);
389
403
  await withRawRuntime('writer', options['data-root'], async (runtime) => {
390
404
  const candidates = videoTaskCandidates(routes.map((route) => ({
@@ -405,7 +419,7 @@ async function main(args) {
405
419
  if (args[0] === 'run' && args[1] === 'music') {
406
420
  const options = flags(args.slice(2), ['data-root', 'provider-config', 'input']);
407
421
  const normalized = generationInput('music', jsonInput(options.input));
408
- const catalog = loadProviderCatalog(required(options['provider-config'], 'provider-config'));
422
+ const catalog = await generationCatalog(options, 'music-gen', normalized.modelRef);
409
423
  const routes = musicCandidatesFromCatalog(catalog, normalized.modelRef);
410
424
  let result;
411
425
  await withRawRuntime('writer', options['data-root'], async runtime => {
@@ -421,7 +435,7 @@ async function main(args) {
421
435
  if (args[0] === 'run' && args[1] === 'tts') {
422
436
  const options = flags(args.slice(2), ['data-root', 'provider-config', 'input']);
423
437
  const { providerInput, modelRef } = generationInput('tts', jsonInput(options.input));
424
- const catalog = loadProviderCatalog(required(options['provider-config'], 'provider-config'));
438
+ const catalog = await generationCatalog(options, 'tts', modelRef);
425
439
  const routes = ttsCandidatesFromCatalog(catalog, modelRef);
426
440
  await withRawRuntime('writer', options['data-root'], async (runtime) => {
427
441
  const candidates = routes.map((route) => ({
@@ -443,7 +457,7 @@ async function main(args) {
443
457
  if (args[0] === 'run' && args[1] === 'transcribe') {
444
458
  const options = flags(args.slice(2), ['data-root', 'provider-config', 'input']);
445
459
  const normalized = generationInput('transcribe', jsonInput(options.input), { allowAudioPath: true });
446
- const catalog = loadProviderCatalog(required(options['provider-config'], 'provider-config'));
460
+ const catalog = await generationCatalog(options, 'transcribe', normalized.modelRef);
447
461
  const routes = transcribeCandidatesFromCatalog(catalog, normalized.modelRef);
448
462
  let providerInput = normalized.providerInput;
449
463
  if (normalized.audioPath) {
@@ -528,7 +542,9 @@ async function main(args) {
528
542
  model_ref: options['model-ref'],
529
543
  confirm_billing: confirmBilling
530
544
  }), {
531
- resolveTaskCandidates: ({ capability, modelRef }) => (capability === 'video'
545
+ resolveTaskCandidates: async ({ capability, modelRef }) => {
546
+ const catalog = await generationCatalog(options, { image: 'image-gen', video: 'video-gen', music: 'music-gen' }[capability] || capability, modelRef);
547
+ return (capability === 'video'
532
548
  ? videoCandidatesFromCatalog(catalog, modelRef || undefined)
533
549
  : capability === 'tts'
534
550
  ? ttsCandidatesFromCatalog(catalog, modelRef || undefined)
@@ -542,7 +558,8 @@ async function main(args) {
542
558
  model: route.modelRef,
543
559
  selectionReason: route.selectionReason,
544
560
  providerBinding: providerTaskBinding(route.provider)
545
- }))
561
+ }));
562
+ }
546
563
  });
547
564
  console.log(JSON.stringify(result, null, 2));
548
565
  return 0;