dsh-vision-router 2.2.7 → 2.3.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 +8 -8
- package/README.zh.md +8 -8
- package/docs/architecture/2.3.0-compat-retirement.md +147 -0
- package/docs/architecture/2.3.0-execution-plan.md +410 -0
- package/docs/architecture/2.3.0-final-audit.md +279 -0
- package/docs/architecture/2.3.0-reopened-plan.md +720 -0
- package/docs/architecture/compat-inventory.md +26 -34
- package/docs/architecture/dsh-020-rc2-adaptation.md +23 -0
- package/docs/architecture/dsh-compatibility-matrix.md +65 -54
- package/docs/architecture/dsh-support-window.md +29 -21
- package/docs/architecture/final-closure-audit.md +2 -0
- package/docs/architecture/host-first-proxy-convergence.md +1 -1
- package/docs/releases/v2.2.8.md +25 -0
- package/docs/releases/v2.3.0.md +53 -0
- package/entry.js +8 -56
- package/index.js +161 -691
- package/lib/catalog-corrections.js +1 -2
- package/lib/client-host-compat-prelude.js +7 -12
- package/lib/client-maintenance-actions.js +145 -0
- package/lib/client-presentation-boundary-main.js +82 -32
- package/lib/client-presentation-boundary.js +60 -40
- package/lib/client-script-carrier.js +90 -0
- package/lib/client.js +248 -146
- package/lib/core-apply-lifecycle.js +47 -0
- package/lib/core-primitives.js +88 -135
- package/lib/desktop-screenshot-tool.js +262 -0
- package/lib/dsh-contract-compat.js +11 -26
- package/lib/dsh-support-window.js +4 -4
- package/lib/guide-vision-toggle-highlight.js +7 -10
- package/lib/http-compat.js +1 -2
- package/lib/live-model-client-prelude.js +7 -14
- package/lib/local-remote-settings-permission.js +41 -16
- package/lib/maintenance-routes.js +136 -0
- package/lib/public-config.js +57 -0
- package/lib/public-entry.js +2 -7
- package/lib/remote-settings-bridge.js +11 -0
- package/lib/remote-settings-risk-client-boundary.js +155 -0
- package/lib/remote-settings-risk-confirmation.js +17 -105
- package/lib/runtime-composition.js +105 -30
- package/lib/runtime-i18n-boundary.js +10 -11
- package/lib/session-message-source-compat.js +7 -3
- package/lib/session-vision-index.js +154 -9
- package/lib/session-vision-mode-boundary.js +43 -8
- package/lib/settings-client-loader-lifecycle.js +129 -0
- package/lib/settings-factory-lifecycle.js +25 -14
- package/lib/settings-ia-client-prelude.js +11 -11
- package/lib/settings-limit-client-prelude.js +7 -9
- package/lib/sharp-runtime.js +0 -7
- package/lib/strict-live-model-client-prelude.js +7 -10
- package/lib/structured-flow-hardening.js +3 -2
- package/lib/v2-settings-ia-integration.js +21 -6
- package/lib/vision-backend-runtime-policy.js +3 -2
- package/lib/vision-background-benchmark.js +3 -5
- package/lib/vision-capability-benchmark-client.js +7 -10
- package/lib/vision-capability-benchmark-service.js +1 -0
- package/lib/vision-diagnostics-routes.js +216 -0
- package/lib/vision-evidence-guidance.js +3 -1
- package/lib/vision-exact-check-client.js +11 -6
- package/lib/vision-model-visibility-boundary-main.js +7 -11
- package/lib/vision-model-visibility-boundary.js +7 -12
- package/lib/vision-provider-transport.js +0 -29
- package/lib/vision-routing-settings-prelude.js +7 -11
- package/lib/vision-toggle-root-hardening.js +50 -8
- package/lib/vision-tool-runtime-boundary.js +5 -1
- package/lib/vision-turn-budget-client-prelude.js +7 -10
- package/lib/web/remote-settings-client.js +9 -14
- package/package.json +23 -13
- package/lib/android-attachment-compat.js +0 -244
- package/lib/settings-client-rc8-lifecycle.js +0 -402
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { withHardDeadline } from './vision-capability-benchmark-hardening.js'
|
|
9
9
|
import { resolveVisionRoutingAuthority } from './vision-routing-authority.js'
|
|
10
10
|
import { redactDiagnosticText } from './diagnostic-redaction.js'
|
|
11
|
-
import {
|
|
11
|
+
import { installVisionExactCheckClient } from './vision-exact-check-client.js'
|
|
12
12
|
import { createImageInputVerdictStore } from './vision-image-input-verdict.js'
|
|
13
13
|
import { createBackgroundBenchmarkStopStore } from './vision-background-stop-store.js'
|
|
14
14
|
import { backgroundFailurePolicy } from './vision-background-failure-policy.js'
|
|
@@ -1033,12 +1033,10 @@ export function installBackgroundCapabilityProfiling(ctx, config, core, store, o
|
|
|
1033
1033
|
// Cleanup registration is best-effort; the profiler remains process-scoped.
|
|
1034
1034
|
}
|
|
1035
1035
|
|
|
1036
|
+
installVisionExactCheckClient(ctx)
|
|
1037
|
+
|
|
1036
1038
|
try {
|
|
1037
1039
|
ctx?.inject?.(['webServer'], (webCtx) => {
|
|
1038
|
-
webCtx.effect(
|
|
1039
|
-
() => webCtx.webServer.tapIndex(injectVisionExactCheckClient),
|
|
1040
|
-
'vision-router: exact image check product control',
|
|
1041
|
-
)
|
|
1042
1040
|
webCtx.effect(() => webCtx.webServer.register({
|
|
1043
1041
|
kind: 'exact',
|
|
1044
1042
|
path: VISION_CAPABILITY_RUNTIME_PATH,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
|
|
2
2
|
|
|
3
3
|
const CLIENT_MARK = 'data-vision-router-capability-benchmark'
|
|
4
4
|
|
|
@@ -412,17 +412,14 @@ export const CAPABILITY_BENCHMARK_CLIENT = String.raw`(function(){
|
|
|
412
412
|
})();`
|
|
413
413
|
|
|
414
414
|
export function injectCapabilityBenchmarkClient(html) {
|
|
415
|
-
|
|
416
|
-
const script = `<script ${CLIENT_MARK}>${CAPABILITY_BENCHMARK_CLIENT.replace(/<\/script/gi, '<\\/script')}</script>`
|
|
417
|
-
const head = html.indexOf('<head>')
|
|
418
|
-
return head === -1 ? `${script}${html}` : `${html.slice(0, head + 6)}${script}${html.slice(head + 6)}`
|
|
415
|
+
return injectClientCarrierHtml(html, CLIENT_MARK, CAPABILITY_BENCHMARK_CLIENT)
|
|
419
416
|
}
|
|
420
417
|
|
|
421
418
|
export function installCapabilityBenchmarkClient(ctx) {
|
|
422
|
-
ctx
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
419
|
+
installClientScriptCarriers(ctx, {
|
|
420
|
+
marker: CLIENT_MARK,
|
|
421
|
+
prelude: CAPABILITY_BENCHMARK_CLIENT,
|
|
422
|
+
label: 'vision-router: capability benchmark client',
|
|
423
|
+
injectHtml: injectCapabilityBenchmarkClient,
|
|
427
424
|
})
|
|
428
425
|
}
|
|
@@ -307,6 +307,7 @@ export function createExactCapabilityInvoker(ctx, core, candidate, config, optio
|
|
|
307
307
|
maxTokens: benchmarkMaxTokensForProvider(exactHttpProvider),
|
|
308
308
|
signal: callSignal,
|
|
309
309
|
affinityId: benchmarkAffinityId,
|
|
310
|
+
providerTransport: options.providerTransport,
|
|
310
311
|
resolveCredential: (ref) => resolvedCredentialValue(ctx, ref),
|
|
311
312
|
}),
|
|
312
313
|
fixtureTimeoutMs,
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { probeLocalBackends } from './local-connection-probe.js'
|
|
2
|
+
import {
|
|
3
|
+
METADATA_RESPONSE_MAX_BYTES,
|
|
4
|
+
readResponseJsonBounded,
|
|
5
|
+
} from './http-body-limit.js'
|
|
6
|
+
|
|
7
|
+
export const VISION_TEST_CONNECTION_PATH = '/_dsh/vision-router/test-connection'
|
|
8
|
+
export const VISION_MODEL_CAPABILITIES_PATH = '/_dsh/vision-router/model-capabilities'
|
|
9
|
+
|
|
10
|
+
function adapterAvailable(llm, provider) {
|
|
11
|
+
if (!llm || typeof llm.registration !== 'function') return false
|
|
12
|
+
try {
|
|
13
|
+
llm.registration(provider)
|
|
14
|
+
return true
|
|
15
|
+
} catch {
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function probeModels(fetchImpl, baseURL, expectedModel, startedAt) {
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetchImpl(`${String(baseURL).replace(/\/$/, '')}/models`, {
|
|
23
|
+
method: 'GET',
|
|
24
|
+
signal: AbortSignal.timeout(8000),
|
|
25
|
+
})
|
|
26
|
+
const latencyMs = Date.now() - startedAt
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
return { ok: false, latencyMs, status: response.status, error: `HTTP ${response.status}` }
|
|
29
|
+
}
|
|
30
|
+
const data = await readResponseJsonBounded(
|
|
31
|
+
response,
|
|
32
|
+
METADATA_RESPONSE_MAX_BYTES,
|
|
33
|
+
{ label: 'vision backend /models response' },
|
|
34
|
+
).catch(() => undefined)
|
|
35
|
+
const models = data && Array.isArray(data.data) ? data.data : undefined
|
|
36
|
+
const count = models ? models.length : undefined
|
|
37
|
+
if (
|
|
38
|
+
typeof expectedModel === 'string' &&
|
|
39
|
+
expectedModel !== '' &&
|
|
40
|
+
models &&
|
|
41
|
+
!models.some((entry) => entry && String(entry.id) === expectedModel)
|
|
42
|
+
) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
latencyMs,
|
|
46
|
+
status: response.status,
|
|
47
|
+
models: count,
|
|
48
|
+
endpoint: baseURL,
|
|
49
|
+
error: `configured model "${expectedModel}" was not returned by /models`,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { ok: true, latencyMs, status: response.status, models: count, endpoint: baseURL }
|
|
53
|
+
} catch (error) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
latencyMs: Date.now() - startedAt,
|
|
57
|
+
error: error && error.message ? error.message : String(error),
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getArray(factory) {
|
|
63
|
+
const value = typeof factory === 'function' ? factory() : factory
|
|
64
|
+
return Array.isArray(value) ? value : []
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Product diagnostics/settings-support routes kept outside visual Core.
|
|
69
|
+
*
|
|
70
|
+
* The caller supplies three coherent domain faces instead of a Core facade:
|
|
71
|
+
* connection candidates/probes, capability snapshot production, and the
|
|
72
|
+
* Host-ownership state rendered in the connection response. Authentication
|
|
73
|
+
* and remote/local capability policy stay outside this module in the existing
|
|
74
|
+
* scoped WebServer boundary.
|
|
75
|
+
*/
|
|
76
|
+
export function installVisionDiagnosticsRoutes(ctx, options = {}) {
|
|
77
|
+
if (!ctx || typeof ctx.inject !== 'function') return ctx
|
|
78
|
+
|
|
79
|
+
const connection = options.connection ?? {}
|
|
80
|
+
const capabilities = options.capabilities ?? {}
|
|
81
|
+
const ownership = options.ownership ?? {}
|
|
82
|
+
const resolveCapability = connection.resolveCapability
|
|
83
|
+
const collectCapabilities = capabilities.collect
|
|
84
|
+
if (typeof resolveCapability !== 'function') {
|
|
85
|
+
throw new TypeError('vision diagnostics routes require a connection capability resolver')
|
|
86
|
+
}
|
|
87
|
+
if (typeof collectCapabilities !== 'function') {
|
|
88
|
+
throw new TypeError('vision diagnostics routes require a capability collector')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const llm = ctx.llm
|
|
92
|
+
const httpRoute = typeof connection.httpRoute === 'string' && connection.httpRoute !== ''
|
|
93
|
+
? connection.httpRoute
|
|
94
|
+
: 'vision-http'
|
|
95
|
+
const fetchImpl = typeof options.fetchImpl === 'function' ? options.fetchImpl : globalThis.fetch
|
|
96
|
+
|
|
97
|
+
const probeConnection = async () => {
|
|
98
|
+
const started = Date.now()
|
|
99
|
+
let first
|
|
100
|
+
for (const pair of getArray(connection.candidatePairs)) {
|
|
101
|
+
if (!pair) continue
|
|
102
|
+
if (pair.provider !== httpRoute && !adapterAvailable(llm, pair.provider)) continue
|
|
103
|
+
const capability = await resolveCapability(pair.provider, pair.model)
|
|
104
|
+
if (capability?.attemptable !== false) {
|
|
105
|
+
first = pair
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const localProbe = await probeLocalBackends(
|
|
111
|
+
getArray(connection.localBackends),
|
|
112
|
+
(provider) => probeModels(fetchImpl, provider.baseURL, provider.model, started),
|
|
113
|
+
started,
|
|
114
|
+
)
|
|
115
|
+
if (localProbe !== undefined) return localProbe
|
|
116
|
+
|
|
117
|
+
const httpBackends = getArray(connection.httpBackends)
|
|
118
|
+
if (first !== undefined && first.provider === httpRoute) {
|
|
119
|
+
const entry = httpBackends.find((provider) => `${provider.name}/${provider.model}` === first.model)
|
|
120
|
+
if (entry !== undefined) return probeModels(fetchImpl, entry.baseURL, entry.model, started)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (first !== undefined) {
|
|
124
|
+
try {
|
|
125
|
+
await llm.resolveModelInfo(first.provider, first.model)
|
|
126
|
+
return {
|
|
127
|
+
ok: true,
|
|
128
|
+
latencyMs: Date.now() - started,
|
|
129
|
+
detail: `${first.provider}/${first.model} metadata resolved (no network call)`,
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
return {
|
|
133
|
+
ok: false,
|
|
134
|
+
latencyMs: Date.now() - started,
|
|
135
|
+
error: error && error.message ? error.message : String(error),
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const httpFirst = httpBackends[0]
|
|
141
|
+
if (httpFirst !== undefined) return probeModels(fetchImpl, httpFirst.baseURL, httpFirst.model, started)
|
|
142
|
+
return { ok: false, error: 'no usable vision provider configured' }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
ctx.inject(['webServer'], (webCtx) => {
|
|
146
|
+
webCtx.effect(() => {
|
|
147
|
+
return webCtx.webServer.register({
|
|
148
|
+
kind: 'exact',
|
|
149
|
+
path: VISION_TEST_CONNECTION_PATH,
|
|
150
|
+
handler: async (req, res) => {
|
|
151
|
+
if (req.method !== 'GET') {
|
|
152
|
+
res.setHeader('Allow', 'GET')
|
|
153
|
+
res.writeHead(405)
|
|
154
|
+
res.end()
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const result = await probeConnection()
|
|
159
|
+
const officialRouteAvailable = adapterAvailable(llm, 'deepseek-official')
|
|
160
|
+
result.stealth = {
|
|
161
|
+
configured: ownership.stealthConfigured,
|
|
162
|
+
active: false,
|
|
163
|
+
reason: ownership.hostOwnsOfficialDeepSeek && !officialRouteAvailable
|
|
164
|
+
? 'host-owned-official-unavailable'
|
|
165
|
+
: undefined,
|
|
166
|
+
hostOwned: ownership.hostOwnsOfficialDeepSeek,
|
|
167
|
+
}
|
|
168
|
+
res.writeHead(result.ok ? 200 : 502, { 'content-type': 'application/json' })
|
|
169
|
+
res.end(JSON.stringify(result))
|
|
170
|
+
} catch (error) {
|
|
171
|
+
res.writeHead(500, { 'content-type': 'application/json' })
|
|
172
|
+
res.end(JSON.stringify({
|
|
173
|
+
ok: false,
|
|
174
|
+
error: error && error.message ? error.message : String(error),
|
|
175
|
+
}))
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
}, 'vision-router: test-connection route')
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
ctx.inject(['webServer'], (webCtx) => {
|
|
183
|
+
webCtx.effect(
|
|
184
|
+
() => webCtx.webServer.register({
|
|
185
|
+
kind: 'exact',
|
|
186
|
+
path: VISION_MODEL_CAPABILITIES_PATH,
|
|
187
|
+
handler: async (req, res) => {
|
|
188
|
+
if (req.method !== 'GET') {
|
|
189
|
+
res.setHeader('Allow', 'GET')
|
|
190
|
+
res.writeHead(405)
|
|
191
|
+
res.end()
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const snapshot = await collectCapabilities()
|
|
196
|
+
res.writeHead(200, { 'content-type': 'application/json' })
|
|
197
|
+
res.end(JSON.stringify({
|
|
198
|
+
capabilities: snapshot,
|
|
199
|
+
builtinFallback: getArray(capabilities.builtinFallback),
|
|
200
|
+
anonymousRpmPerModel: 2,
|
|
201
|
+
}))
|
|
202
|
+
} catch (error) {
|
|
203
|
+
res.writeHead(500, { 'content-type': 'application/json' })
|
|
204
|
+
res.end(JSON.stringify({
|
|
205
|
+
capabilities: {},
|
|
206
|
+
error: error && error.message ? error.message : String(error),
|
|
207
|
+
}))
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
}),
|
|
211
|
+
'vision-router: model capabilities route',
|
|
212
|
+
)
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
return ctx
|
|
216
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { visionRouterMessageSource } from './session-message-source-compat.js'
|
|
2
|
+
|
|
1
3
|
export const VISION_SUCCESS_GUIDANCE =
|
|
2
4
|
'Vision Router trusted execution metadata: the preceding vision_describe call SUCCEEDED. ' +
|
|
3
5
|
'This metadata is not image content. If that successful evidence resolves the visual fact needed for the current task, stop making additional vision calls for that fact and continue the remaining user task from this evidence. ' +
|
|
@@ -34,6 +36,6 @@ export function visionDescribeSuccessContext(exec, result) {
|
|
|
34
36
|
role: 'user',
|
|
35
37
|
id: `vision-router-evidence-success-${String(exec.callId)}`,
|
|
36
38
|
content: [{ type: 'text', text: VISION_SUCCESS_GUIDANCE }],
|
|
37
|
-
source:
|
|
39
|
+
source: visionRouterMessageSource(exec.agent.session),
|
|
38
40
|
}
|
|
39
41
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
|
|
2
2
|
|
|
3
3
|
const CLIENT_MARK = 'data-vision-router-exact-check'
|
|
4
4
|
|
|
@@ -185,9 +185,14 @@ export const VISION_EXACT_CHECK_CLIENT = String.raw`(function(){
|
|
|
185
185
|
})();`
|
|
186
186
|
|
|
187
187
|
export function injectVisionExactCheckClient(html) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
return injectClientCarrierHtml(html, CLIENT_MARK, VISION_EXACT_CHECK_CLIENT)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function installVisionExactCheckClient(ctx) {
|
|
192
|
+
installClientScriptCarriers(ctx, {
|
|
193
|
+
marker: CLIENT_MARK,
|
|
194
|
+
prelude: VISION_EXACT_CHECK_CLIENT,
|
|
195
|
+
label: 'vision-router: exact image check product control',
|
|
196
|
+
injectHtml: injectVisionExactCheckClient,
|
|
197
|
+
})
|
|
193
198
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
|
|
1
2
|
const VISION_MODE_WRAPPER_SOURCE = 'deepseek-official'
|
|
2
3
|
const DEFAULT_WRAPPER_ROUTE = 'deepseek-vision'
|
|
3
4
|
const MODEL_SELECTION_TARGET = '@deepseek-ai/dsh-client-ui-model-selection'
|
|
@@ -454,19 +455,14 @@ export const VISION_MODEL_VISIBILITY_PRELUDE = String.raw`(function(){
|
|
|
454
455
|
})();`
|
|
455
456
|
|
|
456
457
|
export function injectVisionModelVisibilityBoundary(html) {
|
|
457
|
-
|
|
458
|
-
const safe = VISION_MODEL_VISIBILITY_PRELUDE.replace(/<\/script/gi, '<\\/script')
|
|
459
|
-
const script = `<script ${VISIBILITY_MARK}>${safe}</script>`
|
|
460
|
-
const closeHead = html.indexOf('</head>')
|
|
461
|
-
if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
|
|
462
|
-
return `${html}${script}`
|
|
458
|
+
return injectClientCarrierHtml(html, VISIBILITY_MARK, VISION_MODEL_VISIBILITY_PRELUDE)
|
|
463
459
|
}
|
|
464
460
|
|
|
465
461
|
export function installVisionModelVisibilityBoundary(ctx) {
|
|
466
|
-
ctx
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
462
|
+
installClientScriptCarriers(ctx, {
|
|
463
|
+
marker: VISIBILITY_MARK,
|
|
464
|
+
prelude: VISION_MODEL_VISIBILITY_PRELUDE,
|
|
465
|
+
label: 'vision-router: model visibility boundary',
|
|
466
|
+
injectHtml: injectVisionModelVisibilityBoundary,
|
|
471
467
|
})
|
|
472
468
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
|
|
2
2
|
import { VISION_MODEL_VISIBILITY_PRELUDE } from './vision-model-visibility-boundary-main.js'
|
|
3
3
|
|
|
4
4
|
const VISIBILITY_MARK = 'data-vision-router-model-visibility-boundary'
|
|
@@ -10,19 +10,14 @@ export {
|
|
|
10
10
|
} from './vision-model-visibility-boundary-main.js'
|
|
11
11
|
|
|
12
12
|
export function injectVisionModelVisibilityBoundary(html) {
|
|
13
|
-
|
|
14
|
-
const safe = VISION_MODEL_VISIBILITY_PRELUDE.replace(/<\/script/gi, '<\\/script')
|
|
15
|
-
const script = `<script ${VISIBILITY_MARK}>${safe}</script>`
|
|
16
|
-
const closeHead = html.indexOf('</head>')
|
|
17
|
-
if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
|
|
18
|
-
return `${html}${script}`
|
|
13
|
+
return injectClientCarrierHtml(html, VISIBILITY_MARK, VISION_MODEL_VISIBILITY_PRELUDE)
|
|
19
14
|
}
|
|
20
15
|
|
|
21
16
|
export function installVisionModelVisibilityBoundary(ctx) {
|
|
22
|
-
ctx
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
installClientScriptCarriers(ctx, {
|
|
18
|
+
marker: VISIBILITY_MARK,
|
|
19
|
+
prelude: VISION_MODEL_VISIBILITY_PRELUDE,
|
|
20
|
+
label: 'vision-router: model visibility boundary',
|
|
21
|
+
injectHtml: injectVisionModelVisibilityBoundary,
|
|
27
22
|
})
|
|
28
23
|
}
|
|
@@ -33,8 +33,6 @@ const moduleFetch =
|
|
|
33
33
|
? globalThis.fetch.bind(globalThis)
|
|
34
34
|
: undefined
|
|
35
35
|
|
|
36
|
-
const installed = []
|
|
37
|
-
|
|
38
36
|
function live(value) {
|
|
39
37
|
return typeof value === 'function' ? value() : value
|
|
40
38
|
}
|
|
@@ -175,30 +173,3 @@ export function createVisionProviderTransport({
|
|
|
175
173
|
},
|
|
176
174
|
})
|
|
177
175
|
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Scoped process/profile carrier for Router-owned compatibility calls whose
|
|
181
|
-
* mature signatures do not yet accept an explicit VisionProviderTransport.
|
|
182
|
-
* The registry never patches global fetch and is released with the public
|
|
183
|
-
* plugin lifecycle. Remove it only after every production compatibility caller
|
|
184
|
-
* receives the transport explicitly and no production code reads
|
|
185
|
-
* currentVisionProviderTransport().
|
|
186
|
-
*/
|
|
187
|
-
export function installVisionProviderTransport(transport) {
|
|
188
|
-
if (!transport || typeof transport.fetch !== 'function') {
|
|
189
|
-
throw new TypeError('invalid vision provider transport')
|
|
190
|
-
}
|
|
191
|
-
const token = Object.freeze({ transport })
|
|
192
|
-
installed.push(token)
|
|
193
|
-
let active = true
|
|
194
|
-
return () => {
|
|
195
|
-
if (!active) return
|
|
196
|
-
active = false
|
|
197
|
-
const index = installed.indexOf(token)
|
|
198
|
-
if (index >= 0) installed.splice(index, 1)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export function currentVisionProviderTransport() {
|
|
203
|
-
return installed[installed.length - 1]?.transport
|
|
204
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
|
|
2
2
|
|
|
3
3
|
const ROUTING_SETTINGS_PRELUDE_MARK = 'data-vision-router-routing-settings'
|
|
4
4
|
|
|
@@ -536,18 +536,14 @@ export const VISION_ROUTING_SETTINGS_PRELUDE = String.raw`(function(){
|
|
|
536
536
|
})();`
|
|
537
537
|
|
|
538
538
|
export function injectVisionRoutingSettingsPrelude(html) {
|
|
539
|
-
|
|
540
|
-
const script = `<script ${ROUTING_SETTINGS_PRELUDE_MARK}>${VISION_ROUTING_SETTINGS_PRELUDE.replace(/<\/script/gi, '<\\/script')}</script>`
|
|
541
|
-
const closeHead = html.indexOf('</head>')
|
|
542
|
-
if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
|
|
543
|
-
return `${html}${script}`
|
|
539
|
+
return injectClientCarrierHtml(html, ROUTING_SETTINGS_PRELUDE_MARK, VISION_ROUTING_SETTINGS_PRELUDE)
|
|
544
540
|
}
|
|
545
541
|
|
|
546
542
|
export function installVisionRoutingSettingsPrelude(ctx) {
|
|
547
|
-
ctx
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
543
|
+
installClientScriptCarriers(ctx, {
|
|
544
|
+
marker: ROUTING_SETTINGS_PRELUDE_MARK,
|
|
545
|
+
prelude: VISION_ROUTING_SETTINGS_PRELUDE,
|
|
546
|
+
label: 'vision-router: Vision routing Settings prelude',
|
|
547
|
+
injectHtml: injectVisionRoutingSettingsPrelude,
|
|
552
548
|
})
|
|
553
549
|
}
|
|
@@ -251,6 +251,7 @@ const CLIENT_PRELUDE = String.raw`(function(){
|
|
|
251
251
|
var listeners = new Set();
|
|
252
252
|
var pending = new WeakMap();
|
|
253
253
|
var recoveries = new WeakMap();
|
|
254
|
+
var selectionGenerations = new WeakMap();
|
|
254
255
|
var inFlight = null;
|
|
255
256
|
var refreshedAt = 0;
|
|
256
257
|
function emit(){ listeners.forEach(function(fn){ try { fn(); } catch (_) {} }); }
|
|
@@ -302,13 +303,29 @@ const CLIENT_PRELUDE = String.raw`(function(){
|
|
|
302
303
|
var key = JSON.stringify(selection || {});
|
|
303
304
|
var held = pending.get(directory);
|
|
304
305
|
if (held && held.key === key) return held.promise;
|
|
306
|
+
var generation = (selectionGenerations.get(directory) || 0) + 1;
|
|
307
|
+
selectionGenerations.set(directory, generation);
|
|
308
|
+
var current = function(){ return selectionGenerations.get(directory) === generation; };
|
|
305
309
|
var recovery = recoveryFor(directory);
|
|
306
310
|
recovery.clear();
|
|
307
311
|
var promise = Promise.resolve().then(function(){ return directory.select(selection); }).then(
|
|
308
|
-
function(value){
|
|
309
|
-
|
|
312
|
+
function(value){
|
|
313
|
+
if (!current()) return value;
|
|
314
|
+
if (value && value.ok === false) {
|
|
315
|
+
var failure = value.error;
|
|
316
|
+
var message = failure && failure.message
|
|
317
|
+
? String(failure.message)
|
|
318
|
+
: String(failure || 'model operation failed');
|
|
319
|
+
if (failure && failure.code) message = String(failure.code) + ': ' + message;
|
|
320
|
+
recovery.fail(new Error(message));
|
|
321
|
+
return value;
|
|
322
|
+
}
|
|
323
|
+
recovery.clear();
|
|
324
|
+
return value;
|
|
325
|
+
},
|
|
326
|
+
function(error){ if (current()) recovery.fail(error); throw error; }
|
|
310
327
|
);
|
|
311
|
-
pending.set(directory, { key: key, promise: promise });
|
|
328
|
+
pending.set(directory, { key: key, promise: promise, generation: generation });
|
|
312
329
|
promise.finally(function(){
|
|
313
330
|
var latest = pending.get(directory);
|
|
314
331
|
if (latest && latest.promise === promise) pending.delete(directory);
|
|
@@ -331,9 +348,9 @@ function replaceAll(source, before, after) {
|
|
|
331
348
|
return source.includes(before) ? source.split(before).join(after) : source
|
|
332
349
|
}
|
|
333
350
|
|
|
334
|
-
export function
|
|
335
|
-
if (typeof
|
|
336
|
-
let next =
|
|
351
|
+
export function hardenVisionClientSource(source) {
|
|
352
|
+
if (typeof source !== 'string') return source
|
|
353
|
+
let next = source
|
|
337
354
|
|
|
338
355
|
next = replaceAll(
|
|
339
356
|
next,
|
|
@@ -391,8 +408,8 @@ export function hardenVisionToggleHtml(html) {
|
|
|
391
408
|
|
|
392
409
|
next = replaceAll(
|
|
393
410
|
next,
|
|
394
|
-
` try {\n return Promise.resolve(directory.select(selection)).then(\n function(){ return
|
|
395
|
-
` var hardening = window.__dshVisionRouterRootHardening;\n var operation;\n try { operation = hardening ? hardening.select(directory, selection) : Promise.resolve(directory.select(selection)); }\n catch (_) { return Promise.resolve(false); }\n return Promise.resolve(operation).then(function(){ return
|
|
411
|
+
` try {\n return Promise.resolve(directory.select(selection)).then(\n function(result){ return !result || result.ok !== false; },\n function(){ return false; }\n );\n } catch (_) {\n return Promise.resolve(false);\n }`,
|
|
412
|
+
` var hardening = window.__dshVisionRouterRootHardening;\n var operation;\n try { operation = hardening ? hardening.select(directory, selection) : Promise.resolve(directory.select(selection)); }\n catch (_) { return Promise.resolve(false); }\n return Promise.resolve(operation).then(function(result){ return !result || result.ok !== false; }, function(){ return false; });`,
|
|
396
413
|
)
|
|
397
414
|
|
|
398
415
|
next = replaceAll(
|
|
@@ -430,6 +447,13 @@ export function hardenVisionToggleHtml(html) {
|
|
|
430
447
|
` var hardening = window.__dshVisionRouterRootHardening;\n var recovery = hardening ? hardening.recoveryFor(directory) : undefined;\n var store = wrapStore(directory.store, settings, recovery);`,
|
|
431
448
|
)
|
|
432
449
|
|
|
450
|
+
return next
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export function hardenVisionToggleHtml(html) {
|
|
454
|
+
if (typeof html !== 'string') return html
|
|
455
|
+
let next = hardenVisionClientSource(html)
|
|
456
|
+
|
|
433
457
|
if (!next.includes(OWNERSHIP_MARK)) {
|
|
434
458
|
const safe = CLIENT_PRELUDE.replace(/<\/script/gi, '<\\/script')
|
|
435
459
|
const script = `<script ${OWNERSHIP_MARK}>${safe}</script>`
|
|
@@ -474,6 +498,24 @@ export function createVisionToggleRootHardening(ctx, config = {}) {
|
|
|
474
498
|
}),
|
|
475
499
|
'vision-router: route ownership',
|
|
476
500
|
)
|
|
501
|
+
if (typeof webCtx.on === 'function') {
|
|
502
|
+
webCtx.on('webserver/index-inject', (table) => {
|
|
503
|
+
if (!Array.isArray(table)) return
|
|
504
|
+
for (const row of table) {
|
|
505
|
+
if (row?.kind === 'script' && typeof row.text === 'string') {
|
|
506
|
+
row.text = hardenVisionClientSource(row.text)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const signature = `/* ${OWNERSHIP_MARK} */`
|
|
510
|
+
if (!table.some((row) => row?.kind === 'script' && typeof row.text === 'string' && row.text.includes(signature))) {
|
|
511
|
+
table.push({
|
|
512
|
+
kind: 'script',
|
|
513
|
+
placement: 'head',
|
|
514
|
+
text: `${signature}\n${CLIENT_PRELUDE}`,
|
|
515
|
+
})
|
|
516
|
+
}
|
|
517
|
+
})
|
|
518
|
+
}
|
|
477
519
|
webCtx.effect(
|
|
478
520
|
() => webCtx.webServer.tapIndex(hardenVisionToggleHtml),
|
|
479
521
|
'vision-router: vision toggle root hardening',
|
|
@@ -540,7 +540,11 @@ function wrapLlm(llm, runtimeState) {
|
|
|
540
540
|
: state?.callConfigAuthority === 'transparent'
|
|
541
541
|
? projectTransparentCallConfig(options, state, runtimeState)
|
|
542
542
|
: options
|
|
543
|
-
|
|
543
|
+
const signal = combineSignals(projected?.signal, state?.signal)
|
|
544
|
+
const call = signal === undefined || signal === projected?.signal
|
|
545
|
+
? projected
|
|
546
|
+
: { ...(projected ?? {}), signal }
|
|
547
|
+
return stream.call(target, call)
|
|
544
548
|
}
|
|
545
549
|
}
|
|
546
550
|
if (property === 'registerAdapter') {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
|
|
1
2
|
const CLIENT_PRELUDE_MARK = 'data-vision-router-turn-budget'
|
|
2
3
|
|
|
3
4
|
export const VISION_TURN_BUDGET_CLIENT_PRELUDE = String.raw`(function(){
|
|
@@ -259,18 +260,14 @@ export const VISION_TURN_BUDGET_CLIENT_PRELUDE = String.raw`(function(){
|
|
|
259
260
|
})();`
|
|
260
261
|
|
|
261
262
|
export function injectVisionTurnBudgetClientPrelude(html) {
|
|
262
|
-
|
|
263
|
-
const script = `<script ${CLIENT_PRELUDE_MARK}>${VISION_TURN_BUDGET_CLIENT_PRELUDE.replace(/<\/script/gi, '<\\/script')}</script>`
|
|
264
|
-
const closeHead = html.indexOf('</head>')
|
|
265
|
-
if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
|
|
266
|
-
return `${html}${script}`
|
|
263
|
+
return injectClientCarrierHtml(html, CLIENT_PRELUDE_MARK, VISION_TURN_BUDGET_CLIENT_PRELUDE)
|
|
267
264
|
}
|
|
268
265
|
|
|
269
266
|
export function installVisionTurnBudgetClientPrelude(ctx) {
|
|
270
|
-
ctx
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
267
|
+
installClientScriptCarriers(ctx, {
|
|
268
|
+
marker: CLIENT_PRELUDE_MARK,
|
|
269
|
+
prelude: VISION_TURN_BUDGET_CLIENT_PRELUDE,
|
|
270
|
+
label: 'vision-router: turn budget client prelude',
|
|
271
|
+
injectHtml: injectVisionTurnBudgetClientPrelude,
|
|
275
272
|
})
|
|
276
273
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectClientCarrierHtml, installClientScriptCarriers } from '../client-script-carrier.js'
|
|
2
2
|
import { installVisionRouterRemoteSettingsBridge } from '../remote-settings-bridge.js'
|
|
3
|
-
import {
|
|
3
|
+
import { installSettingsClientLoaderLifecycle } from '../settings-client-loader-lifecycle.js'
|
|
4
4
|
|
|
5
5
|
const SETTINGS_CONFIG_FORMS_MARK = 'data-vision-router-settings-configforms-compat'
|
|
6
6
|
|
|
@@ -187,26 +187,21 @@ export const SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE = String.raw`(function(){
|
|
|
187
187
|
})();`
|
|
188
188
|
|
|
189
189
|
export function injectSettingsConfigFormsCompatPrelude(html) {
|
|
190
|
-
|
|
191
|
-
const safe = SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE.replace(/<\/script/gi, '<\\/script')
|
|
192
|
-
const script = `<script ${SETTINGS_CONFIG_FORMS_MARK}>${safe}</script>`
|
|
193
|
-
const closeHead = html.indexOf('</head>')
|
|
194
|
-
return closeHead === -1 ? `${html}${script}` : `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
|
|
190
|
+
return injectClientCarrierHtml(html, SETTINGS_CONFIG_FORMS_MARK, SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE)
|
|
195
191
|
}
|
|
196
192
|
|
|
197
193
|
export function installSettingsConfigFormsCompat(ctx) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
)
|
|
194
|
+
installClientScriptCarriers(ctx, {
|
|
195
|
+
marker: SETTINGS_CONFIG_FORMS_MARK,
|
|
196
|
+
prelude: SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE,
|
|
197
|
+
label: 'vision-router: settings configForms compatibility',
|
|
198
|
+
injectHtml: injectSettingsConfigFormsCompatPrelude,
|
|
204
199
|
})
|
|
205
200
|
}
|
|
206
201
|
|
|
207
202
|
export function installVisionRemoteSettingsClient(ctx, logger) {
|
|
208
203
|
installVisionRouterRemoteSettingsBridge(ctx, logger)
|
|
209
204
|
installSettingsConfigFormsCompat(ctx)
|
|
210
|
-
|
|
205
|
+
installSettingsClientLoaderLifecycle(ctx)
|
|
211
206
|
return ctx
|
|
212
207
|
}
|