@klarkxy/dsh-web-search-manager 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,25 +6,42 @@ Configure DSH web search providers and page fetching from one settings page.
6
6
 
7
7
  ## Install
8
8
 
9
- Requires Node.js ≥22 and DSH `0.1.7-rc.2`. No repository build is needed.
9
+ Requires Node.js ≥22 and DSH `0.1.7-rc.2`. No repository build is needed. Install:
10
+
11
+ ```sh
12
+ npm install @klarkxy/dsh-web-search-manager
13
+ ```
14
+
15
+ Then load it:
10
16
 
11
17
  ```sh
12
18
  dsh plugin --profile web add @klarkxy/dsh-web-search-manager
13
19
  ```
14
20
 
15
- Restart DSH Web and open **Settings → Web search**. For agent access, add this entry to the plugin list in its `agent.cordis.yml`:
21
+ Restart DSH Web and open **Plugins → Web search**. For agent access, add this entry to the plugin list in its `agent.cordis.yml`:
16
22
 
17
23
  ```yaml
18
24
  - name: '@klarkxy/dsh-web-search-manager/tools'
19
25
  ```
20
26
 
21
- DSH Editor already includes the plugin, its tools, and the Tavily adapter.
22
-
23
27
  ## Configure search
24
28
 
25
- DuckDuckGo is enabled by default and requires no key. Enable another provider and configure credentials in settings if needed; one ready provider is enough. DeepSeek shares the key from model settings and may incur additional search charges.
29
+ The settings page has two tabs: **搜索服务** manages providers, and **请求限制** sets request limits. DuckDuckGo is enabled by default and requires no key. Enable another provider and configure credentials in settings if needed; one ready provider is enough. Drag providers to reorder them; the first ready provider by priority handles each request. Missing credentials are skipped; failed requests do not automatically switch providers.
30
+
31
+ Built-in search backends:
32
+
33
+ - **DuckDuckGo**: no registration and no key; the default backend, free of charge.
34
+ - **DeepSeek 搜索**: shares the DeepSeek API key from model settings (`DEEPSEEK_API_KEY`); may incur additional search charges on top of model usage.
35
+ - **Exa**: an independent Search API; requires its own key (`DSH_EDITOR_WEB_EXA_API_KEY`). The Exa provider is declared as a runtime dependency of this plugin.
36
+ - **Brave**: the Brave Search API; requires `DSH_EDITOR_WEB_BRAVE_API_KEY`.
37
+ - **博查**: a Chinese web search API; requires `DSH_EDITOR_WEB_BOCHA_API_KEY`.
38
+ - **Serper**: a Google results API; requires `DSH_EDITOR_WEB_SERPER_API_KEY`.
39
+ - **Firecrawl**: a web search and extraction API; requires `DSH_EDITOR_WEB_FIRECRAWL_API_KEY`.
40
+ - **Tavily**: a Search API fixed to basic search depth, never auto-upgraded; requires `DSH_EDITOR_WEB_TAVILY_API_KEY`. The adapter is built into this plugin; the former standalone `dsh-web-search-tavily` package is retired.
41
+
42
+ Enabling search also enables public-page fetching through the built-in HTTP fetch provider, which reads pages directly from your machine: no key and no search charges. Request limits cap each query's results (`maxResults`), queries per tool call (`maxQueries`), request timeout (`timeoutMs`), and fetched page characters (`maxFetchChars`). A connection test sends a fixed query, not manuscript content, and may incur a provider charge.
26
43
 
27
- The first ready provider by priority is used. Missing credentials are skipped; failed requests do not automatically switch providers. Enabling search also enables public-page fetching. A connection test sends a fixed query, not manuscript content, and may incur a provider charge.
44
+ With the tools entry enabled, the agent receives the official `web_search` and `web_fetch` tools from `@deepseek-ai/dsh-tool-web`, mounted only while search and fetching are enabled.
28
45
 
29
46
  Only configure trusted HTTPS endpoints: API keys are sent to them. Credentials use DSH storage; protection at rest depends on its configured backend. Usage counters are call attempts, not billing statements or a spending cap.
30
47
 
@@ -6,25 +6,42 @@
6
6
 
7
7
  ## 安装
8
8
 
9
- 需要 Node.js ≥22、DSH `0.1.7-rc.2`,无需构建本仓库。
9
+ 需要 Node.js ≥22、DSH `0.1.7-rc.2`,无需构建本仓库。安装:
10
+
11
+ ```sh
12
+ npm install @klarkxy/dsh-web-search-manager
13
+ ```
14
+
15
+ 然后加载:
10
16
 
11
17
  ```sh
12
18
  dsh plugin --profile web add @klarkxy/dsh-web-search-manager
13
19
  ```
14
20
 
15
- 重启 DSH Web,打开「设置 → 网络搜索」。模型需要使用搜索工具时,在所用 `agent.cordis.yml` 的插件列表加入:
21
+ 重启 DSH Web,打开「插件 → 网络搜索」。模型需要使用搜索工具时,在所用 `agent.cordis.yml` 的插件列表加入:
16
22
 
17
23
  ```yaml
18
24
  - name: '@klarkxy/dsh-web-search-manager/tools'
19
25
  ```
20
26
 
21
- DSH Editor 已内置此插件、模型工具及 Tavily 适配器。
22
-
23
27
  ## 配置搜索
24
28
 
25
- 默认开启 DuckDuckGo,无需密钥。需要其它后端时在设置中开启并填写凭据;一个可用后端即可。DeepSeek 共用模型设置中的密钥,可能产生额外搜索费用。
29
+ 设置页分两个标签页:「搜索服务」管理供应商,「请求限制」设置请求限额。默认开启 DuckDuckGo,无需密钥。需要其它后端时在设置中开启并填写凭据;一个可用后端即可。拖拽后端调整顺序;按优先级使用第一个就绪后端,缺密钥的跳过,失败不自动换家。
30
+
31
+ 内置搜索后端:
32
+
33
+ - **DuckDuckGo**:无需注册、无需密钥,默认后端,免费。
34
+ - **DeepSeek 搜索**:与模型设置共用 DeepSeek API Key(`DEEPSEEK_API_KEY`),可能在模型费用外产生额外搜索费用。
35
+ - **Exa**:独立 Search API,需要单独的 Key(`DSH_EDITOR_WEB_EXA_API_KEY`)。Exa 供应商已声明为本插件的运行时依赖。
36
+ - **Brave**:Brave Search API,需要 `DSH_EDITOR_WEB_BRAVE_API_KEY`。
37
+ - **博查**:中文网页搜索 API,需要 `DSH_EDITOR_WEB_BOCHA_API_KEY`。
38
+ - **Serper**:Google 结果 Search API,需要 `DSH_EDITOR_WEB_SERPER_API_KEY`。
39
+ - **Firecrawl**:网页搜索与提取 API,需要 `DSH_EDITOR_WEB_FIRECRAWL_API_KEY`。
40
+ - **Tavily**:Search API,固定 basic 检索深度,不自动升级;需要 `DSH_EDITOR_WEB_TAVILY_API_KEY`。适配器已并入本插件,原独立的 `dsh-web-search-tavily` 包已退役。
41
+
42
+ 开启搜索也会启用公开网页读取,由内置 HTTP 读取后端直接从本机读取页面,无需密钥、不产生搜索费用。请求限制包括每条查询的结果上限(`maxResults`)、每次工具调用的查询上限(`maxQueries`)、请求超时(`timeoutMs`)和网页正文字符上限(`maxFetchChars`)。连接测试发送固定查询,不发送作品内容,可能产生一次调用费用。
26
43
 
27
- 按优先级使用第一个就绪后端,缺密钥的跳过,失败不自动换家。开启搜索也会启用公开网页读取。连接测试发送固定查询,不发送作品内容,可能产生一次调用费用。
44
+ 加入 tools 入口后,模型获得 `@deepseek-ai/dsh-tool-web` 的官方 `web_search` 与 `web_fetch` 工具,仅在搜索与网页读取开启时挂载。
28
45
 
29
46
  只配置可信 HTTPS 端点,密钥会发送到该地址。凭据由 DSH 保存,落盘保护取决于其后端配置。用量计数是调用尝试,不等于账单或消费上限。
30
47
 
package/icon.svg ADDED
@@ -0,0 +1,15 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36" fill="none">
2
+ <defs>
3
+ <linearGradient id="globe" x1="6" y1="6" x2="26" y2="26" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#4D75F5"/>
5
+ <stop offset="1" stop-color="#8EB6FF"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <g transform="translate(3.6 3.6) scale(.8)">
9
+ <circle cx="15" cy="15" r="10" fill="url(#globe)"/>
10
+ <path d="M5.5 15H24.5M15 5.2C11.5 8 11.5 22 15 24.8C18.5 22 18.5 8 15 5.2Z" stroke="#B8D7FF" stroke-width="1.8"/>
11
+ <circle cx="23" cy="23" r="6.5" fill="#0E2A56" fill-opacity=".3"/>
12
+ <circle cx="23" cy="23" r="5.5" stroke="#65DED0" stroke-width="2.6"/>
13
+ <path d="M27.2 27.2L31 31" stroke="#55D9CE" stroke-width="3" stroke-linecap="round"/>
14
+ </g>
15
+ </svg>
@@ -509,11 +509,11 @@ function NetworkSearchSettings({ client }) {
509
509
  }),
510
510
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
511
511
  className: "web-search-provider-info",
512
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: info.description }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [info.pricing, info.pricingUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExternalLink, {
512
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: info.description }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "费用说明" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [info.pricing, info.pricingUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExternalLink, {
513
513
  url: info.pricingUrl,
514
514
  label: provider.label + " 费用说明",
515
515
  children: provider.id === "ddg" ? "官网" : "费用说明"
516
- })] })] })]
516
+ })] })] })] })]
517
517
  }),
518
518
  participating && !provider.configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
519
519
  className: "web-search-meta",
@@ -685,11 +685,9 @@ function apply(ctx) {
685
685
  document.head.appendChild(style);
686
686
  return () => style.remove();
687
687
  }, "web-search-manager.styles");
