From 314c07835e62f575ab8cd6f4c3c92bab8dd4f856 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Thu, 9 Oct 2025 10:36:55 +0300 Subject: Feat: add external tool web search --- tools.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'tools.go') diff --git a/tools.go b/tools.go index acc4697..c1b84ab 100644 --- a/tools.go +++ b/tools.go @@ -1,8 +1,13 @@ package main import ( + "bytes" + "encoding/json" "fmt" + "gf-lt/config" "gf-lt/models" + "io" + "net/http" "regexp" "strings" "time" @@ -76,6 +81,69 @@ After that you are free to respond to the user. sysLabels = []string{"basic_sys", "tool_sys"} ) +func populateTools(cfg config.Config) { + // if we have access to some server with funcs we can populate funcs (tools|toolbelt?) with it + // there must be a better way + if cfg.SearchAPI == "" || cfg.SearchDescribe == "" { + return + } + resp, err := httpClient.Get(cfg.SearchDescribe) + if err != nil { + logger.Error("failed to get websearch tool description", + "link", cfg.SearchDescribe, "error", err) + return + } + descResp := models.Tool{} + if err := json.NewDecoder(resp.Body).Decode(&descResp); err != nil { + logger.Error("failed to unmarshal websearch tool description", + "link", cfg.SearchDescribe, "error", err) + return + } + fnMap["web_search"] = websearch + baseTools = append(baseTools, descResp) + logger.Info("added web_search tool", "tool", descResp) + return +} + +// {"type":"function","function":{"name":"web_search","description":"Perform a web search to find information on varioust topics","parameters":{"type":"object","properties":{"num_results":{"type":"integer","description":"Maximum number of results to return (default: 10)"},"query":{"type":"string","description":"The search query to find information about"},"search_type":{"type":"string","description":"Type of search to perform: 'api' for SearXNG API search or 'scraper' for web scraping (default: 'scraper')"}},"required":["query"]}}} + +// web search (depends on extra server) +func websearch(args map[string]string) []byte { + // make http request return bytes + query, ok := args["query"] + if !ok || query == "" { + msg := "query not provided to web_search tool" + logger.Error(msg) + return []byte(msg) + } + payload, err := json.Marshal(args) + if err != nil { + logger.Error("failed to marshal web_search arguments", "error", err) + msg := fmt.Sprintf("failed to marshal web_search arguments; error: %s\n", err) + return []byte(msg) + } + req, err := http.NewRequest("POST", cfg.SearchAPI, bytes.NewReader(payload)) + if err != nil { + logger.Error("failed to build an http request", "error", err) + msg := fmt.Sprintf("failed to build an http request; error: %s\n", err) + return []byte(msg) + } + resp, err := httpClient.Do(req) + if err != nil { + logger.Error("failed to execute http request", "error", err) + msg := fmt.Sprintf("failed to execute http request; error: %s\n", err) + return []byte(msg) + } + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + if err != nil { + logger.Error("failed to read response body", "error", err) + msg := fmt.Sprintf("failed to read response body; error: %s\n", err) + return []byte(msg) + } + return data +} + /* consider cases: - append mode (treat it like a journal appendix) -- cgit v1.2.3