dsh-vision-router 2.1.1 → 2.1.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.
@@ -12,6 +12,8 @@ import {
12
12
  ProxyDispatcherTracker,
13
13
  proxyRequestIsManaged,
14
14
  } from './runtime-reliability.js'
15
+ import { projectDelegatedCallConfig } from './delegated-call-config.js'
16
+ import { VISION_RESULT_CODES } from './vision-resilience.js'
15
17
 
16
18
  const toolRuntime = new AsyncLocalStorage()
17
19
  const wrappedContexts = new WeakMap()
@@ -21,6 +23,24 @@ const wrappedSettings = new WeakMap()
21
23
  const wrappedScopes = new WeakMap()
22
24
  const wrappedLlms = new WeakMap()
23
25
  const wrappedAdapters = new WeakMap()
26
+ const wrappedDelegatingAdapters = new WeakMap()
27
+ const wrappedTransparentAdapters = new WeakMap()
28
+ const VISION_ROUTER_ADAPTER_OWNER = Symbol.for('dsh-vision-router.adapter-owner')
29
+ const MAX_TRANSPARENT_REASONING_MEMORY = 512
30
+ const VISION_FAILURE_RESULT_CODES = new Set(Object.values(VISION_RESULT_CODES))
31
+
32
+ function cacheableVisionDescribeResult(value) {
33
+ let parsed = value
34
+ if (typeof value === 'string') {
35
+ try {
36
+ parsed = JSON.parse(value)
37
+ } catch {
38
+ return true
39
+ }
40
+ }
41
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return true
42
+ return !(parsed.ok === false && VISION_FAILURE_RESULT_CODES.has(parsed.code))
43
+ }
24
44
 
