fix(web): keep default capability search-only
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-31-web-default-search.md
|
||||
2026-07-31-web-default-search.md: f50180a5509e5f3f26500b2e60e7bc3db0aef20b
|
||||
2026-07-31-web-default-search.zh.md: a93c4fa46d3f1b566217a19cc954c364d721d4aa
|
||||
2026-07-31-web-default-search.md: e3e63dbe58049579934902f465cf5599a115da54
|
||||
2026-07-31-web-default-search.zh.md: 2ad4d9d33e6c76fea4cdc15d5afdac20b0466f30
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Agent Note: Default Web search and fetch in the Web/headless composition
|
||||
# Agent Note: Default Web search in the Web/headless composition
|
||||
|
||||
Status: implemented
|
||||
|
||||
@@ -6,17 +6,17 @@ English | [中文](2026-07-31-web-default-search.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The harness had a complete Web capability family—provider registry, DeepSeek/Exa/Perplexity search providers, local fetch, stable model tools, and structured result presentation—but the shipped `dsh web` composition mounted none of it. The model could not discover current information or follow a source URL unless a deployment supplied a custom overlay. Merely mounting the existing DeepSeek provider would not complete the WebUI path: the Models page stores `DEEPSEEK_API_KEY` through `ctx.credentials`, while the search provider froze only the process environment at plugin load, so a key entered or rotated in the running UI would not reach search.
|
||||
The harness had a complete Web capability family—provider registry, DeepSeek/Exa/Perplexity search providers, local fetch, stable model tools, and structured result presentation—but the shipped `dsh web` composition mounted none of it. The model could not discover current information unless a deployment supplied a custom overlay. Merely mounting the existing DeepSeek provider would not complete the WebUI path: the Models page stores `DEEPSEEK_API_KEY` through `ctx.credentials`, while the search provider froze only the process environment at plugin load, so a key entered or rotated in the running UI would not reach search.
|
||||
|
||||
## Decision
|
||||
|
||||
`apps/cli/config/web.cordis.yml` explicitly mounts `dsh-web` with `searchProvider: deepseek-official` and `fetchProvider: local-http`, `dsh-web-search-deepseek`, `dsh-web-fetch-local`, and `dsh-tool-web`. The shared overlay makes `web_search` and `web_fetch` defaults for both browser and headless sessions; the TUI composition remains unchanged. Explicit provider ids keep selection independent of registration order and leave personal or `--config` overlays able to replace or disable the rows.
|
||||
`apps/cli/config/web.cordis.yml` explicitly mounts `dsh-web` with `searchProvider: deepseek-official`, `dsh-web-search-deepseek`, and `dsh-tool-web` with `fetch: false`. It does not mount `dsh-web-fetch-local` or select a fetch provider. The shared overlay makes only `web_search` a default for browser and headless sessions; the TUI composition remains unchanged. The explicit search provider id keeps selection independent of registration order and leaves personal or `--config` overlays able to replace or disable the rows.
|
||||
|
||||
DeepSeek search uses the same `DEEPSEEK_API_KEY` credential reference as the official conversation adapter. The provider resolves that reference inside every search through the optional `ctx.credentials` service; only a composition without the seam falls back to the launching process environment, and a non-empty literal `apiKey` remains the programmatic last resort. A stored or rotated Web Models key therefore reaches the next search without restarting or retaining the value on the provider. Because `WebSearchProvider.available()` is synchronous, it treats an installed resolver as locally usable and missing dynamic credentials fail the operation with the provider-specific `WEB_PROVIDER_CREDENTIAL_MISSING` code while the stable tool schema stays registered.
|
||||
|
||||
Search keeps its endpoint distinct from chat completions: `DEEPSEEK_SEARCH_BASE_URL` overrides the Anthropic-compatible base, while `DEEPSEEK_BASE_URL` continues to configure conversation requests. Each `web_search` performs an auxiliary DeepSeek Messages call with the native search server tool. `web_fetch` uses the existing anonymous local HTTP(S) provider so a search result can be retrieved without another vendor account.
|
||||
Search keeps its endpoint distinct from chat completions: `DEEPSEEK_SEARCH_BASE_URL` overrides the Anthropic-compatible base, while `DEEPSEEK_BASE_URL` continues to configure conversation requests. Each `web_search` performs an auxiliary DeepSeek Messages call with the native search server tool.
|
||||
|
||||
The default mount does not create a Web-specific permission policy. These tools execute outside the bash/filesystem sandbox and approval presets, following `dsh-tool-web`'s existing contract. The shipped deployment already defaults to `danger-full-access`; a future restricted-network product stance must add a `tools/pre-execute` policy or capability-specific network confinement rather than implying that filesystem access mode governs Web calls.
|
||||
The default mount does not create a Web-specific permission policy. `web_search` executes outside the bash/filesystem sandbox and approval presets, following `dsh-tool-web`'s existing contract. It does not mount `web_fetch` or a local fetch provider, so the default does not grant model-selected arbitrary URL retrieval. The shipped deployment already defaults to `danger-full-access`; a future restricted-network product stance must add a `tools/pre-execute` policy or capability-specific network confinement rather than implying that filesystem access mode governs Web calls.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
@@ -28,8 +28,8 @@ The default mount does not create a Web-specific permission policy. These tools
|
||||
|
||||
**Mount Web tools in `base.cordis.yml`.** Rejected because that would also change the TUI deployment. The browser and headless entries already share `web.cordis.yml`; they gain the capability together while TUI remains an explicit later decision.
|
||||
|
||||
**Enable search without fetch.** Rejected because search snippets are discovery context, not page bodies, and the stable search guidance directs the model to fetch a relevant result before relying on its full content.
|
||||
**Enable search and fetch together.** Rejected because default `web_fetch` would allow model-selected anonymous outbound HTTP(S) retrieval to arbitrary URLs. Search covers discovery; deployments that accept broader retrieval can opt into `dsh-web-fetch-local` and set `dsh-tool-web`'s `fetch` option to `true` in their overlay.
|
||||
|
||||
## Consequences
|
||||
|
||||
Web/headless model requests carry the `web_search` and `web_fetch` schemas plus their fixed prompt guidance in native mode; Code Mode exposes the same capabilities beneath `run_code`. Search adds a complete auxiliary model call and may use the native server tool multiple times, while fetch adds anonymous outbound HTTP(S) access subject to the local provider's redirect, size, timeout, and content-type rules. The Web snapshot lane boots the shipped tree, drives a replayed `web_search` call through the real DeepSeek provider against a local Messages fixture, asserts the durable structured result, and pins the settled browser presentation. Provider tests pin missing, stored, and rotated credential behavior plus literal and ambient compatibility.
|
||||
Web/headless model requests carry only the `web_search` schema and its fixed prompt guidance in native mode; Code Mode exposes the same search capability beneath `run_code`. Search adds a complete auxiliary model call and may use the native server tool multiple times. The default offers search-result snippets and source metadata but no arbitrary page retrieval; deployments that need full-page fetch must opt in. The Web snapshot lane boots the shipped tree, drives a replayed `web_search` call through the real DeepSeek provider against a local Messages fixture, asserts the durable structured result, and pins the settled browser presentation. The real-composition smoke test pins the absence of `web_fetch`; provider tests pin missing, stored, and rotated credential behavior plus literal and ambient compatibility.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Agent Note: Web/无头组合中的默认 Web 搜索与抓取
|
||||
# Agent Note: Web/无头组合中的默认 Web 搜索
|
||||
|
||||
Status: implemented
|
||||
|
||||
@@ -6,17 +6,17 @@ Status: implemented
|
||||
|
||||
## 问题
|
||||
|
||||
该 harness 已具备完整的 Web 能力体系:提供方注册表、DeepSeek、Exa 和 Perplexity 搜索提供方、本地抓取、稳定的面向模型工具,以及结构化结果呈现,但已交付的 `dsh web` 组合没有挂载其中任何一项。除非部署提供自定义覆盖层,否则模型无法发现最新信息,也无法沿来源 URL 读取内容。仅挂载现有 DeepSeek 提供方仍无法打通 WebUI 链路:Models 页面通过 `ctx.credentials` 存储 `DEEPSEEK_API_KEY`,而搜索提供方只会在插件加载时固定读取进程环境,因此在运行中的 UI 输入或轮换的密钥无法用于搜索。
|
||||
该 harness 已具备完整的 Web 能力体系:提供方注册表、DeepSeek、Exa 和 Perplexity 搜索提供方、本地抓取、稳定的面向模型工具,以及结构化结果呈现,但已交付的 `dsh web` 组合没有挂载其中任何一项。除非部署提供自定义覆盖层,否则模型无法发现最新信息。仅挂载现有 DeepSeek 提供方仍无法打通 WebUI 链路:Models 页面通过 `ctx.credentials` 存储 `DEEPSEEK_API_KEY`,而搜索提供方只会在插件加载时固定读取进程环境,因此在运行中的 UI 输入或轮换的密钥无法用于搜索。
|
||||
|
||||
## 决策
|
||||
|
||||
`apps/cli/config/web.cordis.yml` 明确挂载 `dsh-web`,并配置 `searchProvider: deepseek-official` 与 `fetchProvider: local-http`,同时挂载 `dsh-web-search-deepseek`、`dsh-web-fetch-local` 和 `dsh-tool-web`。共享覆盖层使 `web_search` 和 `web_fetch` 成为浏览器与无头会话的默认工具;TUI 组合保持不变。显式提供方 id 使选择不受注册顺序影响,同时个人覆盖层或 `--config` 覆盖层仍可替换或禁用这些配置项。
|
||||
`apps/cli/config/web.cordis.yml` 明确挂载 `dsh-web`,配置 `searchProvider: deepseek-official`,同时挂载 `dsh-web-search-deepseek`,并以 `fetch: false` 挂载 `dsh-tool-web`。它不挂载 `dsh-web-fetch-local`,也不选择抓取提供方。共享覆盖层只将 `web_search` 设为浏览器与无头会话的默认工具;TUI 组合保持不变。显式搜索提供方 id 使选择不受注册顺序影响,同时个人覆盖层或 `--config` 覆盖层仍可替换或禁用这些配置项。
|
||||
|
||||
DeepSeek 搜索使用与官方会话适配器相同的 `DEEPSEEK_API_KEY` 凭据引用。提供方在每次搜索内部通过可选的 `ctx.credentials` 服务解析该引用;只有未挂载该 seam 的组合才会回退到启动进程的环境变量,非空的 `apiKey` 字面值仍作为程序化配置的最后兜底。因此,由 Web 的 Models 页存储或轮换的密钥无需重启即可用于下一次搜索,提供方也无需保留该值。由于 `WebSearchProvider.available()` 是同步方法,它会将已安装解析器视为本地可用;若动态凭据缺失,操作会以提供方专属错误码 `WEB_PROVIDER_CREDENTIAL_MISSING` 失败,而稳定的工具 schema 仍保持注册。
|
||||
|
||||
搜索端点与 chat completions 保持独立:`DEEPSEEK_SEARCH_BASE_URL` 覆盖 Anthropic 兼容基址,`DEEPSEEK_BASE_URL` 则继续配置会话请求。每次 `web_search` 都会发起一次辅助 DeepSeek Messages 调用,并携带原生搜索服务器工具。`web_fetch` 使用现有的匿名本地 HTTP(S) 提供方,因此无需其他厂商账号即可获取搜索结果。
|
||||
搜索端点与 chat completions 保持独立:`DEEPSEEK_SEARCH_BASE_URL` 覆盖 Anthropic 兼容基址,`DEEPSEEK_BASE_URL` 则继续配置会话请求。每次 `web_search` 都会发起一次辅助 DeepSeek Messages 调用,并携带原生搜索服务器工具。
|
||||
|
||||
默认挂载不会创建 Web 专用权限策略。这些工具在 bash/文件系统沙箱及审批预设之外执行,并遵循 `dsh-tool-web` 的现有契约。已交付部署的默认值本就是 `danger-full-access`;未来如果产品采取受限网络策略,必须添加 `tools/pre-execute` 策略或按能力限制网络访问,而不能暗示文件系统访问模式会管辖 Web 调用。
|
||||
默认挂载不会创建 Web 专用权限策略。`web_search` 在 bash/文件系统沙箱及审批预设之外执行,并遵循 `dsh-tool-web` 的现有契约。组合不挂载 `web_fetch` 或本地抓取提供方,因此默认配置不会允许模型自行选择任意 URL 进行抓取。已交付部署的默认值本就是 `danger-full-access`;未来如果产品采取受限网络策略,必须添加 `tools/pre-execute` 策略或按能力限制网络访问,而不能暗示文件系统访问模式会管辖 Web 调用。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
@@ -28,8 +28,8 @@ DeepSeek 搜索使用与官方会话适配器相同的 `DEEPSEEK_API_KEY` 凭据
|
||||
|
||||
**在 `base.cordis.yml` 中挂载 Web 工具。** 不予采纳:这也会改变 TUI 部署。浏览器与无头入口已经共享 `web.cordis.yml`;两者会一同获得该能力,是否为 TUI 启用则仍留作后续显式决策。
|
||||
|
||||
**启用搜索但不启用抓取。** 不予采纳:搜索 snippet 是用于发现内容的上下文,而不是页面正文;稳定的搜索指引会要求模型先抓取相关结果,再依赖其完整内容。
|
||||
**同时启用搜索和抓取。** 不予采纳:默认启用 `web_fetch` 会允许模型自行选择任意 URL,执行匿名出站 HTTP(S) 抓取。搜索负责发现信息;接受更广泛抓取范围的部署可以在覆盖层中选择启用 `dsh-web-fetch-local`,并将 `dsh-tool-web` 的 `fetch` 选项设为 `true`。
|
||||
|
||||
## 后果
|
||||
|
||||
Web/无头模型请求在原生模式下会携带 `web_search` 和 `web_fetch` schema 及其固定提示词指引;Code Mode 通过 `run_code` 公开相同能力。搜索会增加一次完整的辅助模型调用,并可能多次使用原生服务器工具;抓取会增加匿名出站 HTTP(S) 访问,并受本地提供方的重定向、大小、超时和内容类型规则约束。Web 快照通道会启动已交付配置树,使用本地 Messages fixture(测试前置数据),经由真实 DeepSeek 提供方驱动一次回放的 `web_search` 调用,断言持久化的结构化结果,并固定最终浏览器呈现。提供方测试固定缺失、已存储及已轮换凭据的行为,以及字面值与环境变量的兼容性。
|
||||
Web/无头模型请求在原生模式下只会携带 `web_search` schema 及其固定提示词指引;Code Mode 通过 `run_code` 公开相同的搜索能力。搜索会增加一次完整的辅助模型调用,并可能多次使用原生服务器工具。默认配置会提供搜索结果 snippet 与来源元数据,但不支持任意页面抓取;需要抓取完整页面的部署必须自行选择启用抓取。Web 快照通道会启动已交付配置树,使用本地 Messages fixture(测试前置数据),经由真实 DeepSeek 提供方驱动一次回放的 `web_search` 调用,断言持久化的结构化结果,并固定最终浏览器呈现。真实组合冒烟测试固定了不提供 `web_fetch` 这一事实;提供方测试固定缺失、已存储及已轮换凭据的行为,以及字面值与环境变量的兼容性。
|
||||
|
||||
Reference in New Issue
Block a user