feat(search): provider 热重载 + primary/fallback(W3)

- 保存被包成事务:快照 → 落盘 → 按新配置重建工具 → 原子替换注册表条目(registry.ReplaceTool
  窄方法,保留运行期 Policy);下一轮即生效,不要求重启
- 若新配置会让后端下次起不来(主家未配齐 fail-fast)⇒ 文件按字节回滚 + 409 config_unstartable
- 声明面补 primary + fallback[](可配可生效);否决「另开 form」方案(会破坏既有 reauth 回填)
- 主 provider 解析口径核查结论:没被 PLG-4 改坏(顺手修了一处日志缺陷)
- 4 个变异自检(丢 Policy/不换条目/回滚 no-op/忽略 fallback)
This commit is contained in:
AskaEth committed 2026-10-06 15:59:12 +08:00
1 parent 5ee5f9126f
commit a30f4a49ff
12 files changed
+1696 -16

No files matched your search

+8 -5
View File
@@ -8,8 +8,10 @@ package main
//
// 三个文件的分工(都在本包):
// - 本文件:登记入口、处理器环境、动作名映射、「声明了却没实现」的装配期核对;
// - `websearch_action_data.go`:五个动作的业务数据面(可变源的读写与翻译、载荷解析);
// - `websearch_probe.go`:探针的传输层绑定(HTTP 客户端 + 同主机守卫 + 状态映射)。
// - `websearch_action_data.go`:动作本体的业务数据面(可变源的读写与翻译、载荷解析);
// - `websearch_probe.go`:探针的传输层绑定(HTTP 客户端 + 同主机守卫 + 状态映射);
// - `websearch_reload.go`:保存后的**热重载**事务(重建工具 + 换注册表条目 + 失败回滚);
// - `websearch_selection.go`:表单里两个文件级字段(主 provider / 降级链)的读写。
//
// 三条边界:
//
@@ -20,8 +22,9 @@ package main
// 3. **凭据不出后端**:读侧只回掩码(`MaskedWebSearchFile`),日志只记 provider 名与
// 结果码,绝不记 key / 地址。
//
// 本片不做的事(如实登记,见报告 §未做):不热替换**运行中**的 web-search 工具 ——
// 面板保存后工具仍用启动期解析出的 provider 接线,改动在下次重启生效。
// 热重载(切片 W3;裁决 2026-10-06 #1):保存动作被 `webSearchActionHandlersWithHotReload`
// 包上事务 —— 落盘成功后重建 web-search 工具并替换注册表条目,**下一轮对话即生效**
// (design/09 §5.5 的端到端判据「面板加一家 ⇒ 不改 `.env`、不重启 ⇒ 下一次搜索真的走它」)。
import (
"log/slog"
@@ -68,7 +71,7 @@ func wireBuiltinPluginActions(mgr *pluginmgr.Manager, hub *pluginmgr.Panels, a *
"pluginId", search.PanelPluginID, "effect", "panel actions will answer 501")
return
}
handlers := webSearchActionHandlers(env)
handlers := webSearchActionHandlersWithHotReload(env, a, log)
for optionsFrom, handler := range webSearchOptionsHandlers(env) {
name := pluginmgr.OptionsActionName(optionsFrom)
if name == "" {