src / toolsProvider.ts
import { text, tool, type ToolsProviderController } from "@lmstudio/sdk";
import { z } from "zod";
import { configSchematics, globalConfigSchematics } from "./configSchematics";
import { duckduckgoSearch, DuckDuckGoError } from "./duckduckgoClient";
import { searxngSearch, SearxngError } from "./searxngClient";
export async function toolsProvider(ctl: ToolsProviderController) {
const global = ctl.getGlobalPluginConfig(globalConfigSchematics);
const config = ctl.getPluginConfig(configSchematics);
const searchWeb = tool({
name: "search_web",
description: text`
Search the web and return ranked results (title, URL, snippet).
Use this for any question whose answer depends on up-to-date public information
(news, current events, recent releases, prices, sports scores, biographies of
living people, software documentation that may have changed). Quote or summarise
the snippets and cite the URLs; do not pretend to have read the full pages.
`,
parameters: {
query: z.string().min(1).describe("The search query, in natural language."),
max_results: z.number().int().min(1).max(20).optional().describe(
"Override the default maximum number of results returned.",
),
},
implementation: async ({ query, max_results }) => {
const backend = config.get("backend");
const limit = max_results ?? config.get("defaultMaxResults");
const timeoutMs = global.get("requestTimeoutMs");
if (backend === "duckduckgo") {
try {
const results = await duckduckgoSearch(query, limit, timeoutMs);
return { query, backend, results };
} catch (e: unknown) {
if (e instanceof DuckDuckGoError) return { error: e.message };
return { error: `Unexpected error: ${e instanceof Error ? e.message : String(e)}` };
}
}
const instanceUrl = global.get("searxngInstanceUrl");
const language = config.get("searxngLanguage");
const safesearch = config.get("searxngSafesearch") as "0" | "1" | "2";
try {
const data = await searxngSearch(
instanceUrl,
{ query, language, safesearch },
timeoutMs,
);
return {
query: data.query,
backend,
results: data.results.slice(0, limit),
answers: data.answers,
infoboxes: data.infoboxes,
suggestions: data.suggestions,
unresponsive_engines: data.unresponsive_engines,
};
} catch (e: unknown) {
if (e instanceof SearxngError) return { error: e.message };
return { error: `Unexpected error: ${e instanceof Error ? e.message : String(e)}` };
}
},
});
return [searchWeb];
}