@mengruo/dsh-vision-toolkit 0.0.1
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/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +356 -0
- package/README.zh.md +354 -0
- package/assets/community-group-qr.png +0 -0
- package/assets/dsh-conversation-artifact.png +0 -0
- package/assets/dsh-conversation-image-qa-top.png +0 -0
- package/assets/dsh-conversation-image-qa.png +0 -0
- package/assets/dsh-conversation-pixel-diff.png +0 -0
- package/assets/dsh-conversation-screenshot-debugging-top.png +0 -0
- package/assets/dsh-conversation-screenshot-debugging.png +0 -0
- package/assets/dsh-conversation-tool-call.png +0 -0
- package/assets/dsh-conversation-vision-trace.png +0 -0
- package/assets/dsh-view-example.png +0 -0
- package/assets/hero-v2.png +0 -0
- package/assets/logo_aihubmix.png +0 -0
- package/assets/python-bootstrap.json +48 -0
- package/assets/skill/SKILL.md +329 -0
- package/assets/skill/UPSTREAM.json +71 -0
- package/assets/skill/references/gui.md +88 -0
- package/assets/skill/references/long-screenshot-ocr.md +77 -0
- package/assets/skill/references/restore-graphic.md +84 -0
- package/assets/skill/references/restore-structure.md +45 -0
- package/assets/skill/references/restore-ui.md +202 -0
- package/assets/social-preview.png +0 -0
- package/assets/upstream/README.md +18 -0
- package/assets/upstream/focus-hint-comparison-1.webp +0 -0
- package/assets/upstream/focus-hint-comparison-2.webp +0 -0
- package/assets/upstream/infographic-reference.webp +0 -0
- package/assets/upstream/infographic-result.webp +0 -0
- package/assets/upstream/ui-fast-restore-reference.webp +0 -0
- package/assets/upstream/ui-fast-restore-result.webp +0 -0
- package/assets/upstream/ui-result.webp +0 -0
- package/assets/upstream/ui-sketch.webp +0 -0
- package/assets/vision-model-test.png +0 -0
- package/assets/vision-settings.png +0 -0
- package/assets/wechat-reward.png +0 -0
- package/cordis.patch.yml +6 -0
- package/docs/aihubmix-gemini-vision.i18n.yaml +6 -0
- package/docs/aihubmix-gemini-vision.md +138 -0
- package/docs/aihubmix-gemini-vision.zh.md +138 -0
- package/docs/assets/aihubmix-api-keys.png +0 -0
- package/docs/assets/aihubmix-create-key.png +0 -0
- package/docs/assets/aihubmix-free-vision-model.png +0 -0
- package/docs/assets/aihubmix-home.png +0 -0
- package/docs/assets/aihubmix-sign-up.png +0 -0
- package/docs/assets/groq-console-home.png +0 -0
- package/docs/assets/groq-console-keys-login.png +0 -0
- package/docs/assets/groq-docs-quickstart.png +0 -0
- package/docs/assets/groq-docs-qwen3.6.png +0 -0
- package/docs/assets/groq-docs-vision.png +0 -0
- package/docs/assets/vision-settings.png +0 -0
- package/docs/dsh-desktop-install.md +67 -0
- package/docs/dsh-desktop-install.zh.md +67 -0
- package/docs/groq-qwen3.6-vision.i18n.yaml +6 -0
- package/docs/groq-qwen3.6-vision.md +236 -0
- package/docs/groq-qwen3.6-vision.zh.md +236 -0
- package/docs/python-runtime.i18n.yaml +6 -0
- package/docs/python-runtime.md +89 -0
- package/docs/python-runtime.zh.md +89 -0
- package/docs/requirements-traceability/README.i18n.yaml +6 -0
- package/docs/requirements-traceability/README.md +75 -0
- package/docs/requirements-traceability/README.zh.md +75 -0
- package/examples/ui-restoration/README.i18n.yaml +6 -0
- package/examples/ui-restoration/README.md +70 -0
- package/examples/ui-restoration/README.zh.md +70 -0
- package/examples/ui-restoration/assets/final-heatmap.png +0 -0
- package/examples/ui-restoration/assets/final-report.json +83 -0
- package/examples/ui-restoration/assets/implementation.png +0 -0
- package/examples/ui-restoration/assets/initial-heatmap.png +0 -0
- package/examples/ui-restoration/assets/initial-report.json +83 -0
- package/examples/ui-restoration/assets/initial.png +0 -0
- package/examples/ui-restoration/assets/metrics.json +12 -0
- package/examples/ui-restoration/assets/reference.png +0 -0
- package/examples/ui-restoration/implementation.html +94 -0
- package/examples/ui-restoration/initial.html +57 -0
- package/lib/artifact-access.js +369 -0
- package/lib/artifact-access.js.map +1 -0
- package/lib/artifacts.js +56 -0
- package/lib/artifacts.js.map +1 -0
- package/lib/client.js +2099 -0
- package/lib/client.js.map +1 -0
- package/lib/config.js +172 -0
- package/lib/config.js.map +1 -0
- package/lib/defaults.js +6 -0
- package/lib/defaults.js.map +1 -0
- package/lib/errors.js +56 -0
- package/lib/errors.js.map +1 -0
- package/lib/evidence-cache.js +350 -0
- package/lib/evidence-cache.js.map +1 -0
- package/lib/exposure.js +247 -0
- package/lib/exposure.js.map +1 -0
- package/lib/image-input-variants.js +882 -0
- package/lib/image-input-variants.js.map +1 -0
- package/lib/index.js +105 -0
- package/lib/index.js.map +1 -0
- package/lib/paste-images.js +217 -0
- package/lib/paste-images.js.map +1 -0
- package/lib/paths.js +354 -0
- package/lib/paths.js.map +1 -0
- package/lib/plugin-update.js +1003 -0
- package/lib/plugin-update.js.map +1 -0
- package/lib/runtime-install.js +964 -0
- package/lib/runtime-install.js.map +1 -0
- package/lib/runtime-manager.js +133 -0
- package/lib/runtime-manager.js.map +1 -0
- package/lib/runtime.js +1678 -0
- package/lib/runtime.js.map +1 -0
- package/lib/skill.js +25 -0
- package/lib/skill.js.map +1 -0
- package/lib/tools.js +549 -0
- package/lib/tools.js.map +1 -0
- package/lib/types/artifact-access.d.ts +61 -0
- package/lib/types/artifact-access.d.ts.map +1 -0
- package/lib/types/artifacts.d.ts +42 -0
- package/lib/types/artifacts.d.ts.map +1 -0
- package/lib/types/client/display-config.d.ts +24 -0
- package/lib/types/client/display-config.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +350 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/model-variants-hider.d.ts +40 -0
- package/lib/types/client/model-variants-hider.d.ts.map +1 -0
- package/lib/types/client/paste-images.d.ts +126 -0
- package/lib/types/client/paste-images.d.ts.map +1 -0
- package/lib/types/config.d.ts +123 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/defaults.d.ts +6 -0
- package/lib/types/defaults.d.ts.map +1 -0
- package/lib/types/errors.d.ts +35 -0
- package/lib/types/errors.d.ts.map +1 -0
- package/lib/types/evidence-cache.d.ts +91 -0
- package/lib/types/evidence-cache.d.ts.map +1 -0
- package/lib/types/exposure.d.ts +50 -0
- package/lib/types/exposure.d.ts.map +1 -0
- package/lib/types/image-input-variants.d.ts +144 -0
- package/lib/types/image-input-variants.d.ts.map +1 -0
- package/lib/types/index.d.ts +19 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/paste-images.d.ts +73 -0
- package/lib/types/paste-images.d.ts.map +1 -0
- package/lib/types/paths.d.ts +117 -0
- package/lib/types/paths.d.ts.map +1 -0
- package/lib/types/plugin-update.d.ts +119 -0
- package/lib/types/plugin-update.d.ts.map +1 -0
- package/lib/types/runtime-install.d.ts +92 -0
- package/lib/types/runtime-install.d.ts.map +1 -0
- package/lib/types/runtime-manager.d.ts +60 -0
- package/lib/types/runtime-manager.d.ts.map +1 -0
- package/lib/types/runtime.d.ts +412 -0
- package/lib/types/runtime.d.ts.map +1 -0
- package/lib/types/skill.d.ts +14 -0
- package/lib/types/skill.d.ts.map +1 -0
- package/lib/types/tools.d.ts +35 -0
- package/lib/types/tools.d.ts.map +1 -0
- package/lib/types/upstream.d.ts +233 -0
- package/lib/types/upstream.d.ts.map +1 -0
- package/lib/types/version.d.ts +15 -0
- package/lib/types/version.d.ts.map +1 -0
- package/lib/types/web-request.d.ts +11 -0
- package/lib/types/web-request.d.ts.map +1 -0
- package/lib/types/web.d.ts +118 -0
- package/lib/types/web.d.ts.map +1 -0
- package/lib/upstream.js +860 -0
- package/lib/upstream.js.map +1 -0
- package/lib/version.js +18 -0
- package/lib/version.js.map +1 -0
- package/lib/web-request.js +29 -0
- package/lib/web-request.js.map +1 -0
- package/lib/web.js +462 -0
- package/lib/web.js.map +1 -0
- package/package.json +149 -0
- package/patches/vision-tools-dsh.patch +970 -0
- package/runtime/requirements.lock +3 -0
- package/src/artifact-access.ts +386 -0
- package/src/artifacts.ts +85 -0
- package/src/client/display-config.ts +62 -0
- package/src/client/index.tsx +1580 -0
- package/src/client/model-variants-hider.ts +159 -0
- package/src/client/paste-images.tsx +747 -0
- package/src/config.ts +290 -0
- package/src/defaults.ts +5 -0
- package/src/errors.ts +62 -0
- package/src/evidence-cache.ts +418 -0
- package/src/exposure.ts +265 -0
- package/src/image-input-variants.ts +996 -0
- package/src/index.ts +141 -0
- package/src/paste-images.ts +286 -0
- package/src/paths.ts +383 -0
- package/src/plugin-update.ts +1143 -0
- package/src/runtime-install.ts +1161 -0
- package/src/runtime-manager.ts +174 -0
- package/src/runtime.ts +2189 -0
- package/src/skill.ts +35 -0
- package/src/tools.ts +691 -0
- package/src/upstream.ts +1078 -0
- package/src/version.ts +37 -0
- package/src/web-request.ts +27 -0
- package/src/web.ts +594 -0
- package/vendor/agent-vision-toolkit/CHANGELOG.md +30 -0
- package/vendor/agent-vision-toolkit/LICENSE +21 -0
- package/vendor/agent-vision-toolkit/README.md +405 -0
- package/vendor/agent-vision-toolkit/UPSTREAM_MANIFEST.json +94 -0
- package/vendor/agent-vision-toolkit/bin/crop +90 -0
- package/vendor/agent-vision-toolkit/bin/detect +13 -0
- package/vendor/agent-vision-toolkit/bin/glance +93 -0
- package/vendor/agent-vision-toolkit/bin/ground +13 -0
- package/vendor/agent-vision-toolkit/bin/trace +129 -0
- package/vendor/agent-vision-toolkit/detect.py +60 -0
- package/vendor/agent-vision-toolkit/ground.py +267 -0
- package/vendor/agent-vision-toolkit/skills/vision-tools/scripts/dominant_colors.py +224 -0
- package/vendor/agent-vision-toolkit/skills/vision-tools/scripts/extract_fg.py +278 -0
- package/vendor/agent-vision-toolkit/skills/vision-tools/scripts/html_shot.py +420 -0
- package/vendor/agent-vision-toolkit/skills/vision-tools/scripts/long_screenshot_ocr.py +1245 -0
- package/vendor/agent-vision-toolkit/skills/vision-tools/scripts/pixel_diff.py +88 -0
- package/vendor/agent-vision-toolkit/tests/test_vision_client.py +450 -0
- package/vendor/agent-vision-toolkit/vision_client.py +310 -0
package/src/config.ts
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin configuration: provider endpoint and credential reference, output
|
|
3
|
+
* language, limits, and the external upstream runtime location. Secrets never
|
|
4
|
+
* live here — `provider.credential` is a DSH Credential reference resolved per
|
|
5
|
+
* operation through `ctx.credentials`.
|
|
6
|
+
* @module dsh-vision-toolkit/config
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import z from '@deepseek-ai/schemastery'
|
|
10
|
+
import type Schema from '@deepseek-ai/schemastery'
|
|
11
|
+
import { credentialRef, type CredentialRef } from '@deepseek-ai/dsh-credentials'
|
|
12
|
+
import { settingsNamespace } from '@deepseek-ai/dsh-settings'
|
|
13
|
+
import { VisionToolkitError } from './errors.ts'
|
|
14
|
+
import {
|
|
15
|
+
BUILT_IN_FREE_VISION_BASE_URL,
|
|
16
|
+
BUILT_IN_FREE_VISION_CREDENTIAL,
|
|
17
|
+
BUILT_IN_FREE_VISION_MODEL,
|
|
18
|
+
} from './defaults.ts'
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
BUILT_IN_FREE_VISION_BASE_URL,
|
|
22
|
+
BUILT_IN_FREE_VISION_CREDENTIAL,
|
|
23
|
+
BUILT_IN_FREE_VISION_KEY,
|
|
24
|
+
BUILT_IN_FREE_VISION_MODEL,
|
|
25
|
+
} from './defaults.ts'
|
|
26
|
+
|
|
27
|
+
/** Settings document namespace owned by this plugin. */
|
|
28
|
+
export const VISION_TOOLKIT_SETTINGS_NAMESPACE = settingsNamespace('vision-toolkit')
|
|
29
|
+
|
|
30
|
+
/** Browser-compatible default shared with the vendored Python client. */
|
|
31
|
+
export const DEFAULT_VISION_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
|
|
32
|
+
|
|
33
|
+
const BUILT_IN_FREE_VISION_MODEL_ALIASES = new Set([
|
|
34
|
+
BUILT_IN_FREE_VISION_MODEL,
|
|
35
|
+
'gemini-3.7-flash',
|
|
36
|
+
'qwen/qwen3.6-27b',
|
|
37
|
+
'qwen3.6-27b',
|
|
38
|
+
'gemma-4-26b-a4b-it',
|
|
39
|
+
'gemma-4-26b',
|
|
40
|
+
'@cf/google/gemma-4-26b-a4b-it',
|
|
41
|
+
'@cf/moondream/moondream3.1-9B-A2B',
|
|
42
|
+
'moondream',
|
|
43
|
+
'moondream-3.1',
|
|
44
|
+
'moondream3.1-9B-A2B',
|
|
45
|
+
])
|
|
46
|
+
|
|
47
|
+
/** Full user-facing configuration; every field defaults at the schema boundary. */
|
|
48
|
+
export interface VisionToolkitConfig {
|
|
49
|
+
provider?: {
|
|
50
|
+
/** Provider API base URL. */
|
|
51
|
+
baseUrl?: string
|
|
52
|
+
/** DSH Credential reference holding the API key (an environment-style name). */
|
|
53
|
+
credential?: string
|
|
54
|
+
/** Multimodal model name. */
|
|
55
|
+
model?: string
|
|
56
|
+
/** Vision request protocol: OpenAI Chat Completions or Anthropic Messages. */
|
|
57
|
+
protocol?: 'openai' | 'anthropic'
|
|
58
|
+
/** Anthropic thinking field behavior; `omit` leaves model defaults untouched. */
|
|
59
|
+
anthropicThinking?: 'omit' | 'disabled' | 'adaptive'
|
|
60
|
+
/** Outbound User-Agent for provider requests and connection tests. */
|
|
61
|
+
userAgent?: string
|
|
62
|
+
}
|
|
63
|
+
/** Vision output language (`zh` or `en`). */
|
|
64
|
+
language?: 'zh' | 'en'
|
|
65
|
+
/** Single remote/upstream call budget in milliseconds. */
|
|
66
|
+
timeoutMs?: number
|
|
67
|
+
/** Maximum input image size in bytes; larger images are auto-compressed (lossless first). */
|
|
68
|
+
maxImageBytes?: number
|
|
69
|
+
/** Maximum decoded pixel count per input image; larger images are auto-downscaled to fit. */
|
|
70
|
+
maxImagePixels?: number
|
|
71
|
+
/** In-flight tool execution cap per session. */
|
|
72
|
+
concurrency?: number
|
|
73
|
+
runtime?: {
|
|
74
|
+
/** `managed` uses the packaged snapshot and isolated venv; `external` uses a clean pinned checkout. */
|
|
75
|
+
mode?: 'managed' | 'external'
|
|
76
|
+
/** Required path to the clean pinned checkout when `mode` is `external`. */
|
|
77
|
+
agentVisionToolkitPath?: string
|
|
78
|
+
/** Optional Python 3.11+ bootstrap/interpreter override. */
|
|
79
|
+
python?: string
|
|
80
|
+
}
|
|
81
|
+
/** Extra directories (besides the workspace) inputs may come from. */
|
|
82
|
+
allowedDirs?: string[]
|
|
83
|
+
/**
|
|
84
|
+
* Image-input variants: sibling model-selector entries for every model the
|
|
85
|
+
* host positively declares text-only. A variant declares image input, so
|
|
86
|
+
* pasted images keep the native attachment flow (composer thumbnail and
|
|
87
|
+
* durable session image), and the plugin rewrites image blocks into Vision
|
|
88
|
+
* Toolkit descriptions only on the wire to the model.
|
|
89
|
+
*/
|
|
90
|
+
imageInputVariants?: {
|
|
91
|
+
/** Whether variant routes are registered at all (default true). */
|
|
92
|
+
enabled?: boolean
|
|
93
|
+
/** Restrict wrapped upstream routes by provider id; empty wraps every eligible route. */
|
|
94
|
+
providers?: string[]
|
|
95
|
+
/**
|
|
96
|
+
* Whether the browser paste integration automatically switches the Session
|
|
97
|
+
* to the image-input variant of a text-only model before the paste, so
|
|
98
|
+
* pasted images keep the native attachment flow with no manual model
|
|
99
|
+
* change. The variant still exposes a workspace path to the model; off
|
|
100
|
+
* keeps the path-only takeover instead (default true).
|
|
101
|
+
*/
|
|
102
|
+
autoSwitch?: boolean
|
|
103
|
+
/**
|
|
104
|
+
* Transparent routing: variant routes keep the upstream provider and model
|
|
105
|
+
* display names, and the browser integration hides the upstream text-only
|
|
106
|
+
* entries that have a variant twin, so the model selector shows one entry
|
|
107
|
+
* per model and sessions stay on the image-capable variant without users
|
|
108
|
+
* seeing or switching a `(Vision Toolkit)` route. On by default; disable
|
|
109
|
+
* to restore the explicit sibling entries.
|
|
110
|
+
*/
|
|
111
|
+
hidden?: boolean
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Configuration schema with the documented P0 defaults. */
|
|
116
|
+
export const Config: Schema<VisionToolkitConfig> = z.object({
|
|
117
|
+
provider: z.object({
|
|
118
|
+
baseUrl: z.string().default(BUILT_IN_FREE_VISION_BASE_URL),
|
|
119
|
+
credential: z.string().default(BUILT_IN_FREE_VISION_CREDENTIAL),
|
|
120
|
+
model: z.string().default(BUILT_IN_FREE_VISION_MODEL),
|
|
121
|
+
protocol: z.union(['openai', 'anthropic'] as const).default('openai'),
|
|
122
|
+
anthropicThinking: z.union(['omit', 'disabled', 'adaptive'] as const).default('omit'),
|
|
123
|
+
userAgent: z.string().default(DEFAULT_VISION_USER_AGENT),
|
|
124
|
+
}),
|
|
125
|
+
language: z.union(['zh', 'en'] as const).default('zh'),
|
|
126
|
+
timeoutMs: z.number().default(30000),
|
|
127
|
+
maxImageBytes: z.number().default(4194304),
|
|
128
|
+
maxImagePixels: z.number().default(20000000),
|
|
129
|
+
concurrency: z.number().default(4),
|
|
130
|
+
runtime: z.object({
|
|
131
|
+
mode: z.union(['managed', 'external'] as const).default('managed'),
|
|
132
|
+
agentVisionToolkitPath: z.string(),
|
|
133
|
+
python: z.string(),
|
|
134
|
+
}),
|
|
135
|
+
allowedDirs: z.array(z.string()).default([]),
|
|
136
|
+
imageInputVariants: z.object({
|
|
137
|
+
enabled: z.boolean().default(true),
|
|
138
|
+
providers: z.array(z.string()).default([]),
|
|
139
|
+
autoSwitch: z.boolean().default(true),
|
|
140
|
+
hidden: z.boolean().default(true),
|
|
141
|
+
}),
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
/** Configuration after static validation, with every default materialized. */
|
|
145
|
+
export interface ResolvedVisionToolkitConfig {
|
|
146
|
+
provider: {
|
|
147
|
+
baseUrl: string
|
|
148
|
+
credential: CredentialRef
|
|
149
|
+
model: string
|
|
150
|
+
protocol: 'openai' | 'anthropic'
|
|
151
|
+
anthropicThinking: 'omit' | 'disabled' | 'adaptive'
|
|
152
|
+
userAgent: string
|
|
153
|
+
}
|
|
154
|
+
language: 'zh' | 'en'
|
|
155
|
+
timeoutMs: number
|
|
156
|
+
maxImageBytes: number
|
|
157
|
+
maxImagePixels: number
|
|
158
|
+
concurrency: number
|
|
159
|
+
runtime: {
|
|
160
|
+
mode: 'managed' | 'external'
|
|
161
|
+
agentVisionToolkitPath?: string
|
|
162
|
+
python?: string
|
|
163
|
+
}
|
|
164
|
+
allowedDirs: string[]
|
|
165
|
+
imageInputVariants: {
|
|
166
|
+
enabled: boolean
|
|
167
|
+
providers: string[]
|
|
168
|
+
autoSwitch: boolean
|
|
169
|
+
hidden: boolean
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const MAX_TIMEOUT_MS = 600000
|
|
174
|
+
const MAX_IMAGE_BYTES = 268435456
|
|
175
|
+
const MAX_IMAGE_PIXELS = 268435456
|
|
176
|
+
const MAX_CONCURRENCY = 16
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Validate and normalize a config object (partial inputs receive the same
|
|
180
|
+
* defaults the schemastery schema applies). Configuration mistakes fail loud
|
|
181
|
+
* at plugin load (the earliest resolvable point); runtime availability is a
|
|
182
|
+
* separate, later concern.
|
|
183
|
+
* @param config - parsed config with defaults applied.
|
|
184
|
+
* @returns the fully defaulted, validated configuration.
|
|
185
|
+
*/
|
|
186
|
+
export function resolveConfig(config: VisionToolkitConfig = {}): ResolvedVisionToolkitConfig {
|
|
187
|
+
const provider = config.provider ?? {}
|
|
188
|
+
const runtime = config.runtime ?? {}
|
|
189
|
+
const baseUrl = (provider.baseUrl ?? BUILT_IN_FREE_VISION_BASE_URL).trim().replace(/\/+$/, '')
|
|
190
|
+
if (!/^https?:\/\//i.test(baseUrl) || baseUrl.length <= 'https://'.length) {
|
|
191
|
+
throw new VisionToolkitError('config', 'provider.baseUrl must be an http(s) URL')
|
|
192
|
+
}
|
|
193
|
+
let credential: CredentialRef
|
|
194
|
+
try {
|
|
195
|
+
credential = credentialRef((provider.credential ?? BUILT_IN_FREE_VISION_CREDENTIAL).trim())
|
|
196
|
+
} catch (error) {
|
|
197
|
+
throw new VisionToolkitError(
|
|
198
|
+
'config',
|
|
199
|
+
`provider.credential "${provider.credential ?? BUILT_IN_FREE_VISION_CREDENTIAL}" is not a valid credential reference`,
|
|
200
|
+
{ cause: error },
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
const model = (provider.model ?? BUILT_IN_FREE_VISION_MODEL).trim()
|
|
204
|
+
if (model.length === 0) {
|
|
205
|
+
throw new VisionToolkitError('config', 'provider.model must not be empty')
|
|
206
|
+
}
|
|
207
|
+
const protocol = provider.protocol ?? 'openai'
|
|
208
|
+
if (protocol !== 'openai' && protocol !== 'anthropic') {
|
|
209
|
+
throw new VisionToolkitError('config', 'provider.protocol must be "openai" or "anthropic"')
|
|
210
|
+
}
|
|
211
|
+
const anthropicThinking = provider.anthropicThinking ?? 'omit'
|
|
212
|
+
if (anthropicThinking !== 'omit' && anthropicThinking !== 'disabled' && anthropicThinking !== 'adaptive') {
|
|
213
|
+
throw new VisionToolkitError('config', 'provider.anthropicThinking must be "omit", "disabled", or "adaptive"')
|
|
214
|
+
}
|
|
215
|
+
const userAgent = (provider.userAgent ?? DEFAULT_VISION_USER_AGENT).trim()
|
|
216
|
+
if (userAgent.length === 0) {
|
|
217
|
+
throw new VisionToolkitError('config', 'provider.userAgent must not be empty')
|
|
218
|
+
}
|
|
219
|
+
const language = config.language ?? 'zh'
|
|
220
|
+
if (language !== 'zh' && language !== 'en') {
|
|
221
|
+
throw new VisionToolkitError('config', 'language must be "zh" or "en"')
|
|
222
|
+
}
|
|
223
|
+
const timeoutMs = config.timeoutMs ?? 30000
|
|
224
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs < 1000 || timeoutMs > MAX_TIMEOUT_MS) {
|
|
225
|
+
throw new VisionToolkitError('config', `timeoutMs must be an integer between 1000 and ${MAX_TIMEOUT_MS}`)
|
|
226
|
+
}
|
|
227
|
+
const maxImageBytes = config.maxImageBytes ?? 4194304
|
|
228
|
+
if (!Number.isInteger(maxImageBytes) || maxImageBytes < 1024 || maxImageBytes > MAX_IMAGE_BYTES) {
|
|
229
|
+
throw new VisionToolkitError('config', `maxImageBytes must be an integer between 1024 and ${MAX_IMAGE_BYTES}`)
|
|
230
|
+
}
|
|
231
|
+
const maxImagePixels = config.maxImagePixels ?? 20000000
|
|
232
|
+
if (!Number.isInteger(maxImagePixels) || maxImagePixels < 1 || maxImagePixels > MAX_IMAGE_PIXELS) {
|
|
233
|
+
throw new VisionToolkitError('config', `maxImagePixels must be an integer between 1 and ${MAX_IMAGE_PIXELS}`)
|
|
234
|
+
}
|
|
235
|
+
const concurrency = config.concurrency ?? 4
|
|
236
|
+
if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > MAX_CONCURRENCY) {
|
|
237
|
+
throw new VisionToolkitError('config', `concurrency must be an integer between 1 and ${MAX_CONCURRENCY}`)
|
|
238
|
+
}
|
|
239
|
+
const mode = runtime.mode ?? 'managed'
|
|
240
|
+
if (mode !== 'managed' && mode !== 'external') {
|
|
241
|
+
throw new VisionToolkitError('config', 'runtime.mode must be "managed" or "external"')
|
|
242
|
+
}
|
|
243
|
+
const toolkitPath = runtime.agentVisionToolkitPath?.trim()
|
|
244
|
+
if (toolkitPath !== undefined && toolkitPath.length === 0) {
|
|
245
|
+
throw new VisionToolkitError('config', 'runtime.agentVisionToolkitPath must not be empty when provided')
|
|
246
|
+
}
|
|
247
|
+
if (mode === 'external' && toolkitPath === undefined) {
|
|
248
|
+
throw new VisionToolkitError('config', 'runtime.agentVisionToolkitPath is required when runtime.mode is external')
|
|
249
|
+
}
|
|
250
|
+
if (mode === 'managed' && toolkitPath !== undefined) {
|
|
251
|
+
throw new VisionToolkitError('config', 'runtime.agentVisionToolkitPath is only valid when runtime.mode is external')
|
|
252
|
+
}
|
|
253
|
+
const python = runtime.python?.trim()
|
|
254
|
+
if (python !== undefined && python.length === 0) {
|
|
255
|
+
throw new VisionToolkitError('config', 'runtime.python must not be empty')
|
|
256
|
+
}
|
|
257
|
+
const allowedDirs = (config.allowedDirs ?? []).map(dir => dir.trim()).filter(dir => dir.length > 0)
|
|
258
|
+
const imageInputVariants = config.imageInputVariants ?? {}
|
|
259
|
+
const variantProviders = (imageInputVariants.providers ?? [])
|
|
260
|
+
.map(provider => provider.trim())
|
|
261
|
+
.filter(provider => provider.length > 0)
|
|
262
|
+
return {
|
|
263
|
+
provider: { baseUrl, credential, model, protocol, anthropicThinking, userAgent },
|
|
264
|
+
language,
|
|
265
|
+
timeoutMs,
|
|
266
|
+
maxImageBytes,
|
|
267
|
+
maxImagePixels,
|
|
268
|
+
concurrency,
|
|
269
|
+
runtime: {
|
|
270
|
+
mode,
|
|
271
|
+
...(toolkitPath !== undefined ? { agentVisionToolkitPath: toolkitPath } : {}),
|
|
272
|
+
...(python !== undefined ? { python } : {}),
|
|
273
|
+
},
|
|
274
|
+
allowedDirs,
|
|
275
|
+
imageInputVariants: {
|
|
276
|
+
enabled: imageInputVariants.enabled ?? true,
|
|
277
|
+
providers: variantProviders,
|
|
278
|
+
autoSwitch: imageInputVariants.autoSwitch ?? true,
|
|
279
|
+
hidden: imageInputVariants.hidden ?? true,
|
|
280
|
+
},
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Whether a resolved provider should use the bundled public key instead of DSH credentials. */
|
|
285
|
+
export function isBuiltInFreeVisionProvider(provider: ResolvedVisionToolkitConfig['provider']): boolean {
|
|
286
|
+
return String(provider.credential) === BUILT_IN_FREE_VISION_CREDENTIAL
|
|
287
|
+
&& provider.baseUrl === BUILT_IN_FREE_VISION_BASE_URL
|
|
288
|
+
&& BUILT_IN_FREE_VISION_MODEL_ALIASES.has(provider.model)
|
|
289
|
+
&& provider.protocol === 'openai'
|
|
290
|
+
}
|
package/src/defaults.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Public free vision service defaults shared by server and browser settings. */
|
|
2
|
+
export const BUILT_IN_FREE_VISION_BASE_URL = 'https://vision.anionex.me/v1'
|
|
3
|
+
export const BUILT_IN_FREE_VISION_CREDENTIAL = 'ANIONEX_FREE_VISION'
|
|
4
|
+
export const BUILT_IN_FREE_VISION_KEY = 'https://agent-vision.anionex.me'
|
|
5
|
+
export const BUILT_IN_FREE_VISION_MODEL = 'gemini-3.7-flash'
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable error vocabulary shared by the runtime, upstream adapter, and tools.
|
|
3
|
+
* Every failure reaching the model carries one of these codes and a message
|
|
4
|
+
* that never contains credentials or raw upstream stack traces.
|
|
5
|
+
* @module dsh-vision-toolkit/errors
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Discriminant tag for every Vision Toolkit failure. */
|
|
9
|
+
export const VISION_TOOLKIT_ERROR_CODES = [
|
|
10
|
+
'config',
|
|
11
|
+
'input',
|
|
12
|
+
'capacity',
|
|
13
|
+
'service',
|
|
14
|
+
'runtime',
|
|
15
|
+
'output',
|
|
16
|
+
'timeout',
|
|
17
|
+
'cancelled',
|
|
18
|
+
'path',
|
|
19
|
+
] as const
|
|
20
|
+
|
|
21
|
+
/** Stable machine-readable error category. */
|
|
22
|
+
export type VisionToolkitErrorCode = typeof VISION_TOOLKIT_ERROR_CODES[number]
|
|
23
|
+
|
|
24
|
+
/** Error with a stable category; safe to surface to the model. */
|
|
25
|
+
export class VisionToolkitError extends Error {
|
|
26
|
+
readonly code: VisionToolkitErrorCode
|
|
27
|
+
|
|
28
|
+
constructor(code: VisionToolkitErrorCode, message: string, options?: { cause?: unknown }) {
|
|
29
|
+
super(message, options)
|
|
30
|
+
this.name = 'VisionToolkitError'
|
|
31
|
+
this.code = code
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Replace every known secret occurrence in untrusted text. Used before
|
|
37
|
+
* upstream stderr, exit messages, or trace reports enter logs or results.
|
|
38
|
+
* @param text - text that may embed a secret.
|
|
39
|
+
* @param secrets - values that must never be surfaced.
|
|
40
|
+
* @returns text with each secret replaced by a fixed marker.
|
|
41
|
+
*/
|
|
42
|
+
export function redactText(text: string, secrets: readonly string[]): string {
|
|
43
|
+
let result = text
|
|
44
|
+
for (const secret of secrets) {
|
|
45
|
+
if (secret.length === 0) continue
|
|
46
|
+
result = result.split(secret).join('<redacted>')
|
|
47
|
+
}
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Build a model-safe upstream failure line: the tool prefix plus the
|
|
53
|
+
* redacted stderr tail, never a JavaScript stack.
|
|
54
|
+
* @param tool - upstream CLI name.
|
|
55
|
+
* @param stderr - captured upstream stderr.
|
|
56
|
+
* @param secrets - values to redact.
|
|
57
|
+
* @returns one-line safe message.
|
|
58
|
+
*/
|
|
59
|
+
export function upstreamFailureMessage(tool: string, stderr: string, secrets: readonly string[]): string {
|
|
60
|
+
const tail = redactText(stderr, secrets).trim().split(/\r?\n/).filter(Boolean).slice(-2).join(' ')
|
|
61
|
+
return tail.length === 0 ? `${tool}: upstream command failed` : `${tool}: ${tail}`
|
|
62
|
+
}
|