99 lines · 2.9 KB · Lua
RawDownload
-- plugins/web_search.lua-- Web search via Tavily API (https://docs.tavily.com).---- Requires a Tavily API key in ~/.config/clm/config.lua:----   return {--       tools = {--           web_search = {--               api_key = "tvly-YOUR-KEY-HERE",--           },--       },--   }---- Get a free key at https://tavily.com (1000 queries/month on free tier). local api_key = clm.config.api_key or "" clm.tool_register("web_search", {    description = "Search the web and return titles, URLs, and content snippets.",    params_schema = {        type = "object",        properties = {            query = {                type = "string",                description = "search query",            },            max_results = {                type = "integer",                description = "max results to return (default 5, max 20)",            },            topic = {                type = "string",                description = "search category: general, news, or finance (default general)",            },        },        required = { "query" },    },    timeout_ms = 15000,    no_prompt = true,    invoke = function(args, ctx)        if not args.query or args.query == "" then            ctx:fail("missing 'query' argument")            return        end         local max = args.max_results or 5        if max > 20 then max = 20 end         local req = {            query = args.query,            max_results = max,            api_key = api_key,            include_answer = "basic",            topic = args.topic or "general",        }         local body = json.encode(req)        local resp, err = http.post("https://api.tavily.com/search", body)        if err then            ctx:fail("search request failed: " .. err)            return        end         if resp.status ~= 200 then            ctx:fail("search API returned status " .. tostring(resp.status))            return        end         local data = json.decode(resp.body)        if not data or not data.results then            ctx:fail("unexpected response from search API")            return        end         local lines = {}         -- Include the AI-generated answer if present.        if type(data.answer) == "string" and data.answer ~= "" then            lines[#lines + 1] = "Answer: " .. data.answer            lines[#lines + 1] = ""        end         for i, r in ipairs(data.results) do            lines[#lines + 1] = string.format("%d. %s", i,                r.title or "(no title)")            lines[#lines + 1] = "   " .. (r.url or "")            if type(r.content) == "string" and r.content ~= "" then                lines[#lines + 1] = "   " .. r.content            end            lines[#lines + 1] = ""        end         if #lines == 0 then            ctx:complete("No results found for: " .. args.query)        else            ctx:complete(table.concat(lines, "\n"))        end    end,})