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.md"
3
- rawMarkdownPath: "en/reference/subsystems/web.md"
4
- outline: [2,3]
5
- ---
6
-
7
- # Web Access
8
-
9
- The web access seam — a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.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](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web), `ctx.web` + the provider registries), Service Providers ([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)), and Consumer ([dsh-tool-web](https://github.com/deepseek-ai/deepseek-harness/tree/master/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.
10
-
11
- Source: [`packages/web/web/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/types.ts)
12
-
13
- ## Why one capability has two operations
14
-
15
- Search and fetch share no request schema and no business logic, but they are deliberately one `ctx.web` middle layer: one provider-selection policy owner, one abort/error vocabulary, and one product-facing "how this harness reaches the web" configuration API. The cost is the parallel `searchX`/`fetchX` method pairs on the service; that parallelism is intentional, not a missed extraction. Providers register **capabilities** (a `WebSearchProvider` or `WebFetchProvider`), not tools; the model-facing names, schemas, prompt guidance, and presentation all live in the single `dsh-tool-web` consumer.
16
-
17
- ## Search request and result
18
-
19
- Each seam request carries exactly one `query`. The `dsh-tool-web` consumer accepts a required `queries` array and fans it out into separate seam requests; a one-item array performs one search. `maxResults` is a consumer-owned bound (`dsh-tool-web`'s `searchMaxResults` config, default `10`) passed through the seam and enforced on the way back — if a provider over-returns, the seam truncates `sources[]` and sets `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
- ## Fetch request and result
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 status is part of the fetched resource state, not automatically a failure: a successful network fetch of a `404`/`500` returns a `WebFetchResult` with the status code and a bounded decoded body. `url` is the final URL after allowed redirects. `WebError` is reserved for failures to safely retrieve or represent the resource.
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
- ## Provider availability
129
-
130
- 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. Registration, unlike availability, is observable before an operation runs: `listProviders()` returns every registered search and fetch provider by `id`, optional `title`, and optional localized `description`, and the payload-free `web/providers-changed` event fires after each registration or disposal; availability still shows only when an operation runs.
131
-
132
- A search or fetch provider may also implement `ready(llmProvider): Promise<boolean>`, a configuration-only check that must not make network calls: it answers whether an operation made for a model request on that chat route has a credential to send. `searchReady(llmProvider?)` and `fetchReady(llmProvider?)` ask only the provider that `search()` or `fetch()` would select, treat a provider without `ready()` as ready, and answer true when selection fails, because the operation reports that failure as a `WebError`. Readiness is not a selection input; `dsh-tool-web` makes it the activation condition of `web_search` and `web_fetch`, so a model step whose route answers false neither declares nor dispatches the tool. The DeepSeek Search and Fetch API providers use the route to choose between the account token and the API key, as the [web-deepseek-api authentication](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web-deepseek-api/README.md#authentication) section describes.
133
-
134
- 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`.
135
-
136
- ## Fetch network policy
137
-
138
- The shipped Cordis, Code, and Standard presets expose `web_fetch` in every sandbox and approval mode without per-call confirmation. File sandbox presets do not govern Web network access. A deployment that needs confirmation must add a `tools/pre-execute` policy or disable fetch.
139
-
140
- The HTTP provider does not restrict destination addresses: `web_fetch` reaches loopback, private-network, and cloud metadata hosts like any other host, and a model can send data to any URL it can reach. A cross-origin redirect requires a new tool call. A deployment that must keep the model away from private destinations needs network confinement, a `tools/pre-execute` policy, or no fetch tool.
141
-
142
- ## Errors
143
-
144
- `WebError extends HarnessError` ([core.md](./core.md) error taxonomy) with a `code: string` (open, like every other seam's error — `LlmError`, `SubagentError`), not a closed union: a provider may raise its own codes without editing `dsh-web`, and consumers must tolerate an unknown code. The codes split by owner. Seam-neutral codes are raised by the shared `WebRuntime` contract: `WEB_PROVIDER_UNAVAILABLE`, `WEB_PROVIDER_CONFIGURED_MISSING`, `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`, `WEB_PROVIDER_AMBIGUOUS`, `WEB_DUPLICATE_PROVIDER` (a registration-time programming error, the analogue of `LlmRuntime`'s `DUPLICATE_ADAPTER`), `WEB_ABORTED`, and `WEB_PROVIDER_ERROR` (the catch-all for a provider's own failure surfaced through the seam, including network/transport failure — DNS, connection refused, TLS). Fetch-transport codes are owned by the `dsh-web-fetch-http` implementation and a different fetch backend need not raise them: `WEB_INVALID_URL`, `WEB_BLOCKED_URL`, `WEB_REDIRECT_BLOCKED`, `WEB_FETCH_TOO_LARGE`, `WEB_FETCH_TIMEOUT`, `WEB_UNSUPPORTED_CONTENT_TYPE`.
145
-
146
- ## The service
147
-
148
- `WebRuntime` registers search and fetch providers, rejects duplicate ids with `WEB_DUPLICATE_PROVIDER`, and resolves providers at execution time with structured selection errors. The local fetch backend accepts only HTTP(S), rejects credentials, sends each request through the installed proxy policy, repeats URL validation for every same-origin redirect hop, caps redirects, bytes, characters, and time, and decodes the body; the tool owns presentation.
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.md"
3
+ rawMarkdownPath: "en/reference/subsystems/web.md"
4
+ outline: [2,3]
5
+ ---
6
+
7
+ # Web Access
8
+
9
+ The web access seam — a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.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](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/web/web), `ctx.web` + the provider registries), Service Providers ([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)), and Consumer ([dsh-tool-web](https://github.com/deepseek-ai/deepseek-harness/tree/master/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.
10
+
11
+ Source: [`packages/web/web/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web/src/types.ts)
12
+
13
+ ## Why one capability has two operations
14
+
15
+ Search and fetch share no request schema and no business logic, but they are deliberately one `ctx.web` middle layer: one provider-selection policy owner, one abort/error vocabulary, and one product-facing "how this harness reaches the web" configuration API. The cost is the parallel `searchX`/`fetchX` method pairs on the service; that parallelism is intentional, not a missed extraction. Providers register **capabilities** (a `WebSearchProvider` or `WebFetchProvider`), not tools; the model-facing names, schemas, prompt guidance, and presentation all live in the single `dsh-tool-web` consumer.
16
+
17
+ ## Search request and result
18
+
19
+ Each seam request carries exactly one `query`. The `dsh-tool-web` consumer accepts a required `queries` array and fans it out into separate seam requests; a one-item array performs one search. `maxResults` is a consumer-owned bound (`dsh-tool-web`'s `searchMaxResults` config, default `10`) passed through the seam and enforced on the way back — if a provider over-returns, the seam truncates `sources[]` and sets `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
+ ## Fetch request and result
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 status is part of the fetched resource state, not automatically a failure: a successful network fetch of a `404`/`500` returns a `WebFetchResult` with the status code and a bounded decoded body. `url` is the final URL after allowed redirects. `WebError` is reserved for failures to safely retrieve or represent the resource.
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
+ ## Provider availability
129
+
130
+ 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. Registration, unlike availability, is observable before an operation runs: `listProviders()` returns every registered search and fetch provider by `id`, optional `title`, and optional localized `description`, and the payload-free `web/providers-changed` event fires after each registration or disposal; availability still shows only when an operation runs.
131
+
132
+ A search or fetch provider may also implement `ready(llmProvider): Promise<boolean>`, a configuration-only check that must not make network calls: it answers whether an operation made for a model request on that chat route has a credential to send. `searchReady(llmProvider?)` and `fetchReady(llmProvider?)` ask only the provider that `search()` or `fetch()` would select, treat a provider without `ready()` as ready, and answer true when selection fails, because the operation reports that failure as a `WebError`. Readiness is not a selection input; `dsh-tool-web` makes it the activation condition of `web_search` and `web_fetch`, so a model step whose route answers false neither declares nor dispatches the tool. The DeepSeek Search and Fetch API providers use the route to choose between the account token and the API key, as the [web-deepseek-api authentication](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/web/web-deepseek-api/README.md#authentication) section describes.
133
+
134
+ 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`.
135
+
136
+ ## Fetch network policy
137
+
138
+ The shipped Cordis, Code, and Standard presets expose `web_fetch` in every sandbox and approval mode without per-call confirmation. File sandbox presets do not govern Web network access. A deployment that needs confirmation must add a `tools/pre-execute` policy or disable fetch.
139
+
140
+ The HTTP provider does not restrict destination addresses: `web_fetch` reaches loopback, private-network, and cloud metadata hosts like any other host, and a model can send data to any URL it can reach. A cross-origin redirect requires a new tool call. A deployment that must keep the model away from private destinations needs network confinement, a `tools/pre-execute` policy, or no fetch tool.
141
+
142
+ ## Errors
143
+
144
+ `WebError extends HarnessError` ([core.md](./core.md) error taxonomy) with a `code: string` (open, like every other seam's error — `LlmError`, `SubagentError`), not a closed union: a provider may raise its own codes without editing `dsh-web`, and consumers must tolerate an unknown code. The codes split by owner. Seam-neutral codes are raised by the shared `WebRuntime` contract: `WEB_PROVIDER_UNAVAILABLE`, `WEB_PROVIDER_CONFIGURED_MISSING`, `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`, `WEB_PROVIDER_AMBIGUOUS`, `WEB_DUPLICATE_PROVIDER` (a registration-time programming error, the analogue of `LlmRuntime`'s `DUPLICATE_ADAPTER`), `WEB_ABORTED`, and `WEB_PROVIDER_ERROR` (the catch-all for a provider's own failure surfaced through the seam). Fetch-transport codes are owned by the `dsh-web-fetch-http` implementation and a different fetch backend need not raise them: `WEB_INVALID_URL`, `WEB_BLOCKED_URL`, `WEB_REDIRECT_BLOCKED`, `WEB_FETCH_TOO_LARGE`, `WEB_FETCH_TIMEOUT`, `WEB_UNSUPPORTED_CONTENT_TYPE`, and the network failure classes `WEB_FETCH_DNS_FAILED`, `WEB_FETCH_CONNECTION_REFUSED`, `WEB_FETCH_CONNECTION_TIMEOUT`, `WEB_FETCH_CERTIFICATE_INVALID`, `WEB_FETCH_CONNECTION_INTERRUPTED`, `WEB_FETCH_NETWORK_UNREACHABLE`, and `WEB_FETCH_NETWORK_ERROR`. The Web `web_fetch` row shows a localized summary for a network failure class and keeps the recorded message in its output.
145
+
146
+ ## The service
147
+
148
+ `WebRuntime` registers search and fetch providers, rejects duplicate ids with `WEB_DUPLICATE_PROVIDER`, and resolves providers at execution time with structured selection errors. The local fetch backend accepts only HTTP(S), rejects credentials, sends each request through the installed proxy policy, repeats URL validation for every same-origin redirect hop, caps redirects, bytes, characters, and time, and decodes the body; the tool owns presentation.
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 -->