103 lines
3.1 KiB
TypeScript
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) };
|
|
}
|
|
}
|