/** * Exa direct HTTP transport (tech-plan §7, Transport Client). * * Performs direct POSTs against the Exa REST endpoints with an * `Authorization: Bearer ` header. There is NO internal retry — * shared execution owns retry policy. Fetch and timer are injectable for * tests. * * Mirrors `providers/tavily/client.ts` in structure, but Exa-specific * differences: * - Base URL `https://api.exa.ai`. * - JSON bodies use camelCase (contrast Tavily's snake_case). * - Error body is `{"error": "message"}` — a single string. HTTP-status * is the sole error signal; the body is discarded at the transport * boundary and never echoed outward. * - HTTP 402 maps to {@link QuotaError} (Exa returns 402 for three * exhaustion states: account, key, and team budget). * * Boundary rules (ARCHITECTURE.md §2): * - May import Adapter-local config and normalized errors. * - May import `ProviderQuotaFetch` from `providers/types.ts`. * - Must NOT import command presentation, capability contracts, or * another Provider's Adapter. * - Must NOT perform response field normalization — the Adapter owns * that. This module declares Provider-native request-body types * only (Exa API field names); it does not import SearchControls * or any capability contract. */ import type { ProviderQuotaFetch } from "../types.js"; /** Injectable transport dependencies (fetch, timers, env). */ export interface ExaTransportDeps { readonly fetch?: ProviderQuotaFetch; readonly setTimeout?: typeof setTimeout; readonly clearTimeout?: typeof clearTimeout; readonly env?: NodeJS.ProcessEnv; } /** * Provider-native search request body fields (Exa API field names, * camelCase). The Adapter maps the Provider-neutral `SearchControls` * into these before calling {@link fetchExaSearch}; the transport never * imports a capability contract. */ export interface ExaSearchParams { readonly numResults?: number; readonly includeDomains?: readonly string[]; readonly startPublishedDate?: string; readonly type?: string; readonly category?: string; /** * Two-letter ISO country code for result personalization (EXA-8-02). * Maps to Exa's `userLocation` parameter. Accepts `"cn"` and `"us"` * (the two values in `SearchControls.location`). */ readonly userLocation?: string; } /** * Provider-native contents request options (Exa API field names, * camelCase). The Adapter maps `ReaderFetchRequest` fields into these * before calling {@link fetchExaContents}; the transport never imports * a capability contract. * * `livecrawlTimeout` is in milliseconds (the CLI `--timeout` is in * seconds; the Adapter converts before calling). */ export interface ExaContentsParams { readonly livecrawlTimeout?: number; } export declare function resolveTimeoutMs(env: NodeJS.ProcessEnv): number; /** * Perform ONE POST against the Exa /search endpoint. No retry; no * response body in public errors. Returns the parsed JSON body (raw; * the Adapter post-processes into normalized search sources). * * `params` carries Exa-native API fields (camelCase) already mapped * from `SearchControls` by the Adapter. Search always sends * `contents: { highlights: true }` (token-efficient; populates * `summary`). */ export declare function fetchExaSearch(apiKey: string, query: string, params?: ExaSearchParams, deps?: ExaTransportDeps): Promise; /** * Perform ONE POST against the Exa /contents endpoint. No retry; no * response body in public errors. Returns the parsed JSON body (raw; * the Adapter post-processes into a normalized `ReaderFetchResult`). * * The caller wraps a single URL as `urls: [url]`. `text: true` is * always set (Exa returns text content). * * `params.livecrawlTimeout` is in milliseconds. The Adapter converts * from the CLI's seconds-based `--timeout` before calling; the transport * does NOT re-convert. */ export declare function fetchExaContents(apiKey: string, url: string, params?: ExaContentsParams, deps?: ExaTransportDeps): Promise; /** * Provider-native Agent run request body fields (Exa API field names, * camelCase). The Adapter maps the Provider-neutral `ResearchRequest` * into these before calling {@link createExaAgentRun}; the transport * never imports a capability contract. */ export interface ExaAgentRunParams { readonly query: string; readonly effort?: string; } /** * Structured result of POST /agent/runs. The endpoint returns * `{ id, status }` on success. */ export interface ExaAgentRunCreateResult { readonly id: string; readonly status: string; } /** * Structured result of GET /agent/runs/{id}. `output` is passed as raw * `unknown` — the Adapter normalizes it into a `ResearchResult`. * * `status: "not_found"` is returned (not thrown) for HTTP 404 so the * Adapter can treat a stale state file as "delete it and create a new * run" rather than a terminal transport error. */ export interface ExaAgentRunPollResult { readonly status: "queued" | "running" | "completed" | "failed" | "cancelled" | "not_found"; readonly output?: unknown; } /** * Perform ONE POST against the Exa /agent/runs endpoint. No retry; no * response body in public errors. Returns the structured create result * `{ id, status }`. * * Shared execution wraps this with `maxRetries: 0` (double-charge * prevention on a usage-based endpoint), so a transient create-time * failure is terminal. */ export declare function createExaAgentRun(apiKey: string, params: ExaAgentRunParams, deps?: ExaTransportDeps): Promise; /** * Perform ONE GET against the Exa /agent/runs/{id} endpoint. No retry. * Returns a structured poll result. * * Unlike other GETs, a 404 is NOT a terminal transport error here: it * means the server-side run expired/disappeared, so the Adapter can * delete the stale state file and create a fresh run. The poll result * carries `status: "not_found"` for that case. All other non-2xx statuses * throw the standard mapped error. */ export declare function pollExaAgentRun(apiKey: string, runId: string, deps?: ExaTransportDeps): Promise; //# sourceMappingURL=client.d.ts.map