dsh-web-search-enhanced 0.0.5 → 0.0.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/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/docs/design.zh-CN.md +7 -1
- package/lib/client.js +80 -17
- package/lib/client.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/types/client/SearchSettingsCard.d.ts +19 -1
- package/package.json +1 -1
- package/docs/harness-contract.md +0 -30
- package/docs/template-comparison.md +0 -35
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the `dsh-web-search-enhanced` package will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.0.6] - 2026-09-11
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- **Sparse Settings Mutation & Bloat Prevention**: Redesigned client settings card (`SearchSettingsCard`) with differential analysis (`computeSettingsOperations`) against schema defaults and composition base. Default values matching the inherited baseline are omitted to prevent `$DSH_HOME/settings.yaml` from bloating.
|
|
9
|
+
- **Redundant Overrides Self-Healing & Pruning**: Existing redundant default keys in user settings are automatically pruned via `unset` operations on save or reset, restoring a clean configuration file for existing users.
|
|
10
|
+
- **Single Atomic Mutation Batching (`scope.mutate`)**: Replaced consecutive serial `scope.set` calls with a single atomic `scope.mutate(ops)` transaction, eliminating multiple filesystem locks and I/O thrashing during settings persistence.
|
|
11
|
+
- **Decoupled Credential Storage**: Saving an API key without modifying other configuration parameters executes credential writes exclusively, resulting in zero mutations written to `settings.yaml`.
|
|
12
|
+
|
|
13
|
+
### Removed
|
|
14
|
+
- **Scaffolding & Outdated Documentation**: Cleaned up obsolete template comparison and outdated alpha contract references from `docs/`.
|
|
15
|
+
|
|
5
16
|
## [0.0.5] - 2026-09-11
|
|
6
17
|
|
|
7
18
|
### Changed
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
- **跟随当前会话 (`current-session`)**:自动继承当前会话正在使用的模型、提供方、调用协议与凭据,直接使用主模型供应商的搜索功能。
|
|
27
27
|
- **固定搜索路由 (`configured`)**:为联网搜索单独指定专用搜索模型(如 `deepseek-flash`、`claude-3-7-sonnet`、`gpt-4o` 等),主对话与搜索模型分工明确。
|
|
28
28
|
- **智能平滑兜底 (`fallbackModel`)**:当跟随模式遇到未知或未配置的模型路由时,自动降级至备用模型,确保搜索永不断流。
|
|
29
|
-
- 🖥️ **Web
|
|
29
|
+
- 🖥️ **Web 控制台可视化与稀疏配置 (Sparse Overrides)**:深度集成 DSH Web 端「设置 → 插件 → Web Search Enhanced」,支持中英文双语、即时表单校验、草稿暂存、一键保存与重置。遵循 DSH 原生稀疏覆盖规范,默认值不写入 `$DSH_HOME/settings.yaml`,杜绝配置文件膨胀与默认值锁死,并支持存量冗余项自动修剪。
|
|
30
30
|
- 🔒 **凭据安全与隐私保护**:通过 DSH 原生 Credentials 机制安全写入并保管 API Key,公开设置文档绝不保存明文密钥;请求强制阻断携带凭据的恶意 HTTP 重定向。
|
|
31
31
|
- 🎯 **开箱即用无感集成**:上游响应中的来源和引用会自动归一化为标准的 DSH `WebSearchResult`;主模型提示词和工作流无需任何改动。
|
|
32
32
|
|
package/docs/design.zh-CN.md
CHANGED
|
@@ -41,7 +41,13 @@ Chat Completions 与 Responses 的联网搜索表示不同。官方 Chat Complet
|
|
|
41
41
|
|
|
42
42
|
## 4. 配置模型
|
|
43
43
|
|
|
44
|
-
Schema defaults → Profile composition base →
|
|
44
|
+
Schema defaults → Profile composition base → 用户持久化覆盖构成三层设置层级。设置系统遵循稀疏覆盖(Sparse Overrides)原则:
|
|
45
|
+
1. **默认值不写入**:配置卡片在保存时比对用户编辑值与继承基准(Base / Schema default),与默认值一致且原本未覆盖的项不写入 `$DSH_HOME/settings.yaml`,避免配置文件膨胀与默认值版本锁死;
|
|
46
|
+
2. **存量冗余项自动修剪**:对于历史版本中已全量写入默认值的用户,在保存或重置时自动将匹配默认值的键通过 `unset` 移除,实现配置文件静默瘦身;
|
|
47
|
+
3. **单次原子提交**:使用 `scope.mutate(ops)` 批量原子提交所有的 `set` 与 `unset` 变更,避免逐字段串行 I/O 与文件锁争用;
|
|
48
|
+
4. **机密与配置隔离**:API Key 仅写入 DSH 安全凭据域(Credentials Domain),纯 Key 录入对 `settings.yaml` 产生 0 写入。
|
|
49
|
+
|
|
50
|
+
resolved config 在操作入口校验 provider ID、绝对 URL、必填字符串、安全标识符、正整数 Token/使用次数和封闭 context-size 枚举。配置卡片采用暂存编辑;客户端即时校验,Host 执行权威校验。恢复 Profile 清除用户层字段,不复制默认值。
|
|
45
51
|
|
|
46
52
|
## 5. 错误与安全
|
|
47
53
|
|
package/lib/client.js
CHANGED
|
@@ -21,6 +21,76 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
"chatSearchMode",
|
|
22
22
|
"searchContextSize"
|
|
23
23
|
];
|
|
24
|
+
/** Schema default values aligned with host plugin definitions. */
|
|
25
|
+
const SCHEMA_DEFAULTS = {
|
|
26
|
+
modelMode: "configured",
|
|
27
|
+
protocol: "anthropic-messages",
|
|
28
|
+
baseURL: "https://api.deepseek.com/anthropic/v1",
|
|
29
|
+
model: "deepseek-flash",
|
|
30
|
+
fallbackModel: void 0,
|
|
31
|
+
apiKeyEnv: "WEB_SEARCH_ENHANCED_API",
|
|
32
|
+
apiVersion: "2023-06-01",
|
|
33
|
+
toolIdentifier: void 0,
|
|
34
|
+
maxTokens: 4096,
|
|
35
|
+
maxUses: 5,
|
|
36
|
+
chatSearchMode: "search-model",
|
|
37
|
+
searchContextSize: void 0
|
|
38
|
+
};
|
|
39
|
+
function targetValuesFromDraft(draft) {
|
|
40
|
+
return {
|
|
41
|
+
modelMode: draft.modelMode,
|
|
42
|
+
protocol: draft.protocol,
|
|
43
|
+
baseURL: draft.baseURL.trim(),
|
|
44
|
+
model: draft.model.trim(),
|
|
45
|
+
fallbackModel: draft.fallbackModel.trim().length === 0 ? void 0 : draft.fallbackModel.trim(),
|
|
46
|
+
apiKeyEnv: draft.apiKeyEnv.trim(),
|
|
47
|
+
apiVersion: draft.apiVersion.trim(),
|
|
48
|
+
toolIdentifier: draft.toolIdentifier.trim().length === 0 ? void 0 : draft.toolIdentifier.trim(),
|
|
49
|
+
maxTokens: Number(draft.maxTokens),
|
|
50
|
+
maxUses: Number(draft.maxUses),
|
|
51
|
+
chatSearchMode: draft.chatSearchMode,
|
|
52
|
+
searchContextSize: draft.searchContextSize === "" ? void 0 : draft.searchContextSize
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Compute sparse mutation operations required to synchronize user overrides.
|
|
57
|
+
* Default values matching the inherited baseline are omitted to prevent settings.yaml
|
|
58
|
+
* bloating, and existing redundant overrides are pruned automatically.
|
|
59
|
+
*/
|
|
60
|
+
function computeSettingsOperations(draft, snapshot, resetToProfile = false) {
|
|
61
|
+
const baseConfig = typeof snapshot.base === "object" && snapshot.base !== null ? snapshot.base : {};
|
|
62
|
+
const userConfig = typeof snapshot.user === "object" && snapshot.user !== null ? snapshot.user : {};
|
|
63
|
+
const ops = [];
|
|
64
|
+
if (resetToProfile) {
|
|
65
|
+
for (const field of editableFields) if (field in userConfig) ops.push({
|
|
66
|
+
op: "unset",
|
|
67
|
+
path: [field]
|
|
68
|
+
});
|
|
69
|
+
return ops;
|
|
70
|
+
}
|
|
71
|
+
const targets = targetValuesFromDraft(draft);
|
|
72
|
+
for (const field of editableFields) {
|
|
73
|
+
const targetVal = targets[field];
|
|
74
|
+
const baselineVal = baseConfig[field] !== void 0 ? baseConfig[field] : SCHEMA_DEFAULTS[field];
|
|
75
|
+
const isOverriddenInUser = field in userConfig;
|
|
76
|
+
if (targetVal !== baselineVal) {
|
|
77
|
+
if (targetVal === void 0) {
|
|
78
|
+
if (isOverriddenInUser) ops.push({
|
|
79
|
+
op: "unset",
|
|
80
|
+
path: [field]
|
|
81
|
+
});
|
|
82
|
+
} else ops.push({
|
|
83
|
+
op: "set",
|
|
84
|
+
path: [field],
|
|
85
|
+
value: targetVal
|
|
86
|
+
});
|
|
87
|
+
} else if (isOverriddenInUser) ops.push({
|
|
88
|
+
op: "unset",
|
|
89
|
+
path: [field]
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return ops;
|
|
93
|
+
}
|
|
24
94
|
/** Convert resolved settings into a stable form draft. */
|
|
25
95
|
function draftFrom(value) {
|
|
26
96
|
return {
|
|
@@ -318,23 +388,16 @@ window.__ModuleLoader__.load({
|
|
|
318
388
|
setFailed(false);
|
|
319
389
|
try {
|
|
320
390
|
if (await saveCredential(credentials, draft.apiKeyEnv, apiKey)) setCredentialConfigured(true);
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (draft.toolIdentifier.trim().length === 0) await scope.unset("toolIdentifier");
|
|
332
|
-
else await scope.set("toolIdentifier", draft.toolIdentifier.trim());
|
|
333
|
-
await scope.set("maxTokens", Number(draft.maxTokens));
|
|
334
|
-
await scope.set("maxUses", Number(draft.maxUses));
|
|
335
|
-
await scope.set("chatSearchMode", draft.chatSearchMode);
|
|
336
|
-
if (draft.searchContextSize === "") await scope.unset("searchContextSize");
|
|
337
|
-
else await scope.set("searchContextSize", draft.searchContextSize);
|
|
391
|
+
const ops = computeSettingsOperations(draft, snapshot, resetToProfile);
|
|
392
|
+
if (ops.length > 0) {
|
|
393
|
+
if (typeof scope.mutate === "function") await scope.mutate(ops);
|
|
394
|
+
else for (const op of ops) {
|
|
395
|
+
const field = op.path[0];
|
|
396
|
+
if (field !== void 0) {
|
|
397
|
+
if (op.op === "set") await scope.set(field, op.value);
|
|
398
|
+
else await scope.unset(field);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
338
401
|
}
|
|
339
402
|
setApiKey("");
|
|
340
403
|
setHasDraft(false);
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useSyncExternalStore","useMemo","useState","useId","_jsxs","_jsx","_Fragment"],"sources":["types/client/SearchSettingsCard.js","types/client/locales.js","types/client/index.js"],"sourcesContent":["import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport { useEffect, useId, useMemo, useState, useSyncExternalStore } from 'react';\nconst editableFields = ['modelMode', 'protocol', 'baseURL', 'model', 'fallbackModel', 'apiKeyEnv', 'apiVersion', 'toolIdentifier', 'maxTokens', 'maxUses', 'chatSearchMode', 'searchContextSize'];\n/** Convert resolved settings into a stable form draft. */\nexport function draftFrom(value) {\n return {\n modelMode: value?.modelMode ?? 'configured',\n protocol: value?.protocol ?? 'anthropic-messages',\n baseURL: value?.baseURL ?? 'https://api.deepseek.com/anthropic/v1',\n model: value?.model ?? 'deepseek-flash',\n fallbackModel: value?.fallbackModel ?? '',\n apiKeyEnv: value?.apiKeyEnv ?? 'WEB_SEARCH_ENHANCED_API',\n apiVersion: value?.apiVersion ?? '2023-06-01',\n toolIdentifier: value?.toolIdentifier ?? '',\n maxTokens: String(value?.maxTokens ?? 4096),\n maxUses: String(value?.maxUses ?? 5),\n chatSearchMode: value?.chatSearchMode ?? 'search-model',\n searchContextSize: value?.searchContextSize ?? '',\n };\n}\n/** Validate a draft and return field-specific locale keys. */\nexport async function saveCredential(credentials, ref, value) {\n const secret = value.trim();\n if (secret.length === 0)\n return false;\n const result = await credentials.set(ref.trim(), secret);\n if (!result.ok)\n throw new Error(result.error.message);\n return true;\n}\nexport function validateDraft(draft) {\n const errors = {};\n try {\n const url = new URL(draft.baseURL);\n if (url.protocol !== 'http:' && url.protocol !== 'https:')\n errors.baseURL = 'invalidURL';\n }\n catch {\n errors.baseURL = 'invalidURL';\n }\n if (draft.model.trim().length === 0)\n errors.model = 'invalidRequired';\n if (draft.apiKeyEnv.trim().length === 0)\n errors.apiKeyEnv = 'invalidRequired';\n if (draft.apiKeyEnv.trim().length > 0 && !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(draft.apiKeyEnv.trim()))\n errors.apiKeyEnv = 'invalidCredentialRef';\n if (draft.apiVersion.trim().length === 0)\n errors.apiVersion = 'invalidRequired';\n if (draft.toolIdentifier.length > 0 && !/^[A-Za-z][A-Za-z0-9_.:-]{0,127}$/u.test(draft.toolIdentifier))\n errors.toolIdentifier = 'invalidIdentifier';\n if (!positiveInteger(draft.maxTokens))\n errors.maxTokens = 'invalidInteger';\n if (!positiveInteger(draft.maxUses))\n errors.maxUses = 'invalidInteger';\n return errors;\n}\nconst cardCss = `\n.wse-card {\n list-style: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3);\n color: var(--dsw-alias-label-primary);\n transition: border-color .16s, background .16s;\n}\n.wse-card:hover {\n border-color: var(--dsw-alias-label-dimmed);\n}\n.wse-card[data-open='true'] {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n.wse-header {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n}\n.wse-header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.wse-head {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.wse-name {\n color: var(--dsw-alias-label-primary);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n.wse-desc {\n color: var(--dsw-alias-label-tertiary);\n font-size: 13px;\n line-height: 1.5;\n}\n.wse-pending {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n flex: none;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.wse-chevron {\n box-sizing: border-box;\n flex: none;\n width: 8px;\n height: 8px;\n margin-right: 3px;\n border-right: 1.5px solid var(--dsw-alias-label-tertiary);\n border-bottom: 1.5px solid var(--dsw-alias-label-tertiary);\n transform: rotate(45deg);\n transition: transform .16s;\n}\n.wse-card[data-open='true'] .wse-chevron {\n transform: rotate(225deg);\n}\n.wse-body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin: 0 16px;\n padding-bottom: 8px;\n}\n.wse-fields {\n display: flex;\n flex-direction: column;\n}\n.wse-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.wse-field + .wse-field {\n border-top: 1px solid var(--dsw-alias-border-l2);\n}\n.wse-label {\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n}\n.wse-input, .wse-select {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 0 12px;\n background: var(--dsw-alias-bg-layer-3);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n outline: none;\n transition: border-color .16s, background .16s;\n}\n.wse-input:focus-visible, .wse-select:focus-visible,\n.wse-input:focus, .wse-select:focus {\n border-color: var(--dsw-alias-brand-primary);\n outline: none;\n}\n.wse-input[aria-invalid='true'] {\n border-color: var(--dsw-alias-label-error);\n}\n.wse-input:disabled, .wse-select:disabled {\n cursor: default;\n color: var(--dsw-alias-label-tertiary);\n opacity: .55;\n}\n.wse-hint, .wse-error, .wse-readonly, .wse-failed {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n.wse-hint {\n color: var(--dsw-alias-label-tertiary);\n}\n.wse-error, .wse-failed {\n color: var(--dsw-alias-label-error);\n}\n.wse-readonly {\n margin: 12px 0 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.wse-footer {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin-top: 4px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 0 4px;\n}\n.wse-failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n.wse-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n}\n.wse-button {\n appearance: none;\n font: inherit;\n cursor: pointer;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 1.5;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n transition: color .16s, border-color .16s, background .16s, opacity .16s;\n}\n.wse-button:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n background: var(--dsw-alias-bg-layer-4);\n}\n.wse-button:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.wse-button:disabled {\n opacity: .4;\n cursor: default;\n}\n.wse-save {\n border-color: transparent;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary-foreground, var(--dsw-alias-bg-layer-3));\n}\n.wse-save:hover:not(:disabled) {\n background: var(--dsw-alias-label-primary);\n opacity: .9;\n}\n`;\nexport function SearchSettingsCard({ scope, credentials, t }) {\n const snapshot = useSyncExternalStore(scope.subscribe.bind(scope), scope.getSnapshot.bind(scope));\n const resolved = useMemo(() => draftFrom(snapshot.value), [snapshot.value]);\n const [draft, setDraft] = useState(resolved);\n const [open, setOpen] = useState(false);\n const [saving, setSaving] = useState(false);\n const [failed, setFailed] = useState(false);\n const [hasDraft, setHasDraft] = useState(false);\n const [resetToProfile, setResetToProfile] = useState(false);\n const [apiKey, setApiKey] = useState('');\n const [credentialConfigured, setCredentialConfigured] = useState(false);\n const bodyId = useId();\n useEffect(() => { if (!saving && !hasDraft)\n setDraft(resolved); }, [hasDraft, resolved, saving]);\n useEffect(() => {\n const ref = draft.apiKeyEnv.trim();\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(ref)) {\n setCredentialConfigured(false);\n return;\n }\n let active = true;\n void credentials.describe([ref]).then(result => {\n if (active)\n setCredentialConfigured(result.ok && result.value[ref]?.configured === true);\n }).catch(() => { if (active)\n setCredentialConfigured(false); });\n return () => { active = false; };\n }, [credentials, draft.apiKeyEnv]);\n const errors = useMemo(() => validateDraft(draft), [draft]);\n const dirty = resetToProfile || apiKey.length > 0 || JSON.stringify(draft) !== JSON.stringify(resolved);\n const invalid = Object.keys(errors).length > 0;\n const disabled = snapshot.status !== 'ready' || !snapshot.writable || saving;\n const edit = (field, value) => {\n setDraft(current => ({ ...current, [field]: value }));\n setResetToProfile(false);\n setHasDraft(true);\n setFailed(false);\n };\n const save = async () => {\n if (disabled || !dirty || invalid)\n return;\n setSaving(true);\n setFailed(false);\n try {\n if (await saveCredential(credentials, draft.apiKeyEnv, apiKey))\n setCredentialConfigured(true);\n if (resetToProfile) {\n for (const field of editableFields)\n await scope.unset(field);\n }\n else {\n await scope.set('modelMode', draft.modelMode);\n await scope.set('protocol', draft.protocol);\n await scope.set('baseURL', draft.baseURL.trim());\n await scope.set('model', draft.model.trim());\n if (draft.fallbackModel.trim().length === 0)\n await scope.unset('fallbackModel');\n else\n await scope.set('fallbackModel', draft.fallbackModel.trim());\n await scope.set('apiKeyEnv', draft.apiKeyEnv.trim());\n await scope.set('apiVersion', draft.apiVersion.trim());\n if (draft.toolIdentifier.trim().length === 0)\n await scope.unset('toolIdentifier');\n else\n await scope.set('toolIdentifier', draft.toolIdentifier.trim());\n await scope.set('maxTokens', Number(draft.maxTokens));\n await scope.set('maxUses', Number(draft.maxUses));\n await scope.set('chatSearchMode', draft.chatSearchMode);\n if (draft.searchContextSize === '')\n await scope.unset('searchContextSize');\n else\n await scope.set('searchContextSize', draft.searchContextSize);\n }\n setApiKey('');\n setHasDraft(false);\n setResetToProfile(false);\n setOpen(false);\n }\n catch {\n setFailed(true);\n }\n finally {\n setSaving(false);\n }\n };\n const reset = () => { setApiKey(''); setDraft(draftFrom(asSearchSettings(snapshot.base))); setResetToProfile(true); setHasDraft(true); setFailed(false); };\n const discard = () => { setApiKey(''); setDraft(resolved); setResetToProfile(false); setHasDraft(false); setFailed(false); };\n if (snapshot.status === 'unavailable')\n return null;\n const toolHint = draft.protocol === 'anthropic-messages' ? 'toolHintAnthropic' : draft.protocol === 'openai-responses' ? 'toolHintResponses' : draft.chatSearchMode === 'search-model' ? 'toolHintChatOfficial' : 'toolHintChatVendor';\n return _jsxs(\"li\", { className: \"wse-card\", \"data-open\": open, \"data-plugin-key\": \"web-search-enhanced\", \"data-wse-card\": \"true\", children: [_jsx(\"style\", { children: cardCss }), _jsxs(\"button\", { type: \"button\", className: \"wse-header\", \"aria-expanded\": open, \"aria-controls\": bodyId, \"aria-label\": `${t(open ? 'collapse' : 'expand')}: ${t('title')}`, onClick: () => { setOpen(value => !value); }, children: [_jsxs(\"span\", { className: \"wse-head\", children: [_jsx(\"span\", { className: \"wse-name\", children: t('title') }), _jsx(\"span\", { className: \"wse-desc\", children: t('description') })] }), dirty ? _jsx(\"span\", { className: \"wse-pending\", children: t('unsaved') }) : null, _jsx(\"span\", { className: \"wse-chevron\", \"aria-hidden\": \"true\" })] }), open ? _jsxs(\"div\", { className: \"wse-body\", id: bodyId, children: [!snapshot.writable && snapshot.status === 'ready' ? _jsx(\"p\", { className: \"wse-readonly\", role: \"status\", children: t('readOnly') }) : null, _jsxs(\"div\", { className: \"wse-fields\", children: [_jsx(SelectField, { label: t('modelMode'), hint: t('modelModeHint'), value: draft.modelMode, disabled: disabled, onChange: value => { edit('modelMode', value); }, options: [[\"configured\", t('configuredMode')], [\"current-session\", t('currentSessionMode')]] }), _jsx(SelectField, { label: t('protocol'), hint: t('protocolHint'), value: draft.protocol, disabled: disabled, onChange: value => { edit('protocol', value); }, options: [[\"anthropic-messages\", t('anthropic')], [\"openai-responses\", t('responses')], [\"openai-chat-completions\", t('chat')]] }), _jsx(TextField, { label: t('toolIdentifier'), hint: t(toolHint), value: draft.toolIdentifier, error: errors.toolIdentifier === undefined ? undefined : t(errors.toolIdentifier), disabled: disabled || (draft.protocol === 'openai-chat-completions' && draft.chatSearchMode === 'search-model'), onChange: value => { edit('toolIdentifier', value); } }), _jsx(TextField, { label: t('baseURL'), hint: t('baseURLHint'), value: draft.baseURL, error: errors.baseURL === undefined ? undefined : t(errors.baseURL), disabled: disabled, onChange: value => { edit('baseURL', value); } }), _jsx(TextField, { label: t('model'), hint: t('modelHint'), value: draft.model, error: errors.model === undefined ? undefined : t(errors.model), disabled: disabled, onChange: value => { edit('model', value); } }), _jsx(TextField, { label: t('fallbackModel'), hint: t('fallbackModelHint'), value: draft.fallbackModel, error: errors.fallbackModel === undefined ? undefined : t(errors.fallbackModel), disabled: disabled, onChange: value => { edit('fallbackModel', value); } }), _jsx(TextField, { label: t('apiKeyEnv'), hint: credentialConfigured ? t('credentialConfigured') : t('apiKeyEnvHint'), value: draft.apiKeyEnv, error: errors.apiKeyEnv === undefined ? undefined : t(errors.apiKeyEnv), disabled: disabled, onChange: value => { edit('apiKeyEnv', value); } }), _jsx(TextField, { type: \"password\", label: t('apiKey'), hint: t('apiKeyHint'), value: apiKey, disabled: disabled, onChange: value => { setApiKey(value); setHasDraft(true); setFailed(false); } }), _jsx(TextField, { inputMode: \"numeric\", label: t('maxTokens'), hint: t('maxTokensHint'), value: draft.maxTokens, error: errors.maxTokens === undefined ? undefined : t(errors.maxTokens), disabled: disabled, onChange: value => { edit('maxTokens', value); } }), draft.modelMode === 'current-session' ? (_jsxs(_Fragment, { children: [_jsx(TextField, { inputMode: \"numeric\", label: t('maxUses'), hint: t('maxUsesHint'), value: draft.maxUses, error: errors.maxUses === undefined ? undefined : t(errors.maxUses), disabled: disabled, onChange: value => { edit('maxUses', value); } }), _jsx(TextField, { label: t('apiVersion'), hint: t('apiVersionHint'), value: draft.apiVersion, error: errors.apiVersion === undefined ? undefined : t(errors.apiVersion), disabled: disabled, onChange: value => { edit('apiVersion', value); } }), _jsx(SelectField, { label: t('chatSearchMode'), hint: t('chatSearchModeHint'), value: draft.chatSearchMode, disabled: disabled, onChange: value => { edit('chatSearchMode', value); }, options: [[\"search-model\", t('chatOfficial')], [\"vendor-options\", t('chatVendor')]] }), _jsx(SelectField, { label: t('searchContextSize'), hint: t('searchContextSizeHint'), value: draft.searchContextSize, disabled: disabled, onChange: value => { edit('searchContextSize', value); }, options: [[\"\", t('contextDefault')], [\"low\", t('contextLow')], [\"medium\", t('contextMedium')], [\"high\", t('contextHigh')]] })] })) : draft.protocol === 'anthropic-messages' ? (_jsxs(_Fragment, { children: [_jsx(TextField, { inputMode: \"numeric\", label: t('maxUses'), hint: t('maxUsesHint'), value: draft.maxUses, error: errors.maxUses === undefined ? undefined : t(errors.maxUses), disabled: disabled, onChange: value => { edit('maxUses', value); } }), _jsx(TextField, { label: t('apiVersion'), hint: t('apiVersionHint'), value: draft.apiVersion, error: errors.apiVersion === undefined ? undefined : t(errors.apiVersion), disabled: disabled, onChange: value => { edit('apiVersion', value); } })] })) : (_jsxs(_Fragment, { children: [draft.protocol === 'openai-chat-completions' ? (_jsx(SelectField, { label: t('chatSearchMode'), hint: t('chatSearchModeHint'), value: draft.chatSearchMode, disabled: disabled, onChange: value => { edit('chatSearchMode', value); }, options: [[\"search-model\", t('chatOfficial')], [\"vendor-options\", t('chatVendor')]] })) : null, _jsx(SelectField, { label: t('searchContextSize'), hint: t('searchContextSizeHint'), value: draft.searchContextSize, disabled: disabled, onChange: value => { edit('searchContextSize', value); }, options: [[\"\", t('contextDefault')], [\"low\", t('contextLow')], [\"medium\", t('contextMedium')], [\"high\", t('contextHigh')]] })] }))] }), _jsxs(\"div\", { className: \"wse-footer\", children: [failed ? _jsx(\"p\", { className: \"wse-failed\", role: \"alert\", children: t('failed') }) : null, _jsxs(\"div\", { className: \"wse-actions\", children: [_jsx(\"button\", { type: \"button\", className: \"wse-button\", disabled: disabled || resetToProfile, onClick: reset, children: t('reset') }), _jsx(\"button\", { type: \"button\", className: \"wse-button\", disabled: disabled || !dirty, onClick: discard, children: t('discard') }), _jsx(\"button\", { type: \"button\", className: \"wse-button wse-save\", disabled: disabled || !dirty || invalid, onClick: () => { void save(); }, children: saving ? t('saving') : t('save') })] })] })] }) : null] });\n}\nfunction TextField(props) {\n const id = useId();\n const describedBy = useId();\n return _jsxs(\"div\", { className: \"wse-field\", children: [_jsx(\"label\", { className: \"wse-label\", htmlFor: id, children: props.label }), _jsx(\"input\", { id: id, className: \"wse-input\", type: props.type ?? 'text', value: props.value, disabled: props.disabled, inputMode: props.inputMode, \"aria-invalid\": props.error === undefined ? undefined : true, \"aria-describedby\": describedBy, spellCheck: false, onChange: event => { props.onChange(event.target.value); } }), _jsx(\"p\", { id: describedBy, className: props.error === undefined ? 'wse-hint' : 'wse-error', children: props.error ?? props.hint })] });\n}\nfunction SelectField(props) {\n const id = useId();\n const describedBy = useId();\n return _jsxs(\"div\", { className: \"wse-field\", children: [_jsx(\"label\", { className: \"wse-label\", htmlFor: id, children: props.label }), _jsx(\"select\", { id: id, className: \"wse-select\", value: props.value, disabled: props.disabled, \"aria-describedby\": describedBy, onChange: event => { props.onChange(event.target.value); }, children: props.options.map(([value, label]) => _jsx(\"option\", { value: value, children: label }, value)) }), _jsx(\"p\", { id: describedBy, className: \"wse-hint\", children: props.hint })] });\n}\nfunction asSearchSettings(value) { return typeof value === 'object' && value !== null ? value : undefined; }\nfunction positiveInteger(value) { const parsed = Number(value); return Number.isInteger(parsed) && parsed > 0; }\n//# sourceMappingURL=SearchSettingsCard.js.map","export const en = {\n title: 'Web Search Enhanced',\n description: 'Choose the model route and built-in search settings used by web_search.',\n expand: 'Expand', collapse: 'Collapse', unsaved: 'Unsaved',\n modelMode: 'Model route', modelModeHint: 'Use the fixed search route or follow the model and calling protocol of the current session.',\n configuredMode: 'Fixed configuration', currentSessionMode: 'Current session model',\n protocol: 'API protocol', protocolHint: 'The fixed or fallback route protocol. Follow mode uses the current model protocol when available.',\n anthropic: 'Anthropic Messages v1', responses: 'OpenAI Responses API', chat: 'OpenAI Chat Completions API',\n baseURL: 'Endpoint base URL', baseURLHint: 'The protocol endpoint suffix is appended only when it is not already present.',\n model: 'Model ID', modelHint: 'The model used by the fixed route and when no session model is available.',\n fallbackModel: 'Fallback search model', fallbackModelHint: 'Optional model used when the current session route cannot be resolved; blank uses Model ID.',\n apiKeyEnv: 'API key environment variable', apiKeyEnvHint: 'The fixed and fallback route reads the API key from this credential reference.',\n apiKey: 'API key', apiKeyHint: 'Enter a new key to store it securely. The field is cleared after saving.', credentialConfigured: 'A credential is configured for this reference.',\n toolIdentifier: 'Internal search identifier',\n toolHintAnthropic: 'Anthropic tool type. Leave blank for web_search_20250305.',\n toolHintResponses: 'Responses built-in tool type. Leave blank for web_search.',\n toolHintChatOfficial: 'Official Chat search models use the fixed web_search_options field.',\n toolHintChatVendor: 'Vendor-specific Chat search options field. Leave blank for web_search_options.',\n maxTokens: 'Max output tokens', maxTokensHint: 'Positive integer sent as max_tokens or max_output_tokens for one search request.',\n maxUses: 'Max search uses', maxUsesHint: 'Anthropic-only maximum number of server-tool uses in one request.',\n apiVersion: 'Anthropic API version', apiVersionHint: 'Value sent in the anthropic-version request header.',\n chatSearchMode: 'Chat search capability', chatSearchModeHint: 'Use the official specialized-search-model contract unless the gateway documents a custom options field.',\n chatOfficial: 'Official search model', chatVendor: 'Vendor custom options field',\n searchContextSize: 'Search context size', searchContextSizeHint: 'Optional OpenAI-compatible context budget.',\n contextDefault: 'Provider default', contextLow: 'Low', contextMedium: 'Medium', contextHigh: 'High',\n commandLabel: 'Search settings', commandDescription: 'Configure enhanced web search model route and parameters',\n save: 'Save', saving: 'Saving…', reset: 'Reset to Profile', discard: 'Discard',\n readOnly: 'This connection cannot persist Host Profile settings.',\n failed: 'The Host rejected the change. Review the fields and try again.',\n invalidURL: 'Enter an absolute HTTP(S) endpoint URL.', invalidRequired: 'This field must not be blank.', invalidCredentialRef: 'Use a valid environment-variable name such as WEB_SEARCH_ENHANCED_API.',\n invalidIdentifier: 'Use 1–128 identifier characters and start with a letter.', invalidInteger: 'Enter a positive integer.',\n};\nexport const zh = {\n title: 'Web Search Enhanced',\n description: '配置 web_search 使用的模型路由与内置搜索参数。',\n expand: '展开', collapse: '折叠', unsaved: '未保存',\n modelMode: '模型路由', modelModeHint: '选择固定搜索路由,或跟随当前会话模型及其调用协议。',\n configuredMode: '固定配置', currentSessionMode: '当前会话模型',\n protocol: 'API 协议', protocolHint: '固定或兜底路由使用的协议;跟随模式会优先使用当前模型协议。',\n anthropic: 'Anthropic Messages v1', responses: 'OpenAI Responses API', chat: 'OpenAI Chat Completions API',\n baseURL: '接口基础地址', baseURLHint: '仅当地址尚未包含协议端点时,插件才会自动追加相应路径。',\n model: '模型标识', modelHint: '固定路由使用的模型;当前会话没有可用模型时也会使用它。',\n fallbackModel: '兜底搜索模型', fallbackModelHint: '当前会话路由无法解析时使用的可选模型;留空使用模型标识。',\n apiKeyEnv: 'API Key 环境变量', apiKeyEnvHint: '固定和兜底路由从此凭据引用读取 API Key。',\n apiKey: 'API Key', apiKeyHint: '输入新 Key 后安全保存;保存成功后输入框会清空。', credentialConfigured: '此凭据引用已配置。',\n toolIdentifier: '内部搜索标识符',\n toolHintAnthropic: 'Anthropic 工具类型;留空使用 web_search_20250305。',\n toolHintResponses: 'Responses 内置工具类型;留空使用 web_search。',\n toolHintChatOfficial: '官方 Chat 搜索模型固定使用 web_search_options 字段。',\n toolHintChatVendor: '提供方自定义的 Chat 搜索选项字段;留空使用 web_search_options。',\n maxTokens: '最大输出 Token', maxTokensHint: '单次搜索请求使用的正整数 max_tokens 或 max_output_tokens。',\n maxUses: '最大搜索次数', maxUsesHint: '仅 Anthropic:单次请求最多调用服务端搜索工具的次数。',\n apiVersion: 'Anthropic API 版本', apiVersionHint: '写入 anthropic-version 请求头的版本值。',\n chatSearchMode: 'Chat 搜索能力', chatSearchModeHint: '除非网关明确说明自定义选项字段,否则请选择官方专用搜索模型协议。',\n chatOfficial: '官方专用搜索模型', chatVendor: '提供方自定义选项字段',\n searchContextSize: '搜索上下文大小', searchContextSizeHint: '可选的 OpenAI 兼容搜索上下文预算。',\n contextDefault: '提供方默认值', contextLow: '低', contextMedium: '中', contextHigh: '高',\n commandLabel: '搜索设置', commandDescription: '配置增强联网搜索的模型路由与参数',\n save: '保存', saving: '正在保存…', reset: '重置为 Profile 配置', discard: '放弃修改',\n readOnly: '当前连接不能持久化 Host Profile 设置。',\n failed: 'Host 拒绝了修改,请检查字段后重试。',\n invalidURL: '请输入绝对 HTTP(S) 接口地址。', invalidRequired: '此字段不能为空。', invalidCredentialRef: '请输入有效的环境变量名,例如 WEB_SEARCH_ENHANCED_API。',\n invalidIdentifier: '请输入 1–128 位标识符字符,并以字母开头。', invalidInteger: '请输入正整数。',\n};\n//# sourceMappingURL=locales.js.map","import { SearchSettingsCard } from \"./SearchSettingsCard.js\";\nimport { en, zh } from \"./locales.js\";\nconst SETTINGS_NAMESPACE = 'web-search-enhanced';\nconst LOCALE_NAMESPACE = 'settings.webSearchEnhanced';\n/** Browser plugin dependencies. */\nexport const inject = ['slots', 'locale', 'settingsScope', 'remote', 'remote.credentials'];\n/** Register the localized card under Settings -> Plugins -> Plugin configuration. */\nexport function apply(ctx) {\n const t = ctx.locale.bind(LOCALE_NAMESPACE);\n ctx.effect(() => ctx.locale.register(LOCALE_NAMESPACE, { en, zh }), 'web-search-enhanced: settings dictionaries');\n const scope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: SETTINGS_NAMESPACE,\n locale: LOCALE_NAMESPACE,\n inject: () => ({ scope, credentials: ctx.remote.credentials, t }),\n }, SearchSettingsCard));\n ctx.inject(['commandUi'], (scope) => {\n const commandUi = scope.commandUi;\n if (typeof commandUi?.register === 'function') {\n scope.effect(() => commandUi.register({\n name: 'search-config',\n label: () => t('commandLabel'),\n description: () => t('commandDescription'),\n available: () => true,\n ui: {\n kind: 'action',\n run: () => {\n const trigger = document.querySelector('[data-slot=\"sidebar.settings\"] button');\n trigger?.click();\n setTimeout(() => {\n const card = document.querySelector('[data-wse-card=\"true\"]');\n card?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 200);\n },\n },\n }), 'web-search-enhanced: /search-config action command');\n }\n });\n}\n//# sourceMappingURL=index.js.map"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useSyncExternalStore","useMemo","useState","useId","_jsxs","_jsx","_Fragment"],"sources":["types/client/SearchSettingsCard.js","types/client/locales.js","types/client/index.js"],"sourcesContent":["import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\nimport { useEffect, useId, useMemo, useState, useSyncExternalStore } from 'react';\nexport const editableFields = ['modelMode', 'protocol', 'baseURL', 'model', 'fallbackModel', 'apiKeyEnv', 'apiVersion', 'toolIdentifier', 'maxTokens', 'maxUses', 'chatSearchMode', 'searchContextSize'];\n/** Schema default values aligned with host plugin definitions. */\nexport const SCHEMA_DEFAULTS = {\n modelMode: 'configured',\n protocol: 'anthropic-messages',\n baseURL: 'https://api.deepseek.com/anthropic/v1',\n model: 'deepseek-flash',\n fallbackModel: undefined,\n apiKeyEnv: 'WEB_SEARCH_ENHANCED_API',\n apiVersion: '2023-06-01',\n toolIdentifier: undefined,\n maxTokens: 4096,\n maxUses: 5,\n chatSearchMode: 'search-model',\n searchContextSize: undefined,\n};\nexport function targetValuesFromDraft(draft) {\n return {\n modelMode: draft.modelMode,\n protocol: draft.protocol,\n baseURL: draft.baseURL.trim(),\n model: draft.model.trim(),\n fallbackModel: draft.fallbackModel.trim().length === 0 ? undefined : draft.fallbackModel.trim(),\n apiKeyEnv: draft.apiKeyEnv.trim(),\n apiVersion: draft.apiVersion.trim(),\n toolIdentifier: draft.toolIdentifier.trim().length === 0 ? undefined : draft.toolIdentifier.trim(),\n maxTokens: Number(draft.maxTokens),\n maxUses: Number(draft.maxUses),\n chatSearchMode: draft.chatSearchMode,\n searchContextSize: draft.searchContextSize === '' ? undefined : draft.searchContextSize,\n };\n}\n/**\n * Compute sparse mutation operations required to synchronize user overrides.\n * Default values matching the inherited baseline are omitted to prevent settings.yaml\n * bloating, and existing redundant overrides are pruned automatically.\n */\nexport function computeSettingsOperations(draft, snapshot, resetToProfile = false) {\n const baseConfig = typeof snapshot.base === 'object' && snapshot.base !== null\n ? snapshot.base\n : {};\n const userConfig = typeof snapshot.user === 'object' && snapshot.user !== null\n ? snapshot.user\n : {};\n const ops = [];\n if (resetToProfile) {\n for (const field of editableFields) {\n if (field in userConfig) {\n ops.push({ op: 'unset', path: [field] });\n }\n }\n return ops;\n }\n const targets = targetValuesFromDraft(draft);\n for (const field of editableFields) {\n const targetVal = targets[field];\n const baselineVal = baseConfig[field] !== undefined ? baseConfig[field] : SCHEMA_DEFAULTS[field];\n const isOverriddenInUser = field in userConfig;\n if (targetVal !== baselineVal) {\n if (targetVal === undefined) {\n if (isOverriddenInUser) {\n ops.push({ op: 'unset', path: [field] });\n }\n }\n else {\n ops.push({ op: 'set', path: [field], value: targetVal });\n }\n }\n else if (isOverriddenInUser) {\n ops.push({ op: 'unset', path: [field] });\n }\n }\n return ops;\n}\n/** Convert resolved settings into a stable form draft. */\nexport function draftFrom(value) {\n return {\n modelMode: value?.modelMode ?? 'configured',\n protocol: value?.protocol ?? 'anthropic-messages',\n baseURL: value?.baseURL ?? 'https://api.deepseek.com/anthropic/v1',\n model: value?.model ?? 'deepseek-flash',\n fallbackModel: value?.fallbackModel ?? '',\n apiKeyEnv: value?.apiKeyEnv ?? 'WEB_SEARCH_ENHANCED_API',\n apiVersion: value?.apiVersion ?? '2023-06-01',\n toolIdentifier: value?.toolIdentifier ?? '',\n maxTokens: String(value?.maxTokens ?? 4096),\n maxUses: String(value?.maxUses ?? 5),\n chatSearchMode: value?.chatSearchMode ?? 'search-model',\n searchContextSize: value?.searchContextSize ?? '',\n };\n}\n/** Validate a draft and return field-specific locale keys. */\nexport async function saveCredential(credentials, ref, value) {\n const secret = value.trim();\n if (secret.length === 0)\n return false;\n const result = await credentials.set(ref.trim(), secret);\n if (!result.ok)\n throw new Error(result.error.message);\n return true;\n}\nexport function validateDraft(draft) {\n const errors = {};\n try {\n const url = new URL(draft.baseURL);\n if (url.protocol !== 'http:' && url.protocol !== 'https:')\n errors.baseURL = 'invalidURL';\n }\n catch {\n errors.baseURL = 'invalidURL';\n }\n if (draft.model.trim().length === 0)\n errors.model = 'invalidRequired';\n if (draft.apiKeyEnv.trim().length === 0)\n errors.apiKeyEnv = 'invalidRequired';\n if (draft.apiKeyEnv.trim().length > 0 && !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(draft.apiKeyEnv.trim()))\n errors.apiKeyEnv = 'invalidCredentialRef';\n if (draft.apiVersion.trim().length === 0)\n errors.apiVersion = 'invalidRequired';\n if (draft.toolIdentifier.length > 0 && !/^[A-Za-z][A-Za-z0-9_.:-]{0,127}$/u.test(draft.toolIdentifier))\n errors.toolIdentifier = 'invalidIdentifier';\n if (!positiveInteger(draft.maxTokens))\n errors.maxTokens = 'invalidInteger';\n if (!positiveInteger(draft.maxUses))\n errors.maxUses = 'invalidInteger';\n return errors;\n}\nconst cardCss = `\n.wse-card {\n list-style: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3);\n color: var(--dsw-alias-label-primary);\n transition: border-color .16s, background .16s;\n}\n.wse-card:hover {\n border-color: var(--dsw-alias-label-dimmed);\n}\n.wse-card[data-open='true'] {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n.wse-header {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n}\n.wse-header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.wse-head {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.wse-name {\n color: var(--dsw-alias-label-primary);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n.wse-desc {\n color: var(--dsw-alias-label-tertiary);\n font-size: 13px;\n line-height: 1.5;\n}\n.wse-pending {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n flex: none;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.wse-chevron {\n box-sizing: border-box;\n flex: none;\n width: 8px;\n height: 8px;\n margin-right: 3px;\n border-right: 1.5px solid var(--dsw-alias-label-tertiary);\n border-bottom: 1.5px solid var(--dsw-alias-label-tertiary);\n transform: rotate(45deg);\n transition: transform .16s;\n}\n.wse-card[data-open='true'] .wse-chevron {\n transform: rotate(225deg);\n}\n.wse-body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin: 0 16px;\n padding-bottom: 8px;\n}\n.wse-fields {\n display: flex;\n flex-direction: column;\n}\n.wse-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.wse-field + .wse-field {\n border-top: 1px solid var(--dsw-alias-border-l2);\n}\n.wse-label {\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n}\n.wse-input, .wse-select {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 0 12px;\n background: var(--dsw-alias-bg-layer-3);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n outline: none;\n transition: border-color .16s, background .16s;\n}\n.wse-input:focus-visible, .wse-select:focus-visible,\n.wse-input:focus, .wse-select:focus {\n border-color: var(--dsw-alias-brand-primary);\n outline: none;\n}\n.wse-input[aria-invalid='true'] {\n border-color: var(--dsw-alias-label-error);\n}\n.wse-input:disabled, .wse-select:disabled {\n cursor: default;\n color: var(--dsw-alias-label-tertiary);\n opacity: .55;\n}\n.wse-hint, .wse-error, .wse-readonly, .wse-failed {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n.wse-hint {\n color: var(--dsw-alias-label-tertiary);\n}\n.wse-error, .wse-failed {\n color: var(--dsw-alias-label-error);\n}\n.wse-readonly {\n margin: 12px 0 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.wse-footer {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin-top: 4px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 0 4px;\n}\n.wse-failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n.wse-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n}\n.wse-button {\n appearance: none;\n font: inherit;\n cursor: pointer;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 1.5;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n transition: color .16s, border-color .16s, background .16s, opacity .16s;\n}\n.wse-button:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n background: var(--dsw-alias-bg-layer-4);\n}\n.wse-button:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.wse-button:disabled {\n opacity: .4;\n cursor: default;\n}\n.wse-save {\n border-color: transparent;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary-foreground, var(--dsw-alias-bg-layer-3));\n}\n.wse-save:hover:not(:disabled) {\n background: var(--dsw-alias-label-primary);\n opacity: .9;\n}\n`;\nexport function SearchSettingsCard({ scope, credentials, t }) {\n const snapshot = useSyncExternalStore(scope.subscribe.bind(scope), scope.getSnapshot.bind(scope));\n const resolved = useMemo(() => draftFrom(snapshot.value), [snapshot.value]);\n const [draft, setDraft] = useState(resolved);\n const [open, setOpen] = useState(false);\n const [saving, setSaving] = useState(false);\n const [failed, setFailed] = useState(false);\n const [hasDraft, setHasDraft] = useState(false);\n const [resetToProfile, setResetToProfile] = useState(false);\n const [apiKey, setApiKey] = useState('');\n const [credentialConfigured, setCredentialConfigured] = useState(false);\n const bodyId = useId();\n useEffect(() => { if (!saving && !hasDraft)\n setDraft(resolved); }, [hasDraft, resolved, saving]);\n useEffect(() => {\n const ref = draft.apiKeyEnv.trim();\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(ref)) {\n setCredentialConfigured(false);\n return;\n }\n let active = true;\n void credentials.describe([ref]).then(result => {\n if (active)\n setCredentialConfigured(result.ok && result.value[ref]?.configured === true);\n }).catch(() => { if (active)\n setCredentialConfigured(false); });\n return () => { active = false; };\n }, [credentials, draft.apiKeyEnv]);\n const errors = useMemo(() => validateDraft(draft), [draft]);\n const dirty = resetToProfile || apiKey.length > 0 || JSON.stringify(draft) !== JSON.stringify(resolved);\n const invalid = Object.keys(errors).length > 0;\n const disabled = snapshot.status !== 'ready' || !snapshot.writable || saving;\n const edit = (field, value) => {\n setDraft(current => ({ ...current, [field]: value }));\n setResetToProfile(false);\n setHasDraft(true);\n setFailed(false);\n };\n const save = async () => {\n if (disabled || !dirty || invalid)\n return;\n setSaving(true);\n setFailed(false);\n try {\n if (await saveCredential(credentials, draft.apiKeyEnv, apiKey))\n setCredentialConfigured(true);\n const ops = computeSettingsOperations(draft, snapshot, resetToProfile);\n if (ops.length > 0) {\n if (typeof scope.mutate === 'function') {\n await scope.mutate(ops);\n }\n else {\n for (const op of ops) {\n const field = op.path[0];\n if (field !== undefined) {\n if (op.op === 'set')\n await scope.set(field, op.value);\n else\n await scope.unset(field);\n }\n }\n }\n }\n setApiKey('');\n setHasDraft(false);\n setResetToProfile(false);\n setOpen(false);\n }\n catch {\n setFailed(true);\n }\n finally {\n setSaving(false);\n }\n };\n const reset = () => { setApiKey(''); setDraft(draftFrom(asSearchSettings(snapshot.base))); setResetToProfile(true); setHasDraft(true); setFailed(false); };\n const discard = () => { setApiKey(''); setDraft(resolved); setResetToProfile(false); setHasDraft(false); setFailed(false); };\n if (snapshot.status === 'unavailable')\n return null;\n const toolHint = draft.protocol === 'anthropic-messages' ? 'toolHintAnthropic' : draft.protocol === 'openai-responses' ? 'toolHintResponses' : draft.chatSearchMode === 'search-model' ? 'toolHintChatOfficial' : 'toolHintChatVendor';\n return _jsxs(\"li\", { className: \"wse-card\", \"data-open\": open, \"data-plugin-key\": \"web-search-enhanced\", \"data-wse-card\": \"true\", children: [_jsx(\"style\", { children: cardCss }), _jsxs(\"button\", { type: \"button\", className: \"wse-header\", \"aria-expanded\": open, \"aria-controls\": bodyId, \"aria-label\": `${t(open ? 'collapse' : 'expand')}: ${t('title')}`, onClick: () => { setOpen(value => !value); }, children: [_jsxs(\"span\", { className: \"wse-head\", children: [_jsx(\"span\", { className: \"wse-name\", children: t('title') }), _jsx(\"span\", { className: \"wse-desc\", children: t('description') })] }), dirty ? _jsx(\"span\", { className: \"wse-pending\", children: t('unsaved') }) : null, _jsx(\"span\", { className: \"wse-chevron\", \"aria-hidden\": \"true\" })] }), open ? _jsxs(\"div\", { className: \"wse-body\", id: bodyId, children: [!snapshot.writable && snapshot.status === 'ready' ? _jsx(\"p\", { className: \"wse-readonly\", role: \"status\", children: t('readOnly') }) : null, _jsxs(\"div\", { className: \"wse-fields\", children: [_jsx(SelectField, { label: t('modelMode'), hint: t('modelModeHint'), value: draft.modelMode, disabled: disabled, onChange: value => { edit('modelMode', value); }, options: [[\"configured\", t('configuredMode')], [\"current-session\", t('currentSessionMode')]] }), _jsx(SelectField, { label: t('protocol'), hint: t('protocolHint'), value: draft.protocol, disabled: disabled, onChange: value => { edit('protocol', value); }, options: [[\"anthropic-messages\", t('anthropic')], [\"openai-responses\", t('responses')], [\"openai-chat-completions\", t('chat')]] }), _jsx(TextField, { label: t('toolIdentifier'), hint: t(toolHint), value: draft.toolIdentifier, error: errors.toolIdentifier === undefined ? undefined : t(errors.toolIdentifier), disabled: disabled || (draft.protocol === 'openai-chat-completions' && draft.chatSearchMode === 'search-model'), onChange: value => { edit('toolIdentifier', value); } }), _jsx(TextField, { label: t('baseURL'), hint: t('baseURLHint'), value: draft.baseURL, error: errors.baseURL === undefined ? undefined : t(errors.baseURL), disabled: disabled, onChange: value => { edit('baseURL', value); } }), _jsx(TextField, { label: t('model'), hint: t('modelHint'), value: draft.model, error: errors.model === undefined ? undefined : t(errors.model), disabled: disabled, onChange: value => { edit('model', value); } }), _jsx(TextField, { label: t('fallbackModel'), hint: t('fallbackModelHint'), value: draft.fallbackModel, error: errors.fallbackModel === undefined ? undefined : t(errors.fallbackModel), disabled: disabled, onChange: value => { edit('fallbackModel', value); } }), _jsx(TextField, { label: t('apiKeyEnv'), hint: credentialConfigured ? t('credentialConfigured') : t('apiKeyEnvHint'), value: draft.apiKeyEnv, error: errors.apiKeyEnv === undefined ? undefined : t(errors.apiKeyEnv), disabled: disabled, onChange: value => { edit('apiKeyEnv', value); } }), _jsx(TextField, { type: \"password\", label: t('apiKey'), hint: t('apiKeyHint'), value: apiKey, disabled: disabled, onChange: value => { setApiKey(value); setHasDraft(true); setFailed(false); } }), _jsx(TextField, { inputMode: \"numeric\", label: t('maxTokens'), hint: t('maxTokensHint'), value: draft.maxTokens, error: errors.maxTokens === undefined ? undefined : t(errors.maxTokens), disabled: disabled, onChange: value => { edit('maxTokens', value); } }), draft.modelMode === 'current-session' ? (_jsxs(_Fragment, { children: [_jsx(TextField, { inputMode: \"numeric\", label: t('maxUses'), hint: t('maxUsesHint'), value: draft.maxUses, error: errors.maxUses === undefined ? undefined : t(errors.maxUses), disabled: disabled, onChange: value => { edit('maxUses', value); } }), _jsx(TextField, { label: t('apiVersion'), hint: t('apiVersionHint'), value: draft.apiVersion, error: errors.apiVersion === undefined ? undefined : t(errors.apiVersion), disabled: disabled, onChange: value => { edit('apiVersion', value); } }), _jsx(SelectField, { label: t('chatSearchMode'), hint: t('chatSearchModeHint'), value: draft.chatSearchMode, disabled: disabled, onChange: value => { edit('chatSearchMode', value); }, options: [[\"search-model\", t('chatOfficial')], [\"vendor-options\", t('chatVendor')]] }), _jsx(SelectField, { label: t('searchContextSize'), hint: t('searchContextSizeHint'), value: draft.searchContextSize, disabled: disabled, onChange: value => { edit('searchContextSize', value); }, options: [[\"\", t('contextDefault')], [\"low\", t('contextLow')], [\"medium\", t('contextMedium')], [\"high\", t('contextHigh')]] })] })) : draft.protocol === 'anthropic-messages' ? (_jsxs(_Fragment, { children: [_jsx(TextField, { inputMode: \"numeric\", label: t('maxUses'), hint: t('maxUsesHint'), value: draft.maxUses, error: errors.maxUses === undefined ? undefined : t(errors.maxUses), disabled: disabled, onChange: value => { edit('maxUses', value); } }), _jsx(TextField, { label: t('apiVersion'), hint: t('apiVersionHint'), value: draft.apiVersion, error: errors.apiVersion === undefined ? undefined : t(errors.apiVersion), disabled: disabled, onChange: value => { edit('apiVersion', value); } })] })) : (_jsxs(_Fragment, { children: [draft.protocol === 'openai-chat-completions' ? (_jsx(SelectField, { label: t('chatSearchMode'), hint: t('chatSearchModeHint'), value: draft.chatSearchMode, disabled: disabled, onChange: value => { edit('chatSearchMode', value); }, options: [[\"search-model\", t('chatOfficial')], [\"vendor-options\", t('chatVendor')]] })) : null, _jsx(SelectField, { label: t('searchContextSize'), hint: t('searchContextSizeHint'), value: draft.searchContextSize, disabled: disabled, onChange: value => { edit('searchContextSize', value); }, options: [[\"\", t('contextDefault')], [\"low\", t('contextLow')], [\"medium\", t('contextMedium')], [\"high\", t('contextHigh')]] })] }))] }), _jsxs(\"div\", { className: \"wse-footer\", children: [failed ? _jsx(\"p\", { className: \"wse-failed\", role: \"alert\", children: t('failed') }) : null, _jsxs(\"div\", { className: \"wse-actions\", children: [_jsx(\"button\", { type: \"button\", className: \"wse-button\", disabled: disabled || resetToProfile, onClick: reset, children: t('reset') }), _jsx(\"button\", { type: \"button\", className: \"wse-button\", disabled: disabled || !dirty, onClick: discard, children: t('discard') }), _jsx(\"button\", { type: \"button\", className: \"wse-button wse-save\", disabled: disabled || !dirty || invalid, onClick: () => { void save(); }, children: saving ? t('saving') : t('save') })] })] })] }) : null] });\n}\nfunction TextField(props) {\n const id = useId();\n const describedBy = useId();\n return _jsxs(\"div\", { className: \"wse-field\", children: [_jsx(\"label\", { className: \"wse-label\", htmlFor: id, children: props.label }), _jsx(\"input\", { id: id, className: \"wse-input\", type: props.type ?? 'text', value: props.value, disabled: props.disabled, inputMode: props.inputMode, \"aria-invalid\": props.error === undefined ? undefined : true, \"aria-describedby\": describedBy, spellCheck: false, onChange: event => { props.onChange(event.target.value); } }), _jsx(\"p\", { id: describedBy, className: props.error === undefined ? 'wse-hint' : 'wse-error', children: props.error ?? props.hint })] });\n}\nfunction SelectField(props) {\n const id = useId();\n const describedBy = useId();\n return _jsxs(\"div\", { className: \"wse-field\", children: [_jsx(\"label\", { className: \"wse-label\", htmlFor: id, children: props.label }), _jsx(\"select\", { id: id, className: \"wse-select\", value: props.value, disabled: props.disabled, \"aria-describedby\": describedBy, onChange: event => { props.onChange(event.target.value); }, children: props.options.map(([value, label]) => _jsx(\"option\", { value: value, children: label }, value)) }), _jsx(\"p\", { id: describedBy, className: \"wse-hint\", children: props.hint })] });\n}\nfunction asSearchSettings(value) { return typeof value === 'object' && value !== null ? value : undefined; }\nfunction positiveInteger(value) { const parsed = Number(value); return Number.isInteger(parsed) && parsed > 0; }\n//# sourceMappingURL=SearchSettingsCard.js.map","export const en = {\n title: 'Web Search Enhanced',\n description: 'Choose the model route and built-in search settings used by web_search.',\n expand: 'Expand', collapse: 'Collapse', unsaved: 'Unsaved',\n modelMode: 'Model route', modelModeHint: 'Use the fixed search route or follow the model and calling protocol of the current session.',\n configuredMode: 'Fixed configuration', currentSessionMode: 'Current session model',\n protocol: 'API protocol', protocolHint: 'The fixed or fallback route protocol. Follow mode uses the current model protocol when available.',\n anthropic: 'Anthropic Messages v1', responses: 'OpenAI Responses API', chat: 'OpenAI Chat Completions API',\n baseURL: 'Endpoint base URL', baseURLHint: 'The protocol endpoint suffix is appended only when it is not already present.',\n model: 'Model ID', modelHint: 'The model used by the fixed route and when no session model is available.',\n fallbackModel: 'Fallback search model', fallbackModelHint: 'Optional model used when the current session route cannot be resolved; blank uses Model ID.',\n apiKeyEnv: 'API key environment variable', apiKeyEnvHint: 'The fixed and fallback route reads the API key from this credential reference.',\n apiKey: 'API key', apiKeyHint: 'Enter a new key to store it securely. The field is cleared after saving.', credentialConfigured: 'A credential is configured for this reference.',\n toolIdentifier: 'Internal search identifier',\n toolHintAnthropic: 'Anthropic tool type. Leave blank for web_search_20250305.',\n toolHintResponses: 'Responses built-in tool type. Leave blank for web_search.',\n toolHintChatOfficial: 'Official Chat search models use the fixed web_search_options field.',\n toolHintChatVendor: 'Vendor-specific Chat search options field. Leave blank for web_search_options.',\n maxTokens: 'Max output tokens', maxTokensHint: 'Positive integer sent as max_tokens or max_output_tokens for one search request.',\n maxUses: 'Max search uses', maxUsesHint: 'Anthropic-only maximum number of server-tool uses in one request.',\n apiVersion: 'Anthropic API version', apiVersionHint: 'Value sent in the anthropic-version request header.',\n chatSearchMode: 'Chat search capability', chatSearchModeHint: 'Use the official specialized-search-model contract unless the gateway documents a custom options field.',\n chatOfficial: 'Official search model', chatVendor: 'Vendor custom options field',\n searchContextSize: 'Search context size', searchContextSizeHint: 'Optional OpenAI-compatible context budget.',\n contextDefault: 'Provider default', contextLow: 'Low', contextMedium: 'Medium', contextHigh: 'High',\n commandLabel: 'Search settings', commandDescription: 'Configure enhanced web search model route and parameters',\n save: 'Save', saving: 'Saving…', reset: 'Reset to Profile', discard: 'Discard',\n readOnly: 'This connection cannot persist Host Profile settings.',\n failed: 'The Host rejected the change. Review the fields and try again.',\n invalidURL: 'Enter an absolute HTTP(S) endpoint URL.', invalidRequired: 'This field must not be blank.', invalidCredentialRef: 'Use a valid environment-variable name such as WEB_SEARCH_ENHANCED_API.',\n invalidIdentifier: 'Use 1–128 identifier characters and start with a letter.', invalidInteger: 'Enter a positive integer.',\n};\nexport const zh = {\n title: 'Web Search Enhanced',\n description: '配置 web_search 使用的模型路由与内置搜索参数。',\n expand: '展开', collapse: '折叠', unsaved: '未保存',\n modelMode: '模型路由', modelModeHint: '选择固定搜索路由,或跟随当前会话模型及其调用协议。',\n configuredMode: '固定配置', currentSessionMode: '当前会话模型',\n protocol: 'API 协议', protocolHint: '固定或兜底路由使用的协议;跟随模式会优先使用当前模型协议。',\n anthropic: 'Anthropic Messages v1', responses: 'OpenAI Responses API', chat: 'OpenAI Chat Completions API',\n baseURL: '接口基础地址', baseURLHint: '仅当地址尚未包含协议端点时,插件才会自动追加相应路径。',\n model: '模型标识', modelHint: '固定路由使用的模型;当前会话没有可用模型时也会使用它。',\n fallbackModel: '兜底搜索模型', fallbackModelHint: '当前会话路由无法解析时使用的可选模型;留空使用模型标识。',\n apiKeyEnv: 'API Key 环境变量', apiKeyEnvHint: '固定和兜底路由从此凭据引用读取 API Key。',\n apiKey: 'API Key', apiKeyHint: '输入新 Key 后安全保存;保存成功后输入框会清空。', credentialConfigured: '此凭据引用已配置。',\n toolIdentifier: '内部搜索标识符',\n toolHintAnthropic: 'Anthropic 工具类型;留空使用 web_search_20250305。',\n toolHintResponses: 'Responses 内置工具类型;留空使用 web_search。',\n toolHintChatOfficial: '官方 Chat 搜索模型固定使用 web_search_options 字段。',\n toolHintChatVendor: '提供方自定义的 Chat 搜索选项字段;留空使用 web_search_options。',\n maxTokens: '最大输出 Token', maxTokensHint: '单次搜索请求使用的正整数 max_tokens 或 max_output_tokens。',\n maxUses: '最大搜索次数', maxUsesHint: '仅 Anthropic:单次请求最多调用服务端搜索工具的次数。',\n apiVersion: 'Anthropic API 版本', apiVersionHint: '写入 anthropic-version 请求头的版本值。',\n chatSearchMode: 'Chat 搜索能力', chatSearchModeHint: '除非网关明确说明自定义选项字段,否则请选择官方专用搜索模型协议。',\n chatOfficial: '官方专用搜索模型', chatVendor: '提供方自定义选项字段',\n searchContextSize: '搜索上下文大小', searchContextSizeHint: '可选的 OpenAI 兼容搜索上下文预算。',\n contextDefault: '提供方默认值', contextLow: '低', contextMedium: '中', contextHigh: '高',\n commandLabel: '搜索设置', commandDescription: '配置增强联网搜索的模型路由与参数',\n save: '保存', saving: '正在保存…', reset: '重置为 Profile 配置', discard: '放弃修改',\n readOnly: '当前连接不能持久化 Host Profile 设置。',\n failed: 'Host 拒绝了修改,请检查字段后重试。',\n invalidURL: '请输入绝对 HTTP(S) 接口地址。', invalidRequired: '此字段不能为空。', invalidCredentialRef: '请输入有效的环境变量名,例如 WEB_SEARCH_ENHANCED_API。',\n invalidIdentifier: '请输入 1–128 位标识符字符,并以字母开头。', invalidInteger: '请输入正整数。',\n};\n//# sourceMappingURL=locales.js.map","import { SearchSettingsCard } from \"./SearchSettingsCard.js\";\nimport { en, zh } from \"./locales.js\";\nconst SETTINGS_NAMESPACE = 'web-search-enhanced';\nconst LOCALE_NAMESPACE = 'settings.webSearchEnhanced';\n/** Browser plugin dependencies. */\nexport const inject = ['slots', 'locale', 'settingsScope', 'remote', 'remote.credentials'];\n/** Register the localized card under Settings -> Plugins -> Plugin configuration. */\nexport function apply(ctx) {\n const t = ctx.locale.bind(LOCALE_NAMESPACE);\n ctx.effect(() => ctx.locale.register(LOCALE_NAMESPACE, { en, zh }), 'web-search-enhanced: settings dictionaries');\n const scope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: SETTINGS_NAMESPACE,\n locale: LOCALE_NAMESPACE,\n inject: () => ({ scope, credentials: ctx.remote.credentials, t }),\n }, SearchSettingsCard));\n ctx.inject(['commandUi'], (scope) => {\n const commandUi = scope.commandUi;\n if (typeof commandUi?.register === 'function') {\n scope.effect(() => commandUi.register({\n name: 'search-config',\n label: () => t('commandLabel'),\n description: () => t('commandDescription'),\n available: () => true,\n ui: {\n kind: 'action',\n run: () => {\n const trigger = document.querySelector('[data-slot=\"sidebar.settings\"] button');\n trigger?.click();\n setTimeout(() => {\n const card = document.querySelector('[data-wse-card=\"true\"]');\n card?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 200);\n },\n },\n }), 'web-search-enhanced: /search-config action command');\n }\n });\n}\n//# sourceMappingURL=index.js.map"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -22,7 +22,7 @@ function buildWireRequest(config, query, apiKey) {
|
|
|
22
22
|
const commonHeaders = {
|
|
23
23
|
"accept": "application/json",
|
|
24
24
|
"content-type": "application/json",
|
|
25
|
-
"user-agent": "dsh-web-search-enhanced/0.0.
|
|
25
|
+
"user-agent": "dsh-web-search-enhanced/0.0.6"
|
|
26
26
|
};
|
|
27
27
|
switch (config.protocol) {
|
|
28
28
|
case "anthropic-messages": return {
|
|
@@ -39,7 +39,7 @@ export interface SearchSettingsCardProps {
|
|
|
39
39
|
credentials: CredentialRemote;
|
|
40
40
|
t: (key: LocaleKey) => string;
|
|
41
41
|
}
|
|
42
|
-
interface Draft {
|
|
42
|
+
export interface Draft {
|
|
43
43
|
modelMode: ModelMode;
|
|
44
44
|
protocol: SearchProtocol;
|
|
45
45
|
baseURL: string;
|
|
@@ -53,6 +53,24 @@ interface Draft {
|
|
|
53
53
|
chatSearchMode: 'search-model' | 'vendor-options';
|
|
54
54
|
searchContextSize: '' | 'low' | 'medium' | 'high';
|
|
55
55
|
}
|
|
56
|
+
export declare const editableFields: readonly ["modelMode", "protocol", "baseURL", "model", "fallbackModel", "apiKeyEnv", "apiVersion", "toolIdentifier", "maxTokens", "maxUses", "chatSearchMode", "searchContextSize"];
|
|
57
|
+
/** Schema default values aligned with host plugin definitions. */
|
|
58
|
+
export declare const SCHEMA_DEFAULTS: Record<typeof editableFields[number], unknown>;
|
|
59
|
+
export interface SettingsMutationOp {
|
|
60
|
+
op: 'set' | 'unset';
|
|
61
|
+
path: string[];
|
|
62
|
+
value?: unknown;
|
|
63
|
+
}
|
|
64
|
+
export declare function targetValuesFromDraft(draft: Draft): Record<typeof editableFields[number], unknown>;
|
|
65
|
+
/**
|
|
66
|
+
* Compute sparse mutation operations required to synchronize user overrides.
|
|
67
|
+
* Default values matching the inherited baseline are omitted to prevent settings.yaml
|
|
68
|
+
* bloating, and existing redundant overrides are pruned automatically.
|
|
69
|
+
*/
|
|
70
|
+
export declare function computeSettingsOperations(draft: Draft, snapshot: {
|
|
71
|
+
base?: unknown;
|
|
72
|
+
user?: unknown;
|
|
73
|
+
}, resetToProfile?: boolean): SettingsMutationOp[];
|
|
56
74
|
/** Convert resolved settings into a stable form draft. */
|
|
57
75
|
export declare function draftFrom(value: SearchSettings | undefined): Draft;
|
|
58
76
|
/** Validate a draft and return field-specific locale keys. */
|
package/package.json
CHANGED
package/docs/harness-contract.md
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# Harness Contract
|
|
2
|
-
|
|
3
|
-
## Source of truth
|
|
4
|
-
|
|
5
|
-
Extracted from DeepSeek Harness release `0.1.2-alpha.2` (commit `3f1b46a5db`). Installable dependencies use the npm package line `>=0.1.1-rc.2`; source and registry baselines are intentionally recorded separately.
|
|
6
|
-
|
|
7
|
-
Representative sources:
|
|
8
|
-
|
|
9
|
-
- `packages/fs/tool-fs/src/index.ts`: named Cordis exports, Schemastery config, required and conditional injection.
|
|
10
|
-
- `packages/core/tools/src/schema.ts`: tool definitions and execution contracts.
|
|
11
|
-
- `packages/client/tsdown.client.ts`: ModuleLoader output, external purity, CSS, and build faces.
|
|
12
|
-
- `packages/client/ui-settings-plugins/package.json`: `dsh.client`, exports, peers, and files.
|
|
13
|
-
- `packages/client/ui-settings-plugins/src/client/index.ts`: browser surface ownership.
|
|
14
|
-
- `packages/api/settings-controller/src/index.ts`: redacted settings namespaces and Remote ownership.
|
|
15
|
-
|
|
16
|
-
## Portable contract retained here
|
|
17
|
-
|
|
18
|
-
One package exposes a Node host half and optional browser half. `dsh.bundle.patch` publishes composition defaults; `dsh.client` declares browser dependencies. Client output calls `window.__ModuleLoader__.load` and resolves shared identity through injected `require`. TypeScript uses strict NodeNext semantics, relative runtime imports end in `.js`, declarations live under `lib/types`, and published files are explicit.
|
|
19
|
-
|
|
20
|
-
## Deliberately not copied
|
|
21
|
-
|
|
22
|
-
The internal monorepo uses `workspace:^`, project references, generated catalogs, build faces, Typert generators, oxlint, package-invariant gates, static-linked client channels, and root release orchestration. Those are repository infrastructure, not portable plugin API. Typert generation is especially monorepo-bound today, so this basic template demonstrates a narrow optional RPC adapter instead of copying generated internals.
|
|
23
|
-
|
|
24
|
-
## Upgrade checklist
|
|
25
|
-
|
|
26
|
-
- Compare DSH package versions and Node/pnpm engines.
|
|
27
|
-
- Inspect `packages/client/tsdown.client.ts` for loader, external, CSS, and build changes.
|
|
28
|
-
- Inspect a current tool package for `defineTool` changes.
|
|
29
|
-
- Inspect a current client package for slot, locale, and `dsh.client.inject` changes.
|
|
30
|
-
- Run `pnpm run check`, then verify the packed plugin in the current DSH GUI after refresh.
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Existing Template Comparison
|
|
2
|
-
|
|
3
|
-
Audited on 2026-08-28 against DeepSeek Harness `cd5ef8148158c3a752a658978873241fdf8e2bbc`.
|
|
4
|
-
|
|
5
|
-
| Area | bugmaker2 | kun2-5code | sunshine-lang | This template |
|
|
6
|
-
| --- | --- | --- | --- | --- |
|
|
7
|
-
| Audit commit | `31af7eb` | `0b4fbda` | `6417045` | harness-derived |
|
|
8
|
-
| Shape | Dual host/client, Typert, React | Six host shapes, 14 UI surfaces | Minimal host-only tool | Small host/tool plus optional UI/RPC |
|
|
9
|
-
| Build | esbuild + tsc | tsdown + loader wrapper | tsc only | tsc declarations + tsdown adapter |
|
|
10
|
-
| Tests | Vitest contracts/runtime | One build smoke | Unwired integration file | Vitest + build + tarball gate |
|
|
11
|
-
| Publish gate | check, no packed consumer | prepare only | none | prepublish check and pack extraction |
|
|
12
|
-
| Scaffolding | Manual rename checklist | Fork/edit | Script with weak exclusions | Validated name, excludes VCS/build state |
|
|
13
|
-
| DSH baseline | old rc.6, wildcard peers | rc.5/rc.6, obsolete settings docs | rc.1 tools | documented alpha baseline |
|
|
14
|
-
|
|
15
|
-
## Assessment
|
|
16
|
-
|
|
17
|
-
### bugmaker2/dsh-web-search-enhanced
|
|
18
|
-
|
|
19
|
-
The strongest contract-oriented example. Shared Zod/Typert descriptors, lifecycle handling, React, i18n, lint and CI are useful. Its handwritten loader, duplicated manifest, wildcard optional peers, manual ten-point rename, old rc.6 baseline, and missing packed-consumer gate increase drift risk.
|
|
20
|
-
|
|
21
|
-
### kun2-5code/dsh-web-search-enhanced
|
|
22
|
-
|
|
23
|
-
The best catalog of extension shapes and UI slots, useful as an API showcase rather than a minimal production baseline. Its README still describes a settings whitelist and internal paths absent from the current settings controller. It lacks lint, Vitest, package verification, compatibility engines, and prepublish checks.
|
|
24
|
-
|
|
25
|
-
### sunshine-lang/dsh-web-search-enhanced
|
|
26
|
-
|
|
27
|
-
The clearest host-only starter and only compared repository with a scaffold script. Its exports and tool example are sound, but it lacks client/RPC/UI, package exports, peer separation, typecheck/test/publish gates, and a wired integration test. Its scaffold may copy `lib` and handles arguments weakly.
|
|
28
|
-
|
|
29
|
-
## Material differences here
|
|
30
|
-
|
|
31
|
-
- Internal package files are evidence, while nonportable monorepo machinery is called out explicitly.
|
|
32
|
-
- One example is kept per important boundary instead of maximizing feature count.
|
|
33
|
-
- Client externals derive from peers and the ModuleLoader compatibility adapter is isolated.
|
|
34
|
-
- The exact tarball is extracted and checked.
|
|
35
|
-
- Host-only deletion and deterministic scaffolding are documented.
|