refactor(search): provider 配置面去 env 化 —— 加新家不再需要动 .env
动因:`.env` 已冻结(基础键不加/不改/不删),而「加一家 provider」原本会逼出 新的 env 键(一家一个 struct 字段 + searchProviderVector 逐家读 + 逐家写死的 switch)⇒ 想接腾讯云元宝/秘塔就只能破红线。面板本来就该是插件配置的一等来源 ($DATA_DIR/config/plugins/web-search.json),故让**文件成为权威**。 - plugins/tools/io/search/registry.go:接入位表加 defaultBaseURL(「没配 baseUrl 回落代码默认值」从此只有一个出处);新增 Descriptor(s)/DefaultBaseURL。 - cmd/cyrene/websearch_providers.go(新):按接入位表逐家算出生效投影 —— 加一家时这里**零改动**,这正是本片的核心;顺手把 wire_io_tools.go 从 430 行 降到 342(它逼近 §10 的 500 行上限)。 - cmd/cyrene/wire_plugin_actions.go / websearch_action_data.go / websearch_selection.go:基地址判定统一走「文件值 → 接入位默认值」的进位链; checkPrimaryUsable 判据不放松(真没配齐仍 400 primary_not_configured)。 🔴 **一处对我任务书的纠正(子代理提出、我采纳)**:我要求「既有 6 家在文件里 没有该条目时仍回落 .env」。仓库现状**没有**这层回落,且有回归用例把它钉死 (TestWireIOTools_PanelConfigClearedProviderDoesNotReviveFromEnv:「文件里没有 的家不得从 .env 复活」)。本片按「不改变既有行为」实现 —— 我的要求才是错的: 文件一旦存在就是权威,env 只在文件缺失/为空时播种。 验收(主会话复跑 + 亲自变异):go build ./... + 两包 vet 绿;search 包与 cmd/cyrene 全绿;我用 -overlay 让文件里的 apiKey 被忽略 ⇒ 4 条用例变红 (含「无 env 字段的家只认文件也能进注册表」这条核心判据)。 ⚠️ 新家仍未接:腾讯云元宝(tencent_wsa)/ 秘塔(metaso)两片随后串行落地。
This commit is contained in:
1 parent
e5e5207c94
commit
bc1dee3f56
8 files changed
+825
-175
No files matched your search
@@ -80,9 +80,9 @@ func (e webSearchActionEnv) mergeSelectionPatch(
|
||||
|
||||
// checkPrimaryUsable 判定一个主 provider 名在**落盘后的文件**里是否可用。
|
||||
//
|
||||
// 判定口径与工具接线同源(searchProviderSpecs + effectiveBaseURL):云家看 API Key、
|
||||
// searxng 看接口地址,基地址缺位时回落到代码默认值;条目被显式停用视同没配
|
||||
// (effectiveSearchConfig 会跳过它)。
|
||||
// 判定口径与工具接线同源(resolveSearchProviders + resolveBaseURL):云家看 API Key、
|
||||
// searxng 看接口地址,基地址缺位时回落**该接入位的代码默认基地址**;条目被显式停用
|
||||
// 视同没配(装配期会跳过它)。判据本身**不放松**:真的没配齐的主家仍必须被拒。
|
||||
func (e webSearchActionEnv) checkPrimaryUsable(f runtimeconfig.WebSearchFile, name string) error {
|
||||
// 显式关闭(空串 / off / none)永远合法:它表示「不要这把工具」,工具不进注册面,
|
||||
// 后端照常启动(与 WEB_SEARCH_PROVIDER 的既有语义逐字一致)。
|
||||
@@ -93,19 +93,27 @@ func (e webSearchActionEnv) checkPrimaryUsable(f runtimeconfig.WebSearchFile, na
|
||||
return err
|
||||
}
|
||||
entry, found := findProviderEntry(f, name)
|
||||
base := ""
|
||||
if found {
|
||||
base = e.effectiveBaseURL(name, entry)
|
||||
if !found || !entry.IsEnabled() {
|
||||
return primaryNotConfiguredError(name)
|
||||
}
|
||||
if !found || !entry.IsEnabled() || !search.Configured(name, entry.APIKey, base) {
|
||||
return pluginmgr.NewActionError(actionCodePrimaryNotConfigured,
|
||||
fmt.Sprintf("主提供商 %q 还没配齐(缺 API Key / 接口地址,或这条被停用了):"+
|
||||
"先把它配好再选它 —— 否则这份配置会让后端下一次启动直接失败", name),
|
||||
http.StatusBadRequest, nil)
|
||||
// 基地址的进位链与装配期**同一个函数**:条目里的值 → 该接入位的默认基地址 → 空。
|
||||
// 云家的可用性只看 key(地址取默认值也照样能打通),searxng 的默认值是空
|
||||
// —— 因此「searxng 主家必须有地址」这条判据与既往逐字一致。
|
||||
if !search.Configured(name, entry.APIKey, resolveBaseURL(name, entry.BaseURL)) {
|
||||
return primaryNotConfiguredError(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// primaryNotConfiguredError 造「主家没配齐」这一条的 400:文案与码只有一份
|
||||
// (两个判据分支共用,免得两处措辞漂移)。
|
||||
func primaryNotConfiguredError(name string) error {
|
||||
return pluginmgr.NewActionError(actionCodePrimaryNotConfigured,
|
||||
fmt.Sprintf("主提供商 %q 还没配齐(缺 API Key / 接口地址,或这条被停用了):"+
|
||||
"先把它配好再选它 —— 否则这份配置会让后端下一次启动直接失败", name),
|
||||
http.StatusBadRequest, nil)
|
||||
}
|
||||
|
||||
// selectionNames 返回降级链的线形状(**非 nil 空切片**:nil 会在 JSON 里变成 null,
|
||||
// 而「一条降级都没有」与「这个字段没值」在前端不该长得不一样)。
|
||||
func selectionNames(names []string) []string {
|
||||
|
||||
Reference in new issue
Block a user