@anionex/dsh-vision-toolkit 0.1.38 → 0.1.40
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.i18n.yaml +2 -2
- package/README.md +21 -42
- package/README.zh.md +20 -41
- package/assets/logo_eapi_dark.png +0 -0
- package/docs/aihubmix-gemini-vision.i18n.yaml +2 -2
- package/docs/aihubmix-gemini-vision.md +2 -2
- package/docs/aihubmix-gemini-vision.zh.md +2 -2
- package/docs/requirements-traceability/README.i18n.yaml +2 -2
- package/docs/requirements-traceability/README.md +1 -1
- package/docs/requirements-traceability/README.zh.md +1 -1
- package/lib/artifact-access.js +20 -2
- package/lib/artifact-access.js.map +1 -1
- package/lib/client.js +11 -3
- package/lib/client.js.map +1 -1
- package/lib/config.js +46 -2
- package/lib/config.js.map +1 -1
- package/lib/evidence-cache.js +2 -1
- package/lib/evidence-cache.js.map +1 -1
- package/lib/image-input-variants.js +61 -26
- package/lib/image-input-variants.js.map +1 -1
- package/lib/index.js +53 -6
- package/lib/index.js.map +1 -1
- package/lib/paste-images.js +67 -19
- package/lib/paste-images.js.map +1 -1
- package/lib/paths.js +214 -28
- package/lib/paths.js.map +1 -1
- package/lib/runtime-install.js +204 -19
- package/lib/runtime-install.js.map +1 -1
- package/lib/runtime-manager.js +76 -10
- package/lib/runtime-manager.js.map +1 -1
- package/lib/runtime.js +16 -10
- package/lib/runtime.js.map +1 -1
- package/lib/storage-history.js +154 -0
- package/lib/storage-history.js.map +1 -0
- package/lib/types/artifact-access.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +6 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/config.d.ts +24 -1
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/evidence-cache.d.ts +1 -1
- package/lib/types/evidence-cache.d.ts.map +1 -1
- package/lib/types/image-input-variants.d.ts +7 -4
- package/lib/types/image-input-variants.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/paste-images.d.ts +12 -4
- package/lib/types/paste-images.d.ts.map +1 -1
- package/lib/types/paths.d.ts +31 -5
- package/lib/types/paths.d.ts.map +1 -1
- package/lib/types/runtime-install.d.ts +21 -0
- package/lib/types/runtime-install.d.ts.map +1 -1
- package/lib/types/runtime-manager.d.ts +28 -4
- package/lib/types/runtime-manager.d.ts.map +1 -1
- package/lib/types/runtime.d.ts +4 -1
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/storage-history.d.ts +63 -0
- package/lib/types/storage-history.d.ts.map +1 -0
- package/lib/types/upstream.d.ts.map +1 -1
- package/lib/types/web.d.ts.map +1 -1
- package/lib/upstream.js +10 -0
- package/lib/upstream.js.map +1 -1
- package/lib/web.js +9 -3
- package/lib/web.js.map +1 -1
- package/package.json +1 -1
- package/src/artifact-access.ts +22 -2
- package/src/client/index.tsx +18 -3
- package/src/config.ts +76 -2
- package/src/evidence-cache.ts +2 -1
- package/src/image-input-variants.ts +61 -20
- package/src/index.ts +65 -6
- package/src/paste-images.ts +81 -19
- package/src/paths.ts +249 -28
- package/src/runtime-install.ts +231 -20
- package/src/runtime-manager.ts +93 -10
- package/src/runtime.ts +15 -9
- package/src/storage-history.ts +172 -0
- package/src/upstream.ts +10 -0
- package/src/web.ts +9 -2
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/** Durable configured-storage history used to authorize persisted image paths after Profile restarts. */
|
|
2
|
+
|
|
3
|
+
import type { Context, Fiber } from '@deepseek-ai/cordis'
|
|
4
|
+
import { defineDomain } from '@deepseek-ai/dsh-storage-domain'
|
|
5
|
+
import type { DomainGlobal } from '@deepseek-ai/dsh-storage-domain'
|
|
6
|
+
import { z } from 'zod'
|
|
7
|
+
import { resolveConfig, type VisionToolkitConfig } from './config.ts'
|
|
8
|
+
|
|
9
|
+
const storageHistoryStateSchema = z.object({
|
|
10
|
+
roots: z.array(z.string().min(1)),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
type StorageHistoryState = z.infer<typeof storageHistoryStateSchema>
|
|
14
|
+
|
|
15
|
+
/** Plugin-owned storage roots that survive Settings-provider and Profile restarts. */
|
|
16
|
+
export const storageHistoryDomainSpec = defineDomain({
|
|
17
|
+
name: 'vision_toolkit_storage',
|
|
18
|
+
version: 0,
|
|
19
|
+
global: {
|
|
20
|
+
schema: storageHistoryStateSchema,
|
|
21
|
+
initial: { roots: [] },
|
|
22
|
+
},
|
|
23
|
+
tables: {},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
interface StorageBinding {
|
|
27
|
+
accepting: boolean
|
|
28
|
+
global: DomainGlobal<StorageHistoryState>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function sameRoots(left: readonly string[], right: readonly string[]): boolean {
|
|
32
|
+
return left.length === right.length && left.every((root, index) => root === right[index])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Return every configured root that must remain readable, including the active root.
|
|
37
|
+
* @param config - Settings generation to summarize.
|
|
38
|
+
* @returns normalized configured roots in retention order.
|
|
39
|
+
*/
|
|
40
|
+
export function configuredStorageRoots(config: VisionToolkitConfig): string[] {
|
|
41
|
+
const resolved = resolveConfig(config)
|
|
42
|
+
return [...new Set([
|
|
43
|
+
...resolved.storageHistory,
|
|
44
|
+
...(resolved.storageDir === undefined ? [] : [resolved.storageDir]),
|
|
45
|
+
])]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Merge plugin-owned roots into a Settings generation without retaining its active root as history.
|
|
50
|
+
* @param config - Settings generation being restored.
|
|
51
|
+
* @param durableRoots - roots loaded from the plugin-owned sidecar.
|
|
52
|
+
* @returns the original generation when unchanged, otherwise a generation with restored history.
|
|
53
|
+
*/
|
|
54
|
+
export function restoreDurableStorageHistory(
|
|
55
|
+
config: VisionToolkitConfig,
|
|
56
|
+
durableRoots: readonly string[],
|
|
57
|
+
): VisionToolkitConfig {
|
|
58
|
+
const resolved = resolveConfig(config)
|
|
59
|
+
const storageHistory = [...new Set([...resolved.storageHistory, ...durableRoots])]
|
|
60
|
+
.filter(root => root !== resolved.storageDir)
|
|
61
|
+
if (sameRoots(storageHistory, resolved.storageHistory)) return config
|
|
62
|
+
return { ...config, storageHistory }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Optional storage-domain sidecar for storage roots that Settings cannot persist itself. */
|
|
66
|
+
export class StorageHistoryStore {
|
|
67
|
+
private storage: StorageBinding | undefined
|
|
68
|
+
private storageFiber: (Fiber & PromiseLike<Fiber>) | undefined
|
|
69
|
+
private storageReady: Promise<void> | undefined
|
|
70
|
+
private mutationTail: Promise<void> = Promise.resolve()
|
|
71
|
+
private desiredRoots: readonly string[] | undefined
|
|
72
|
+
private persistenceTicket = 0
|
|
73
|
+
private warned = false
|
|
74
|
+
|
|
75
|
+
constructor(private readonly ctx: Context) {
|
|
76
|
+
if (typeof ctx.inject !== 'function') return
|
|
77
|
+
this.storageFiber = ctx.inject(['storageDomain'], async (storageCtx: Context) => {
|
|
78
|
+
const domain = await storageCtx.storageDomain.open(storageHistoryDomainSpec)
|
|
79
|
+
const binding: StorageBinding = { accepting: true, global: domain.global }
|
|
80
|
+
this.storage = binding
|
|
81
|
+
try {
|
|
82
|
+
if (this.desiredRoots !== undefined) {
|
|
83
|
+
await this.write(binding, this.desiredRoots, this.persistenceTicket)
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.storage = undefined
|
|
87
|
+
await domain.close()
|
|
88
|
+
throw error
|
|
89
|
+
}
|
|
90
|
+
return async () => {
|
|
91
|
+
binding.accepting = false
|
|
92
|
+
if (this.storage === binding) this.storage = undefined
|
|
93
|
+
await this.mutationTail
|
|
94
|
+
await domain.close()
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
this.storageReady = Promise.resolve(this.storageFiber).then(
|
|
98
|
+
() => undefined,
|
|
99
|
+
(error: unknown) => { this.warnOnce(error) },
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Restore durable roots into one Settings generation before runtime preparation.
|
|
105
|
+
* @param config - Settings generation to restore.
|
|
106
|
+
* @returns the generation with available durable roots merged into its history.
|
|
107
|
+
*/
|
|
108
|
+
async restore(config: VisionToolkitConfig): Promise<VisionToolkitConfig> {
|
|
109
|
+
const binding = await this.prepareStorage()
|
|
110
|
+
return restoreDurableStorageHistory(config, binding?.global.get().roots ?? [])
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Persist the active and historical configured roots.
|
|
115
|
+
* @param config - validated generation whose roots must survive restart.
|
|
116
|
+
* @returns false when no storage-domain is available; true after persistence or when there are no roots.
|
|
117
|
+
*/
|
|
118
|
+
async persist(config: VisionToolkitConfig): Promise<boolean> {
|
|
119
|
+
const roots = configuredStorageRoots(config)
|
|
120
|
+
const ticket = ++this.persistenceTicket
|
|
121
|
+
this.desiredRoots = roots
|
|
122
|
+
if (roots.length === 0) return true
|
|
123
|
+
const binding = await this.prepareStorage()
|
|
124
|
+
if (binding === undefined) return false
|
|
125
|
+
await this.write(binding, roots, ticket)
|
|
126
|
+
return true
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Release the optional storage-domain binding with the plugin lifecycle. */
|
|
130
|
+
dispose(): void {
|
|
131
|
+
const fiber = this.storageFiber
|
|
132
|
+
this.storageFiber = undefined
|
|
133
|
+
this.storageReady = undefined
|
|
134
|
+
if (fiber !== undefined) void fiber.dispose().catch(error => { this.warnOnce(error) })
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private async prepareStorage(): Promise<StorageBinding | undefined> {
|
|
138
|
+
const current = this.activeStorage()
|
|
139
|
+
if (current !== undefined) return current
|
|
140
|
+
if (this.ctx.get('storageDomain') === undefined) return undefined
|
|
141
|
+
await this.storageReady
|
|
142
|
+
return this.activeStorage()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private activeStorage(): StorageBinding | undefined {
|
|
146
|
+
return this.storage?.accepting === true ? this.storage : undefined
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private write(binding: StorageBinding, roots: readonly string[], ticket: number): Promise<void> {
|
|
150
|
+
return this.enqueueMutation(async () => {
|
|
151
|
+
if (!binding.accepting) throw new Error('the storage-domain provider changed while storage history was pending')
|
|
152
|
+
if (ticket !== this.persistenceTicket) return
|
|
153
|
+
if (sameRoots(binding.global.get().roots, roots)) return
|
|
154
|
+
await binding.global.set({ roots: [...roots] })
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private enqueueMutation(operation: () => Promise<void>): Promise<void> {
|
|
159
|
+
const result = this.mutationTail.then(operation)
|
|
160
|
+
this.mutationTail = result.then(() => undefined, () => undefined)
|
|
161
|
+
return result
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private warnOnce(error: unknown): void {
|
|
165
|
+
if (this.warned) return
|
|
166
|
+
this.warned = true
|
|
167
|
+
this.ctx.logger?.warn(
|
|
168
|
+
'dsh-vision-toolkit: configured storage history sidecar is unavailable. %s',
|
|
169
|
+
(error instanceof Error ? error.message : String(error)).slice(0, 500),
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/upstream.ts
CHANGED
|
@@ -541,9 +541,19 @@ const VISION_MODEL_GUARD = [
|
|
|
541
541
|
' requested=prompt or vision_client.DEFAULT_PROMPT',
|
|
542
542
|
' return original_describe(image_url,f"{policy}\\n\\n{requested}",*args,**kwargs)',
|
|
543
543
|
' vision_client.describe_image=guarded_describe',
|
|
544
|
+
' ground_module=None',
|
|
545
|
+
' original_parse_matches=None',
|
|
546
|
+
' if Path(script).name in {"ground","detect"} and importlib.util.find_spec("ground") is not None:',
|
|
547
|
+
' import ground as ground_module',
|
|
548
|
+
' original_parse_matches=ground_module.parse_matches',
|
|
549
|
+
' def normalized_parse_matches(*args,**kwargs):',
|
|
550
|
+
' matches=original_parse_matches(*args,**kwargs)',
|
|
551
|
+
' return [ground_module.Match(" ".join(str(match.label).split()),match.bbox) for match in matches]',
|
|
552
|
+
' ground_module.parse_matches=normalized_parse_matches',
|
|
544
553
|
' try:',
|
|
545
554
|
' runpy.run_path(script,run_name="__main__")',
|
|
546
555
|
' finally:',
|
|
556
|
+
' if ground_module is not None: ground_module.parse_matches=original_parse_matches',
|
|
547
557
|
' vision_client.describe_image=original_describe',
|
|
548
558
|
].join('\n')
|
|
549
559
|
|
package/src/web.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from './paste-images.ts'
|
|
23
23
|
import {
|
|
24
24
|
resolveConfig,
|
|
25
|
+
retainedStorageHistory,
|
|
25
26
|
isBuiltInFreeVisionProvider,
|
|
26
27
|
VISION_TOOLKIT_SETTINGS_NAMESPACE,
|
|
27
28
|
type ResolvedVisionToolkitConfig,
|
|
@@ -303,16 +304,22 @@ export class VisionToolkitWebBackend {
|
|
|
303
304
|
|
|
304
305
|
private async save(request: SaveRequest): Promise<VisionToolkitSettingsSnapshot> {
|
|
305
306
|
if (!this.ctx.settings.writable) throw new Error('settings provider is read-only')
|
|
307
|
+
const current = resolveConfig(descriptorOf(this.ctx).value as VisionToolkitConfig)
|
|
308
|
+
const storageHistory = retainedStorageHistory(request.value, current)
|
|
309
|
+
const value: VisionToolkitConfig = {
|
|
310
|
+
...request.value,
|
|
311
|
+
...(storageHistory.length === 0 ? {} : { storageHistory }),
|
|
312
|
+
}
|
|
306
313
|
let candidate: PreparedRuntimeGeneration
|
|
307
314
|
try {
|
|
308
|
-
candidate = await this.manager.prepareCandidate(
|
|
315
|
+
candidate = await this.manager.prepareCandidate(value)
|
|
309
316
|
} catch (error) {
|
|
310
317
|
this.manager.recordFailure(error)
|
|
311
318
|
throw error
|
|
312
319
|
}
|
|
313
320
|
await this.ctx.settings.replace(
|
|
314
321
|
VISION_TOOLKIT_SETTINGS_NAMESPACE,
|
|
315
|
-
|
|
322
|
+
value as object,
|
|
316
323
|
request.expectedRevision,
|
|
317
324
|
)
|
|
318
325
|
this.manager.activateCandidate(candidate)
|