dsh-tool-vision 0.9.0 → 0.9.2

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 CHANGED
@@ -1,23 +1,23 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Scorp1o117
4
- Bridge image preview contributed by xing666173 (dsh-bridge-preview),
5
- Copyright (c) 2026 xing666173
6
-
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to deal
9
- in the Software without restriction, including without limitation the rights
10
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in all
15
- copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scorp1o117
4
+ Bridge image preview contributed by xing666173 (dsh-bridge-preview),
5
+ Copyright (c) 2026 xing666173
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md CHANGED
@@ -42,6 +42,14 @@ bridge keeps its conversion inside that durable path:
42
42
  key lives in `settings.yaml`, not the profile patch. Mount by package name
43
43
  (`name: 'dsh-tool-vision'`) so the web client bundle is discovered.
44
44
 
45
+ ## Compatibility (v0.9.1)
46
+
47
+ Verified in a DSH `0.1.5-rc.3` (`next`) disposable Web profile; DSH
48
+ `0.1.5-rc.2` remains `latest`. The rc.3 host currently references an
49
+ unpublished `dsh-client-ui-sidebar-documentpreview@0.1.5-rc.3`, so the smoke
50
+ profile temporarily used that unrelated UI package at rc.2. A clean rc.3
51
+ installation is blocked upstream. Alpha releases remain `unknown`.
52
+
45
53
  ## Install
46
54
 
47
55
  Mount in a profile patch (`$DSH_HOME/profiles/<name>/cordis.patch.yml`):
@@ -374,6 +382,56 @@ the panel's picker carries a badge:
374
382
  > A route on an unknown protocol (e.g. `openai-responses`) returns `unknown`
375
383
  > with a reason, rather than guessing confidently with `chat/completions`.
376
384
 
385
+ ## v0.9.2: admission is not dispatch
386
+
387
+ **The bug.** Every capability signal this plugin collects — `probeResults`,
388
+ `multimodalModels`, `autoDetectMultimodal` — decided whether the *bridge*
389
+ intercepts an image. None of them decided whether the model *receives* it.
390
+
391
+ `LlmService.generate` resolves modalities from the adapter, not from the plugin:
392
+
393
+ ```js
394
+ const adapterCall = await adapter.prepareCall(provider, model, signal);
395
+ modelInfo = this.normalizeModelInfo(registration, model, adapterCall.model);
396
+ if (modelInfo.inputModalities !== undefined
397
+ && !modelInfo.inputModalities.includes("image")
398
+ && projectedMessages.some((message) => contentHasImage(message.content)))
399
+ projectedMessages = projectImagesForTextModel(projectedMessages);
400
+ ```
401
+
402
+ `projectImagesForTextModel` rewrites every image block into
403
+ `[image omitted because this model accepts text only; attachment sha256:…]`
404
+ **before the adapter is called**. So on a route the plugin had measured as
405
+ image-capable — where the bridge therefore stepped aside and let the image
406
+ through — the image was still destroyed, by a check that reads the adapter's
407
+ declaration and nothing else. The `resolveModelInfo` wrap (`bridgeAutoImage`) is
408
+ *admission*: it decides who may offer an image, and it never changes what the
409
+ adapter streams. Nothing in the plugin reached the layer that does.
410
+
411
+ The symptom is a route that probes `yes`, is listed in `multimodalModels`, and
412
+ still answers `[image omitted …]`.
413
+
414
+ **The fix.** `installDispatchImageAdmission` wraps `llm.registration` — the
415
+ accessor the core itself calls — so every adapter, including one registered
416
+ later, answers `prepareCall` through the same `routeDirectDecision` the bridge
417
+ uses. One precedence rule, two seams, so the two can never disagree about a
418
+ route. When the decision is "bridge", nothing changes: the bridge already turned
419
+ the image into an `inspect_image` hint, and the core's projection stays as the
420
+ correct fallback for any image that still reaches dispatch.
421
+
422
+ Three properties worth stating, because each one is a test:
423
+
424
+ - **Fail closed.** A decision that cannot be made (a throwing config) leaves the
425
+ call untouched, rather than sending pixels a route may reject.
426
+ - **Reversible.** Dispose restores every adapter it patched *and* the accessor
427
+ itself; a re-install after dispose wraps again.
428
+ - **Late providers count.** The wrap is on the accessor rather than on a snapshot
429
+ of adapters, so a provider registered after install is covered too.
430
+
431
+ `routeDirectDecision` is now the single implementation of the precedence rule,
432
+ shared by the bridge and the dispatch path — two copies of it would drift, and
433
+ this one has three inputs.
434
+
377
435
  ## v0.8.0: master switch, and the save-path fix
378
436
 
379
437
  **Master switch.** `enabled`, plus a one-click button at the top of the section