688
- ctx.effect(() => client.slots.inject("settings.section", () => client.slots.register({
689
- name: "settings.section",
690
- id: "web-search",
691
- order: 70,
692
- label: "网络搜索"
688
+ ctx.effect(() => client.slots.inject("plugins.bundle.config", () => client.slots.register({
689
+ name: "plugins.bundle.config",
690
+ key: "@klarkxy/dsh-web-search-manager"
693
691
  }, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NetworkSearchSettings, { client }))), "web-search-manager.settings");
694
692
  }
695
693
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"client.inner.cjs","names":["useState","useRef","useId"],"sources":["../src/provider-info.ts","../src/contracts.ts","../src/client.tsx"],"sourcesContent":["import type { ProviderView } from './contracts.ts'\n\n// Public prices checked on 2026-09-21; links remain available for current account terms.\nexport const PROVIDER_PRICING_CHECKED = '2026-09-21'\n\ninterface ProviderInfo {\n description: string\n pricing: string\n pricingUrl?: string\n}\n\nconst providerInfo: Record<string, ProviderInfo> = {\n ddg: {\n description: '搜索 DuckDuckGo 公开网页,无需注册或 API Key。',\n pricing: '免费使用,不产生搜索 API 费用。',\n pricingUrl: 'https://duckduckgo.com/',\n },\n bocha: {\n description: '面向中文内容的网页搜索,返回标题、链接和摘要。',\n pricing: '按调用次数计费,目录价 ¥0.036/次;试用额度以官方活动为准。',\n pricingUrl: 'https://aq6ky2b8nql.feishu.cn/wiki/JYSbwzdPIiFnz4kDYPXcHSDrnZb',\n },\n brave: {\n description: '使用 Brave 独立网页索引,搜索网页、新闻等内容。',\n pricing: '每月赠 $5(约 1,000 次);超出 $5/千次,激活需绑卡。',\n pricingUrl: 'https://brave.com/search/api/',\n },\n 'deepseek-official': {\n description: '由 DeepSeek 模型调用内置搜索,复用模型 API Key。',\n pricing: '默认 Flash 按 tokens 计费:每百万输入 ¥1–2(缓存命中 ¥0.02–0.04)、输出 ¥4–8,随峰谷时段变化;赠送余额和搜索工具费用以平台为准。',\n pricingUrl: 'https://api-docs.deepseek.com/zh-cn/quick_start/pricing/',\n },\n exa: {\n description: '面向 AI 的网页搜索,提供相关网页与内容片段。',\n pricing: '注册赠 $20,此后每月赠 $10;$7/千次(每次最多 10 条),超过 10 条每多一条加 $1/千次。',\n pricingUrl: 'https://exa.ai/pricing',\n },\n firecrawl: {\n description: '搜索网页,并可配合网页内容提取。',\n pricing: '每月免费 1,000 积分,搜索每 10 条结果扣 2 积分;Hobby 含 5,000 积分/月,年付折合 $16/月,额外 $5/千积分。',\n pricingUrl: 'https://www.firecrawl.dev/pricing',\n },\n serper: {\n description: '获取 Google 的网页搜索结果。',\n pricing: '注册赠 2,500 次(一次性);充值 $50/5万次($1/千次),付费额度有效期 6 个月。',\n pricingUrl: 'https://serper.dev/',\n },\n tavily: {\n description: '面向 AI 的网页搜索,当前使用基础搜索。',\n pricing: '每月免费 1,000 积分,基础搜索 1 积分/次;按量付费 $0.008/积分($8/千次)。',\n pricingUrl: 'https://docs.tavily.com/documentation/api-credits',\n },\n}\n\nexport function searchProviderInfo(provider: ProviderView): ProviderInfo {\n const known = Object.hasOwn(providerInfo, provider.id) ? providerInfo[provider.id] : undefined\n return {\n description: known?.description ?? provider.description,\n pricing: provider.pricing ?? known?.pricing ?? (provider.billing === 'none' ? '此后端不收取搜索费用。'\n : provider.billing === 'model-and-tools' ? '按模型用量和工具调用计费;免费额度及单价请查看供应商说明。'\n : '按 API 调用计费;免费额度及单价请查看供应商说明。'),\n pricingUrl: provider.pricingUrl ?? known?.pricingUrl ?? provider.signupUrl,\n }\n}\n","import type { WebFetchProvider, WebSearchProvider } from '@deepseek-ai/dsh-web'\n\nexport const WEB_SEARCH_RPC_CHANNEL = '/web-search-manager'\nexport type RpcResult<T = unknown> = { ok: true; value: T } | {\n ok: false; error: { code: string; message: string; details: Record<string, unknown> }\n}\nexport type ProviderKind = 'search' | 'fetch'\n/** Management metadata only. Execution and source vocabulary belong to ctx.web. */\nexport interface ProviderDescriptor {\n readonly id: string\n readonly label: string\n readonly description: string\n readonly defaultBaseURL?: string\n readonly credentialRef?: string\n /** True when the key is shared with another surface. The page must not delete it. */\n readonly credentialShared?: boolean\n /** Optional notice naming the settings surface that owns a shared credential. */\n readonly credentialHint?: string\n readonly billing: 'request' | 'model-and-tools' | 'none'\n /** Optional provider-supplied billing summary. */\n readonly pricing?: string\n /** Public HTTPS page explaining provider charges. */\n readonly pricingUrl?: string\n /** Public HTTPS page where the user can create an API key. */\n readonly signupUrl?: string\n}\nexport interface ProviderOptions {\n readonly apiKey?: string\n readonly baseURL?: string\n readonly timeoutMs: number\n readonly maxFetchChars: number\n}\nexport type SearchProviderFactory = (options: ProviderOptions) => WebSearchProvider\nexport type FetchProviderFactory = (options: ProviderOptions) => WebFetchProvider\n/** Never store credential values here. Keys are resolved by reference per call. */\nexport interface WebSettings {\n revision: number\n searchEnabled: boolean\n fetchEnabled: boolean\n searchProvider: string\n fetchProvider: string\n searchOrder: string[]\n maxResults: number\n maxQueries: number\n timeoutMs: number\n maxFetchChars: number\n endpoints: Record<string, string>\n}\nexport const DEFAULT_SEARCH_ORDER = ['ddg'] as const\n\nexport const defaultSettings = (): WebSettings => ({\n revision: 0, searchEnabled: true, fetchEnabled: true,\n searchProvider: 'ddg', fetchProvider: 'http', searchOrder: [...DEFAULT_SEARCH_ORDER],\n maxResults: 5, maxQueries: 1,\n timeoutMs: 30_000, maxFetchChars: 100_000, endpoints: {},\n})\n\n/** Keyed backends first, keyless last — same idea as OpenClaw auto-detect. */\nexport function defaultSearchOrder(ids: readonly string[], keyed: (id: string) => boolean): string[] {\n return [...ids.filter(keyed), ...ids.filter(id => !keyed(id))]\n}\n\nexport function migrateSearchOrder(settings: { searchOrder?: string[]; searchProvider?: string }): string[] {\n return settings.searchOrder ?? (settings.searchProvider ? [settings.searchProvider] : [...DEFAULT_SEARCH_ORDER])\n}\n\nexport function resolveSearchOrder(\n knownIds: readonly string[],\n settings: Pick<WebSettings, 'searchOrder' | 'searchProvider'>,\n _keyed: (id: string) => boolean,\n): string[] {\n return [...new Set(settings.searchOrder.filter(id => knownIds.includes(id)))]\n}\n\nexport function pickActiveSearch(order: readonly string[], configured: (id: string) => boolean): string {\n return order.find(configured) ?? ''\n}\nexport interface ProviderView extends ProviderDescriptor {\n kind: ProviderKind\n configured: boolean\n baseURL?: string\n calls: number\n failures: number\n}\nexport interface WebStatus {\n settings: WebSettings\n providers: ProviderView[]\n searchActive: boolean\n fetchActive: boolean\n storageFailed: boolean\n}\nexport function providerKey(kind: ProviderKind, id: string): string { return `${kind}:${id}` }\nexport function validateBaseURL(value: string): string {\n const url = new URL(value)\n if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) {\n throw new Error('供应商地址必须是 HTTPS,且不能包含用户名、密码、查询参数或片段。')\n }\n return url.href.replace(/\\/+$/, '')\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { useEffect, useId, useRef, useState } from 'react'\nimport { PROVIDER_PRICING_CHECKED, searchProviderInfo } from './provider-info.ts'\nimport {\n WEB_SEARCH_RPC_CHANNEL, pickActiveSearch, resolveSearchOrder,\n type ProviderView, type RpcResult, type WebSettings, type WebStatus,\n} from './contracts.ts'\n\nexport const name = 'dsh-web-search-manager-client'\nexport const inject = ['slots', 'connection', 'remote', 'remote.credentials'] as const\n\ninterface Credentials {\n describe(refs: string[]): Promise<RpcResult<Record<string, { configured: boolean; writable: boolean; source?: string }>>>\n set(ref: string, value: string): Promise<RpcResult<unknown>>\n unset(ref: string): Promise<RpcResult<unknown>>\n}\ninterface Client {\n connection: { rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> } }\n remote: { credentials: Credentials }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; id: string; label: string; order: number }, render: unknown): () => void\n }\n}\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\nfunction editable(settings: WebSettings): Omit<WebSettings, 'revision'> {\n const { revision: _revision, ...rest } = settings\n return rest\n}\n\nexport function isProviderOn(status: WebStatus, provider: ProviderView): boolean {\n const enabled = provider.kind === 'search' ? status.searchActive : status.fetchActive\n const selected = status.settings[provider.kind === 'search' ? 'searchProvider' : 'fetchProvider']\n return enabled && selected === provider.id\n}\n\nexport function searchBackends(status: WebStatus): ProviderView[] {\n const all = status.providers.filter(provider => provider.kind === 'search')\n const order = resolveSearchOrder(\n all.map(provider => provider.id),\n status.settings,\n id => Boolean(all.find(provider => provider.id === id)?.credentialRef),\n )\n return order.flatMap(id => all.find(provider => provider.id === id) ?? [])\n}\n\nexport function catalogSearchBackends(status: WebStatus): ProviderView[] {\n const enabled = searchBackends(status)\n const rest = status.providers.filter(provider => provider.kind === 'search' && !enabled.some(row => row.id === provider.id))\n return [...enabled, ...rest]\n}\n\nexport function selectedSearchBackend(status: WebStatus): ProviderView | undefined {\n const backends = searchBackends(status)\n const id = pickActiveSearch(backends.map(provider => provider.id), id => Boolean(backends.find(provider => provider.id === id)?.configured))\n return backends.find(provider => provider.id === id)\n}\n\nfunction ExternalLink({ url, label, children }: { url: string; label: string; children: string }) {\n return <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" aria-label={label}\n onClick={event => {\n const bridge = (globalThis as { dshWindow?: { openExternal?(url: string): void } }).dshWindow\n if (bridge?.openExternal) {\n event.preventDefault()\n bridge.openExternal(url)\n }\n }}>{children}</a>\n}\n\nexport function canEnableSearch(\n order: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return order.some(id => {\n const provider = providers.find(item => item.kind === 'search' && item.id === id)\n if (!provider) return false\n if (provider.configured) return true\n const typed = (keys[provider.id] ?? '').trim()\n return Boolean(provider.credentialRef && typed && writable[provider.credentialRef] !== false)\n })\n}\n\nexport function nextSearchEnabled(\n currentlyEnabled: boolean,\n nextOrder: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return currentlyEnabled && canEnableSearch(nextOrder, providers, keys, writable)\n}\n\nfunction ConfirmButton(props: { label: string; confirmLabel: string; disabled?: boolean; onConfirm(): void }) {\n const [armed, setArmed] = useState(false)\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined)\n useEffect(() => () => clearTimeout(timer.current), [])\n function disarm() {\n clearTimeout(timer.current)\n setArmed(false)\n }\n return <button type=\"button\" className=\"web-search-danger\" disabled={props.disabled}\n onClick={() => {\n if (!armed) {\n setArmed(true)\n timer.current = setTimeout(() => setArmed(false), 3000)\n return\n }\n disarm()\n props.onConfirm()\n }}\n onBlur={disarm}>{armed ? props.confirmLabel : props.label}</button>\n}\n\nexport function NetworkSearchSettings({ client }: { client: Client }) {\n const tabsId = useId()\n const [tab, setTab] = useState<'providers' | 'limits'>('providers')\n const [status, setStatus] = useState<WebStatus>()\n const [draft, setDraft] = useState<WebSettings>()\n const [keys, setKeys] = useState<Record<string, string>>({})\n const [busy, setBusy] = useState(false)\n const [dragSource, setDragSource] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<string | null>(null)\n const [sortAnnouncement, setSortAnnouncement] = useState('')\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n const [writable, setWritable] = useState<Record<string, boolean>>({})\n\n async function call<T>(endpoint: string, payload: unknown = {}): Promise<T> {\n return unwrap(await client.connection.rpc.call(WEB_SEARCH_RPC_CHANNEL, endpoint, payload) as RpcResult<T>)\n }\n async function load() {\n const next = await call<WebStatus>('status')\n setStatus(next); setDraft(next.settings)\n const refs = next.providers.flatMap(provider => provider.credentialRef ? [provider.credentialRef] : [])\n if (refs.length) {\n const credentials = unwrap(await client.remote.credentials.describe(refs))\n setWritable(Object.fromEntries(Object.entries(credentials).map(([ref, value]) => [ref, value.writable])))\n }\n return next\n }\n useEffect(() => { void load().catch(() => setError('无法读取网络搜索设置,请检查 Host 连接后重试。')) }, [client])\n\n async function action(run: () => Promise<void>) {\n setBusy(true); setNote(''); setError('')\n try { await run() }\n catch (cause) { setError(cause instanceof Error ? cause.message : '操作失败。'); await load().catch(() => {}) }\n finally { setBusy(false) }\n }\n async function update(settings: Omit<WebSettings, 'revision'>, expectedRevision: number) {\n const next = await call<WebStatus>('update', { settings, expectedRevision })\n setStatus(next); setDraft(next.settings)\n return next\n }\n\n async function persist(on: boolean, order: string[]) {\n if (!status || !draft) return\n for (const provider of status.providers) {\n if (provider.kind !== 'search') continue\n const snapshot = keys[provider.id] ?? ''\n const typed = snapshot.trim()\n if (!provider.credentialRef || !typed) continue\n if (writable[provider.credentialRef] === false) throw new Error('当前凭据为只读,无法写入。')\n unwrap(await client.remote.credentials.set(provider.credentialRef, typed))\n setKeys(current => current[provider.id] === snapshot ? { ...current, [provider.id]: '' } : current)\n }\n const bounded = (key: (typeof limits)[number][0]) => {\n const row = limits.find(item => item[0] === key)!\n return Math.min(row[3], Math.max(row[2], Number.isFinite(draft[key]) ? draft[key] : row[2]))\n }\n await update({\n ...editable(status.settings),\n maxResults: bounded('maxResults'), maxQueries: bounded('maxQueries'),\n timeoutMs: bounded('timeoutMs'), maxFetchChars: bounded('maxFetchChars'),\n endpoints: draft.endpoints, searchOrder: order,\n searchEnabled: on, fetchProvider: 'http', fetchEnabled: on,\n }, status.settings.revision)\n await load()\n }\n\n async function removeKey(provider: ProviderView) {\n if (!provider.credentialRef || provider.credentialShared || !status) return\n unwrap(await client.remote.credentials.unset(provider.credentialRef))\n setKeys(current => ({ ...current, [provider.id]: '' }))\n await load()\n setNote('已删除 Key。')\n }\n\n if (!status || !draft) {\n return <section className=\"web-search-settings\">\n <p role=\"status\">{error || '正在读取设置…'}</p>\n {error ? <button type=\"button\" onClick={() => void action(async () => { await load() })}>重新连接</button> : null}\n </section>\n }\n\n const enabled = searchBackends(status)\n const backends = catalogSearchBackends(status)\n const selected = selectedSearchBackend(status)\n const on = status.settings.searchEnabled\n const order = enabled.map(provider => provider.id)\n const canEnable = canEnableSearch(order, status.providers, keys, writable)\n const limits = [\n ['maxResults', '每条查询的结果上限', 1, 20],\n ['maxQueries', '每次工具调用的查询上限', 1, 5],\n ['timeoutMs', '请求超时(毫秒)', 1000, 120000],\n ['maxFetchChars', '网页正文字符上限', 1000, 200000],\n ] as const\n\n function move(id: string, nextIndex: number) {\n const index = order.indexOf(id)\n if (busy || index < 0 || nextIndex < 0 || nextIndex >= order.length || index === nextIndex) return\n const next = [...order]\n const [item] = next.splice(index, 1)\n next.splice(nextIndex, 0, item)\n void action(async () => {\n await persist(on, next)\n setSortAnnouncement((backends.find(provider => provider.id === id)?.label ?? id) + ' 已移至第 ' + (nextIndex + 1) + ' 位')\n })\n }\n\n function endDrag() {\n setDragSource(null)\n setDropTarget(null)\n }\n\n return <section className=\"web-search-settings\" data-testid=\"web-search-settings\">\n <div className=\"web-search-tabs\" role=\"tablist\" aria-label=\"网络搜索设置\" onKeyDown={event => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return\n const buttons = [...event.currentTarget.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]')]\n const index = buttons.indexOf(event.target as HTMLButtonElement)\n if (index < 0) return\n event.preventDefault()\n const next = event.key === 'Home' ? 0 : event.key === 'End' ? buttons.length - 1\n : (index + (event.key === 'ArrowRight' ? 1 : -1) + buttons.length) % buttons.length\n buttons[next]?.focus()\n buttons[next]?.click()\n }}>\n {([['providers', '搜索服务'], ['limits', '请求限制']] as const).map(([key, label]) => (\n <button key={key} type=\"button\" role=\"tab\" id={tabsId + '-' + key + '-tab'}\n aria-controls={tabsId + '-' + key + '-panel'} aria-selected={tab === key}\n tabIndex={tab === key ? 0 : -1} onClick={() => setTab(key)}>{label}</button>\n ))}\n </div>\n <span className=\"web-search-sr-only\" role=\"status\" aria-live=\"polite\">{sortAnnouncement}</span>\n {error && <p role=\"alert\" className=\"web-search-error\">{error}</p>}\n {note && <p role=\"status\">{note}</p>}\n {status.storageFailed && <p role=\"alert\">配置保存异常,当前运行已暂停网络访问。请重新保存。</p>}\n <div role=\"tabpanel\" id={tabsId + '-providers-panel'} aria-labelledby={tabsId + '-providers-tab'}\n hidden={tab !== 'providers'} tabIndex={0}>\n {backends.length === 0 ? <p className=\"web-search-empty\">还没有可用的搜索后端。</p> : <article\n className=\"web-search-card\"\n data-testid=\"web-search-tool\"\n data-on={on ? 'true' : 'false'}>\n <header>\n <div>\n <h3>联网搜索</h3>\n {!canEnable && <p className=\"web-search-meta\">请选择搜索服务并配置 Key。</p>}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n className={`web-search-switch${on ? ' is-on' : ''}`}\n aria-checked={on}\n aria-label={on ? '关闭联网搜索' : '启用联网搜索'}\n disabled={busy || (!on && !canEnable)}\n onClick={() => void action(() => persist(!on, order))}>\n <span className=\"web-search-switch-thumb\" aria-hidden=\"true\" />\n </button>\n </header>\n <ol className=\"web-search-rank\" aria-label=\"搜索后端\">\n {backends.map(provider => {\n const participating = order.includes(provider.id)\n const rank = order.indexOf(provider.id)\n const active = status.searchActive && selected?.id === provider.id\n const info = searchProviderInfo(provider)\n const needsKey = Boolean(provider.credentialRef)\n const shared = Boolean(provider.credentialShared)\n const showKey = needsKey && participating && (!shared || !provider.configured)\n const canSort = participating && order.length > 1\n return <li key={provider.id} className={active ? 'is-active' : undefined} data-testid={`web-search-rank-${provider.id}`}\n data-dragging={dragSource === provider.id || undefined}\n data-drop={dropTarget === provider.id && dragSource ? (order.indexOf(dragSource) < rank ? 'after' : 'before') : undefined}\n onDragOver={event => {\n if (busy || !canSort || !dragSource || dragSource === provider.id) return\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n setDropTarget(provider.id)\n }}\n onDragLeave={event => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setDropTarget(null)\n }}\n onDrop={event => {\n if (busy || !canSort || !dragSource) return\n event.preventDefault()\n move(dragSource, rank)\n endDrag()\n }}>\n {canSort ? <button type=\"button\" className=\"web-search-drag-handle\"\n draggable={!busy} aria-disabled={busy}\n aria-label={'拖动排序 ' + provider.label}\n title=\"拖动排序,或用上下方向键调整\"\n onDragStart={event => {\n if (busy) { event.preventDefault(); return }\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('application/x-dsh-search-provider', provider.id)\n const row = event.currentTarget.closest('li')\n if (row) event.dataTransfer.setDragImage(row, 16, 16)\n setDragSource(provider.id)\n setSortAnnouncement('')\n }}\n onDragEnd={endDrag}\n onKeyDown={event => {\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n move(provider.id, rank + (event.key === 'ArrowUp' ? -1 : 1))\n }}>\n <svg width=\"16\" height=\"20\" viewBox=\"0 0 16 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" /><circle cx=\"11\" cy=\"5\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" /><circle cx=\"11\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" /><circle cx=\"11\" cy=\"15\" r=\"1.5\" />\n </svg>\n </button> : <span className=\"web-search-rank-index\">{participating ? rank + 1 : '—'}</span>}\n <div className=\"web-search-provider\">\n <div className=\"web-search-provider-heading\">\n <strong>{provider.label}</strong>\n {active && <span className=\"web-search-meta\">当前使用</span>}\n {provider.signupUrl && <ExternalLink url={provider.signupUrl} label={provider.label + ' 去注册'}>去注册</ExternalLink>}\n </div>\n <div className=\"web-search-provider-info\">\n <p>{info.description}</p>\n <p>{info.pricing}{info.pricingUrl && <> <ExternalLink url={info.pricingUrl}\n label={provider.label + ' 费用说明'}>{provider.id === 'ddg' ? '官网' : '费用说明'}</ExternalLink></>}</p>\n </div>\n {participating && !provider.configured && <p className=\"web-search-meta\">{needsKey ? '待配置 Key' : '暂不可用'}</p>}\n {shared && participating && <small>{provider.credentialHint ?? '与其他设置共用凭据'}</small>}\n {showKey ? <label>API Key\n <input type=\"password\" autoComplete=\"off\" spellCheck={false}\n disabled={busy || writable[provider.credentialRef ?? ''] === false}\n value={keys[provider.id] ?? ''}\n placeholder={provider.configured ? '已配置,留空不替换' : '请输入 API Key'}\n onChange={event => setKeys(current => ({ ...current, [provider.id]: event.target.value }))} />\n </label> : null}\n {needsKey && !shared && provider.configured ? <ConfirmButton\n disabled={busy || writable[provider.credentialRef ?? ''] === false}\n label=\"删除 Key\" confirmLabel=\"确认删除 Key?\"\n onConfirm={() => void action(() => removeKey(provider))} /> : null}\n </div>\n <div className=\"web-search-rank-move\">\n <button\n type=\"button\"\n role=\"switch\"\n className={`web-search-switch${participating ? ' is-on' : ''}`}\n aria-checked={participating}\n aria-label={`${participating ? '关闭' : '开启'} ${provider.label}`}\n disabled={busy}\n onClick={() => {\n const next = participating ? order.filter(id => id !== provider.id) : [...order, provider.id]\n void action(() => persist(nextSearchEnabled(status.settings.searchEnabled, next, status.providers, keys, writable), next))\n }}>\n <span className=\"web-search-switch-thumb\" aria-hidden=\"true\" />\n </button>\n </div>\n </li>\n })}\n </ol>\n <p className=\"web-search-meta\">价格核对于 {PROVIDER_PRICING_CHECKED},实际额度与费用以供应商账户为准。</p>\n {on ? <div className=\"web-search-card-actions\">\n <button type=\"button\" disabled={busy} onClick={() => void action(async () => {\n await persist(status.settings.searchEnabled, order)\n const result = await call<{ sources: number }>('test')\n await load()\n setNote(`连接正常,返回 ${result.sources} 条来源。`)\n })}>测试连接(可能计费)</button>\n </div> : null}\n </article>}\n </div>\n <div role=\"tabpanel\" id={tabsId + '-limits-panel'} aria-labelledby={tabsId + '-limits-tab'}\n hidden={tab !== 'limits'} tabIndex={0}>\n <fieldset className=\"web-search-limits\" disabled={busy} aria-label=\"请求限制\">\n {limits.map(([key, label, min, max]) => (\n <label key={key}>{label}\n <input type=\"number\" min={min} max={max} step={1} value={draft[key]}\n onChange={event => setDraft({ ...draft, [key]: Number(event.target.value) })} />\n </label>\n ))}\n </fieldset>\n </div>\n <button type=\"button\" disabled={busy} onClick={() => void action(async () => {\n await persist(status.settings.searchEnabled, order)\n setNote('已保存。')\n })}>保存</button>\n </section>\n}\n\nconst styles = `\n.web-search-settings{max-width:760px;display:grid;gap:24px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}\n.web-search-settings p{margin:0;line-height:1.5}\n.web-search-settings small,.web-search-meta,.web-search-empty{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}\n.web-search-error{color:var(--red-11,#b42318)}\n.web-search-card{display:grid;gap:12px;padding:16px;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:12px}\n.web-search-card header{display:flex;justify-content:space-between;gap:12px;align-items:center;padding-bottom:8px}\n.web-search-card h3{margin:0;font-size:var(--font-size-3,16px);font-weight:600}\n.web-search-provider{display:grid;gap:8px;min-width:0}\n.web-search-provider-info{display:grid;gap:3px;font-size:var(--font-size-1,13px);color:var(--gray-11,inherit);overflow-wrap:anywhere}\n.web-search-provider-heading{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;min-height:24px}\n.web-search-provider-heading strong{font-weight:500}\n.web-search-card label{display:grid;gap:6px}\n.web-search-settings input{box-sizing:border-box;width:100%;min-width:0;padding:8px 10px;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 22%,transparent));border-radius:8px;background:var(--color-surface,transparent);color:inherit;font:inherit;transition:border-color 150ms ease,box-shadow 150ms ease}\n.web-search-settings input:focus{border-color:var(--accent-9,#3b82f6);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-9,#3b82f6) 25%,transparent)}\n.web-search-settings button:not([role=\"switch\"]){min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}\n.web-search-settings button:not([role=\"switch\"]):not([role=\"tab\"]):not(.web-search-drag-handle):hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}\n.web-search-settings button:not([role=\"switch\"]):not([role=\"tab\"]):not(.web-search-drag-handle):active:not(:disabled){transform:scale(.97)}\n.web-search-danger:hover:not(:disabled){border-color:var(--red-11,#b42318);color:var(--red-11,#b42318);background:color-mix(in srgb,var(--red-11,#b42318) 8%,transparent)}\n.web-search-settings button:disabled{opacity:.45;cursor:not-allowed}\n.web-search-tabs{display:flex;gap:20px;border-bottom:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent))}\n.web-search-tabs button[role=\"tab\"]{padding:8px 0;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--gray-11,inherit)}\n.web-search-tabs button[role=\"tab\"]:hover{color:inherit}\n.web-search-tabs button[aria-selected=\"true\"]{border-bottom-color:var(--accent-9,#3b82f6);color:var(--accent-11,inherit);font-weight:600}\n.web-search-settings [role=\"tabpanel\"]{border-radius:12px}\n.web-search-settings .web-search-switch{all:unset;box-sizing:border-box;position:relative;display:inline-block;width:36px;height:20px;flex:none;border-radius:999px;background:var(--gray-7,color-mix(in srgb,currentColor 28%,transparent));cursor:pointer}\n.web-search-switch.is-on{background:var(--accent-9,#3b82f6)}\n.web-search-switch:disabled{cursor:not-allowed;opacity:.7}\n.web-search-switch-thumb{position:absolute;top:3px;left:3px;width:14px;height:14px;border-radius:999px;background:#fff;transition:transform 150ms ease}\n.web-search-switch.is-on .web-search-switch-thumb{transform:translateX(16px)}\n.web-search-settings :focus-visible{outline:2px solid var(--accent-9,currentColor);outline-offset:3px}\n.web-search-card-actions{display:flex;flex-wrap:wrap;gap:8px}\n.web-search-rank{margin:0;padding:0;list-style:none}\n.web-search-rank li{position:relative;display:grid;grid-template-columns:24px minmax(0,1fr) auto;gap:10px;align-items:start;padding:14px 0;border-top:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent))}\n.web-search-settings button.web-search-drag-handle{display:grid;place-items:center;width:24px;height:24px;min-height:24px;padding:0;border:0;cursor:grab;color:inherit;opacity:.65}\n.web-search-settings button.web-search-drag-handle:hover{opacity:1;background:var(--gray-3,color-mix(in srgb,currentColor 8%,transparent))}\n.web-search-settings button.web-search-drag-handle:active{cursor:grabbing}\n.web-search-settings button.web-search-drag-handle[aria-disabled=\"true\"]{cursor:wait;opacity:.4}\n.web-search-rank li[data-dragging]{opacity:.45}\n.web-search-rank li[data-drop]::after{content:'';position:absolute;left:0;right:0;height:2px;background:var(--accent-9,#3b82f6);pointer-events:none}\n.web-search-rank li[data-drop=\"before\"]::after{top:-1px}\n.web-search-rank li[data-drop=\"after\"]::after{bottom:-1px}\n.web-search-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n.web-search-rank-index{opacity:.6;font-variant-numeric:tabular-nums;line-height:24px}\n.web-search-rank-move{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:flex-end;padding-top:2px}\n.web-search-settings a{color:var(--accent-11,currentColor);font-size:var(--font-size-1,13px);text-underline-offset:3px}\n.web-search-limits{margin:0;border:0;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 20px}\n.web-search-limits label{display:grid;gap:6px;font-size:var(--font-size-2,14px)}\n@media(max-width:560px){.web-search-rank-move{flex-direction:column;align-items:flex-end}.web-search-limits{grid-template-columns:minmax(0,1fr)}}\n@media(prefers-reduced-motion:reduce){.web-search-switch-thumb{transition:none}.web-search-settings button:not([role=\"switch\"]),.web-search-settings input{transition:none}}\n`\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', '@klarkxy/dsh-web-search-manager'); style.textContent = styles\n style.dataset.dshWebSearch = ''; document.head.appendChild(style)\n return () => style.remove()\n }, 'web-search-manager.styles')\n ctx.effect(() => client.slots.inject('settings.section', () => client.slots.register({\n name: 'settings.section', id: 'web-search', order: 70, label: '网络搜索',\n }, () => <NetworkSearchSettings client={client} />)), 'web-search-manager.settings')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.inner.cjs","names":["useState","useRef","useId"],"sources":["../src/provider-info.ts","../src/contracts.ts","../src/client.tsx"],"sourcesContent":["import type { ProviderView } from './contracts.ts'\n\n// Public prices checked on 2026-09-21; links remain available for current account terms.\nexport const PROVIDER_PRICING_CHECKED = '2026-09-21'\n\ninterface ProviderInfo {\n description: string\n pricing: string\n pricingUrl?: string\n}\n\nconst providerInfo: Record<string, ProviderInfo> = {\n ddg: {\n description: '搜索 DuckDuckGo 公开网页,无需注册或 API Key。',\n pricing: '免费使用,不产生搜索 API 费用。',\n pricingUrl: 'https://duckduckgo.com/',\n },\n bocha: {\n description: '面向中文内容的网页搜索,返回标题、链接和摘要。',\n pricing: '按调用次数计费,目录价 ¥0.036/次;试用额度以官方活动为准。',\n pricingUrl: 'https://aq6ky2b8nql.feishu.cn/wiki/JYSbwzdPIiFnz4kDYPXcHSDrnZb',\n },\n brave: {\n description: '使用 Brave 独立网页索引,搜索网页、新闻等内容。',\n pricing: '每月赠 $5(约 1,000 次);超出 $5/千次,激活需绑卡。',\n pricingUrl: 'https://brave.com/search/api/',\n },\n 'deepseek-official': {\n description: '由 DeepSeek 模型调用内置搜索,复用模型 API Key。',\n pricing: '默认 Flash 按 tokens 计费:每百万输入 ¥1–2(缓存命中 ¥0.02–0.04)、输出 ¥4–8,随峰谷时段变化;赠送余额和搜索工具费用以平台为准。',\n pricingUrl: 'https://api-docs.deepseek.com/zh-cn/quick_start/pricing/',\n },\n exa: {\n description: '面向 AI 的网页搜索,提供相关网页与内容片段。',\n pricing: '注册赠 $20,此后每月赠 $10;$7/千次(每次最多 10 条),超过 10 条每多一条加 $1/千次。',\n pricingUrl: 'https://exa.ai/pricing',\n },\n firecrawl: {\n description: '搜索网页,并可配合网页内容提取。',\n pricing: '每月免费 1,000 积分,搜索每 10 条结果扣 2 积分;Hobby 含 5,000 积分/月,年付折合 $16/月,额外 $5/千积分。',\n pricingUrl: 'https://www.firecrawl.dev/pricing',\n },\n serper: {\n description: '获取 Google 的网页搜索结果。',\n pricing: '注册赠 2,500 次(一次性);充值 $50/5万次($1/千次),付费额度有效期 6 个月。',\n pricingUrl: 'https://serper.dev/',\n },\n tavily: {\n description: '面向 AI 的网页搜索,当前使用基础搜索。',\n pricing: '每月免费 1,000 积分,基础搜索 1 积分/次;按量付费 $0.008/积分($8/千次)。',\n pricingUrl: 'https://docs.tavily.com/documentation/api-credits',\n },\n}\n\nexport function searchProviderInfo(provider: ProviderView): ProviderInfo {\n const known = Object.hasOwn(providerInfo, provider.id) ? providerInfo[provider.id] : undefined\n return {\n description: known?.description ?? provider.description,\n pricing: provider.pricing ?? known?.pricing ?? (provider.billing === 'none' ? '此后端不收取搜索费用。'\n : provider.billing === 'model-and-tools' ? '按模型用量和工具调用计费;免费额度及单价请查看供应商说明。'\n : '按 API 调用计费;免费额度及单价请查看供应商说明。'),\n pricingUrl: provider.pricingUrl ?? known?.pricingUrl ?? provider.signupUrl,\n }\n}\n","import type { WebFetchProvider, WebSearchProvider } from '@deepseek-ai/dsh-web'\n\nexport const WEB_SEARCH_RPC_CHANNEL = '/web-search-manager'\nexport type RpcResult<T = unknown> = { ok: true; value: T } | {\n ok: false; error: { code: string; message: string; details: Record<string, unknown> }\n}\nexport type ProviderKind = 'search' | 'fetch'\n/** Management metadata only. Execution and source vocabulary belong to ctx.web. */\nexport interface ProviderDescriptor {\n readonly id: string\n readonly label: string\n readonly description: string\n readonly defaultBaseURL?: string\n readonly credentialRef?: string\n /** True when the key is shared with another surface. The page must not delete it. */\n readonly credentialShared?: boolean\n /** Optional notice naming the settings surface that owns a shared credential. */\n readonly credentialHint?: string\n readonly billing: 'request' | 'model-and-tools' | 'none'\n /** Optional provider-supplied billing summary. */\n readonly pricing?: string\n /** Public HTTPS page explaining provider charges. */\n readonly pricingUrl?: string\n /** Public HTTPS page where the user can create an API key. */\n readonly signupUrl?: string\n}\nexport interface ProviderOptions {\n readonly apiKey?: string\n readonly baseURL?: string\n readonly timeoutMs: number\n readonly maxFetchChars: number\n}\nexport type SearchProviderFactory = (options: ProviderOptions) => WebSearchProvider\nexport type FetchProviderFactory = (options: ProviderOptions) => WebFetchProvider\n/** Never store credential values here. Keys are resolved by reference per call. */\nexport interface WebSettings {\n revision: number\n searchEnabled: boolean\n fetchEnabled: boolean\n searchProvider: string\n fetchProvider: string\n searchOrder: string[]\n maxResults: number\n maxQueries: number\n timeoutMs: number\n maxFetchChars: number\n endpoints: Record<string, string>\n}\nexport const DEFAULT_SEARCH_ORDER = ['ddg'] as const\n\nexport const defaultSettings = (): WebSettings => ({\n revision: 0, searchEnabled: true, fetchEnabled: true,\n searchProvider: 'ddg', fetchProvider: 'http', searchOrder: [...DEFAULT_SEARCH_ORDER],\n maxResults: 5, maxQueries: 1,\n timeoutMs: 30_000, maxFetchChars: 100_000, endpoints: {},\n})\n\n/** Keyed backends first, keyless last — same idea as OpenClaw auto-detect. */\nexport function defaultSearchOrder(ids: readonly string[], keyed: (id: string) => boolean): string[] {\n return [...ids.filter(keyed), ...ids.filter(id => !keyed(id))]\n}\n\nexport function migrateSearchOrder(settings: { searchOrder?: string[]; searchProvider?: string }): string[] {\n return settings.searchOrder ?? (settings.searchProvider ? [settings.searchProvider] : [...DEFAULT_SEARCH_ORDER])\n}\n\nexport function resolveSearchOrder(\n knownIds: readonly string[],\n settings: Pick<WebSettings, 'searchOrder' | 'searchProvider'>,\n _keyed: (id: string) => boolean,\n): string[] {\n return [...new Set(settings.searchOrder.filter(id => knownIds.includes(id)))]\n}\n\nexport function pickActiveSearch(order: readonly string[], configured: (id: string) => boolean): string {\n return order.find(configured) ?? ''\n}\nexport interface ProviderView extends ProviderDescriptor {\n kind: ProviderKind\n configured: boolean\n baseURL?: string\n calls: number\n failures: number\n}\nexport interface WebStatus {\n settings: WebSettings\n providers: ProviderView[]\n searchActive: boolean\n fetchActive: boolean\n storageFailed: boolean\n}\nexport function providerKey(kind: ProviderKind, id: string): string { return `${kind}:${id}` }\nexport function validateBaseURL(value: string): string {\n const url = new URL(value)\n if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) {\n throw new Error('供应商地址必须是 HTTPS,且不能包含用户名、密码、查询参数或片段。')\n }\n return url.href.replace(/\\/+$/, '')\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { useEffect, useId, useRef, useState } from 'react'\nimport { PROVIDER_PRICING_CHECKED, searchProviderInfo } from './provider-info.ts'\nimport {\n WEB_SEARCH_RPC_CHANNEL, pickActiveSearch, resolveSearchOrder,\n type ProviderView, type RpcResult, type WebSettings, type WebStatus,\n} from './contracts.ts'\n\nexport const name = 'dsh-web-search-manager-client'\nexport const inject = ['slots', 'connection', 'remote', 'remote.credentials'] as const\n\ninterface Credentials {\n describe(refs: string[]): Promise<RpcResult<Record<string, { configured: boolean; writable: boolean; source?: string }>>>\n set(ref: string, value: string): Promise<RpcResult<unknown>>\n unset(ref: string): Promise<RpcResult<unknown>>\n}\ninterface Client {\n connection: { rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> } }\n remote: { credentials: Credentials }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; key: string }, render: unknown): () => void\n }\n}\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\nfunction editable(settings: WebSettings): Omit<WebSettings, 'revision'> {\n const { revision: _revision, ...rest } = settings\n return rest\n}\n\nexport function isProviderOn(status: WebStatus, provider: ProviderView): boolean {\n const enabled = provider.kind === 'search' ? status.searchActive : status.fetchActive\n const selected = status.settings[provider.kind === 'search' ? 'searchProvider' : 'fetchProvider']\n return enabled && selected === provider.id\n}\n\nexport function searchBackends(status: WebStatus): ProviderView[] {\n const all = status.providers.filter(provider => provider.kind === 'search')\n const order = resolveSearchOrder(\n all.map(provider => provider.id),\n status.settings,\n id => Boolean(all.find(provider => provider.id === id)?.credentialRef),\n )\n return order.flatMap(id => all.find(provider => provider.id === id) ?? [])\n}\n\nexport function catalogSearchBackends(status: WebStatus): ProviderView[] {\n const enabled = searchBackends(status)\n const rest = status.providers.filter(provider => provider.kind === 'search' && !enabled.some(row => row.id === provider.id))\n return [...enabled, ...rest]\n}\n\nexport function selectedSearchBackend(status: WebStatus): ProviderView | undefined {\n const backends = searchBackends(status)\n const id = pickActiveSearch(backends.map(provider => provider.id), id => Boolean(backends.find(provider => provider.id === id)?.configured))\n return backends.find(provider => provider.id === id)\n}\n\nfunction ExternalLink({ url, label, children }: { url: string; label: string; children: string }) {\n return <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" aria-label={label}\n onClick={event => {\n const bridge = (globalThis as { dshWindow?: { openExternal?(url: string): void } }).dshWindow\n if (bridge?.openExternal) {\n event.preventDefault()\n bridge.openExternal(url)\n }\n }}>{children}</a>\n}\n\nexport function canEnableSearch(\n order: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return order.some(id => {\n const provider = providers.find(item => item.kind === 'search' && item.id === id)\n if (!provider) return false\n if (provider.configured) return true\n const typed = (keys[provider.id] ?? '').trim()\n return Boolean(provider.credentialRef && typed && writable[provider.credentialRef] !== false)\n })\n}\n\nexport function nextSearchEnabled(\n currentlyEnabled: boolean,\n nextOrder: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return currentlyEnabled && canEnableSearch(nextOrder, providers, keys, writable)\n}\n\nfunction ConfirmButton(props: { label: string; confirmLabel: string; disabled?: boolean; onConfirm(): void }) {\n const [armed, setArmed] = useState(false)\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined)\n useEffect(() => () => clearTimeout(timer.current), [])\n function disarm() {\n clearTimeout(timer.current)\n setArmed(false)\n }\n return <button type=\"button\" className=\"web-search-danger\" disabled={props.disabled}\n onClick={() => {\n if (!armed) {\n setArmed(true)\n timer.current = setTimeout(() => setArmed(false), 3000)\n return\n }\n disarm()\n props.onConfirm()\n }}\n onBlur={disarm}>{armed ? props.confirmLabel : props.label}</button>\n}\n\nexport function NetworkSearchSettings({ client }: { client: Client }) {\n const tabsId = useId()\n const [tab, setTab] = useState<'providers' | 'limits'>('providers')\n const [status, setStatus] = useState<WebStatus>()\n const [draft, setDraft] = useState<WebSettings>()\n const [keys, setKeys] = useState<Record<string, string>>({})\n const [busy, setBusy] = useState(false)\n const [dragSource, setDragSource] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<string | null>(null)\n const [sortAnnouncement, setSortAnnouncement] = useState('')\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n const [writable, setWritable] = useState<Record<string, boolean>>({})\n\n async function call<T>(endpoint: string, payload: unknown = {}): Promise<T> {\n return unwrap(await client.connection.rpc.call(WEB_SEARCH_RPC_CHANNEL, endpoint, payload) as RpcResult<T>)\n }\n async function load() {\n const next = await call<WebStatus>('status')\n setStatus(next); setDraft(next.settings)\n const refs = next.providers.flatMap(provider => provider.credentialRef ? [provider.credentialRef] : [])\n if (refs.length) {\n const credentials = unwrap(await client.remote.credentials.describe(refs))\n setWritable(Object.fromEntries(Object.entries(credentials).map(([ref, value]) => [ref, value.writable])))\n }\n return next\n }\n useEffect(() => { void load().catch(() => setError('无法读取网络搜索设置,请检查 Host 连接后重试。')) }, [client])\n\n async function action(run: () => Promise<void>) {\n setBusy(true); setNote(''); setError('')\n try { await run() }\n catch (cause) { setError(cause instanceof Error ? cause.message : '操作失败。'); await load().catch(() => {}) }\n finally { setBusy(false) }\n }\n async function update(settings: Omit<WebSettings, 'revision'>, expectedRevision: number) {\n const next = await call<WebStatus>('update', { settings, expectedRevision })\n setStatus(next); setDraft(next.settings)\n return next\n }\n\n async function persist(on: boolean, order: string[]) {\n if (!status || !draft) return\n for (const provider of status.providers) {\n if (provider.kind !== 'search') continue\n const snapshot = keys[provider.id] ?? ''\n const typed = snapshot.trim()\n if (!provider.credentialRef || !typed) continue\n if (writable[provider.credentialRef] === false) throw new Error('当前凭据为只读,无法写入。')\n unwrap(await client.remote.credentials.set(provider.credentialRef, typed))\n setKeys(current => current[provider.id] === snapshot ? { ...current, [provider.id]: '' } : current)\n }\n const bounded = (key: (typeof limits)[number][0]) => {\n const row = limits.find(item => item[0] === key)!\n return Math.min(row[3], Math.max(row[2], Number.isFinite(draft[key]) ? draft[key] : row[2]))\n }\n await update({\n ...editable(status.settings),\n maxResults: bounded('maxResults'), maxQueries: bounded('maxQueries'),\n timeoutMs: bounded('timeoutMs'), maxFetchChars: bounded('maxFetchChars'),\n endpoints: draft.endpoints, searchOrder: order,\n searchEnabled: on, fetchProvider: 'http', fetchEnabled: on,\n }, status.settings.revision)\n await load()\n }\n\n async function removeKey(provider: ProviderView) {\n if (!provider.credentialRef || provider.credentialShared || !status) return\n unwrap(await client.remote.credentials.unset(provider.credentialRef))\n setKeys(current => ({ ...current, [provider.id]: '' }))\n await load()\n setNote('已删除 Key。')\n }\n\n if (!status || !draft) {\n return <section className=\"web-search-settings\">\n <p role=\"status\">{error || '正在读取设置…'}</p>\n {error ? <button type=\"button\" onClick={() => void action(async () => { await load() })}>重新连接</button> : null}\n </section>\n }\n\n const enabled = searchBackends(status)\n const backends = catalogSearchBackends(status)\n const selected = selectedSearchBackend(status)\n const on = status.settings.searchEnabled\n const order = enabled.map(provider => provider.id)\n const canEnable = canEnableSearch(order, status.providers, keys, writable)\n const limits = [\n ['maxResults', '每条查询的结果上限', 1, 20],\n ['maxQueries', '每次工具调用的查询上限', 1, 5],\n ['timeoutMs', '请求超时(毫秒)', 1000, 120000],\n ['maxFetchChars', '网页正文字符上限', 1000, 200000],\n ] as const\n\n function move(id: string, nextIndex: number) {\n const index = order.indexOf(id)\n if (busy || index < 0 || nextIndex < 0 || nextIndex >= order.length || index === nextIndex) return\n const next = [...order]\n const [item] = next.splice(index, 1)\n next.splice(nextIndex, 0, item)\n void action(async () => {\n await persist(on, next)\n setSortAnnouncement((backends.find(provider => provider.id === id)?.label ?? id) + ' 已移至第 ' + (nextIndex + 1) + ' 位')\n })\n }\n\n function endDrag() {\n setDragSource(null)\n setDropTarget(null)\n }\n\n return <section className=\"web-search-settings\" data-testid=\"web-search-settings\">\n <div className=\"web-search-tabs\" role=\"tablist\" aria-label=\"网络搜索设置\" onKeyDown={event => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return\n const buttons = [...event.currentTarget.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]')]\n const index = buttons.indexOf(event.target as HTMLButtonElement)\n if (index < 0) return\n event.preventDefault()\n const next = event.key === 'Home' ? 0 : event.key === 'End' ? buttons.length - 1\n : (index + (event.key === 'ArrowRight' ? 1 : -1) + buttons.length) % buttons.length\n buttons[next]?.focus()\n buttons[next]?.click()\n }}>\n {([['providers', '搜索服务'], ['limits', '请求限制']] as const).map(([key, label]) => (\n <button key={key} type=\"button\" role=\"tab\" id={tabsId + '-' + key + '-tab'}\n aria-controls={tabsId + '-' + key + '-panel'} aria-selected={tab === key}\n tabIndex={tab === key ? 0 : -1} onClick={() => setTab(key)}>{label}</button>\n ))}\n </div>\n <span className=\"web-search-sr-only\" role=\"status\" aria-live=\"polite\">{sortAnnouncement}</span>\n {error && <p role=\"alert\" className=\"web-search-error\">{error}</p>}\n {note && <p role=\"status\">{note}</p>}\n {status.storageFailed && <p role=\"alert\">配置保存异常,当前运行已暂停网络访问。请重新保存。</p>}\n <div role=\"tabpanel\" id={tabsId + '-providers-panel'} aria-labelledby={tabsId + '-providers-tab'}\n hidden={tab !== 'providers'} tabIndex={0}>\n {backends.length === 0 ? <p className=\"web-search-empty\">还没有可用的搜索后端。</p> : <article\n className=\"web-search-card\"\n data-testid=\"web-search-tool\"\n data-on={on ? 'true' : 'false'}>\n <header>\n <div>\n <h3>联网搜索</h3>\n {!canEnable && <p className=\"web-search-meta\">请选择搜索服务并配置 Key。</p>}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n className={`web-search-switch${on ? ' is-on' : ''}`}\n aria-checked={on}\n aria-label={on ? '关闭联网搜索' : '启用联网搜索'}\n disabled={busy || (!on && !canEnable)}\n onClick={() => void action(() => persist(!on, order))}>\n <span className=\"web-search-switch-thumb\" aria-hidden=\"true\" />\n </button>\n </header>\n <ol className=\"web-search-rank\" aria-label=\"搜索后端\">\n {backends.map(provider => {\n const participating = order.includes(provider.id)\n const rank = order.indexOf(provider.id)\n const active = status.searchActive && selected?.id === provider.id\n const info = searchProviderInfo(provider)\n const needsKey = Boolean(provider.credentialRef)\n const shared = Boolean(provider.credentialShared)\n const showKey = needsKey && participating && (!shared || !provider.configured)\n const canSort = participating && order.length > 1\n return <li key={provider.id} className={active ? 'is-active' : undefined} data-testid={`web-search-rank-${provider.id}`}\n data-dragging={dragSource === provider.id || undefined}\n data-drop={dropTarget === provider.id && dragSource ? (order.indexOf(dragSource) < rank ? 'after' : 'before') : undefined}\n onDragOver={event => {\n if (busy || !canSort || !dragSource || dragSource === provider.id) return\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n setDropTarget(provider.id)\n }}\n onDragLeave={event => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setDropTarget(null)\n }}\n onDrop={event => {\n if (busy || !canSort || !dragSource) return\n event.preventDefault()\n move(dragSource, rank)\n endDrag()\n }}>\n {canSort ? <button type=\"button\" className=\"web-search-drag-handle\"\n draggable={!busy} aria-disabled={busy}\n aria-label={'拖动排序 ' + provider.label}\n title=\"拖动排序,或用上下方向键调整\"\n onDragStart={event => {\n if (busy) { event.preventDefault(); return }\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('application/x-dsh-search-provider', provider.id)\n const row = event.currentTarget.closest('li')\n if (row) event.dataTransfer.setDragImage(row, 16, 16)\n setDragSource(provider.id)\n setSortAnnouncement('')\n }}\n onDragEnd={endDrag}\n onKeyDown={event => {\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n move(provider.id, rank + (event.key === 'ArrowUp' ? -1 : 1))\n }}>\n <svg width=\"16\" height=\"20\" viewBox=\"0 0 16 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" /><circle cx=\"11\" cy=\"5\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" /><circle cx=\"11\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" /><circle cx=\"11\" cy=\"15\" r=\"1.5\" />\n </svg>\n </button> : <span className=\"web-search-rank-index\">{participating ? rank + 1 : '—'}</span>}\n <div className=\"web-search-provider\">\n <div className=\"web-search-provider-heading\">\n <strong>{provider.label}</strong>\n {active && <span className=\"web-search-meta\">当前使用</span>}\n {provider.signupUrl && <ExternalLink url={provider.signupUrl} label={provider.label + ' 去注册'}>去注册</ExternalLink>}\n </div>\n <div className=\"web-search-provider-info\">\n <p>{info.description}</p>\n <details>\n <summary>费用说明</summary>\n <p>{info.pricing}{info.pricingUrl && <> <ExternalLink url={info.pricingUrl}\n label={provider.label + ' 费用说明'}>{provider.id === 'ddg' ? '官网' : '费用说明'}</ExternalLink></>}</p>\n </details>\n </div>\n {participating && !provider.configured && <p className=\"web-search-meta\">{needsKey ? '待配置 Key' : '暂不可用'}</p>}\n {shared && participating && <small>{provider.credentialHint ?? '与其他设置共用凭据'}</small>}\n {showKey ? <label>API Key\n <input type=\"password\" autoComplete=\"off\" spellCheck={false}\n disabled={busy || writable[provider.credentialRef ?? ''] === false}\n value={keys[provider.id] ?? ''}\n placeholder={provider.configured ? '已配置,留空不替换' : '请输入 API Key'}\n onChange={event => setKeys(current => ({ ...current, [provider.id]: event.target.value }))} />\n </label> : null}\n {needsKey && !shared && provider.configured ? <ConfirmButton\n disabled={busy || writable[provider.credentialRef ?? ''] === false}\n label=\"删除 Key\" confirmLabel=\"确认删除 Key?\"\n onConfirm={() => void action(() => removeKey(provider))} /> : null}\n </div>\n <div className=\"web-search-rank-move\">\n <button\n type=\"button\"\n role=\"switch\"\n className={`web-search-switch${participating ? ' is-on' : ''}`}\n aria-checked={participating}\n aria-label={`${participating ? '关闭' : '开启'} ${provider.label}`}\n disabled={busy}\n onClick={() => {\n const next = participating ? order.filter(id => id !== provider.id) : [...order, provider.id]\n void action(() => persist(nextSearchEnabled(status.settings.searchEnabled, next, status.providers, keys, writable), next))\n }}>\n <span className=\"web-search-switch-thumb\" aria-hidden=\"true\" />\n </button>\n </div>\n </li>\n })}\n </ol>\n <p className=\"web-search-meta\">价格核对于 {PROVIDER_PRICING_CHECKED},实际额度与费用以供应商账户为准。</p>\n {on ? <div className=\"web-search-card-actions\">\n <button type=\"button\" disabled={busy} onClick={() => void action(async () => {\n await persist(status.settings.searchEnabled, order)\n const result = await call<{ sources: number }>('test')\n await load()\n setNote(`连接正常,返回 ${result.sources} 条来源。`)\n })}>测试连接(可能计费)</button>\n </div> : null}\n </article>}\n </div>\n <div role=\"tabpanel\" id={tabsId + '-limits-panel'} aria-labelledby={tabsId + '-limits-tab'}\n hidden={tab !== 'limits'} tabIndex={0}>\n <fieldset className=\"web-search-limits\" disabled={busy} aria-label=\"请求限制\">\n {limits.map(([key, label, min, max]) => (\n <label key={key}>{label}\n <input type=\"number\" min={min} max={max} step={1} value={draft[key]}\n onChange={event => setDraft({ ...draft, [key]: Number(event.target.value) })} />\n </label>\n ))}\n </fieldset>\n </div>\n <button type=\"button\" disabled={busy} onClick={() => void action(async () => {\n await persist(status.settings.searchEnabled, order)\n setNote('已保存。')\n })}>保存</button>\n </section>\n}\n\nconst styles = `\n.web-search-settings{max-width:760px;display:grid;gap:24px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}\n.web-search-settings p{margin:0;line-height:1.5}\n.web-search-settings small,.web-search-meta,.web-search-empty{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}\n.web-search-error{color:var(--red-11,#b42318)}\n.web-search-card{display:grid;gap:12px;padding:16px;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:12px}\n.web-search-card header{display:flex;justify-content:space-between;gap:12px;align-items:center;padding-bottom:8px}\n.web-search-card h3{margin:0;font-size:var(--font-size-3,16px);font-weight:600}\n.web-search-provider{display:grid;gap:8px;min-width:0}\n.web-search-provider-info{display:grid;gap:3px;font-size:var(--font-size-1,13px);color:var(--gray-11,inherit);overflow-wrap:anywhere}\n.web-search-provider-heading{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;min-height:24px}\n.web-search-provider-heading strong{font-weight:500}\n.web-search-card label{display:grid;gap:6px}\n.web-search-settings input{box-sizing:border-box;width:100%;min-width:0;padding:8px 10px;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 22%,transparent));border-radius:8px;background:var(--color-surface,transparent);color:inherit;font:inherit;transition:border-color 150ms ease,box-shadow 150ms ease}\n.web-search-settings input:focus{border-color:var(--accent-9,#3b82f6);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-9,#3b82f6) 25%,transparent)}\n.web-search-settings button:not([role=\"switch\"]){min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}\n.web-search-settings button:not([role=\"switch\"]):not([role=\"tab\"]):not(.web-search-drag-handle):hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}\n.web-search-settings button:not([role=\"switch\"]):not([role=\"tab\"]):not(.web-search-drag-handle):active:not(:disabled){transform:scale(.97)}\n.web-search-danger:hover:not(:disabled){border-color:var(--red-11,#b42318);color:var(--red-11,#b42318);background:color-mix(in srgb,var(--red-11,#b42318) 8%,transparent)}\n.web-search-settings button:disabled{opacity:.45;cursor:not-allowed}\n.web-search-tabs{display:flex;gap:20px;border-bottom:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent))}\n.web-search-tabs button[role=\"tab\"]{padding:8px 0;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--gray-11,inherit)}\n.web-search-tabs button[role=\"tab\"]:hover{color:inherit}\n.web-search-tabs button[aria-selected=\"true\"]{border-bottom-color:var(--accent-9,#3b82f6);color:var(--accent-11,inherit);font-weight:600}\n.web-search-settings [role=\"tabpanel\"]{border-radius:12px}\n.web-search-settings .web-search-switch{all:unset;box-sizing:border-box;position:relative;display:inline-block;width:36px;height:20px;flex:none;border-radius:999px;background:var(--gray-7,color-mix(in srgb,currentColor 28%,transparent));cursor:pointer}\n.web-search-switch.is-on{background:var(--accent-9,#3b82f6)}\n.web-search-switch:disabled{cursor:not-allowed;opacity:.7}\n.web-search-switch-thumb{position:absolute;top:3px;left:3px;width:14px;height:14px;border-radius:999px;background:#fff;transition:transform 150ms ease}\n.web-search-switch.is-on .web-search-switch-thumb{transform:translateX(16px)}\n.web-search-settings :focus-visible{outline:2px solid var(--accent-9,currentColor);outline-offset:3px}\n.web-search-card-actions{display:flex;flex-wrap:wrap;gap:8px}\n.web-search-rank{margin:0;padding:0;list-style:none}\n.web-search-rank li{position:relative;display:grid;grid-template-columns:24px minmax(0,1fr) auto;gap:10px;align-items:start;padding:14px 0;border-top:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent))}\n.web-search-settings button.web-search-drag-handle{display:grid;place-items:center;width:24px;height:24px;min-height:24px;padding:0;border:0;cursor:grab;color:inherit;opacity:.65}\n.web-search-settings button.web-search-drag-handle:hover{opacity:1;background:var(--gray-3,color-mix(in srgb,currentColor 8%,transparent))}\n.web-search-settings button.web-search-drag-handle:active{cursor:grabbing}\n.web-search-settings button.web-search-drag-handle[aria-disabled=\"true\"]{cursor:wait;opacity:.4}\n.web-search-rank li[data-dragging]{opacity:.45}\n.web-search-rank li[data-drop]::after{content:'';position:absolute;left:0;right:0;height:2px;background:var(--accent-9,#3b82f6);pointer-events:none}\n.web-search-rank li[data-drop=\"before\"]::after{top:-1px}\n.web-search-rank li[data-drop=\"after\"]::after{bottom:-1px}\n.web-search-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n.web-search-rank-index{opacity:.6;font-variant-numeric:tabular-nums;line-height:24px}\n.web-search-rank-move{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:flex-end;padding-top:2px}\n.web-search-settings a{color:var(--accent-11,currentColor);font-size:var(--font-size-1,13px);text-underline-offset:3px}\n.web-search-limits{margin:0;border:0;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 20px}\n.web-search-limits label{display:grid;gap:6px;font-size:var(--font-size-2,14px)}\n@media(max-width:560px){.web-search-rank-move{flex-direction:column;align-items:flex-end}.web-search-limits{grid-template-columns:minmax(0,1fr)}}\n@media(prefers-reduced-motion:reduce){.web-search-switch-thumb{transition:none}.web-search-settings button:not([role=\"switch\"]),.web-search-settings input{transition:none}}\n`\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', '@klarkxy/dsh-web-search-manager'); style.textContent = styles\n style.dataset.dshWebSearch = ''; document.head.appendChild(style)\n return () => style.remove()\n }, 'web-search-manager.styles')\n ctx.effect(() => client.slots.inject('plugins.bundle.config', () => client.slots.register({\n name: 'plugins.bundle.config', key: '@klarkxy/dsh-web-search-manager',\n }, () => <NetworkSearchSettings client={client} />)), 'web-search-manager.settings')\n}\n"],"mappings":"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"}
package/lib/client.js CHANGED
@@ -676,11 +676,11 @@ function NetworkSearchSettings({ client }) {
676
676
  }),
