fix: the assistant is told which search engine it has, results say which one they came from (and why, when DuckDuckGo stood in), the stand-in is logged

This commit is contained in:
redtea committed 2026-10-16 10:59:39 +03:00
1 parent 060975a443
commit 74a22ab57f
4 files changed
+60 -23

No files matched your search

+39 -8
View File
@@ -6,6 +6,7 @@ import (
"errors"
"html"
"io"
"log"
"net/http"
"net/url"
"regexp"
@@ -99,8 +100,23 @@ var (
ddgSearch = webSearch
)
// searchWith asks the engine c names; DuckDuckGo if that one fails.
func searchWith(ctx context.Context, c searchConf, q string, n int) ([]searchResult, error) {
// engineName is how the engine is called to people and to the model.
func engineName(e string) string {
switch e {
case "searxng":
return "SearXNG"
case "brave":
return "Brave Search"
case "tavily":
return "Tavily"
}
return "DuckDuckGo"
}
// searchWith asks the engine c names; DuckDuckGo if that one fails. It
// tells which engine the results came from (and why, when it was not the
// chosen one).
func searchWith(ctx context.Context, c searchConf, q string, n int) ([]searchResult, string, error) {
var rs []searchResult
var err error
switch c.Engine {
@@ -111,15 +127,30 @@ func searchWith(ctx context.Context, c searchConf, q string, n int) ([]searchRes
case "tavily":
rs, err = searchTavily(ctx, c, q, n)
default:
return ddgSearch(ctx, q, n)
rs, err = ddgSearch(ctx, q, n)
return rs, "DuckDuckGo", err
}
if err != nil || len(rs) == 0 {
return ddgSearch(ctx, q, n)
why := "ничего не нашёл"
if err != nil {
why = err.Error()
}
log.Printf("search: %s failed (%s), DuckDuckGo instead", engineName(c.Engine), why)
rs, err = ddgSearch(ctx, q, n)
return rs, "DuckDuckGo (" + engineName(c.Engine) + " не ответил: " + why + ")", err
}
if len(rs) > n {
rs = rs[:n]
}
return rs, nil
return rs, engineName(c.Engine), nil
}
// searchPrompt tells the model it can search, and with what.
func searchPrompt(c searchConf) string {
return "\nПоиск в интернете включён (поисковик: " + engineName(c.Engine) + "): блок ```search\nзапрос\n``` - панель найдёт и пришлёт результаты " +
"(заголовок, адрес, отрывок) следующим сообщением, с пометкой, через какой поисковик они пришли.\n" +
"Ищи активно: свежие данные, версии, документация, тексты ошибок, всё, в чём не уверен, - сначала поиск, потом ответ со ссылками на найденное. " +
"Одно действие за ответ. Ссылки не выдумывай."
}
// getJSON fetches url (with the headers) into v.
@@ -241,10 +272,10 @@ func (s *Server) handleAISearch(w http.ResponseWriter, r *http.Request) {
writeJSON(w, map[string]any{"ok": false, "error": "пустой запрос"})
return
}
rs, err := searchWith(r.Context(), s.searchConf(), strings.TrimSpace(in.Q), 6)
rs, used, err := searchWith(r.Context(), s.searchConf(), strings.TrimSpace(in.Q), 6)
if err != nil {
writeJSON(w, map[string]any{"ok": false, "error": err.Error()})
writeJSON(w, map[string]any{"ok": false, "error": err.Error(), "engine": used})
return
}
writeJSON(w, map[string]any{"ok": true, "data": rs})
writeJSON(w, map[string]any{"ok": true, "data": rs, "engine": used})
}