{"version":3,"file":"searxng-BFTJ6rTE.mjs","names":[],"sources":["../src/batteries/tools/searxng/exceptions.ts","../src/batteries/tools/searxng/index.ts"],"sourcesContent":["/**\n * Battery-scoped exception constructors for the SearXNG search tool.\n *\n * @remarks\n * Battery-scoped exception classes owned by the SearXNG tool battery (not the ADK core). Minted\n * via `createException` from `@nhtio/adk/factories` and re-exported from the battery's barrel\n * (`@nhtio/adk/batteries/tools/searxng`). This file intentionally carries **no** `@module` tag:\n * it is an internal sibling relative-imported by `index.ts`, so it does not mint its own\n * `…/searxng/exceptions` entrypoint (whose `exceptions` leaf basename would collide with sibling\n * batteries under the `vite-plugin-dts` rolled-up `.d.ts` rule).\n */\n\nimport { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when {@link createSearxngSearchTool} receives invalid configuration.\n *\n * @remarks\n * Fatal: config bugs (missing or unparseable `instanceUrl`) fail loud at factory-call time\n * rather than at the first search.\n */\nexport const E_INVALID_SEARXNG_CONFIG = createException<[string]>(\n  'E_INVALID_SEARXNG_CONFIG',\n  'Invalid SearXNG tool config: %s',\n  'E_INVALID_SEARXNG_CONFIG',\n  529,\n  true\n)\n","/**\n * Factory for a configured SearXNG metasearch tool.\n *\n * @module @nhtio/adk/batteries/tools/searxng\n *\n * @remarks\n * Unlike the other bundled tool categories — every one of which exports a ready-made,\n * stateless `Tool` constant — the SearXNG battery exports **factories**,\n * {@link createSearxngSearchTool} (async) and {@link createSearxngSearchToolSync}. A search tool\n * has to talk to a *specific* SearXNG instance, usually behind custom authentication, so it needs\n * per-deployment configuration (a base URL and headers) that cannot be baked in at module load.\n *\n * Because this module exports factories rather than `Tool` instances, they MUST NOT be\n * bulk-registered via `Object.values(batteries)`. Call a factory first, then register the\n * returned tool: `new ToolRegistry([await createSearxngSearchTool({ instanceUrl })])`.\n *\n * @see https://docs.searxng.org/dev/search_api.html\n */\n\nimport { Tool } from '@nhtio/adk/forge'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { Middleware } from '@nhtio/middleware'\nimport { E_INVALID_SEARXNG_CONFIG } from './exceptions'\nimport { SpooledJsonArtifact } from '@nhtio/adk/spooled_artifact'\nimport {\n  resolveHeaders,\n  resolveArtifact,\n  resolveArtifactSync,\n  makeShortCircuit,\n  isShortCircuit,\n  runInputPipeline,\n  runOutputPipeline,\n  runToolGate,\n  type ToolGateFn,\n  type ArtifactResolver,\n  type SyncArtifactResolver,\n  type SpooledArtifactCtor,\n  type MiddlewareFn,\n} from '../_shared'\nimport type { Schema } from '@nhtio/validation'\nimport type { NextFn } from '@nhtio/middleware'\n\nexport { E_INVALID_SEARXNG_CONFIG } from './exceptions'\n\n/** A static set of request headers (used for custom authentication). */\nexport type SearxngHeaders = Record<string, string>\n\n/**\n * A resolver returning request headers, sync or async. Use this form when the auth token is\n * refreshable — the resolver runs on every search, so a fresh token can be minted per call.\n */\nexport type SearxngHeadersResolver = () => SearxngHeaders | Promise<SearxngHeaders>\n\n/** The output shape the tool serialises. `either` lets the model pick per call. */\nexport type SearxngResultFormat = 'normalized' | 'raw' | 'either'\n\n/**\n * A single normalised SearXNG result. SearXNG result items are deliberately untyped upstream,\n * so every field except a best-effort `title`/`url` is optional.\n */\nexport interface SearxngResult {\n  /** Result title, when the source engine provided one. */\n  title?: string\n  /** Result URL, when the source engine provided one. */\n  url?: string\n  /** Snippet / summary text for the result. */\n  content?: string\n  /** The SearXNG engine that produced this result (e.g. `google`, `duckduckgo`). */\n  engine?: string\n  /** Relevance score as reported by SearXNG (higher is more relevant). */\n  score?: number\n  /** Publication date, when the source engine exposed one (ISO-ish string, engine-dependent). */\n  publishedDate?: string\n}\n\n/**\n * Mutable context handed to each input-pipeline stage **before** the HTTP request is sent.\n *\n * @remarks\n * Stages mutate this in place (onion `(ctx, next)` style) to adjust the outgoing request —\n * inject or rotate auth headers, force a language, rewrite the query — or call\n * {@link SearxngRequestContext.shortCircuit} to skip the fetch entirely (e.g. a cache hit).\n */\nexport interface SearxngRequestContext {\n  /** The tool's name (read-only). */\n  readonly toolName: string\n  /** The search query. Mutable. */\n  query: string\n  /** Extra SearXNG query parameters (`categories`, `engines`, `language`, …). Mutable. */\n  params: Record<string, string>\n  /** Resolved request headers. Mutable — inject, redact, or rotate auth here. */\n  headers: SearxngHeaders\n  /** The target instance base URL (read-only). */\n  readonly instanceUrl: string\n  /** Cross-stage scratch space; also carried onto the response context. */\n  readonly stash: Map<string, unknown>\n  /** Skip the fetch and return `result` verbatim as the tool's output. */\n  shortCircuit(result: string): void\n}\n\n/**\n * Mutable context handed to each output-pipeline stage **after** the response JSON is parsed.\n *\n * @remarks\n * Stages reshape, redact, enrich, or re-rank {@link SearxngResponseContext.results}, mutate the\n * raw body, or set {@link SearxngResponseContext.output} to override the serialised string\n * verbatim (e.g. to render markdown that matches a markdown `artifact` resolver).\n */\nexport interface SearxngResponseContext {\n  /** The tool's name (read-only). */\n  readonly toolName: string\n  /** The request context as it was sent (post-input-pipeline). */\n  readonly request: SearxngRequestContext\n  /** The parsed SearXNG JSON body. Mutable (used when `format` is `raw`). */\n  raw: unknown\n  /** The normalised result list. Mutable — filter, redact, or re-rank. */\n  results: SearxngResult[]\n  /** The effective payload shape for this call. */\n  format: 'normalized' | 'raw'\n  /** When set, used verbatim as the tool's output (overrides serialisation). */\n  output?: string\n  /** Cross-stage scratch space; carried over from the request context. */\n  readonly stash: Map<string, unknown>\n}\n\n/** An input-pipeline stage. Onion middleware over {@link SearxngRequestContext}. */\nexport type SearxngInputMiddlewareFn = (\n  ctx: SearxngRequestContext,\n  next: NextFn\n) => void | Promise<void>\n\n/** An output-pipeline stage. Onion middleware over {@link SearxngResponseContext}. */\nexport type SearxngOutputMiddlewareFn = (\n  ctx: SearxngResponseContext,\n  next: NextFn\n) => void | Promise<void>\n\n/**\n * Configuration for {@link createSearxngSearchTool} (async) and\n * {@link createSearxngSearchToolSync} (sync — `artifact` narrowed to the sync subset).\n *\n * @typeParam A - The {@link ArtifactResolver} variant accepted: the full resolver (async factory)\n *   or the sync subset ({@link createSearxngSearchToolSync}).\n */\nexport interface SearxngToolConfig<A = ArtifactResolver> {\n  /** Base URL of the SearXNG instance, e.g. `https://searx.example.org`. Required. */\n  instanceUrl: string\n  /** Custom request headers — a static object or a (sync/async) resolver for refreshable auth. */\n  headers?: SearxngHeaders | SearxngHeadersResolver\n  /** Request timeout in milliseconds. Default `10_000`. */\n  timeout?: number\n  /**\n   * Output shape. `normalized`/`raw` pin the shape (the model cannot change it); `either`\n   * (default) exposes a `format` argument so the model chooses per call.\n   */\n  resultFormat?: SearxngResultFormat\n  /** Tool name. Default `searxng_search`. */\n  name?: string\n  /** Tool description override. */\n  description?: string\n  /**\n   * Spool-artifact resolver for the tool's output. Default `() => SpooledJsonArtifact`. Accepts a\n   * constructor, a sync resolver, or — via {@link createSearxngSearchTool} — an async /\n   * dynamic-import resolver. Pass `() => SpooledMarkdownArtifact` (paired with an output stage that\n   * renders markdown into `ctx.output`) or `() => SpooledArtifact` for plain text.\n   */\n  artifact?: A\n  /**\n   * Optional per-call gate run before the HTTP request — the seam for human-approval/RBAC\n   * flows built on `ctx.waitFor` (the ADK gates primitive). Throwing aborts the call through\n   * the standard tool-error path. Search queries reach the network on the agent's behalf,\n   * which makes every call a candidate for gating.\n   */\n  gate?: ToolGateFn\n  /** Stages run before the HTTP request. See {@link SearxngRequestContext}. */\n  inputPipeline?: SearxngInputMiddlewareFn[]\n  /** Stages run after the response is parsed. See {@link SearxngResponseContext}. */\n  outputPipeline?: SearxngOutputMiddlewareFn[]\n}\n\nconst DEFAULT_NAME = 'searxng_search'\nconst DEFAULT_TIMEOUT = 10_000\nconst DEFAULT_DESCRIPTION =\n  'Search the web via a SearXNG metasearch instance. Returns aggregated results (title, url, ' +\n  'snippet, source engine) plus any answers, infoboxes, and suggestions.'\n\n/** Normalise a loose SearXNG result item into a {@link SearxngResult}. */\nconst normaliseResult = (raw: unknown): SearxngResult => {\n  const r = (raw ?? {}) as Record<string, unknown>\n  const out: SearxngResult = {}\n  if (typeof r.title === 'string') out.title = r.title\n  if (typeof r.url === 'string') out.url = r.url\n  if (typeof r.content === 'string') out.content = r.content\n  if (typeof r.engine === 'string') out.engine = r.engine\n  if (typeof r.score === 'number') out.score = r.score\n  if (typeof r.publishedDate === 'string') out.publishedDate = r.publishedDate\n  return out\n}\n\nconst fail = (reason: string): never => {\n  throw new E_INVALID_SEARXNG_CONFIG([reason])\n}\n\n/** Validate `instanceUrl` and return the trailing-slash-normalised base. */\nconst validateInstanceUrl = (config: { instanceUrl?: string }): string => {\n  if (typeof config?.instanceUrl !== 'string' || config.instanceUrl.trim() === '') {\n    fail('instanceUrl is required')\n  }\n  try {\n    new URL(config.instanceUrl as string)\n  } catch {\n    fail(`instanceUrl is not a valid URL: ${config.instanceUrl}`)\n  }\n  return (config.instanceUrl as string).replace(/\\/+$/, '')\n}\n\n/**\n * Assemble the `Tool` from validated config + an already-resolved sync artifact constructor.\n * Shared by both the async and sync factories — they differ only in how `artifact` is resolved.\n */\nconst assembleTool = (\n  config: SearxngToolConfig<unknown>,\n  instanceUrl: string,\n  artifactConstructor: () => SpooledArtifactCtor\n): Tool => {\n  const timeout = config.timeout ?? DEFAULT_TIMEOUT\n  const resultFormat: SearxngResultFormat = config.resultFormat ?? 'either'\n  const toolName = config.name ?? DEFAULT_NAME\n\n  // Stages are fixed at factory time; build the Middleware shells once. A fresh `.runner()` is\n  // minted per invocation inside the handler (runners are single-use).\n  const inputMw = new Middleware<MiddlewareFn<SearxngRequestContext>>()\n  for (const fn of config.inputPipeline ?? []) inputMw.add(fn)\n  const outputMw = new Middleware<MiddlewareFn<SearxngResponseContext>>()\n  for (const fn of config.outputPipeline ?? []) outputMw.add(fn)\n  const hasInput = (config.inputPipeline ?? []).length > 0\n  const hasOutput = (config.outputPipeline ?? []).length > 0\n\n  // Build the input schema, conditionally exposing `format` only when the factory is neutral.\n  const schemaShape: Record<string, Schema> = {\n    query: validator.string().required().description('The search query.'),\n    categories: validator\n      .string()\n      .optional()\n      .allow('')\n      .description(\n        'Comma-separated SearXNG categories (e.g. \"general,news\"). Omit or send an empty string to search every category.'\n      ),\n    engines: validator\n      .string()\n      .optional()\n      .allow('')\n      .description(\n        'Comma-separated SearXNG engines (e.g. \"google,duckduckgo\"). Omit or send an empty string to search every engine.'\n      ),\n    language: validator\n      .string()\n      .optional()\n      .allow('')\n      .description(\n        'Language code (e.g. \"en\", \"de\"). Omit or send an empty string to search all languages.'\n      ),\n    pageno: validator.number().min(1).default(1).description('Result page number (1-based).'),\n    time_range: validator\n      .string()\n      .valid('day', 'month', 'year')\n      .optional()\n      .description('Restrict results to a time range.'),\n    safesearch: validator\n      .number()\n      .valid(0, 1, 2)\n      .optional()\n      .description('Safe-search level: 0 (off), 1 (moderate), 2 (strict).'),\n  }\n  if (resultFormat === 'either') {\n    schemaShape.format = validator\n      .string()\n      .valid('normalized', 'raw')\n      .default('normalized')\n      .description('Output shape: \"normalized\" (trimmed) or \"raw\" (full SearXNG JSON).')\n  }\n  const inputSchema = validator.object(schemaShape)\n\n  return new Tool({\n    name: toolName,\n    description: config.description ?? DEFAULT_DESCRIPTION,\n    inputSchema,\n    artifactConstructor,\n    handler: async (args, handlerCtx) => {\n      await runToolGate(config.gate, handlerCtx, toolName, args)\n      const a = args as {\n        query: string\n        categories?: string\n        engines?: string\n        language?: string\n        pageno?: number\n        time_range?: string\n        safesearch?: number\n        format?: 'normalized' | 'raw'\n      }\n\n      try {\n        // 1. Effective output format: a pinned factory format wins; else the model's choice.\n        const format: 'normalized' | 'raw' =\n          resultFormat === 'either' ? (a.format ?? 'normalized') : resultFormat\n\n        // 2. Resolve headers, merged over portable defaults (caller headers win).\n        const headers: SearxngHeaders = {\n          'Accept': 'application/json',\n          'User-Agent': 'adk-searxng-tool',\n          ...(await resolveHeaders(config.headers)),\n        }\n\n        // 3. Assemble the SearXNG query params from validated args.\n        const params: Record<string, string> = {}\n        if (a.categories) params.categories = a.categories\n        if (a.engines) params.engines = a.engines\n        if (a.language) params.language = a.language\n        if (a.pageno && a.pageno !== 1) params.pageno = String(a.pageno)\n        if (a.time_range) params.time_range = a.time_range\n        if (typeof a.safesearch === 'number') params.safesearch = String(a.safesearch)\n\n        const stash = new Map<string, unknown>()\n\n        // 4. Run the input pipeline (fresh runner) over a mutable request context.\n        const requestCtx: SearxngRequestContext = {\n          toolName,\n          query: a.query,\n          params,\n          headers,\n          instanceUrl,\n          stash,\n          shortCircuit: makeShortCircuit(),\n        }\n\n        if (hasInput) {\n          const short = await runInputPipeline(inputMw, requestCtx, 'SearXNG')\n          if (short !== undefined) return short\n        }\n\n        // 5. Build the request URL from the (possibly mutated) query + params.\n        const url = new URL('/search', instanceUrl + '/')\n        url.searchParams.set('q', requestCtx.query)\n        for (const [k, v] of Object.entries(requestCtx.params)) url.searchParams.set(k, v)\n        url.searchParams.set('format', 'json')\n\n        // 6. Fetch with an AbortController timeout.\n        const controller = new AbortController()\n        const timer = setTimeout(() => controller.abort(), timeout)\n        let response: Response\n        try {\n          response = await fetch(url, {\n            method: 'GET',\n            headers: requestCtx.headers,\n            signal: controller.signal,\n          })\n        } finally {\n          clearTimeout(timer)\n        }\n\n        if (!response.ok) {\n          if (response.status === 403) {\n            return (\n              `Error: SearXNG returned 403 Forbidden. The instance likely has the JSON output ` +\n              `format disabled — enable it under \"search.formats: [json]\" in its settings.yml.`\n            )\n          }\n          return `Error: SearXNG returned HTTP ${response.status} ${response.statusText}.`\n        }\n\n        const body = (await response.json()) as Record<string, unknown>\n\n        // 7. Run the output pipeline (fresh runner) over a mutable response context.\n        const responseCtx: SearxngResponseContext = {\n          toolName,\n          request: requestCtx,\n          raw: body,\n          results: Array.isArray(body.results) ? body.results.map(normaliseResult) : [],\n          format,\n          stash,\n        }\n\n        if (hasOutput) await runOutputPipeline(outputMw, responseCtx, 'SearXNG')\n\n        // 8. Serialise and return.\n        if (typeof responseCtx.output === 'string') return responseCtx.output\n        if (responseCtx.format === 'raw') return JSON.stringify(responseCtx.raw, null, 2)\n        return JSON.stringify(buildNormalisedPayload(responseCtx), null, 2)\n      } catch (err) {\n        if (isShortCircuit(err)) return err.result\n        return `Error: ${isError(err) ? err.message : String(err)}`\n      }\n    },\n  })\n}\n\n/**\n * Create a configured SearXNG search {@link Tool} (async — accepts a dynamic-import `artifact`).\n *\n * @remarks\n * Async because `artifact` may be an async / dynamic-import resolver, which must be resolved to the\n * sync `() => Ctor` that `Tool.artifactConstructor` requires before the tool is built (the\n * wrap-site invokes it synchronously). For the common case where you reference the artifact class\n * directly, use {@link createSearxngSearchToolSync} and skip the `await`.\n *\n * The handler always requests `format=json`. Note that SearXNG ships with JSON output\n * **disabled** by default (it is abused by bots); an instance that has not enabled\n * `search.formats: [json]` in its `settings.yml` answers with HTTP 403, which the tool returns\n * as a graceful `Error:` string naming the setting.\n *\n * @warning\n * Do not trust the `number_of_results` field for a result count — SearXNG frequently reports `0`\n * in JSON output even when `results` is non-empty. This is a long-standing upstream quirk, not a\n * tool defect (see {@link https://github.com/searxng/searxng/issues/2987 | searxng#2987} and\n * {@link https://github.com/searxng/searxng/issues/2457 | searxng#2457}). The tool passes the\n * field through verbatim; use `results.length` as the authoritative count.\n *\n * @param config - The instance URL, optional custom headers, output-format policy, `artifact`\n *   resolver, and input/output middleware pipelines. See {@link SearxngToolConfig}.\n * @returns A promise of a `Tool` ready to register in a `ToolRegistry`.\n * @throws {@link E_INVALID_SEARXNG_CONFIG} when `instanceUrl` or `artifact` is invalid.\n */\nexport const createSearxngSearchTool = async (\n  config: SearxngToolConfig<ArtifactResolver>\n): Promise<Tool> => {\n  const instanceUrl = validateInstanceUrl(config)\n  const artifactConstructor = await resolveArtifact(\n    config.artifact ?? (() => SpooledJsonArtifact),\n    fail\n  )\n  return assembleTool(config, instanceUrl, artifactConstructor)\n}\n\n/**\n * Synchronous {@link createSearxngSearchTool} — the ergonomic common path.\n *\n * @remarks\n * `artifact` is narrowed to the sync subset (a constructor or a sync resolver). Passing an async\n * resolver is a compile-time type error and a runtime {@link E_INVALID_SEARXNG_CONFIG}; for\n * dynamic-import resolvers use the async {@link createSearxngSearchTool}. See its docs for the\n * `number_of_results` caveat and 403/JSON-disabled behaviour.\n *\n * @param config - Same as {@link SearxngToolConfig}, with `artifact` restricted to the sync subset.\n * @returns A `Tool` ready to register in a `ToolRegistry`.\n * @throws {@link E_INVALID_SEARXNG_CONFIG} when `instanceUrl` or `artifact` is invalid (incl. an async resolver).\n */\nexport const createSearxngSearchToolSync = (\n  config: SearxngToolConfig<SyncArtifactResolver>\n): Tool => {\n  const instanceUrl = validateInstanceUrl(config)\n  const artifactConstructor = resolveArtifactSync(\n    config.artifact ?? (() => SpooledJsonArtifact),\n    fail\n  )\n  return assembleTool(config, instanceUrl, artifactConstructor)\n}\n\n/** Assemble the trimmed normalised payload, dropping empty aggregate arrays. */\nconst buildNormalisedPayload = (ctx: SearxngResponseContext): Record<string, unknown> => {\n  const raw = (ctx.raw ?? {}) as Record<string, unknown>\n  const payload: Record<string, unknown> = {\n    query: typeof raw.query === 'string' ? raw.query : ctx.request.query,\n    results: ctx.results,\n  }\n  // NOTE: SearXNG's `number_of_results` is frequently `0` in JSON output even when `results`\n  // is non-empty — a long-standing upstream quirk, not a tool bug (see\n  // https://github.com/searxng/searxng/issues/2987 and\n  // https://github.com/searxng/searxng/issues/2457). We pass through whatever the instance\n  // reports; treat `results.length` as the authoritative count, not this field.\n  if (typeof raw.number_of_results === 'number') payload.number_of_results = raw.number_of_results\n  for (const key of ['answers', 'infoboxes', 'suggestions', 'corrections'] as const) {\n    const value = raw[key]\n    if (Array.isArray(value) && value.length > 0) payload[key] = value\n  }\n  return payload\n}\n"],"mappings":"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"}