/** * Pure core for the search-settings feature — zero DOM, zero effects, zero * Svelte. * * The "Search backend" dropdown (Settings pane) picks the engine backing the * `web_search` tool's SEARCH mode. The selection is GLOBAL and persisted on * the backend (`GET/PUT /search/config`); decided entries are exactly * "Firecrawl (self-hosted)" + "Umans (Exa)" plus "None (search disabled)" as * the off state. Scrape/crawl always route to the self-hosted Firecrawl * backend regardless of the selection; the tool's `map` mode is removed * entirely (backend plan). */ /** * One selectable backend as the backend's wire advertises it (mirrors * `@dispatch/wire`'s `SearchBackendAvailability`). */ export interface SearchBackendAvailability { readonly id: string; readonly label: string; /** The availability gate (umans: `UMANS_API_KEY` resolves; firecrawl: always). */ readonly configured: boolean; } /** The global search-backend config (`GET /search/config` response). */ export interface SearchBackendConfig { /** The selected backend id, or `"none"` (search off). */ readonly backend: string; readonly available: readonly SearchBackendAvailability[]; } // ── Injected ports (consumer-defines-port; the composition root adapts the // store's HTTP calls to these shapes). ────────────────────────────────────── /** Outcome of `GET/PUT /search/config`. `unavailable` marks the 503 degrade * (the backend's search-config service not loaded) so the UI can disable the * field with a "search not available" hint instead of a generic error. */ export type SearchBackendConfigResult = | { readonly ok: true; readonly config: SearchBackendConfig } | { readonly ok: false; readonly error: string; readonly unavailable?: boolean }; export type LoadSearchBackendConfig = () => Promise; export type SaveSearchBackend = (backend: string) => Promise; /** The explicit off-state option label. */ export const NONE_BACKEND_ID = "none"; export const NONE_BACKEND_LABEL = "None (search disabled)"; /** One rendered `