677
677
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
678
678
  className: "web-search-provider-info",
679
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: info.description }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [info.pricing, info.pricingUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExternalLink, {
679
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: info.description }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "费用说明" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [info.pricing, info.pricingUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExternalLink, {
680
680
  url: info.pricingUrl,
681
681
  label: provider.label + " 费用说明",
682
682
  children: provider.id === "ddg" ? "官网" : "费用说明"
683
- })] })] })]
683
+ })] })] })] })]
684
684
  }),
685
685
  participating && !provider.configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
686
686
  className: "web-search-meta",
@@ -852,11 +852,9 @@ function apply(ctx) {
852
852
  document.head.appendChild(style);
853
853
  return () => style.remove();
854
854
  }, "web-search-manager.styles");
855
- ctx.effect(() => client.slots.inject("settings.section", () => client.slots.register({
856
- name: "settings.section",
857
- id: "web-search",
858
- order: 70,
859
- label: "网络搜索"
855
+ ctx.effect(() => client.slots.inject("plugins.bundle.config", () => client.slots.register({
856
+ name: "plugins.bundle.config",
857
+ key: "@klarkxy/dsh-web-search-manager"
860
858
  }, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NetworkSearchSettings, { client }))), "web-search-manager.settings");
861
859
  }
862
860
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@klarkxy/dsh-web-search-manager",
3
- "version": "0.1.7",
4
- "description": "Manage web search providers and public-page fetching in DeepSeek Harness.",
3
+ "version": "0.1.8",
4
+ "description": "Web Search: manage web search providers and public-page fetching from one settings page.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
7
7
  "engines": {
@@ -31,6 +31,7 @@
31
31
  "./package.json": "./package.json"
32
32
  },
33
33
  "files": [
34
+ "icon.svg",
34
35
  "lib",
35
36
  "cordis.patch.yml",
36
37
  "README.md",
@@ -59,31 +60,59 @@
59
60
  "entries": [
60
61
  {
61
62
  "id": "web-search-manager",
62
- "title": "网络搜索",
63
- "description": "主动授权联网搜索和网页读取,管理搜索供应商",
63
+ "title": "网页搜索",
64
+ "description": "在一个设置页管理搜索服务商和公开页面抓取",
64
65
  "feature": "web-search",
65
66
  "service": "webSearchManager"
66
67
  }
67
68
  ]
68
69
  },
70
+ "scripts": {
71
+ "build": "tsdown && node ../../scripts/editor-plugins/wrap-client.mjs @klarkxy/dsh-web-search-manager",
72
+ "typecheck": "tsc --noEmit -p tsconfig.json",
73
+ "test": "vitest run --root ../.. --config vitest.editor-plugins.config.ts --maxWorkers=2 plugins/dsh-web-search-manager/src"
74
+ },
69
75
  "dependencies": {
70
- "@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2",
71
- "@deepseek-ai/dsh-web-search-deepseek": "0.1.7-rc.2",
72
- "@deepseek-ai/dsh-web-search-exa": "0.1.7-rc.2",
73
- "@deepseek-ai/dsh-web-fetch-http": "0.1.7-rc.2",
76
+ "@deepseek-ai/dsh-web-search-exa": ">=0.1.7-rc.2",
74
77
  "zod": "^4.1.5"
75
78
  },
76
79
  "peerDependencies": {
77
80
  "@deepseek-ai/cordis": "^4.0.4",
78
- "@deepseek-ai/dsh-credentials": "0.1.7-rc.2",
79
- "@deepseek-ai/dsh-web": "0.1.7-rc.2",
80
- "@deepseek-ai/dsh-tool-web": "0.1.7-rc.2"
81
+ "@deepseek-ai/dsh-credentials": ">=0.1.7-rc.2",
82
+ "@deepseek-ai/dsh-storage-domain": ">=0.1.7-rc.2",
83
+ "@deepseek-ai/dsh-tool-web": ">=0.1.7-rc.2",
84
+ "@deepseek-ai/dsh-web": ">=0.1.7-rc.2",
85
+ "@deepseek-ai/dsh-web-fetch-http": ">=0.1.7-rc.2",
86
+ "@deepseek-ai/dsh-web-search-deepseek": ">=0.1.7-rc.2"
87
+ },
88
+ "peerDependenciesMeta": {
89
+ "@deepseek-ai/dsh-credentials": {
90
+ "optional": true
91
+ },
92
+ "@deepseek-ai/dsh-storage-domain": {
93
+ "optional": true
94
+ },
95
+ "@deepseek-ai/dsh-tool-web": {
96
+ "optional": true
97
+ },
98
+ "@deepseek-ai/dsh-web": {
99
+ "optional": true
100
+ },
101
+ "@deepseek-ai/dsh-web-fetch-http": {
102
+ "optional": true
103
+ },
104
+ "@deepseek-ai/dsh-web-search-deepseek": {
105
+ "optional": true
106
+ }
81
107
  },
82
108
  "devDependencies": {
83
109
  "@deepseek-ai/cordis": "^4.0.4",
84
110
  "@deepseek-ai/dsh-credentials": "0.1.7-rc.2",
85
- "@deepseek-ai/dsh-web": "0.1.7-rc.2",
111
+ "@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2",
86
112
  "@deepseek-ai/dsh-tool-web": "0.1.7-rc.2",
113
+ "@deepseek-ai/dsh-web": "0.1.7-rc.2",
114
+ "@deepseek-ai/dsh-web-fetch-http": "0.1.7-rc.2",
115
+ "@deepseek-ai/dsh-web-search-deepseek": "0.1.7-rc.2",
87
116
  "react": "^18.2.0",
88
117
  "@types/react": "18.3.31"
89
118
  },
@@ -100,23 +129,18 @@
100
129
  ],
101
130
  "repository": {
102
131
  "type": "git",
103
- "url": "git+https://github.com/klarkxy/dsh-editor.git",
104
- "directory": "packages/dsh-web-search-manager"
132
+ "url": "git+https://github.com/klarkxy/dsh-plugins.git",
133
+ "directory": "plugins/dsh-web-search-manager"
105
134
  },
106
- "homepage": "https://github.com/klarkxy/dsh-editor/tree/main/packages/dsh-web-search-manager#readme",
135
+ "homepage": "https://klarkxy.github.io/dsh-plugins/plugins/web-search-manager/",
107
136
  "bugs": {
108
- "url": "https://github.com/klarkxy/dsh-editor/issues"
137
+ "url": "https://github.com/klarkxy/dsh-plugins/issues"
109
138
  },
110
139
  "publishConfig": {
111
140
  "access": "public",
112
141
  "registry": "https://registry.npmjs.org/"
113
142
  },
114
143
  "dshRelease": {
115
- "contentHash": "sha256-5b908be3edc69572607bf0211aca943367994405a0c534660fda783fc9eb0219"
116
- },
117
- "scripts": {
118
- "build": "tsdown && node ../../scripts/wrap-client.mjs @klarkxy/dsh-web-search-manager",
119
- "typecheck": "tsc --noEmit -p tsconfig.json",
120
- "test": "vitest run --root ../.. packages/dsh-web-search-manager/src"
144
+ "contentHash": "bf0d3a6c045677e009bf8cec234ef966392afc94b90a5b2e538426b7f1cc5d06"
121
145
  }
122
- }
146
+ }