dsh-plugin-dev-kb 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/CHANGELOG.md +186 -178
  2. package/README.en.md +172 -172
  3. package/README.md +183 -183
  4. package/kb/INDEX.md +236 -234
  5. package/kb/README.md +88 -88
  6. package/kb/extra/AGENTS.md +77 -77
  7. package/kb/extra/deepseek-llm-api-wire-extensions.md +162 -162
  8. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +162 -162
  9. package/kb/extra/defensive-patterns/package-surface.md +233 -232
  10. package/kb/extra/defensive-patterns/package-surface.zh.md +233 -232
  11. package/kb/extra/defensive-patterns/remote-and-api.md +117 -117
  12. package/kb/extra/defensive-patterns/remote-and-api.zh.md +117 -117
  13. package/kb/extra/development.md +221 -221
  14. package/kb/extra/development.zh.md +228 -228
  15. package/kb/extra/event-producer-consumer.md +133 -123
  16. package/kb/extra/event-producer-consumer.zh.md +135 -125
  17. package/kb/extra/module-graph.md +1961 -1888
  18. package/kb/extra/module-graph.zh.md +1963 -1890
  19. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.md +60 -0
  20. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.zh.md +60 -0
  21. package/kb/extra/persistence-changes/README.md +92 -92
  22. package/kb/extra/persistence-changes/README.zh.md +92 -92
  23. package/kb/extra/persistence-changes/historical-formats/README.md +75 -75
  24. package/kb/extra/persistence-changes/historical-formats/README.zh.md +75 -75
  25. package/kb/extra/persistence-changes/releases/README.md +103 -103
  26. package/kb/extra/persistence-changes/releases/README.zh.md +103 -103
  27. package/kb/extra/rescope.md +55 -55
  28. package/kb/extra/rescope.zh.md +55 -55
  29. package/kb/extra/subsystems/boot.md +631 -621
  30. package/kb/extra/subsystems/boot.zh.md +631 -621
  31. package/kb/extra/subsystems/computer-use.md +179 -137
  32. package/kb/extra/subsystems/computer-use.zh.md +179 -137
  33. package/kb/extra/subsystems/extensions.md +387 -384
  34. package/kb/extra/subsystems/extensions.zh.md +387 -384
  35. package/kb/extra/subsystems/feedback.md +418 -400
  36. package/kb/extra/subsystems/feedback.zh.md +418 -400
  37. package/kb/extra/subsystems/forge.md +2169 -1226
  38. package/kb/extra/subsystems/forge.zh.md +2171 -1226
  39. package/kb/extra/subsystems/liveshare.md +167 -158
  40. package/kb/extra/subsystems/liveshare.zh.md +167 -158
  41. package/kb/extra/subsystems/mcp.md +237 -234
  42. package/kb/extra/subsystems/mcp.zh.md +237 -234
  43. package/kb/extra/subsystems/office-kit.md +122 -0
  44. package/kb/extra/subsystems/office-kit.zh.md +122 -0
  45. package/kb/extra/subsystems/working-directory.md +95 -64
  46. package/kb/extra/subsystems/working-directory.zh.md +95 -64
  47. package/kb/extra/subsystems/worktrees.md +187 -127
  48. package/kb/extra/subsystems/worktrees.zh.md +187 -127
  49. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.md +21 -21
  50. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.zh.md +21 -21
  51. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.md +18 -0
  52. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.zh.md +18 -0
  53. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.md +18 -0
  54. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.zh.md +18 -0
  55. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.md +34 -0
  56. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.zh.md +34 -0
  57. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.md +49 -0
  58. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.zh.md +49 -0
  59. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.md +36 -0
  60. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.zh.md +36 -0
  61. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.md +26 -0
  62. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.zh.md +26 -0
  63. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.md +22 -0
  64. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.zh.md +22 -0
  65. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.md +21 -0
  66. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.zh.md +21 -0
  67. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.md +23 -0
  68. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.zh.md +23 -0
  69. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.md +20 -0
  70. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.zh.md +20 -0
  71. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.md +18 -0
  72. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.zh.md +18 -0
  73. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.md +23 -0
  74. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.zh.md +23 -0
  75. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.md +35 -0
  76. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.zh.md +35 -0
  77. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.md +26 -0
  78. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.zh.md +26 -0
  79. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.md +26 -0
  80. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.zh.md +26 -0
  81. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.md +19 -0
  82. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.zh.md +19 -0
  83. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.md +26 -0
  84. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.zh.md +26 -0
  85. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.md +22 -0
  86. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.zh.md +22 -0
  87. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.md +25 -0
  88. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.zh.md +25 -0
  89. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.md +48 -0
  90. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.zh.md +48 -0
  91. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.md +45 -0
  92. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.zh.md +45 -0
  93. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.md +19 -0
  94. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.zh.md +19 -0
  95. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.md +17 -0
  96. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.zh.md +17 -0
  97. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.md +27 -0
  98. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.zh.md +27 -0
  99. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.md +20 -0
  100. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.zh.md +20 -0
  101. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.md +19 -0
  102. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.zh.md +19 -0
  103. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.md +18 -0
  104. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.zh.md +18 -0
  105. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.md +41 -0
  106. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.zh.md +41 -0
  107. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.md +21 -0
  108. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.zh.md +21 -0
  109. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.md +29 -0
  110. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.zh.md +29 -0
  111. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.md +25 -0
  112. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.zh.md +25 -0
  113. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.md +31 -0
  114. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.zh.md +31 -0
  115. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.md +24 -0
  116. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.zh.md +24 -0
  117. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.md +24 -0
  118. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.zh.md +24 -0
  119. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.md +19 -0
  120. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.zh.md +19 -0
  121. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.md +15 -0
  122. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.zh.md +15 -0
  123. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.md +28 -0
  124. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.zh.md +28 -0
  125. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.md +36 -0
  126. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.zh.md +36 -0
  127. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.md +22 -0
  128. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.zh.md +22 -0
  129. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.md +31 -0
  130. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.zh.md +31 -0
  131. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.md +18 -0
  132. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.zh.md +18 -0
  133. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.md +30 -0
  134. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.zh.md +30 -0
  135. package/kb/extra/web-styling.md +57 -57
  136. package/kb/extra/web-styling.zh.md +57 -57
  137. package/kb/meta/search-index.json +4508 -3980
  138. package/kb/meta/source.json +18 -18
  139. package/kb/site/develop/practice/llm-adapter.md +192 -192
  140. package/kb/site/en/develop/practice/llm-adapter.md +192 -192
  141. package/kb/site/en/guide/desktop-uninstall-cleanup.md +63 -0
  142. package/kb/site/en/guide/plugin-market.md +153 -151
  143. package/kb/site/en/guide/providers.md +234 -234
  144. package/kb/site/en/guide/quickstart.md +35 -34
  145. package/kb/site/en/reference/capability-seams.md +789 -767
  146. package/kb/site/en/reference/config-catalog.md +5432 -5128
  147. package/kb/site/en/reference/cookbook/adding-a-package.md +175 -175
  148. package/kb/site/en/reference/cookbook/adding-a-tool.md +105 -104
  149. package/kb/site/en/reference/cookbook/extension-cookbook.md +178 -135
  150. package/kb/site/en/reference/cordis-api/context.md +373 -369
  151. package/kb/site/en/reference/cordis-api/fiber.md +457 -433
  152. package/kb/site/en/reference/cordis-api/inherited.md +44 -44
  153. package/kb/site/en/reference/cordis-api/service.md +118 -107
  154. package/kb/site/en/reference/experimental-persistence-catalog.md +36 -23
  155. package/kb/site/en/reference/index.md +174 -174
  156. package/kb/site/en/reference/persistence-catalog.md +9453 -9432
  157. package/kb/site/en/reference/subsystems/compaction.md +288 -288
  158. package/kb/site/en/reference/subsystems/core.md +1172 -1171
  159. package/kb/site/en/reference/subsystems/credentials.md +526 -497
  160. package/kb/site/en/reference/subsystems/filesystem.md +708 -708
  161. package/kb/site/en/reference/subsystems/index.md +82 -82
  162. package/kb/site/en/reference/subsystems/llm-streaming.md +1290 -1288
  163. package/kb/site/en/reference/subsystems/lsp.md +230 -206
  164. package/kb/site/en/reference/subsystems/persistence.md +451 -432
  165. package/kb/site/en/reference/subsystems/plan.md +91 -91
  166. package/kb/site/en/reference/subsystems/ptc-runtime.md +295 -261
  167. package/kb/site/en/reference/subsystems/sandbox.md +250 -232
  168. package/kb/site/en/reference/subsystems/session-query.md +525 -515
  169. package/kb/site/en/reference/subsystems/session-reference.md +231 -229
  170. package/kb/site/en/reference/subsystems/session.md +1478 -1431
  171. package/kb/site/en/reference/subsystems/sidebar-right.md +165 -165
  172. package/kb/site/en/reference/subsystems/skills.md +356 -356
  173. package/kb/site/en/reference/subsystems/slots.md +235 -231
  174. package/kb/site/en/reference/subsystems/terminal.md +188 -188
  175. package/kb/site/en/reference/subsystems/tools.md +902 -891
  176. package/kb/site/en/reference/subsystems/user-questions.md +330 -327
  177. package/kb/site/en/reference/subsystems/web-client.md +161 -104
  178. package/kb/site/en/reference/subsystems/web-server.md +434 -351
  179. package/kb/site/en/reference/subsystems/web.md +268 -268
  180. package/kb/site/en/reference/subsystems/workflow.md +287 -282
  181. package/kb/site/en/reference/subsystems/workspace.md +743 -651
  182. package/kb/site/en/reference/tool-catalog.md +2867 -2704
  183. package/kb/site/guide/desktop-uninstall-cleanup.md +63 -0
  184. package/kb/site/guide/plugin-market.md +153 -151
  185. package/kb/site/guide/providers.md +234 -234
  186. package/kb/site/guide/quickstart.md +35 -34
  187. package/kb/site/reference/capability-seams.md +789 -767
  188. package/kb/site/reference/config-catalog.md +5432 -5128
  189. package/kb/site/reference/cookbook/adding-a-package.md +175 -175
  190. package/kb/site/reference/cookbook/adding-a-tool.md +107 -106
  191. package/kb/site/reference/cookbook/extension-cookbook.md +182 -139
  192. package/kb/site/reference/cordis-api/context.md +373 -369
  193. package/kb/site/reference/cordis-api/fiber.md +459 -435
  194. package/kb/site/reference/cordis-api/inherited.md +44 -44
  195. package/kb/site/reference/cordis-api/service.md +118 -107
  196. package/kb/site/reference/experimental-persistence-catalog.md +36 -23
  197. package/kb/site/reference/index.md +178 -178
  198. package/kb/site/reference/persistence-catalog.md +9453 -9432
  199. package/kb/site/reference/subsystems/compaction.md +288 -288
  200. package/kb/site/reference/subsystems/core.md +1184 -1183
  201. package/kb/site/reference/subsystems/credentials.md +526 -497
  202. package/kb/site/reference/subsystems/filesystem.md +708 -708
  203. package/kb/site/reference/subsystems/index.md +82 -82
  204. package/kb/site/reference/subsystems/llm-streaming.md +1296 -1294
  205. package/kb/site/reference/subsystems/lsp.md +230 -206
  206. package/kb/site/reference/subsystems/persistence.md +451 -432
  207. package/kb/site/reference/subsystems/plan.md +91 -91
  208. package/kb/site/reference/subsystems/ptc-runtime.md +295 -261
  209. package/kb/site/reference/subsystems/sandbox.md +250 -232
  210. package/kb/site/reference/subsystems/session-query.md +525 -515
  211. package/kb/site/reference/subsystems/session-reference.md +231 -229
  212. package/kb/site/reference/subsystems/session.md +1482 -1435
  213. package/kb/site/reference/subsystems/sidebar-right.md +165 -165
  214. package/kb/site/reference/subsystems/skills.md +356 -356
  215. package/kb/site/reference/subsystems/slots.md +239 -235
  216. package/kb/site/reference/subsystems/terminal.md +188 -188
  217. package/kb/site/reference/subsystems/tools.md +902 -891
  218. package/kb/site/reference/subsystems/user-questions.md +330 -327
  219. package/kb/site/reference/subsystems/web-client.md +161 -104
  220. package/kb/site/reference/subsystems/web-server.md +434 -351
  221. package/kb/site/reference/subsystems/web.md +268 -268
  222. package/kb/site/reference/subsystems/workflow.md +287 -282
  223. package/kb/site/reference/subsystems/workspace.md +743 -651
  224. package/kb/site/reference/tool-catalog.md +2872 -2709
  225. package/lib/index.js +359 -359
  226. package/package.json +68 -68
  227. package/skills/dsh-plugin-dev-kb.md +71 -70
  228. package/kb/extra/subsystems/office-to-pdf.md +0 -87
  229. package/kb/extra/subsystems/office-to-pdf.zh.md +0 -87
