@anionex/dsh-vision-toolkit 0.1.5 → 0.1.6
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 +3 -3
- package/README.md +23 -8
- package/README.zh.md +23 -8
- package/docs/assets/vision-settings.png +0 -0
- package/docs/requirements-traceability/README.md +1 -1
- package/docs/requirements-traceability/README.zh.md +1 -1
- package/lib/client.js +338 -76
- package/lib/client.js.map +1 -1
- package/lib/config.js +18 -1
- package/lib/config.js.map +1 -1
- package/lib/runtime.js +18 -1
- package/lib/runtime.js.map +1 -1
- package/lib/types/client/index.d.ts +73 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/config.d.ts +12 -1
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/upstream.d.ts +3 -0
- package/lib/types/upstream.d.ts.map +1 -1
- package/lib/types/web.d.ts +1 -1
- package/lib/upstream.js +3 -0
- package/lib/upstream.js.map +1 -1
- package/lib/web.js +1 -1
- package/package.json +4 -4
- package/src/client/index.tsx +375 -102
- package/src/config.ts +29 -2
- package/src/runtime.ts +17 -1
- package/src/upstream.ts +6 -0
- package/src/web.ts +1 -1
- package/vendor/agent-vision-toolkit/CHANGELOG.md +13 -0
- package/vendor/agent-vision-toolkit/README.md +11 -6
- package/vendor/agent-vision-toolkit/UPSTREAM_MANIFEST.json +14 -9
- package/vendor/agent-vision-toolkit/tests/test_vision_client.py +396 -0
- package/vendor/agent-vision-toolkit/vision_client.py +134 -18
package/src/config.ts
CHANGED
|
@@ -15,15 +15,24 @@ import { VisionToolkitError } from './errors.ts'
|
|
|
15
15
|
/** Settings document namespace owned by this plugin. */
|
|
16
16
|
export const VISION_TOOLKIT_SETTINGS_NAMESPACE = settingsNamespace('vision-toolkit')
|
|
17
17
|
|
|
18
|
+
/** Browser-compatible default shared with the vendored Python client. */
|
|
19
|
+
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'
|
|
20
|
+
|
|
18
21
|
/** Full user-facing configuration; every field defaults at the schema boundary. */
|
|
19
22
|
export interface VisionToolkitConfig {
|
|
20
23
|
provider?: {
|
|
21
|
-
/**
|
|
24
|
+
/** Provider API base URL. */
|
|
22
25
|
baseUrl?: string
|
|
23
26
|
/** DSH Credential reference holding the API key (an environment-style name). */
|
|
24
27
|
credential?: string
|
|
25
28
|
/** Multimodal model name. */
|
|
26
29
|
model?: string
|
|
30
|
+
/** Vision request protocol: OpenAI Chat Completions or Anthropic Messages. */
|
|
31
|
+
protocol?: 'openai' | 'anthropic'
|
|
32
|
+
/** Anthropic thinking field behavior; `omit` leaves model defaults untouched. */
|
|
33
|
+
anthropicThinking?: 'omit' | 'disabled' | 'adaptive'
|
|
34
|
+
/** Outbound User-Agent for provider requests and connection tests. */
|
|
35
|
+
userAgent?: string
|
|
27
36
|
}
|
|
28
37
|
/** Vision output language (`zh` or `en`). */
|
|
29
38
|
language?: 'zh' | 'en'
|
|
@@ -53,6 +62,9 @@ export const Config: Schema<VisionToolkitConfig> = z.object({
|
|
|
53
62
|
baseUrl: z.string().default('https://api.inferera.com/v1'),
|
|
54
63
|
credential: z.string().default('VISION_API_KEY'),
|
|
55
64
|
model: z.string().default('gemini-3.6-flash'),
|
|
65
|
+
protocol: z.union(['openai', 'anthropic'] as const).default('openai'),
|
|
66
|
+
anthropicThinking: z.union(['omit', 'disabled', 'adaptive'] as const).default('omit'),
|
|
67
|
+
userAgent: z.string().default(DEFAULT_VISION_USER_AGENT),
|
|
56
68
|
}),
|
|
57
69
|
language: z.union(['zh', 'en'] as const).default('zh'),
|
|
58
70
|
timeoutMs: z.number().default(60000),
|
|
@@ -73,6 +85,9 @@ export interface ResolvedVisionToolkitConfig {
|
|
|
73
85
|
baseUrl: string
|
|
74
86
|
credential: CredentialRef
|
|
75
87
|
model: string
|
|
88
|
+
protocol: 'openai' | 'anthropic'
|
|
89
|
+
anthropicThinking: 'omit' | 'disabled' | 'adaptive'
|
|
90
|
+
userAgent: string
|
|
76
91
|
}
|
|
77
92
|
language: 'zh' | 'en'
|
|
78
93
|
timeoutMs: number
|
|
@@ -121,6 +136,18 @@ export function resolveConfig(config: VisionToolkitConfig = {}): ResolvedVisionT
|
|
|
121
136
|
if (model.length === 0) {
|
|
122
137
|
throw new VisionToolkitError('config', 'provider.model must not be empty')
|
|
123
138
|
}
|
|
139
|
+
const protocol = provider.protocol ?? 'openai'
|
|
140
|
+
if (protocol !== 'openai' && protocol !== 'anthropic') {
|
|
141
|
+
throw new VisionToolkitError('config', 'provider.protocol must be "openai" or "anthropic"')
|
|
142
|
+
}
|
|
143
|
+
const anthropicThinking = provider.anthropicThinking ?? 'omit'
|
|
144
|
+
if (anthropicThinking !== 'omit' && anthropicThinking !== 'disabled' && anthropicThinking !== 'adaptive') {
|
|
145
|
+
throw new VisionToolkitError('config', 'provider.anthropicThinking must be "omit", "disabled", or "adaptive"')
|
|
146
|
+
}
|
|
147
|
+
const userAgent = (provider.userAgent ?? DEFAULT_VISION_USER_AGENT).trim()
|
|
148
|
+
if (userAgent.length === 0) {
|
|
149
|
+
throw new VisionToolkitError('config', 'provider.userAgent must not be empty')
|
|
150
|
+
}
|
|
124
151
|
const language = config.language ?? 'zh'
|
|
125
152
|
if (language !== 'zh' && language !== 'en') {
|
|
126
153
|
throw new VisionToolkitError('config', 'language must be "zh" or "en"')
|
|
@@ -161,7 +188,7 @@ export function resolveConfig(config: VisionToolkitConfig = {}): ResolvedVisionT
|
|
|
161
188
|
}
|
|
162
189
|
const allowedDirs = (config.allowedDirs ?? []).map(dir => dir.trim()).filter(dir => dir.length > 0)
|
|
163
190
|
return {
|
|
164
|
-
provider: { baseUrl, credential, model },
|
|
191
|
+
provider: { baseUrl, credential, model, protocol, anthropicThinking, userAgent },
|
|
165
192
|
language,
|
|
166
193
|
timeoutMs,
|
|
167
194
|
maxImageBytes,
|
package/src/runtime.ts
CHANGED
|
@@ -768,6 +768,9 @@ export class VisionToolkitRuntime {
|
|
|
768
768
|
VISION_API_KEY: resolved.value,
|
|
769
769
|
VISION_BASE_URL: this.config.provider.baseUrl,
|
|
770
770
|
VISION_MODEL: this.config.provider.model,
|
|
771
|
+
VISION_API_PROTOCOL: this.config.provider.protocol === 'anthropic' ? 'anthropic' : 'chat_completions',
|
|
772
|
+
VISION_ANTHROPIC_THINKING: this.config.provider.anthropicThinking,
|
|
773
|
+
VISION_USER_AGENT: this.config.provider.userAgent,
|
|
771
774
|
LANG: this.config.language,
|
|
772
775
|
}
|
|
773
776
|
}
|
|
@@ -832,6 +835,9 @@ export class VisionToolkitRuntime {
|
|
|
832
835
|
provider: {
|
|
833
836
|
baseUrl: env.VISION_BASE_URL,
|
|
834
837
|
model: env.VISION_MODEL,
|
|
838
|
+
protocol: env.VISION_API_PROTOCOL,
|
|
839
|
+
anthropicThinking: env.VISION_ANTHROPIC_THINKING,
|
|
840
|
+
userAgent: env.VISION_USER_AGENT,
|
|
835
841
|
language: env.LANG,
|
|
836
842
|
credentialSha256: createHash('sha256').update(env.VISION_API_KEY).digest('hex'),
|
|
837
843
|
},
|
|
@@ -1735,9 +1741,19 @@ export class VisionToolkitRuntime {
|
|
|
1735
1741
|
const endpoint = `${this.config.provider.baseUrl}/models`
|
|
1736
1742
|
try {
|
|
1737
1743
|
const started = Date.now()
|
|
1744
|
+
const headers: Record<string, string> = {
|
|
1745
|
+
Accept: 'application/json',
|
|
1746
|
+
'User-Agent': this.config.provider.userAgent,
|
|
1747
|
+
}
|
|
1748
|
+
if (this.config.provider.protocol === 'anthropic') {
|
|
1749
|
+
headers['x-api-key'] = resolvedCredential.value
|
|
1750
|
+
headers['anthropic-version'] = '2023-06-01'
|
|
1751
|
+
} else {
|
|
1752
|
+
headers.Authorization = `Bearer ${resolvedCredential.value}`
|
|
1753
|
+
}
|
|
1738
1754
|
const response = await fetch(endpoint, {
|
|
1739
1755
|
method: 'GET',
|
|
1740
|
-
headers
|
|
1756
|
+
headers,
|
|
1741
1757
|
signal: operation.signal,
|
|
1742
1758
|
})
|
|
1743
1759
|
operation.metrics.upstreamMs += Date.now() - started
|
package/src/upstream.ts
CHANGED
|
@@ -38,6 +38,9 @@ export interface UpstreamEnvironment {
|
|
|
38
38
|
VISION_API_KEY: string
|
|
39
39
|
VISION_BASE_URL: string
|
|
40
40
|
VISION_MODEL: string
|
|
41
|
+
VISION_API_PROTOCOL: 'chat_completions' | 'anthropic'
|
|
42
|
+
VISION_ANTHROPIC_THINKING: 'omit' | 'disabled' | 'adaptive'
|
|
43
|
+
VISION_USER_AGENT: string
|
|
41
44
|
LANG: 'zh' | 'en'
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -612,6 +615,9 @@ export class UpstreamAdapter {
|
|
|
612
615
|
VISION_API_KEY: options.env.VISION_API_KEY,
|
|
613
616
|
VISION_BASE_URL: options.env.VISION_BASE_URL,
|
|
614
617
|
VISION_MODEL: options.env.VISION_MODEL,
|
|
618
|
+
VISION_API_PROTOCOL: options.env.VISION_API_PROTOCOL,
|
|
619
|
+
VISION_ANTHROPIC_THINKING: options.env.VISION_ANTHROPIC_THINKING,
|
|
620
|
+
VISION_USER_AGENT: options.env.VISION_USER_AGENT,
|
|
615
621
|
LANG: options.env.LANG,
|
|
616
622
|
VISION_ENV_FILE: join(prepared.cleanHome, 'vision.env'),
|
|
617
623
|
}),
|
package/src/web.ts
CHANGED
|
@@ -289,7 +289,7 @@ export class VisionToolkitWebBackend {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
/**
|
|
292
|
-
* Attach optional Web routes whenever
|
|
292
|
+
* Attach optional Web routes whenever a webServer service is present.
|
|
293
293
|
* @param ctx - plugin context owning route effects.
|
|
294
294
|
* @param backend - Settings handler.
|
|
295
295
|
* @param artifacts - signed Artifact handler.
|
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable user-facing changes to agent-vision-toolkit are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Let the shared Python vision client call either Chat Completions or Responses APIs, including optional reasoning effort and explicit `store: false` data handling.
|
|
10
|
+
- Add native Anthropic Messages requests with protocol-specific authentication, image sources, optional thinking control, and text-block response extraction.
|
|
11
|
+
- Rewrite OpenAI Chat Completions `image_url` blocks through the existing vision-description pipeline with a host-neutral channel note.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Send a browser-compatible, configurable User-Agent from the shared Python vision client so Cloudflare-backed OpenAI-compatible endpoints do not reject the default `Python-urllib` signature.
|
|
16
|
+
- Honor `Retry-After` and retry Anthropic 529 overload responses.
|
|
17
|
+
|
|
5
18
|
## [0.1.0] - 2026-08-07
|
|
6
19
|
|
|
7
20
|
### Added
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# agent-vision-toolkit
|
|
8
8
|
|
|
9
|
+
[](https://x.com/anion_ex)
|
|
9
10
|
[](https://github.com/Anionex/agent-vision-toolkit/stargazers)
|
|
10
11
|
[](https://github.com/Anionex/agent-vision-toolkit/forks)
|
|
11
12
|
[](https://github.com/Anionex/agent-vision-toolkit/blob/main/LICENSE)
|
|
@@ -136,7 +137,7 @@ When to use them, the order in which to call tools, and how to verify the result
|
|
|
136
137
|
|
|
137
138
|
> Read https://github.com/Anionex/agent-vision-toolkit/blob/main/AGENT_INSTALL.md in full, then install the appropriate vision proxy or native extension/plugin for the agent application we are currently using. If the vision API is not configured, locate the configuration file for the current operating system and guide me through setting `VISION_API_KEY`, `VISION_BASE_URL`, and `VISION_MODEL`.
|
|
138
139
|
|
|
139
|
-
All you need to prepare is
|
|
140
|
+
All you need to prepare is a multimodal API supporting OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages, plus its base URL, API key, and model name. The agent will guide you through writing them to the appropriate configuration file.
|
|
140
141
|
|
|
141
142
|
> After installing the optional integration and restarting the agent, paste an image directly or let the model call its built-in image tool. Pi, Oh My Pi, and OpenCode use single-file [native extensions](extensions/) rather than the proxy; see each agent's documentation.
|
|
142
143
|
|
|
@@ -151,7 +152,7 @@ VISION_BASE_URL=https://openrouter.ai/api/v1
|
|
|
151
152
|
VISION_MODEL=google/gemini-3.6-flash
|
|
152
153
|
```
|
|
153
154
|
|
|
154
|
-
Any OpenAI-compatible endpoint that supports `/chat/completions` with `image_url` works (e.g. Aliyun DashScope: `https://dashscope.aliyuncs.com/compatible-mode/v1` + `qwen-vl-max-latest`). Add `LANG=en` for English descriptions (default is Chinese).
|
|
155
|
+
Any OpenAI-compatible endpoint that supports `/chat/completions` with `image_url` works (e.g. Aliyun DashScope: `https://dashscope.aliyuncs.com/compatible-mode/v1` + `qwen-vl-max-latest`). The Python client/proxy can also use `/responses` with `input_image` by setting `VISION_API_PROTOCOL=responses`, or Anthropic Messages by setting `VISION_API_PROTOCOL=anthropic` and a base URL ending in `/v1` (not `/messages`). Add `LANG=en` for English descriptions (default is Chinese).
|
|
155
156
|
|
|
156
157
|
**2. Put the CLIs on your PATH:**
|
|
157
158
|
|
|
@@ -322,14 +323,18 @@ Codex -> 127.0.0.1:19100 -> your existing text-only upstream
|
|
|
322
323
|
<details>
|
|
323
324
|
<summary><b>Environment variables</b></summary>
|
|
324
325
|
|
|
325
|
-
The
|
|
326
|
+
The standalone CLIs and Python proxy use these environment variables; just three are required. The native Pi and OpenCode extensions use their own settings and currently call `/chat/completions` only.
|
|
326
327
|
|
|
327
328
|
| Variable | Required | Description |
|
|
328
329
|
|---|---:|---|
|
|
329
330
|
| `VISION_API_KEY` | Yes | API key of the multimodal model |
|
|
330
|
-
| `VISION_BASE_URL` | Yes |
|
|
331
|
+
| `VISION_BASE_URL` | Yes | Provider API base URL; include `/v1` but not the protocol endpoint such as `/messages` |
|
|
331
332
|
| `VISION_MODEL` | Yes | Multimodal model name |
|
|
332
333
|
| `LANG` | No | Vision model output language: `zh` (Chinese) or `en` (English); default `zh` |
|
|
334
|
+
| `VISION_API_PROTOCOL` | No | Python client/proxy protocol: `chat_completions` (default), `responses`, or `anthropic`; Anthropic mode uses `x-api-key` and `anthropic-version` |
|
|
335
|
+
| `VISION_REASONING_EFFORT` | No | Optional provider-supported reasoning effort for the Python client/proxy when using `responses` |
|
|
336
|
+
| `VISION_ANTHROPIC_THINKING` | No | Anthropic thinking mode. `omit` (default) sends no thinking field and has the broadest compatibility. Use `disabled` or `adaptive` only when the selected model documents that mode; restore `omit` first if the provider returns HTTP 400. Manual `enabled` plus `budget_tokens` is not exposed. |
|
|
337
|
+
| `VISION_USER_AGENT` | No | Outbound User-Agent for the Python client/proxy; defaults to a browser-compatible value and can be overridden for provider requirements |
|
|
333
338
|
|
|
334
339
|
</details>
|
|
335
340
|
|
|
@@ -348,7 +353,7 @@ The route whose connection (TCP/TLS handshake) succeeds is kept in memory and re
|
|
|
348
353
|
## Prerequisites
|
|
349
354
|
|
|
350
355
|
- A coding agent already working with a model, including a text-only model such as DeepSeek V4
|
|
351
|
-
-
|
|
356
|
+
- A vision API supporting OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages; select the latter two with `VISION_API_PROTOCOL=responses` or `VISION_API_PROTOCOL=anthropic`
|
|
352
357
|
- No other configuration is required
|
|
353
358
|
|
|
354
359
|
## FAQ
|
|
@@ -396,4 +401,4 @@ To reduce costs further, you can use a locally deployed small multimodal side mo
|
|
|
396
401
|
|
|
397
402
|
If agent-vision-toolkit saves you time, you are welcome to star it, share it, contribute, or [sponsor the project](FUNDING.md).
|
|
398
403
|
|
|
399
|
-
I'm [anionex](https://anionex.me/), an AI-native developer who once ranked No. 4 on GitHub's global developer trending list, with more than 16k stars across my projects. If you would like to follow my future work, [follow me on GitHub](https://github.com/Anionex).
|
|
404
|
+
I'm [anionex](https://anionex.me/), an AI-native developer who once ranked No. 4 on GitHub's global developer trending list, with more than 16k stars across my projects. If you would like to follow my future work, [follow me on X](https://x.com/anion_ex) or [GitHub](https://github.com/Anionex).
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"repository": "https://github.com/Anionex/agent-vision-toolkit",
|
|
4
|
-
"version": "v0.1.0+snapshot.
|
|
5
|
-
"commit": "
|
|
6
|
-
"contentSha256": "
|
|
4
|
+
"version": "v0.1.0+snapshot.bc9803d",
|
|
5
|
+
"commit": "bc9803d7d6300c864d17460ecbb33540b26638e0",
|
|
6
|
+
"contentSha256": "6936f8fba3ed40f54267245e717603c2622649ce4bd7ccf3c1b23f39047b1f3f",
|
|
7
7
|
"files": [
|
|
8
8
|
{
|
|
9
9
|
"path": "CHANGELOG.md",
|
|
10
|
-
"bytes":
|
|
11
|
-
"sha256": "
|
|
10
|
+
"bytes": 1671,
|
|
11
|
+
"sha256": "0bb23408797c8e5389abc0b34d47b43907316f8bd106420e4c05f25606bccde1"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"path": "LICENSE",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "README.md",
|
|
20
|
-
"bytes":
|
|
21
|
-
"sha256": "
|
|
20
|
+
"bytes": 23625,
|
|
21
|
+
"sha256": "55d880175b51d288f5b817d064ebb79e6c8663ee0bb1817f4a0390ab18b5c3ee"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"path": "bin/crop",
|
|
@@ -80,10 +80,15 @@
|
|
|
80
80
|
"bytes": 3978,
|
|
81
81
|
"sha256": "70e04fea9bf452f35d12bed0c19c7e2be46934a5423caa778b24da82b78f2251"
|
|
82
82
|
},
|
|
83
|
+
{
|
|
84
|
+
"path": "tests/test_vision_client.py",
|
|
85
|
+
"bytes": 17933,
|
|
86
|
+
"sha256": "eb31118751a5724385f486b98d45af83cad1cf7e4506b79ddf9a840d08f22367"
|
|
87
|
+
},
|
|
83
88
|
{
|
|
84
89
|
"path": "vision_client.py",
|
|
85
|
-
"bytes":
|
|
86
|
-
"sha256": "
|
|
90
|
+
"bytes": 10610,
|
|
91
|
+
"sha256": "7a899d08b1c65721c9fdfd42d9d3288671c149fdc919b5dedb5b36cc6b06ddce"
|
|
87
92
|
}
|
|
88
93
|
]
|
|
89
94
|
}
|