@anionex/dsh-vision-toolkit 0.1.7 → 0.1.8

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/lib/web.js CHANGED
@@ -7,10 +7,10 @@
7
7
  import { credentialRef } from '@deepseek-ai/dsh-credentials';
8
8
  import { SettingsConflictError } from '@deepseek-ai/dsh-settings';
9
9
  import { ARTIFACT_ROUTE_PREFIX } from "./artifact-access.js";
10
- import { PASTE_IMAGES_ROUTE } from "./paste-images.js";
10
+ import { PASTE_IMAGES_ROUTE, PASTE_POLICY_ROUTE, } from "./paste-images.js";
11
11
  import { resolveConfig, VISION_TOOLKIT_SETTINGS_NAMESPACE, } from "./config.js";
12
12
  import { PLUGIN_VERSION, UPSTREAM_COMMIT, UPSTREAM_REPOSITORY, UPSTREAM_VERSION } from "./version.js";
13
- import { sameOriginPost } from "./web-request.js";
13
+ import { sameOriginPost, sameOriginRequest } from "./web-request.js";
14
14
  /** Exact route used by the browser Settings page. */
15
15
  export const SETTINGS_ROUTE = '/_dsh/vision-toolkit/settings';
16
16
  function isRecord(value) {
@@ -260,13 +260,85 @@ export class VisionToolkitWebBackend {
260
260
  }
261
261
  }
262
262
  }
263
+ /**
264
+ * Same-origin policy handler for the paste route: whether the browser should
265
+ * take a paste over into workspace paths, or let it flow natively after an
266
+ * optional automatic switch to the image-input variant. The optional `model`
267
+ * query carries the model-selector label the client currently shows; the
268
+ * optional `provider`/`modelId`/`reasoningEffort` queries carry the exact
269
+ * route the client read from the live model catalog, which the resolver
270
+ * prefers (a label alone cannot pick a provider). Unresolvable routes answer
271
+ * native — the safe default.
272
+ * @param resolve - resolves one live Session's paste verdict.
273
+ * @returns the HTTP handler.
274
+ */
275
+ export function createPastePolicyHandler(resolve) {
276
+ return (req, res) => {
277
+ void (async () => {
278
+ try {
279
+ if (req.method !== 'GET') {
280
+ requestError(res, 405, 'method-not-allowed', 'Use GET');
281
+ return;
282
+ }
283
+ if (!sameOriginRequest(req)) {
284
+ requestError(res, 403, 'origin-rejected', 'The request must originate from this DSH Web application');
285
+ return;
286
+ }
287
+ let sessionId;
288
+ let modelLabel;
289
+ let selection;
290
+ try {
291
+ const url = new URL(req.url ?? PASTE_POLICY_ROUTE, 'http://dsh.internal');
292
+ const sessions = url.searchParams.getAll('sessionId');
293
+ if (sessions.length !== 1 || sessions[0] === undefined || sessions[0] === '') {
294
+ throw new TypeError('sessionId is required exactly once');
295
+ }
296
+ sessionId = sessions[0];
297
+ const models = url.searchParams.getAll('model');
298
+ if (models.length > 1)
299
+ throw new TypeError('model may be given at most once');
300
+ modelLabel = models[0];
301
+ const providers = url.searchParams.getAll('provider');
302
+ if (providers.length > 1)
303
+ throw new TypeError('provider may be given at most once');
304
+ const modelIds = url.searchParams.getAll('modelId');
305
+ if (modelIds.length > 1)
306
+ throw new TypeError('modelId may be given at most once');
307
+ const efforts = url.searchParams.getAll('reasoningEffort');
308
+ if (efforts.length > 1)
309
+ throw new TypeError('reasoningEffort may be given at most once');
310
+ const provider = providers[0];
311
+ const modelId = modelIds[0];
312
+ if (provider !== undefined && modelId !== undefined && provider !== '' && modelId !== '') {
313
+ selection = {
314
+ provider,
315
+ model: modelId,
316
+ ...(efforts[0] === undefined || efforts[0] === '' ? {} : { reasoningEffort: efforts[0] }),
317
+ };
318
+ }
319
+ }
320
+ catch (error) {
321
+ requestError(res, 400, 'invalid-request', publicMessage(error));
322
+ return;
323
+ }
324
+ const verdict = await resolve(sessionId, selection, modelLabel);
325
+ responseJson(res, 200, { ok: true, value: verdict });
326
+ }
327
+ catch (error) {
328
+ requestError(res, 500, 'policy-failed', publicMessage(error));
329
+ }
330
+ })();
331
+ };
332
+ }
263
333
  /**
264
334
  * Attach optional Web routes whenever a webServer service is present.
265
335
  * @param ctx - plugin context owning route effects.
266
336
  * @param backend - Settings handler.
267
337
  * @param artifacts - signed Artifact handler.
338
+ * @param pastedImages - pasted-image workspace handler.
339
+ * @param pastePolicy - paste-policy verdict resolver (sessionId, selection, modelLabel).
268
340
  */
