@mengruo/dsh-vision-toolkit 0.1.5 → 0.1.6-beta.0
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/assets/1.mp4 +0 -0
- package/assets/skill/SKILL.md +37 -5
- package/docs/plan-per-tool-visibility.md +82 -0
- package/lib/client.js +53 -3
- package/lib/client.js.map +1 -1
- package/lib/config.js +17 -0
- package/lib/config.js.map +1 -1
- package/lib/exposure.js +35 -8
- package/lib/exposure.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/paths.js +9 -0
- package/lib/paths.js.map +1 -1
- package/lib/runtime.js +175 -1
- package/lib/runtime.js.map +1 -1
- package/lib/tools.js +116 -4
- package/lib/tools.js.map +1 -1
- package/lib/types/client/index.d.ts +24 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/config.d.ts +26 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/exposure.d.ts +14 -2
- package/lib/types/exposure.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/paths.d.ts +7 -0
- package/lib/types/paths.d.ts.map +1 -1
- package/lib/types/runtime.d.ts +38 -0
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/tools.d.ts +22 -1
- package/lib/types/tools.d.ts.map +1 -1
- package/lib/types/video.d.ts +78 -0
- package/lib/types/video.d.ts.map +1 -0
- package/lib/types/web.d.ts +1 -0
- package/lib/types/web.d.ts.map +1 -1
- package/lib/video.js +169 -0
- package/lib/video.js.map +1 -0
- package/lib/web.js +47 -4
- package/lib/web.js.map +1 -1
- package/package.json +2 -1
- package/src/client/index.tsx +72 -1
- package/src/config.ts +43 -0
- package/src/exposure.ts +34 -9
- package/src/index.ts +10 -5
- package/src/paths.ts +11 -0
- package/src/runtime.ts +196 -0
- package/src/tools.ts +144 -3
- package/src/video.ts +222 -0
- package/src/web.ts +53 -5
package/assets/1.mp4
ADDED
|
Binary file
|
package/assets/skill/SKILL.md
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
# vision-skills
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Native DSH tools give a text-only agent eyes. Use these structured tools
|
|
4
4
|
directly; do not shell out to the bundled Python scripts or reproduce their
|
|
5
5
|
implementation. Vision API credentials and model settings are managed by the
|
|
6
6
|
plugin, so tool calls do not receive credentials.
|
|
7
7
|
|
|
8
8
|
The visual execution schemas are mounted only for the current Agent after this
|
|
9
9
|
Skill is loaded. A normal `skill` call activates them for the next model step.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Which tools actually mount is governed by the plugin's **tool-visibility**
|
|
11
|
+
snapshot in Settings (local / on-line / video buckets); each bucket's tools
|
|
12
|
+
appear only when that bucket is enabled. If this content arrived through a
|
|
13
|
+
direct `/vision-skills` invocation and a listed tool is still absent, call
|
|
14
|
+
`vision_toolkit_activate` once **only when the user explicitly asks you to
|
|
15
|
+
refresh or list the current vision tools** — doing so re-reads the latest
|
|
16
|
+
Settings snapshot and returns the tool names currently mounted. Do not call
|
|
17
|
+
that bootstrap just to discover the tool list on ordinary image work.
|
|
18
|
+
|
|
19
|
+
Concurrency applies only to on-line vision calls (glance, ground, detect,
|
|
20
|
+
long-screenshot OCR, video understanding); the local-processing tools (trace,
|
|
21
|
+
crop, pixel diff, foreground, colors, HTML screenshot, video info) run
|
|
22
|
+
immediately and are not throttled by it.
|
|
13
23
|
|
|
14
24
|
Pick the tool by the question you are answering:
|
|
15
25
|
|
|
@@ -239,6 +249,27 @@ significant colours and their shares. Candidate mode scores each supplied
|
|
|
239
249
|
value against the pixels and returns the winner. Take the value from here,
|
|
240
250
|
never from `vision_glance` prose.
|
|
241
251
|
|
|
252
|
+
## Vision tools (video) — info is local, understanding is on-line
|
|
253
|
+
|
|
254
|
+
Both video tools live under the plugin's **video tool bucket** in Settings
|
|
255
|
+
(the video-understanding one is experimental and off by default). When their
|
|
256
|
+
bucket is enabled:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{"video":"clip.mp4"}
|
|
260
|
+
{"video":"clip.mp4","prompt":"what happens in this video?","fps":2}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
- `vision_video_info` — local ffprobe probe of a video file's metadata
|
|
264
|
+
(format, duration, resolution, frame rate, codecs). No API call, no
|
|
265
|
+
credential, never throttled by concurrency. This is in the **local** bucket,
|
|
266
|
+
not the video bucket.
|
|
267
|
+
- `vision_video_understand` — uploads the video to object storage and sends it
|
|
268
|
+
plus your prompt to a configured vision service. It requires a video-capable
|
|
269
|
+
vision service; if none is enabled, the call returns a
|
|
270
|
+
"video understanding unavailable" config error — do not retry it with a
|
|
271
|
+
different wording. This is in the **video** bucket.
|
|
272
|
+
|
|
242
273
|
## Prefer a durable path; platform temp paths are supported
|
|
243
274
|
|
|
244
275
|
Use workspace storage when the image or a derived artifact must remain
|
|
@@ -318,7 +349,8 @@ resource base and load only the relevant file.
|
|
|
318
349
|
- Only PNG / JPEG / GIF / WebP images are supported.
|
|
319
350
|
- `vision_html_screenshot` accepts local `.html` / `.htm` files only, not URLs
|
|
320
351
|
or data URIs.
|
|
321
|
-
- If a visual tool is absent after Skill activation,
|
|
352
|
+
- If a visual tool is absent after Skill activation, first check whether its
|
|
353
|
+
tool-visibility bucket is disabled in Settings; report that the plugin
|
|
322
354
|
runtime is unavailable instead of improvising a shell replacement.
|
|
323
355
|
- If a tool fails, relay its stable error faithfully and fix the identified
|
|
324
356
|
path, limit, Credential, runtime, or service condition. Never fabricate image
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# 按工具组可见性开关(toolVisibility)实现规格
|
|
2
|
+
|
|
3
|
+
## 目标
|
|
4
|
+
|
|
5
|
+
在 `vision-toolkit` 配置下新增一个粗粒度可见性开关组,按"会话头快照"生效:
|
|
6
|
+
|
|
7
|
+
- 开 → 该组工具在**下一个 agent 对话**(下次激活)可见;
|
|
8
|
+
- 关 → 不可见;已激活 agent 维持激活时的旧快照,不实时增删(激活时截取快照语义)。
|
|
9
|
+
- 保留全局兜底 `vision_toolkit_activate`,但语义改为"显式刷新/重载视觉工具集",AI 只在用户要求时调用。
|
|
10
|
+
|
|
11
|
+
## 三个开关与工具分桶
|
|
12
|
+
|
|
13
|
+
新配置段(全局一份,旧配置自动兼容,缺省即默认值):
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
vision-toolkit:
|
|
17
|
+
toolVisibility:
|
|
18
|
+
local: true # 本地处理工具,默认开
|
|
19
|
+
online: true # 联机图片工具 + concurrency,默认开
|
|
20
|
+
video: false # 视频理解工具,默认关(UI 标注「测试」)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| 桶 | 开关字段 | 工具 | 走 concurrency? |
|
|
24
|
+
|----|---------|------|----------------|
|
|
25
|
+
| **local** | `toolVisibility.local` | `vision_trace`、`vision_crop`、`vision_pixel_diff`、`vision_extract_foreground`、`vision_dominant_colors`、`vision_html_screenshot`、`vision_video_info` | 否(本地处理,无并联限制) |
|
|
26
|
+
| **online** | `toolVisibility.online` | `vision_glance`、`vision_ground`、`vision_detect`、`vision_long_screenshot_ocr`、`vision_concurrency` | 是(受 session 并发限流) |
|
|
27
|
+
| **video** | `toolVisibility.video` | `vision_video_understand` | 是(走后端能力) |
|
|
28
|
+
| 兜底 | 永远可用 | `vision_toolkit_activate` | — |
|
|
29
|
+
|
|
30
|
+
> 说明:
|
|
31
|
+
> - `vision_concurrency` 归 `online` 桶,且其语义改为"当前**联机服务**的可用并发配额",本地工具不受并行限制。工具描述 / 返回需随之更新。
|
|
32
|
+
> - 上游"那 10 个工具"被拆进 local 与 online 两桶,二者默认均开,构成完整上游集 + `video_info`。
|
|
33
|
+
> - 默认全开(local+online),video 默认关。
|
|
34
|
+
|
|
35
|
+
## 可见性判定
|
|
36
|
+
|
|
37
|
+
对某个工具 `T`:**激活 agent 作用域工具集时**,根据当时读到的 `toolVisibility` 快照,逐个决定是否注册该工具的定义。
|
|
38
|
+
|
|
39
|
+
- `local` 桶工具 → 若 `toolVisibility.local === true`。
|
|
40
|
+
- `online` 桶工具 → 若 `toolVisibility.online === true`。
|
|
41
|
+
- `video` 桶(`vision_video_understand`) → 若 `toolVisibility.video === true`;**不再**受 `videoSupportEnabled` 门控决定"是否暴露"。
|
|
42
|
+
- 激活后不再变动;后续设置改动只影响下一个 agent 的激活。
|
|
43
|
+
|
|
44
|
+
## 视频工具与后端能力的解耦
|
|
45
|
+
|
|
46
|
+
`videoSupportEnabled`(provider 的 `videoSupport` 标记)**不再**决定 `vision_video_understand` 是否出现在工具列表。
|
|
47
|
+
|
|
48
|
+
- 工具可见性:仅由 `toolVisibility.video` 决定。
|
|
49
|
+
- 工具成功率:调用 `videoUnderstand` 时,若无任何具备视频能力的可用 provider/模型,**返回明确的"视频理解不可用"错误**(沿用 `config` 类错误,文案如 `no enabled vision service has video support; enable it in Settings first`),而不是在暴露阶段就隐藏。
|
|
50
|
+
|
|
51
|
+
## `vision_toolkit_activate` 兜底改造
|
|
52
|
+
|
|
53
|
+
- **始终存在、不分桶**。
|
|
54
|
+
- **描述改写**:从"激活 vison 工具"改为"**当用户显式要求刷新/重载当前会话的视觉工具时调用**"。要求模型仅在用户显式触发时使用,不作为普通激活路径。
|
|
55
|
+
- 调用后按**当时**的 `toolVisibility` 快照重新生成工具集(重载),并返回当前实际可用的工具清单,让 AI 自查。
|
|
56
|
+
- 保持"激活后从模型视野收起"的既有行为,但语义对齐上述描述。
|
|
57
|
+
|
|
58
|
+
## 配置 / UI
|
|
59
|
+
|
|
60
|
+
- `src/config.ts`:新增 `toolVisibility` 字段(`local`/`online`/`video` 三个 bool),schema 默认 `{local:true, online:true, video:false}`,迁移兼容旧配置。
|
|
61
|
+
- `src/client/index.tsx`:视觉工具高级设置区新增三个开关,label:
|
|
62
|
+
- 本地工具(默认开)
|
|
63
|
+
- 联机图片工具(默认开)
|
|
64
|
+
- 视频工具(默认关,文案标注「(测试)」)
|
|
65
|
+
- `src/runtime.ts`:`videoSupportEnabled` 语义保持"存在 video-capable provider";`videoUnderstand` 在无视频 provider 时返回"视频理解不可用"。
|
|
66
|
+
|
|
67
|
+
## 涉及文件
|
|
68
|
+
|
|
69
|
+
- `src/config.ts`(schema / defaults / 迁移)
|
|
70
|
+
- `src/index.ts`(将 toolVisibility 快照传入 exposure 生成逻辑)
|
|
71
|
+
- `src/exposure.ts`(激活时按快照生成对应桶子集;重载语义;activate 描述改写)
|
|
72
|
+
- `src/tools.ts`(按桶把工具定义分组;concurrency 描述/语义调整;video 工具与 capability 解耦)
|
|
73
|
+
- `src/runtime.ts`(`videoUnderstand` 无能力即报错)
|
|
74
|
+
- `src/client/index.tsx`(高级设置 UI:三个开关 + 文案)
|
|
75
|
+
- `assets/skill/SKILL.md`(描述补充:按桶可用性、concurrency 语义、activate 的新语义)
|
|
76
|
+
- `docs/plan-per-tool-visibility.md`(本文件)
|
|
77
|
+
|
|
78
|
+
## 待实现时再确认的细点(标记,非阻塞)
|
|
79
|
+
|
|
80
|
+
- `vision_video_info` 归 local 桶;如需并入 video 桶再调整。
|
|
81
|
+
- `vision_concurrency` 返回改写为"联机并发可用额度 + 本地无限制"的说明文案。
|
|
82
|
+
- 空桶(如 local 关但 online 开)时无工具可注册,exposure 需正确处理"只有兜底 activate"的情况。
|
package/lib/client.js
CHANGED
|
@@ -132,6 +132,8 @@ const en = {
|
|
|
132
132
|
streamHint: 'Request a streamed (SSE) completion instead of one JSON response. Use it for endpoints with weak non-streaming support or that time out on long outputs.',
|
|
133
133
|
uploadViaUrl: 'Transfer images via URL',
|
|
134
134
|
uploadViaUrlHint: 'Upload each image to the configured object storage and send the model a URL instead of base64. Requires object storage (below); region crops fall back to base64.',
|
|
135
|
+
videoSupport: 'Enable video support',
|
|
136
|
+
videoSupportHint: 'OpenAI-compatible video understanding. This setting is hidden for Anthropic providers and is currently a placeholder with no effect yet.',
|
|
135
137
|
language: 'Output language',
|
|
136
138
|
limits: 'Timeout and concurrency',
|
|
137
139
|
timeout: 'Request timeout (ms)',
|
|
@@ -186,8 +188,10 @@ const en = {
|
|
|
186
188
|
runHealth: 'Run health check',
|
|
187
189
|
testConnection: 'Test API connection',
|
|
188
190
|
testModel: 'Test vision model',
|
|
191
|
+
testVideo: 'Test video call',
|
|
189
192
|
testing: 'Checking…',
|
|
190
193
|
testingModel: 'Testing model…',
|
|
194
|
+
testingVideo: 'Testing video…',
|
|
191
195
|
connectionHint: 'The API connection test only queries GET /models. The vision model test sends the bundled diagnostic image and verifies one real multimodal request.',
|
|
192
196
|
saveBeforeTesting: 'Save service changes before testing the connection.',
|
|
193
197
|
advanced: 'Advanced settings',
|
|
@@ -196,6 +200,14 @@ const en = {
|
|
|
196
200
|
hiddenVariants: 'Transparent variant routing',
|
|
197
201
|
hiddenVariantsLabel: 'Keep the original model names and enable images automatically',
|
|
198
202
|
hiddenVariantsHint: 'Text-only models keep one model-selector entry with the original name while the session runs on the image-capable variant. Pasted images, image history, and the built-in read_image tool keep working; disable to restore the explicit (Vision Toolkit) entries.',
|
|
203
|
+
toolVisibility: 'Tool visibility',
|
|
204
|
+
toolVisibilityHint: 'Which groups of vision tools an Agent sees. Applies to the next Agent conversation: an already-active Agent keeps its activation-time set until it is reloaded.',
|
|
205
|
+
toolVisibilityLocal: 'Local tools',
|
|
206
|
+
toolVisibilityLocalHint: 'trace / crop / pixel diff / foreground / colors / HTML screenshot / video info. Local processing, no on-line parallel limits.',
|
|
207
|
+
toolVisibilityOnline: 'Online image tools',
|
|
208
|
+
toolVisibilityOnlineHint: 'glance / ground / detect / long-screenshot OCR, plus the concurrency/status probe. On-line service calls share the session concurrency budget.',
|
|
209
|
+
toolVisibilityVideo: 'Video tools',
|
|
210
|
+
toolVisibilityVideoHint: 'video understanding (experimental). Calling it without an enabled video-capable service returns "video understanding unavailable".',
|
|
199
211
|
pluginVersion: 'Plugin',
|
|
200
212
|
upstreamVersion: 'Upstream',
|
|
201
213
|
activeGeneration: 'Runtime generation',
|
|
@@ -364,6 +376,8 @@ const zh = {
|
|
|
364
376
|
streamHint: '以流式(SSE)方式请求补全,而非一次性返回 JSON。适合对非流式支持不佳、长输出易连接超时的端点。',
|
|
365
377
|
uploadViaUrl: '通过 URL 传输图片',
|
|
366
378
|
uploadViaUrlHint: '把每张图片上传到下方配置的对象存储,将 URL 传给模型而不是 base64。需要先配置对象存储;使用 region 裁剪时回退为 base64。',
|
|
379
|
+
videoSupport: '启用视频支持',
|
|
380
|
+
videoSupportHint: 'OpenAI 兼容接口的视频理解能力。Anthropic 服务不显示此项;当前为占位设置,尚未生效。',
|
|
367
381
|
language: '结果语言',
|
|
368
382
|
limits: '超时与并发限制',
|
|
369
383
|
timeout: '单次请求超时(毫秒)',
|
|
@@ -418,8 +432,10 @@ const zh = {
|
|
|
418
432
|
runHealth: '检查本地环境',
|
|
419
433
|
testConnection: '测试 API 连接',
|
|
420
434
|
testModel: '测试视觉模型',
|
|
435
|
+
testVideo: '测试视频调用',
|
|
421
436
|
testing: '检查中…',
|
|
422
437
|
testingModel: '正在测试模型…',
|
|
438
|
+
testingVideo: '正在测试视频…',
|
|
423
439
|
connectionHint: '“测试 API 连接”只请求 GET /models;“测试视觉模型”会发送插件自带的诊断图片,验证一次真实多模态调用。',
|
|
424
440
|
saveBeforeTesting: '修改服务配置后,请先保存,再执行 API 或视觉模型测试。',
|
|
425
441
|
advanced: '高级设置',
|
|
@@ -428,6 +444,14 @@ const zh = {
|
|
|
428
444
|
hiddenVariants: '透明变体路由',
|
|
429
445
|
hiddenVariantsLabel: '保留原模型名并自动启用图片能力',
|
|
430
446
|
hiddenVariantsHint: '文本模型在模型列表中只显示原名称,会话实际运行在支持图片的变体路由上:粘贴图片、历史图片和内置 read_image 工具均可正常使用。关闭后恢复显示显式的(Vision Toolkit)条目。',
|
|
447
|
+
toolVisibility: '工具可见性',
|
|
448
|
+
toolVisibilityHint: 'Agent 可见的视觉工具分组。仅在下一个 agent 对话中生效:已激活的 agent 保持激活时的工具集,直到重载。',
|
|
449
|
+
toolVisibilityLocal: '本地工具',
|
|
450
|
+
toolVisibilityLocalHint: 'trace / crop / 像素对比 / 前景提取 / 取色 / HTML 截图 / 视频信息。本地处理,不受联机并发限制。',
|
|
451
|
+
toolVisibilityOnline: '联机图片工具',
|
|
452
|
+
toolVisibilityOnlineHint: 'glance / ground / detect / 长截图 OCR,以及并发/状态查询。联机调用共享会话并发额度。',
|
|
453
|
+
toolVisibilityVideo: '视频工具',
|
|
454
|
+
toolVisibilityVideoHint: '视频理解(测试)。调用时若没有已启用且支持视频的服务,将返回“视频理解不可用”。',
|
|
431
455
|
pluginVersion: '插件版本',
|
|
432
456
|
upstreamVersion: '工具包版本',
|
|
433
457
|
activeGeneration: '本次运行已应用',
|
|
@@ -928,6 +952,20 @@ class VisionSettingsController {
|
|
|
928
952
|
this.set({ ...this.state, action: undefined, error: error instanceof Error ? error.message : String(error) });
|
|
929
953
|
}
|
|
930
954
|
}
|
|
955
|
+
async runVideoTest(providerIndex) {
|
|
956
|
+
this.set({ ...this.state, action: 'test-video', error: undefined, message: undefined });
|
|
957
|
+
try {
|
|
958
|
+
const result = await apiRequest({
|
|
959
|
+
method: 'POST',
|
|
960
|
+
headers: { 'Content-Type': 'application/json' },
|
|
961
|
+
body: JSON.stringify({ action: 'test-video', ...(providerIndex === undefined ? {} : { providerIndex }) }),
|
|
962
|
+
});
|
|
963
|
+
this.set({ ...this.state, action: undefined, videoTest: result });
|
|
964
|
+
}
|
|
965
|
+
catch (error) {
|
|
966
|
+
this.set({ ...this.state, action: undefined, error: error instanceof Error ? error.message : String(error) });
|
|
967
|
+
}
|
|
968
|
+
}
|
|
931
969
|
async checkUpdate() {
|
|
932
970
|
this.set({ ...this.state, action: 'check-update', error: undefined, message: undefined });
|
|
933
971
|
try {
|
|
@@ -994,6 +1032,7 @@ function emptyProviderDraft(defaults) {
|
|
|
994
1032
|
userAgent: DEFAULT_USER_AGENT,
|
|
995
1033
|
stream: false,
|
|
996
1034
|
uploadViaUrl: false,
|
|
1035
|
+
videoSupport: false,
|
|
997
1036
|
t1Seconds: '90',
|
|
998
1037
|
t2Seconds: '90',
|
|
999
1038
|
maxImageBytes: String(defaults.maxImageBytes),
|
|
@@ -1017,6 +1056,7 @@ function providerDraftOf(value, fallback, defaults) {
|
|
|
1017
1056
|
userAgent: source?.userAgent ?? DEFAULT_USER_AGENT,
|
|
1018
1057
|
stream: source?.stream === true,
|
|
1019
1058
|
uploadViaUrl: source?.uploadViaUrl === true,
|
|
1059
|
+
videoSupport: source?.videoSupport === true,
|
|
1020
1060
|
t1Seconds: String(source?.t1Seconds ?? 90),
|
|
1021
1061
|
t2Seconds: String(source?.t2Seconds ?? 90),
|
|
1022
1062
|
maxImageBytes: String(source?.maxImageBytes ?? defaults.maxImageBytes),
|
|
@@ -1056,6 +1096,9 @@ function draftOf(value) {
|
|
|
1056
1096
|
variantEnabled: value.imageInputVariants?.enabled ?? true,
|
|
1057
1097
|
variantProviders: (value.imageInputVariants?.providers ?? []).join('\n'),
|
|
1058
1098
|
variantAutoSwitch: value.imageInputVariants?.autoSwitch ?? true,
|
|
1099
|
+
toolVisibilityLocal: value.toolVisibility?.local ?? true,
|
|
1100
|
+
toolVisibilityOnline: value.toolVisibility?.online ?? true,
|
|
1101
|
+
toolVisibilityVideo: value.toolVisibility?.video ?? false,
|
|
1059
1102
|
};
|
|
1060
1103
|
}
|
|
1061
1104
|
function positiveInteger(raw, label, t) {
|
|
@@ -1089,6 +1132,7 @@ function valueOf(draft, t) {
|
|
|
1089
1132
|
...(provider.userAgent.trim() === DEFAULT_USER_AGENT ? {} : { userAgent: provider.userAgent.trim() }),
|
|
1090
1133
|
...(provider.stream ? { stream: true } : {}),
|
|
1091
1134
|
...(provider.uploadViaUrl ? { uploadViaUrl: true } : {}),
|
|
1135
|
+
...(provider.videoSupport ? { videoSupport: true } : {}),
|
|
1092
1136
|
...(provider.t1Seconds.trim().length === 0 ? {} : { t1Seconds: positiveInteger(provider.t1Seconds, t('t1'), t) }),
|
|
1093
1137
|
...(provider.t2Seconds.trim().length === 0 ? {} : { t2Seconds: positiveInteger(provider.t2Seconds, t('t2'), t) }),
|
|
1094
1138
|
...(provider.maxImageBytes.trim().length === 0 ? {} : { maxImageBytes: positiveInteger(provider.maxImageBytes, t('maxBytes'), t) }),
|
|
@@ -1107,6 +1151,7 @@ function valueOf(draft, t) {
|
|
|
1107
1151
|
userAgent: primary?.userAgent.trim() || DEFAULT_USER_AGENT,
|
|
1108
1152
|
stream: primary?.stream === true,
|
|
1109
1153
|
uploadViaUrl: primary?.uploadViaUrl === true,
|
|
1154
|
+
videoSupport: primary?.videoSupport === true,
|
|
1110
1155
|
},
|
|
1111
1156
|
providers,
|
|
1112
1157
|
language: draft.language,
|
|
@@ -1141,6 +1186,11 @@ function valueOf(draft, t) {
|
|
|
1141
1186
|
...(draft.variantAutoSwitch ? {} : { autoSwitch: false }),
|
|
1142
1187
|
hidden: draft.hiddenVariants,
|
|
1143
1188
|
},
|
|
1189
|
+
toolVisibility: {
|
|
1190
|
+
local: draft.toolVisibilityLocal,
|
|
1191
|
+
online: draft.toolVisibilityOnline,
|
|
1192
|
+
video: draft.toolVisibilityVideo,
|
|
1193
|
+
},
|
|
1144
1194
|
};
|
|
1145
1195
|
}
|
|
1146
1196
|
function settingsDraftChanged(draft, saved, t) {
|
|
@@ -1452,17 +1502,17 @@ function LoadedSettings({ controller, t }) {
|
|
|
1452
1502
|
void controller.applyUpdate(latestVersion);
|
|
1453
1503
|
};
|
|
1454
1504
|
const providerHealth = state.providerHealth?.[selectedIndex];
|
|
1455
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-settings", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-save-dock", "data-dirty": updateHasUnsavedChanges ? 'true' : undefined, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "dvt-save-dock-reload", "aria-label": t('reload'), title: t('reload'), disabled: busy, onClick: () => { void controller.load(); }, children: (0, jsx_runtime_1.jsx)(ReloadIcon, {}) }), updateHasUnsavedChanges ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-save-dock-text", children: t('unsavedChanges') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy, onClick: discard, children: t('discardChanges') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: !canSave || busy, onClick: save, children: state.action === 'save' ? t('saving') : t('save') })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "dvt-save-dock-text", children: t('noUnsavedChanges') }))] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert notice", children: t('externalNotice') }), !snapshot.writable ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('readOnly') }) : null, draftError === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: draftError }), state.error === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: state.error }), state.message === 'saved' ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('saved') }) : null, state.message === 'restarting' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('restarting', { version: state.restart.toVersion }) }) : null, state.message === 'manual-restart-required' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('manualRestartRequired', { version: state.restart.toVersion }) }) : null, snapshot.runtime.lastError === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert error", children: [(0, jsx_runtime_1.jsx)("strong", { children: runtimeErrorTitle }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.runtime.lastError })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-essential", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('providers') }), (0, jsx_runtime_1.jsx)("p", { children: t('providerHint') })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-select", children: [(0, jsx_runtime_1.jsx)("select", { "aria-label": t('providers'), disabled: !snapshot.writable || busy, value: selectedIndex, onChange: (event) => { setSelectedIndex(Number(event.target.value)); }, children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("option", { value: index, children: [index + 1, ". ", provider.name.trim() || provider.model.trim() || t('provider')] }, index))) }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length >= 32, onClick: addProvider, children: t('addProvider') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length <= 1, onClick: () => { removeProvider(selectedIndex); }, children: t('removeProvider') })] }), selectedProvider === undefined ? null : ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-card", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-head", children: [(0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: selectedProvider.enabled, disabled: !snapshot.writable || busy, onChange: (event) => { updateProvider(selectedIndex, 'enabled', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('enabled') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-provider-priority", children: t('priority', { index: selectedIndex + 1 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('name'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('name'), value: selectedProvider.name, onChange: (event) => { updateProvider(selectedIndex, 'name', event.target.value); }, placeholder: selectedProvider.model || t('model') }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('model'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('model'), disabled: !snapshot.writable || busy, value: selectedProvider.model, onChange: (event) => { updateProvider(selectedIndex, 'model', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('baseUrl'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('baseUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.baseUrl, onChange: (event) => { updateProvider(selectedIndex, 'baseUrl', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('protocol'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('protocol'), disabled: !snapshot.writable || busy, value: selectedProvider.protocol, onChange: (event) => { updateProvider(selectedIndex, 'protocol', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "openai", children: "OpenAI Chat Completions" }), (0, jsx_runtime_1.jsx)("option", { value: "anthropic", children: "Anthropic Messages" })] }) }), selectedProvider.protocol === 'anthropic' ? (0, jsx_runtime_1.jsx)(Field, { label: t('anthropicThinking'), hint: t('anthropicThinkingHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('anthropicThinking'), value: selectedProvider.anthropicThinking, onChange: (event) => { updateProvider(selectedIndex, 'anthropicThinking', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "omit", children: "omit (widest compatibility)" }), (0, jsx_runtime_1.jsx)("option", { value: "disabled", children: "disabled (model support required)" }), (0, jsx_runtime_1.jsx)("option", { value: "adaptive", children: "adaptive (model support required)" })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('userAgent'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('userAgent'), value: selectedProvider.userAgent, onChange: (event) => { updateProvider(selectedIndex, 'userAgent', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('stream'), hint: t('streamHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('stream'), disabled: !snapshot.writable || busy, value: selectedProvider.stream ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'stream', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('uploadViaUrl'), hint: t('uploadViaUrlHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('uploadViaUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.uploadViaUrl ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'uploadViaUrl', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('t1'), hint: t('t1Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t1'), inputMode: "numeric", value: selectedProvider.t1Seconds, onChange: (event) => { updateProvider(selectedIndex, 't1Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('t2'), hint: t('t2Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t2'), inputMode: "numeric", value: selectedProvider.t2Seconds, onChange: (event) => { updateProvider(selectedIndex, 't2Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxBytes'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxBytes'), inputMode: "numeric", value: selectedProvider.maxImageBytes, onChange: (event) => { updateProvider(selectedIndex, 'maxImageBytes', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxPixels'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxPixels'), inputMode: "numeric", value: selectedProvider.maxImagePixels, onChange: (event) => { updateProvider(selectedIndex, 'maxImagePixels', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('concurrency'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('concurrency'), inputMode: "numeric", value: selectedProvider.concurrency, onChange: (event) => { updateProvider(selectedIndex, 'concurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('attempts'), hint: t('attemptsHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('attempts'), inputMode: "numeric", value: selectedProvider.attempts, onChange: (event) => { updateProvider(selectedIndex, 'attempts', event.target.value); } }) })] }), (0, jsx_runtime_1.jsx)(Field, { label: t('apiKey'), hint: selectedBuiltInFree ? t('apiKeyBuiltInFree') : selectedKeyLocked ? t('apiKeyLocked') : t('apiKeyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('apiKey'), type: "password", autoComplete: "new-password", disabled: busy || selectedKeyLocked || selectedBuiltInFree, placeholder: selectedCredential?.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: selectedKey, onChange: (event) => { setKeys(current => ({ ...current, [selectedProvider.credential]: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-tests", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('connection', selectedIndex); }, children: state.action === 'connection' ? t('testing') : t('testConnection') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('model', selectedIndex); }, children: state.action === 'model' ? t('testingModel') : t('testModel') })] }), providerHealth === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: ['service', 'model'].map(name => {
|
|
1505
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-settings", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-save-dock", "data-dirty": updateHasUnsavedChanges ? 'true' : undefined, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "dvt-save-dock-reload", "aria-label": t('reload'), title: t('reload'), disabled: busy, onClick: () => { void controller.load(); }, children: (0, jsx_runtime_1.jsx)(ReloadIcon, {}) }), updateHasUnsavedChanges ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-save-dock-text", children: t('unsavedChanges') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy, onClick: discard, children: t('discardChanges') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: !canSave || busy, onClick: save, children: state.action === 'save' ? t('saving') : t('save') })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "dvt-save-dock-text", children: t('noUnsavedChanges') }))] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert notice", children: t('externalNotice') }), !snapshot.writable ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('readOnly') }) : null, draftError === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: draftError }), state.error === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: state.error }), state.message === 'saved' ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('saved') }) : null, state.message === 'restarting' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('restarting', { version: state.restart.toVersion }) }) : null, state.message === 'manual-restart-required' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('manualRestartRequired', { version: state.restart.toVersion }) }) : null, snapshot.runtime.lastError === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert error", children: [(0, jsx_runtime_1.jsx)("strong", { children: runtimeErrorTitle }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.runtime.lastError })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-essential", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('providers') }), (0, jsx_runtime_1.jsx)("p", { children: t('providerHint') })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-select", children: [(0, jsx_runtime_1.jsx)("select", { "aria-label": t('providers'), disabled: !snapshot.writable || busy, value: selectedIndex, onChange: (event) => { setSelectedIndex(Number(event.target.value)); }, children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("option", { value: index, children: [index + 1, ". ", provider.name.trim() || provider.model.trim() || t('provider')] }, index))) }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length >= 32, onClick: addProvider, children: t('addProvider') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length <= 1, onClick: () => { removeProvider(selectedIndex); }, children: t('removeProvider') })] }), selectedProvider === undefined ? null : ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-card", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-head", children: [(0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: selectedProvider.enabled, disabled: !snapshot.writable || busy, onChange: (event) => { updateProvider(selectedIndex, 'enabled', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('enabled') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-provider-priority", children: t('priority', { index: selectedIndex + 1 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('name'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('name'), value: selectedProvider.name, onChange: (event) => { updateProvider(selectedIndex, 'name', event.target.value); }, placeholder: selectedProvider.model || t('model') }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('model'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('model'), disabled: !snapshot.writable || busy, value: selectedProvider.model, onChange: (event) => { updateProvider(selectedIndex, 'model', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('baseUrl'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('baseUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.baseUrl, onChange: (event) => { updateProvider(selectedIndex, 'baseUrl', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('protocol'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('protocol'), disabled: !snapshot.writable || busy, value: selectedProvider.protocol, onChange: (event) => { updateProvider(selectedIndex, 'protocol', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "openai", children: "OpenAI Chat Completions" }), (0, jsx_runtime_1.jsx)("option", { value: "anthropic", children: "Anthropic Messages" })] }) }), selectedProvider.protocol === 'anthropic' ? (0, jsx_runtime_1.jsx)(Field, { label: t('anthropicThinking'), hint: t('anthropicThinkingHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('anthropicThinking'), value: selectedProvider.anthropicThinking, onChange: (event) => { updateProvider(selectedIndex, 'anthropicThinking', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "omit", children: "omit (widest compatibility)" }), (0, jsx_runtime_1.jsx)("option", { value: "disabled", children: "disabled (model support required)" }), (0, jsx_runtime_1.jsx)("option", { value: "adaptive", children: "adaptive (model support required)" })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('userAgent'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('userAgent'), value: selectedProvider.userAgent, onChange: (event) => { updateProvider(selectedIndex, 'userAgent', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('stream'), hint: t('streamHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('stream'), disabled: !snapshot.writable || busy, value: selectedProvider.stream ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'stream', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('uploadViaUrl'), hint: t('uploadViaUrlHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('uploadViaUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.uploadViaUrl ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'uploadViaUrl', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }), selectedProvider.protocol === 'openai' ? (0, jsx_runtime_1.jsx)(Field, { label: t('videoSupport'), hint: t('videoSupportHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('videoSupport'), disabled: !snapshot.writable || busy, value: selectedProvider.videoSupport ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'videoSupport', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('t1'), hint: t('t1Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t1'), inputMode: "numeric", value: selectedProvider.t1Seconds, onChange: (event) => { updateProvider(selectedIndex, 't1Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('t2'), hint: t('t2Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t2'), inputMode: "numeric", value: selectedProvider.t2Seconds, onChange: (event) => { updateProvider(selectedIndex, 't2Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxBytes'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxBytes'), inputMode: "numeric", value: selectedProvider.maxImageBytes, onChange: (event) => { updateProvider(selectedIndex, 'maxImageBytes', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxPixels'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxPixels'), inputMode: "numeric", value: selectedProvider.maxImagePixels, onChange: (event) => { updateProvider(selectedIndex, 'maxImagePixels', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('concurrency'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('concurrency'), inputMode: "numeric", value: selectedProvider.concurrency, onChange: (event) => { updateProvider(selectedIndex, 'concurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('attempts'), hint: t('attemptsHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('attempts'), inputMode: "numeric", value: selectedProvider.attempts, onChange: (event) => { updateProvider(selectedIndex, 'attempts', event.target.value); } }) })] }), (0, jsx_runtime_1.jsx)(Field, { label: t('apiKey'), hint: selectedBuiltInFree ? t('apiKeyBuiltInFree') : selectedKeyLocked ? t('apiKeyLocked') : t('apiKeyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('apiKey'), type: "password", autoComplete: "new-password", disabled: busy || selectedKeyLocked || selectedBuiltInFree, placeholder: selectedCredential?.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: selectedKey, onChange: (event) => { setKeys(current => ({ ...current, [selectedProvider.credential]: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-tests", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('connection', selectedIndex); }, children: state.action === 'connection' ? t('testing') : t('testConnection') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('model', selectedIndex); }, children: state.action === 'model' ? t('testingModel') : t('testModel') }), selectedProvider.protocol === 'openai' ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runVideoTest(selectedIndex); }, children: state.action === 'test-video' ? t('testingVideo') : t('testVideo') }) : null] }), providerHealth === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: ['service', 'model'].map(name => {
|
|
1456
1506
|
const check = providerHealth.checks[name];
|
|
1457
1507
|
if (check === undefined)
|
|
1458
1508
|
return null;
|
|
1459
1509
|
return (0, jsx_runtime_1.jsxs)("div", { "data-status": check.status, children: [(0, jsx_runtime_1.jsx)("span", { children: t(HEALTH_NAME_KEYS[name] ?? 'health') }), (0, jsx_runtime_1.jsx)("strong", { children: t(HEALTH_STATUS_KEYS[check.status]) }), (0, jsx_runtime_1.jsx)("p", { children: healthDetail(name, check.detail, t) })] }, name);
|
|
1460
|
-
}) })] }))] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('prioritySort') }), (0, jsx_runtime_1.jsx)("p", { children: t('prioritySortHint') })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-sorter", children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-sorter-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-index", children: index + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-name", children: provider.name.trim() || provider.model.trim() || t('provider') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveUp'), title: t('moveUp'), disabled: !snapshot.writable || busy || index === 0, onClick: () => { moveProvider(index, -1); }, children: "\u2191" }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveDown'), title: t('moveDown'), disabled: !snapshot.writable || busy || index === draft.providers.length - 1, onClick: () => { moveProvider(index, 1); }, children: "\u2193" })] })] }, index))) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-update-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtimeCheck') }), (0, jsx_runtime_1.jsx)("p", { children: t('runtimeCheckHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-actions", children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('health'); }, children: state.action === 'health' ? t('testing') : t('runHealth') }) })] }), state.health === undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('notTested') }) : (0, jsx_runtime_1.jsx)("div", { className: "dvt-health-grid", children: ['python', 'dependencies', 'chrome'].map(name => {
|
|
1510
|
+
}) }), state.videoTest === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: (0, jsx_runtime_1.jsxs)("div", { "data-status": "ok", children: [(0, jsx_runtime_1.jsx)("span", { children: t('videoSupport') }), (0, jsx_runtime_1.jsx)("strong", { children: t('statusOk') }), (0, jsx_runtime_1.jsx)("p", { children: state.videoTest.detail })] }) })] }))] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('prioritySort') }), (0, jsx_runtime_1.jsx)("p", { children: t('prioritySortHint') })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-sorter", children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-sorter-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-index", children: index + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-name", children: provider.name.trim() || provider.model.trim() || t('provider') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveUp'), title: t('moveUp'), disabled: !snapshot.writable || busy || index === 0, onClick: () => { moveProvider(index, -1); }, children: "\u2191" }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveDown'), title: t('moveDown'), disabled: !snapshot.writable || busy || index === draft.providers.length - 1, onClick: () => { moveProvider(index, 1); }, children: "\u2193" })] })] }, index))) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-update-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtimeCheck') }), (0, jsx_runtime_1.jsx)("p", { children: t('runtimeCheckHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-actions", children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('health'); }, children: state.action === 'health' ? t('testing') : t('runHealth') }) })] }), state.health === undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('notTested') }) : (0, jsx_runtime_1.jsx)("div", { className: "dvt-health-grid", children: ['python', 'dependencies', 'chrome'].map(name => {
|
|
1461
1511
|
const check = state.health?.checks[name];
|
|
1462
1512
|
if (check === undefined)
|
|
1463
1513
|
return null;
|
|
1464
1514
|
return (0, jsx_runtime_1.jsxs)("div", { "data-status": check.status, children: [(0, jsx_runtime_1.jsx)("span", { children: t(HEALTH_NAME_KEYS[name] ?? 'health') }), (0, jsx_runtime_1.jsx)("strong", { children: t(HEALTH_STATUS_KEYS[check.status]) }), (0, jsx_runtime_1.jsx)("p", { children: healthDetail(name, check.detail, t) })] }, name);
|
|
1465
|
-
}) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('updates') }), (0, jsx_runtime_1.jsx)("p", { children: t('updatesHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${pluginUpdate?.updateAvailable ? 'warning' : pluginUpdate !== undefined && pluginUpdate.supported ? 'ok' : ''}`, children: pluginUpdate?.updateAvailable ? t('updateAvailable') : pluginUpdate !== undefined && pluginUpdate.supported ? t('upToDate') : t('pluginVersion') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-update-grid", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateInstalled') }), (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateLatest') }), (0, jsx_runtime_1.jsx)("strong", { children: latestVersion ?? '—' })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateProfile') }), (0, jsx_runtime_1.jsx)("strong", { children: updateCapability.profile ?? '—' })] })] }), !updateCapability.supported ? (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert warning", children: [(0, jsx_runtime_1.jsx)("strong", { children: t('updateUnsupported') }), (0, jsx_runtime_1.jsx)("span", { children: updateReason })] }) : null, updateCapability.supported && updateHasUnsavedChanges ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('updateSaveFirst') }) : null, pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('updateAvailableDetail', { version: latestVersion }) }) : null, pluginUpdate?.supported && !pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('upToDateDetail', { version: latestVersion }) }) : null, (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('manualUpdateHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-manual-update", children: [(0, jsx_runtime_1.jsx)("code", { children: manualUpdateCommand }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", onClick: copyManualUpdate, children: copiedCommand ? t('copied') : t('copy') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-actions", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", disabled: busy || !updateCheckSupported || state.restart !== undefined, onClick: () => { void controller.checkUpdate(); }, children: state.action === 'check-update' ? t('checkingUpdate') : t('checkUpdate') }), pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "primary", disabled: busy || state.restart !== undefined || updateHasUnsavedChanges, onClick: applyUpdate, children: state.action === 'apply-update' ? t('updatingPlugin') : t('updateNow') }) : null] })] }), (0, jsx_runtime_1.jsxs)("details", { className: "dvt-advanced", children: [(0, jsx_runtime_1.jsxs)("summary", { children: [(0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)("strong", { children: t('advanced') }), (0, jsx_runtime_1.jsx)("small", { children: t('advancedHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-details-chevron", "aria-hidden": "true", children: "\u2304" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-advanced-body", children: [(0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('language') }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-form-grid", children: (0, jsx_runtime_1.jsx)(Field, { label: t('language'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.language, onChange: (event) => { update('language', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }), (0, jsx_runtime_1.jsx)("option", { value: "en", children: "English" })] }) }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('limits') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('hardTimeout'), hint: t('hardTimeoutHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('hardTimeout'), inputMode: "numeric", value: draft.hardTimeoutSeconds, onChange: (event) => { update('hardTimeoutSeconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('sessionConcurrency'), hint: t('sessionConcurrencyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('sessionConcurrency'), inputMode: "numeric", value: draft.sessionMaxConcurrency, onChange: (event) => { update('sessionMaxConcurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('minAvailable'), hint: t('minAvailableHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('minAvailable'), inputMode: "numeric", value: draft.minAvailableSeconds, onChange: (event) => { update('minAvailableSeconds', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('imageInput') }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.hiddenVariants, disabled: !snapshot.writable || busy, onChange: (event) => { update('hiddenVariants', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('hiddenVariantsLabel') }), (0, jsx_runtime_1.jsx)("small", { children: t('hiddenVariantsHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('storage') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('storageDir'), hint: t('storageDirHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageDir'), placeholder: "/tmp/dsh-vision-toolkit", value: draft.storageDir, onChange: (event) => { update('storageDir', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('allowedDirs'), hint: t('allowedDirsHint'), children: (0, jsx_runtime_1.jsx)("textarea", { rows: 3, value: draft.allowedDirs, onChange: (event) => { update('allowedDirs', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('objectStorage') }), (0, jsx_runtime_1.jsx)("p", { children: t('objectStorageHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-actions", children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.testStorage(); }, children: state.action === 'test-storage' ? t('testingStorage') : t('testStorage') }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('storageEndpoint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageEndpoint'), disabled: !snapshot.writable || busy, value: draft.storageEndpoint, onChange: (event) => { update('storageEndpoint', event.target.value); }, placeholder: "https://<account>.r2.cloudflarestorage.com" }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageBucket'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageBucket'), disabled: !snapshot.writable || busy, value: draft.storageBucket, onChange: (event) => { update('storageBucket', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageAccessKeyId'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageAccessKeyId'), type: "password", autoComplete: "new-password", disabled: busy || !snapshot.writable, placeholder: objectStorageCredential.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: storageKeys.accessKeyId, onChange: (event) => { setStorageKeys(current => ({ ...current, accessKeyId: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageSecretAccessKey'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageSecretAccessKey'), type: "password", autoComplete: "new-password", disabled: busy || !snapshot.writable, placeholder: objectStorageCredential.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: storageKeys.secretAccessKey, onChange: (event) => { setStorageKeys(current => ({ ...current, secretAccessKey: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storagePublicBase'), hint: t('storagePublicBaseHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storagePublicBase'), disabled: !snapshot.writable || busy, value: draft.storagePublicBase, onChange: (event) => { update('storagePublicBase', event.target.value); }, placeholder: "https://cdn.example.com" }) })] }), state.storageTest === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: (0, jsx_runtime_1.jsxs)("div", { "data-status": "ok", children: [(0, jsx_runtime_1.jsx)("span", { children: t('objectStorage') }), (0, jsx_runtime_1.jsx)("strong", { children: t('statusOk') }), (0, jsx_runtime_1.jsx)("p", { children: state.storageTest.detail })] }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtime') }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${snapshot.runtime.ready ? 'ok' : 'error'}`, children: snapshot.runtime.ready ? snapshot.runtime.upstream?.source === 'managed' ? t('runtimeManaged') : snapshot.runtime.upstream?.source === 'external' ? t('runtimeExternal') : t('runtimeReady') : t('runtimeUnavailable') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('runtimeMode'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.runtimeMode, onChange: (event) => { update('runtimeMode', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "managed", children: t('runtimeManaged') }), (0, jsx_runtime_1.jsx)("option", { value: "external", children: t('runtimeExternal') })] }) }), draft.runtimeMode === 'external' ? (0, jsx_runtime_1.jsx)(Field, { label: t('toolkitPath'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { value: draft.toolkitPath, onChange: (event) => { update('toolkitPath', event.target.value); } }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('python'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { placeholder: "python3", value: draft.python, onChange: (event) => { update('python', event.target.value); } }) })] }), snapshot.runtime.upstream === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-runtime-facts", children: [(0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.path }), (0, jsx_runtime_1.jsxs)("code", { children: [snapshot.runtime.upstream.python, " \u00B7 ", snapshot.runtime.upstream.pythonVersion] }), (0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.runtimeHome })] })] })] })] }), (0, jsx_runtime_1.jsxs)("footer", { className: "dvt-settings-footer", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-kicker", children: t('pluginKind') }), (0, jsx_runtime_1.jsx)("h2", { children: t('settingsTitle') }), (0, jsx_runtime_1.jsx)("p", { children: t('settingsIntro') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-release", children: [(0, jsx_runtime_1.jsxs)("span", { children: [t('pluginVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('upstreamVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.upstreamVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('activeGeneration'), " ", (0, jsx_runtime_1.jsx)("strong", { children: t('activeGenerationValue', { generation: snapshot.runtime.generation }) })] })] })] })] }));
|
|
1515
|
+
}) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('updates') }), (0, jsx_runtime_1.jsx)("p", { children: t('updatesHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${pluginUpdate?.updateAvailable ? 'warning' : pluginUpdate !== undefined && pluginUpdate.supported ? 'ok' : ''}`, children: pluginUpdate?.updateAvailable ? t('updateAvailable') : pluginUpdate !== undefined && pluginUpdate.supported ? t('upToDate') : t('pluginVersion') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-update-grid", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateInstalled') }), (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateLatest') }), (0, jsx_runtime_1.jsx)("strong", { children: latestVersion ?? '—' })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateProfile') }), (0, jsx_runtime_1.jsx)("strong", { children: updateCapability.profile ?? '—' })] })] }), !updateCapability.supported ? (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert warning", children: [(0, jsx_runtime_1.jsx)("strong", { children: t('updateUnsupported') }), (0, jsx_runtime_1.jsx)("span", { children: updateReason })] }) : null, updateCapability.supported && updateHasUnsavedChanges ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('updateSaveFirst') }) : null, pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('updateAvailableDetail', { version: latestVersion }) }) : null, pluginUpdate?.supported && !pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('upToDateDetail', { version: latestVersion }) }) : null, (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('manualUpdateHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-manual-update", children: [(0, jsx_runtime_1.jsx)("code", { children: manualUpdateCommand }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", onClick: copyManualUpdate, children: copiedCommand ? t('copied') : t('copy') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-actions", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", disabled: busy || !updateCheckSupported || state.restart !== undefined, onClick: () => { void controller.checkUpdate(); }, children: state.action === 'check-update' ? t('checkingUpdate') : t('checkUpdate') }), pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "primary", disabled: busy || state.restart !== undefined || updateHasUnsavedChanges, onClick: applyUpdate, children: state.action === 'apply-update' ? t('updatingPlugin') : t('updateNow') }) : null] })] }), (0, jsx_runtime_1.jsxs)("details", { className: "dvt-advanced", children: [(0, jsx_runtime_1.jsxs)("summary", { children: [(0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)("strong", { children: t('advanced') }), (0, jsx_runtime_1.jsx)("small", { children: t('advancedHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-details-chevron", "aria-hidden": "true", children: "\u2304" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-advanced-body", children: [(0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('language') }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-form-grid", children: (0, jsx_runtime_1.jsx)(Field, { label: t('language'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.language, onChange: (event) => { update('language', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }), (0, jsx_runtime_1.jsx)("option", { value: "en", children: "English" })] }) }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('limits') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('hardTimeout'), hint: t('hardTimeoutHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('hardTimeout'), inputMode: "numeric", value: draft.hardTimeoutSeconds, onChange: (event) => { update('hardTimeoutSeconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('sessionConcurrency'), hint: t('sessionConcurrencyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('sessionConcurrency'), inputMode: "numeric", value: draft.sessionMaxConcurrency, onChange: (event) => { update('sessionMaxConcurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('minAvailable'), hint: t('minAvailableHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('minAvailable'), inputMode: "numeric", value: draft.minAvailableSeconds, onChange: (event) => { update('minAvailableSeconds', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('imageInput') }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.hiddenVariants, disabled: !snapshot.writable || busy, onChange: (event) => { update('hiddenVariants', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('hiddenVariantsLabel') }), (0, jsx_runtime_1.jsx)("small", { children: t('hiddenVariantsHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('toolVisibility') }), (0, jsx_runtime_1.jsx)("p", { children: t('toolVisibilityHint') })] }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.toolVisibilityLocal, disabled: !snapshot.writable || busy, onChange: (event) => { update('toolVisibilityLocal', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('toolVisibilityLocal') }), (0, jsx_runtime_1.jsx)("small", { children: t('toolVisibilityLocalHint') })] }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.toolVisibilityOnline, disabled: !snapshot.writable || busy, onChange: (event) => { update('toolVisibilityOnline', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('toolVisibilityOnline') }), (0, jsx_runtime_1.jsx)("small", { children: t('toolVisibilityOnlineHint') })] }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.toolVisibilityVideo, disabled: !snapshot.writable || busy, onChange: (event) => { update('toolVisibilityVideo', event.target.checked); } }), (0, jsx_runtime_1.jsxs)("span", { children: [t('toolVisibilityVideo'), " ", (0, jsx_runtime_1.jsx)("em", { children: "\uFF08\u6D4B\u8BD5\uFF09" })] }), (0, jsx_runtime_1.jsx)("small", { children: t('toolVisibilityVideoHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('storage') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('storageDir'), hint: t('storageDirHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageDir'), placeholder: "/tmp/dsh-vision-toolkit", value: draft.storageDir, onChange: (event) => { update('storageDir', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('allowedDirs'), hint: t('allowedDirsHint'), children: (0, jsx_runtime_1.jsx)("textarea", { rows: 3, value: draft.allowedDirs, onChange: (event) => { update('allowedDirs', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('objectStorage') }), (0, jsx_runtime_1.jsx)("p", { children: t('objectStorageHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-actions", children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.testStorage(); }, children: state.action === 'test-storage' ? t('testingStorage') : t('testStorage') }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('storageEndpoint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageEndpoint'), disabled: !snapshot.writable || busy, value: draft.storageEndpoint, onChange: (event) => { update('storageEndpoint', event.target.value); }, placeholder: "https://<account>.r2.cloudflarestorage.com" }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageBucket'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageBucket'), disabled: !snapshot.writable || busy, value: draft.storageBucket, onChange: (event) => { update('storageBucket', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageAccessKeyId'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageAccessKeyId'), type: "password", autoComplete: "new-password", disabled: busy || !snapshot.writable, placeholder: objectStorageCredential.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: storageKeys.accessKeyId, onChange: (event) => { setStorageKeys(current => ({ ...current, accessKeyId: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageSecretAccessKey'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageSecretAccessKey'), type: "password", autoComplete: "new-password", disabled: busy || !snapshot.writable, placeholder: objectStorageCredential.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: storageKeys.secretAccessKey, onChange: (event) => { setStorageKeys(current => ({ ...current, secretAccessKey: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storagePublicBase'), hint: t('storagePublicBaseHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storagePublicBase'), disabled: !snapshot.writable || busy, value: draft.storagePublicBase, onChange: (event) => { update('storagePublicBase', event.target.value); }, placeholder: "https://cdn.example.com" }) })] }), state.storageTest === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: (0, jsx_runtime_1.jsxs)("div", { "data-status": "ok", children: [(0, jsx_runtime_1.jsx)("span", { children: t('objectStorage') }), (0, jsx_runtime_1.jsx)("strong", { children: t('statusOk') }), (0, jsx_runtime_1.jsx)("p", { children: state.storageTest.detail })] }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtime') }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${snapshot.runtime.ready ? 'ok' : 'error'}`, children: snapshot.runtime.ready ? snapshot.runtime.upstream?.source === 'managed' ? t('runtimeManaged') : snapshot.runtime.upstream?.source === 'external' ? t('runtimeExternal') : t('runtimeReady') : t('runtimeUnavailable') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('runtimeMode'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.runtimeMode, onChange: (event) => { update('runtimeMode', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "managed", children: t('runtimeManaged') }), (0, jsx_runtime_1.jsx)("option", { value: "external", children: t('runtimeExternal') })] }) }), draft.runtimeMode === 'external' ? (0, jsx_runtime_1.jsx)(Field, { label: t('toolkitPath'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { value: draft.toolkitPath, onChange: (event) => { update('toolkitPath', event.target.value); } }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('python'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { placeholder: "python3", value: draft.python, onChange: (event) => { update('python', event.target.value); } }) })] }), snapshot.runtime.upstream === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-runtime-facts", children: [(0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.path }), (0, jsx_runtime_1.jsxs)("code", { children: [snapshot.runtime.upstream.python, " \u00B7 ", snapshot.runtime.upstream.pythonVersion] }), (0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.runtimeHome })] })] })] })] }), (0, jsx_runtime_1.jsxs)("footer", { className: "dvt-settings-footer", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-kicker", children: t('pluginKind') }), (0, jsx_runtime_1.jsx)("h2", { children: t('settingsTitle') }), (0, jsx_runtime_1.jsx)("p", { children: t('settingsIntro') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-release", children: [(0, jsx_runtime_1.jsxs)("span", { children: [t('pluginVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('upstreamVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.upstreamVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('activeGeneration'), " ", (0, jsx_runtime_1.jsx)("strong", { children: t('activeGenerationValue', { generation: snapshot.runtime.generation }) })] })] })] })] }));
|
|
1466
1516
|
}
|
|
1467
1517
|
const CSS = `
|
|
1468
1518
|
.dvt-tool{margin:4px 0;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-1);overflow:hidden;box-shadow:var(--dsw-shadow-lv1)}
|