Adds searxng support for tool calling
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { convert as htmlToText } from "html-to-text";
|
||||
import type OpenAI from "openai";
|
||||
import { z } from "zod";
|
||||
import { env } from "../env.js";
|
||||
import { exaClient } from "../search/exa.js";
|
||||
import { searchSearxng } from "../search/searxng.js";
|
||||
import type { ChatMessage } from "./types.js";
|
||||
|
||||
const MAX_TOOL_ROUNDS = 4;
|
||||
@@ -21,6 +23,8 @@ const WebSearchArgsSchema = z
|
||||
})
|
||||
.strict();
|
||||
|
||||
type WebSearchArgs = z.infer<typeof WebSearchArgsSchema>;
|
||||
|
||||
const FetchUrlArgsSchema = z
|
||||
.object({
|
||||
url: z.string().trim().url(),
|
||||
@@ -267,8 +271,7 @@ function normalizeIncomingMessages(messages: ChatMessage[]) {
|
||||
return [{ role: "system", content: CHAT_TOOL_SYSTEM_PROMPT }, ...normalized];
|
||||
}
|
||||
|
||||
async function runWebSearchTool(input: unknown): Promise<ToolRunOutcome> {
|
||||
const args = WebSearchArgsSchema.parse(input);
|
||||
async function runExaWebSearchTool(args: WebSearchArgs): Promise<ToolRunOutcome> {
|
||||
const exa = exaClient();
|
||||
const response = await exa.search(args.query, {
|
||||
type: args.type ?? "auto",
|
||||
@@ -292,6 +295,7 @@ async function runWebSearchTool(input: unknown): Promise<ToolRunOutcome> {
|
||||
const results = Array.isArray(response?.results) ? response.results : [];
|
||||
return {
|
||||
ok: true,
|
||||
searchEngine: "exa",
|
||||
query: args.query,
|
||||
requestId: response?.requestId ?? null,
|
||||
results: results.map((result: any, index: number) => ({
|
||||
@@ -309,6 +313,40 @@ async function runWebSearchTool(input: unknown): Promise<ToolRunOutcome> {
|
||||
};
|
||||
}
|
||||
|
||||
async function runSearxngWebSearchTool(args: WebSearchArgs): Promise<ToolRunOutcome> {
|
||||
const response = await searchSearxng(args.query, {
|
||||
numResults: args.numResults ?? DEFAULT_WEB_RESULTS,
|
||||
includeDomains: args.includeDomains,
|
||||
excludeDomains: args.excludeDomains,
|
||||
});
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
searchEngine: "searxng",
|
||||
query: args.query,
|
||||
requestId: response.requestId,
|
||||
results: response.results.map((result, index) => ({
|
||||
rank: index + 1,
|
||||
title: result.title,
|
||||
url: result.url,
|
||||
publishedDate: result.publishedDate,
|
||||
author: null,
|
||||
summary: result.summary,
|
||||
text: result.text,
|
||||
highlights: result.summary ? [clipText(result.summary, 280)] : [],
|
||||
engines: result.engines,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
async function runWebSearchTool(input: unknown): Promise<ToolRunOutcome> {
|
||||
const args = WebSearchArgsSchema.parse(input);
|
||||
if (env.CHAT_WEB_SEARCH_ENGINE === "searxng") {
|
||||
return runSearxngWebSearchTool(args);
|
||||
}
|
||||
return runExaWebSearchTool(args);
|
||||
}
|
||||
|
||||
function assertSafeFetchUrl(urlRaw: string) {
|
||||
const parsed = new URL(urlRaw);
|
||||
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
||||
|
||||
Reference in New Issue
Block a user