25
45
  function usableSignal(value) {
26
46
  return value && typeof value === 'object' && typeof value.aborted === 'boolean' ? value : undefined
@@ -86,6 +106,7 @@ function createRuntimeState(initialConfig = {}) {
86
106
  const cache = new LiveDescribeCache()
87
107
  const endpoints = new HttpEndpointRevisionTracker()
88
108
  const proxyDispatchers = new ProxyDispatcherTracker()
109
+ const transparentReasoning = new Map()
89
110
  let config = {
90
111
  cache: true,
91
112
  cacheMaxEntries: 200,
@@ -117,6 +138,23 @@ function createRuntimeState(initialConfig = {}) {
117
138
  return config
118
139
  }
119
140
 
141
+ const rememberTransparentReasoning = (key, value) => {
142
+ if (transparentReasoning.size >= MAX_TRANSPARENT_REASONING_MEMORY && !transparentReasoning.has(key)) {
143
+ const oldest = transparentReasoning.keys().next().value
144
+ if (oldest !== undefined) transparentReasoning.delete(oldest)
145
+ }
146
+ transparentReasoning.delete(key)
147
+ transparentReasoning.set(key, value)
148
+ }
149
+
150
+ const recallTransparentReasoning = (key) => {
151
+ if (!transparentReasoning.has(key)) return undefined
152
+ const value = transparentReasoning.get(key)
153
+ transparentReasoning.delete(key)
154
+ transparentReasoning.set(key, value)
155
+ return value
156
+ }
157
+
120
158
  return {
121
159
  cache,
122
160
  endpoints,
@@ -124,6 +162,8 @@ function createRuntimeState(initialConfig = {}) {
124
162
  noteConfig,
125
163
  config: () => config,
126
164
  revision: () => revision,
165
+ rememberTransparentReasoning,
166
+ recallTransparentReasoning,
127
167
  }
128
168
  }
129
169
 
@@ -134,6 +174,10 @@ function stateFor(name, exec) {
134
174
  signal: usableSignal(exec?.signal),
135
175
  artifactRunId: `.vision-run-${Date.now().toString(36)}-${randomUUID()}`,
136
176
  disableCoreCache: name === 'vision_describe',
177
+ // Every model call made from a Vision Router tool is a real authority
178
+ // handoff. The selected target adapter, not the tool's generic defaults,
179
+ // owns reasoning/sampling/output-limit call config.
180
+ callConfigAuthority: 'target',
137
181
  }
138
182
  }
139
183
 
@@ -309,6 +353,159 @@ function wrapVisionHttpAdapter(adapter, runtimeState) {
309
353
  return wrapped
310
354
  }
311
355
 
356
+ function visionChainAdapter(adapter, routes) {
357
+ if (!adapter || (typeof adapter !== 'object' && typeof adapter !== 'function')) return false
358
+ if (typeof adapter.providerInfo !== 'function') return false
359
+ for (const route of routes) {
360
+ try {
361
+ const name = adapter.providerInfo(String(route))?.name
362
+ if (name === 'Vision Chain') return true
363
+ } catch {
364
+ // Provider metadata is advisory; another route may still identify it.
365
+ }
366
+ }
367
+ return false
368
+ }
369
+
370
+ function visionRouterOwnedAdapter(adapter) {
371
+ if (!adapter || (typeof adapter !== 'object' && typeof adapter !== 'function')) return false
372
+ try {
373
+ return adapter[VISION_ROUTER_ADAPTER_OWNER] !== undefined
374
+ } catch {
375
+ return false
376
+ }
377
+ }
378
+
379
+ function explicitReasoningEffort(options) {
380
+ const value = options?.reasoningEffort
381
+ return typeof value === 'string' && value !== '' ? value : undefined
382
+ }
383
+
384
+ function sessionIdentity(options) {
385
+ const value = options?.sessionId
386
+ return value === undefined || value === null || String(value) === '' ? undefined : String(value)
387
+ }
388
+
389
+ function transparentReasoningKey(state, options) {
390
+ const sessionId = state?.transparentSessionId
391
+ const provider = options?.provider
392
+ const model = options?.model
393
+ if (
394
+ typeof sessionId !== 'string' || sessionId === '' ||
395
+ typeof provider !== 'string' || provider === '' ||
396
+ typeof model !== 'string' || model === ''
397
+ ) return undefined
398
+ return `${sessionId}\u0000${provider}\u0000${model}`
399
+ }
400
+
401
+ function projectTransparentCallConfig(options, state, runtimeState) {
402
+ if (!options || typeof options !== 'object' || Array.isArray(options)) return options
403
+ const key = transparentReasoningKey(state, options)
404
+ const explicit = state?.transparentExplicitReasoning
405
+ if (explicit !== undefined) {
406
+ if (key !== undefined) runtimeState.rememberTransparentReasoning(key, explicit)
407
+ return options.reasoningEffort === explicit ? options : { ...options, reasoningEffort: explicit }
408
+ }
409
+
410
+ const remembered = key === undefined ? undefined : runtimeState.recallTransparentReasoning(key)
411
+ if (remembered !== undefined) {
412
+ return options.reasoningEffort === remembered ? options : { ...options, reasoningEffort: remembered }
413
+ }
414
+
415
+ // Core 1.7.x still carries a provider/model-only wrapper cache. Without an
416
+ // exact session proof, discard only that potentially stale injected effort;
417
+ // all other caller-owned generation config remains transparent.
418
+ if (!Object.hasOwn(options, 'reasoningEffort')) return options
419
+ const { reasoningEffort: _reasoningEffort, ...rest } = options
420
+ return rest
421
+ }
422
+
423
+ async function* iterateUnderRuntimeState(iterable, state) {
424
+ const iterator = toolRuntime.run(state, () => iterable[Symbol.asyncIterator]())
425
+ let completed = false
426
+ try {
427
+ while (true) {
428
+ const item = await toolRuntime.run(state, () => iterator.next())
429
+ if (item.done) {
430
+ completed = true
431
+ return
432
+ }
433
+ yield item.value
434
+ }
435
+ } finally {
436
+ if (!completed && typeof iterator.return === 'function') {
437
+ await toolRuntime.run(state, () => iterator.return())
438
+ }
439
+ }
440
+ }
441
+
442
+ function wrapDelegatingAdapter(adapter, runtimeState) {
443
+ if (!adapter || (typeof adapter !== 'object' && typeof adapter !== 'function')) return adapter
444
+ let byRuntime = wrappedDelegatingAdapters.get(adapter)
445
+ if (!byRuntime) {
446
+ byRuntime = new WeakMap()
447
+ wrappedDelegatingAdapters.set(adapter, byRuntime)
448
+ }
449
+ const cached = byRuntime.get(runtimeState)
450
+ if (cached) return cached
451
+ const wrapped = new Proxy(adapter, {
452
+ get(target, property) {
453
+ if (property !== 'stream') {
454
+ const value = Reflect.get(target, property, target)
455
+ return typeof value === 'function' ? value.bind(target) : value
456
+ }
457
+ const stream = Reflect.get(target, property, target)
458
+ if (typeof stream !== 'function') return stream
459
+ return function streamWithDelegatedCallAuthority(options) {
460
+ const parent = toolRuntime.getStore()
461
+ const state = {
462
+ ...(parent && typeof parent === 'object' ? parent : {}),
463
+ callConfigAuthority: 'target',
464
+ delegationOwner: 'vision-chain',
465
+ }
466
+ const iterable = toolRuntime.run(state, () => stream.call(target, options))
467
+ return iterateUnderRuntimeState(iterable, state)
468
+ }
469
+ },
470
+ })
471
+ byRuntime.set(runtimeState, wrapped)
472
+ return wrapped
473
+ }
474
+
475
+ function wrapTransparentAdapter(adapter, runtimeState) {
476
+ if (!adapter || (typeof adapter !== 'object' && typeof adapter !== 'function')) return adapter
477
+ let byRuntime = wrappedTransparentAdapters.get(adapter)
478
+ if (!byRuntime) {
479
+ byRuntime = new WeakMap()
480
+ wrappedTransparentAdapters.set(adapter, byRuntime)
481
+ }
482
+ const cached = byRuntime.get(runtimeState)
483
+ if (cached) return cached
484
+ const wrapped = new Proxy(adapter, {
485
+ get(target, property) {
486
+ if (property !== 'stream') {
487
+ const value = Reflect.get(target, property, target)
488
+ return typeof value === 'function' ? value.bind(target) : value
489
+ }
490
+ const stream = Reflect.get(target, property, target)
491
+ if (typeof stream !== 'function') return stream
492
+ return function streamWithTransparentCallAuthority(options) {
493
+ const parent = toolRuntime.getStore()
494
+ const state = {
495
+ ...(parent && typeof parent === 'object' ? parent : {}),
496
+ callConfigAuthority: 'transparent',
497
+ transparentExplicitReasoning: explicitReasoningEffort(options),
498
+ transparentSessionId: sessionIdentity(options),
499
+ }
500
+ const iterable = toolRuntime.run(state, () => stream.call(target, options))
501
+ return iterateUnderRuntimeState(iterable, state)
502
+ }
503
+ },
504
+ })
505
+ byRuntime.set(runtimeState, wrapped)
506
+ return wrapped
507
+ }
508
+
312
509
  function wrapLlm(llm, runtimeState) {
313
510
  if (!llm || (typeof llm !== 'object' && typeof llm !== 'function')) return llm
314
511
  let byRuntime = wrappedLlms.get(llm)
@@ -320,14 +517,31 @@ function wrapLlm(llm, runtimeState) {
320
517
  if (cached) return cached
321
518
  const wrapped = new Proxy(llm, {
322
519
  get(target, property) {
520
+ if (property === 'stream') {
521
+ const stream = Reflect.get(target, property, target)
522
+ if (typeof stream !== 'function') return stream
523
+ return (options) => {
524
+ const state = toolRuntime.getStore()
525
+ const projected = state?.callConfigAuthority === 'target'
526
+ ? projectDelegatedCallConfig(options)
527
+ : state?.callConfigAuthority === 'transparent'
528
+ ? projectTransparentCallConfig(options, state, runtimeState)
529
+ : options
530
+ return stream.call(target, projected)
531
+ }
532
+ }
323
533
  if (property === 'registerAdapter') {
324
534
  const register = Reflect.get(target, property, target)
325
535
  if (typeof register !== 'function') return register
326
536
  return (routes, adapter, ...rest) => {
327
537
  const list = Array.isArray(routes) ? routes : [routes]
328
- const nextAdapter = list.some((route) => String(route) === 'vision-http')
329
- ? wrapVisionHttpAdapter(adapter, runtimeState)
330
- : adapter
538
+ const visionHttp = list.some((route) => String(route) === 'vision-http')
539
+ let nextAdapter = visionHttp ? wrapVisionHttpAdapter(adapter, runtimeState) : adapter
540
+ if (visionChainAdapter(nextAdapter, list)) {
541
+ nextAdapter = wrapDelegatingAdapter(nextAdapter, runtimeState)
542
+ } else if (!visionHttp && visionRouterOwnedAdapter(nextAdapter)) {
543
+ nextAdapter = wrapTransparentAdapter(nextAdapter, runtimeState)
544
+ }
331
545
  return register.call(target, routes, nextAdapter, ...rest)
332
546
  }
333
547
  }
@@ -363,7 +577,12 @@ async function executeVisionTool(def, args, exec, execute, wrappedCtx, runtimeSt
363
577
  }
364
578
  }
365
579
  const result = await execute(args, exec)
366
- if (cacheKey && runtimeState.config().cache !== false && !state.signal?.aborted) {
580
+ if (
581
+ cacheKey &&
582
+ runtimeState.config().cache !== false &&
583
+ !state.signal?.aborted &&
584
+ cacheableVisionDescribeResult(result)
585
+ ) {
367
586
  runtimeState.cache.set(cacheKey, result)
368
587
  }
369
588
  return result
@@ -506,4 +725,4 @@ export function installVisionToolRuntimeBoundary(ctx, initialConfig = {}) {
506
725
 
507
726
  export function getVisionToolRuntimeState(ctx) {
508
727
  return runtimeStates.get(ctx)
509
- }
728
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vision-router",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "Eyes for text-only DeepSeek Harness agents: built-in free vision chain (no key) + pixel-level vision tools (Q&A, grounding, crop, pixel diff, colors, OCR, SVG trace, cutout, screenshots). One-command install, no Python, image turns work like ordinary tool-calling turns.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -69,14 +69,14 @@
69
69
  "sharp": "^0.35.3"
70
70
  },
71
71
  "scripts": {
72
- "test": "node --test tests/adapter-prepare-call-compat.test.js tests/core.test.js tests/grounding-coordinate-frame.test.js tests/grounding-coordinate-runtime.test.js tests/capability-advisory.test.js tests/vision-execution-policy.test.js tests/vision-backend-diagnostics.test.js tests/live-model-discovery.test.js tests/live-model-credential-resolution.test.js tests/vision-model-registry.test.js tests/live-model-client-stability.test.js tests/providers-persistence.test.js tests/provider-directory-fallback.test.js tests/model-catalog-policy.test.js tests/settings-ia-client-prelude.test.js tests/settings-ia-fj.test.js tests/settings-ia-acceptance-regression.test.js tests/settings-migration.test.js tests/settings-section-order.test.js tests/attachment-admission-policy.test.js tests/vision-resilience.test.js tests/vision-resilience-lifecycle.test.js tests/vision-breaker-readonly.test.js tests/alpha1-browser-lifecycle-integration.test.js tests/issue-367-remote-session-inject.test.js tests/client.test.js tests/issue-307-regression.test.js tests/issue-284-vision-mode-toggle.test.js tests/issue-284-vision-mode-hardening.test.js tests/issue-284-attachment-id-hint.test.js tests/issue-284-model-visibility.test.js tests/issue-284-vision-selection-effort.test.js tests/client-presentation-boundary.test.js tests/remote-settings-bridge.test.js tests/remote-settings-v2-contract.test.js tests/remote-settings-risk-confirmation.test.js tests/local-remote-settings-permission.test.js tests/rc6-real-settings-persistence.test.js tests/artifact-path-security.test.js tests/http-compat.test.js tests/catalog-corrections.test.js tests/update-check.test.js tests/update-check-signal-lifecycle.test.js tests/self-update.test.js tests/doctor.test.js tests/doctor-cli.test.js tests/legacy-session-repair.test.js tests/profile-pnpm-diagnostics.test.js tests/doctor-v2.test.js tests/doctor-cli-v2.test.js tests/doctor-runtime.test.js tests/dsh-host-capabilities.test.js tests/doctor-host-capabilities.test.js tests/session-repair-v2.test.js tests/bundle-defaults.test.js tests/file-logger.test.js tests/replay-delegation.test.js tests/adversarial-hardening.test.js tests/vision-adversarial-hardening-v2.test.js tests/vision-capability-benchmark-visual-proof.test.js tests/wrapper-directory.test.js tests/logging-ui.test.js tests/manifest-dependencies.test.js tests/structured-bootstrap.test.js tests/structured-bootstrap-gate.test.js tests/local-ollama.test.js tests/ollama-cold-start.test.js tests/ollama-cold-start-loaded.test.js tests/zero-regression-gate.test.js tests/runtime-e2e.test.js tests/local-vision-stabilizer.test.js tests/local-connection-probe.test.js tests/repetition-guard.test.js tests/guide-scroll-gate.test.js tests/settings-scroll-jank-regression.test.js tests/android-attachment-compat.test.js tests/free-cloud-first.test.js tests/rc6-rc7-compat.test.js tests/native-image-coexistence.test.js tests/issue-276-session-image-ownership.test.js tests/issue-276-entry-policy-bridge.test.js tests/issue-276-policy-hardening.test.js tests/issue-289-native-nonintervention.test.js tests/pi-ai-bridge-wire-compat.test.js tests/mixed-router.test.js tests/depth-tier.test.js tests/depth-quota-behavior.test.js tests/structured-flow-hardening.test.js tests/structured-flow-adversarial.test.js tests/vision-budget-activation.test.js tests/runtime-boundary-fixes.test.js tests/runtime-i18n.test.js tests/tesseract-node24-boot.test.js tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/image-resource-governor.test.js tests/resource-retention-lifecycle.test.js tests/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/structured-guard-idempotency.test.js tests/vision-routing-product.test.js tests/vision-runtime-performance.test.js tests/vision-routing-settings-prelude.test.js tests/v2-settings-ia-integration.test.js tests/vision-capability-router.test.js tests/vision-capability-reference.test.js tests/vision-capability-benchmark.test.js tests/vision-capability-grounding-proof-contract.test.js tests/vision-capability-probe.test.js tests/vision-capability-shadow.test.js tests/vision-capability-axis-freshness.test.js tests/vision-capability-shadow-health.test.js tests/vision-capability-benchmark-service.test.js tests/vision-capability-preflight-hardening.test.js tests/vision-capability-benchmark-contract.test.js tests/vision-capability-benchmark-client.test.js tests/vision-capability-benchmark-client-productization.test.js tests/vision-capability-adapter-route.test.js tests/vision-background-benchmark.test.js tests/vision-background-lifecycle.test.js tests/vision-background-benchmark-productization.test.js tests/vision-capability-benchmark-budget.test.js tests/vision-image-input-verdict.test.js tests/vision-capability-failure-classification.test.js tests/vision-capability-gate-client.test.js tests/v2-product-review-fixes.test.js tests/qa-top5-reliability.test.js tests/qa-screenshot-runtime.test.js tests/qa-runtime-identity.test.js tests/qa-turn-budget-cancellation.test.js tests/qa-cancellation-publication.test.js tests/qa-reliability-tail.test.js tests/qa-endpoint-route-alias.test.js tests/settings-native-card-semantics.test.js tests/settings-native-card-lazy-data.test.js tests/settings-invalid-staged-dirty.test.js tests/vision-toggle-root-hardening.test.js && node --test tests/vision-backend-runtime-policy.test.js",
72
+ "test": "node --test tests/adapter-prepare-call-compat.test.js tests/core.test.js tests/issue-374-delegated-call-config.test.js tests/grounding-coordinate-frame.test.js tests/grounding-coordinate-runtime.test.js tests/capability-advisory.test.js tests/vision-execution-policy.test.js tests/vision-backend-diagnostics.test.js tests/live-model-discovery.test.js tests/live-model-credential-resolution.test.js tests/vision-model-registry.test.js tests/live-model-client-stability.test.js tests/providers-persistence.test.js tests/provider-directory-fallback.test.js tests/model-catalog-policy.test.js tests/settings-ia-client-prelude.test.js tests/settings-ia-fj.test.js tests/settings-ia-acceptance-regression.test.js tests/settings-migration.test.js tests/settings-section-order.test.js tests/attachment-admission-policy.test.js tests/vision-resilience.test.js tests/vision-resilience-lifecycle.test.js tests/vision-breaker-readonly.test.js tests/alpha1-browser-lifecycle-integration.test.js tests/issue-367-remote-session-inject.test.js tests/client.test.js tests/issue-307-regression.test.js tests/issue-284-vision-mode-toggle.test.js tests/issue-284-vision-mode-hardening.test.js tests/issue-284-attachment-id-hint.test.js tests/issue-284-model-visibility.test.js tests/issue-284-vision-selection-effort.test.js tests/client-presentation-boundary.test.js tests/remote-settings-bridge.test.js tests/remote-settings-v2-contract.test.js tests/remote-settings-risk-confirmation.test.js tests/local-remote-settings-permission.test.js tests/rc6-real-settings-persistence.test.js tests/artifact-path-security.test.js tests/http-compat.test.js tests/catalog-corrections.test.js tests/update-check.test.js tests/update-check-signal-lifecycle.test.js tests/self-update.test.js tests/doctor.test.js tests/doctor-cli.test.js tests/legacy-session-repair.test.js tests/profile-pnpm-diagnostics.test.js tests/doctor-v2.test.js tests/doctor-cli-v2.test.js tests/doctor-runtime.test.js tests/dsh-host-capabilities.test.js tests/doctor-host-capabilities.test.js tests/session-repair-v2.test.js tests/bundle-defaults.test.js tests/file-logger.test.js tests/replay-delegation.test.js tests/twin-image-capability-fallback.test.js tests/twin-image-custom-wrapper.test.js tests/adversarial-hardening.test.js tests/vision-adversarial-hardening-v2.test.js tests/vision-capability-benchmark-visual-proof.test.js tests/wrapper-directory.test.js tests/logging-ui.test.js tests/manifest-dependencies.test.js tests/structured-bootstrap.test.js tests/structured-bootstrap-gate.test.js tests/local-ollama.test.js tests/ollama-cold-start.test.js tests/ollama-cold-start-loaded.test.js tests/zero-regression-gate.test.js tests/runtime-e2e.test.js tests/local-vision-stabilizer.test.js tests/local-connection-probe.test.js tests/repetition-guard.test.js tests/guide-scroll-gate.test.js tests/settings-scroll-jank-regression.test.js tests/android-attachment-compat.test.js tests/free-cloud-first.test.js tests/rc6-rc7-compat.test.js tests/native-image-coexistence.test.js tests/issue-276-session-image-ownership.test.js tests/issue-276-entry-policy-bridge.test.js tests/issue-276-policy-hardening.test.js tests/issue-289-native-nonintervention.test.js tests/pi-ai-bridge-wire-compat.test.js tests/mixed-router.test.js tests/depth-tier.test.js tests/depth-quota-behavior.test.js tests/structured-flow-hardening.test.js tests/structured-flow-adversarial.test.js tests/vision-budget-activation.test.js tests/runtime-boundary-fixes.test.js tests/runtime-i18n.test.js tests/tesseract-node24-boot.test.js tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/image-resource-governor.test.js tests/resource-retention-lifecycle.test.js tests/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/structured-guard-idempotency.test.js tests/vision-routing-product.test.js tests/vision-runtime-performance.test.js tests/vision-routing-settings-prelude.test.js tests/v2-settings-ia-integration.test.js tests/vision-capability-router.test.js tests/vision-capability-reference.test.js tests/vision-capability-benchmark.test.js tests/vision-capability-grounding-proof-contract.test.js tests/vision-capability-probe.test.js tests/vision-capability-axis-freshness.test.js tests/vision-capability-shadow-health.test.js tests/vision-capability-benchmark-service.test.js tests/vision-capability-preflight-hardening.test.js tests/vision-capability-benchmark-contract.test.js tests/vision-capability-benchmark-client.test.js tests/vision-capability-benchmark-client-productization.test.js tests/vision-capability-adapter-route.test.js tests/vision-background-benchmark.test.js tests/vision-background-lifecycle.test.js tests/vision-background-benchmark-productization.test.js tests/vision-capability-benchmark-budget.test.js tests/vision-image-input-verdict.test.js tests/vision-capability-failure-classification.test.js tests/vision-capability-gate-client.test.js tests/v2-product-review-fixes.test.js tests/qa-top5-reliability.test.js tests/qa-screenshot-runtime.test.js tests/qa-runtime-identity.test.js tests/qa-turn-budget-cancellation.test.js tests/qa-cancellation-publication.test.js tests/qa-reliability-tail.test.js tests/qa-endpoint-route-alias.test.js tests/settings-native-card-semantics.test.js tests/settings-native-card-lazy-data.test.js tests/settings-invalid-staged-dirty.test.js tests/vision-toggle-root-hardening.test.js && node --test tests/vision-backend-runtime-policy.test.js",
73
73
  "test:core": "node --test tests/core.test.js tests/runtime-e2e.test.js tests/structured-bootstrap.test.js tests/structured-flow-hardening.test.js tests/structured-flow-adversarial.test.js tests/vision-execution-policy.test.js tests/vision-backend-runtime-policy.test.js",
74
- "test:routing": "node --test tests/vision-routing-product.test.js tests/vision-capability-router.test.js tests/vision-capability-probe.test.js tests/vision-capability-shadow.test.js tests/vision-capability-shadow-health.test.js tests/vision-runtime-performance.test.js tests/vision-background-benchmark.test.js tests/vision-image-input-verdict.test.js",
74
+ "test:routing": "node --test tests/issue-374-delegated-call-config.test.js tests/twin-image-capability-fallback.test.js tests/twin-image-custom-wrapper.test.js tests/vision-routing-product.test.js tests/vision-capability-router.test.js tests/vision-capability-probe.test.js tests/vision-capability-shadow-health.test.js tests/vision-runtime-performance.test.js tests/vision-background-benchmark.test.js tests/vision-image-input-verdict.test.js",
75
75
  "test:session": "node --test tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/replay-delegation.test.js tests/legacy-session-repair.test.js tests/session-repair-v2.test.js tests/issue-276-session-image-ownership.test.js",
76
76
  "test:resources": "node --test tests/artifact-path-security.test.js tests/image-resource-governor.test.js tests/resource-retention-lifecycle.test.js tests/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/qa-turn-budget-cancellation.test.js tests/qa-cancellation-publication.test.js",
77
77
  "test:compat": "node --test tests/adapter-prepare-call-compat.test.js tests/attachment-admission-policy.test.js tests/rc6-rc7-compat.test.js tests/rc6-real-settings-persistence.test.js tests/android-attachment-compat.test.js tests/http-compat.test.js tests/pi-ai-bridge-wire-compat.test.js tests/native-image-coexistence.test.js tests/tesseract-node24-boot.test.js tests/dsh-host-capabilities.test.js",
78
78
  "test:web": "node --test tests/alpha1-browser-lifecycle-integration.test.js tests/issue-367-remote-session-inject.test.js tests/client.test.js tests/client-presentation-boundary.test.js tests/settings-ia-client-prelude.test.js tests/settings-ia-acceptance-regression.test.js tests/remote-settings-bridge.test.js tests/remote-settings-v2-contract.test.js tests/local-remote-settings-permission.test.js tests/v2-settings-ia-integration.test.js tests/logging-ui.test.js",
79
- "test:contract": "node --test tests/manifest-dependencies.test.js tests/bundle-defaults.test.js tests/zero-regression-gate.test.js tests/issue-289-native-nonintervention.test.js tests/runtime-boundary-fixes.test.js tests/runtime-i18n.test.js tests/adapter-prepare-call-compat.test.js tests/rc6-rc7-compat.test.js tests/attachment-admission-policy.test.js tests/dsh-host-capabilities.test.js tests/doctor-host-capabilities.test.js tests/structured-bootstrap.test.js tests/structured-bootstrap-gate.test.js",
79
+ "test:contract": "node --test tests/manifest-dependencies.test.js tests/bundle-defaults.test.js tests/zero-regression-gate.test.js tests/issue-289-native-nonintervention.test.js tests/issue-374-delegated-call-config.test.js tests/runtime-boundary-fixes.test.js tests/runtime-i18n.test.js tests/adapter-prepare-call-compat.test.js tests/rc6-rc7-compat.test.js tests/attachment-admission-policy.test.js tests/dsh-host-capabilities.test.js tests/doctor-host-capabilities.test.js tests/structured-bootstrap.test.js tests/structured-bootstrap-gate.test.js",
80
80
  "test:grounding": "node --test tests/grounding-coordinate-frame.test.js tests/grounding-coordinate-runtime.test.js tests/vision-capability-grounding-proof-contract.test.js",
81
81
  "test:stress": "node scripts/image-resource-stress.mjs && node --test tests/large-image-resource-integration.test.js tests/resource-retention-lifecycle.test.js"
82
82
  },
@@ -96,4 +96,4 @@
96
96
  },
97
97
  "bundle": { "patch": "./cordis.patch.yml" }
98
98
  }
99
- }
99
+ }