summaryrefslogtreecommitdiffhomepage
path: root/packages/tool-web-search/src/tool.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/tool-web-search/src/tool.ts')
-rw-r--r--packages/tool-web-search/src/tool.ts216
1 files changed, 108 insertions, 108 deletions
diff --git a/packages/tool-web-search/src/tool.ts b/packages/tool-web-search/src/tool.ts
index 751278d..b2e84fe 100644
--- a/packages/tool-web-search/src/tool.ts
+++ b/packages/tool-web-search/src/tool.ts
@@ -10,11 +10,11 @@
import type { ToolContract, ToolExecuteContext, ToolResult } from "@dispatch/kernel";
import type { FirecrawlClient } from "./client.js";
import {
- formatCrawlResults,
- formatMapResults,
- formatScrapeResult,
- formatSearchResults,
- truncateOutput,
+ formatCrawlResults,
+ formatMapResults,
+ formatScrapeResult,
+ formatSearchResults,
+ truncateOutput,
} from "./format.js";
import type { ValidatedArgs } from "./validate.js";
import { validateArgs } from "./validate.js";
@@ -22,51 +22,51 @@ import { validateArgs } from "./validate.js";
const OUTPUT_CAP = 50_000;
export interface WebSearchToolDeps {
- readonly client: FirecrawlClient;
- readonly outputCap?: number;
+ readonly client: FirecrawlClient;
+ readonly outputCap?: number;
}
/** Dispatch validated args to the right client method and format the result. */
async function runMode(
- validated: ValidatedArgs,
- client: FirecrawlClient,
- signal: AbortSignal,
+ validated: ValidatedArgs,
+ client: FirecrawlClient,
+ signal: AbortSignal,
): Promise<string> {
- switch (validated.mode) {
- case "search": {
- const hits = await client.search(
- {
- query: validated.query,
- limit: validated.limit,
- ...(validated.scrape
- ? { scrapeOptions: { formats: ["markdown"], onlyMainContent: true } }
- : {}),
- ...(validated.lang !== undefined ? { lang: validated.lang } : {}),
- ...(validated.country !== undefined ? { country: validated.country } : {}),
- },
- signal,
- );
- return formatSearchResults(hits);
- }
- case "scrape": {
- const result = await client.scrape(
- { url: validated.url, formats: [validated.format] },
- signal,
- );
- return formatScrapeResult(result);
- }
- case "crawl": {
- const pages = await client.crawl(
- { url: validated.url, limit: validated.limit, formats: [validated.format] },
- signal,
- );
- return formatCrawlResults(pages);
- }
- case "map": {
- const links = await client.map(validated.url, signal);
- return formatMapResults(links);
- }
- }
+ switch (validated.mode) {
+ case "search": {
+ const hits = await client.search(
+ {
+ query: validated.query,
+ limit: validated.limit,
+ ...(validated.scrape
+ ? { scrapeOptions: { formats: ["markdown"], onlyMainContent: true } }
+ : {}),
+ ...(validated.lang !== undefined ? { lang: validated.lang } : {}),
+ ...(validated.country !== undefined ? { country: validated.country } : {}),
+ },
+ signal,
+ );
+ return formatSearchResults(hits);
+ }
+ case "scrape": {
+ const result = await client.scrape(
+ { url: validated.url, formats: [validated.format] },
+ signal,
+ );
+ return formatScrapeResult(result);
+ }
+ case "crawl": {
+ const pages = await client.crawl(
+ { url: validated.url, limit: validated.limit, formats: [validated.format] },
+ signal,
+ );
+ return formatCrawlResults(pages);
+ }
+ case "map": {
+ const links = await client.map(validated.url, signal);
+ return formatMapResults(links);
+ }
+ }
}
/**
@@ -75,68 +75,68 @@ async function runMode(
* is declared on the extension manifest (not the tool contract).
*/
export function createWebSearchTool(deps: WebSearchToolDeps): ToolContract {
- const client = deps.client;
- const cap = deps.outputCap ?? OUTPUT_CAP;
+ const client = deps.client;
+ const cap = deps.outputCap ?? OUTPUT_CAP;
- return {
- name: "web_search",
- description:
- "Access the web via a self-hosted Firecrawl instance. Supports search, " +
- "single-page scrape, site crawling, and sitemap discovery.",
- parameters: {
- type: "object",
- properties: {
- query: { type: "string", description: "The search query (search mode)." },
- url: { type: "string", description: "A URL to scrape, crawl, or map." },
- mode: {
- type: "string",
- enum: ["search", "scrape", "crawl", "map"],
- description:
- "Operation mode. 'search' (default when query present), 'scrape' " +
- "(default when url present), 'crawl' (recursively scrape pages from a site), " +
- "'map' (discover URLs on a site).",
- },
- limit: {
- type: "number",
- description: "Max results. Search: default 7, max 10. Crawl: default 3, max 10.",
- },
- scrape: {
- type: "boolean",
- description: "When searching, also scrape full markdown content of each result page.",
- },
- lang: {
- type: "string",
- description: 'Language code to filter search results (e.g. "en", "ja").',
- },
- country: {
- type: "string",
- description: 'Country code to filter search results (e.g. "us", "jp").',
- },
- format: {
- type: "string",
- enum: ["markdown", "text", "html"],
- description: "Format for scrape/crawl output (default: markdown).",
- },
- },
- },
- concurrencySafe: true,
- async execute(args: unknown, ctx: ToolExecuteContext): Promise<ToolResult> {
- const validated = validateArgs(args);
- if ("error" in validated) {
- return { content: validated.error, isError: true };
- }
- const span = ctx.log.span("web_search.execute", { mode: validated.mode });
- try {
- const output = await runMode(validated, client, ctx.signal);
- span.end();
- return { content: truncateOutput(output, cap) };
- } catch (err: unknown) {
- span.end({ err });
- return {
- content: `Error: ${err instanceof Error ? err.message : String(err)}`,
- isError: true,
- };
- }
- },
- };
+ return {
+ name: "web_search",
+ description:
+ "Access the web via a self-hosted Firecrawl instance. Supports search, " +
+ "single-page scrape, site crawling, and sitemap discovery.",
+ parameters: {
+ type: "object",
+ properties: {
+ query: { type: "string", description: "The search query (search mode)." },
+ url: { type: "string", description: "A URL to scrape, crawl, or map." },
+ mode: {
+ type: "string",
+ enum: ["search", "scrape", "crawl", "map"],
+ description:
+ "Operation mode. 'search' (default when query present), 'scrape' " +
+ "(default when url present), 'crawl' (recursively scrape pages from a site), " +
+ "'map' (discover URLs on a site).",
+ },
+ limit: {
+ type: "number",
+ description: "Max results. Search: default 7, max 10. Crawl: default 3, max 10.",
+ },
+ scrape: {
+ type: "boolean",
+ description: "When searching, also scrape full markdown content of each result page.",
+ },
+ lang: {
+ type: "string",
+ description: 'Language code to filter search results (e.g. "en", "ja").',
+ },
+ country: {
+ type: "string",
+ description: 'Country code to filter search results (e.g. "us", "jp").',
+ },
+ format: {
+ type: "string",
+ enum: ["markdown", "text", "html"],
+ description: "Format for scrape/crawl output (default: markdown).",
+ },
+ },
+ },
+ concurrencySafe: true,
+ async execute(args: unknown, ctx: ToolExecuteContext): Promise<ToolResult> {
+ const validated = validateArgs(args);
+ if ("error" in validated) {
+ return { content: validated.error, isError: true };
+ }
+ const span = ctx.log.span("web_search.execute", { mode: validated.mode });
+ try {
+ const output = await runMode(validated, client, ctx.signal);
+ span.end();
+ return { content: truncateOutput(output, cap) };
+ } catch (err: unknown) {
+ span.end({ err });
+ return {
+ content: `Error: ${err instanceof Error ? err.message : String(err)}`,
+ isError: true,
+ };
+ }
+ },
+ };
}