Compare commits

...
Author SHA1 Message Date
imccyu 687f282e86 Merge pull request #6408 from deepseek-harness/worktree/release-dsh-0.2.1-rc.2
release: next version [email protected]
2026-10-17 15:22:43 +08:00
imccyu d1b9c04067 release(dsh): 0.2.1-rc.2 2026-10-17 15:10:31 +08:00
Yudong HanandLegGasai fda98dadd2 feat(web): add DeepSeek Search and Fetch APIs behind a settings switch (#6103)
* fix(web-search-deepseek): disable thinking for auxiliary search requests

The provider discards the generated text of the auxiliary Messages turn,
so reasoning tokens have no consumer. DeepSeek enables thinking by default,
which adds latency and output tokens to every search.

Fixes #6099.

* feat(web): add opt-in traditional Search and Fetch APIs

* test(web): verify API settings persistence and refresh Session evidence

* fix(web): require an explicit Search API base with its route prefix

* docs(web): document direct Search and Fetch API decisions

* fix(web): keep Messages search default behind the new Web Search API switch

- Rename useTraditionalApi/traditionalBaseURL to useSearchApi/searchApiBaseURL and
  label the switch "Use the new Web Search API"; Messages search stays the default.
- Default the Search / Fetch API base to https://api.deepseek.com/v1/tools.
- Authenticate the Search API with an API key only: DeepSeek Account tokens
  returned an empty HTTP 404 on /v1/tools/* when probed on 2026-10-16.
- Remove the count setting, which tool-web's maxResults always overrides, and
  the undocumented DeepSeek-API-Version header.
- Name the active API's base URL field and the current settings path in
  endpoint guidance; re-record the endpoint guidance Session.
- Keep WebFetchResult.statusCode required: DeepSeek Fetch reports HTTP 200 and
  drops the page title, so the fetch-metadata widening and its upgrade guide
  are removed.

* fix(web): accept account sign-in on the live Search API

The public Search and Fetch routes went live on 2026-10-16 and accept the
DeepSeek Account token, so account-route Sessions send it to the Search API
as they do for Messages search, and the settings copy no longer says account
sign-in does not apply.

Record the live behavior in the README and Agent Note: summaries of
1,000-2,300 characters, an HTTP 500 for an unresolvable Fetch target, and
migration notes for gateways without /v1/tools routes. Test doubles now use
the live response fields and RFC 3339 offsets.

* feat(web): configure Search API result count and send the triggering question

- Add web-search-deepseek.count (1-50, default 10, the service default) and
  show it as "Results per search" in Search API mode, where "Max searches per
  request" applies only to Messages; a smaller request maxResults still wins.
- Send the initiating Session's latest human prompt as ori_question, with
  whitespace collapsed and cut to the API's 128-character limit; blank or
  absent prompts omit it, and sendOriginalQuestion: false disables it. The
  settings hint states that the question is sent.
- Match the web search double on the request's query field, since
  ori_question now carries every query in the prompt.

* fix(client): unify web search endpoint override controls

* feat(web): configure registered search and fetch providers through shared settings

* feat(web): include Exa and Perplexity in provider settings

* test(web): cover provider settings branches and refresh plugin snapshots

* revert(web): drop the provider dropdown, schema-driven form, and Exa/Perplexity settings

Revert aed8c5cb609, d88c47dcd80, and 036a5a337d3. The Web search settings
page returns to the DeepSeek toggle; the DeepSeek Search and Fetch API split
is reintroduced as one plugin in the following commit.

* feat(web): move the DeepSeek Search and Fetch APIs into web-deepseek-api

The new web-deepseek-api plugin registers deepseek-search-api and
deepseek-fetch-api over one credential and API base, and exports the
authentication and redirect-rejecting transport that web-search-deepseek now
reuses for Messages search only. The web service reads searchProvider and
fetchProvider for each operation, so the Web search settings switch selects
both APIs together on save and restores Messages search with local HTTP fetch
when turned off. The switch hint links to the DeepSeek search and fetch guide.

* refactor(client): keep the web search endpoint fields on the shared override controls

Drop the always-visible reset and the inherited-address placeholder from the
Web search page, restoring ui-primitives to its base. Each endpoint field shows
the selected section's effective value and offers Reset to default only for an
override, like every other settings field.

* refactor(web): keep Messages search independent of web-deepseek-api

Restore dsh-web-search-deepseek to its own credential and transport code,
keeping only the disabled-thinking request and the current settings guidance,
so the Messages plugin no longer depends on the Search and Fetch API package.
dsh-web-deepseek-api keeps its transport internal; the regions that repeat the
Messages helpers carry jscpd:ignore markers, with the rationale recorded in the
Search and Fetch API Agent Note.

* refactor(web): keep the web-deepseek-api request type module-private

---------

Co-authored-by: LegGasai <[email protected]>
2026-10-17 15:08:08 +08:00
Yichen Jiang ca15fe4f17 Merge pull request #6417 from deepseek-harness/worktree/deepseek-flash-1017-badge
feat(web): replace the DeepSeek Flash suffix with a temporary badge
2026-10-17 13:54:15 +08:00
Yichen Jiang 3c937cd0ba feat(web): display a temporary 1017 badge for DeepSeek Flash 2026-10-17 13:33:35 +08:00
Yichen Jiang 32efe36a4e revert: restore the bundled DeepSeek Flash display name 2026-10-17 13:23:06 +08:00
Yichen Jiang c6acc07232 Merge pull request #6406 from deepseek-harness/worktree/deepseek-flash-1017
fix(llm): append 1017 to the bundled DeepSeek Flash display name
2026-10-17 09:23:32 +08:00
Yichen Jiang 9404cd1790 Merge branch 'master' into worktree/deepseek-flash-1017 2026-10-17 09:13:01 +08:00
Yichen Jiang 7d844abc87 fix(llm): append 1017 to the bundled DeepSeek Flash display name 2026-10-17 09:06:36 +08:00
456 changed files with 4927 additions and 851 deletions

No files matched your search

@@ -18,8 +18,8 @@
en: b432f80a424c3e49
zh: faa26925fdd98387
/agent-note-web-capability-seam-stable-tools-over-multiple-providers/provider-availability-and-selection:
en: dff78c46432311a1
zh: 58d5db4c3c85b886
en: 4e4ec068c2a22383
zh: b7030d0f00bfdb74
/agent-note-web-capability-seam-stable-tools-over-multiple-providers/search-request-and-result-schema:
en: ec3703b7e7c6b23d
zh: 325755e6e90092da
@@ -60,6 +60,7 @@ flowchart LR
exa["@deepseek-ai/dsh-web-search-exa"] -->|registerSearchProvider| web["@deepseek-ai/dsh-web / ctx.web"]
perplexity["@deepseek-ai/dsh-web-search-perplexity"] -->|registerSearchProvider| web
deepseek["@deepseek-ai/dsh-web-search-deepseek"] -->|registerSearchProvider| web
deepseekApi["@deepseek-ai/dsh-web-deepseek-api"] -->|registerSearchProvider / registerFetchProvider| web
fetchLocal["@deepseek-ai/dsh-web-fetch-http"] -->|registerFetchProvider| web
toolWeb["@deepseek-ai/dsh-tool-web"] -->|search/fetch| web
toolWeb -->|ctx.tools.register| webSearch["tool: web_search"]
@@ -151,6 +152,8 @@ The "single provider auto-selects" rule is for tests, demos, and simple deployme
Operational overrides feed the same explicit selection path: `DSH_WEB_SEARCH_PROVIDER=perplexity` is equivalent to config `searchProvider: perplexity`, not a hidden priority chain inside `dsh-tool-web`.
Each search or fetch reads the configured id when it runs, so a saved settings change selects another provider for the next operation without remounting `dsh-web`. The Web search settings switch relies on this to move both capabilities to the [DeepSeek Search and Fetch APIs](../feature/2026-10-15-deepseek-search-fetch-api.md) at once.
`ctx.web.search()` and `ctx.web.fetch()` resolve the provider at execution time using the selection rules above. If the selected capability is unavailable, they throw `WebError` with a structured code such as `WEB_PROVIDER_UNAVAILABLE`, `WEB_PROVIDER_CONFIGURED_MISSING`, `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`, or `WEB_PROVIDER_AMBIGUOUS`. If no provider is explicitly configured and no usable provider exists, the execution error is the generic `WEB_PROVIDER_UNAVAILABLE` case; there is deliberately no diagnostic summary of every unavailable provider.
## Search request and result schema
@@ -60,6 +60,7 @@ flowchart LR
exa["@deepseek-ai/dsh-web-search-exa"] -->|registerSearchProvider| web["@deepseek-ai/dsh-web / ctx.web"]
perplexity["@deepseek-ai/dsh-web-search-perplexity"] -->|registerSearchProvider| web
deepseek["@deepseek-ai/dsh-web-search-deepseek"] -->|registerSearchProvider| web
deepseekApi["@deepseek-ai/dsh-web-deepseek-api"] -->|registerSearchProvider / registerFetchProvider| web
fetchLocal["@deepseek-ai/dsh-web-fetch-http"] -->|registerFetchProvider| web
toolWeb["@deepseek-ai/dsh-tool-web"] -->|search/fetch| web
toolWeb -->|ctx.tools.register| webSearch["tool: web_search"]
@@ -151,6 +152,8 @@ interface WebRuntime {
运维覆盖走同一条显式选择路径:`DSH_WEB_SEARCH_PROVIDER=perplexity` 等同于配置 `searchProvider: perplexity`,而非 `dsh-tool-web` 内部的隐式优先级链。
每次搜索或抓取在执行时读取配置的 id,因此保存的设置变更无需重新挂载 `dsh-web` 即对下一次操作选择另一个提供方。网页搜索设置页的开关借此把两种能力同时切换到 [DeepSeek Search 与 Fetch API](../feature/2026-10-15-deepseek-search-fetch-api.zh.md)。
`ctx.web.search()` 和 `ctx.web.fetch()` 在执行时按上述选择规则解析提供方。如果选定的能力不可用,它们抛出带有结构化代码的 `WebError`,如 `WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE` 或 `WEB_PROVIDER_AMBIGUOUS`。如果未显式配置提供方且不存在可用提供方,执行错误是通用的 `WEB_PROVIDER_UNAVAILABLE` 情况;刻意不提供对每个不可用提供方的诊断汇总。
## 搜索请求与结果 schema
@@ -0,0 +1,37 @@
# Bilingual-pair consistency record for 2026-10-15-deepseek-search-fetch-api.md (docs/i18n/README.md): per heading
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
# After editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-10-15-deepseek-search-fetch-api.md
/agent-note-direct-deepseek-search-and-fetch-apis:
en: fb19be7e7fc65810
zh: 865aaed5b7f802cc
/agent-note-direct-deepseek-search-and-fetch-apis/problem:
en: d1aad580a4db9872
zh: 1eb3bac59353291d
/agent-note-direct-deepseek-search-and-fetch-apis/decision:
en: e70efbb3aa9d53b6
zh: 1d25eae2461346df
/agent-note-direct-deepseek-search-and-fetch-apis/decision/protocol-selection-and-deployment:
en: ec653b59d62ed95f
zh: 0d675616059930ba
/agent-note-direct-deepseek-search-and-fetch-apis/decision/search-results-and-model-input:
en: a95618f172ef63ee
zh: 306556be09c56bdf
/agent-note-direct-deepseek-search-and-fetch-apis/decision/fetch-metadata-and-ownership:
en: 8051417b08739ed0
zh: c11d35a346014436
/agent-note-direct-deepseek-search-and-fetch-apis/decision/default-migration:
en: d5a8e36b545f1c04
zh: d741fd0789401c62
/agent-note-direct-deepseek-search-and-fetch-apis/decision/supplementary-messages-fix:
en: 738e32b488bbc1a1
zh: f33afe570f62599a
/agent-note-direct-deepseek-search-and-fetch-apis/alternatives-considered:
en: 641cbfefc76f2f95
zh: e3e718473eace85f
/agent-note-direct-deepseek-search-and-fetch-apis/consequences:
en: a55da02f4d3c06c0
zh: 3c1a624f03f34f28
/agent-note-direct-deepseek-search-and-fetch-apis/verification-and-remaining-api-adoption:
en: 41f9a331c7aca397
zh: 17a0fd53e133c2f5
@@ -0,0 +1,84 @@
# Agent Note: Direct DeepSeek Search and Fetch APIs
Status: implemented
English | [中文](2026-10-15-deepseek-search-fetch-api.zh.md)
## Problem
DeepSeek web retrieval through Messages requires an auxiliary model request for each query. Harness extracts sources and citation excerpts but discards the generated answer. The dedicated Search and Fetch APIs provide structured sources and Markdown directly, so retrieval can run without Harness starting that auxiliary generation. Adopting these APIs requires explicit selection of both operations, independent deployment addresses, and a mapping of Fetch results onto the existing fetch result.
## Decision
The [DeepSeek Search and Fetch guide](https://api-docs.deepseek.com/zh-cn/guides/search), checked on 2026-10-16, defines the upstream API. The [web-deepseek-api plugin](../../../../packages/web/web-deepseek-api/README.md) implements it behind the existing `web_search` and `web_fetch` tools, and [web-search-deepseek](../../../../packages/web/web-search-deepseek/README.md) keeps Messages search. The [web capability decision](../architecture/2026-06-24-web-capability-seam.md) continues to own provider selection, tool responsibilities, and the fetch result fields.
### Protocol selection and deployment
The APIs register as `deepseek-search-api` and `deepseek-fetch-api`; Messages search keeps `deepseek-official`. The setting **Use the new Web Search API** (**启用新版 Web 搜索 API**) on the Web search page writes `web.searchProvider` and `web.fetchProvider` together: on selects both APIs, and off restores Messages search with local HTTP fetch, the shipped selection. The switch defaults off and takes effect after saving, because the web service reads both selections for each operation. Messages remains the default until the Search API launch is announced, so existing users keep working search without configuration. Each operation resolves one settings snapshot, including its endpoint and credentials. Both APIs read one credential and one API base, because the guide serves them from one base and the switch selects them together.
The two protocols retain independent API bases. Messages keeps `https://api.deepseek.com/anthropic/v1` and appends `/messages`. Direct retrieval uses `web-deepseek-api.baseURL`, which defaults to the guide's public base `https://api.deepseek.com/v1/tools`, and appends `/search` or `/fetch`; the verified development base is `http://api-dev.deepseek.com:8031/api/v1/tools`. These prefixes are different and are never inferred from the hostname, so another deployment enters its complete base. The switch is already the explicit opt-in, so the documented public deployment serves as its default. A blank or unparseable base leaves both providers unavailable.
The guide specifies API-key Bearer authentication, and requests send only the documented authorization and JSON content type. A Session on the DeepSeek account route sends its account token instead, as Messages search does; the public Search and Fetch routes accepted it on 2026-10-16, so account-only users can enable direct retrieval. An Anthropic-compatible gateway checked the same day served Messages web search and had no `/v1/tools` routes; such deployments keep Messages search.
### Search results and model input
Direct Search sends `query`, `count`, `need_content: false`, and `ori_question`. `count` is the configured value from 1 to 50, defaulting to the service's 10, unless the request's result bound is smaller; the tool always sends its limit, 8 by default. `ori_question` is the text of the initiating Session's latest human prompt with whitespace collapsed and cut to the API's 128-character limit. The API rejects blank or longer values, so a search without such a prompt omits the field, and `sendOriginalQuestion: false` disables it. In 2026-10-16 probes, different values left result order, scores, and summaries unchanged. Queries pass through unchanged, including the documented site, language, date, exclusion, and exact-phrase operators. The service enforces the 1–128 Unicode-character query constraint. Empty `results` is successful.
The provider preserves service order and maps URL, title, `snippet`, and nullable `date` into shared sources. The current tool gives the same short excerpt to the model and search card. It does not consume `summary`, full `content`, `site_name`, `site_icon`, `rerank_score`, or `authority`, and it does not send `localization`. Those omissions are integration limits, not absent API capabilities.
Direct retrieval emits no auxiliary model-request event because Harness makes no such request. The normal tool-call and tool-result events retain the query and model-visible result. This says nothing about the search service's internal use of models. Returned text remains external, untrusted data.
### Fetch metadata and ownership
Fetch sends a URL and returns Markdown without an extra Harness summarization request. The API supplies neither a final redirected URL nor a target HTTP status, and the shared result has no title field. The provider keeps the requested URL, returns the Markdown body, and reports HTTP 200 for a successful response: the Fetch API answers 404 when the URL is unavailable, blocked by site policy, or returns an error, or when no Markdown can be extracted. On 2026-10-16 an unresolvable host returned HTTP 500 instead, so every non-success status is a retrieval failure rather than a specific target diagnosis. The shared fetch result and its consumers stay unchanged.
The HTTP provider retains its own public-address validation, connection pinning, and resource limits. Selecting DeepSeek delegates page retrieval and target access policy to that service; Harness rejects redirects of the API request and retains cancellation and bounded tool output. The reported HTTP 200 therefore means the service retrieved the page, not that Harness observed the target response. The guide's Fetch 403 means crawler-policy rejection, while 404 means no usable page content.
### Default migration
Changing the default to the Search API is a separate change after the launch is announced. API keys and account tokens both reach the public routes; deployments behind a gateway without `/v1/tools` routes need an explicit `web.searchProvider: deepseek-official` before the default changes, and a stored Messages selection keeps Messages.
### Supplementary Messages fix
The retained Messages path explicitly sends `thinking: { type: 'disabled' }` and records that same body before dispatch. This avoids reasoning work in an auxiliary request whose generated answer is discarded; it does not implement or control the new retrieval API. `tool_choice` remains omitted. The [persistence acknowledgement](../../../../docs/persistence-changes/2026-10-13-deepseek-search-thinking.md) owns compatibility for the optional logged field.
## Alternatives considered
**Keep Messages as the only search implementation.** It preserves auxiliary generation and response extraction even when callers need only sources. Direct Search removes that Harness model request while retaining Messages as an explicit mode.
**Make the Search API the default now.** The launch is not announced, and some gateways expose only Messages; their users would lose working search.
**Reuse the Messages address or infer a route prefix.** The protocols and deployed prefixes differ. Separate bases preserve existing configurations and avoid sending a valid request to the wrong route.
**Require an explicit Search API base.** Enabling the switch is already an explicit choice, and an empty default would make every user copy the documented public address. Other deployments still override it.
**Keep the APIs inside the Messages provider behind a provider-local switch.** A switch inside `web-search-deepseek` cannot change fetch routing, so turning it on left `web_fetch` on HTTP unless the user also edited `web.fetchProvider`; it also tied the APIs' lifecycle to Messages search, which the default migration may retire. Separate registrations let the web service's existing selection express the switch, and each package can change or retire alone.
**Share one transport between Messages search and the new APIs.** Both resolve credentials through the same seams, `ctx.credentials` and `ctx.deepseekAccount`, so a shared module would save only the dispatch and failure-mapping code. It would make the Messages package depend on the new API package and tie their releases, while the default migration may retire Messages search. Each package keeps its own transport until then.
**Split Search and Fetch into separate packages.** The guide serves both APIs from one base with one credential, and the switch selects them together; separate packages would duplicate the settings a user edits once. Each operation lives in its own module, so either API can change without the other.
**List every registered provider in a settings dropdown.** A generic provider form derives editors from Config schemas and needs host-side display metadata on the provider interfaces. The page needs only the DeepSeek choice, and other providers keep their own settings pages.
**Let the model supply `ori_question` as a tool argument.** The API defines the field as the user's original question, which the latest human prompt already records. A tool argument would change the model-facing schema shared by every search provider and invite paraphrase.
**Keep HTTP fetch when the switch turns on.** The switch adopts the new DeepSeek retrieval APIs, and leaving fetch on HTTP made Fetch API adoption depend on a hand-edited `web.fetchProvider`. HTTP fetch, with its own access policy, remains the selection whenever the switch is off, and configuration can still select either fetch provider alone.
**Add an extraction tool or widen the fetch result.** The API retrieves one concrete web page as Markdown, which fits the existing fetch operation. Its success already implies a retrieved page, and the Markdown body carries the page heading, so widening the result would change every fetch consumer for little model-visible gain.
## Consequences
Retrieval no longer requires auxiliary model tokens in direct mode, but its results still consume the main model's context. One Messages web search through a gateway on 2026-10-16 consumed 8,154 input and 828 output tokens for a single server-side search. The guide prices Search and Fetch independently at CNY 5 per 1,000 successful requests with results; result count does not change a request's price. Multiple queries remain multiple requests. The stated Claude Code and Codex promotion does not establish a Harness exemption. Search API mode also sends up to 128 characters of the user's prompt to the search service with each query unless `sendOriginalQuestion` is off.
Search and Fetch each have an account-wide 5 QPS limit, independent of model concurrency and shared across that account's API keys. Fetch also has a target-domain limit. The current tool can issue four queries concurrently and fails the batch if one query fails. The provider has no shared rate scheduler, automatic retries, or fallback; other Sessions or processes can exhaust the same account allowance.
## Verification and remaining API adoption
Provider tests cover request mapping, empty results, malformed responses, independent and default bases, account-token authentication, cancellation, and blank configuration. Settings tests and the [plugin configuration browser scenario](../../../../apps/web/tests/plugin-config.e2e.ts) cover staged saves, the default base, and switching both selections. The [web search replay](../../../../apps/web/tests/web-search-round.e2e.ts) and [Fetch Session replay](../../../../snapshots/session/deepseek-fetch/snapshot.yml) pin model-visible results. On 2026-10-16 the [real provider tests](../../../../packages/web/web-deepseek-api/tests/web-deepseek-api.e2e.ts) passed Search and Fetch against the public base, and a headless round on the shipped profile returned eight sources and fetched Markdown without an auxiliary request event. The account-token, gateway, and status observations above come from manual probes the same day.
The following capabilities remain outside the implemented integration:
- Separate model-facing `summary` from display `snippet`, with per-source and total output budgets and matching Session records. The guide's typical summary length is not a maximum: returned summaries measured 1,000–2,300 characters on 2026-10-16.
- Expose search syntax in provider-appropriate tool guidance and define a bounded localization input before forwarding it. API `localization` is an IP address, not an inferred city or UI language.
- Retain quality metadata before defining selection policies. `rerank_score` and `authority` describe service assessments, not guarantees of truth; a hard cutoff can discard useful niche sources.
- Add cancellation-aware scheduling and bounded retry ownership. The guide recommends waiting before retrying 408, 429, and 5xx; 402 requires funding first, and other 4xx require a changed request. Local pacing cannot enforce an account-wide quota across unrelated processes.
@@ -0,0 +1,84 @@
# Agent Note: 直接接入 DeepSeek Search 与 Fetch API
Status: implemented
[English](2026-10-15-deepseek-search-fetch-api.md) | 中文
## 问题
通过 Messages 获取 DeepSeek 网页搜索结果时,每个查询都需要一次辅助模型请求。Harness 提取来源与引用摘录,却丢弃生成的回答。独立 Search 和 Fetch API 直接提供结构化来源与 Markdown,使检索无需由 Harness 发起这次辅助生成。接入这些 API 需要明确选择两种操作的提供方、独立配置部署地址,并把 Fetch 结果映射到现有抓取结果。
## 决策
2026-10-16 核对的 [DeepSeek Search 与 Fetch 指南](https://api-docs.deepseek.com/zh-cn/guides/search)定义上游 API。[web-deepseek-api 插件](../../../../packages/web/web-deepseek-api/README.zh.md)通过现有 `web_search` 和 `web_fetch` 工具接入它,[web-search-deepseek](../../../../packages/web/web-search-deepseek/README.zh.md) 保留 Messages 搜索。[Web 能力决策](../architecture/2026-06-24-web-capability-seam.zh.md)继续负责提供方选择、工具职责和抓取结果字段。
### 协议选择与部署
两个 API 注册为 `deepseek-search-api` 和 `deepseek-fetch-api`;Messages 搜索保留 `deepseek-official`。网页搜索页上的设置 **Use the new Web Search API**(**启用新版 Web 搜索 API**)同时写入 `web.searchProvider` 和 `web.fetchProvider`:开启时选择两个 API,关闭时恢复内置选择,即 Messages 搜索与本地 HTTP 抓取。开关默认关闭,保存后生效,因为 Web 服务在每次操作时读取两项选择。在 Search API 正式发布公告之前,Messages 仍是默认值,已有用户无需配置即可继续使用搜索。每次操作解析一份设置快照,包含端点和凭据。两个 API 读取同一份凭据和同一个 API 基础地址,因为指南从同一基础地址提供它们,开关也同时选择它们。
两种协议分别保存 API 基础地址。Messages 保留 `https://api.deepseek.com/anthropic/v1`,追加 `/messages`。直接检索使用 `web-deepseek-api.baseURL`,默认值为指南中的公网地址 `https://api.deepseek.com/v1/tools`,追加 `/search` 或 `/fetch`;已验证的开发地址为 `http://api-dev.deepseek.com:8031/api/v1/tools`。两者前缀不同,程序不会根据主机名推断,其他部署需填写完整基础地址。开关本身已是显式启用,因此以文档中的公网部署作为默认值。基础地址为空白或无法解析时,两个提供方都不可用。
指南规定使用 API 密钥进行 Bearer 鉴权,请求只发送文档规定的鉴权与 JSON 内容类型请求头。DeepSeek 账号路由上的会话改为发送其账号 token,与 Messages 搜索一致;2026-10-16 公网 Search 与 Fetch 路由已接受该 token,因此只登录账号的用户也可以启用直接检索。同日检查的一个 Anthropic 兼容网关提供 Messages 网页搜索,但没有 `/v1/tools` 路由;此类部署继续使用 Messages 搜索。
### 搜索结果与模型输入
直接 Search 发送 `query`、`count`、`need_content: false` 和 `ori_question`。`count` 为 1 至 50 的配置值,默认采用服务的 10;请求的结果上限更小时以后者为准,工具总会发送其上限,默认为 8。`ori_question` 是发起会话中最近一条用户提示的文本,空白折叠后截取至 API 的 128 个字符上限。API 拒绝空白或更长的值,因此没有此类提示的搜索不发送该字段,`sendOriginalQuestion: false` 可将其关闭。2026-10-16 的探测中,不同取值未改变结果顺序、评分或摘要。查询原样传递,包括文档中的站点、语言、日期、排除和精确短语操作符。服务端执行查询长度为 1–128 个 Unicode 字符的约束。空 `results` 表示成功。
提供方保留服务端顺序,将 URL、标题、`snippet` 和可为 null 的 `date` 映射为共享来源。当前工具将同一段短摘要提供给模型和搜索卡片。它不使用 `summary`、完整 `content`、`site_name`、`site_icon`、`rerank_score` 或 `authority`,也不发送 `localization`。这些是当前接入的限制,并非 API 缺少这些能力。
直接检索不产生辅助模型请求事件,因为 Harness 没有发起该请求。普通工具调用与工具结果事件继续保留查询及模型可见的结果。这不代表搜索服务内部不使用模型。返回文本仍是外部不受信任的数据。
### 抓取元数据与职责
Fetch 发送 URL,返回 Markdown,无需 Harness 额外发起摘要请求。API 既不提供重定向后的最终 URL,也不提供目标 HTTP 状态,而共享结果没有标题字段。提供方保留请求 URL,返回 Markdown 正文,并对成功响应报告 HTTP 200:URL 不可用、被站点策略拦截、目标站点返回错误或无法提取 Markdown 时,Fetch API 会返回 404。2026-10-16 无法解析的主机实际返回 HTTP 500,因此任何非成功状态都视为抓取失败,而不是对目标的具体诊断。共享抓取结果及其消费方保持不变。
HTTP 提供方继续负责自身的公开地址校验、连接固定和资源限制。选择 DeepSeek 会将页面抓取与目标访问策略交给该服务;Harness 拒绝 API 请求重定向,并保留取消与工具输出限额。因此报告的 HTTP 200 表示服务已获取页面,而不是 Harness 观察到了目标响应。指南中的 Fetch 403 表示抓取器策略拒绝,404 则表示没有可用的页面内容。
### 默认值迁移
将默认值改为 Search API 是发布公告之后的另一项变更。API 密钥和账号 token 都能访问公网路由;位于没有 `/v1/tools` 路由的网关之后的部署,需要在默认值变更前显式设置 `web.searchProvider: deepseek-official`,已保存的 Messages 选择仍使用 Messages。
### 附带的 Messages 修复
保留的 Messages 路径显式发送 `thinking: { type: 'disabled' }`,并在发送前记录同一请求体。这避免了辅助请求在生成回答被丢弃的情况下执行思考;它不实现或控制新的检索 API。`tool_choice` 仍不传递。[持久化确认记录](../../../../docs/persistence-changes/2026-10-13-deepseek-search-thinking.zh.md)负责日志中可选字段的兼容性。
## 考虑过的替代方案
**仅保留 Messages 搜索实现。** 即使调用方只需要来源,这也保留了辅助生成和响应提取。直接 Search 去掉这次 Harness 模型请求,同时保留 Messages 供显式选择。
**立即将 Search API 设为默认值。** 尚未发布公告,部分网关也只提供 Messages;这些用户会失去可用的搜索。
**复用 Messages 地址或推断路由前缀。** 协议与部署前缀不同。分别保存基础地址可保留现有配置,避免把有效请求发往错误路由。
**要求显式填写 Search API 基础地址。** 开启开关已是显式选择,空默认值会迫使每位用户复制文档中的公网地址。其他部署仍可覆盖它。
**把两个 API 放在 Messages 提供方内部,由提供方自己的开关切换。** `web-search-deepseek` 内的开关无法改变抓取路由,因此开启后除非用户另外修改 `web.fetchProvider`,`web_fetch` 仍走 HTTP;它还把两个 API 的生命周期绑在 Messages 搜索上,而默认值迁移后 Messages 搜索可能被移除。独立注册让 Web 服务现有的选择来表达这个开关,每个包都可以单独修改或移除。
**让 Messages 搜索与新 API 共用一套传输层。** 两者都通过同样的 seam,即 `ctx.credentials` 和 `ctx.deepseekAccount` 解析凭据,共享模块只能省下请求派发与失败映射代码。它会让 Messages 包依赖新 API 包、两者必须一起发版,而默认值迁移后 Messages 搜索可能被移除。在此之前,两个包各自保留传输层。
**把 Search 和 Fetch 拆成两个包。** 指南从同一基础地址、以同一份凭据提供两个 API,开关也同时选择它们;拆成两个包会让用户只需编辑一次的设置重复出现。每种操作位于独立模块,任一 API 都可以单独修改。
**在设置页用下拉框列出所有已注册的提供方。** 通用提供方表单从 Config schema 推导编辑控件,还需要在提供方接口上增加宿主侧展示元数据。该页面只需要 DeepSeek 的选择,其他提供方保留各自的设置页。
**让模型以工具参数提供 `ori_question`。** API 将该字段定义为用户的原始问题,而最近一条用户提示已记录了这段文本。工具参数会改变所有搜索提供方共用的面向模型的 schema,并引入改写。
**开启开关时保留 HTTP 抓取。** 该开关用于启用 DeepSeek 新的检索 API,保留 HTTP 抓取会让使用 Fetch API 依赖手动修改 `web.fetchProvider`。开关关闭时,抓取仍选择带有自身访问策略的 HTTP 提供方,配置中也仍可单独选择任一抓取提供方。
**新增提取工具或扩展抓取结果。** API 以 Markdown 获取一个具体网页,符合现有抓取操作。其成功本身即表示已获取页面,Markdown 正文也带有页面标题,因此扩展结果会改动每个抓取消费方,而模型可见的收益很小。
## 影响
直接模式中的检索不再需要辅助模型 token,但结果仍消耗主模型上下文。2026-10-16 通过网关进行的一次 Messages 网页搜索,为一次服务端搜索消耗了 8,154 个输入 token 和 828 个输出 token。指南对 Search 和 Fetch 分别按每 1,000 次成功且有结果的请求收取 5 元;结果条数不影响单次价格。多个查询仍对应多次请求。文档中的 Claude Code 与 Codex 优惠不能作为 Harness 免收费用的依据。除非关闭 `sendOriginalQuestion`,Search API 模式还会随每个查询把用户提示的至多 128 个字符发送给搜索服务。
Search 和 Fetch 各有账号级 5 QPS 限制,独立于模型并发,同一账号的 API 密钥共享额度。Fetch 还有目标域名限制。当前工具可并发发送四个查询,任一查询失败会使整批失败。提供方没有共享限速调度器、自动重试或回退;其他会话或进程也会消耗同一账号的额度。
## 验证与尚未接入的 API 能力
提供方测试覆盖请求映射、空结果、格式错误的响应、独立地址与默认地址、账号 token 鉴权、取消与空白配置。设置测试及[插件配置浏览器场景](../../../../apps/web/tests/plugin-config.e2e.ts)覆盖暂存后保存、默认地址和同时切换两项选择。[网页搜索回放](../../../../apps/web/tests/web-search-round.e2e.ts)与 [Fetch Session 回放](../../../../snapshots/session/deepseek-fetch/snapshot.yml)固定模型可见结果。2026-10-16,[真实提供方测试](../../../../packages/web/web-deepseek-api/tests/web-deepseek-api.e2e.ts)在公网地址通过了 Search 与 Fetch 验证;在内置配置上运行的一轮 headless 对话返回了八个来源并抓取到 Markdown,且没有辅助请求事件。上文的账号 token、网关和状态码观察来自同日的手动探测。
以下能力尚未包含在已实现的接入中:
- 区分面向模型的 `summary` 与用于展示的 `snippet`,设置每个来源和总输出限额,并记录对应的 Session 内容。指南中的典型摘要长度不是最大值:2026-10-16 实测返回的摘要为 1,000–2,300 个字符。
- 在适用于提供方的工具说明中介绍搜索语法,先定义有界的本地化输入,再进行转发。API 的 `localization` 是 IP 地址,不能用推测的城市或界面语言代替。
- 先保留质量元数据,再定义筛选策略。`rerank_score` 与 `authority` 表示服务端评估,不保证内容真实;固定阈值可能丢弃有用的冷门来源。
- 增加支持取消的调度并明确有限重试的职责。指南建议对 408、429 和 5xx 等待后重试;402 需要先充值,其他 4xx 需要修改请求。本地节流无法跨无关进程执行账号级配额。
+3
View File
@@ -180,6 +180,8 @@ flowchart LR
cfg --> plugin_dsh_base_web
plugin_dsh_base_web_search_deepseek["web-search-deepseek<br/>@deepseek-ai/dsh-web-search-deepseek"]
cfg --> plugin_dsh_base_web_search_deepseek
plugin_dsh_base_web_deepseek_api["web-deepseek-api<br/>@deepseek-ai/dsh-web-deepseek-api"]
cfg --> plugin_dsh_base_web_deepseek_api
plugin_dsh_base_web_fetch_http["web-fetch-http<br/>@deepseek-ai/dsh-web-fetch-http"]
cfg --> plugin_dsh_base_web_fetch_http
plugin_dsh_base_tool_web["tool-web<br/>@deepseek-ai/dsh-tool-web"]
@@ -288,6 +290,7 @@ flowchart LR
| `repeat-tool-reminder` | `@deepseek-ai/dsh-repeat-tool-reminder` |
| `web` | `@deepseek-ai/dsh-web` |
| `web-search-deepseek` | `@deepseek-ai/dsh-web-search-deepseek` |
| `web-deepseek-api` | `@deepseek-ai/dsh-web-deepseek-api` |
| `web-fetch-http` | `@deepseek-ai/dsh-web-fetch-http` |
| `tool-web` | `@deepseek-ai/dsh-tool-web` |
| `mcp-resources` | `@deepseek-ai/dsh-mcp-resources` |
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh",
"description": "dsh CLI: profile launch, plugin management, and configuration inspection",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-desktop-host",
"description": "Private Node-mode host process for the Electron desktop application",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"private": true,
"license": "MIT",
"type": "module",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-desktop",
"description": "Electron desktop shell for a bundled dsh runtime and external plugins",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"private": true,
"license": "MIT",
"type": "module",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-plugin-market-generator",
"description": "Reference generator of plugin market index files from a list of npm packages and Git repositories",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"private": true,
"type": "module",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-web-frontend",
"description": "Web application entry: vite build over the @deepseek-ai/dsh-client-web shell library; dist/ served by apps/cli's dsh web",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -0,0 +1,107 @@
/** The shipped browser plugin decorates both DeepSeek routes without changing catalog identity. */
import { fileURLToPath } from 'node:url'
import { chromium, type Browser, type Page } from 'playwright'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import {
captureStableAria, compareOrRefreshGolden, launchWebScaffold, watchConsole, webSnapshotMode, type WebScaffold,
} from './scaffold.ts'
import { connectFreshWorkspaceZh, ZH_BROWSER_LOCALE } from './support.ts'
const NAME = 'DeepSeek-V4.1-Flash'
const FIXTURE = fileURLToPath(new URL('./fixtures/deepseek-model-label-1017/session.v4.jsonl', import.meta.url))
const EXPECTED = fileURLToPath(new URL('./expected/deepseek-model-label-1017/models.expected.md', import.meta.url))
const MODE = webSnapshotMode()
describe.skipIf(MODE === 'record')('web e2e: temporary DeepSeek release badge', () => {
let scaffold: WebScaffold
let browser: Browser
let page: Page
let tripwire: ReturnType<typeof watchConsole>
beforeAll(async () => {
scaffold = await launchWebScaffold({
extraOverlayPath: fileURLToPath(new URL('./fixtures/deepseek-model-label-1017/account.overlay.yml', import.meta.url)),
replayFixture: FIXTURE,
replayProvidersOnly: true,
replayProviders: [
{ id: 'deepseek-account', name: 'DeepSeek Account', models: [{ id: 'deepseek-flash', name: NAME }] },
{ id: 'deepseek-official', name: 'DeepSeek', models: [
{ id: 'deepseek-flash', name: NAME }, { id: 'deepseek-v4-pro', name: 'DeepSeek-V4-Pro' },
] },
{ id: 'external', name: 'External', models: [{ id: 'deepseek-flash', name: NAME }] },
],
})
browser = await chromium.launch()
page = await browser.newPage({ viewport: { width: 1440, height: 900 }, locale: ZH_BROWSER_LOCALE })
tripwire = watchConsole(page)
await page.goto(scaffold.authenticatedUrl, { waitUntil: 'load' })
await connectFreshWorkspaceZh(page, scaffold.workspaceCwd)
})
afterAll(async () => {
try { await browser?.close() }
finally { await scaffold?.close() }
})
it('shows the same badge in all placements while preserving the chosen provider and model id', async () => {
const trigger = page.getByRole('button', { name: /^选择模型/ })
await trigger.getByText('1017', { exact: true }).waitFor()
expect(await trigger.textContent()).toContain(`${NAME} 1017`)
expect(await trigger.getAttribute('aria-label')).toBe(`选择模型,当前 ${NAME}`)
try {
await trigger.click()
const current = page.getByRole('menuitem', { name: /^模型/ })
expect(await current.getByText('1017', { exact: true }).count()).toBe(1)
await current.click()
const menu = page.getByRole('menu', { name: '模型', exact: true })
await compareOrRefreshGolden(EXPECTED, await captureStableAria(page, '[role="menu"][aria-label="模型"]', scaffold.workspaceCwd), MODE)
expect(await menu.getByText('1017', { exact: true }).count()).toBe(2)
expect(await menu.getByRole('group', { name: 'External', exact: true }).getByText('1017', { exact: true }).count()).toBe(0)
const account = menu.getByRole('group', { name: 'DeepSeek 账号', exact: true })
await account.getByRole('menuitemradio', { name: `${NAME} 1017`, exact: true }).click()
await expect.poll(() => scaffold.ctx.agentDefaultModel.currentSelection()).toEqual({ provider: 'deepseek-account', model: 'deepseek-flash' })
await expect.poll(() => trigger.textContent()).toContain(`${NAME} 1017`)
const catalog = await scaffold.ctx.llm.listModels('deepseek-account')
expect(catalog.map(model => ({ id: model.id, name: model.name }))).toEqual([{ id: 'deepseek-flash', name: NAME }])
} finally {
await page.keyboard.press('Escape')
await page.keyboard.press('Escape')
}
})
it('keeps the release badge inside a 390px model menu and uses both theme palettes', async () => {
try {
await page.setViewportSize({ width: 390, height: 844 })
const trigger = page.getByRole('button', { name: /^选择模型/ })
await trigger.click()
await page.getByRole('menuitem', { name: /^模型/ }).click()
const menu = page.getByRole('menu', { name: '模型', exact: true })
const badge = menu.getByRole('group', { name: 'DeepSeek 账号', exact: true }).getByText('1017', { exact: true })
const box = await badge.boundingBox()
expect(box).not.toBeNull()
expect(box!.x).toBeGreaterThanOrEqual(12)
expect(box!.x + box!.width).toBeLessThanOrEqual(378)
const colors = await badge.evaluate((node) => {
const body = node.ownerDocument.body
const previous = body.getAttribute('data-ds-dark-theme')
try {
return [false, true].map((dark) => {
body.toggleAttribute('data-ds-dark-theme', dark)
const style = getComputedStyle(node)
return { color: style.color, background: style.backgroundColor }
})
} finally {
if (previous === null) body.removeAttribute('data-ds-dark-theme')
else body.setAttribute('data-ds-dark-theme', previous)
}
})
expect(colors[0]).not.toEqual(colors[1])
for (const color of colors) expect(color.color).not.toBe(color.background)
} finally {
await page.keyboard.press('Escape')
await page.keyboard.press('Escape')
await page.setViewportSize({ width: 1440, height: 900 })
}
expect(tripwire.pageErrors).toEqual([])
})
})
@@ -0,0 +1,11 @@
- menu "模型":
- group "DeepSeek 账号":
- text: DeepSeek 账号
- menuitemradio "DeepSeek-V4.1-Flash 1017"
- group "DeepSeek":
- text: DeepSeek
- menuitemradio "DeepSeek-V4.1-Flash 1017" [checked]
- menuitemradio "DeepSeek-V4-Pro"
- group "External":
- text: External
- menuitemradio "DeepSeek-V4.1-Flash"
@@ -0,0 +1,24 @@
- button "返回插件": 插件
- heading "网页搜索" [level=3]
- paragraph: 设置 DeepSeek 的搜索提供方。
- text: 启用新版 Web 搜索 API
- switch "启用新版 Web 搜索 API" [checked]
- paragraph:
- text: 默认关闭,搜索通过 DeepSeek Messages 完成。新版 Web 搜索 API 功能与计费详见
- link "网页搜索与抓取指南":
- /url: https://api-docs.deepseek.com/zh-cn/guides/search
- text: API Key 未配置密钥;仅使用 DeepSeek 账号模型的对话可以通过默认接口地址搜索。
- textbox "API Key"
- paragraph: 不写入设置文件。留空表示保持当前密钥。
- text: Search / Fetch API 基础地址 已覆盖
- button "恢复默认"
- textbox "Search / Fetch API 基础地址":
- /placeholder: ""
- text: https://search-api.test/api/v1/tools
- paragraph: 填写含 API 前缀的地址,例如 https://api.deepseek.com/v1/tools;程序追加 /search 或 /fetch,留空恢复默认。
- text: 每次搜索结果数
- textbox "每次搜索结果数":
- /placeholder: ""
- text: "10"
- paragraph: 每个查询返回的结果条数,须为 1–50 的整数,默认 10;不控制搜索调用次数。web_search 保留的来源数不超过其自身的结果上限。
- button "保存" [disabled]
@@ -0,0 +1,7 @@
# The replay catalog supplies the account route without account authentication or network I/O.
- id: llm-deepseek-account
disabled: true
- id: agent-default-model
config:
provider: deepseek-official
model: deepseek-flash
@@ -0,0 +1 @@
{"type":"session","version":4,"id":"{{session:1}}","createdAt":1785015039278,"cwd":"{{cwd}}","isSeeded":false,"delegationDepth":0,"agentPreset":"standard"}
+62 -1
View File
@@ -36,6 +36,7 @@ describe('web e2e: plugin configuration pages', () => {
// below, that half registers its row's configuration into the page.
scaffold = await launchWebScaffold({
extraOverlayPath: fileURLToPath(new URL('./pin-browse-picker.overlay.yml', import.meta.url)),
deepSeekSearch: { apiKeyEnv: 'DSH_PLUGIN_CONFIG_E2E_UNUSED_KEY' },
profile: { packages: [{ dir: join(FIXTURE_PLUGINS, 'fixture-live-client') }] },
})
browser = await chromium.launch()
@@ -134,6 +135,66 @@ describe('web e2e: plugin configuration pages', () => {
expect(tripwire.pageErrors).toEqual([])
}, 60_000)
it('switches search and fetch to the Search and Fetch APIs together and preserves each API’s endpoint', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-search-api-settings'))
const panel = await openPlugins()
await openPage(panel, '网页搜索')
const toggle = panel.getByRole('switch', { name: '启用新版 Web 搜索 API', exact: true })
const endpoint = panel.locator('#plugin-config-web-search-endpoint')
const maxUses = panel.getByLabel('单次请求最多搜索次数', { exact: true })
const save = panel.getByRole('button', { name: '保存', exact: true })
expect(await toggle.getAttribute('aria-checked')).toBe('false')
expect(await panel.getByRole('link', { name: '网页搜索与抓取指南', exact: true }).getAttribute('href'))
.toBe('https://api-docs.deepseek.com/zh-cn/guides/search')
expect(await panel.getByLabel('Messages API 基础地址', { exact: true }).count()).toBe(1)
expect(await maxUses.inputValue()).toBe('5')
expect(await endpoint.inputValue()).toBe('')
expect(await save.isDisabled()).toBe(true)
await endpoint.fill('https://messages.test/anthropic/v1')
await save.click()
await expect.poll(() => save.isDisabled()).toBe(true)
await toggle.focus()
await page.keyboard.press('Space')
expect(await panel.getByLabel('Search / Fetch API 基础地址', { exact: true }).count()).toBe(1)
expect(await endpoint.inputValue()).toBe('https://api.deepseek.com/v1/tools')
expect(await maxUses.count()).toBe(0)
const count = panel.getByLabel('每次搜索结果数', { exact: true })
expect(await count.inputValue()).toBe('10')
await count.fill('51')
await panel.getByText('请填 1–50 的整数;留空表示使用默认值。', { exact: true }).waitFor()
expect(await save.isDisabled()).toBe(true)
expect(await toggle.isDisabled()).toBe(true)
await count.fill('10')
expect(await settingsDocument()).not.toContain('searchProvider: deepseek-search-api')
await endpoint.fill('https://search-api.test/api/v1/tools')
await save.click()
await expect.poll(() => save.isDisabled()).toBe(true)
await expect.poll(settingsDocument).toContain('searchProvider: deepseek-search-api')
await expect.poll(settingsDocument).toContain('fetchProvider: deepseek-fetch-api')
await expect.poll(settingsDocument).toContain('baseURL: https://search-api.test/api/v1/tools')
await page.reload({ waitUntil: 'load' })
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
await openPlugins()
await openPage(panel, '网页搜索')
expect(await toggle.getAttribute('aria-checked')).toBe('true')
expect(await endpoint.inputValue()).toBe('https://search-api.test/api/v1/tools')
const snapshot = await captureStableAria(page, '[data-plugin-panel]', scaffold.workspaceCwd)
await compareOrRefreshGolden(join(SNAPSHOT_DIR, 'web-search.expected.md'), snapshot, MODE)
await panel.getByRole('button', { name: '恢复默认', exact: true }).click()
expect(await endpoint.inputValue()).toBe('https://api.deepseek.com/v1/tools')
await save.click()
await expect.poll(() => save.isDisabled()).toBe(true)
await expect.poll(settingsDocument).not.toContain('https://search-api.test/api/v1/tools')
await toggle.click()
expect(await endpoint.inputValue()).toBe('https://messages.test/anthropic/v1')
await save.click()
await expect.poll(() => save.isDisabled()).toBe(true)
await expect.poll(settingsDocument).not.toContain('searchProvider: deepseek-search-api')
await expect.poll(settingsDocument).not.toContain('fetchProvider: deepseek-fetch-api')
expect(await settingsDocument()).toContain('baseURL: https://messages.test/anthropic/v1')
expect(tripwire.pageErrors).toEqual([])
})
it('saves subagent limits and resets them to the deployment defaults', async () => {
const panel = await openPlugins()
await openPage(panel, '子智能体')
@@ -379,7 +440,7 @@ describe('web e2e: plugin configuration pages', () => {
it.skipIf(MODE === 'record')('keeps the fixture inventory closed', async () => {
expect(tripwire.warnings).toEqual([])
await assertFixtureInventory(SNAPSHOT_DIR, ['bundle.expected.md', 'official.expected.md', 'row.expected.md', 'subagent.expected.md'])
await assertFixtureInventory(SNAPSHOT_DIR, ['bundle.expected.md', 'official.expected.md', 'row.expected.md', 'subagent.expected.md', 'web-search.expected.md'])
})
+22 -3
View File
@@ -408,10 +408,23 @@ export interface LaunchOptions {
*/
deepSeekSearch?: {
/** Anthropic-compatible base URL; the provider appends `/messages`. */
baseURL: string
baseURL?: string
/** Credential reference resolved by the shipped search provider. */
apiKeyEnv: string
}
/**
* Patch the shipped DeepSeek Search and Fetch API row to a deterministic
* endpoint and credential reference, optionally selecting both providers as
* the settings switch does.
*/
deepSeekWebApi?: {
/** Search and Fetch API base URL; the providers append `/search` or `/fetch`. */
baseURL: string
/** Credential reference resolved by both providers. */
apiKeyEnv: string
/** Select `deepseek-search-api` and `deepseek-fetch-api` in place of the shipped selection. */
select?: boolean
}
/** Preset selection default and additional declarative definitions for this scenario. */
agentPresets?: {
default: string
@@ -683,15 +696,21 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
id: 'web-search-deepseek',
config: {
apiKeyEnv: options.deepSeekSearch.apiKeyEnv,
baseURL: options.deepSeekSearch.baseURL,
...options.deepSeekSearch.baseURL === undefined ? {} : { baseURL: options.deepSeekSearch.baseURL },
},
}],
...options.deepSeekWebApi === undefined ? [] : [
{ id: 'web-deepseek-api', config: { apiKeyEnv: options.deepSeekWebApi.apiKeyEnv, baseURL: options.deepSeekWebApi.baseURL } },
...options.deepSeekWebApi.select === true
? [{ id: 'web', config: { searchProvider: 'deepseek-search-api', fetchProvider: 'deepseek-fetch-api' } }]
: [],
],
{ id: 'llm-deepseek', disabled: mode !== 'record' && !maskDeepSeekCredential },
]
// Live fields use a shared deployment layer; process-specific ports and roots stay in CLI overlays.
const formEntries = new Set(['agent-default-model', 'agent-preset-registry', 'llm-deepseek', 'llm-pi-ai',
'web-search-deepseek', 'agent-loop', 'subagent', 'bash-sandbox', 'pwsh-sandbox',
'web', 'web-search-deepseek', 'web-deepseek-api', 'agent-loop', 'subagent', 'bash-sandbox', 'pwsh-sandbox',
'session-log-deepseek', 'ui-theme', 'locale', 'ui-chat', 'ui-conversation', 'ui-settings', 'ui-settings-general', 'permission'])
const formDefaults: PatchOptions[] = []
const processOverlays = overlayPatches.map((patch) => {
+27 -59
View File
@@ -1,6 +1,6 @@
// Web e2e scenario for the shipped default search composition. A real browser
// drives `web_search`; the model stream is replayed while the real DeepSeek
// provider calls a deterministic local Anthropic-compatible endpoint through
// provider calls a deterministic local Search API endpoint through
// the real credentials service.
import { readFile } from 'node:fs/promises'
import { createServer, type Server } from 'node:http'
@@ -50,7 +50,7 @@ function resultSnippet(queryIndex: number, ordinal: number): string {
return `Snapshot search ${queryIndex + 1} excerpt ${ordinal}: the harness replays this source list from a local endpoint.`
}
/** One provider result's `page_age`, by 1-based provider order (July 2026 days 01..12). */
/** One provider result's publication date, by 1-based provider order (July 2026 days 01..12). */
function resultPageAge(ordinal: number): string {
return `2026-07-${String(ordinal).padStart(2, '0')}`
}
@@ -77,7 +77,12 @@ interface CapturedSearchRequest {
body: unknown
}
/** Start the deterministic DeepSeek Messages double used by the real provider. */
/** The Search API `query` field of one captured request body; `ori_question` also names every query. */
function requestQuery(body: unknown): unknown {
return typeof body === 'object' && body !== null && 'query' in body ? body.query : undefined
}
/** Start the deterministic DeepSeek Search double used by the real provider. */
async function startSearchServer(captured: CapturedSearchRequest[]): Promise<{ server: Server; baseURL: string }> {
const server = createServer((request, response) => {
let body = ''
@@ -87,11 +92,10 @@ async function startSearchServer(captured: CapturedSearchRequest[]): Promise<{ s
const parsedBody: unknown = JSON.parse(body)
captured.push({
path: request.url ?? '',
apiKey: typeof request.headers['x-api-key'] === 'string' ? request.headers['x-api-key'] : undefined,
apiKey: typeof request.headers.authorization === 'string' ? request.headers.authorization : undefined,
body: parsedBody,
})
const serializedBody = JSON.stringify(parsedBody)
const queryIndex = QUERIES.findIndex(query => serializedBody.includes(`Perform a web search for the query: ${query}`))
const queryIndex = QUERIES.findIndex(query => requestQuery(parsedBody) === query)
if (queryIndex < 0) {
response.writeHead(400, { 'content-type': 'application/json' })
response.end(JSON.stringify({ error: 'unknown fixture query' }))
@@ -99,26 +103,13 @@ async function startSearchServer(captured: CapturedSearchRequest[]): Promise<{ s
}
response.writeHead(200, { 'content-type': 'application/json' })
response.end(JSON.stringify({
content: [
{
type: 'text',
text: `Found ${PROVIDER_RESULT_COUNT} sources.`,
citations: RESULT_ORDINALS.map(ordinal => ({
type: 'web_search_result_location',
url: resultUrl(queryIndex, ordinal),
cited_text: resultSnippet(queryIndex, ordinal),
})),
},
{
type: 'web_search_tool_result',
content: RESULT_ORDINALS.map(ordinal => ({
type: 'web_search_result',
url: resultUrl(queryIndex, ordinal),
title: resultTitle(queryIndex, ordinal),
page_age: resultPageAge(ordinal),
})),
},
],
results: RESULT_ORDINALS.map(ordinal => ({
url: resultUrl(queryIndex, ordinal),
title: resultTitle(queryIndex, ordinal),
snippet: resultSnippet(queryIndex, ordinal),
content: '', site_name: null, site_icon: null,
date: resultPageAge(ordinal),
})),
}))
})
})
@@ -133,12 +124,11 @@ async function startSearchServer(captured: CapturedSearchRequest[]): Promise<{ s
return { server, baseURL: `http://127.0.0.1:${address.port}` }
}
describe('web e2e: shipped default web search', () => {
describe('web e2e: opt-in Search API web search', () => {
let scaffold: WebScaffold
let browser: Browser
let page: Page
let searchServer: Server | undefined
let searchBaseURL: string
let tripwire: ReturnType<typeof watchConsole>
const searchRequests: CapturedSearchRequest[] = []
const sessionEvents: SessionEvent[] = []
@@ -146,12 +136,13 @@ describe('web e2e: shipped default web search', () => {
beforeAll(async () => {
const search = await startSearchServer(searchRequests)
searchServer = search.server
searchBaseURL = search.baseURL
scaffold = await launchWebScaffold({
extraOverlayPath: fileURLToPath(new URL('./pin-browse-picker.overlay.yml', import.meta.url)),
compareReplaySession: true,
deepSeekSearch: {
baseURL: search.baseURL,
deepSeekWebApi: {
baseURL: `${search.baseURL}/api/v1/tools`,
apiKeyEnv: SEARCH_CREDENTIAL_REF,
select: true,
},
...(MODE === 'record' ? {} : { replayFixture: FIXTURE, paceMs: 15 }),
})
@@ -197,37 +188,14 @@ describe('web e2e: shipped default web search', () => {
it.skipIf(MODE === 'record')('uses the real provider and persists the capped structured result', () => {
expect(searchRequests).toHaveLength(QUERIES.length)
for (const query of QUERIES) {
const request = searchRequests.find(candidate => JSON.stringify(candidate.body).includes(query))
const request = searchRequests.find(candidate => requestQuery(candidate.body) === query)
if (request === undefined) throw new Error(`missing provider request for query: ${query}`)
expect(request).toMatchObject({ path: '/messages', apiKey: SEARCH_CREDENTIAL })
expect(request.body).toMatchObject({
messages: [{
role: 'user',
content: [{ type: 'text', text: `Perform a web search for the query: ${query}` }],
}],
})
const tools = (request.body as { tools?: unknown }).tools
expect(tools).toHaveLength(1)
expect((tools as unknown[])[0]).toMatchObject({ type: 'web_search_20250305', name: 'web_search' })
}
const auxiliaryRequests = sessionEvents.filter(
(event): event is Extract<SessionEvent, { type: 'web/deepseek-search-llm-request' }> =>
event.type === 'web/deepseek-search-llm-request',
)
expect(auxiliaryRequests).toHaveLength(QUERIES.length)
for (const query of QUERIES) {
const request = searchRequests.find(candidate => JSON.stringify(candidate.body).includes(query))
const auxiliaryRequest = auxiliaryRequests.find(event => JSON.stringify(event.data.body).includes(query))
if (request === undefined || auxiliaryRequest === undefined) {
throw new Error(`missing paired provider request for query: ${query}`)
}
expect(auxiliaryRequest.data).toEqual({
endpoint: `${searchBaseURL}/messages`,
apiVersion: '2023-06-01',
body: request.body,
expect(request).toMatchObject({ path: '/api/v1/tools/search', apiKey: `Bearer ${SEARCH_CREDENTIAL}` })
expect(request.body).toEqual({
query, count: WEB_SEARCH_MAX_RESULTS, need_content: false, ori_question: Array.from(PROMPT).slice(0, 128).join(''),
})
}
expect(sessionEvents.filter(event => event.type === 'web/deepseek-search-llm-request')).toEqual([])
const searchCall = sessionEvents.find(
(event): event is Extract<SessionEvent, { type: 'tool/call' }> =>
+1
View File
@@ -107,6 +107,7 @@
"tests/developer-tools-settings.e2e.ts",
"tests/models-settings.e2e.ts",
"tests/deepseek-messages-settings.e2e.ts",
"tests/deepseek-model-label-1017.e2e.ts",
"tests/deepseek-messages-chat.e2e.ts",
"tests/models-settings-recovery.e2e.ts",
"tests/default-model.e2e.ts",
+2 -2
View File
@@ -6,5 +6,5 @@
en: 41d772192075e133
zh: 5ef3da69b4de1d8a
/capability-seams-and-core-services:
en: 048c8c150734d0dd
zh: 836dd6c78d4c8278
en: c0c69a4be20d2157
zh: 9218ae36d2fe4a04
+3 -1
View File
@@ -264,6 +264,7 @@ flowchart LR
pkg_web_search_exa["web-search-exa"]
pkg_web_search_perplexity["web-search-perplexity"]
pkg_web_search_deepseek["web-search-deepseek"]
pkg_web_deepseek_api["web-deepseek-api"]
pkg_web_fetch_http["web-fetch-http"]
pkg_spill["spill"]
svc_spillStore["ctx.spillStore<br/>Spill storage seam"]
@@ -439,6 +440,7 @@ flowchart LR
pkg_user_questions --> svc_userQuestions
pkg_web --> svc_web
pkg_web_app --> svc_webApp
pkg_web_deepseek_api --> svc_web
pkg_web_fetch_http --> svc_web
pkg_web_search_deepseek --> svc_web
pkg_web_search_exa --> svc_web
@@ -697,7 +699,7 @@ flowchart LR
| `ctx.claudeCodeMods` | `core` | [`experimental-claude-code-mods`](../packages/experimental/claude-code-mods) | - | - | - | Loads mods that defineMod plugins add, raises their hook chains from harness extension points, and draws the band above the prompt over its Remote. |
| `ctx.inspector` | `core` | `inspector` | - | - | - | Owns the Worker-hosted CDP target and the transport-independent Host and Client observation and Cordis-tree query API. |
| `ctx.jobs` | `seam` | [`jobs`](../packages/jobs/jobs) | [`jobs-local`](../packages/jobs/jobs-local) | [`tool-bash`](../packages/shell/tool-bash), [`tool-pwsh`](../packages/shell/tool-pwsh), [`tool-terminal`](../packages/experimental/tool-terminal), [`tool-jobs`](../packages/jobs/tool-jobs), [`api-job-controller`](../packages/api/job-controller) | - | Producers (background bash/pwsh and PTY sends) register running work; record-declaring jobs additionally stream raw output for non-consuming observers; tool-jobs is the model-facing controller that reads, lists, and kills it; jobs-local is the process-local registry. |
| `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | Search and fetch providers register into one ctx.web seam; tool-web owns the stable model-facing names. |
| `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-deepseek-api`](../packages/web/web-deepseek-api), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | Search and fetch providers register into one ctx.web seam; tool-web owns the stable model-facing names. |
| `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | The backend saves oversized tool text and returns a model-facing locator plus retrieval hint; spill-policy is the tools/post-execute consumer that decides when to spill. |
| `ctx.directoryPicker` | `seam` | [`host-directory-picker`](../packages/host/directory-picker) | [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse) | [`api-workspace-controller`](../packages/api/workspace-controller) | - | Discriminated interaction capability: the native backend opens one OS chooser on the host display, the browse backend serves listing/creation primitives for the in-app browser; dual-face backends fill ui-workspace directory-flow slots from their browser halves (no wire advertisement). |
| `ctx.webServer` | `core` | [`host-webserver`](../packages/host/webserver) | - | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`client-hmr`](../packages/client/hmr) | - | Plain node:http carrier: named-route registry, index transform taps, and the static dist fallback; web-transport plugins register their own routes. |
+3 -1
View File
@@ -266,6 +266,7 @@ flowchart LR
pkg_web_search_exa["web-search-exa"]
pkg_web_search_perplexity["web-search-perplexity"]
pkg_web_search_deepseek["web-search-deepseek"]
pkg_web_deepseek_api["web-deepseek-api"]
pkg_web_fetch_http["web-fetch-http"]
pkg_spill["spill"]
svc_spillStore["ctx.spillStore<br/>Spill storage seam"]
@@ -441,6 +442,7 @@ flowchart LR
pkg_user_questions --> svc_userQuestions
pkg_web --> svc_web
pkg_web_app --> svc_webApp
pkg_web_deepseek_api --> svc_web
pkg_web_fetch_http --> svc_web
pkg_web_search_deepseek --> svc_web
pkg_web_search_exa --> svc_web
@@ -699,7 +701,7 @@ flowchart LR
| `ctx.claudeCodeMods` | `core` | [`experimental-claude-code-mods`](../packages/experimental/claude-code-mods) | - | - | - | 加载 defineMod 插件添加的模组,从 harness 扩展点触发其钩子链,并通过其 Remote 绘制提示框上方的横幅。 |
| `ctx.inspector` | `core` | `inspector` | - | - | - | 负责 Worker 托管的 CDP target,以及独立于传输的 Host 和 Client observation 与 Cordis tree query API。 |
| `ctx.jobs` | `seam` | [`jobs`](../packages/jobs/jobs) | [`jobs-local`](../packages/jobs/jobs-local) | [`tool-bash`](../packages/shell/tool-bash), [`tool-pwsh`](../packages/shell/tool-pwsh), [`tool-terminal`](../packages/experimental/tool-terminal), [`tool-jobs`](../packages/jobs/tool-jobs), [`api-job-controller`](../packages/api/job-controller) | - | 生产方(后台 bash/pwsh 与 PTY 发送)登记正在运行的工作;声明 record 的 job 还为非消费观察者流式提供原始输出;tool-jobs 是面向模型的控制器,用于读取、列出和终止这些工作;jobs-local 是进程本地注册表。 |
| `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | 搜索和抓取提供方注册到同一个 ctx.web seam;tool-web 负责稳定的面向模型名称。 |
| `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-deepseek-api`](../packages/web/web-deepseek-api), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | 搜索和抓取提供方注册到同一个 ctx.web seam;tool-web 负责稳定的面向模型名称。 |
| `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | 后端保存过大的工具文本,并返回面向模型的定位信息和取回提示;spill-policy 是 tools/post-execute 消费方,负责决定何时 spill。 |
| `ctx.directoryPicker` | `seam` | [`host-directory-picker`](../packages/host/directory-picker) | [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse) | [`api-workspace-controller`](../packages/api/workspace-controller) | - | 带判别标记的交互能力:原生后端在 Host 显示设备上打开一个操作系统选择器,浏览后端为应用内浏览器提供列表与创建原语;双端后端通过其浏览器侧填充 ui-workspace 目录流程的 slot(不通过协议发布)。 |
| `ctx.webServer` | `core` | [`host-webserver`](../packages/host/webserver) | - | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`client-hmr`](../packages/client/hmr) | - | 普通的 node:http 载体:具名路由注册表、索引转换 tap,以及静态 dist 回退;Web 传输插件注册自己的路由。 |
+35 -5
View File
@@ -4306,20 +4306,23 @@ export type ApprovalPolicy = 'ask' | 'never'
## `@deepseek-ai/dsh-web`
- `source`: [`packages/web/web/src/index.ts:55`](../packages/web/web/src/index.ts)
- `refs`: `Volatile` (`@deepseek-ai/cordis`)
- `source`: [`packages/web/web/src/index.ts:57`](../packages/web/web/src/index.ts)
```ts config-catalog
/**
* Config for the web seam. `searchProvider` / `fetchProvider` pin which provider
* wins for each capability; both are optional (a single registered usable
* provider auto-selects). Operational overrides such as environment variables
* must feed these same fields rather than introduce a hidden priority chain.
* provider auto-selects). Each operation reads the current value, so a settings
* change applies to the next search or fetch without remounting the service.
* Operational overrides such as environment variables must feed these same
* fields rather than introduce a hidden priority chain.
*/
export interface WebRuntimeConfig {
/** Explicit search provider id. Omitted = auto-select when exactly one usable. */
readonly searchProvider?: string
readonly searchProvider: Volatile<string | undefined>
/** Explicit fetch provider id. Omitted = auto-select when exactly one usable. */
readonly fetchProvider?: string
readonly fetchProvider: Volatile<string | undefined>
}
```
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-web -->
@@ -4356,6 +4359,32 @@ export interface Config {
```
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-web-app -->
<!-- BEGIN GENERATED config-catalog:@deepseek-ai/dsh-web-deepseek-api -->
<a id="deepseek-aidsh-web-deepseek-api"></a>
## `@deepseek-ai/dsh-web-deepseek-api`
- `inject`: `web`
- `refs`: `Volatile` (`@deepseek-ai/cordis`)
- `source`: [`packages/web/web-deepseek-api/src/index.ts:34`](../packages/web/web-deepseek-api/src/index.ts)
```ts config-catalog
/** Settings read by the next search or fetch without re-registering either provider. */
export interface Config {
/** Literal DeepSeek API key; prefer {@link apiKeyEnv} so no secret enters configuration files. */
apiKey: Volatile<string | undefined>
/** Credential reference resolved for each operation; defaults to `DEEPSEEK_API_KEY`. */
apiKeyEnv: Volatile<string>
/** API base including its path prefix; `/search` and `/fetch` are appended. */
baseURL: Volatile<string>
/** Search API results per search, from 1 through 50; a smaller request bound wins. Defaults to 10. */
count: Volatile<number>
/** Send the triggering user question, bounded to 128 characters, as `ori_question`. Defaults to true. */
sendOriginalQuestion: Volatile<boolean>
}
```
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-web-deepseek-api -->
<!-- BEGIN GENERATED config-catalog:@deepseek-ai/dsh-web-fetch-http -->
<a id="deepseek-aidsh-web-fetch-http"></a>
@@ -4580,6 +4609,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
| `@deepseek-ai/dsh-client-ui-commands` | — | [`packages/client/ui-commands/src/index.ts`](../packages/client/ui-commands/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-conversation` | — | [`packages/client/ui-conversation/src/index.ts`](../packages/client/ui-conversation/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-cordis` | — | [`packages/extensions/ui-cordis/src/index.ts`](../packages/extensions/ui-cordis/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-deepseek-model-label-1017` | — | [`packages/client/ui-deepseek-model-label-1017/src/index.ts`](../packages/client/ui-deepseek-model-label-1017/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-deliverables` | `systemPrompt` · `connection` · `sessionQuery` · `sessionController` · `workspaceFiles` · `fs` · `sandboxPolicy` · `workspaceChanges` | [`packages/client/ui-deliverables/src/index.ts`](../packages/client/ui-deliverables/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-directory-picker-browse` | — | [`packages/client/ui-directory-picker-browse/src/index.ts`](../packages/client/ui-directory-picker-browse/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-directory-picker-native` | — | [`packages/client/ui-directory-picker-native/src/index.ts`](../packages/client/ui-directory-picker-native/src/index.ts) |
+35 -5
View File
@@ -4308,20 +4308,23 @@ export type ApprovalPolicy = 'ask' | 'never'
## `@deepseek-ai/dsh-web`
- `source`: [`packages/web/web/src/index.ts:55`](../packages/web/web/src/index.ts)
- `refs`: `Volatile` (`@deepseek-ai/cordis`)
- `source`: [`packages/web/web/src/index.ts:57`](../packages/web/web/src/index.ts)
```ts config-catalog
/**
* Config for the web seam. `searchProvider` / `fetchProvider` pin which provider
* wins for each capability; both are optional (a single registered usable
* provider auto-selects). Operational overrides such as environment variables
* must feed these same fields rather than introduce a hidden priority chain.
* provider auto-selects). Each operation reads the current value, so a settings
* change applies to the next search or fetch without remounting the service.
* Operational overrides such as environment variables must feed these same
* fields rather than introduce a hidden priority chain.
*/
export interface WebRuntimeConfig {
/** Explicit search provider id. Omitted = auto-select when exactly one usable. */
readonly searchProvider?: string
readonly searchProvider: Volatile<string | undefined>
/** Explicit fetch provider id. Omitted = auto-select when exactly one usable. */
readonly fetchProvider?: string
readonly fetchProvider: Volatile<string | undefined>
}
```
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-web -->
@@ -4358,6 +4361,32 @@ export interface Config {
```
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-web-app -->
<!-- BEGIN GENERATED config-catalog:@deepseek-ai/dsh-web-deepseek-api -->
<a id="deepseek-aidsh-web-deepseek-api"></a>
## `@deepseek-ai/dsh-web-deepseek-api`
- `inject`: `web`
- `refs`: `Volatile` (`@deepseek-ai/cordis`)
- `source`: [`packages/web/web-deepseek-api/src/index.ts:34`](../packages/web/web-deepseek-api/src/index.ts)
```ts config-catalog
/** Settings read by the next search or fetch without re-registering either provider. */
export interface Config {
/** Literal DeepSeek API key; prefer {@link apiKeyEnv} so no secret enters configuration files. */
apiKey: Volatile<string | undefined>
/** Credential reference resolved for each operation; defaults to `DEEPSEEK_API_KEY`. */
apiKeyEnv: Volatile<string>
/** API base including its path prefix; `/search` and `/fetch` are appended. */
baseURL: Volatile<string>
/** Search API results per search, from 1 through 50; a smaller request bound wins. Defaults to 10. */
count: Volatile<number>
/** Send the triggering user question, bounded to 128 characters, as `ori_question`. Defaults to true. */
sendOriginalQuestion: Volatile<boolean>
}
```
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-web-deepseek-api -->
<!-- BEGIN GENERATED config-catalog:@deepseek-ai/dsh-web-fetch-http -->
<a id="deepseek-aidsh-web-fetch-http"></a>
@@ -4582,6 +4611,7 @@ export interface Config {
| `@deepseek-ai/dsh-client-ui-commands` | — | [`packages/client/ui-commands/src/index.ts`](../packages/client/ui-commands/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-conversation` | — | [`packages/client/ui-conversation/src/index.ts`](../packages/client/ui-conversation/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-cordis` | — | [`packages/extensions/ui-cordis/src/index.ts`](../packages/extensions/ui-cordis/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-deepseek-model-label-1017` | — | [`packages/client/ui-deepseek-model-label-1017/src/index.ts`](../packages/client/ui-deepseek-model-label-1017/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-deliverables` | `systemPrompt` · `connection` · `sessionQuery` · `sessionController` · `workspaceFiles` · `fs` · `sandboxPolicy` · `workspaceChanges` | [`packages/client/ui-deliverables/src/index.ts`](../packages/client/ui-deliverables/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-directory-picker-browse` | — | [`packages/client/ui-directory-picker-browse/src/index.ts`](../packages/client/ui-directory-picker-browse/src/index.ts) |
| `@deepseek-ai/dsh-client-ui-directory-picker-native` | — | [`packages/client/ui-directory-picker-native/src/index.ts`](../packages/client/ui-directory-picker-native/src/index.ts) |
+10
View File
@@ -84,6 +84,7 @@ flowchart TD
subgraph group_web["packages/web"]
pkg_tool_web["tool-web"]
pkg_web["web"]
pkg_web_deepseek_api["web-deepseek-api"]
pkg_web_fetch_http["web-fetch-http"]
pkg_web_search_deepseek["web-search-deepseek"]
pkg_web_search_exa["web-search-exa"]
@@ -160,6 +161,7 @@ flowchart TD
pkg_client_ui_chat["client-ui-chat"]
pkg_client_ui_commands["client-ui-commands"]
pkg_client_ui_conversation["client-ui-conversation"]
pkg_client_ui_deepseek_model_label_1017["client-ui-deepseek-model-label-1017"]
pkg_client_ui_deliverables["client-ui-deliverables"]
pkg_client_ui_directory_picker_browse["client-ui-directory-picker-browse"]
pkg_client_ui_directory_picker_native["client-ui-directory-picker-native"]
@@ -731,6 +733,12 @@ flowchart TD
pkg_fs_sandbox --> pkg_fs_local
pkg_fs_sandbox --> pkg_sandbox
pkg_fs_sandbox --> pkg_sandbox_policy
pkg_web_deepseek_api --> pkg_agent
pkg_web_deepseek_api --> pkg_credentials
pkg_web_deepseek_api --> pkg_deepseek_account
pkg_web_deepseek_api --> pkg_launch_environment
pkg_web_deepseek_api --> pkg_session
pkg_web_deepseek_api --> pkg_web
pkg_web_search_deepseek --> pkg_agent
pkg_web_search_deepseek --> pkg_credentials
pkg_web_search_deepseek --> pkg_deepseek_account
@@ -1468,6 +1476,7 @@ flowchart TD
| [`client-ui-chat`](../packages/client/ui-chat) | `client` | — |
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | — |
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | — |
| [`client-ui-deepseek-model-label-1017`](../packages/client/ui-deepseek-model-label-1017) | `client` | — |
| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | — |
| [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | — |
| [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | — |
@@ -1651,6 +1660,7 @@ flowchart TD
| [`tools`](../packages/core/tools) | `core` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`user-approval`](../packages/interaction/user-approval), [`working-directory`](../packages/session/working-directory) |
| [`command-goal`](../packages/goal/command-goal) | `goal` | [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`llm`](../packages/llm/llm) |
| [`fs-sandbox`](../packages/fs/fs-sandbox) | `fs` | [`fs`](../packages/fs/fs), [`fs-local`](../packages/fs/fs-local), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy) |
| [`web-deepseek-api`](../packages/web/web-deepseek-api) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`deepseek-account`](../packages/credentials/deepseek-account), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`web`](../packages/web/web) |
| [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`deepseek-account`](../packages/credentials/deepseek-account), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`web`](../packages/web/web) |
| [`api-account-controller`](../packages/api/account-controller) | `api` | [`agent`](../packages/core/agent), [`deepseek-account`](../packages/credentials/deepseek-account), [`typert-protocol`](../packages/typert/protocol) |
| [`compaction`](../packages/compaction/compaction) | `compaction` | [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
+10
View File
@@ -86,6 +86,7 @@ flowchart TD
subgraph group_web["packages/web"]
pkg_tool_web["tool-web"]
pkg_web["web"]
pkg_web_deepseek_api["web-deepseek-api"]
pkg_web_fetch_http["web-fetch-http"]
pkg_web_search_deepseek["web-search-deepseek"]
pkg_web_search_exa["web-search-exa"]
@@ -162,6 +163,7 @@ flowchart TD
pkg_client_ui_chat["client-ui-chat"]
pkg_client_ui_commands["client-ui-commands"]
pkg_client_ui_conversation["client-ui-conversation"]
pkg_client_ui_deepseek_model_label_1017["client-ui-deepseek-model-label-1017"]
pkg_client_ui_deliverables["client-ui-deliverables"]
pkg_client_ui_directory_picker_browse["client-ui-directory-picker-browse"]
pkg_client_ui_directory_picker_native["client-ui-directory-picker-native"]
@@ -733,6 +735,12 @@ flowchart TD
pkg_fs_sandbox --> pkg_fs_local
pkg_fs_sandbox --> pkg_sandbox
pkg_fs_sandbox --> pkg_sandbox_policy
pkg_web_deepseek_api --> pkg_agent
pkg_web_deepseek_api --> pkg_credentials
pkg_web_deepseek_api --> pkg_deepseek_account
pkg_web_deepseek_api --> pkg_launch_environment
pkg_web_deepseek_api --> pkg_session
pkg_web_deepseek_api --> pkg_web
pkg_web_search_deepseek --> pkg_agent
pkg_web_search_deepseek --> pkg_credentials
pkg_web_search_deepseek --> pkg_deepseek_account
@@ -1470,6 +1478,7 @@ flowchart TD
| [`client-ui-chat`](../packages/client/ui-chat) | `client` | — |
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | — |
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | — |
| [`client-ui-deepseek-model-label-1017`](../packages/client/ui-deepseek-model-label-1017) | `client` | — |
| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | — |
| [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | — |
| [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | — |
@@ -1653,6 +1662,7 @@ flowchart TD
| [`tools`](../packages/core/tools) | `core` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`user-approval`](../packages/interaction/user-approval), [`working-directory`](../packages/session/working-directory) |
| [`command-goal`](../packages/goal/command-goal) | `goal` | [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`llm`](../packages/llm/llm) |
| [`fs-sandbox`](../packages/fs/fs-sandbox) | `fs` | [`fs`](../packages/fs/fs), [`fs-local`](../packages/fs/fs-local), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy) |
| [`web-deepseek-api`](../packages/web/web-deepseek-api) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`deepseek-account`](../packages/credentials/deepseek-account), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`web`](../packages/web/web) |
| [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`deepseek-account`](../packages/credentials/deepseek-account), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`web`](../packages/web/web) |
| [`api-account-controller`](../packages/api/account-controller) | `api` | [`agent`](../packages/core/agent), [`deepseek-account`](../packages/credentials/deepseek-account), [`typert-protocol`](../packages/typert/protocol) |
| [`compaction`](../packages/compaction/compaction) | `compaction` | [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
+27 -21
View File
@@ -9,8 +9,8 @@
en: 1387c4505dde2faf
zh: 48570fa1c13d6910
/session-persistence-event-catalog/persistence-type-fingerprints:
en: a696c43a89d5fbe8
zh: 6855eb0239b8dcb3
en: bcff48893d904af8
zh: f82e75c91c39adb1
/session-persistence-event-catalog/event-envelope:
en: 689f781d95689e20
zh: 602f6a7f0835d698
@@ -291,8 +291,8 @@
en: d278748103cf1640
zh: d278748103cf1640
/session-persistence-event-catalog/events/web/web-deepseek-search-llm-request-log-only:
en: f12c598242992aa3
zh: 08609553e15a91f3
en: a3e7718f295ba130
zh: e6435b44b42f0784
/session-persistence-event-catalog/events/working-directory:
en: e8dd0cebbb930eb7
zh: e8dd0cebbb930eb7
@@ -456,8 +456,11 @@
en: 42389e30f99e210f
zh: 42389e30f99e210f
/session-persistence-event-catalog/resolved-persistence-types/developer-message:
en: e9a6abc2549ddf91
zh: e9a6abc2549ddf91
en: 65261480029e2779
zh: 65261480029e2779
/session-persistence-event-catalog/resolved-persistence-types/disabled:
en: acde9453c30a141f
zh: acde9453c30a141f
/session-persistence-event-catalog/resolved-persistence-types/dispatch:
en: aae8924fd5eb9013
zh: aae8924fd5eb9013
@@ -999,11 +1002,11 @@
en: 6e11a7855b002f20
zh: d752566bb2b75948
/session-persistence-event-catalog/resolved-persistence-types/continuablesubagentdescriptordata:
en: 586743dfeab78c55
zh: 26ccef4a02dd7a58
en: a6a2e38fdd6d127a
zh: 1fe82356d89f5769
/session-persistence-event-catalog/resolved-persistence-types/deepseeksearchllmrequest:
en: db71ecccc1e5409e
zh: 7b55744e022dc102
en: 128c0ecc1897eb68
zh: e4c67c92752bcc2a
/session-persistence-event-catalog/resolved-persistence-types/developermessage:
en: 997b5db27df00446
zh: 07e5197ddd7bd59b
@@ -1860,11 +1863,11 @@
en: 0b74295f7c5c8f11
zh: 5f1213cec87f6be0
/session-persistence-event-catalog/resolved-persistence-types/kind-working-directory:
en: 9848d783b7b5af16
zh: f161eaf1a841cd55
/session-persistence-event-catalog/resolved-persistence-types/max-tokens-messages-model-tools:
en: afedf4a31a67eb14
zh: 98d3bc882f2b61c3
en: 1a6c0842d549a5f9
zh: cde31cc53cbcab66
/session-persistence-event-catalog/resolved-persistence-types/max-tokens-messages-model-thinking:
en: 3216b23c131d0070
zh: 73ca171c6014f16e
/session-persistence-event-catalog/resolved-persistence-types/member-teamid-version:
en: 82b0989dad6bbfc0
zh: 0789b63f1d59b2ed
@@ -1968,8 +1971,11 @@
en: a4d9eab2928e9b30
zh: b36702c866518273
/session-persistence-event-catalog/resolved-persistence-types/type-developer-message:
en: ed8c78af3a89ba8f
zh: 4f859687aa13c1a3
en: a9e6e24b98390923
zh: 65addae898d8aaec
/session-persistence-event-catalog/resolved-persistence-types/type-disabled:
en: 585627a50ece4e5f
zh: 157837aee3da0ac3
/session-persistence-event-catalog/resolved-persistence-types/type-feedback-message-delete:
en: 204561e2311db97e
zh: 77264396bd5e25c4
@@ -2124,11 +2130,11 @@
en: 8eec3bb6eee5085b
zh: 04bb3281fd7bd95c
/session-persistence-event-catalog/resolved-persistence-types/type-user-message:
en: afab869c0592b46c
zh: f15874a1e728ab0d
en: d6d9401f19a66ee8
zh: 569fdddf887660a2
/session-persistence-event-catalog/resolved-persistence-types/type-web-deepseek-search-llm-request:
en: f109997e295af37d
zh: b2dcfd599f73b61c
en: 99c8837344178a47
zh: bf746f5678346596
/session-persistence-event-catalog/resolved-persistence-types/type-web-search-20250305:
en: e0071555851c7cee
zh: 1f368baf78a7d689
+32 -11
View File
@@ -81,7 +81,7 @@ The [format references](persistence-changes/historical-formats/README.md) cover
| `event:turn/end` | event | `0f8512903d94f57a4748fa1a2092e64342856796684e6b8343db685b192745ce` | [`{ type: "turn/end" }`](#persistence-type-sha256-0f8512903d94f57a4748fa1a2092e64342856796684e6b8343db685b192745ce) |
| `event:turn/start` | event | `aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8` | [`{ type: "turn/start" }`](#persistence-type-sha256-aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8) |
| `event:user/message` | event | `2ae8594a998c9862a597129e782277bcc518266712a703b5c3161bdf552d13b8` | [`{ type: "user/message" }`](#persistence-type-sha256-2ae8594a998c9862a597129e782277bcc518266712a703b5c3161bdf552d13b8) |
| `event:web/deepseek-search-llm-request` | event | `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331` | [`{ type: "web/deepseek-search-llm-request" }`](#persistence-type-sha256-cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331) |
| `event:web/deepseek-search-llm-request` | event | `0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52` | [`{ type: "web/deepseek-search-llm-request" }`](#persistence-type-sha256-0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52) |
| `event:working-directory/change` | event | `124aa62078ca3311353b39cc3bf6c75da281338be6bbf672f8b361d828cddca3` | [`{ type: "working-directory/change" }`](#persistence-type-sha256-124aa62078ca3311353b39cc3bf6c75da281338be6bbf672f8b361d828cddca3) |
| `event:workspace/changes` | event | `e308ccf867a5398e316e0af8cb6ce238a8d33a63b9b384c8250a686786285f72` | [`{ type: "workspace/changes" }`](#persistence-type-sha256-e308ccf867a5398e316e0af8cb6ce238a8d33a63b9b384c8250a686786285f72) |
@@ -1300,7 +1300,7 @@ Source: [`packages/core/session/src/types.ts:310`](../packages/core/session/src/
'web/deepseek-search-llm-request': DeepSeekSearchLlmRequest
```
Source: [`packages/web/web-search-deepseek/src/provider.ts:82`](../packages/web/web-search-deepseek/src/provider.ts)
Source: [`packages/web/web-search-deepseek/src/provider.ts:89`](../packages/web/web-search-deepseek/src/provider.ts)
### `working-directory/*`
@@ -1739,6 +1739,14 @@ SHA-256: `1379f0b72275994d20f1ddca2d60a96ab16ec80397ca9f1af21bdc67ba5c269c`
`"developer/message"`
<a id="persistence-type-sha256-0b9b8facbe2c19773b3fb0ecc824ccbcc603d41b8f18069faa3807d449572fce"></a>
### `"disabled"`
SHA-256: `0b9b8facbe2c19773b3fb0ecc824ccbcc603d41b8f18069faa3807d449572fce`
`"disabled"`
<a id="persistence-type-sha256-26c879bdd130e8b8683a6ce588414fad2244783d6573ca399fa0de184a2b0bb1"></a>
### `"dispatch"`
@@ -3339,7 +3347,7 @@ Sources: [`packages/subagent/subagent/src/descriptor.ts:72`](../packages/subagen
| `toolFilter` | optional | [`ToolRestriction`](#persistence-type-sha256-3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f) |
| `version` | required | `number` |
<a id="persistence-type-sha256-2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9"></a>
<a id="persistence-type-sha256-abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c"></a>
<a id="persistence-type-deepseeksearchllmrequest"></a>
@@ -3347,14 +3355,14 @@ Sources: [`packages/subagent/subagent/src/descriptor.ts:72`](../packages/subagen
### `DeepSeekSearchLlmRequest`
SHA-256: `2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9`
SHA-256: `abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c`
Sources: [`packages/web/web-search-deepseek/src/provider.ts:55`](../packages/web/web-search-deepseek/src/provider.ts)
| Property | Presence | Type |
|---|---|---|
| `apiVersion` | required | `string` |
| `body` | required | [`{ max_tokens, messages, model, tools }`](#persistence-type-sha256-930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731) |
| `body` | required | [`{ max_tokens, messages, model, thinking?, … }`](#persistence-type-sha256-9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee) |
| `endpoint` | required | `string` |
<a id="persistence-type-sha256-0f6265188dae7ba6faa26830a180bb4deb0760561f97ee0c9d399ccf6c9cf1f7"></a>
@@ -7677,11 +7685,11 @@ Sources: [`packages/session/working-directory/src/index.ts:29`](../packages/sess
|---|---|---|
| `kind` | required | `"working-directory"` |
<a id="persistence-type-sha256-930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731"></a>
<a id="persistence-type-sha256-9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee"></a>
### `{ max_tokens, messages, model, tools }`
### `{ max_tokens, messages, model, thinking?, … }`
SHA-256: `930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731`
SHA-256: `9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee`
Sources: [`packages/web/web-search-deepseek/src/provider.ts:61`](../packages/web/web-search-deepseek/src/provider.ts)
@@ -7690,6 +7698,7 @@ Sources: [`packages/web/web-search-deepseek/src/provider.ts:61`](../packages/web
| `max_tokens` | required | `number` |
| `messages` | required | [`tuple (1 positions)`](#persistence-type-sha256-b993441f8ce7d27b80e619e113e232ae8e62d3d5a8340f6bfe12d8c4c018e62f) |
| `model` | required | `string` |
| `thinking` | optional | [`{ type: "disabled" }`](#persistence-type-sha256-37ff65426bcf130f045d3a59ef2a4648eb170cd30280cbd024108a2e9b4401d1) |
| `tools` | required | [`tuple (1 positions)`](#persistence-type-sha256-4aed17ec726b5397c29f6cb4bcd7905dc1a12bb6140f1657f073cd24380f2af8) |
<a id="persistence-type-sha256-b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1"></a>
@@ -8203,6 +8212,18 @@ SHA-256: `97e0162f983c27456ec71269fb4976b1851588b8c1aeac5d071d43e11f95e03c`
| `time` | required | `number` |
| `type` | required | `"developer/message"` |
<a id="persistence-type-sha256-37ff65426bcf130f045d3a59ef2a4648eb170cd30280cbd024108a2e9b4401d1"></a>
### `{ type: "disabled" }`
SHA-256: `37ff65426bcf130f045d3a59ef2a4648eb170cd30280cbd024108a2e9b4401d1`
Sources: [`packages/web/web-search-deepseek/src/provider.ts:82`](../packages/web/web-search-deepseek/src/provider.ts)
| Property | Presence | Type |
|---|---|---|
| `type` | required | `"disabled"` |
<a id="persistence-type-sha256-3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796"></a>
<a id="persistence-type-eventfeedbackmessage-delete"></a>
@@ -9034,17 +9055,17 @@ SHA-256: `2ae8594a998c9862a597129e782277bcc518266712a703b5c3161bdf552d13b8`
| `time` | required | `number` |
| `type` | required | `"user/message"` |
<a id="persistence-type-sha256-cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331"></a>
<a id="persistence-type-sha256-0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52"></a>
<a id="persistence-type-eventwebdeepseek-search-llm-request"></a>
### `{ type: "web/deepseek-search-llm-request" }`
SHA-256: `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331`
SHA-256: `0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52`
| Property | Presence | Type |
|---|---|---|
| `data` | required | [`DeepSeekSearchLlmRequest`](#persistence-type-sha256-2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9) |
| `data` | required | [`DeepSeekSearchLlmRequest`](#persistence-type-sha256-abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c) |
| `ignorable` | optional | `true` |
| `seq` | required | `number` |
| `time` | required | `number` |
+32 -11
View File
@@ -83,7 +83,7 @@
| `event:turn/end` | event | `0f8512903d94f57a4748fa1a2092e64342856796684e6b8343db685b192745ce` | [`{ type: "turn/end" }`](#persistence-type-sha256-0f8512903d94f57a4748fa1a2092e64342856796684e6b8343db685b192745ce) |
| `event:turn/start` | event | `aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8` | [`{ type: "turn/start" }`](#persistence-type-sha256-aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8) |
| `event:user/message` | event | `2ae8594a998c9862a597129e782277bcc518266712a703b5c3161bdf552d13b8` | [`{ type: "user/message" }`](#persistence-type-sha256-2ae8594a998c9862a597129e782277bcc518266712a703b5c3161bdf552d13b8) |
| `event:web/deepseek-search-llm-request` | event | `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331` | [`{ type: "web/deepseek-search-llm-request" }`](#persistence-type-sha256-cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331) |
| `event:web/deepseek-search-llm-request` | event | `0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52` | [`{ type: "web/deepseek-search-llm-request" }`](#persistence-type-sha256-0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52) |
| `event:working-directory/change` | event | `124aa62078ca3311353b39cc3bf6c75da281338be6bbf672f8b361d828cddca3` | [`{ type: "working-directory/change" }`](#persistence-type-sha256-124aa62078ca3311353b39cc3bf6c75da281338be6bbf672f8b361d828cddca3) |
| `event:workspace/changes` | event | `e308ccf867a5398e316e0af8cb6ce238a8d33a63b9b384c8250a686786285f72` | [`{ type: "workspace/changes" }`](#persistence-type-sha256-e308ccf867a5398e316e0af8cb6ce238a8d33a63b9b384c8250a686786285f72) |
@@ -1302,7 +1302,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
'web/deepseek-search-llm-request': DeepSeekSearchLlmRequest
```
来源:[`packages/web/web-search-deepseek/src/provider.ts:82`](../packages/web/web-search-deepseek/src/provider.ts)
来源:[`packages/web/web-search-deepseek/src/provider.ts:89`](../packages/web/web-search-deepseek/src/provider.ts)
### `working-directory/*`
@@ -1741,6 +1741,14 @@ SHA-256: `1379f0b72275994d20f1ddca2d60a96ab16ec80397ca9f1af21bdc67ba5c269c`
`"developer/message"`
<a id="persistence-type-sha256-0b9b8facbe2c19773b3fb0ecc824ccbcc603d41b8f18069faa3807d449572fce"></a>
### `"disabled"`
SHA-256: `0b9b8facbe2c19773b3fb0ecc824ccbcc603d41b8f18069faa3807d449572fce`
`"disabled"`
<a id="persistence-type-sha256-26c879bdd130e8b8683a6ce588414fad2244783d6573ca399fa0de184a2b0bb1"></a>
### `"dispatch"`
@@ -3341,7 +3349,7 @@ SHA-256: `6487b10ba7542f3c447b1e41a1c6a590b7bfafe0b9b66b49f34028da85bb970f`
| `toolFilter` | 可选 | [`ToolRestriction`](#persistence-type-sha256-3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f) |
| `version` | 必需 | `number` |
<a id="persistence-type-sha256-2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9"></a>
<a id="persistence-type-sha256-abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c"></a>
<a id="persistence-type-deepseeksearchllmrequest"></a>
@@ -3349,14 +3357,14 @@ SHA-256: `6487b10ba7542f3c447b1e41a1c6a590b7bfafe0b9b66b49f34028da85bb970f`
### `DeepSeekSearchLlmRequest`
SHA-256: `2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9`
SHA-256: `abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c`
来源:[`packages/web/web-search-deepseek/src/provider.ts:55`](../packages/web/web-search-deepseek/src/provider.ts)
| 属性 | 存在性 | 类型 |
|---|---|---|
| `apiVersion` | 必需 | `string` |
| `body` | 必需 | [`{ max_tokens, messages, model, tools }`](#persistence-type-sha256-930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731) |
| `body` | 必需 | [`{ max_tokens, messages, model, thinking?, … }`](#persistence-type-sha256-9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee) |
| `endpoint` | 必需 | `string` |
<a id="persistence-type-sha256-0f6265188dae7ba6faa26830a180bb4deb0760561f97ee0c9d399ccf6c9cf1f7"></a>
@@ -7679,11 +7687,11 @@ SHA-256: `2235d957bf4b7c6cf959231d480f0ba1f3a6d72d82981493fb6c7c963021d3d5`
|---|---|---|
| `kind` | 必需 | `"working-directory"` |
<a id="persistence-type-sha256-930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731"></a>
<a id="persistence-type-sha256-9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee"></a>
### `{ max_tokens, messages, model, tools }`
### `{ max_tokens, messages, model, thinking?, … }`
SHA-256: `930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731`
SHA-256: `9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee`
来源:[`packages/web/web-search-deepseek/src/provider.ts:61`](../packages/web/web-search-deepseek/src/provider.ts)
@@ -7692,6 +7700,7 @@ SHA-256: `930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731`
| `max_tokens` | 必需 | `number` |
| `messages` | 必需 | [`tuple (1 positions)`](#persistence-type-sha256-b993441f8ce7d27b80e619e113e232ae8e62d3d5a8340f6bfe12d8c4c018e62f) |
| `model` | 必需 | `string` |
| `thinking` | 可选 | [`{ type: "disabled" }`](#persistence-type-sha256-37ff65426bcf130f045d3a59ef2a4648eb170cd30280cbd024108a2e9b4401d1) |
| `tools` | 必需 | [`tuple (1 positions)`](#persistence-type-sha256-4aed17ec726b5397c29f6cb4bcd7905dc1a12bb6140f1657f073cd24380f2af8) |
<a id="persistence-type-sha256-b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1"></a>
@@ -8205,6 +8214,18 @@ SHA-256: `97e0162f983c27456ec71269fb4976b1851588b8c1aeac5d071d43e11f95e03c`
| `time` | 必需 | `number` |
| `type` | 必需 | `"developer/message"` |
<a id="persistence-type-sha256-37ff65426bcf130f045d3a59ef2a4648eb170cd30280cbd024108a2e9b4401d1"></a>
### `{ type: "disabled" }`
SHA-256: `37ff65426bcf130f045d3a59ef2a4648eb170cd30280cbd024108a2e9b4401d1`
来源:[`packages/web/web-search-deepseek/src/provider.ts:82`](../packages/web/web-search-deepseek/src/provider.ts)
| 属性 | 存在性 | 类型 |
|---|---|---|
| `type` | 必需 | `"disabled"` |
<a id="persistence-type-sha256-3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796"></a>
<a id="persistence-type-eventfeedbackmessage-delete"></a>
@@ -9036,17 +9057,17 @@ SHA-256: `2ae8594a998c9862a597129e782277bcc518266712a703b5c3161bdf552d13b8`
| `time` | 必需 | `number` |
| `type` | 必需 | `"user/message"` |
<a id="persistence-type-sha256-cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331"></a>
<a id="persistence-type-sha256-0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52"></a>
<a id="persistence-type-eventwebdeepseek-search-llm-request"></a>
### `{ type: "web/deepseek-search-llm-request" }`
SHA-256: `cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331`
SHA-256: `0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52`
| 属性 | 存在性 | 类型 |
|---|---|---|
| `data` | 必需 | [`DeepSeekSearchLlmRequest`](#persistence-type-sha256-2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9) |
| `data` | 必需 | [`DeepSeekSearchLlmRequest`](#persistence-type-sha256-abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c) |
| `ignorable` | 可选 | `true` |
| `seq` | 必需 | `number` |
| `time` | 必需 | `number` |
@@ -0,0 +1,28 @@
# Bilingual-pair consistency record for 2026-10-13-deepseek-search-thinking.md (docs/i18n/README.md): per heading
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
# After editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/persistence-changes/2026-10-13-deepseek-search-thinking.md
/:
en: 3d5a424ae7d7e46b
zh: c22a8e4a62d8cc1a
/2026-10-13-deepseek-search-thinking:
en: 033d5d72a19a029b
zh: 334111dcdead54d8
/2026-10-13-deepseek-search-thinking/summary:
en: 398b25bff3dd0fd8
zh: fef39218a015d80b
/2026-10-13-deepseek-search-thinking/table-of-contents:
en: 6cf314a069ceb451
zh: 9adff678e9ecab3b
/2026-10-13-deepseek-search-thinking/declaration:
en: 6907136f28e48c90
zh: 02f8298485f3d8e7
/2026-10-13-deepseek-search-thinking/compatibility:
en: 2729e86f71451364
zh: af19f76f7fee238b
/2026-10-13-deepseek-search-thinking/verification:
en: ce8adf6d438b6b22
zh: 6c4a421051c99dce
/2026-10-13-deepseek-search-thinking/dev-note:
en: b75c8458928b72b9
zh: 003ba4e17b4b5269
@@ -0,0 +1,48 @@
---
description: "Records a persistence type transition and its compatibility acknowledgement."
kind: persistence-change
---
# 2026-10-13-deepseek-search-thinking
English | [中文](2026-10-13-deepseek-search-thinking.zh.md)
## Summary
Adds the optional `thinking` member to the logged DeepSeek search request body, recording that the auxiliary search turn disables thinking.
## Table of Contents
- [Declaration](#declaration)
- [Compatibility](#compatibility)
- [Verification](#verification)
- [Dev Note](#dev-note)
<a id="declaration"></a>
## Declaration
```yaml persistence-change
schemaVersion: 1
id: 2026-10-13-deepseek-search-thinking
baseline: false
changes:
- root: "event:web/deepseek-search-llm-request"
previous: "2026-09-11-initial"
after: "0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52"
decision: same-version
```
<a id="compatibility"></a>
## Compatibility
Existing records remain valid: absence means the request omitted the field and DeepSeek applied its default. The event is log-only; no reader replays or interprets the body for behavior, and the provider writes the member on every new request.
<a id="verification"></a>
## Verification
pnpm exec vitest run packages/web/web-search-deepseek/tests/deepseek.spec.ts: 59 tests passed.
<a id="dev-note"></a>
## Dev Note
None.
@@ -0,0 +1,231 @@
{
"formatVersion": 2,
"roots": [
{
"key": "event:web/deepseek-search-llm-request",
"kind": "event",
"event": "web/deepseek-search-llm-request",
"surface": false,
"digest": "0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52",
"schema": {
"root": 0,
"nodes": [
{
"kind": "object",
"properties": [
{
"name": "data",
"type": 1,
"optional": false
},
{
"name": "ignorable",
"type": 17,
"optional": true
},
{
"name": "seq",
"type": 4,
"optional": false
},
{
"name": "time",
"type": 4,
"optional": false
},
{
"name": "type",
"type": 18,
"optional": false
}
],
"indices": []
},
{
"kind": "object",
"properties": [
{
"name": "apiVersion",
"type": 2,
"optional": false
},
{
"name": "body",
"type": 3,
"optional": false
},
{
"name": "endpoint",
"type": 2,
"optional": false
}
],
"indices": []
},
{
"kind": "primitive",
"type": "string"
},
{
"kind": "object",
"properties": [
{
"name": "max_tokens",
"type": 4,
"optional": false
},
{
"name": "messages",
"type": 5,
"optional": false
},
{
"name": "model",
"type": 2,
"optional": false
},
{
"name": "thinking",
"type": 11,
"optional": true
},
{
"name": "tools",
"type": 13,
"optional": false
}
],
"indices": []
},
{
"kind": "primitive",
"type": "number"
},
{
"kind": "tuple",
"elements": [
{
"type": 6,
"optional": false,
"rest": false
}
]
},
{
"kind": "object",
"properties": [
{
"name": "content",
"type": 7,
"optional": false
},
{
"name": "role",
"type": 10,
"optional": false
}
],
"indices": []
},
{
"kind": "tuple",
"elements": [
{
"type": 8,
"optional": false,
"rest": false
}
]
},
{
"kind": "object",
"properties": [
{
"name": "text",
"type": 2,
"optional": false
},
{
"name": "type",
"type": 9,
"optional": false
}
],
"indices": []
},
{
"kind": "literal",
"value": "text"
},
{
"kind": "literal",
"value": "user"
},
{
"kind": "object",
"properties": [
{
"name": "type",
"type": 12,
"optional": false
}
],
"indices": []
},
{
"kind": "literal",
"value": "disabled"
},
{
"kind": "tuple",
"elements": [
{
"type": 14,
"optional": false,
"rest": false
}
]
},
{
"kind": "object",
"properties": [
{
"name": "max_uses",
"type": 4,
"optional": false
},
{
"name": "name",
"type": 15,
"optional": false
},
{
"name": "type",
"type": 16,
"optional": false
}
],
"indices": []
},
{
"kind": "literal",
"value": "web_search"
},
{
"kind": "literal",
"value": "web_search_20250305"
},
{
"kind": "literal",
"value": true
},
{
"kind": "literal",
"value": "web/deepseek-search-llm-request"
}
]
}
}
],
"types": []
}
@@ -0,0 +1,48 @@
---
description: "记录持久化类型更改及其兼容性确认。"
kind: persistence-change
---
# 2026-10-13-deepseek-search-thinking
[English](2026-10-13-deepseek-search-thinking.md) | 中文
## 概述
为记录的 DeepSeek 搜索请求体新增可选成员 `thinking`,记录辅助搜索回合关闭了思考模式。
## 目录
- [声明](#declaration)
- [兼容性](#compatibility)
- [验证](#verification)
- [开发备注](#dev-note)
<a id="declaration"></a>
## 声明
```yaml persistence-change
schemaVersion: 1
id: 2026-10-13-deepseek-search-thinking
baseline: false
changes:
- root: "event:web/deepseek-search-llm-request"
previous: "2026-09-11-initial"
after: "0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52"
decision: same-version
```
<a id="compatibility"></a>
## 兼容性
已有记录仍然有效:缺失表示请求省略了该字段,由 DeepSeek 使用默认值。该事件仅用于日志;没有读取方为行为回放或解释请求体,提供方在每个新请求中写入该成员。
<a id="verification"></a>
## 验证
pnpm exec vitest run packages/web/web-search-deepseek/tests/deepseek.spec.ts:59 个测试通过。
<a id="dev-note"></a>
## 开发备注
无。
@@ -15,8 +15,8 @@
en: 14c57f30e676f6e3
zh: b1a0ccf26fab3727
/session-persistence-formats/format-references:
en: 43a4a6600fa37a1a
zh: 72174fab8355c344
en: 17ef09dfc5a89073
zh: 59b8d60acb66c2dc
/session-persistence-formats/scope-and-evidence:
en: b220062139ddac1e
zh: 7c4c0efe05dafa9c
@@ -32,7 +32,7 @@ The index is generated from validated snapshots and the current writer constant.
| 1 | PR #3349 | [V1](v1.md) | [JSON](v1.schema.json) | 54 / 415 |
| 2 | `dsh-v0.1.3-alpha.2` | [V2](v2.md) | [JSON](v2.schema.json) | 56 / 435 |
| 3 | PR #4320 | [V3](v3.md) | [JSON](v3.schema.json) | 60 / 467 |
| 4 | Current checkout | [Current catalog](../../persistence-catalog.md) | [JSON](../../persistence-schema.json) | 65 / 612 |
| 4 | Current checkout | [Current catalog](../../persistence-catalog.md) | [JSON](../../persistence-schema.json) | 65 / 614 |
<!-- persistence-format-index:end -->
@@ -32,7 +32,7 @@ description: "查找从 V0 到工作区写入器版本的每个 Session 格式
| 1 | PR #3349 | [V1](v1.zh.md) | [JSON](v1.schema.json) | 54 / 415 |
| 2 | `dsh-v0.1.3-alpha.2` | [V2](v2.zh.md) | [JSON](v2.schema.json) | 56 / 435 |
| 3 | PR #4320 | [V3](v3.zh.md) | [JSON](v3.schema.json) | 60 / 467 |
| 4 | 当前工作树 | [当前目录](../../persistence-catalog.zh.md) | [JSON](../../persistence-schema.json) | 65 / 612 |
| 4 | 当前工作树 | [当前目录](../../persistence-catalog.zh.md) | [JSON](../../persistence-schema.json) | 65 / 614 |
<!-- persistence-format-index:end -->
+60 -28
View File
@@ -22045,7 +22045,7 @@
"kind": "event",
"event": "web/deepseek-search-llm-request",
"surface": false,
"digest": "cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331",
"digest": "0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52",
"schema": {
"root": 0,
"nodes": [
@@ -22059,7 +22059,7 @@
},
{
"name": "ignorable",
"type": 15,
"type": 17,
"optional": true
},
{
@@ -22074,7 +22074,7 @@
},
{
"name": "type",
"type": 16,
"type": 18,
"optional": false
}
],
@@ -22124,8 +22124,13 @@
"optional": false
},
{
"name": "tools",
"name": "thinking",
"type": 11,
"optional": true
},
{
"name": "tools",
"type": 13,
"optional": false
}
],
@@ -22195,11 +22200,26 @@
"kind": "literal",
"value": "user"
},
{
"kind": "object",
"properties": [
{
"name": "type",
"type": 12,
"optional": false
}
],
"indices": []
},
{
"kind": "literal",
"value": "disabled"
},
{
"kind": "tuple",
"elements": [
{
"type": 12,
"type": 14,
"optional": false,
"rest": false
}
@@ -22215,12 +22235,12 @@
},
{
"name": "name",
"type": 13,
"type": 15,
"optional": false
},
{
"name": "type",
"type": 14,
"type": 16,
"optional": false
}
],
@@ -22533,6 +22553,11 @@
"packages/goal/goal/src/types.ts:20"
]
},
{
"digest": "0b9b8facbe2c19773b3fb0ecc824ccbcc603d41b8f18069faa3807d449572fce",
"names": [],
"sources": []
},
{
"digest": "0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1",
"names": [],
@@ -22559,6 +22584,11 @@
"names": [],
"sources": []
},
{
"digest": "0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52",
"names": [],
"sources": []
},
{
"digest": "0d47a8f3d847243c4488e755ad4cab7a04ac5d4621b9c81865524cf3f4d8536f",
"names": [],
@@ -22967,15 +22997,6 @@
"names": [],
"sources": []
},
{
"digest": "2517ba143a271508d3ca35126d5aca8f7f1facf5aaddce4adf011832042fa2b9",
"names": [
"packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest"
],
"sources": [
"packages/web/web-search-deepseek/src/provider.ts:55"
]
},
{
"digest": "254dce209e735f9cb6f6b7aec0354712b1611759ec02af4d35a96f2081e666f6",
"names": [],
@@ -23229,6 +23250,13 @@
"names": [],
"sources": []
},
{
"digest": "37ff65426bcf130f045d3a59ef2a4648eb170cd30280cbd024108a2e9b4401d1",
"names": [],
"sources": [
"packages/web/web-search-deepseek/src/provider.ts:82"
]
},
{
"digest": "383cf73ae4748e5beb281ae74857ba1ffb92ae01075b9fbf51af78b666007a8f",
"names": [],
@@ -24579,13 +24607,6 @@
"names": [],
"sources": []
},
{
"digest": "930a6567a10bb62ddd157bd8abdf4b182810c8c3b49d91309b3b009a5fed9731",
"names": [],
"sources": [
"packages/web/web-search-deepseek/src/provider.ts:61"
]
},
{
"digest": "930c1cd289def119d443e19dd90008916bf035f0a4d23e07241e7f050f2b89b7",
"names": [
@@ -24740,6 +24761,13 @@
"names": [],
"sources": []
},
{
"digest": "9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee",
"names": [],
"sources": [
"packages/web/web-search-deepseek/src/provider.ts:61"
]
},
{
"digest": "9d80129e13edfb6feb03ed327e6085c6ef60b97ad074244b2f5fd4667424a6a4",
"names": [],
@@ -24987,6 +25015,15 @@
"names": [],
"sources": []
},
{
"digest": "abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c",
"names": [
"packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest"
],
"sources": [
"packages/web/web-search-deepseek/src/provider.ts:55"
]
},
{
"digest": "ad0c38a0adb82a94c925456df41586d9b5f9202fca18593eae2213d4445b4585",
"names": [],
@@ -25478,11 +25515,6 @@
"packages/core/tools/src/types.ts:21"
]
},
{
"digest": "cf6e3aaf1e2de6480aa0157730a41b9a492108a55304100b0f7e112711dd4331",
"names": [],
"sources": []
},
{
"digest": "cffcdc19881ab61ec0a9ce18743996f7ac44ac8889f34dfac36ae745574aa22f",
"names": [
+4 -4
View File
@@ -3,8 +3,8 @@
# After editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/subsystems/web.md
/web-access:
en: f1a28f6a0c2e2a7a
zh: 8a6cdddde6d75acc
en: 86d12e6e81fb63b8
zh: 52ed66dcacaf6d85
/web-access/why-one-capability-has-two-operations:
en: 380da3cd0aabd52b
zh: 1317c26089c3ab07
@@ -15,8 +15,8 @@
en: b96bcdf42ced9eab
zh: aa927e2450238557
/web-access/provider-availability:
en: 84e3d6fdb0b2a1d7
zh: 6175a9d011152d3d
en: da78eb96d684ad47
zh: 4b726cc04c92ef13
/web-access/fetch-network-policy:
en: 261fce9249be8b2b
zh: bf6abf77679aca6d
+2 -2
View File
@@ -2,7 +2,7 @@
English | [中文](web.zh.md)
The web access seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md) that spans **two operations** (search and fetch) on one `ctx.web` service, split across packages: Service Definition ([dsh-web](../../packages/web/web), `ctx.web` + the provider registries), Service Providers ([dsh-web-search-exa](../../packages/web/web-search-exa), [dsh-web-search-perplexity](../../packages/web/web-search-perplexity), [dsh-web-search-deepseek](../../packages/web/web-search-deepseek), [dsh-web-fetch-http](../../packages/web/web-fetch-http)), and Consumer ([dsh-tool-web](../../packages/web/tool-web), the `web_search`/`web_fetch` tool schemas). Web is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A search-provider swap does not change how the model asks for a query, and a fetch-provider swap does not change how the model asks for a URL.
The web access seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md) that spans **two operations** (search and fetch) on one `ctx.web` service, split across packages: Service Definition ([dsh-web](../../packages/web/web), `ctx.web` + the provider registries), Service Providers ([dsh-web-search-exa](../../packages/web/web-search-exa), [dsh-web-search-perplexity](../../packages/web/web-search-perplexity), [dsh-web-search-deepseek](../../packages/web/web-search-deepseek), [dsh-web-deepseek-api](../../packages/web/web-deepseek-api), [dsh-web-fetch-http](../../packages/web/web-fetch-http)), and Consumer ([dsh-tool-web](../../packages/web/tool-web), the `web_search`/`web_fetch` tool schemas). Web is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A search-provider swap does not change how the model asks for a query, and a fetch-provider swap does not change how the model asks for a URL.
Source: [`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts)
@@ -122,7 +122,7 @@ type WebFetchBody =
A provider's `available(): boolean` is a cheap LOCAL check (credential presence, parseable config) and **must not make network calls**. It is an input to execution-time selection, not a health system: `search()`/`fetch()` read it to pick a usable provider, and a selection failure surfaces as the structured `WebError` the caller routes on — which carries the branchable detail (the missing id or ambiguous candidate set) in its code and message.
Selection never depends on registration, config, or HMR order: a capability has an explicit provider id (config `searchProvider`/`fetchProvider`, or the matching env var feeding the same field), or auto-selects when exactly one usable provider is registered; multiple usable providers with no configured id is `WEB_PROVIDER_AMBIGUOUS`, not first-wins.
Selection never depends on registration, config, or HMR order: a capability has an explicit provider id (config `searchProvider`/`fetchProvider`, or the matching env var feeding the same field), or auto-selects when exactly one usable provider is registered; multiple usable providers with no configured id is `WEB_PROVIDER_AMBIGUOUS`, not first-wins. Each operation reads the configured id when it runs, so a saved settings change applies to the next search or fetch without remounting `ctx.web`.
## Fetch network policy
+2 -2
View File
@@ -2,7 +2,7 @@
[English](web.md) | 中文
Web 访问 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md),在同一个 `ctx.web` 服务上横跨**两项操作**(search 与 fetch),并拆分到多个包:Service Definition([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、Service Provider([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-http](../../packages/web/web-fetch-http))与 Consumer([dsh-tool-web](../../packages/web/tool-web),即 `web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.zh.md) 中。更换 search 提供方不会改变模型提交查询的方式,更换 fetch 提供方也不会改变模型请求 URL 的方式。
Web 访问 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md),在同一个 `ctx.web` 服务上横跨**两项操作**(search 与 fetch),并拆分到多个包:Service Definition([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、Service Provider([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-deepseek-api](../../packages/web/web-deepseek-api)、[dsh-web-fetch-http](../../packages/web/web-fetch-http))与 Consumer([dsh-tool-web](../../packages/web/tool-web),即 `web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.zh.md) 中。更换 search 提供方不会改变模型提交查询的方式,更换 fetch 提供方也不会改变模型请求 URL 的方式。
源码:[`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts)
@@ -122,7 +122,7 @@ type WebFetchBody =
提供方的 `available(): boolean` 是一个廉价的本地检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择提供方的输入,而不是健康检查系统:`search()`/`fetch()` 会读取它来选择可用的提供方。选择失败时,调用方会收到可据以分支处理的结构化 `WebError`;其错误代码和消息会说明缺失的 id 或存在歧义的候选集。
选择从不依赖注册顺序、配置顺序或 HMR(热模块替换)顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或填充同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;如果存在多个可用提供方却未配置 id,则抛出 `WEB_PROVIDER_AMBIGUOUS`,而不会选用最先注册的提供方。
选择从不依赖注册顺序、配置顺序或 HMR(热模块替换)顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或填充同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;如果存在多个可用提供方却未配置 id,则抛出 `WEB_PROVIDER_AMBIGUOUS`,而不会选用最先注册的提供方。每次操作在执行时读取配置的 id,因此保存的设置变更无需重新挂载 `ctx.web` 即对下一次搜索或抓取生效。
## 抓取网络策略
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@deepseek-ai/dsh-root",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"license": "MIT",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-acp",
"description": "Automation-only Agent Client Protocol server for driving DeepSeek Harness agents over JSON-RPC stdio",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-account-controller",
"description": "Expose safe account operations over authenticated Remote",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-gateway",
"description": "Typert Remote Host dispatcher and Client API endpoint",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-job-controller",
"description": "Job Remote observation stream and the reference-counted client job-output service",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-remote-access",
"description": "Method-level Remote access control for non-owner Peers and the per-Peer access snapshot",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-remotes",
"description": "Remote BFF assembly for application-selected Host capabilities",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-session-controller",
"description": "Session Remote commands, cold reads, and live control transport",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-settings-controller",
"description": "Remote owner for the configuration surfaces over the settings-domain seams",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-terminal-controller",
"description": "Session-owned interactive terminals with shell discovery, screen recovery and typed Remote control",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-workspace-controller",
"description": "Workspace Remote commands and reconnect-safe state transport",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-api-workspace-files",
"description": "Workspace file service and Client resource provider: bounded reads, directory listing, and live metadata over the workspaceFiles Remote namespace",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-attachment-local",
"description": "Private content-addressed DSH_HOME attachment storage",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-attachment",
"description": "Durable immutable attachment storage seam for the DeepSeek Harness",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-app-boot",
"description": "Shared boot glue for the app bins: .env loading, fail-loud Loader guards, snapshot-aware config resolution, and the Loader boot sequence",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-cmdline",
"description": "Immutable command-line handoff from a dsh launcher to any app plugin that injects cmdlineArgs",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-config-editor",
"description": "Persist plugin configuration through profile patches and Loader reconciliation",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-hmr",
"description": "Coordinated module and profile configuration hot reload",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-plugin-manager",
"description": "Current-profile plugin and bundle management shared by dsh CLI, Web and agent tools",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-plugin-market",
"description": "Configured plugin market indexes for the Web Discover page and the plugin_market agent tool",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-browser-use",
"description": "Exclusive named browser-use provider registration",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-acp-app",
"description": "The dsh ACP profile bundle: automation-only JSON-RPC stdio and process lifecycle over dsh-base",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+8 -1
View File
@@ -461,7 +461,9 @@
# resolves and validates every destination, and pins every actual connection.
# Search is a full auxiliary model request with server-side retrieval, so this
# shipped DeepSeek route gets 60s while the provider-neutral tool default
# remains 30s.
# remains 30s. The DeepSeek Search and Fetch APIs register as
# deepseek-search-api and deepseek-fetch-api with the same credential; the Web
# search settings switch selects both in place of these defaults.
- id: web
name: '@deepseek-ai/dsh-web'
config:
@@ -473,6 +475,11 @@
config:
apiKeyEnv: DEEPSEEK_API_KEY
- id: web-deepseek-api
name: '@deepseek-ai/dsh-web-deepseek-api'
config:
apiKeyEnv: DEEPSEEK_API_KEY
- id: web-fetch-http
name: '@deepseek-ai/dsh-web-fetch-http'
+3 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-base",
"description": "The shared dsh core as a profile bundle: the first patch layer of base-backed profiles, inserting core rows over the empty profile root",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -127,7 +127,8 @@
"@deepseek-ai/dsh-settings": "workspace:*",
"@deepseek-ai/dsh-otel": "workspace:*",
"@deepseek-ai/dsh-working-directory": "workspace:*",
"@deepseek-ai/dsh-tool-working-directory": "workspace:*"
"@deepseek-ai/dsh-tool-working-directory": "workspace:*",
"@deepseek-ai/dsh-web-deepseek-api": "workspace:*"
},
"peerDependencies": {
"@deepseek-ai/cordis": "workspace:~"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-headless",
"description": "The dsh one-shot bundle: a direct core Agent/Session runner over dsh-base with no Host, HTTP, or browser layer",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-sdk-app",
"description": "The dsh SDK profile bundle: stdio JSON-RPC serving and process lifecycle over dsh-base",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-sdk-minimal",
"description": "The standalone minimal SDK profile bundle: JSON-RPC, one DeepSeek adapter, persistent shell, and JSONL sessions",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+3
View File
@@ -412,6 +412,9 @@
- id: ui-model-selection
name: '@deepseek-ai/dsh-client-ui-model-selection'
- id: ui-deepseek-model-label-1017
name: '@deepseek-ai/dsh-client-ui-deepseek-model-label-1017'
- id: ui-permission
name: '@deepseek-ai/dsh-client-ui-permission-presets'
+2 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-web-app",
"description": "The dsh browser-surface bundle: the web patch layer over dsh-base plus the runtime glue plugin (frontend dist serving, bash runtime variables, URL line)",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -90,6 +90,7 @@
"@deepseek-ai/dsh-client-ui-layout": "workspace:*",
"@deepseek-ai/dsh-client-ui-message-feedback": "workspace:*",
"@deepseek-ai/dsh-client-ui-model-selection": "workspace:*",
"@deepseek-ai/dsh-client-ui-deepseek-model-label-1017": "workspace:*",
"@deepseek-ai/dsh-client-ui-open-in-app": "workspace:*",
"@deepseek-ai/dsh-client-ui-permission-presets": "workspace:*",
"@deepseek-ai/dsh-client-ui-plan": "workspace:*",
+2 -2
View File
@@ -15,8 +15,8 @@
en: 1eb35b015a6c423f
zh: a8a3dceee2c9e943
/client-web-gui-browser-half/packages:
en: 3026f68770598c24
zh: e479959e605faea0
en: 4d88ec16156593e5
zh: 745b3aab722ca17d
/client-web-gui-browser-half/related-documentation:
en: d1d506e68fab7333
zh: 1a90fe6f3f8f24a9
+1
View File
@@ -68,6 +68,7 @@ The kernel packages boot and serve the page; the UI feature packages present it.
| [`ui-jobs/`](ui-jobs/README.md) | Lists this session's background jobs with on-demand streaming record panels | — |
| [`ui-schedule/`](ui-schedule/README.md) | Lists the current Session's active reminders in a read-only header catalog | — |
| [`ui-model-selection/`](ui-model-selection/README.md) | Provides model selection in conversation surfaces | — |
| [`ui-deepseek-model-label-1017/`](ui-deepseek-model-label-1017/README.md) | Adds the temporary 1017 badge to official DeepSeek Flash model labels | — |
| [`ui-permission-presets/`](ui-permission-presets/README.md) | Configures default permissions and switches the current session's access | — |
| [`ui-plan/`](ui-plan/README.md) | Presents active plan-mode status and its exit control | — |
| [`ui-settings-plugins/`](ui-settings-plugins/README.md) | Owns the Built-in plugins settings section shell and its tab extension point | — |
+1
View File
@@ -68,6 +68,7 @@ kind: "package-group"
| [`ui-jobs/`](ui-jobs/README.zh.md) | 列出本会话的后台任务,并提供按需展开的流式输出面板 | — |
| [`ui-schedule/`](ui-schedule/README.zh.md) | 在只读标题栏目录中列出当前会话中生效的提醒 | — |
| [`ui-model-selection/`](ui-model-selection/README.zh.md) | 在对话界面中提供模型选择 | — |
| [`ui-deepseek-model-label-1017/`](ui-deepseek-model-label-1017/README.zh.md) | 为官方 DeepSeek Flash 模型名称添加临时的 1017 角标 | — |
| [`ui-permission-presets/`](ui-permission-presets/README.zh.md) | 配置默认权限并切换当前会话的访问模式 | — |
| [`ui-plan/`](ui-plan/README.zh.md) | 展示生效中的 plan mode 状态及其退出控件 | — |
| [`ui-settings-plugins/`](ui-settings-plugins/README.zh.md) | 负责「内置插件」设置分区壳及其标签页扩展点 | — |
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-connection",
"description": "Authenticated RPC transport and generation lifecycle",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-file-upload",
"description": "Agent-scoped browser file upload, streaming intake, and staged receipt service",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-hmr",
"description": "Web client graph synchronization and rebuilt-bundle reload transport",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-locale",
"description": "Locale plugin: Host-backed preference, extensible language catalog, browser fallback, and typed built-in dictionaries",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-modules",
"description": "Client module system, dual-face: node half composes the __DSH_BOOT__ entry graph (incremental dsh.client scan, bundle route, index tap, webPlugins service); browser half is the lazy-CJS module table the vendored cordis Loader consumes as its internal seam",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-product-analytics",
"description": "Desktop product event collection and authenticated Host reporting",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-resources",
"description": "Unified client resource model: protocol-registered providers turn URL addresses into live values, consumed through the useResource global standard hook",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-shortcuts",
"description": "Application keyboard command registry and physical-key routing",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-store",
"description": "React-free observable and snapshot-store contracts with the shared Zustand/Immer engine",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-ui-agent-preset",
"description": "Agent-preset surfaces: the default for later sessions, this session's seat, and the composition editor",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-ui-approval",
"description": "Approval composer takeover over the scoped Remote Event waterfall",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-ui-attachment",
"description": "Dynamic attachment presentation plugin for conversation input, message-image, and trajectory image slots",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-ui-brand-official",
"description": "Official DeepSeek Harness brand occupants for the Web client's sidebar slots",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-ui-chat",
"description": "Chat Conversation target, node definitions, renderers, and details surface",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-ui-commands",
"description": "Client command surface: global directory cache, '/' source, three command UI kinds, popupSelect registry",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-client-ui-conversation",
"description": "Target-neutral Conversation assembly, shell, composer, queue, and view navigation",
"version": "0.2.1-rc.1",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
@@ -0,0 +1,37 @@
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
# After editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-deepseek-model-label-1017/README.md
/:
en: 21f43d0c704c3668
zh: 0497e58bb871e2c4
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017:
en: aa0cd60e16297d9f
zh: 882cee782592c56b
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/summary:
en: 708be526d5758c04
zh: 136b968ae71c9657
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/table-of-contents:
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/use-this-package:
en: a6d5fcecfa93935b
zh: 8ae2809a06910c52
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/understand-the-implementation:
en: ca1d0c5db1b819a0
zh: 960e8db56fa5987e
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/further-exploration:
en: 2885099078047d38
zh: d7de1db3f1ba0a50
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/model-experience:
en: 16ab1406c87419d7
zh: 01bce720d29ab2e8
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/model-experience/kv-cache-effect:
en: b7599ec8e5b66e58
zh: a21537863b9b6e3a
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/known-limitations-and-deferred-work:
en: bce774c6d8ae9428
zh: b9d7019acc7bbc19
/deepseek-ai-dsh-client-ui-deepseek-model-label-1017/known-limitations-and-deferred-work/dev-note:
en: e67f633dc6fe7773
zh: 8ec3e73528ddb1a6
@@ -0,0 +1,91 @@
---
description: "Show a temporary 1017 badge beside DeepSeek Flash in the composer model selector."
kind: "package-reference"
---
# @deepseek-ai/dsh-client-ui-deepseek-model-label-1017
English | [中文](README.zh.md)
## Summary
This package shows `1017` beside `DeepSeek-V4.1-Flash` in the composer model selector. It covers the official API-key and account routes while preserving their catalog names and request IDs. Disable it to restore plain model names.
## Table of Contents
- [Use this package](#use-this-package)
- [Understand the implementation](#understand-the-implementation)
- [Further Exploration](#further-exploration)
- [Model Experience](#model-experience)
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
- [Dev Note](#dev-note)
-----
<a id="use-this-package"></a>
## Use this package
The Web bundle includes this plugin, including when Desktop uses that bundle. It has no configuration fields.
The badge appears only when the provider is `deepseek-official` or `deepseek-account`, the model ID is `deepseek-flash`, and the catalog name is exactly `DeepSeek-V4.1-Flash`. Other names and providers keep their catalog text. The input button, current-model menu row, and model options share the badge.
Disable the following row through a profile patch to restore the catalog name:
```yaml
- id: ui-deepseek-model-label-1017
disabled: true
```
-----
<a id="understand-the-implementation"></a>
## Understand the implementation
<details>
<summary>Implementation internals — click to expand</summary>
The browser entry contributes to the existing `conversation.input.model.label` slot through `ctx.slots.inject()`. Its component derives the label from owner props and uses the shared `Tag` primitive; it owns no cache, subscription, network request, or model-selection state. Registration and dictionaries leave with the plugin. The Host entry only makes the browser package available to the Loader.
</details>
-----
<a id="further-exploration"></a>
## Further Exploration
These packages own the selector and its two directory sources.
- [Model selection](../ui-model-selection/README.md) — label placement and selection behavior.
- [DeepSeek transport](../../llm/llm-deepseek/README.md) — built-in model catalog.
- [DeepSeek account](../../llm/llm-deepseek-account/README.md) — account-provided model directory.
-----
<a id="model-experience"></a>
## Model Experience
None, as the package only decorates browser labels without changing model requests or Session events.
#### KV Cache effect
None; provider requests and their cached prefixes are unchanged.
## Known Limitations and Deferred Work
<a id="known-limitations-and-deferred-work"></a>
The fixed release marker has these presentation limits:
- The settings editor, `/model` command, trigger accessibility text, and existing tooltip keep the original catalog name.
- This package occupies a `single` slot. Another model-label plugin at the same priority conflicts; the two presentations do not compose automatically.
- The `1017` marker is fixed client presentation, not a server capability assertion. Remove this package and its bundle row when structured release labels replace it.
<a id="dev-note"></a>
### Dev Note
<details>
<summary>Working context for maintainers — click to expand</summary>
None.
</details>
@@ -0,0 +1,91 @@
---
description: "在输入框的模型选择器中为 DeepSeek Flash 显示临时的 1017 角标。"
kind: "package-reference"
---
# @deepseek-ai/dsh-client-ui-deepseek-model-label-1017
[English](README.md) | 中文
## 概述
本包在输入框模型选择器的 `DeepSeek-V4.1-Flash` 旁显示 `1017`。它覆盖官方 API Key 和账号通道,保留目录名称和请求 ID。停用后恢复纯模型名称。
## 目录
- [使用本包](#use-this-package)
- [理解实现](#understand-the-implementation)
- [进一步探索](#further-exploration)
- [模型体验](#model-experience)
- [已知限制与延期工作](#known-limitations-and-deferred-work)
- [开发备注](#dev-note)
-----
<a id="use-this-package"></a>
## 使用本包
Web bundle 包含本插件,桌面端使用该 bundle 时也会加载。本包没有配置字段。
只有提供方为 `deepseek-official` 或 `deepseek-account`、模型 ID 为 `deepseek-flash`,且目录名称恰好为 `DeepSeek-V4.1-Flash` 时才显示角标。其他名称和提供方保留目录文字。输入框按钮、当前模型菜单行和模型选项共用这个角标。
通过 profile patch 停用以下条目即可恢复目录名称:
```yaml
- id: ui-deepseek-model-label-1017
disabled: true
```
-----
<a id="understand-the-implementation"></a>
## 理解实现
<details>
<summary>内部实现 — 点击展开</summary>
浏览器入口通过 `ctx.slots.inject()` 向已有的 `conversation.input.model.label` slot 注册组件。组件根据 owner props 派生标签,使用共享 `Tag` 基元,不拥有缓存、订阅、网络请求或模型选择状态。注册和字典随插件卸载。Host 入口仅让 Loader 能加载浏览器包。
</details>
-----
<a id="further-exploration"></a>
## 进一步探索
以下包分别拥有选择器和两个目录来源。
- [模型选择](../ui-model-selection/README.zh.md) — 名称显示位置与选择行为。
- [DeepSeek 传输](../../llm/llm-deepseek/README.zh.md) — 内置模型目录。
- [DeepSeek 账号](../../llm/llm-deepseek-account/README.zh.md) — 账号提供的模型目录。
-----
<a id="model-experience"></a>
## 模型体验
无,本包只装饰浏览器标签,不改变模型请求或 Session 事件。
#### KV Cache effect
无;提供方请求及其缓存前缀保持不变。
## 已知限制与延期工作
<a id="known-limitations-and-deferred-work"></a>
固定的版本标记有以下显示限制:
- 设置编辑器、`/model` 命令、触发按钮的无障碍文字及已有提示保留原始目录名称。
- 本包占用 `single` slot。其他模型名称插件若使用相同优先级会冲突,两种展示不会自动组合。
- `1017` 是固定的客户端展示,不是服务端能力声明。结构化版本标签替代它时,移除本包及其 bundle 条目。
<a id="dev-note"></a>
### 开发备注
<details>
<summary>维护者工作上下文 — 点击展开</summary>
无。
</details>
@@ -0,0 +1,66 @@
{
"name": "@deepseek-ai/dsh-client-ui-deepseek-model-label-1017",
"description": "Temporary 1017 release badge for official DeepSeek Flash model labels",
"version": "0.2.1-rc.2",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
"directory": "packages/client/ui-deepseek-model-label-1017"
},
"type": "module",
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
"exports": {
".": {
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./client": {
"types": "./lib/types/client/index.d.ts",
"default": "./lib/client.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json",
"./locale/*.json": "./locale/*.json"
},
"dsh": {
"client": {
"inject": [
"@deepseek-ai/dsh-client-ui-model-selection",
"@deepseek-ai/dsh-client-ui-renderer",
"@deepseek-ai/dsh-client-locale"
],
"platform": "web"
}
},
"scripts": {
"bundle": "tsdown",
"watch": "tsdown --watch"
},
"license": "MIT",
"peerDependencies": {
"@deepseek-ai/cordis": "workspace:~"
},
"devDependencies": {
"@deepseek-ai/cordis": "workspace:~",
"@deepseek-ai/dsh-client-locale": "workspace:*",
"@deepseek-ai/dsh-client-ui-model-selection": "workspace:*",
"@deepseek-ai/dsh-client-ui-renderer": "workspace:*",
"@deepseek-ai/dsh-client-ui-primitives": "workspace:*",
"@deepseek-ai/dsh-client-ui-slots": "workspace:*",
"@deepseek-ai/dsh-client-test-runtime": "workspace:*",
"@deepseek-ai/dsh-session": "workspace:*",
"@testing-library/react": "^16.3.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"files": [
"locale/*.json",
"lib/index.js",
"lib/client.js",
"lib/types/**/*.d.ts"
]
}
@@ -0,0 +1,7 @@
.label {
display: inline-flex;
align-items: center;
gap: 4px;
vertical-align: baseline;
white-space: nowrap;
}
@@ -0,0 +1,22 @@
/** Display-only release marking; the catalog and selected route remain unchanged. */
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
import type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'
import { Tag } from '@deepseek-ai/dsh-client-ui-primitives'
import css from './DeepSeekModelLabel.module.css'
const MODEL_NAME = 'DeepSeek-V4.1-Flash'
/**
* Render the fixed 1017 release label for recognized official Flash entries.
* @param props - Provider and model identity plus the badge dictionary.
* @returns The base name with a badge, or the untouched catalog name.
*/
export function DeepSeekModelLabel({ provider, model, t }:
PropsRuntime<'conversation.input.model.label'> & PropsLocale<'deepseek-model-label-1017'>,
) {
const official = provider.id === 'deepseek-account' || provider.id === 'deepseek-official'
if (!official || model.id !== 'deepseek-flash' || model.name !== MODEL_NAME) return model.name
return <span className={css.label}>
<span>{model.name}</span>{' '}<Tag tone="info">{t('badge.label')}</Tag>
</span>
}
@@ -0,0 +1,29 @@
/** Temporary 1017 badge for the two official DeepSeek model routes. */
import type { Context } from '@deepseek-ai/cordis'
import type {} from '@deepseek-ai/dsh-client-locale/client'
import type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
import { DeepSeekModelLabel } from './DeepSeekModelLabel.tsx'
import { en, zh, type LabelKey } from './locales.ts'
declare module '@deepseek-ai/dsh-client-ui-slots' {
interface LocaleNamespaceMap {
/** The temporary model release badge. */
'deepseek-model-label-1017': LabelKey
}
}
/** Required services: model-label registration and localized badge text. */
export const inject = ['slots', 'locale']
/**
* Decorate existing model labels while their declaring slot is mounted.
* @param ctx - Client plugin context owning the dictionaries and registration.
*/
export function apply(ctx: Context): void {
const namespace = 'deepseek-model-label-1017'
ctx.effect(() => ctx.locale.register(namespace, { zh, en }), 'deepseek-model-label-1017: dictionaries')
ctx.slots.inject('conversation.input.model.label', () => ctx.slots.register({
name: 'conversation.input.model.label', locale: namespace,
}, DeepSeekModelLabel))
}
@@ -0,0 +1,10 @@
/** Localized label of the fixed release marker. */
/** Simplified Chinese badge copy. */
export const zh = { 'badge.label': '1017' }
/** Keys owned by the release-label namespace. */
export type LabelKey = keyof typeof zh
/** English badge copy. */
export const en: Record<LabelKey, string> = { 'badge.label': '1017' }
@@ -0,0 +1,4 @@
declare module '*.module.css' {
const classes: Record<string, string>
export default classes
}
@@ -0,0 +1,4 @@
/** Loader entry for the temporary DeepSeek model-label presentation. */
/** Mount the browser entry through the package's client declaration. */
export function apply(): void {}
Loaded 100 of 456 files, more files were not shown because too many files have changed in this diff. Show more