dsh-vision-router 2.0.0 → 2.1.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 +33 -16
- package/README.zh.md +34 -17
- package/cordis.patch.yml +19 -9
- package/docs/architecture/2x-contract-ledger.md +165 -0
- package/docs/architecture/compat-inventory.md +121 -0
- package/docs/architecture/dsh-compatibility-matrix.md +57 -0
- package/docs/architecture/dsh-support-window.md +50 -0
- package/docs/architecture/final-closure-audit.md +148 -0
- package/docs/architecture/p2-jobs-feasibility.md +94 -0
- package/docs/architecture/p3-compat-retirement.md +46 -0
- package/docs/architecture/p3-host-native-seams.md +43 -0
- package/docs/architecture/p3-native-recovery-evaluation.md +65 -0
- package/docs/architecture/runtime-boundaries.md +124 -0
- package/docs/releases/v2.0.1.md +17 -0
- package/docs/releases/v2.1.0-support-window.md +29 -0
- package/docs/releases/v2.1.0.md +83 -0
- package/entry.js +13 -307
- package/index.js +85 -352
- package/lib/abort-signal-compat.js +191 -0
- package/lib/adapter-update-coalescer.js +113 -29
- package/lib/adversarial-hardening.js +24 -9
- package/lib/artifact-boundary.js +16 -175
- package/lib/artifact-io.js +220 -0
- package/lib/artifact-retention.js +305 -53
- package/lib/catalog-corrections.js +6 -1
- package/lib/client-host-compat-prelude.js +249 -0
- package/lib/client-presentation-boundary.js +61 -3
- package/lib/client.js +71 -72
- package/lib/core-vision-surface.js +124 -0
- package/lib/depth-guidance.js +114 -90
- package/lib/doctor-cli-p0.js +168 -0
- package/lib/doctor-cli.js +7 -0
- package/lib/doctor-vision-limits.js +72 -0
- package/lib/dsh-contract-compat.js +207 -39
- package/lib/dsh-host-capabilities.js +107 -0
- package/lib/dsh-support-window.js +48 -0
- package/lib/http-compat.js +22 -6
- package/lib/image-resource-governor.js +35 -10
- package/lib/legacy-core-vision-policy-bridge.js +25 -226
- package/lib/legacy-global-proxy-boundary.js +127 -0
- package/lib/live-model-client-prelude.js +0 -12
- package/lib/mixed-router.js +81 -81
- package/lib/public-entry.js +42 -4
- package/lib/runtime-composition.js +348 -0
- package/lib/runtime-i18n-boundary.js +683 -0
- package/lib/runtime-i18n-core-scope.js +56 -0
- package/lib/runtime-i18n-core.js +34 -0
- package/lib/runtime-i18n.js +121 -0
- package/lib/session-surface-policy.js +97 -0
- package/lib/session-vision-index.js +282 -0
- package/lib/session-vision-runtime.js +48 -0
- package/lib/settings-factory-lifecycle.js +144 -0
- package/lib/settings-ia-client-prelude.js +74 -2
- package/lib/settings-limit-client-prelude.js +110 -0
- package/lib/settings-native-card-layout.js +297 -0
- package/lib/settings-number-contract.js +29 -0
- package/lib/structured-flow-hardening.js +207 -76
- package/lib/tesseract-exec-compat.js +58 -32
- package/lib/update-check.js +17 -5
- package/lib/v2-settings-ia-integration.js +9 -4
- package/lib/vision-artifact-store.js +77 -0
- package/lib/vision-backend-runtime-policy.js +6 -2
- package/lib/vision-background-benchmark.js +130 -41
- package/lib/vision-background-failure-policy.js +70 -0
- package/lib/vision-background-stop-store.js +54 -9
- package/lib/vision-capability-benchmark-client.js +57 -66
- package/lib/vision-capability-benchmark-presentation.js +97 -0
- package/lib/vision-capability-benchmark-service.js +3 -3
- package/lib/vision-execution-order-apply.js +61 -0
- package/lib/vision-execution-order-plan.js +64 -0
- package/lib/vision-execution-order.js +38 -0
- package/lib/vision-limit-diagnostics.js +202 -0
- package/lib/vision-product-presentation.js +284 -0
- package/lib/vision-provider-transport.js +197 -0
- package/lib/vision-resilience.js +87 -45
- package/lib/vision-routing-evidence.js +366 -0
- package/lib/vision-routing-runtime.js +278 -0
- package/lib/vision-tool-runtime-boundary.js +27 -21
- package/lib/vision-turn-budget-client-prelude.js +9 -9
- package/lib/web/benchmark-panel.js +6 -0
- package/lib/web/diagnostics-panel.js +44 -0
- package/lib/web/index.js +60 -0
- package/lib/web/model-picker.js +22 -0
- package/lib/web/onboarding.js +6 -0
- package/lib/web/product-state.js +59 -0
- package/lib/web/remote-settings-client.js +8 -0
- package/lib/web/routing-section.js +6 -0
- package/lib/web/settings-controller.js +6 -0
- package/lib/web-capability-boundary.js +65 -9
- package/lib/windows-screenshot-dpi-compat.js +148 -0
- package/package.json +14 -6
- package/lib/vision-capability-shadow.js +0 -576
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# v2.0.1
|
|
2
|
+
|
|
3
|
+
这是一个针对长任务识图设置与诊断的补丁版本。
|
|
4
|
+
|
|
5
|
+
## 修复
|
|
6
|
+
|
|
7
|
+
- 修复 `visionTaskTimeoutMs` 在浏览器设置页与 Host schema 之间的校验漂移:客户端现在会在写入前正确检查范围和步进,避免 Host 拒绝后只留下 `readback-mismatch`。
|
|
8
|
+
- 明确区分“单次识图任务超时”和“首次识图后的整轮时间上限”;整轮限制继续沿用既有 wall-clock 语义。
|
|
9
|
+
- 保持 v2 默认 `visionTurnBudgetMs=0`(不限制);不会自动迁移或清除用户已有的显式正数配置。
|
|
10
|
+
- 当整轮视觉时间上限耗尽时,guard 与日志会显示实际生效的限制;Diagnostics 与 Doctor 也会显示有效值及其来源,便于定位旧 profile / composition 覆盖。
|
|
11
|
+
- 增加针对设置边界、预算诊断、Doctor 输出和运行时结构不变量的回归测试。
|
|
12
|
+
|
|
13
|
+
## Compatibility
|
|
14
|
+
|
|
15
|
+
- No change to #220/#295 lazy activation or wall-clock accounting.
|
|
16
|
+
- No change to the v2 default: `visionTurnBudgetMs=0` remains unlimited.
|
|
17
|
+
- Existing explicit positive whole-turn limits remain honored.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# DVR 2.1.0 Host support-window announcement
|
|
2
|
+
|
|
3
|
+
This file is the historical advance notice published during the DVR 2.0.x train. The announced boundary is fulfilled by DVR 2.1.0. The current normative window is maintained in [`docs/architecture/dsh-support-window.md`](../architecture/dsh-support-window.md).
|
|
4
|
+
|
|
5
|
+
## 中文
|
|
6
|
+
|
|
7
|
+
DVR 2.0.x 的公开最低 Host 是 DSH `0.1.0-rc.6`。项目曾提前公告:从 **DVR 2.1.0** 起,最低支持 Host 调整为 DSH `0.1.0-rc.8`。
|
|
8
|
+
|
|
9
|
+
该边界现已在 v2.1.0 发版线正式激活:
|
|
10
|
+
|
|
11
|
+
- Minimum Supported Host:`0.1.0-rc.8`
|
|
12
|
+
- Previous Supported Train:`0.1.1-rc.1`
|
|
13
|
+
- Current Supported Train:`0.1.1-rc.2`
|
|
14
|
+
- `0.1.2-alpha.4`:当前 canary / upstream compatibility evidence,不视为正式支持基线
|
|
15
|
+
|
|
16
|
+
仍在 rc.6 / rc.7 的用户应先升级 DSH,再升级 DVR 2.1.x。兼容代码的删除仍需独立能力证明,不会因为提高公开支持下限而自动发生。
|
|
17
|
+
|
|
18
|
+
## English
|
|
19
|
+
|
|
20
|
+
DVR 2.0.x publicly supported DSH `0.1.0-rc.6` as its minimum Host. The project announced in advance that **DVR 2.1.0** would raise the minimum to DSH `0.1.0-rc.8`.
|
|
21
|
+
|
|
22
|
+
That boundary is now active on the v2.1.0 release line:
|
|
23
|
+
|
|
24
|
+
- Minimum Supported Host: `0.1.0-rc.8`
|
|
25
|
+
- Previous Supported Train: `0.1.1-rc.1`
|
|
26
|
+
- Current Supported Train: `0.1.1-rc.2`
|
|
27
|
+
- `0.1.2-alpha.4`: current canary/upstream compatibility evidence, not a released support-floor claim
|
|
28
|
+
|
|
29
|
+
Users still on rc.6 / rc.7 should upgrade DSH before upgrading to DVR 2.1.x. Raising the public floor does not automatically delete historical compatibility seams; each retirement still requires separate capability proof.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# v2.1.0
|
|
2
|
+
|
|
3
|
+
这是从 v2.0.1 到当前 2.1 线的一次完整 minor release:把输入框识图、Settings 原生化、运行时双语、能力路由与测评、DSH 新 Host 兼容、资源与取消治理,以及 2.x 架构收敛一起正式交付。
|
|
4
|
+
|
|
5
|
+
## 升级前先看
|
|
6
|
+
|
|
7
|
+
**DVR 2.1.x 的最低支持 Host 提升为 DSH `0.1.0-rc.8`。**
|
|
8
|
+
|
|
9
|
+
- DVR 2.0.x 最低支持:DSH `0.1.0-rc.6`
|
|
10
|
+
- DVR 2.1.x 最低支持:DSH `0.1.0-rc.8`
|
|
11
|
+
- Previous Supported Train:DSH `0.1.1-rc.1`
|
|
12
|
+
- Current Supported Train:DSH `0.1.1-rc.2`
|
|
13
|
+
- DSH `0.1.2-alpha.4` 只作为当前 canary / upstream compatibility evidence
|
|
14
|
+
|
|
15
|
+
仍在 rc.6 / rc.7 的用户请先升级 DSH,再升级到 DVR 2.1.x。这个最低 Host 调整已在 2.0.x 阶段提前公告;2.1.0 只激活既定边界。rc.6 时代的兼容代码不会因此一次性删除,后续仍按 capability-first + 单独退休审计逐项收敛。
|
|
16
|
+
|
|
17
|
+
## 输入框识图模式
|
|
18
|
+
|
|
19
|
+
- 新增显式 Composer「识图 / Vision」开关:普通模型继续由 DSH 原生模型选择器管理,需要看图时再进入对应的内部 Vision Router wrapper。
|
|
20
|
+
- 开关状态直接来自会话真实 ModelDirectory,不维护第二份布尔状态;发送后不会自动复位,手动切换普通模型会退出 wrapper,只修改 reasoning effort 不会退出。
|
|
21
|
+
- 能确认归属时,内部「+ 自动识图」wrapper 从原生 picker 与 `/model` 展示层隐藏;归属不确定时 fail-open,不误藏第三方 route。
|
|
22
|
+
- Host 拒绝模型切换时使用临时错误提示,同时保持 UI 与真实当前模型一致。
|
|
23
|
+
- `👁` 与文本 `✓` 已替换为固定尺寸、`currentColor` 的内联 SVG,Windows / macOS / Linux 不再受系统 emoji / 字体 fallback 影响。
|
|
24
|
+
|
|
25
|
+
## Settings 与新手引导
|
|
26
|
+
|
|
27
|
+
- **Settings → Vision Router** 成为唯一正式入口,不再恢复旧 `settings.plugin.item` 隐藏入口。
|
|
28
|
+
- 设置页重构为 5 张 DSH 风格披露卡:常规、识图策略、本地与设备、高级、诊断。
|
|
29
|
+
- 五张卡默认全部折叠,可独立同时展开;卡体和模型数据按需懒加载,减少设置页无关工作和滚动卡顿。
|
|
30
|
+
- 每张可编辑卡拥有独立保存 / 放弃 / 校验边界;无效 staged draft 也会正确计入 dirty,跨卡保存不会吞掉其他未保存修改。
|
|
31
|
+
- Reset、保存 settlement、并发切卡等路径增加竞态保护。
|
|
32
|
+
- 「重新查看新手引导」恢复;最终完成 callout 与 onboarding 持久化恢复,新装用户不再卡死在 step2。
|
|
33
|
+
- capability benchmark 客户端改为观察稳定的 `document`,即使 DSH 启动过程替换完整 `documentElement`,后续懒挂载模型链仍会自动出现测评控件;没有永久 1 秒 DOM 轮询。
|
|
34
|
+
|
|
35
|
+
## 识图策略、深度与双语
|
|
36
|
+
|
|
37
|
+
- 运行时 i18n 进入正式路径:设置、引导、深度策略、fallback guidance 等用户可见内容跟随 Host locale,中文 / 英文可切换。
|
|
38
|
+
- Fast / Standard / Deep 明确为识图策略;深看最大调用次数作为独立 opt-in cap,不再把“策略”和“次数限制”混成同一个概念。
|
|
39
|
+
- 1+x structured vision、自由后续工具调用和自定义 guidance 继续可组合使用,并补齐异常/取消/重复执行保护。
|
|
40
|
+
|
|
41
|
+
## Auto 路由与模型测评
|
|
42
|
+
|
|
43
|
+
- capability shadow 退役,路由运行时、证据、展示与 benchmark 生命周期进一步拆分,减少双重状态源。
|
|
44
|
+
- Auto 只在已经授权的候选与已有能力证据之间调整顺序;开启 Auto 本身不会启动 benchmark。
|
|
45
|
+
- 后台能力补测继续独立授权,前台真实识图优先;失败、暂缓、停止和凭据域都显式化。
|
|
46
|
+
- benchmark 控件对 DSH Web shell 生命周期自愈,且保持事件驱动,无长期全局 DOM sweep。
|
|
47
|
+
|
|
48
|
+
## Runtime / 2.x 架构收敛
|
|
49
|
+
|
|
50
|
+
- 路由 runtime / evidence、execution order、provider transport、session vision index 等从历史大模块中拆出,行为通过 parity/closure gate 固定。
|
|
51
|
+
- artifact I/O 与 vision artifact store 收敛,Host canonical attachment 继续是图像事实来源。
|
|
52
|
+
- fetch 代理可撤销、断路器失败寿命显式化、扫描/队列有界化;AbortSignal、硬超时与取消语义在新 Host 上继续保持。
|
|
53
|
+
- capability shadow 等过时中间层删除,最终 runtime composition、public entry 与 Web presentation ownership 有专门架构闭包测试。
|
|
54
|
+
|
|
55
|
+
## DSH / 平台兼容
|
|
56
|
+
|
|
57
|
+
- 2.1.x 正式最低 Host:DSH `0.1.0-rc.8`;当前 release train 为 `0.1.1-rc.2`。
|
|
58
|
+
- DSH `0.1.2-alpha.4` 使用官方 tag `dsh-v0.1.2-alpha.4` 的精确源码提交做 canary contract;Settings 生命周期、附件归一化、client/adapter seam 等均纳入验证,但 alpha 不作为正式最低支持声明。
|
|
59
|
+
- Host capability snapshot 与 Doctor support-window 输出进入正式诊断路径。
|
|
60
|
+
- Windows 混合 DPI 桌面截图路径加固。
|
|
61
|
+
- 原生多模态模型继续遵循 non-intervention:Host 已能原生处理图片时,Vision Router 不强行劫持原生路径。
|
|
62
|
+
|
|
63
|
+
## 验证
|
|
64
|
+
|
|
65
|
+
本版本周期已经覆盖:
|
|
66
|
+
|
|
67
|
+
- Node 22 / Node 24 全量测试;
|
|
68
|
+
- DSH rc.8 最低支持线、0.1.1 released trains 与 0.1.2-alpha.4 canary contract;
|
|
69
|
+
- Ubuntu / macOS / Windows host/runtime lanes;
|
|
70
|
+
- Architecture Closure、P1 Routing Parity、DSH Contract;
|
|
71
|
+
- Native multimodal cold resume;
|
|
72
|
+
- 大图资源压力与取消/超时回归;
|
|
73
|
+
- 真实 Chrome Browser P1 acceptance:DSH shell root replacement 后 benchmark 自愈,以及新手引导完成状态持久化;
|
|
74
|
+
- 版本级真实 DSH 自验收:Settings 五卡、1+x、fallback、视觉工具、大图/多图、本地服务降级、Doctor/product-state、重启冷恢复等。
|
|
75
|
+
|
|
76
|
+
## 已知限制
|
|
77
|
+
|
|
78
|
+
以下两项在发版验收中确认存在,但不是 v2.1.0 引入的回归,因此不阻塞本次发布:
|
|
79
|
+
|
|
80
|
+
- [#360](https://github.com/ysr666/dsh-vision-router/issues/360):部分视觉后端在非方形图片上返回内部方形坐标帧,`vision_ground` / `vision_detect` 需要增加确定性坐标回映射;方形图片不受该问题影响。
|
|
81
|
+
- [#361](https://github.com/ysr666/dsh-vision-router/issues/361):Doctor 可能把合法 route/id override 误判成 duplicate mount;运行时实际仍可能只有一个有效实例。
|
|
82
|
+
|
|
83
|
+
这两项将作为 2.1.x 后续专项处理。
|
package/entry.js
CHANGED
|
@@ -1,68 +1,11 @@
|
|
|
1
1
|
// Public plugin entrypoint.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// that changing the tool schema mid-session can invalidate provider prefix/KV
|
|
6
|
-
// caches for very long conversations, so progressive exposure is now an
|
|
7
|
-
// explicit opt-in rather than the implicit fallback.
|
|
3
|
+
// P3-F keeps this file as the public schema/export boundary. Runtime ownership
|
|
4
|
+
// lives in lib/runtime-composition.js; the mature core remains in index.js.
|
|
8
5
|
|
|
9
6
|
import z from '@deepseek-ai/schemastery'
|
|
10
7
|
import * as core from './index.js'
|
|
11
|
-
import {
|
|
12
|
-
import { contextWithDelegatedReplay } from './lib/replay-delegation.js'
|
|
13
|
-
import { contextWithReplayEnvelopeV2Compat } from './lib/replay-envelope-v2-compat.js'
|
|
14
|
-
import { contextWithVisionExecutionPolicy } from './lib/vision-execution-policy.js'
|
|
15
|
-
import { contextWithVisionBackendRuntimePolicy } from './lib/vision-backend-runtime-policy.js'
|
|
16
|
-
import { contextWithNativeImageCoexistence } from './lib/native-image-coexistence.js'
|
|
17
|
-
import { installLegacyCoreVisionPolicyBridge } from './lib/legacy-core-vision-policy-bridge.js'
|
|
18
|
-
import { installPiAiBridgeWireCompat } from './lib/pi-ai-bridge-wire-compat.js'
|
|
19
|
-
import { installLiveModelDiscovery } from './lib/live-model-discovery.js'
|
|
20
|
-
import { installVisionModelRegistry } from './lib/vision-model-registry.js'
|
|
21
|
-
import { installStrictLiveModelClientPrelude } from './lib/strict-live-model-client-prelude.js'
|
|
22
|
-
import { installWrapperScopeClientPrelude } from './lib/wrapper-scope-client-prelude.js'
|
|
23
|
-
import { installClientPresentationBoundary } from './lib/client-presentation-boundary.js'
|
|
24
|
-
import { installGuideVisionToggleHighlight } from './lib/guide-vision-toggle-highlight.js'
|
|
25
|
-
import { installVisionModelVisibilityBoundary } from './lib/vision-model-visibility-boundary.js'
|
|
26
|
-
import { installAdversarialHardening } from './lib/adversarial-hardening.js'
|
|
27
|
-
import { installOllamaColdStartGuard } from './lib/ollama-cold-start.js'
|
|
28
|
-
import { installLocalVisionStabilizer } from './lib/local-vision-stabilizer.js'
|
|
29
|
-
import { installWrapperDirectoryAlias } from './lib/wrapper-directory.js'
|
|
30
|
-
import { installAndroidAttachmentCompat } from './lib/android-attachment-compat.js'
|
|
31
|
-
import { contextWithCoalescedAdapterUpdates } from './lib/adapter-update-coalescer.js'
|
|
32
|
-
import { installTesseractExecFileCompat } from './lib/tesseract-exec-compat.js'
|
|
33
|
-
import { installLocalMutationRouteBoundary } from './lib/web-capability-boundary.js'
|
|
34
|
-
import { installScreenshotSourceBoundary } from './lib/screenshot-source-boundary.js'
|
|
35
|
-
import { installVisionToolRuntimeBoundary } from './lib/vision-tool-runtime-boundary.js'
|
|
36
|
-
import { installVisionRouterRemoteSettingsBridge } from './lib/remote-settings-bridge.js'
|
|
37
|
-
import { installSettingsRc8ClientLifecycle } from './lib/settings-client-rc8-lifecycle.js'
|
|
38
|
-
import { installCapabilityShadowRuntime } from './lib/vision-capability-shadow.js'
|
|
39
|
-
import { createCapabilityProfileStore } from './lib/vision-capability-probe.js'
|
|
40
|
-
import { installCapabilityBenchmarkService } from './lib/vision-capability-benchmark-service.js'
|
|
41
|
-
import { installCapabilityBenchmarkClient } from './lib/vision-capability-benchmark-client.js'
|
|
42
|
-
import { installVisionRoutingSettingsPrelude } from './lib/vision-routing-settings-prelude.js'
|
|
43
|
-
import { resolveVisionRoutingProduct } from './lib/vision-routing-product.js'
|
|
44
|
-
import {
|
|
45
|
-
normalizeBackgroundMeasurementAuthority,
|
|
46
|
-
resolveVisionRoutingAuthority,
|
|
47
|
-
} from './lib/vision-routing-authority.js'
|
|
48
|
-
import { withVisionCircuitBreakerObserver } from './lib/vision-breaker-observer.js'
|
|
49
|
-
import { createVisionBreakerShadowHealth } from './lib/vision-breaker-shadow-health.js'
|
|
50
|
-
import { installBackgroundCapabilityProfiling } from './lib/vision-background-benchmark.js'
|
|
51
|
-
import {
|
|
52
|
-
contextWithVisionRuntimePerformance,
|
|
53
|
-
createVisionRuntimePerformanceStore,
|
|
54
|
-
} from './lib/vision-runtime-performance.js'
|
|
55
|
-
import {
|
|
56
|
-
installStructuredFlowHardening,
|
|
57
|
-
normalizeGuidanceOverrides,
|
|
58
|
-
} from './lib/structured-flow-hardening.js'
|
|
59
|
-
import {
|
|
60
|
-
attachmentContextForContract,
|
|
61
|
-
hasBatchAttachmentContract,
|
|
62
|
-
installHostSettingsCompatibility,
|
|
63
|
-
installVisionAttachmentAdmissionPolicy,
|
|
64
|
-
protectHostProviderOwnership,
|
|
65
|
-
} from './lib/dsh-contract-compat.js'
|
|
8
|
+
import { applyVisionRuntimeComposition } from './lib/runtime-composition.js'
|
|
66
9
|
|
|
67
10
|
// Increment whenever the browser-visible settings contract gains a field whose
|
|
68
11
|
// absence changes write semantics. This revision is also exposed as a resolved
|
|
@@ -80,47 +23,32 @@ core.Config.set('progressiveTools', z.boolean().default(false))
|
|
|
80
23
|
// one visual task (including fallbacks) shares 120s. The whole-turn visual
|
|
81
24
|
// budget is an optional user safety cap rather than an Agent lifetime policy:
|
|
82
25
|
// 0 means unlimited, which is the default for long-running autonomous turns.
|
|
83
|
-
// The runtime policy below still reserves the final quarter of a multi-backend
|
|
84
|
-
// task for fallback, so disabling the aggregate cap does not revive the
|
|
85
|
-
// historical "120s per backend" stall that #117 removed.
|
|
86
26
|
core.Config.set('visionTaskTimeoutMs', z.number().step(1000).min(1000).max(180000).default(120000))
|
|
87
27
|
core.Config.set('visionTurnBudgetMs', z.number().step(1000).min(0).max(600000).default(0))
|
|
88
28
|
|
|
89
29
|
// Both visible entry points — Settings > Vision Router and the legacy
|
|
90
30
|
// Settings > Plugins compatibility card — edit the same Host-owned namespace.
|
|
91
|
-
// Keep the depth enum and custom cap on this final public contract so either
|
|
92
|
-
// entry serializes exactly the same shape on every supported Host generation.
|
|
93
31
|
core.Config.set('visionDepth', z.union(['fast', 'standard', 'deep', 'custom']).default('standard'))
|
|
94
32
|
core.Config.set('visionDepthMaxCalls', z.number().step(1).min(0).max(100).default(0))
|
|
95
33
|
|
|
96
|
-
// Product semantics:
|
|
97
|
-
// automatically or must obey the configured order, plus a plain-language
|
|
98
|
-
// routing preference. Ordered remains the safe default; Auto changes execution
|
|
34
|
+
// Product semantics: ordered remains the safe default; Auto changes execution
|
|
99
35
|
// only under explicit live routingMode:auto authority.
|
|
100
36
|
core.Config.set('routingMode', z.union(['ordered', 'auto']).default('ordered'))
|
|
101
37
|
core.Config.set(
|
|
102
38
|
'routingPreference',
|
|
103
39
|
z.union(['balanced', 'quality', 'speed', 'local']).default('balanced'),
|
|
104
40
|
)
|
|
105
|
-
// Background measurement is
|
|
106
|
-
// consumes resources, so absence never grants it: users explicitly choose
|
|
107
|
-
// local-free or all when they want standing background measurement.
|
|
41
|
+
// Background measurement is separate user authority; absence never grants it.
|
|
108
42
|
core.Config.set(
|
|
109
43
|
'backgroundBenchmarking',
|
|
110
44
|
z.union(['local-free', 'all', 'off']).default('off'),
|
|
111
45
|
)
|
|
112
46
|
|
|
113
|
-
// Settings surfaces and Host persistence must agree on this field.
|
|
114
|
-
// permission on the public entry contract as well as index.js so a packaged
|
|
115
|
-
// build cannot expose the new client toggle while registering an older Host
|
|
116
|
-
// schema that silently recovers from the rejected settings.mutate call. This
|
|
117
|
-
// deliberately repeats the default: entry.js is the final schema authority
|
|
118
|
-
// loaded by Cordis and therefore the right place to close client/Host drift.
|
|
47
|
+
// Settings surfaces and Host persistence must agree on this field.
|
|
119
48
|
core.Config.set('allowRemoteSettings', z.boolean().default(false))
|
|
120
49
|
|
|
121
50
|
// Internal read-only-by-convention handshake. It is not rendered by Vision
|
|
122
|
-
// Router's settings UI and is not in the remote mutable allow-list
|
|
123
|
-
// default lets diagnostics prove which schema the running Host actually loaded.
|
|
51
|
+
// Router's settings UI and is not in the remote mutable allow-list.
|
|
124
52
|
core.Config.set(
|
|
125
53
|
'settingsContractRevision',
|
|
126
54
|
z.number().step(1).min(1).max(SETTINGS_CONTRACT_REVISION).default(SETTINGS_CONTRACT_REVISION),
|
|
@@ -135,238 +63,16 @@ export {
|
|
|
135
63
|
installVisionAttachmentAdmissionPolicy,
|
|
136
64
|
protectHostProviderOwnership,
|
|
137
65
|
// Transitional public aliases retained for callers/tests written during the
|
|
138
|
-
// rc.7 compatibility pass.
|
|
66
|
+
// rc.7 compatibility pass. Production runtime branches on feature seams.
|
|
139
67
|
installRc7SettingsCompatibility,
|
|
140
68
|
isRc7ContractRuntime,
|
|
141
69
|
protectRc7ProviderOwnership,
|
|
142
70
|
} from './lib/dsh-contract-compat.js'
|
|
143
71
|
export const Config = core.Config
|
|
144
72
|
|
|
145
|
-
// Defense in depth for direct/programmatic callers
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
// private llm/tools view used only by Vision Router: wrapper -> delegate calls
|
|
149
|
-
// preserve replay identity, while vision-tool network calls are constrained to
|
|
150
|
-
// the exact backends the user selected in Vision Router.
|
|
73
|
+
// Defense in depth for direct/programmatic callers is implemented by the same
|
|
74
|
+
// production composition used by Cordis. This public entry intentionally owns
|
|
75
|
+
// no runtime installer ordering beyond that single call.
|
|
151
76
|
export function apply(ctx, config = {}) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// signal, so install a transport-level loopback fence before ANY plugin-owned
|
|
155
|
-
// route is registered. The wrapper patches only webServer.register and hands
|
|
156
|
-
// every injection callback the original child context identity unchanged.
|
|
157
|
-
const localMutationCtx = installLocalMutationRouteBoundary(ctx)
|
|
158
|
-
// Normalize DSH 0.1.1's prepareCall contract at the deepest private LLM
|
|
159
|
-
// boundary. Higher Vision Router layers can finish wrapping adapter.stream
|
|
160
|
-
// before this boundary captures the final Host-visible adapter, so prepareCall
|
|
161
|
-
// cannot bypass local/runtime/replay stream behavior.
|
|
162
|
-
const adapterContractCtx = contextWithCoalescedAdapterUpdates(localMutationCtx)
|
|
163
|
-
const logging = installVisionRouterFileLogging(adapterContractCtx)
|
|
164
|
-
const capabilityStore = createCapabilityProfileStore({ logger: logging.logger })
|
|
165
|
-
// Runtime speed is deliberately process-local and short-lived. It is not
|
|
166
|
-
// persisted beside capability evidence because network/provider performance
|
|
167
|
-
// is a dynamic runtime fact, not a model capability fact.
|
|
168
|
-
const runtimePerformanceStore = createVisionRuntimePerformanceStore()
|
|
169
|
-
const delegatedReplayCtx = contextWithDelegatedReplay(logging.ctx, {
|
|
170
|
-
wrapperRoute:
|
|
171
|
-
typeof config.wrapperRoute === 'string' && config.wrapperRoute !== ''
|
|
172
|
-
? config.wrapperRoute
|
|
173
|
-
: 'deepseek-vision',
|
|
174
|
-
visionConfig: config,
|
|
175
|
-
})
|
|
176
|
-
const runtimeCtx = contextWithReplayEnvelopeV2Compat(delegatedReplayCtx)
|
|
177
|
-
const screenshotSourceCtx = installScreenshotSourceBoundary(runtimeCtx, core)
|
|
178
|
-
const { ctx: hardenedCtx, config: hardenedConfig } = installAdversarialHardening(
|
|
179
|
-
screenshotSourceCtx,
|
|
180
|
-
config,
|
|
181
|
-
core,
|
|
182
|
-
)
|
|
183
|
-
const ollamaColdStartCtx = installOllamaColdStartGuard(hardenedCtx, hardenedConfig, core)
|
|
184
|
-
const { ctx: stabilizedCtx, bootConfig } = installLocalVisionStabilizer(
|
|
185
|
-
ollamaColdStartCtx,
|
|
186
|
-
hardenedConfig,
|
|
187
|
-
core,
|
|
188
|
-
)
|
|
189
|
-
const routingProduct = resolveVisionRoutingProduct(bootConfig)
|
|
190
|
-
const runtimeConfig = {
|
|
191
|
-
...bootConfig,
|
|
192
|
-
routingMode: routingProduct.mode,
|
|
193
|
-
routingPreference: routingProduct.preference,
|
|
194
|
-
backgroundBenchmarking: normalizeBackgroundMeasurementAuthority(bootConfig.backgroundBenchmarking),
|
|
195
|
-
progressiveTools: hardenedConfig.progressiveTools === true,
|
|
196
|
-
guidanceOverrides: normalizeGuidanceOverrides(bootConfig.guidanceOverrides ?? hardenedConfig.guidanceOverrides),
|
|
197
|
-
visionTaskTimeoutMs:
|
|
198
|
-
Number.isFinite(Number(bootConfig.visionTaskTimeoutMs))
|
|
199
|
-
? Number(bootConfig.visionTaskTimeoutMs)
|
|
200
|
-
: 120000,
|
|
201
|
-
visionTurnBudgetMs:
|
|
202
|
-
Number.isFinite(Number(bootConfig.visionTurnBudgetMs))
|
|
203
|
-
? Number(bootConfig.visionTurnBudgetMs)
|
|
204
|
-
: 0,
|
|
205
|
-
}
|
|
206
|
-
const batchAttachmentHost = hasBatchAttachmentContract(stabilizedCtx)
|
|
207
|
-
if (batchAttachmentHost) installVisionAttachmentAdmissionPolicy(stabilizedCtx, logging.logger)
|
|
208
|
-
installVisionRouterRemoteSettingsBridge(stabilizedCtx, logging.logger)
|
|
209
|
-
installSettingsRc8ClientLifecycle(stabilizedCtx)
|
|
210
|
-
const ownershipCtx = batchAttachmentHost ? protectHostProviderOwnership(stabilizedCtx) : stabilizedCtx
|
|
211
|
-
const settingsCtx = batchAttachmentHost
|
|
212
|
-
? installHostSettingsCompatibility(ownershipCtx, { ...runtimeConfig, stealth: false }, {
|
|
213
|
-
namespace: 'vision-router',
|
|
214
|
-
Config: core.Config,
|
|
215
|
-
})
|
|
216
|
-
: ownershipCtx
|
|
217
|
-
const attachmentCompatCtx = attachmentContextForContract(settingsCtx, logging.logger, {
|
|
218
|
-
installAndroidAttachmentCompat,
|
|
219
|
-
})
|
|
220
|
-
const toolRuntimeCtx = installVisionToolRuntimeBoundary(attachmentCompatCtx, runtimeConfig)
|
|
221
|
-
const nativeImageCompat = contextWithNativeImageCoexistence(toolRuntimeCtx, runtimeConfig)
|
|
222
|
-
// Feed the session-level image-ownership decision into the legacy core's
|
|
223
|
-
// wrapper/tool gates without reintroducing a global policy guess.
|
|
224
|
-
const legacyCoreCompat = installLegacyCoreVisionPolicyBridge(
|
|
225
|
-
nativeImageCompat.ctx,
|
|
226
|
-
nativeImageCompat.config,
|
|
227
|
-
{ rewriteHistoryImages: core.rewriteHistoryImages },
|
|
228
|
-
)
|
|
229
|
-
// Final structured-flow guard sits closest to core.apply so it sees the
|
|
230
|
-
// actual tool registrations and pre-step listener. It makes bootstrap
|
|
231
|
-
// one-shot, enforces fast/standard/deep/custom quotas, tracks mixed branches,
|
|
232
|
-
// rejects empty/non-evidence results, and applies the optional turn deadline
|
|
233
|
-
// only when the user explicitly configures one.
|
|
234
|
-
const structuredCtx = installStructuredFlowHardening(legacyCoreCompat.ctx, legacyCoreCompat.config)
|
|
235
|
-
const backgroundProfiling = installBackgroundCapabilityProfiling(
|
|
236
|
-
structuredCtx,
|
|
237
|
-
runtimeConfig,
|
|
238
|
-
core,
|
|
239
|
-
capabilityStore,
|
|
240
|
-
{ logger: logging.logger },
|
|
241
|
-
)
|
|
242
|
-
const breakerShadowHealth = createVisionBreakerShadowHealth(backgroundProfiling.ctx)
|
|
243
|
-
const capabilityShadowCtx = installCapabilityShadowRuntime(
|
|
244
|
-
backgroundProfiling.ctx,
|
|
245
|
-
runtimeConfig,
|
|
246
|
-
core,
|
|
247
|
-
{
|
|
248
|
-
logger: logging.logger,
|
|
249
|
-
store: capabilityStore,
|
|
250
|
-
runtimePerformanceStore,
|
|
251
|
-
healthForCandidate: breakerShadowHealth.healthForCandidate,
|
|
252
|
-
},
|
|
253
|
-
)
|
|
254
|
-
// prepareCall normalization/reconciliation is already installed at the
|
|
255
|
-
// deepest private Host registration boundary above. Do not wrap it again
|
|
256
|
-
// here or a prepared adapter may capture a pre-wrapper stream.
|
|
257
|
-
const reconciledCtx = capabilityShadowCtx
|
|
258
|
-
const liveDiscovery = installLiveModelDiscovery(reconciledCtx, {
|
|
259
|
-
config: runtimeConfig,
|
|
260
|
-
logger: logging.logger,
|
|
261
|
-
})
|
|
262
|
-
installVisionModelRegistry(reconciledCtx, liveDiscovery, { config: runtimeConfig })
|
|
263
|
-
installClientPresentationBoundary(reconciledCtx)
|
|
264
|
-
// The same first walkthrough step now teaches the explicit "识图" control
|
|
265
|
-
// introduced by #284. Widen the existing spotlight to cover that button and
|
|
266
|
-
// the adjacent model selector as one target instead of leaving the control
|
|
267
|
-
// under the dimming veil.
|
|
268
|
-
installGuideVisionToggleHighlight(reconciledCtx)
|
|
269
|
-
// The Host keeps wrapper routes registered because image admission and the
|
|
270
|
-
// Vision toggle need their real identity. Hide only confidently owned
|
|
271
|
-
// wrapper groups from DSH's stock model-selection presentation and project an
|
|
272
|
-
// active wrapper back to its ordinary source label; uncertain routes stay
|
|
273
|
-
// visible rather than being guessed away.
|
|
274
|
-
installVisionModelVisibilityBoundary(reconciledCtx)
|
|
275
|
-
// Keep endpoint-discovered ids private to Vision Router's settings client,
|
|
276
|
-
// but make Settings -> Models authoritative when DSH already enumerates a
|
|
277
|
-
// provider. Live /models data now fills only a still-active provider whose
|
|
278
|
-
// DSH catalog is empty, so disabled models and removed providers cannot leak
|
|
279
|
-
// back into the Vision Router picker through stale endpoint discovery.
|
|
280
|
-
installStrictLiveModelClientPrelude(reconciledCtx)
|
|
281
|
-
// Surface the existing autoWrapProviders/wrappedProviders contract in the
|
|
282
|
-
// primary Vision Router settings section. This is presentation-only: the Host
|
|
283
|
-
// keeps one settings namespace and one wrapper-registration implementation.
|
|
284
|
-
installWrapperScopeClientPrelude(reconciledCtx)
|
|
285
|
-
// Capability Benchmark is the single visible and callable per-model
|
|
286
|
-
// capability-test surface in the release runtime.
|
|
287
|
-
installVisionRoutingSettingsPrelude(reconciledCtx)
|
|
288
|
-
installCapabilityBenchmarkClient(reconciledCtx)
|
|
289
|
-
installPiAiBridgeWireCompat(reconciledCtx, logging.logger)
|
|
290
|
-
const executionCtx = contextWithVisionExecutionPolicy(reconciledCtx, {
|
|
291
|
-
isBridgeEvidence: (provider, model) => liveDiscovery.hasModel(provider, model),
|
|
292
|
-
evidenceSource: (provider, model) => liveDiscovery.evidenceSource?.(provider, model),
|
|
293
|
-
logger: logging.logger,
|
|
294
|
-
})
|
|
295
|
-
// Only real visual-tool adapter streams are timed, and only while live Auto
|
|
296
|
-
// authority permits future-routing observation. Benchmark/background calls
|
|
297
|
-
// have no visual-tool scope and cannot contaminate this store.
|
|
298
|
-
const performanceCtx = contextWithVisionRuntimePerformance(
|
|
299
|
-
executionCtx,
|
|
300
|
-
runtimePerformanceStore,
|
|
301
|
-
{
|
|
302
|
-
logger: logging.logger,
|
|
303
|
-
observationAllowed() {
|
|
304
|
-
try {
|
|
305
|
-
const settings = executionCtx?.get?.('settings')
|
|
306
|
-
const current = settings?.get?.('vision-router')
|
|
307
|
-
if (!current || typeof current !== 'object' || Array.isArray(current)) return false
|
|
308
|
-
return resolveVisionRoutingAuthority(current).ephemeralRuntimeObservation
|
|
309
|
-
} catch {
|
|
310
|
-
return false
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
},
|
|
314
|
-
)
|
|
315
|
-
// v1.7.7's outer policy covers cases where DSH would otherwise project image
|
|
316
|
-
// bytes to SHA text before an adapter gets the chance to reject them. Keeping
|
|
317
|
-
// it outside the runtime-performance observer means native adapter execution
|
|
318
|
-
// is still timed, while a preflight direct bridge bypasses runtime sampling
|
|
319
|
-
// and therefore stays incomparable for Balanced/Speed as designed.
|
|
320
|
-
const backendRuntimeCtx = contextWithVisionBackendRuntimePolicy(performanceCtx, {
|
|
321
|
-
config: runtimeConfig,
|
|
322
|
-
core,
|
|
323
|
-
evidenceSource: (provider, model) => liveDiscovery.evidenceSource?.(provider, model),
|
|
324
|
-
logger: logging.logger,
|
|
325
|
-
})
|
|
326
|
-
installCapabilityBenchmarkService(backendRuntimeCtx, runtimeConfig, core, {
|
|
327
|
-
logger: logging.logger,
|
|
328
|
-
store: capabilityStore,
|
|
329
|
-
})
|
|
330
|
-
installTesseractExecFileCompat(backendRuntimeCtx)
|
|
331
|
-
|
|
332
|
-
try {
|
|
333
|
-
const c = hardenedConfig && typeof hardenedConfig === 'object' ? hardenedConfig : {}
|
|
334
|
-
const local = c.localOllama && typeof c.localOllama === 'object' ? c.localOllama : {}
|
|
335
|
-
const lms = c.localLmStudio && typeof c.localLmStudio === 'object' ? c.localLmStudio : {}
|
|
336
|
-
logging.logger.info(
|
|
337
|
-
'vision-router: base config summary — contract=%s instantDescribe=%s localDescribeStyle=%s localOllama=%s localLmStudio=%s',
|
|
338
|
-
batchAttachmentHost ? 'batch-attachments' : 'single-attachment',
|
|
339
|
-
c.instantDescribe === true ? 'on' : 'off',
|
|
340
|
-
c.localDescribeStyle === 'structured' ? 'structured' : 'plain',
|
|
341
|
-
local.enabled === true ? 'on' : 'off',
|
|
342
|
-
lms.enabled === true ? 'on' : 'off',
|
|
343
|
-
)
|
|
344
|
-
} catch {
|
|
345
|
-
/* diagnostics must never break apply */
|
|
346
|
-
}
|
|
347
|
-
try {
|
|
348
|
-
const result = withVisionCircuitBreakerObserver(
|
|
349
|
-
breakerShadowHealth.capture,
|
|
350
|
-
() => core.apply(backendRuntimeCtx, legacyCoreCompat.config),
|
|
351
|
-
)
|
|
352
|
-
legacyCoreCompat.finishSchemaBootstrap()
|
|
353
|
-
installWrapperDirectoryAlias(attachmentCompatCtx, runtimeConfig, logging.logger)
|
|
354
|
-
if (result && typeof result.then === 'function') {
|
|
355
|
-
return result.catch((error) => {
|
|
356
|
-
logging.logger.error(
|
|
357
|
-
'vision-router: plugin apply failed: %s',
|
|
358
|
-
error && error.stack ? error.stack : error && error.message ? error.message : String(error),
|
|
359
|
-
)
|
|
360
|
-
throw error
|
|
361
|
-
})
|
|
362
|
-
}
|
|
363
|
-
return result
|
|
364
|
-
} catch (error) {
|
|
365
|
-
legacyCoreCompat.finishSchemaBootstrap()
|
|
366
|
-
logging.logger.error(
|
|
367
|
-
'vision-router: plugin apply failed: %s',
|
|
368
|
-
error && error.stack ? error.stack : error && error.message ? error.message : String(error),
|
|
369
|
-
)
|
|
370
|
-
throw error
|
|
371
|
-
}
|
|
372
|
-
}
|
|
77
|
+
return applyVisionRuntimeComposition(ctx, config, core)
|
|
78
|
+
}
|