feat(io): web-fetch 直连→浏览器渲染降级档 + fetchedBy 如实标注(Z5 机制)
- 降级链:直连失败 / 判定为动态页 ⇒ 浏览器渲染取正文;返回体带 fetchedBy=direct|browser,
两条档的失败各自留痕(directError/browserError/browserSource/dynamicSuspect),**绝不静默替换**
- 被 SSRF 拒绝的目标**不换路**(红线);渲染器缺位时如实报双失败
- 3 个变异自检(去掉动态页判据 / 去掉 SSRF 短路 / 掩盖双失败)
⚠️ **生产接不通**:internal/capability/browser 没有「取正文」入口(不在本片文件面)⇒
开关默认关、不假装可用;解封形状已在报告里给出(加 RenderText ≈40 行)
This commit is contained in:
1 parent
20f82c9679
commit
c2e413ec38
6 files changed
+687
-41
No files matched your search
@@ -1,7 +1,8 @@
|
||||
package main
|
||||
|
||||
// 本文件装配 io 工具集(plugins/tools/io)的选项:知识检索器、日志,以及
|
||||
// **web-search 的后端与超时**(切片 WS1-A 接线 + WS1-B provider 层 + PLG-4 可变源)。
|
||||
// 本文件装配 io 工具集(plugins/tools/io)的选项:知识检索器、日志、
|
||||
// **web-search 的后端与超时**(切片 WS1-A 接线 + WS1-B provider 层 + PLG-4 可变源),
|
||||
// 以及 design/28 §8 B5 的**浏览器降级档开关**(`bodyFallbackOption`,当前 = 关)。
|
||||
//
|
||||
// 为什么单独成文件而不是塞在 wire_runtime.go 里:那条装配线本就接近文件行数上限,
|
||||
// 而这里新增的裁决(端点/provider 关闭 ⇒ 工具不进注册面;选定 provider 未登记/未配置
|
||||
@@ -90,10 +91,34 @@ func (a *app) ioToolOptions() []iotools.Option {
|
||||
opts := []iotools.Option{
|
||||
iotools.WithKnowledgeRetriever(a.retriever),
|
||||
iotools.WithLogger(a.log),
|
||||
// B5 的降级档开关(当前 = **关**,理由见 bodyFallbackOption 的文档)。
|
||||
a.bodyFallbackOption(),
|
||||
}
|
||||
return append(opts, a.webSearchOptions(webSearchCauseStartup)...)
|
||||
}
|
||||
|
||||
// bodyFallbackOption 是 design/28 §8 B5 的**开关点**:web-fetch 取正文时,直连失败 /
|
||||
// 判定为动态页要不要改走**浏览器渲染**(`iotools.WithBrowserFallback`,默认关)。
|
||||
//
|
||||
// **当前结论 = 关**(本函数返回的就是「不注入渲染器」)。理由在能力面上,不在这个开关上:
|
||||
// `internal/capability/browser` 目前只导出 `Open`(导航,回报 url/title/readyState)、
|
||||
// `Screenshot`、`Fingerprint` —— **没有**任何「取页面正文」的入口,`plugins/tools/browser`
|
||||
// 的工具动作也只有 `open`/`screenshot`/`info`。没有渲染器可注入,这一档打开也只可能
|
||||
// 如实失败 —— 那不是「降级档」,是给每次取正文加一条注定失败的噪声。
|
||||
//
|
||||
// 打开它要等能力面先补一个正文抽取入口(形如
|
||||
// `Manager.RenderText(ctx, url) (RenderedText, error)`,内部走既有的隔离世界求值 +
|
||||
// 同一份 `io.ValidateRequestURL` 判定源),届时把这里换成注入该适配器即可(一行)。
|
||||
// 在此之前**不假装可用** —— 与 web-search「拿不到后端就不注册」同一口径
|
||||
// (design/28 §7 判据 1、§7 判据 4 的诚实标注)。
|
||||
//
|
||||
// 为什么不在这里现场探测浏览器:`ioToolOptions()` 是**只读装配**,探测的副作用
|
||||
// (起进程 / 连 CDP 端点)不属于「取一份 io 选项」这件事 —— 口径见 `wire_browser.go`
|
||||
// 顶部第 3 条,且 `wire_browser_test.go` 钉住它不许在这里探测。
|
||||
func (a *app) bodyFallbackOption() iotools.Option {
|
||||
return iotools.WithBrowserFallback(nil)
|
||||
}
|
||||
|
||||
// buildWebSearchTool 按**当前生效配置**构造这一把 web-search 工具(面板保存后的热重载用它
|
||||
// 重建工具,见 websearch_reload.go)。
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user