feat(search): 结果条数上限 5 → 10,并让「上限」真的是上限
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

主人原话:「返回五条结果会不会太少了?」。裁定:**上限抬高到 10,且它是真上限**
(模型要 50 也只给 10);模型要更少(3)时**尊重模型**;缺省/非法(≤0/非数)⇒ 上限。

- plugins/tools/io/web_search.go:`n := resultLimit(s.maxResults, m)` 一处收口
  (原来是 `if count>0 { n = count }` ⇒ 模型的 count 能顶掉配置上限,与
  .env.example 写的「条数上限」不符 —— 那是一条真口径缺陷,本次一并修正)。
- internal/config/websearch.go:`WEB_SEARCH_MAX_RESULTS` 代码默认值 5 → 10
  (三处口径现已一致:env 默认 10 / io 包 defaultMaxResults 10 / 各家发给上游的
  请求区间是另一回事,未动)。
- 生产:`data/config/plugins/web-search.json` 的 `maxResults` 5 → 10 + 一次
  saveProvider 触发**热重载**(applied+registered),盘上已生效。

验收(主会话复跑 + 亲自打两个变异):
- io 包 / internal/config / cmd/cyrene 相关用例全绿;
- 变异 A(拆掉上限、恒取 50)⇒ **4 条用例变红**(含「默认上限 10」「count 非数值
  ⇒ 上限」「count=0 ⇒ 上限」「既有 MaxResultsOption」);
- 变异 B(默认值退回 5)⇒ internal/config 的默认值断言变红。

🔴 顺带挖出一条真缺陷(**本片只报不修,等派**):`maxResults` **在面板 UI 上
根本改不了** —— ① `search/panel.go` 的字段表里没有这个字段(输入框不显示);
② `saveProvider` 只并 provider/apiKey/baseUrl/enabled;③ `mergeSelectionPatch`
只处理 primary/fallback ⇒ **手工塞进 values 也会被静默丢弃**(「我改了它却没变」
成立)。修它要给面板加一个数字字段 + 三态落 `f.MaxResults`,属**管理面板对外契约
变更**(须同步 Docs/api-client.md),留给主会话。
This commit is contained in:
AskaEth committed 2026-10-07 10:58:40 +08:00
1 parent 7f63c5bec4
commit bff57bd1ae
5 files changed
+298 -9

No files matched your search

+4 -2
View File
@@ -22,8 +22,10 @@ type WebSearchConfig struct {
// 链上的家**只在「不可用」时**才被跳过(无 key / 网络失败 / 额度错误…);
// 结果里会如实标注**实际应答**的那一家,绝不拿兜底冒充主力。
Fallback []string `env:"WEB_SEARCH_FALLBACK"`
// MaxResults 是单次检索返回的条数上限(design/27 §3 默认 5)。
MaxResults int `env:"WEB_SEARCH_MAX_RESULTS" default:"5"`
// MaxResults 是单次检索返回的条数上限(主人 2026-10-07 裁定:默认由 5 提到 10;
// design/27 §3 记的仍是 5,待同步设计文档)。它是**真上限**:模型给的 count 只能要得
// 更少,顶不掉它(`plugins/tools/io/web_search.go` 的 resultLimit)。
MaxResults int `env:"WEB_SEARCH_MAX_RESULTS" default:"10"`
// Endpoint 是 **searxng provider** 的端点(SearXNG 兼容的 `format=json` GET 接口)。
//
+3 -3
View File
@@ -23,7 +23,7 @@ func wsTestLoad(t *testing.T, extra ...string) (*Config, error) {
}
// TestWebSearchProvider_Defaults 钉住三个新键的默认值:provider=searxng、
// maxResults=5、fallback 为空(= 只管手选那一家)。
// maxResults=10、fallback 为空(= 只管手选那一家)。
func TestWebSearchProvider_Defaults(t *testing.T) {
cfg, err := wsTestLoad(t)
if err != nil {
@@ -32,8 +32,8 @@ func TestWebSearchProvider_Defaults(t *testing.T) {
if cfg.WebSearch.Provider != "searxng" {
t.Fatalf("WEB_SEARCH_PROVIDER 默认值 = %q, want searxng", cfg.WebSearch.Provider)
}
if cfg.WebSearch.MaxResults != 5 {
t.Fatalf("WEB_SEARCH_MAX_RESULTS 默认值 = %d, want 5", cfg.WebSearch.MaxResults)
if cfg.WebSearch.MaxResults != 10 {
t.Fatalf("WEB_SEARCH_MAX_RESULTS 默认值 = %d, want 10", cfg.WebSearch.MaxResults)
}
if len(cfg.WebSearch.Fallback) != 0 {
t.Fatalf("WEB_SEARCH_FALLBACK 未配置时应为空, got %v", cfg.WebSearch.Fallback)