@@ -1,268 +1,268 @@
1
- ---
2
- editSource: "docs/subsystems/web.zh.md"
3
- rawMarkdownPath: "reference/subsystems/web.md"
4
- outline: [2,3]
5
- ---
6
-
7
- # Web 访问
8
-
9
- Web 访问 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md),在同一个 `ctx.web` 服务上横跨**两项操作**(search 与 fetch),并拆分到多个包:Service Definition([dsh-web](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web),`ctx.web` + 提供方注册表)、Service Provider([dsh-web-search-deepseek](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web-search-deepseek)、[dsh-web-deepseek-api](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web-deepseek-api)、[dsh-web-fetch-http](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web-fetch-http))与 Consumer([dsh-tool-web](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/tool-web),即 `web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](./core.md) 中。更换 search 提供方不会改变模型提交查询的方式,更换 fetch 提供方也不会改变模型请求 URL 的方式。
10
-
11
- 源码:[`packages/web/web/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/types.ts)
12
-
13
- ## 为什么一项能力包含两项操作
14
-
15
- 搜索与抓取既不共享请求 schema,也不共享业务逻辑,但它们被有意设计为同一个 `ctx.web` 中间层:一个提供方选择策略的所有者、一套中止与错误词汇,以及一个面向产品的「此 harness 如何访问 Web」配置界面。代价是服务上并行的 `searchX`/`fetchX` 方法对;这种并行是有意为之,而不是遗漏了可抽取的共性。提供方注册的是**能力**(`WebSearchProvider` 或 `WebFetchProvider`),而非工具;面向模型的名称、schema、提示词引导与展示全部集中在唯一的消费方 `dsh-tool-web` 中。
16
-
17
- ## 搜索请求与结果
18
-
19
- 每个 seam 请求只携带一个 `query`。消费方 `dsh-tool-web` 接受必填的 `queries` 数组,并把它扇出为多个独立 seam 请求;单元素数组执行一次搜索。`maxResults` 是消费方自有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `10`),通过 seam 传递并在返回时强制执行——如果提供方返回超量,seam 截断 `sources[]` 并设置 `truncated`。
20
-
21
- ```ts type-equiv
22
- /**
23
- * What one search-capable backend is asked to search. Each request carries one
24
- * query; a consumer may issue several requests. `maxResults` is a
25
- * `dsh-tool-web`-layer bound passed through unchanged and enforced on the way
26
- * back by the seam (see {@link WebSearchResult}).
27
- */
28
- interface WebSearchRequest {
29
- readonly query: string
30
- /**
31
- * Upper bound on returned sources; the seam truncates to it. Omitted = no
32
- * bound. `dsh-tool-web` always sets it. A provider whose API supports a
33
- * result-count control (the DeepSeek Search API's `count`) should apply it
34
- * at the request layer as a cost/latency optimization; the seam enforces the
35
- * bound regardless.
36
- */
37
- readonly maxResults?: number
38
- }
39
- ```
40
-
41
- ```ts type-equiv
42
- /**
43
- * Normalized search outcome. `content` is optional provider-generated answer
44
- * text or summary (DeepSeek returns none; a provider whose API generates an
45
- * answer returns it here).
46
- * `sources[]` is the portable citation shape. `truncated` is set by the seam
47
- * when it cut `sources[]` down to `maxResults`.
48
- */
49
- interface WebSearchResult {
50
- /** Optional provider-generated answer text, search context, or summary. */
51
- readonly content?: string
52
- /** Citeable sources, already truncated to the request's `maxResults`. */
53
- readonly sources: readonly WebSearchSource[]
54
- /** True when the seam dropped sources to honor `maxResults`. */
55
- readonly truncated: boolean
56
- }
57
- ```
58
-
59
- ```ts type-equiv
60
- /**
61
- * One citeable source. A source always has a URL; `title`, `snippet`, `summary`,
62
- * and `publishedAt` are optional because not every provider returns them — forcing
63
- * adapters to invent them would make the seam lie (some providers return
64
- * URL-only citations). `dsh-tool-web` renders `title ?? hostname(url)` for display.
65
- */
66
- interface WebSearchSource {
67
- readonly url: string
68
- readonly title?: string
69
- /** Short excerpt suited to display. */
70
- readonly snippet?: string
71
- /** Longer excerpt suited to model reading; consumers bound its length. */
72
- readonly summary?: string
73
- /** Publication/crawl timestamp as a provider-supplied ISO-8601 string. */
74
- readonly publishedAt?: string
75
- }
76
- ```
77
-
78
- ## 抓取请求与结果
79
-
80
- ```ts type-equiv
81
- /**
82
- * What one fetch-capable backend is asked to retrieve. The request deliberately
83
- * omits timeout, format, prompt, and extraction controls: cancellation is a
84
- * direct execution argument, while presentation and higher-level LLM concerns
85
- * belong outside safe retrieval.
86
- */
87
- interface WebFetchRequest {
88
- readonly url: string
89
- }
90
- ```
91
-
92
- HTTP 状态码是被抓取资源状态的一部分,不自动视为失败:即使一次成功的网络抓取收到 `404` 或 `500` 响应,也仍会产出一个 `WebFetchResult`,其中包含状态码和长度受限的已解码正文。`url` 是经过允许的重定向后的最终 URL。`WebError` 仅用于无法安全获取或表示资源的情况。
93
-
94
- ```ts type-equiv
95
- /**
96
- * Normalized fetch outcome. A successful network fetch of a non-2xx response is
97
- * a result, not an error: the status code is part of the fetched resource
98
- * state. {@link WebError} is reserved for failures to safely retrieve or
99
- * represent the resource.
100
- */
101
- interface WebFetchResult {
102
- /** The final URL after allowed redirects (the request URL is in the request). */
103
- readonly url: string
104
- /** HTTP status code of the fetched response. */
105
- readonly statusCode: number
106
- /** Decoded body, classified by content kind. */
107
- readonly body: WebFetchBody
108
- /** True when the provider capped the decoded body. */
109
- readonly truncated: boolean
110
- }
111
- ```
112
-
113
- ```ts type-equiv
114
- /**
115
- * The decoded body of a fetched resource. A CLOSED discriminated union owned by
116
- * `dsh-web`: the provider decodes the kind and `dsh-tool-web` renders it, so a
117
- * new kind is a coordinated change across known packages, not a plugin
118
- * extension. Consumers `switch` on `kind` ending in `default: assertNever(...)`
119
- * so adding a kind breaks compilation at every consumer until handled. Each arm
120
- * stays its own object literal even where fields coincide, so an arm can gain
121
- * fields the others lack.
122
- */
123
- type WebFetchBody =
124
- | { readonly kind: 'html'; readonly content: string }
125
- | { readonly kind: 'text'; readonly content: string }
126
- ```
127
-
128
- ## 提供方可用性
129
-
130
- 提供方的 `available(): boolean` 是一个廉价的本地检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择提供方的输入,而不是健康检查系统:`search()`/`fetch()` 会读取它来选择可用的提供方。选择失败时,调用方会收到可据以分支处理的结构化 `WebError`;其错误代码和消息会说明缺失的 id 或存在歧义的候选集。与可用性不同,注册情况在操作运行前即可观测:`listProviders()` 按 `id`、可选的 `title` 和可选的多语言 `description` 返回每个已注册的搜索与抓取提供方,每次注册或注销后都会触发不带载荷的 `web/providers-changed` 事件;可用性仍只在操作运行时体现。
131
-
132
- 搜索或抓取提供方还可以实现 `ready(llmProvider): Promise<boolean>`,这是只检查配置、禁止发起网络调用的判断:它回答为该对话路由上的模型请求发起的操作是否有可发送的凭据。`searchReady(llmProvider?)` 与 `fetchReady(llmProvider?)` 只询问 `search()` 或 `fetch()` 会选中的提供方,把没有 `ready()` 的提供方视为就绪,并在选择失败时回答 true,因为对应操作会把该失败报告为 `WebError`。就绪判断不是选择输入;`dsh-tool-web` 把它作为 `web_search` 与 `web_fetch` 的激活条件,因此路由回答 false 的模型步骤既不声明也不派发该工具。DeepSeek Search 与 Fetch API 提供方依据该路由在账号令牌与 API 密钥之间选择,见 [web-deepseek-api 鉴权](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web-deepseek-api/README.zh.md#authentication)一节。
133
-
134
- 选择从不依赖注册顺序、配置顺序或 HMR(热模块替换)顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或填充同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;如果存在多个可用提供方却未配置 id,则抛出 `WEB_PROVIDER_AMBIGUOUS`,而不会选用最先注册的提供方。每次操作在执行时读取配置的 id,因此保存的设置变更无需重新挂载 `ctx.web` 即对下一次搜索或抓取生效。
135
-
136
- ## 抓取网络策略
137
-
138
- 已交付的 Cordis、Code 与 Standard preset 会在所有 sandbox 和审批模式下暴露 `web_fetch`,无需逐次确认。文件 sandbox preset 不管辖 Web 网络访问。需要确认步骤的部署必须添加 `tools/pre-execute` 策略或禁用抓取。
139
-
140
- HTTP 提供方不限制目的地址:`web_fetch` 会像访问其他主机一样访问 loopback、内网与云元数据主机,模型也可以把数据发送到它能访问的任何 URL。跨源重定向需要新的工具调用。需要阻止模型访问私有目的地址的部署必须使用网络隔离、`tools/pre-execute` 策略,或不挂载抓取工具。
141
-
142
- ## 错误
143
-
144
- `WebError extends HarnessError`([core.md](./core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致——`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的错误代码,消费方必须容忍未知错误代码。错误代码按所有者划分。共享的 `WebRuntime` 约定会抛出与 seam 无关的错误代码:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmRuntime` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身故障经 seam 暴露时使用的兜底代码,包括 DNS、连接被拒绝、TLS 等网络或传输故障)。抓取传输层错误代码由 `dsh-web-fetch-http` 实现拥有,不同的抓取后端无需抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`。
145
-
146
- ## 服务
147
-
148
- `WebRuntime` 注册搜索与抓取提供方,以 `WEB_DUPLICATE_PROVIDER` 拒绝重复 id,并在执行时以结构化的选择错误解析提供方。本地抓取后端仅接受 HTTP(S)、拒绝凭证、经已安装的代理策略发送每个请求、对每一次同源重定向跳转重复 URL 校验、限制重定向次数、字节数、字符数和时间,并解码正文;展示由工具负责。
149
-
150
- <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
151
-
152
- <a id="cordis-surface"></a>
153
-
154
- ## Cordis API
155
-
156
- Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
157
-
158
- <a id="ctxweb--webruntime"></a>
159
-
160
- ### `ctx.web` — `WebRuntime`
161
-
162
- The web access service. Registered as `ctx.web` (one instance per context) and exposed to Clients as the `web` Remote namespace (`listProviders`).
163
-
164
- Selection semantics (resolved at execution time, never order-dependent):
165
-
166
- - A configured id that is registered and `available()` → that provider.
167
- - A configured id not registered → `WEB_PROVIDER_CONFIGURED_MISSING`.
168
- - A configured id registered but unavailable → `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`.
169
- - No id configured, exactly one registered usable provider → that provider.
170
- - No id configured, multiple usable providers → `WEB_PROVIDER_AMBIGUOUS`.
171
- - No id configured, no usable provider → `WEB_PROVIDER_UNAVAILABLE`.
172
-
173
- ```ts cordis-catalog
174
- /**
175
- * Register a search provider. `listProviders()` lists it until the
176
- * registration is disposed, which happens with the calling fiber or through
177
- * the returned disposer; registration and disposal each emit
178
- * `web/providers-changed`. Throws {@link WebError} `WEB_DUPLICATE_PROVIDER`
179
- * if its id is already registered for search.
180
- * @param provider - the provider; its `id` is the registry key.
181
- * @returns the disposer that unregisters the provider.
182
- */
183
- registerSearchProvider(provider: WebSearchProvider): () => void
184
-
185
- /**
186
- * Register a fetch provider, with the listing, disposal, and event behavior
187
- * of {@link WebRuntime.registerSearchProvider}. Throws {@link WebError}
188
- * `WEB_DUPLICATE_PROVIDER` if its id is already registered for fetch.
189
- * @param provider - the provider; its `id` is the registry key.
190
- * @returns the disposer that unregisters the provider.
191
- */
192
- registerFetchProvider(provider: WebFetchProvider): () => void
193
-
194
- /**
195
- * List every registered search and fetch provider for provider pickers.
196
- * Availability does not filter the lists.
197
- * @returns detached `{ id, title, description }` entries per capability, in registration order.
198
- */
199
- @Remote listProviders(): WebProviderList
200
-
201
- /**
202
- * Run one search through the selected provider. Resolves the provider at call
203
- * time with the selection rules above; throws {@link WebError} when the
204
- * capability cannot run. The seam enforces `request.maxResults` on the result:
205
- * if the provider over-returns, `sources[]` is truncated and `truncated` set.
206
- * @param request - the query and optional result limit.
207
- * @param signal - optional cancellation signal forwarded to the provider.
208
- * @returns the provider's results, capped to `request.maxResults`.
209
- */
210
- async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>
211
-
212
- /**
213
- * Whether the provider `search()` would select can authenticate a search made for a
214
- * model request on the `llmProvider` chat route. Asks only that provider's `ready()`;
215
- * one without `ready()` counts as ready. Makes no network calls. A selection failure
216
- * answers true, because `search()` reports that failure as a structured `WebError`.
217
- * @param llmProvider - the provider route id of the model request, when known.
218
- * @returns false only when the selected provider reports that it cannot authenticate.
219
- */
220
- async searchReady(llmProvider?: string): Promise<boolean>
221
-
222
- /**
223
- * Retrieve one URL through the selected provider. Resolves the provider at
224
- * call time with the selection rules above; throws {@link WebError} when the
225
- * capability cannot run. A non-2xx response is a result, not a throw.
226
- * @param request - the URL plus retrieval options.
227
- * @param signal - optional cancellation signal forwarded to the provider.
228
- * @returns the retrieval outcome; non-2xx responses resolve descriptively.
229
- */
230
- async fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>
231
-
232
- /**
233
- * Whether the provider `fetch()` would select can authenticate a fetch made for a
234
- * model request on the `llmProvider` chat route. Asks only that provider's `ready()`;
235
- * one without `ready()` counts as ready. Makes no network calls. A selection failure
236
- * answers true, because `fetch()` reports that failure as a structured `WebError`.
237
- * @param llmProvider - the provider route id of the model request, when known.
238
- * @returns false only when the selected provider reports that it cannot authenticate.
239
- */
240
- async fetchReady(llmProvider?: string): Promise<boolean>
241
- ```
242
-
243
- Source: [`packages/web/web/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/index.ts)
244
-
245
- <a id="web-events"></a>
246
-
247
- ### `web/*` events
248
-
249
- <a id="webproviders-changed--emit"></a>
250
-
251
- #### `web/providers-changed` — emit
252
-
253
- The set of registered search or fetch providers changed: one provider registered, or its registration was disposed. Payload-free; consumers re-read `ctx.web.listProviders()` (Remote `web/listProviders`) for the new list. Fires after each committed registry mutation. Observer failures are contained and cannot veto the mutation.
254
-
255
- ```ts cordis-catalog
256
- /**
257
- * The set of registered search or fetch providers changed: one provider
258
- * registered, or its registration was disposed. Payload-free; consumers
259
- * re-read `ctx.web.listProviders()` (Remote `web/listProviders`) for the
260
- * new list. Fires after each committed registry mutation. Observer failures
261
- * are contained and cannot veto the mutation.
262
- * @mode emit
263
- */
264
- 'web/providers-changed'(): void
265
- ```
266
-
267
- Source: [`packages/web/web/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/types.ts)
268
- <!-- END GENERATED cordis-surface -->
1
+ ---
2
+ editSource: "docs/subsystems/web.zh.md"
3
+ rawMarkdownPath: "reference/subsystems/web.md"
4
+ outline: [2,3]
5
+ ---
6
+
7
+ # Web 访问
8
+
9
+ Web 访问 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md),在同一个 `ctx.web` 服务上横跨**两项操作**(search 与 fetch),并拆分到多个包:Service Definition([dsh-web](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web),`ctx.web` + 提供方注册表)、Service Provider([dsh-web-search-deepseek](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web-search-deepseek)、[dsh-web-deepseek-api](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web-deepseek-api)、[dsh-web-fetch-http](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web-fetch-http))与 Consumer([dsh-tool-web](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/tool-web),即 `web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](./core.md) 中。更换 search 提供方不会改变模型提交查询的方式,更换 fetch 提供方也不会改变模型请求 URL 的方式。
10
+
11
+ 源码:[`packages/web/web/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/types.ts)
12
+
13
+ ## 为什么一项能力包含两项操作
14
+
15
+ 搜索与抓取既不共享请求 schema,也不共享业务逻辑,但它们被有意设计为同一个 `ctx.web` 中间层:一个提供方选择策略的所有者、一套中止与错误词汇,以及一个面向产品的「此 harness 如何访问 Web」配置界面。代价是服务上并行的 `searchX`/`fetchX` 方法对;这种并行是有意为之,而不是遗漏了可抽取的共性。提供方注册的是**能力**(`WebSearchProvider` 或 `WebFetchProvider`),而非工具;面向模型的名称、schema、提示词引导与展示全部集中在唯一的消费方 `dsh-tool-web` 中。
16
+
17
+ ## 搜索请求与结果
18
+
19
+ 每个 seam 请求只携带一个 `query`。消费方 `dsh-tool-web` 接受必填的 `queries` 数组,并把它扇出为多个独立 seam 请求;单元素数组执行一次搜索。`maxResults` 是消费方自有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `10`),通过 seam 传递并在返回时强制执行——如果提供方返回超量,seam 截断 `sources[]` 并设置 `truncated`。
20
+
21
+ ```ts type-equiv
22
+ /**
23
+ * What one search-capable backend is asked to search. Each request carries one
24
+ * query; a consumer may issue several requests. `maxResults` is a
25
+ * `dsh-tool-web`-layer bound passed through unchanged and enforced on the way
26
+ * back by the seam (see {@link WebSearchResult}).
27
+ */
28
+ interface WebSearchRequest {
29
+ readonly query: string
30
+ /**
31
+ * Upper bound on returned sources; the seam truncates to it. Omitted = no
32
+ * bound. `dsh-tool-web` always sets it. A provider whose API supports a
33
+ * result-count control (the DeepSeek Search API's `count`) should apply it
34
+ * at the request layer as a cost/latency optimization; the seam enforces the
35
+ * bound regardless.
36
+ */
37
+ readonly maxResults?: number
38
+ }
39
+ ```
40
+
41
+ ```ts type-equiv
42
+ /**
43
+ * Normalized search outcome. `content` is optional provider-generated answer
44
+ * text or summary (DeepSeek returns none; a provider whose API generates an
45
+ * answer returns it here).
46
+ * `sources[]` is the portable citation shape. `truncated` is set by the seam
47
+ * when it cut `sources[]` down to `maxResults`.
48
+ */
49
+ interface WebSearchResult {
50
+ /** Optional provider-generated answer text, search context, or summary. */
51
+ readonly content?: string
52
+ /** Citeable sources, already truncated to the request's `maxResults`. */
53
+ readonly sources: readonly WebSearchSource[]
54
+ /** True when the seam dropped sources to honor `maxResults`. */
55
+ readonly truncated: boolean
56
+ }
57
+ ```
58
+
59
+ ```ts type-equiv
60
+ /**
61
+ * One citeable source. A source always has a URL; `title`, `snippet`, `summary`,
62
+ * and `publishedAt` are optional because not every provider returns them — forcing
63
+ * adapters to invent them would make the seam lie (some providers return
64
+ * URL-only citations). `dsh-tool-web` renders `title ?? hostname(url)` for display.
65
+ */
66
+ interface WebSearchSource {
67
+ readonly url: string
68
+ readonly title?: string
69
+ /** Short excerpt suited to display. */
70
+ readonly snippet?: string
71
+ /** Longer excerpt suited to model reading; consumers bound its length. */
72
+ readonly summary?: string
73
+ /** Publication/crawl timestamp as a provider-supplied ISO-8601 string. */
74
+ readonly publishedAt?: string
75
+ }
76
+ ```
77
+
78
+ ## 抓取请求与结果
79
+
80
+ ```ts type-equiv
81
+ /**
82
+ * What one fetch-capable backend is asked to retrieve. The request deliberately
83
+ * omits timeout, format, prompt, and extraction controls: cancellation is a
84
+ * direct execution argument, while presentation and higher-level LLM concerns
85
+ * belong outside safe retrieval.
86
+ */
87
+ interface WebFetchRequest {
88
+ readonly url: string
89
+ }
90
+ ```
91
+
92
+ HTTP 状态码是被抓取资源状态的一部分,不自动视为失败:即使一次成功的网络抓取收到 `404` 或 `500` 响应,也仍会产出一个 `WebFetchResult`,其中包含状态码和长度受限的已解码正文。`url` 是经过允许的重定向后的最终 URL。`WebError` 仅用于无法安全获取或表示资源的情况。
93
+
94
+ ```ts type-equiv
95
+ /**
96
+ * Normalized fetch outcome. A successful network fetch of a non-2xx response is
97
+ * a result, not an error: the status code is part of the fetched resource
98
+ * state. {@link WebError} is reserved for failures to safely retrieve or
99
+ * represent the resource.
100
+ */
101
+ interface WebFetchResult {
102
+ /** The final URL after allowed redirects (the request URL is in the request). */
103
+ readonly url: string
104
+ /** HTTP status code of the fetched response. */
105
+ readonly statusCode: number
106
+ /** Decoded body, classified by content kind. */
107
+ readonly body: WebFetchBody
108
+ /** True when the provider capped the decoded body. */
109
+ readonly truncated: boolean
110
+ }
111
+ ```
112
+
113
+ ```ts type-equiv
114
+ /**
115
+ * The decoded body of a fetched resource. A CLOSED discriminated union owned by
116
+ * `dsh-web`: the provider decodes the kind and `dsh-tool-web` renders it, so a
117
+ * new kind is a coordinated change across known packages, not a plugin
118
+ * extension. Consumers `switch` on `kind` ending in `default: assertNever(...)`
119
+ * so adding a kind breaks compilation at every consumer until handled. Each arm
120
+ * stays its own object literal even where fields coincide, so an arm can gain
121
+ * fields the others lack.
122
+ */
123
+ type WebFetchBody =
124
+ | { readonly kind: 'html'; readonly content: string }
125
+ | { readonly kind: 'text'; readonly content: string }
126
+ ```
127
+
128
+ ## 提供方可用性
129
+
130
+ 提供方的 `available(): boolean` 是一个廉价的本地检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择提供方的输入,而不是健康检查系统:`search()`/`fetch()` 会读取它来选择可用的提供方。选择失败时,调用方会收到可据以分支处理的结构化 `WebError`;其错误代码和消息会说明缺失的 id 或存在歧义的候选集。与可用性不同,注册情况在操作运行前即可观测:`listProviders()` 按 `id`、可选的 `title` 和可选的多语言 `description` 返回每个已注册的搜索与抓取提供方,每次注册或注销后都会触发不带载荷的 `web/providers-changed` 事件;可用性仍只在操作运行时体现。
131
+
132
+ 搜索或抓取提供方还可以实现 `ready(llmProvider): Promise<boolean>`,这是只检查配置、禁止发起网络调用的判断:它回答为该对话路由上的模型请求发起的操作是否有可发送的凭据。`searchReady(llmProvider?)` 与 `fetchReady(llmProvider?)` 只询问 `search()` 或 `fetch()` 会选中的提供方,把没有 `ready()` 的提供方视为就绪,并在选择失败时回答 true,因为对应操作会把该失败报告为 `WebError`。就绪判断不是选择输入;`dsh-tool-web` 把它作为 `web_search` 与 `web_fetch` 的激活条件,因此路由回答 false 的模型步骤既不声明也不派发该工具。DeepSeek Search 与 Fetch API 提供方依据该路由在账号令牌与 API 密钥之间选择,见 [web-deepseek-api 鉴权](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web-deepseek-api/README.zh.md#authentication)一节。
133
+
134
+ 选择从不依赖注册顺序、配置顺序或 HMR(热模块替换)顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或填充同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;如果存在多个可用提供方却未配置 id,则抛出 `WEB_PROVIDER_AMBIGUOUS`,而不会选用最先注册的提供方。每次操作在执行时读取配置的 id,因此保存的设置变更无需重新挂载 `ctx.web` 即对下一次搜索或抓取生效。
135
+
136
+ ## 抓取网络策略
137
+
138
+ 已交付的 Cordis、Code 与 Standard preset 会在所有 sandbox 和审批模式下暴露 `web_fetch`,无需逐次确认。文件 sandbox preset 不管辖 Web 网络访问。需要确认步骤的部署必须添加 `tools/pre-execute` 策略或禁用抓取。
139
+
140
+ HTTP 提供方不限制目的地址:`web_fetch` 会像访问其他主机一样访问 loopback、内网与云元数据主机,模型也可以把数据发送到它能访问的任何 URL。跨源重定向需要新的工具调用。需要阻止模型访问私有目的地址的部署必须使用网络隔离、`tools/pre-execute` 策略,或不挂载抓取工具。
141
+
142
+ ## 错误
143
+
144
+ `WebError extends HarnessError`([core.md](./core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致——`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的错误代码,消费方必须容忍未知错误代码。错误代码按所有者划分。共享的 `WebRuntime` 约定会抛出与 seam 无关的错误代码:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmRuntime` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身故障经 seam 暴露时使用的兜底代码)。抓取传输层错误代码由 `dsh-web-fetch-http` 实现拥有,不同的抓取后端无需抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`,以及网络故障类别 `WEB_FETCH_DNS_FAILED`、`WEB_FETCH_CONNECTION_REFUSED`、`WEB_FETCH_CONNECTION_TIMEOUT`、`WEB_FETCH_CERTIFICATE_INVALID`、`WEB_FETCH_CONNECTION_INTERRUPTED`、`WEB_FETCH_NETWORK_UNREACHABLE` 和 `WEB_FETCH_NETWORK_ERROR`。Web 中的 `web_fetch` 行会为网络故障类别显示本地化摘要,并在输出中保留记录的消息。
145
+
146
+ ## 服务
147
+
148
+ `WebRuntime` 注册搜索与抓取提供方,以 `WEB_DUPLICATE_PROVIDER` 拒绝重复 id,并在执行时以结构化的选择错误解析提供方。本地抓取后端仅接受 HTTP(S)、拒绝凭证、经已安装的代理策略发送每个请求、对每一次同源重定向跳转重复 URL 校验、限制重定向次数、字节数、字符数和时间,并解码正文;展示由工具负责。
149
+
150
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
151
+
152
+ <a id="cordis-surface"></a>
153
+
154
+ ## Cordis API
155
+
156
+ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
157
+
158
+ <a id="ctxweb--webruntime"></a>
159
+
160
+ ### `ctx.web` — `WebRuntime`
161
+
162
+ The web access service. Registered as `ctx.web` (one instance per context) and exposed to Clients as the `web` Remote namespace (`listProviders`).
163
+
164
+ Selection semantics (resolved at execution time, never order-dependent):
165
+
166
+ - A configured id that is registered and `available()` → that provider.
167
+ - A configured id not registered → `WEB_PROVIDER_CONFIGURED_MISSING`.
168
+ - A configured id registered but unavailable → `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`.
169
+ - No id configured, exactly one registered usable provider → that provider.
170
+ - No id configured, multiple usable providers → `WEB_PROVIDER_AMBIGUOUS`.
171
+ - No id configured, no usable provider → `WEB_PROVIDER_UNAVAILABLE`.
172
+
173
+ ```ts cordis-catalog
174
+ /**
175
+ * Register a search provider. `listProviders()` lists it until the
176
+ * registration is disposed, which happens with the calling fiber or through
177
+ * the returned disposer; registration and disposal each emit
178
+ * `web/providers-changed`. Throws {@link WebError} `WEB_DUPLICATE_PROVIDER`
179
+ * if its id is already registered for search.
180
+ * @param provider - the provider; its `id` is the registry key.
181
+ * @returns the disposer that unregisters the provider.
182
+ */
183
+ registerSearchProvider(provider: WebSearchProvider): () => void
184
+
185
+ /**
186
+ * Register a fetch provider, with the listing, disposal, and event behavior
187
+ * of {@link WebRuntime.registerSearchProvider}. Throws {@link WebError}
188
+ * `WEB_DUPLICATE_PROVIDER` if its id is already registered for fetch.
189
+ * @param provider - the provider; its `id` is the registry key.
190
+ * @returns the disposer that unregisters the provider.
191
+ */
192
+ registerFetchProvider(provider: WebFetchProvider): () => void
193
+
194
+ /**
195
+ * List every registered search and fetch provider for provider pickers.
196
+ * Availability does not filter the lists.
197
+ * @returns detached `{ id, title, description }` entries per capability, in registration order.
198
+ */
199
+ @Remote listProviders(): WebProviderList
200
+
201
+ /**
202
+ * Run one search through the selected provider. Resolves the provider at call
203
+ * time with the selection rules above; throws {@link WebError} when the
204
+ * capability cannot run. The seam enforces `request.maxResults` on the result:
205
+ * if the provider over-returns, `sources[]` is truncated and `truncated` set.
206
+ * @param request - the query and optional result limit.
207
+ * @param signal - optional cancellation signal forwarded to the provider.
208
+ * @returns the provider's results, capped to `request.maxResults`.
209
+ */
210
+ async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>
211
+
212
+ /**
213
+ * Whether the provider `search()` would select can authenticate a search made for a
214
+ * model request on the `llmProvider` chat route. Asks only that provider's `ready()`;
215
+ * one without `ready()` counts as ready. Makes no network calls. A selection failure
216
+ * answers true, because `search()` reports that failure as a structured `WebError`.
217
+ * @param llmProvider - the provider route id of the model request, when known.
218
+ * @returns false only when the selected provider reports that it cannot authenticate.
219
+ */
220
+ async searchReady(llmProvider?: string): Promise<boolean>
221
+
222
+ /**
223
+ * Retrieve one URL through the selected provider. Resolves the provider at
224
+ * call time with the selection rules above; throws {@link WebError} when the
225
+ * capability cannot run. A non-2xx response is a result, not a throw.
226
+ * @param request - the URL plus retrieval options.
227
+ * @param signal - optional cancellation signal forwarded to the provider.
228
+ * @returns the retrieval outcome; non-2xx responses resolve descriptively.
229
+ */
230
+ async fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>
231
+
232
+ /**
233
+ * Whether the provider `fetch()` would select can authenticate a fetch made for a
234
+ * model request on the `llmProvider` chat route. Asks only that provider's `ready()`;
235
+ * one without `ready()` counts as ready. Makes no network calls. A selection failure
236
+ * answers true, because `fetch()` reports that failure as a structured `WebError`.
237
+ * @param llmProvider - the provider route id of the model request, when known.
238
+ * @returns false only when the selected provider reports that it cannot authenticate.
239
+ */
240
+ async fetchReady(llmProvider?: string): Promise<boolean>
241
+ ```
242
+
243
+ Source: [`packages/web/web/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/index.ts)
244
+
245
+ <a id="web-events"></a>
246
+
247
+ ### `web/*` events
248
+
249
+ <a id="webproviders-changed--emit"></a>
250
+
251
+ #### `web/providers-changed` — emit
252
+
253
+ The set of registered search or fetch providers changed: one provider registered, or its registration was disposed. Payload-free; consumers re-read `ctx.web.listProviders()` (Remote `web/listProviders`) for the new list. Fires after each committed registry mutation. Observer failures are contained and cannot veto the mutation.
254
+
255
+ ```ts cordis-catalog
256
+ /**
257
+ * The set of registered search or fetch providers changed: one provider
258
+ * registered, or its registration was disposed. Payload-free; consumers
259
+ * re-read `ctx.web.listProviders()` (Remote `web/listProviders`) for the
260
+ * new list. Fires after each committed registry mutation. Observer failures
261
+ * are contained and cannot veto the mutation.
262
+ * @mode emit
263
+ */
264
+ 'web/providers-changed'(): void
265
+ ```
266
+
267
+ Source: [`packages/web/web/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/types.ts)
268
+ <!-- END GENERATED cordis-surface -->