103 lines
3.1 KiB
TypeScript

import type { AdapterContext, WebFetchProvider, WebSearchProvider } from "@rakazo/adapter-kit";
import { clampMaxChars, clampMaxResults, MAX_WEB_FETCH_URLS } from "./web-limits.js";
import {
normalizeSearchCategory,
normalizeSearchDomains,
resolveSearchQueries,
} from "./web-research.js";
export async function webSearchFromTool(
search: WebSearchProvider,
context: AdapterContext,
args: Record<string, unknown>,
) {
const rawQuery = typeof args.query === "string" ? args.query.trim() : "";
const rawQueries = Array.isArray(args.queries)
? args.queries.filter((q): q is string => typeof q === "string" && q.trim().length > 0)
: undefined;
const queries = resolveSearchQueries({
query: rawQuery,
queries: rawQueries,
});
if (queries.length === 0) return { error: "query is required" };
const category = normalizeSearchCategory(args.category);
const domains = normalizeSearchDomains(args.domains);
try {
const results = await search.search(
{
query: rawQuery || queries[0]!,
...(rawQueries && rawQueries.length > 0 ? { queries } : {}),
...(category ? { category } : {}),
...(domains ? { domains } : {}),
maxResults: clampMaxResults(args.maxResults),
signal: context.signal,
},
context,
);
return { results };
} catch (error) {
return { error: error instanceof Error ? error.message : String(error) };
}
}
export async function webFetchFromTool(
fetchProvider: WebFetchProvider,
context: AdapterContext,
args: Record<string, unknown>,
) {
const singleUrl = typeof args.url === "string" ? args.url.trim() : "";
const batchUrls = Array.isArray(args.urls)
? args.urls
.filter((u): u is string => typeof u === "string")
.map((u) => u.trim())
.filter((u) => u.length > 0)
.slice(0, MAX_WEB_FETCH_URLS)
: undefined;
const query = typeof args.query === "string" && args.query.trim() ? args.query.trim() : undefined;
const maxChars = clampMaxChars(args.maxChars);
if (batchUrls && batchUrls.length > 0) {
const uniqueUrls = [...new Set(singleUrl ? [singleUrl, ...batchUrls] : batchUrls)].slice(
0,
MAX_WEB_FETCH_URLS,
);
const pages = await Promise.all(
uniqueUrls.map(async (targetUrl) => {
try {
return await fetchProvider.fetch(
{
url: targetUrl,
...(query ? { query } : {}),
maxChars,
signal: context.signal,
},
context,
);
} catch (error) {
return {
url: targetUrl,
error: error instanceof Error ? error.message : String(error),
};
}
}),
);
return { pages };
}
if (!singleUrl) return { error: "url is required" };
try {
const result = await fetchProvider.fetch(
{
url: singleUrl,
...(query ? { query } : {}),
maxChars,
signal: context.signal,
},
context,
);
return result;
} catch (error) {
return { error: error instanceof Error ? error.message : String(error) };
}
}