269
- export function installVisionToolkitWeb(ctx, backend, artifacts, pastedImages) {
341
+ export function installVisionToolkitWeb(ctx, backend, artifacts, pastedImages, pastePolicy) {
270
342
  ctx.inject(['webServer'], (webCtx) => {
271
343
  webCtx.effect(() => {
272
344
  const detach = artifacts.attachRoute();
@@ -285,7 +357,13 @@ export function installVisionToolkitWeb(ctx, backend, artifacts, pastedImages) {
285
357
  path: PASTE_IMAGES_ROUTE,
286
358
  handler: (req, res) => pastedImages.handle(req, res),
287
359
  });
360
+ const disposePastePolicy = webCtx.webServer.register({
361
+ kind: 'exact',
362
+ path: PASTE_POLICY_ROUTE,
363
+ handler: createPastePolicyHandler(pastePolicy),
364
+ });
288
365
  return () => {
366
+ disposePastePolicy();
289
367
  disposePasteImages();
290
368
  disposeSettings();
291
369
  disposeArtifact();
package/lib/web.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anionex/dsh-vision-toolkit",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "DeepSeek Harness-native integration for agent-vision-toolkit: image Q&A, OCR, grounding, UI restoration, pixel diff, Artifacts, and Web UI.",
5
5
  "keywords": [
6
6
  "deepseek",
@@ -95,6 +95,7 @@
95
95
  "peerDependencies": {
96
96
  "@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
97
97
  "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6",
98
+ "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6",
98
99
  "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6",
99
100
  "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.6",
100
101
  "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.6",
@@ -8,9 +8,12 @@ import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
8
8
 
9
9
  const SOURCE = 'vision-toolkit-pasted-image'
10
10
  export const PASTE_IMAGES_ROUTE = '/_dsh/vision-toolkit/paste-images'
11
+ export const PASTE_POLICY_ROUTE = '/_dsh/vision-toolkit/paste-policy'
11
12
  const MAX_IMAGES = 20
12
13
  const MAX_IMAGE_BYTES = 20 * 1024 * 1024
13
14
  const MAX_BATCH_BYTES = 80 * 1024 * 1024
15
+ /** A confirmed paste verdict older than this is unknown again, even while a refresh is in flight. */
16
+ const VERDICT_MAX_AGE_MS = 15000
14
17
 
15
18
  interface PasteRecord {
16
19
  ref: string
@@ -28,6 +31,20 @@ interface PasteBatch {
28
31
  unsubscribe?: (() => void) | undefined
29
32
  }
30
33
 
34
+ /** One model route the host asks the browser to switch to before the native paste flow. */
35
+ interface PasteSwitchRoute {
36
+ provider: string
37
+ model: string
38
+ label: string
39
+ reasoningEffort?: string
40
+ }
41
+
42
+ /** A fresh host verdict for one Session and model label. */
43
+ interface PasteVerdictValue {
44
+ takeOver: boolean
45
+ autoSwitch?: PasteSwitchRoute
46
+ }
47
+
31
48
  interface PasteResponse {
32
49
  ok: boolean
33
50
  value?: { absolutePath?: string }
@@ -105,6 +122,26 @@ function imageFiles(data: DataTransfer | null): File[] {
105
122
  return candidates.filter(file => file.type.toLowerCase().startsWith('image/'))
106
123
  }
107
124
 
125
+ /**
126
+ * The selector label the model picker currently shows, or '' when none is
127
+ * readable. Matches the host ModelSelect trigger aria-labels ("Select model,
128
+ * current …" / "选择模型,当前 …"); any other label wording falls back to the
129
+ * session-header verdict, which is stale until the next request.
130
+ */
131
+ function currentModelLabel(): string {
132
+ const buttons = document.querySelectorAll('button[aria-label]')
133
+ for (const button of buttons) {
134
+ const label = button.getAttribute('aria-label') ?? ''
135
+ if (/select model|current model|选择模型/iu.test(label)) return label
136
+ }
137
+ return ''
138
+ }
139
+
140
+ /** Verdict cache key: the model label is part of the answer, so a switch invalidates it. */
141
+ function verdictKey(sessionId: string, modelLabel: string): string {
142
+ return `${sessionId}|${modelLabel}`
143
+ }
144
+
108
145
  function validateImages(files: readonly File[]): void {
109
146
  if (files.length > MAX_IMAGES) throw new Error(`Paste at most ${MAX_IMAGES} images at a time`)
110
147
  let total = 0
@@ -132,6 +169,14 @@ export class PasteImageController {
132
169
  private readonly records = new Map<string, PasteRecord>()
133
170
  private readonly listeners = new Set<() => void>()
134
171
  private revision = 0
172
+ private readonly verdicts = new Map<string, {
173
+ takeOver: boolean
174
+ autoSwitch?: PasteSwitchRoute
175
+ at: number
176
+ pending: boolean
177
+ }>()
178
+ /** Guards the synthetic replay paste from re-entering capture interception. */
179
+ private replaying = false
135
180
 
136
181
  constructor(private readonly ctx: ClientContext) {}
137
182
 
@@ -234,29 +279,254 @@ export class PasteImageController {
234
279
  }
235
280
  }
236
281
 
237
- handlePaste(event: ClipboardEvent): boolean {
238
- const files = imageFiles(event.clipboardData)
239
- if (files.length === 0) return false
240
- const target = event.target
241
- if (!(target instanceof HTMLTextAreaElement) || target.closest('[data-composer-card]') === null) return false
282
+ /**
283
+ * The host's verdict for one Session and selector label, when fresh. The
284
+ * last CONFIRMED answer is authoritative while a background refresh is in
285
+ * flight (the paste acts on what the host last said; the refresh only
286
+ * covers the next paste). A label that changed since the confirmation
287
+ * answers undefined, so the native attachment flow stays the default.
288
+ * @param sessionId - the live Session the paste belongs to.
289
+ * @param modelLabel - the model-selector label currently shown.
290
+ * @returns the fresh confirmed verdict, or undefined when unconfirmed.
291
+ */
292
+ private verdictFor(sessionId: string, modelLabel: string): PasteVerdictValue | undefined {
293
+ const entry = this.verdicts.get(verdictKey(sessionId, modelLabel))
294
+ if (entry === undefined || entry.at === 0) return undefined
295
+ if (Date.now() - entry.at > VERDICT_MAX_AGE_MS) return undefined
296
+ return { takeOver: entry.takeOver, ...(entry.autoSwitch === undefined ? {} : { autoSwitch: entry.autoSwitch }) }
297
+ }
242
298
 
243
- event.preventDefault()
244
- event.stopPropagation()
245
- event.stopImmediatePropagation()
299
+ /**
300
+ * The exact model route the live model catalog reports for one Session.
301
+ * Unreadable routes answer undefined, so the verdict falls back to the
302
+ * selector label alone.
303
+ * @param sessionId - the live Session id.
304
+ * @returns the current provider/model selection, when readable.
305
+ */
306
+ private async readSelection(sessionId: string): Promise<{ provider: string; model: string; reasoningEffort?: string } | undefined> {
307
+ const connection = this.ctx.get('connection') as { api: { sessions: {
308
+ models(request: { sessionId: string }): Promise<{ result: {
309
+ ok: true
310
+ value: { current?: { provider: string; model: string; reasoningEffort?: string } | null }
311
+ } | { ok: false; error: { code: string; message: string } } }>
312
+ } } } | undefined
313
+ if (connection === undefined) return undefined
314
+ try {
315
+ const { result } = await connection.api.sessions.models({ sessionId })
316
+ if (!result.ok) return undefined
317
+ const current = result.value.current
318
+ if (current === undefined || current === null || current.provider === '' || current.model === '') return undefined
319
+ return {
320
+ provider: current.provider,
321
+ model: current.model,
322
+ ...(current.reasoningEffort === undefined ? {} : { reasoningEffort: current.reasoningEffort }),
323
+ }
324
+ } catch {
325
+ return undefined
326
+ }
327
+ }
246
328
 
247
- const sessionId = this.ctx.sessions.list.getSnapshot().current
248
- if (sessionId === undefined) return true
329
+ /**
330
+ * Ask the host what to do with a paste for the current model, and cache the
331
+ * answer per Session and selector label. A model switch changes the label,
332
+ * which changes the cache key, so a stale verdict never outlives the model
333
+ * it described. The exact selection rides along when the live model catalog
334
+ * is readable, so the host can answer with an auto-switch route; a 404
335
+ * simply leaves the verdict unconfirmed; the next focus or paste retries.
336
+ * @param sessionId - the live Session to ask about.
337
+ * @param modelLabel - the model-selector label currently shown.
338
+ */
339
+ refreshVerdict(sessionId: string, modelLabel: string): void {
340
+ const key = verdictKey(sessionId, modelLabel)
341
+ const cached = this.verdicts.get(key)
342
+ // Dedupe only on an in-flight request, never on freshness: the host's
343
+ // model route can change under an unchanged Session id.
344
+ if (cached?.pending) return
345
+ const entry = {
346
+ pending: true,
347
+ takeOver: cached ? cached.takeOver : false,
348
+ at: cached ? cached.at : 0,
349
+ ...(cached?.autoSwitch === undefined ? {} : { autoSwitch: cached.autoSwitch }),
350
+ }
351
+ this.verdicts.set(key, entry)
352
+ void (async () => {
353
+ const selection = await this.readSelection(sessionId)
354
+ const query = new URLSearchParams({ sessionId })
355
+ if (modelLabel !== '') query.set('model', modelLabel)
356
+ if (selection !== undefined) {
357
+ query.set('provider', selection.provider)
358
+ query.set('modelId', selection.model)
359
+ if (selection.reasoningEffort !== undefined) query.set('reasoningEffort', selection.reasoningEffort)
360
+ }
361
+ let request: Promise<Response>
362
+ try {
363
+ request = fetch(`${PASTE_POLICY_ROUTE}?${query.toString()}`)
364
+ } catch {
365
+ // No fetch surface (test runtime, pre-fetch bootstrap): leave the
366
+ // verdict unconfirmed rather than letting the paste listener die.
367
+ entry.pending = false
368
+ return
369
+ }
370
+ request
371
+ .then((response) => {
372
+ if (response.status === 404) {
373
+ // Route not mounted yet (plugin load race, hot reload): forget every
374
+ // verdict and retry on the next focus or paste instead of standing
375
+ // down for the page lifetime.
376
+ this.verdicts.clear()
377
+ return null
378
+ }
379
+ if (!response.ok) throw new Error(`paste policy ${response.status}`)
380
+ return response.json() as Promise<{ ok: true; value: PasteVerdictValue }>
381
+ })
382
+ .then((body) => {
383
+ entry.pending = false
384
+ if (body !== null) {
385
+ entry.takeOver = body.value.takeOver === true
386
+ if (body.value.autoSwitch !== undefined) entry.autoSwitch = body.value.autoSwitch
387
+ else delete entry.autoSwitch
388
+ entry.at = Date.now()
389
+ }
390
+ })
391
+ .catch(() => {
392
+ entry.pending = false
393
+ })
394
+ })()
395
+ }
396
+
397
+ /**
398
+ * Switch one Session to the route the host validated, through the same
399
+ * model-directory seat the selector uses when present (so the shared UI
400
+ * state moves with the session), falling back to the raw RPC.
401
+ * @param sessionId - the live Session id.
402
+ * @param route - the validated variant route.
403
+ */
404
+ private async switchModel(sessionId: string, route: PasteSwitchRoute): Promise<void> {
405
+ const directories = this.ctx.get('modelDirectories') as {
406
+ directoryFor(id: string): { select(selection: { provider: string; model: string; reasoningEffort?: string }): Promise<void> }
407
+ } | undefined
408
+ if (directories !== undefined) {
409
+ // The label is a display hint; the seat only needs the exact route.
410
+ await directories.directoryFor(sessionId).select({
411
+ provider: route.provider,
412
+ model: route.model,
413
+ ...(route.reasoningEffort === undefined ? {} : { reasoningEffort: route.reasoningEffort }),
414
+ })
415
+ return
416
+ }
417
+ const connection = this.ctx.get('connection') as { api: { sessions: {
418
+ selectModel(request: {
419
+ sessionId: string
420
+ provider: string
421
+ model: string
422
+ reasoningEffort?: string
423
+ }): Promise<{ result: { ok: boolean; error?: { code: string; message: string } } }>
424
+ } } } | undefined
425
+ if (connection === undefined) throw new Error('No model switch channel is available in this Web application')
426
+ const { result } = await connection.api.sessions.selectModel({
427
+ sessionId,
428
+ provider: route.provider,
429
+ model: route.model,
430
+ ...(route.reasoningEffort === undefined ? {} : { reasoningEffort: route.reasoningEffort }),
431
+ })
432
+ if (!result.ok) throw new Error(`${result.error?.code ?? 'select-model-failed'}: ${result.error?.message ?? 'unknown error'}`)
433
+ }
434
+
435
+ /**
436
+ * Replay a swallowed paste as a synthetic clipboard event so the composer's
437
+ * own intake (limits, thumbnails, keyboard) runs with the captured files.
438
+ * @returns false when the environment cannot construct a clipboard payload.
439
+ */
440
+ private replayPaste(target: HTMLTextAreaElement, files: readonly File[], text: string): boolean {
441
+ let data: DataTransfer
442
+ try {
443
+ data = new DataTransfer()
444
+ for (const file of files) data.items.add(file)
445
+ if (text !== '') data.setData('text/plain', text)
446
+ } catch {
447
+ return false
448
+ }
449
+ let event: ClipboardEvent
450
+ try {
451
+ event = new ClipboardEvent('paste', {
452
+ clipboardData: data,
453
+ bubbles: true,
454
+ cancelable: true,
455
+ } as ClipboardEventInit)
456
+ } catch {
457
+ return false
458
+ }
459
+ if (event.clipboardData === null || event.clipboardData.files.length === 0) return false
460
+ this.replaying = true
461
+ try {
462
+ target.dispatchEvent(event)
463
+ } finally {
464
+ this.replaying = false
465
+ }
466
+ return true
467
+ }
468
+
469
+ /**
470
+ * Auto-switch flow: switch the Session to the image-input variant, announce
471
+ * it, then replay the paste into the composer's native intake. A failed
472
+ * switch, or an environment that cannot replay clipboard bytes, degrades to
473
+ * the path takeover with the same files.
474
+ * @param sessionId - the live Session id.
475
+ * @param target - the composer textarea the paste landed on.
476
+ * @param files - the captured image files.
477
+ * @param text - same-paste text, replayed alongside the files.
478
+ * @param route - the validated variant route to switch to.
479
+ */
480
+ private async autoSwitchPaste(
481
+ sessionId: string,
482
+ target: HTMLTextAreaElement,
483
+ files: readonly File[],
484
+ text: string,
485
+ route: PasteSwitchRoute,
486
+ ): Promise<void> {
249
487
  const input = this.inputFor(sessionId)
250
- const snapshot = input.state.getSnapshot()
251
- if (snapshot.phase !== 'plain') return true
488
+ try {
489
+ await this.switchModel(sessionId, route)
490
+ input.notify('info', `Switched to ${route.label || `${route.model} (Vision Toolkit)`}; pasted images now keep the native attachment flow`)
491
+ } catch (error) {
492
+ input.notify('error', `Model switch failed; images will be sent as workspace paths: ${message(error)}`)
493
+ this.takeoverPaste(sessionId, target, files, text)
494
+ return
495
+ }
496
+ // Replaying lets the composer's own intake run (thumbnail, limits,
497
+ // keyboard); if the environment cannot replay clipboard bytes, the
498
+ // images still land as workspace paths.
499
+ const before = input.state.getSnapshot().imageIds.length
500
+ const replayed = this.replayPaste(target, files, text)
501
+ const after = input.state.getSnapshot().imageIds.length
502
+ if (!replayed || after <= before) {
503
+ this.takeoverPaste(sessionId, target, files, text)
504
+ }
505
+ }
252
506
 
507
+ /**
508
+ * Path-takeover flow: insert the same-paste text and every image as a text
509
+ * reference that serializes to the image's workspace path on send.
510
+ * @param sessionId - the live Session id.
511
+ * @param target - the composer textarea the paste landed on.
512
+ * @param files - the captured image files.
513
+ * @param text - same-paste text.
514
+ */
515
+ private takeoverPaste(
516
+ sessionId: string,
517
+ target: HTMLTextAreaElement,
518
+ files: readonly File[],
519
+ text: string,
520
+ ): void {
521
+ const input = this.inputFor(sessionId)
522
+ const snapshot = input.state.getSnapshot()
523
+ if (snapshot.phase !== 'plain') return
253
524
  const start = Math.max(0, Math.min(target.selectionStart ?? snapshot.draft.length, snapshot.draft.length))
254
525
  const end = Math.max(start, Math.min(target.selectionEnd ?? start, snapshot.draft.length))
255
- const text = (event.clipboardData?.getData('text/plain') ?? '').replaceAll('\uFFFC', '')
256
526
  try {
257
527
  let cursor = this.insertText(input, text, start, end)
258
528
  validateImages(files)
259
- cursor = this.insertRecords(String(sessionId), input, files, cursor)
529
+ cursor = this.insertRecords(sessionId, input, files, cursor)
260
530
  requestAnimationFrame(() => {
261
531
  target.focus({ preventScroll: true })
262
532
  target.setSelectionRange(cursor, cursor)
@@ -264,6 +534,43 @@ export class PasteImageController {
264
534
  } catch (error) {
265
535
  input.notify('error', message(error))
266
536
  }
537
+ }
538
+
539
+ handlePaste(event: ClipboardEvent): boolean {
540
+ if (this.replaying) return false
541
+ const files = imageFiles(event.clipboardData)
542
+ if (files.length === 0) return false
543
+ const target = event.target
544
+ if (!(target instanceof HTMLTextAreaElement) || target.closest('[data-composer-card]') === null) return false
545
+
546
+ const sessionId = this.ctx.sessions.list.getSnapshot().current
547
+ if (sessionId === undefined) return false
548
+ const modelLabel = currentModelLabel()
549
+ this.refreshVerdict(sessionId, modelLabel)
550
+ // Only a fresh host verdict acts; the native attachment flow stays the
551
+ // default while the host is unconfirmed.
552
+ const verdict = this.verdictFor(sessionId, modelLabel)
553
+ if (verdict === undefined) return false
554
+ // An image-capable model (the variant routes included) keeps its native
555
+ // paste: no switch, no takeover.
556
+ if (verdict.takeOver === false && verdict.autoSwitch === undefined) return false
557
+
558
+ event.preventDefault()
559
+ event.stopPropagation()
560
+ event.stopImmediatePropagation()
561
+
562
+ const input = this.inputFor(sessionId)
563
+ if (input.state.getSnapshot().phase !== 'plain') return true
564
+
565
+ const text = (event.clipboardData?.getData('text/plain') ?? '').replaceAll('\uFFFC', '')
566
+ if (verdict.autoSwitch !== undefined) {
567
+ // The text-only model has an image-input variant: switch first, then
568
+ // let the paste flow natively so the thumbnail and durable session
569
+ // image are preserved.
570
+ void this.autoSwitchPaste(sessionId, target, files, text, verdict.autoSwitch)
571
+ return true
572
+ }
573
+ this.takeoverPaste(sessionId, target, files, text)
267
574
  return true
268
575
  }
269
576
 
@@ -411,8 +718,17 @@ export function installPasteImages(ctx: ClientContext): void {
411
718
  })
412
719
  ctx.effect(() => {
413
720
  const listener = (event: ClipboardEvent): void => { controller.handlePaste(event) }
721
+ // A focus-time prefetch has the verdict ready before the first paste can land.
722
+ const onFocusIn = (): void => {
723
+ const sessionId = ctx.sessions.list.getSnapshot().current
724
+ if (sessionId !== undefined) controller.refreshVerdict(String(sessionId), currentModelLabel())
725
+ }
414
726
  document.addEventListener('paste', listener, true)
415
- return () => { document.removeEventListener('paste', listener, true) }
727
+ document.addEventListener('focusin', onFocusIn, true)
728
+ return () => {
729
+ document.removeEventListener('paste', listener, true)
730
+ document.removeEventListener('focusin', onFocusIn, true)
731
+ }
416
732
  }, 'dsh-vision-toolkit: clipboard image capture')
417
733
  ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({
418
734
  name: 'conversation.input.dock',
package/src/config.ts CHANGED
@@ -54,6 +54,27 @@ export interface VisionToolkitConfig {
54
54
  }
55
55
  /** Extra directories (besides the workspace) inputs may come from. */
56
56
  allowedDirs?: string[]
57
+ /**
58
+ * Image-input variants: sibling model-selector entries for every model the
59
+ * host positively declares text-only. A variant declares image input, so
60
+ * pasted images keep the native attachment flow (composer thumbnail and
61
+ * durable session image), and the plugin rewrites image blocks into Vision
62
+ * Toolkit descriptions only on the wire to the model.
63
+ */
64
+ imageInputVariants?: {
65
+ /** Whether variant routes are registered at all (default true). */
66
+ enabled?: boolean
67
+ /** Restrict wrapped upstream routes by provider id; empty wraps every eligible route. */
68
+ providers?: string[]
69
+ /**
70
+ * Whether the browser paste integration automatically switches the Session
71
+ * to the image-input variant of a text-only model before the paste, so
72
+ * pasted images keep the native attachment flow with no manual model
73
+ * change. Off means a text-only model keeps the path takeover (default
74
+ * true).
75
+ */
76
+ autoSwitch?: boolean
77
+ }
57
78
  }
58
79
 
59
80
  /** Configuration schema with the documented P0 defaults. */
@@ -77,6 +98,11 @@ export const Config: Schema<VisionToolkitConfig> = z.object({
77
98
  python: z.string(),
78
99
  }),
79
100
  allowedDirs: z.array(z.string()).default([]),
101
+ imageInputVariants: z.object({
102
+ enabled: z.boolean().default(true),
103
+ providers: z.array(z.string()).default([]),
104
+ autoSwitch: z.boolean().default(true),
105
+ }),
80
106
  })
81
107
 
82
108
  /** Configuration after static validation, with every default materialized. */
@@ -100,6 +126,11 @@ export interface ResolvedVisionToolkitConfig {
100
126
  python?: string
101
127
  }
102
128
  allowedDirs: string[]
129
+ imageInputVariants: {
130
+ enabled: boolean
131
+ providers: string[]
132
+ autoSwitch: boolean
133
+ }
103
134
  }
104
135
 
105
136
  const MAX_TIMEOUT_MS = 600000
@@ -187,6 +218,10 @@ export function resolveConfig(config: VisionToolkitConfig = {}): ResolvedVisionT
187
218
  throw new VisionToolkitError('config', 'runtime.python must not be empty')
188
219
  }
189
220
  const allowedDirs = (config.allowedDirs ?? []).map(dir => dir.trim()).filter(dir => dir.length > 0)
221
+ const imageInputVariants = config.imageInputVariants ?? {}
222
+ const variantProviders = (imageInputVariants.providers ?? [])
223
+ .map(provider => provider.trim())
224
+ .filter(provider => provider.length > 0)
190
225
  return {
191
226
  provider: { baseUrl, credential, model, protocol, anthropicThinking, userAgent },
192
227
  language,
@@ -200,5 +235,10 @@ export function resolveConfig(config: VisionToolkitConfig = {}): ResolvedVisionT
200
235
  ...(python !== undefined ? { python } : {}),
201
236
  },
202
237
  allowedDirs,
238
+ imageInputVariants: {
239
+ enabled: imageInputVariants.enabled ?? true,
240
+ providers: variantProviders,
241
+ autoSwitch: imageInputVariants.autoSwitch ?? true,
242
+ },
203
243
  }
204
244
  }