@deepseek-ai/dsh-tool-web 0.0.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, DeepSeek
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,6 @@
1
+ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
+ # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
+ # after editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/web/tool-web/README.md
5
+ README.md: 643da4e2f083c2efabd39a462290559ddbd291c8
6
+ README.zh.md: 7b52f2b08f393a584258dea1a216d9124ec8760a
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # @deepseek-ai/dsh-tool-web
2
+
3
+ English | [中文](README.zh.md)
4
+
5
+ The model-facing web tool suite — `web_search` and `web_fetch` — over the [web capability seam](../web/README.md) (`ctx.web`). It owns model-facing concerns only: tool names, JSON schemas, snake_case argument names, prompt sections, the result-count bound, result formatting, HTML→markdown presentation, and the UI presentation projection — `presentCall`, `presentResult` (a `card: 'web'` result card discriminated by `kind: 'search' | 'fetch'`), and the `output.presentationMeta` that carries the structured search sources or the fetch summary the lossy render text cannot (see the [web-result-card Agent Note](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card.md)). All web access goes through `ctx.web`; this package never imports a concrete provider. Neither tool exposes a model-facing timeout — each tool's cooperative tool-call budget is declared here via config (`fetchTimeoutMs`/`searchTimeoutMs`, attached as `ToolDefinition.timeoutMs`) and enforced by [`@deepseek-ai/dsh-timeout-policy`](../../guard/timeout-policy/README.md) (a `tools/execute` wrapper); each tool just forwards `exec.signal` to the seam.
6
+
7
+ Each tool is registered independently; a product that wants only one disables the other via config (`{ search: false }` / `{ fetch: false }`). Search guidance mentions `web_fetch` only when fetch is also config-enabled; a search-only composition instead tells the model to use returned snippets and cite their URLs.
8
+
9
+ ## Tools
10
+
11
+ | Tool | Args | Behavior |
12
+ |---|---|---|
13
+ | `web_search` | `query` (string) | Discovery. Returns an optional answer plus source URLs. `max_results` is **not** model-facing — the tool sets the bound (the `searchMaxResults` config, default 8) and passes it to the seam. |
14
+ | `web_fetch` | `url` (string) | Retrieves a specific URL. HTML bodies are rendered to markdown (turndown with GFM tables/strikethrough); text bodies pass through. A non-2xx status is reported, not an error. The tool-call timeout is deployment policy (`dsh-timeout-policy`), not a model argument. |
15
+
16
+ Both tools opt into concurrent scheduling because provider reads return content without mutating parent-agent state.
17
+
18
+ The normalized service results are also the canonical tool values: `WebSearchResult` and `WebFetchResult`. Native renderers preserve the answer/source and fetched-body text below; provider search/body caps remain acquisition limits rather than presentation-only truncation.
19
+
20
+ ## Config
21
+
22
+ | Key | Default | Meaning |
23
+ |---|---|---|
24
+ | `search` | `true` | Register `web_search`. |
25
+ | `fetch` | `true` | Register `web_fetch`. |
26
+ | `searchMaxResults` | `8` | Upper bound on sources returned by one `web_search` call (the seam truncates a longer provider list and flags it). |
27
+ | `fetchTimeoutMs` | `30000` | Cooperative tool-call timeout budget (ms) for `web_fetch`. |
28
+ | `searchTimeoutMs` | `30000` | Cooperative tool-call timeout budget (ms) for `web_search`. |
29
+ | `fetchMaxOutputChars` | `200000` | Cap on source characters converted synchronously and on one complete `web_fetch` output (header, rendered body, and footer); a cut body gets the truncation notice when it fits. |
30
+
31
+ `fetchTimeoutMs`/`searchTimeoutMs` declare each tool's cooperative timeout budget (attached as `ToolDefinition.timeoutMs`), enforced by [`@deepseek-ai/dsh-timeout-policy`](../../guard/timeout-policy/README.md); the model-facing schema exposes no timeout argument. `fetchMaxOutputChars` bounds both synchronous conversion work and the complete rendered result: only that many source characters are converted, and the header, converted prefix, and truncation notice are then capped together. The default leaves headroom above the local provider's 100,000-character body cap, but rendered expansion can still make the final bound truncate the result.
32
+
33
+ ```yaml
34
+ - id: tool-web
35
+ name: '@deepseek-ai/dsh-tool-web'
36
+ ```
37
+
38
+ ## Stable registration
39
+
40
+ Tool registration follows product **enablement**, not backend availability. A tool stays visible even when its selected provider is missing, misconfigured, ambiguous, or temporarily unavailable; the seam resolves the provider at execution time and execution fails with a structured `WebError` (e.g. `WEB_PROVIDER_UNAVAILABLE`, `WEB_PROVIDER_AMBIGUOUS`), which `ToolRegistry.execute()` turns into an error tool result the model can read and hooks/UI can route on. This keeps the model schema stable without making plugin load order, credential state, or HMR timing part of the model-facing contract. To remove a web tool entirely, disable it here in config.
41
+
42
+ The tool never calls a provider's `available()` and never enumerates providers — its only execution path is `ctx.web.search()` / `ctx.web.fetch()`, and provider unavailability reaches it as the structured `WebError` codes selection throws at execution time. Provider selection stays entirely inside the seam, with one owner.
43
+
44
+ ## Model Experience
45
+
46
+ ### System prompt
47
+
48
+ #### What the model sees
49
+
50
+ Search and fetch contribute the web-search and web-fetch guidance below. Search chooses its fetch-enabled or search-only text from config at registration time. A scoped tool restriction does not remove these independently registered sections.
51
+
52
+ ##### Web search guidance with fetch enabled
53
+
54
+ ```markdown
55
+ Use the web_search tool to discover current information on the web. It returns an optional answer plus a list of source URLs. Follow up with web_fetch when you need the full content of a specific result, and cite the relevant URLs as markdown links.
56
+ ```
57
+
58
+ ##### Web search-only guidance
59
+
60
+ ```markdown
61
+ Use the web_search tool to discover current information on the web. It returns an optional answer plus a list of source URLs. Use the returned source snippets when available, and cite the relevant URLs as markdown links.
62
+ ```
63
+
64
+ ##### Web fetch guidance
65
+
66
+ ```markdown
67
+ Use the web_fetch tool to retrieve the content of a specific HTTP(S) URL (for example a result from web_search). It returns the page content decoded to text. Cite the URL as a markdown link when you use its content.
68
+ ```
69
+
70
+ #### Token effect
71
+
72
+ Fixed guidance cost per request for each config-enabled tool, even when a restriction hides its schema. Toggling fetch changes the search guidance as well as registering or removing the fetch section.
73
+
74
+ #### KV Cache effect
75
+
76
+ Prefix-stable while enabled tools, scope, and guidance text are unchanged. Config enablement—including toggling fetch's search-guidance branch—or plugin lifecycle may invalidate reuse from the first changed prompt section; scoped schema restrictions do not remove it.
77
+
78
+ ### Tool schemas
79
+
80
+ #### What the model sees
81
+
82
+ The model sees the generated [`web_search` and `web_fetch` schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-web). Result-count and timeout budgets are deployment settings, not model arguments.
83
+
84
+ #### Token effect
85
+
86
+ Fixed schema cost per request; config disablement removes both schema and guidance, while a scoped restriction removes only the schema.
87
+
88
+ #### KV Cache effect
89
+
90
+ Prefix-stable while definitions and visibility are unchanged. Config enablement, plugin lifecycle, or scoped restrictions may invalidate reuse from the first changed schema token.
91
+
92
+ ### Search result
93
+
94
+ #### What the model sees
95
+
96
+ The optional provider-owned answer is followed by `Sources:` and data-dependent lines shaped exactly `- [<title-or-url>](<url>)`, optionally suffixed ` — <snippet> (<publishedAt>)`. With neither answer nor sources the result says `No results found.` A capped list adds `(Showing the first <count> sources. Refine the query for more.)`; every result ends `Cite the relevant URLs above as markdown links in your answer.`
97
+
98
+ #### Token effect
99
+
100
+ Data-dependent results are resent until compaction and sources are capped by `searchMaxResults`.
101
+
102
+ #### KV Cache effect
103
+
104
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
105
+
106
+ ### Fetch result
107
+
108
+ #### What the model sees
109
+
110
+ A successful fetch is exactly `Fetched <finalUrl> (HTTP <statusCode>)`, a blank line, and the provider-owned decoded body. Truncation adds a blank line and `(Content truncated. Fetch a more specific URL or section for the full text.)`; failures become `Error: <message>`. Queries and URLs remain in call history.
111
+
112
+ #### Token effect
113
+
114
+ Provider caps bound body size; retained call arguments and results are resent until compaction, and timeout policy can replace a late result with a short error.
115
+
116
+ #### KV Cache effect
117
+
118
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
119
+
120
+ ### Argument errors
121
+
122
+ #### What the model sees
123
+
124
+ Blank inputs become exactly `Error: query must be a non-empty string` or `Error: url must be a non-empty string`.
125
+
126
+ #### Token effect
127
+
128
+ Only the failing call adds these retained tokens.
129
+
130
+ #### KV Cache effect
131
+
132
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
133
+
134
+ ## Known Limitations and Deferred Work
135
+
136
+ - **HTML→markdown conversion degrades on inputs GFM cannot safely represent** — [turndown](https://github.com/mixmark-io/turndown) (with GFM tables/strikethrough) converts at most `fetchMaxOutputChars` source characters through a real DOM. A conservative 512-level lexical guard passes deeply or ambiguously nested bodies through as raw HTML, conversion exceptions do the same, and table `colspan` is ignored because GFM has no spanning-cell representation; these bounds avoid blocking the event loop or expanding output from an untrusted numeric attribute ([archived dependency decision](../../../.agents/notes/archived/simplification/2026-07-26-turndown-for-tool-web-html-markdown.md)).
137
+ - **The model-facing surface is minimal by design, with promotions deferred** — `max_results` stays a config bound (not a model argument), and `web_fetch` takes only `url` (no `format`/`prompt`/LLM-summarization mode); both are named later steps in [the seam Agent Note](../../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md).
138
+ - **No web-specific permission policy** — both tools execute without requesting `ctx.approval`; a deployment that needs confirmation must add a `tools/pre-execute` policy, and the package does not define persistent URL/domain grants.
package/README.zh.md ADDED
@@ -0,0 +1,138 @@
1
+ # @deepseek-ai/dsh-tool-web
2
+
3
+ [English](README.md) | 中文
4
+
5
+ 面向模型的 web 工具套件 `web_search` 与 `web_fetch`,构建于 [web 能力 seam](../web/README.md)(`ctx.web`)之上。它只负责面向模型的事项:工具名称、JSON Schema、snake_case 参数名称、提示词区段、结果数量上限、结果格式、HTML→markdown 呈现,以及 UI 呈现投影——`presentCall`、`presentResult`(以 `kind: 'search' | 'fetch'` 区分的 `card: 'web'` 结果卡片),以及承载有损渲染文本无法携带的结构化搜索来源或抓取摘要的 `output.presentationMeta`(见 [web-result-card Agent Note](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card.md))。所有 web 访问都通过 `ctx.web`;该包绝不导入具体提供方。两个工具都不公开面向模型的超时:每个工具的协作式工具调用超时预算通过配置在此声明(`fetchTimeoutMs`/`searchTimeoutMs`,附加为 `ToolDefinition.timeoutMs`),由 [`@deepseek-ai/dsh-timeout-policy`](../../guard/timeout-policy/README.md)(`tools/execute` 包装层)强制执行;每个工具只把 `exec.signal` 转发给 seam。
6
+
7
+ 每个工具独立注册;只需要其中一个工具的产品可以通过配置禁用另一个(`{ search: false }`/`{ fetch: false }`)。仅当抓取也通过配置启用时,搜索指引才会提及 `web_fetch`;仅启用搜索的组合则会要求模型使用返回的 snippet 并引用其 URL。
8
+
9
+ ## 工具
10
+
11
+ | 工具 | 参数 | 行为 |
12
+ |---|---|---|
13
+ | `web_search` | `query`(string) | 用于发现信息。返回可选答案与来源 URL。`max_results` **不**面向模型:工具设置上限(`searchMaxResults` 配置,默认 8)并传给 seam。 |
14
+ | `web_fetch` | `url`(string) | 获取特定 URL。HTML 主体渲染为 markdown(turndown,带 GFM 表格/删除线);文本主体原样通过。非 2xx 状态会报告,而非报错。工具调用超时是部署策略(`dsh-timeout-policy`),不是模型参数。 |
15
+
16
+ 两个工具都选择并发调度,因为提供方读取会返回内容,不会修改父 agent(智能体)的状态。
17
+
18
+ 规范化后的服务结果也是标准工具值:`WebSearchResult` 与 `WebFetchResult`。原生渲染器会保留下文所述的答案、来源和抓取正文文本;提供方对搜索结果数量和正文大小的上限仍属于获取限制,而非仅用于呈现的截断。
19
+
20
+ ## 配置
21
+
22
+ | 配置键 | 默认值 | 含义 |
23
+ |---|---|---|
24
+ | `search` | `true` | 注册 `web_search`。 |
25
+ | `fetch` | `true` | 注册 `web_fetch`。 |
26
+ | `searchMaxResults` | `8` | 一次 `web_search` 调用返回的来源数量上限(seam 截断更长的提供方列表并标记)。 |
27
+ | `fetchTimeoutMs` | `30000` | `web_fetch` 的协作式工具调用超时预算(ms)。 |
28
+ | `searchTimeoutMs` | `30000` | `web_search` 的协作式工具调用超时预算(ms)。 |
29
+ | `fetchMaxOutputChars` | `200000` | 同步转换的源字符数与单次完整 `web_fetch` 输出的上限(状态头、渲染后的主体与页脚合并计算);主体被截断时,在能容纳的情况下附带截断提示。 |
30
+
31
+ `fetchTimeoutMs`/`searchTimeoutMs` 声明每个工具的协作式超时预算(附加为 `ToolDefinition.timeoutMs`),由 [`@deepseek-ai/dsh-timeout-policy`](../../guard/timeout-policy/README.md) 强制执行;面向模型的 schema 不公开超时参数。`fetchMaxOutputChars` 同时限制同步转换工作量和完整渲染结果:只转换至多该数量的源字符,随后对状态头、转换后的前缀和截断提示合并设限。默认值为本地提供方的 100,000 字符主体上限留出余量,但渲染膨胀仍可能使最终上限截断结果。
32
+
33
+ ```yaml
34
+ - id: tool-web
35
+ name: '@deepseek-ai/dsh-tool-web'
36
+ ```
37
+
38
+ ## 稳定注册
39
+
40
+ 工具注册遵循产品**启用状态**,而非后端可用性。即使选中的提供方缺失、错误配置、存在歧义或暂时不可用,工具仍保持可见;seam 在执行时解析提供方,执行以结构化 `WebError`(例如 `WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`)失败,`ToolRegistry.execute()` 会把它转为模型可读、钩子/UI 可路由的错误工具结果。这样无需把插件加载顺序、凭据状态或 HMR(热模块替换)时机纳入面向模型约定,也能保持模型 schema 稳定。要彻底移除 web 工具,请在此处通过配置将其禁用。
41
+
42
+ 工具绝不会调用提供方的 `available()`,也不会枚举提供方;唯一执行路径是 `ctx.web.search()`/`ctx.web.fetch()`,提供方不可用时,选择机制会在执行阶段抛出结构化 `WebError`,其错误码由工具接收。提供方选择完全留在 seam 内,由单一主体负责。
43
+
44
+ ## 模型体验
45
+
46
+ ### 系统提示词
47
+
48
+ #### 模型看到的内容
49
+
50
+ 搜索与抓取分别贡献以下 web-search 和 web-fetch 指引。搜索会在注册时根据配置选用启用抓取或仅搜索的文本。scope 工具限制不会移除这些独立注册的区段。
51
+
52
+ ##### 启用抓取时的 Web 搜索指引
53
+
54
+ ```markdown
55
+ Use the web_search tool to discover current information on the web. It returns an optional answer plus a list of source URLs. Follow up with web_fetch when you need the full content of a specific result, and cite the relevant URLs as markdown links.
56
+ ```
57
+
58
+ ##### 仅搜索时的 Web 搜索指引
59
+
60
+ ```markdown
61
+ Use the web_search tool to discover current information on the web. It returns an optional answer plus a list of source URLs. Use the returned source snippets when available, and cite the relevant URLs as markdown links.
62
+ ```
63
+
64
+ ##### Web 抓取指引
65
+
66
+ ```markdown
67
+ Use the web_fetch tool to retrieve the content of a specific HTTP(S) URL (for example a result from web_search). It returns the page content decoded to text. Cite the URL as a markdown link when you use its content.
68
+ ```
69
+
70
+ #### Token 影响
71
+
72
+ 每个通过配置启用的工具都会为每次请求增加固定的指引 token 开销,即使限制隐藏了其 schema。切换抓取状态不仅会注册或移除抓取区段,也会更改搜索指引。
73
+
74
+ #### KV Cache 影响
75
+
76
+ 只要启用工具、scope 与指引文本不变,前缀就保持稳定。配置启用状态(包括因切换抓取状态而改变搜索指引分支)或插件生命周期可能使从第一个变化的提示词区段起的复用失效;scope schema 限制不会移除该区段。
77
+
78
+ ### 工具 schema
79
+
80
+ #### 模型看到的内容
81
+
82
+ 模型会看到生成的 [`web_search` 与 `web_fetch` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-web)。结果数量与超时预算属于部署设置,不是模型参数。
83
+
84
+ #### Token 影响
85
+
86
+ 每次请求都会产生固定的 schema token 开销;通过配置禁用会同时移除 schema 与指引,scope 限制只移除 schema。
87
+
88
+ #### KV Cache 影响
89
+
90
+ 只要定义与可见性不变,前缀就保持稳定。配置启用状态、插件生命周期或 scope 限制可能使从第一个变化的 schema token 起的复用失效。
91
+
92
+ ### 搜索结果
93
+
94
+ #### 模型看到的内容
95
+
96
+ 可选的提供方答案之后是 `Sources:`,再跟随内容取决于数据且格式严格为 `- [<title-or-url>](<url>)` 的行,并可添加后缀 ` — <snippet> (<publishedAt>)`。既无答案也无来源时,结果显示 `No results found.`。列表达到上限时会添加 `(Showing the first <count> sources. Refine the query for more.)`;每个结果都以 `Cite the relevant URLs above as markdown links in your answer.` 结尾。
97
+
98
+ #### Token 影响
99
+
100
+ 数据相关结果会重复发送直到压缩(compaction),来源数量由 `searchMaxResults` 限制。
101
+
102
+ #### KV Cache 影响
103
+
104
+ 仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
105
+
106
+ ### 抓取结果
107
+
108
+ #### 模型看到的内容
109
+
110
+ 成功抓取的精确形状是 `Fetched <finalUrl> (HTTP <statusCode>)`、一个空行,以及由提供方返回的已解码正文。发生截断时会再添加一个空行和 `(Content truncated. Fetch a more specific URL or section for the full text.)`;失败变为 `Error: <message>`。查询与 URL 保留在调用历史中。
111
+
112
+ #### Token 影响
113
+
114
+ 提供方上限限制主体大小;保留的调用参数与结果会重复发送直到压缩,超时策略可以把迟到结果替换为简短错误。
115
+
116
+ #### KV Cache 影响
117
+
118
+ 仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
119
+
120
+ ### 参数错误
121
+
122
+ #### 模型看到的内容
123
+
124
+ 空输入精确地变为 `Error: query must be a non-empty string` 或 `Error: url must be a non-empty string`。
125
+
126
+ #### Token 影响
127
+
128
+ 只有失败调用会增加这些保留 token。
129
+
130
+ #### KV Cache 影响
131
+
132
+ 仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
133
+
134
+ ## 已知限制与暂缓事项
135
+
136
+ - **HTML→markdown 转换会在 GFM 无法安全表示的输入上降级**:[turndown](https://github.com/mixmark-io/turndown)(带 GFM 表格/删除线)通过真实 DOM 转换至多 `fetchMaxOutputChars` 个源字符。保守的 512 层词法守卫会将深层或嵌套有歧义的主体作为原始 HTML 直接透传,转换异常也会如此处理;表格的 `colspan` 会被忽略,因为 GFM 无法表示跨列单元格。这些限制可避免阻塞事件循环,也避免不受信任的数值属性使输出膨胀([已归档的依赖决策](../../../.agents/notes/archived/simplification/2026-07-26-turndown-for-tool-web-html-markdown.md))。
137
+ - **面向模型的接口有意保持精简,后续扩展暂缓**:`max_results` 保持为配置上限(不是模型参数),`web_fetch` 只接受 `url`(没有 `format`/`prompt`/LLM(大语言模型)摘要模式);两项都列为 [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md) 中的后续步骤。
138
+ - **没有 web 专用权限策略**:两个工具都不会请求 `ctx.approval` 就直接执行;需要确认的部署必须添加 `tools/pre-execute` 策略,该包不定义持久化的 URL/域名授权。