{"_id":"@buckeyestudio/toh-tool-web","name":"@buckeyestudio/toh-tool-web","dist-tags":{"next":"0.1.1-rc.2","latest":"0.1.1-rc.2"},"versions":{"0.1.1-rc.2":{"name":"@buckeyestudio/toh-tool-web","description":"Model-facing web tools (web_search, web_fetch) over the TheOpen Harness web capability seam (ctx.web)","version":"0.1.1-rc.2","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/dustinwloring1988/theopen-harness.git","directory":"packages/web/tool-web"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","author":{"name":"buckeyestudio"},"peerDependencies":{"@buckeyestudio/toh-invariants":"^0.1.1-rc.2","@buckeyestudio/toh-tools":"^0.1.1-rc.2","@buckeyestudio/toh-system-prompt":"^0.1.1-rc.2","@buckeyestudio/toh-llm":"^0.1.1-rc.2","@buckeyestudio/cordis":"^4.0.1","@buckeyestudio/toh-web":"^0.1.1-rc.2"},"dependencies":{"@joplin/turndown-plugin-gfm":"^1.0.67","turndown":"^7.2.4","@buckeyestudio/schemastery":"^3.18.1"},"devDependencies":{"@types/turndown":"^5.0.6","@buckeyestudio/toh-agent":"^0.1.1-rc.2","@buckeyestudio/toh-invariants":"^0.1.1-rc.2","@buckeyestudio/toh-llm":"^0.1.1-rc.2","@buckeyestudio/toh-spill-local":"^0.1.1-rc.2","@buckeyestudio/toh-session":"^0.1.1-rc.2","@buckeyestudio/toh-spill-policy":"^0.1.1-rc.2","@buckeyestudio/toh-tool-call-timeout-policy":"^0.1.1-rc.2","@buckeyestudio/toh-web":"^0.1.1-rc.2","@buckeyestudio/toh-system-prompt":"^0.1.1-rc.2","@buckeyestudio/toh-web-fetch-http":"^0.1.1-rc.2","@buckeyestudio/toh-tools":"^0.1.1-rc.2","@buckeyestudio/toh-web-search-exa":"^0.1.1-rc.2","@buckeyestudio/cordis":"^4.0.1"},"_id":"@buckeyestudio/toh-tool-web@0.1.1-rc.2","bugs":{"url":"https://github.com/dustinwloring1988/theopen-harness/issues"},"homepage":"https://github.com/dustinwloring1988/theopen-harness#readme","_integrity":"sha512-/HtLy9GpRtrfrd2ZMLW95zU2bT/KsWjxgUvCTbO56B9eUu0JprSls951f2njwdXhRF9kkS3LxodYrVD3m9Bcqg==","_resolved":"/home/runner/work/theopen-harness/theopen-harness/dist/npm/buckeyestudio-toh-tool-web-0.1.1-rc.2.tgz","_from":"file:/home/runner/work/theopen-harness/theopen-harness/dist/npm/buckeyestudio-toh-tool-web-0.1.1-rc.2.tgz","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-/HtLy9GpRtrfrd2ZMLW95zU2bT/KsWjxgUvCTbO56B9eUu0JprSls951f2njwdXhRF9kkS3LxodYrVD3m9Bcqg==","shasum":"a7cf05a59d02a1f123371e49148f596e4b6ad6e6","tarball":"https://registry.npmjs.org/@buckeyestudio/toh-tool-web/-/toh-tool-web-0.1.1-rc.2.tgz","fileCount":11,"unpackedSize":78983,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFBbV2WN5Uj3IEuKaGQeFyrRMp1LDKx/QUEjLfDYSo37AiEAgGhq5FFeqm+G7Uu2Rv+oHoLSyshwdJ3M8YkygyzxV8s="}]},"_npmUser":{"name":"buckeyestudio","email":"dustinwloring1988@gmail.com"},"directories":{},"maintainers":[{"name":"buckeyestudio","email":"dustinwloring1988@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/toh-tool-web_0.1.1-rc.2_1787489429791_0.3517822534468744"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-23T12:50:29.693Z","0.1.1-rc.2":"2026-08-23T12:50:29.953Z","modified":"2026-08-23T12:50:30.221Z"},"maintainers":[{"name":"buckeyestudio","email":"dustinwloring1988@gmail.com"}],"description":"Model-facing web tools (web_search, web_fetch) over the TheOpen Harness web capability seam (ctx.web)","homepage":"https://github.com/dustinwloring1988/theopen-harness#readme","repository":{"type":"git","url":"git+https://github.com/dustinwloring1988/theopen-harness.git","directory":"packages/web/tool-web"},"author":{"name":"buckeyestudio"},"bugs":{"url":"https://github.com/dustinwloring1988/theopen-harness/issues"},"license":"MIT","readme":"# @buckeyestudio/toh-tool-web\n\n[English](README.md) | 中文\n\n面向模型的 web 工具套件 `web_search` 与 `web_fetch`，构建于 [web 能力 seam](../web/README.zh.md)（`ctx.web`）之上。它只负责面向模型的事项：工具名称、JSON Schema、snake_case 参数名称、提示词区段、结果数量上限、结果格式、HTML→markdown 呈现，以及 UI 呈现投影——`presentCall`、`presentResult`（以 `kind: 'search' | 'fetch'` 区分的 `card: 'web'` 结果卡片），以及承载有损渲染文本无法携带的结构化搜索来源或抓取摘要的 `output.presentationMeta`（见 [web-result-card Agent Note](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card.zh.md)）。所有 web 访问都通过 `ctx.web`；该包绝不导入具体提供方。两个工具都不公开面向模型的超时：每个工具的协作式工具调用超时预算通过配置在此声明（`fetchTimeoutMs`／`searchTimeoutMs`，附加为 `ToolDefinition.timeoutMs`），由 [`@buckeyestudio/toh-tool-call-timeout-policy`](../../guard/timeout-policy/README.zh.md)（`tools/execute` 包装层）强制执行。单项操作会转发 `exec.signal`；多查询搜索会把它与批次取消信号融合，使失败查询能够中止其余查询。\n\n每个工具独立注册；只需要其中一个工具的产品可以通过配置禁用另一个（`{ search: false }`／`{ fetch: false }`）。仅当抓取也通过配置启用时，搜索指引才会提及 `web_fetch`；仅启用搜索的组合则会要求模型使用返回的 snippet 并引用其 URL。\n\n## 工具\n\n| 工具 | 参数 | 行为 |\n|---|---|---|\n| `web_search` | `queries`（必填 string[]） | 用于发现信息。返回可选答案与来源 URL。它会并发执行 1 至 `searchMaxQueries` 个不同搜索，按轮询顺序合并来源，再应用组合后的 `searchMaxResults` 上限。单元素数组执行一次搜索。完全相同的查询只执行一次。任何搜索失败都会中止批次中的其余搜索；批次结算完毕后调用才返回错误。两个上限都不面向模型。 |\n| `web_fetch` | `url`（string） | 获取特定 URL。HTML 主体渲染为 markdown（turndown，带 GFM 表格／删除线）；文本主体原样通过。非 2xx 状态会报告，而非报错。工具调用超时是部署策略（`toh-tool-call-timeout-policy`），不是模型参数。 |\n\n两个工具都选择并发调度，因为提供方读取会返回内容，不会修改父 agent（智能体）的状态。\n\n规范化后的服务结果也是标准工具值：`WebSearchResult` 与 `WebFetchResult`。原生渲染器会保留下文所述的答案、来源和抓取正文文本；提供方对搜索结果数量和正文大小的上限仍属于获取限制，而非仅用于呈现的截断。\n\n## 配置\n\n| 配置键 | 默认值 | 含义 |\n|---|---|---|\n| `search` | `true` | 注册 `web_search`。 |\n| `fetch` | `true` | 注册 `web_fetch`。 |\n| `searchMaxResults` | `8` | 一次 `web_search` 调用返回的来源数量上限（seam 截断各提供方列表；工具还会限制多查询组合列表）。 |\n| `searchMaxQueries` | `4` | 一次 `web_search` 调用接受的查询数量上限。配置值会出现在提示词指引与 schema 描述中。 |\n| `fetchTimeoutMs` | `30000` | `web_fetch` 的协作式工具调用超时预算（ms）。 |\n| `searchTimeoutMs` | `30000` | `web_search` 的协作式工具调用超时预算（ms）。 |\n| `fetchMaxOutputChars` | `200000` | 同步转换的源字符数与单次完整 `web_fetch` 输出的上限（状态头、渲染后的主体与页脚合并计算）；主体被截断时，在能容纳的情况下附带截断提示。 |\n\n`searchMaxQueries` 在完全相同的字符串去重前限制可接受数组、提供方请求扇出与组合后的提供方答案增长；校验会在任何搜索开始前拒绝超限数组，随后分发只保留每个查询第一次出现的位置。该设置与各提供方自己的 `maxUses` 等控制项共同构成产品的搜索预算；通用 seam 不公开提供方内部的原生搜索计数。`fetchTimeoutMs`／`searchTimeoutMs` 声明每个工具的协作式超时预算（附加为 `ToolDefinition.timeoutMs`），由 [`@buckeyestudio/toh-tool-call-timeout-policy`](../../guard/timeout-policy/README.zh.md) 强制执行；面向模型的 schema 不公开超时参数。`fetchMaxOutputChars` 同时限制同步转换工作量和完整渲染结果：只转换至多该数量的源字符，随后对状态头、转换后的前缀和截断提示合并设限。默认值为本地提供方的 100,000 字符主体上限留出余量，但渲染膨胀仍可能使最终上限截断结果。\n\n```yaml\n- id: tool-web\n  name: '@buckeyestudio/toh-tool-web'\n```\n\n## 稳定注册\n\n工具注册遵循产品**启用状态**，而非后端可用性。即使选中的提供方缺失、错误配置、存在歧义或暂时不可用，工具仍保持可见；seam 在执行时解析提供方，执行以结构化 `WebError`（例如 `WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`）失败，`ToolRuntime.execute()` 会把它转为模型可读、钩子／UI 可路由的错误工具结果。这样无需把插件加载顺序、凭据状态或 HMR（热模块替换）时机纳入面向模型约定，也能保持模型 schema 稳定。要彻底移除 web 工具，请在此处通过配置将其禁用。\n\n工具绝不会调用提供方的 `available()`，也不会枚举提供方；唯一执行路径是 `ctx.web.search()`／`ctx.web.fetch()`，提供方不可用时，选择机制会在执行阶段抛出结构化 `WebError`，其错误码由工具接收。提供方选择完全留在 seam 内，由单一主体负责。\n\n## 模型体验\n\n### 系统提示词\n\n#### 模型看到的内容\n\n搜索与抓取分别贡献以下 web-search 和 web-fetch 指引。搜索会在注册时根据配置选用启用抓取或仅搜索的文本。scope 工具限制不会移除这些独立注册的区段。\n\n##### 启用抓取时的 Web 搜索指引\n\n```markdown\nUse the web_search tool to discover current information on the web. The required queries array accepts 1–4 non-empty search queries; use a one-item array for a single search. It returns an optional answer plus a list of source URLs. Follow up with web_fetch when you need the full content of a specific result, and cite the relevant URLs as markdown links.\n```\n\n##### 仅搜索时的 Web 搜索指引\n\n```markdown\nUse the web_search tool to discover current information on the web. The required queries array accepts 1–4 non-empty search queries; use a one-item array for a single search. It returns an optional answer plus a list of source URLs. Use the returned source snippets when available, and cite the relevant URLs as markdown links.\n```\n\n##### Web 抓取指引\n\n```markdown\nUse the web_fetch tool to retrieve the content of a specific HTTP(S) URL (for example a result from web_search). It returns the page content decoded to text. Cite the URL as a markdown link when you use its content.\n```\n\n#### Token 影响\n\n每个通过配置启用的工具都会为每次请求增加固定的指引 token 开销，即使限制隐藏了其 schema。切换抓取状态或更改 `searchMaxQueries` 会改变搜索指引；切换抓取状态还会注册或移除抓取区段。\n\n#### KV Cache 影响\n\n只要启用工具、scope 与指引文本不变，前缀就保持稳定。配置启用状态（包括因切换抓取状态而改变搜索指引分支）、更改 `searchMaxQueries` 或插件生命周期可能使从第一个变化的提示词区段起的复用失效；scope schema 限制不会移除该区段。\n\n### 工具 schema\n\n#### 模型看到的内容\n\n模型会看到生成的 [`web_search` 与 `web_fetch` schema](../../../docs/tool-catalog.zh.md#buckeyestudiotoh-tool-web)。结果数量与超时预算属于部署设置，不是模型参数。\n\n#### Token 影响\n\n对于已解析的 `searchMaxQueries`，每次请求都会产生固定的 schema token 开销；通过配置禁用会同时移除 schema 与指引，scope 限制只移除 schema。\n\n#### KV Cache 影响\n\n只要定义、已解析查询上限与可见性不变，前缀就保持稳定。配置启用状态、更改 `searchMaxQueries`、插件生命周期或 scope 限制可能使从第一个变化的 schema token 起的复用失效。\n\n### 搜索结果\n\n#### 模型看到的内容\n\n可选的提供方答案之后是 `Sources:`，再跟随内容取决于数据且格式严格为 `- [<title-or-url>](<url>)` 的行，并可添加后缀 ` — <snippet> (<publishedAt>)`。多查询调用会让每个完全相同的查询字符串只执行一次，并保留它首次出现的位置；调用会用来源查询作为 markdown 标题标注每个提供方答案，按 URL 对来源去重，并从每个查询取得同一排名的一条来源后再推进至下一排名。既无答案也无来源时，结果显示 `No results found.`。列表被截断至上限时会添加 `(Showing the first <count> sources. Refine the query for more.)`；每个结果都以 `Cite the relevant URLs above as markdown links in your answer.` 结尾。\n\n#### Token 影响\n\n数据相关结果会重复发送直到压缩（compaction）；查询请求扇出由 `searchMaxQueries` 限制，来源数量由 `searchMaxResults` 限制。\n\n#### KV Cache 影响\n\n仅追加；新可见内容位于可复用请求前缀之后，不会使现有 KV Cache 条目失效。\n\n### 搜索失败\n\n#### 模型看到的内容\n\n多查询调用中的任何查询失败时，`web_search` 会中止其余搜索，等待所有已启动搜索结算，丢弃成功结果，并针对首次失败返回 `Error: <message>`。\n\n#### Token 影响\n\n只有保留的错误结果会增加 token；被丢弃的成功结果不会进入模型历史。\n\n#### KV Cache 影响\n\n仅追加；错误位于可复用请求前缀之后，不会使现有 KV Cache 条目失效。\n\n### 抓取结果\n\n#### 模型看到的内容\n\n成功抓取的精确形状是 `Fetched <finalUrl> (HTTP <statusCode>)`、一个空行，以及由提供方返回的已解码正文。发生截断时会再添加一个空行和 `(Content truncated. Fetch a more specific URL or section for the full text.)`；失败变为 `Error: <message>`。查询与 URL 保留在调用历史中。\n\n#### Token 影响\n\n提供方上限限制主体大小；保留的调用参数与结果会重复发送直到压缩，超时策略可以把迟到结果替换为简短错误。\n\n#### KV Cache 影响\n\n仅追加；新可见内容位于可复用请求前缀之后，不会使现有 KV Cache 条目失效。\n\n### 参数错误\n\n#### 模型看到的内容\n\nschema 校验会在执行前拒绝缺失或非数组的 `queries` 字段以及非字符串数组元素。值错误精确地变为 `Error: queries must contain at least one query`、配置上限为 1 时的 `Error: queries must contain at most 1 query`、上限更大时的 `Error: queries must contain at most <count> queries`、`Error: each query must be a non-empty string` 或 `Error: url must be a non-empty string`。\n\n#### Token 影响\n\n只有失败调用会增加这些保留 token。\n\n#### KV Cache 影响\n\n仅追加；新可见内容位于可复用请求前缀之后，不会使现有 KV Cache 条目失效。\n\n## 已知限制与暂缓事项\n\n- **没有覆盖整个批次的原生搜索计数器**：`searchMaxQueries` 限制 `ctx.web.search` 调用数，但提供方可以在每次调用内执行多次原生搜索。例如，配置了 `maxUses` 的模型型提供方最多可以执行 `searchMaxQueries × maxUses` 次原生搜索；`searchMaxResults` 只限制返回给调用方的组合来源。部署通过这些独立的消费方与提供方设置控制成本，因为通用 seam 不知道提供方内部的搜索计量单位。\n- **HTML→markdown 转换会在 GFM 无法安全表示的输入上降级**：[turndown](https://github.com/mixmark-io/turndown)（带 GFM 表格／删除线）通过真实 DOM 转换至多 `fetchMaxOutputChars` 个源字符。保守的 512 层词法守卫会将深层或嵌套有歧义的主体作为原始 HTML 直接透传，转换异常也会如此处理；表格的 `colspan` 会被忽略，因为 GFM 无法表示跨列单元格。这些限制可避免阻塞事件循环，也避免不受信任的数值属性使输出膨胀（[已归档的依赖决策](../../../.agents/notes/archived/simplification/2026-07-26-turndown-for-tool-web-html-markdown.md)）。\n- **面向模型的接口有意保持精简，后续扩展暂缓**：`max_results` 保持为配置上限（不是模型参数），`web_fetch` 只接受 `url`（没有 `format`／`prompt`／LLM（大语言模型）摘要模式）；两项都列为 [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md) 中的后续步骤。\n- **没有 web 专用权限策略**：两个工具都不会请求 `ctx.approval` 就直接执行；需要确认的部署必须添加 `tools/pre-execute` 策略，该包不定义持久化的 URL／域名授权。\n","readmeFilename":"README.zh.md","_rev":"1-0d89d60dfc5d5bf9c1e270c092ec7c32"}