Files
Cyrene_v2/plugins/tools/io/search/paneldata.go
T
AskaEth 120d926cf8 feat(search): 搜索 provider 可变源 + 插件声明面板(PLG-4)
- 新增 $DATA_DIR/config/plugins/web-search.json(0600 + temp+rename,文件名 = 插件 id)
- 组合根改「先读可变源、缺失回落 .env 播种」;**不新增任何 env 键**(.env 已冻结)
- 多实例:每家 provider 独立 key/baseURL/启用态 + 「测试连通」探针
- 用 PLG-1 的声明库给出该面板的 adminPanels 声明;动作名交给 PLG-2 的通用动作端点分发
  (本片自己不开路由)

⚠️ 本片自认越界:改了 cmd/cyrene/wire_web_search_test.go(既有测试,为适配 DataDir);
  另有 design/28 的相关注册留给主会话。
2026-10-06 09:04:04 +08:00

88 lines
3.6 KiB
Go

package search
import "strings"
// 本文件是「搜索提供商」页的**数据面**:表格行与下拉选项的来源。
//
// 它只做**翻译**(事实 → 面板要的形状),不读文件、不开路由、不鉴权 —— 那些是插件管理器
// 与宿主端点的事(design/09 §5.2.1 B)。放这里的理由只有一个:`state` 与选项值的语义
// 属于 provider 领域(要问 `Configured` / `KnownNames`),散到宿主里就会与面板声明各写一套。
// 表格 `state` 列的取值(design/09 §5.2 示例:「ok | 未配置 | 凭据失效 | 未知」)。
//
// 「凭据失效」不在这里:它只能由一次真实调用得知(那是 plugin.testProvider 的结论,
// 见 probe.go),列表接口不该为了它去逐家发请求。
const (
// StateOK 表示这家可以用了(名字已登记且已配齐且启用)。
StateOK = "ok"
// StateNotConfigured 表示这个名字已登记,但没配齐(云家缺 key、searxng 缺地址)。
StateNotConfigured = "not_configured"
// StateDisabled 表示这条已被显式停用(enabled=false)。
StateDisabled = "disabled"
// StateUnknown 表示这个名字本期没登记(写错了 / 还没做,如 tavily)。
StateUnknown = "unknown"
)
// ProviderInput 是构造一行所需的最小事实(一条 provider 配置)。
//
// 刻意用平铺字段而不是引用 runtimeconfig 的类型:search 包是插件实现,不该认识宿主的
// 配置文件形状(那份形状属于宿主,见 internal/config/runtimeconfig/websearch.go)。
type ProviderInput struct {
// Provider 是 provider 名。
Provider string
// APIKey 是上游凭据(判定是否配齐用,**绝不进行数据**)。
APIKey string
// BaseURL 是上游基地址(同上,判定用)。
BaseURL string
// Enabled 是启用态。
Enabled bool
}
// ProviderRow 是「已配置的提供商」表格的一行。字段名即表格列的 key(panel.go 的 columns)。
//
// 凭据与基地址**都不进行数据**:列表只需要状态,凭据读侧无明文(design/09 §5.4.2),
// 而基地址可能带用户名口令。要看地址就点「重配凭据」,由表单一对一带回。
type ProviderRow struct {
Provider string `json:"provider"`
State string `json:"state"`
Enabled bool `json:"enabled"`
}
// BuildRows 把各条配置翻译成表格行。
//
// 判定顺序是把「根因」排在前面:名字没登记(写错了)> 显式停用 > 没配齐 > 可用。
// 一个停用的陌生名字报 `unknown` —— 名字错了才是要修的那处。
func BuildRows(inputs []ProviderInput) []ProviderRow {
out := make([]ProviderRow, 0, len(inputs))
for _, in := range inputs {
out = append(out, ProviderRow{
Provider: strings.ToLower(strings.TrimSpace(in.Provider)),
State: providerState(in),
Enabled: in.Enabled,
})
}
return out
}
// providerState 判定一条配置的表格状态。
func providerState(in ProviderInput) string {
name := strings.ToLower(strings.TrimSpace(in.Provider))
if !Known(name) {
return StateUnknown
}
if !in.Enabled {
return StateDisabled
}
if !Configured(name, in.APIKey, in.BaseURL) {
return StateNotConfigured
}
return StateOK
}
// ProviderOptions 返回 `optionsFrom: plugin:providers` 的选项值 —— 本期**全部已登记**的
// provider 名(含尚未配置的家),稳定排序。
//
// 为什么给全部而不是「已配置的家」:表单的用途就是**新增**一家,只列已配置的会让
// 「第一次配置」无从选起。可用性不靠下拉限制,靠列表的 `state` 列如实呈现。
func ProviderOptions() []string { return KnownNames() }