feat(browser): 取正文能力 + web-fetch 浏览器降级档接线(解封 Z5/B5)
Z5(c2e413e)把 web-fetch 的降级链与注入点做完了,但「取正文」入口缺失 ⇒ 组合根拿不到 BodyRenderer、这一档实际关着(当时如实登记)。本片补上: - internal/capability/browser/render.go:新增 Manager.RenderText(ctx,url) (导出的进程内能力)—— 先过 GuardURL(与全仓同一份 SSRF 判定源)、复用 withSession/session、等 readyState=complete 之后才取 body.innerText; 渲染失败 = 分类错误,渲染成功但正文为空 = 空串+无错(不冒充成功/失败)。 - cmd/cyrene/wire_body_fallback.go:适配器 + 挂载点,把 Manager 适配成 io.BodyRenderer 并用 WithBrowserFallback 挂上;web_runtime 里把浏览器 接线**上移到 io 工具集之前**(顺序颠倒会静默关死这一档)。 - plugins/tools/browser/tool.go:新增 Tool.Manager(),供组合根取驱动句柄。 开关口径(裁决,依据 design/28 §1 M5 / §7 判据 4 / §8 B5):**有可用浏览器 就挂,没有就不挂**,不新增开关 —— ① 设计把 M5/B5 写成要落地生效的降级档,不是永远关着的空壳; ② 设计 §8 的可调项清单里没有这条降级档的开关,`.env` 已冻结 ⇒ 自造开关属 「自行发挥」; ③ io 库层「不传 = 默认关」的语义一字未改,本片只把组合根从「永远关」改成 「没来源就关」,并留带来源的 WARN(reason=no-usable-browser)。 ⚠️ 若日后要「有浏览器也需显式开启」,得先给设计定开关落点,代码侧一行改回。 验收(主会话复跑 + 亲自变异):go build ./... + 三包 vet 绿;browser/io 两包 测试绿(cmd/cyrene 由子代理跑过全绿);我用 -overlay 把 GuardURL 的判定对象 换成常量 URL(绕过被拒目标)⇒ TestManager_RenderTextBlockedURLRejectedBeforeAnyProcess 变红,证明判定确实**在起任何进程之前**跑。 ⚠️ 生产端到端未验:按红线没重启后端、没起真 Chrome ⇒「真页面 → browser 取到 正文」这条链只有假 CDP + 组合根接线级证据。 ⚠️ design/28 有 6 处表述与代码现状冲突(归属 web-fetch vs web-search、extract 动作归属、B5 排期、状态过期等),已登记待我同步文档。
This commit is contained in:
1 parent
25aa50e532
commit
378faf212e
7 files changed
+685
-31
No files matched your search
@@ -164,8 +164,19 @@ func (a *app) wireRuntime() error {
|
||||
if err := basic.Register(a.caps); err != nil {
|
||||
return fmt.Errorf("register basic tools: %w", err)
|
||||
}
|
||||
// io 工具集的选项(含 web-search 的端点与超时裁决)在 wire_io_tools.go 一处组装:
|
||||
// 端点不可用时它交出 WithoutSearch(),使 web-search **不进注册面**(WS1-A)。
|
||||
// 浏览器工具(design/28 B1 接线,切片 V5;挂点由 X3 归位到这里):
|
||||
// 与 vision / transcode 同族 —— 可选增强,不可用就**不注册**(模型看不见这个
|
||||
// 工具,而不是看得见、一调就报错),失败不阻塞启动;装配细节与六条口径都在
|
||||
// wire_browser.go 一处。它的关闭挂点在 a.close(wire_services.go),成对。
|
||||
//
|
||||
// ⚠️ 它必须排在 io 工具集**之前**(切片 Z5 的解封):io 的 web-fetch 降级档
|
||||
// (design/28 §1 M5 / §8 B5)按「能力面里到底有没有可用浏览器」决定挂不挂,
|
||||
// 而那条判据就是在这里被写进注册面的(`bodyFallbackOption()`,见
|
||||
// wire_body_fallback.go)。装配顺序即这条判定的输入,颠倒过来降级档会静默关死。
|
||||
a.wireBrowser()
|
||||
// io 工具集的选项(含 web-search 的端点与超时裁决、web-fetch 的浏览器降级档)
|
||||
// 在 wire_io_tools.go 一处组装:端点不可用时它交出 WithoutSearch(),使 web-search
|
||||
// **不进注册面**(WS1-A)。
|
||||
ioTools, ioErr := iotools.New(a.cfg, a.ioToolOptions()...)
|
||||
if ioErr != nil {
|
||||
return fmt.Errorf("build io tools: %w", ioErr)
|
||||
@@ -177,11 +188,6 @@ func (a *app) wireRuntime() error {
|
||||
}
|
||||
a.wireVision()
|
||||
a.wireTranscode()
|
||||
a.wireBrowser()
|
||||
// 浏览器工具(design/28 B1 接线,切片 V5;挂点由 X3 归位到这里):
|
||||
// 与 vision / transcode 同族 —— 可选增强,不可用就**不注册**(模型看不见这个
|
||||
// 工具,而不是看得见、一调就报错),失败不阻塞启动;装配细节与六条口径都在
|
||||
// wire_browser.go 一处。它的关闭挂点在 a.close(wire_services.go),成对。
|
||||
|
||||
// 上下文溢出压缩:预算按模型窗口推导(CONTEXT_MAX_TOKENS 未设置时;
|
||||
// 显式 >0 = 覆盖、0/负 = 关闭),推导与「窗口未声明」的 WARN 都在
|
||||
|
||||
Reference in new issue
Block a user