Provider Selection & Routing
Relevant source files
The following files were used as context for generating this wiki page:
Provider Selection and Routing identifies and assigns the appropriate service provider to handle a specific research or search capability request. The system evaluates user input, environment variables, configuration files, and real-time quota snapshots to determine which provider executes an operation.
This system ensures that scoutline can support multiple backends for capabilities such as web search, page reading, and repository exploration. It provides a standardized mechanism for selecting between providers like Z.AI, Tavily, Exa, and others based on availability and user preference.
Sources: packages/scoutline/src/index.ts:182-212, packages/scoutline/src/providers/selection.ts:1-25
Core Selection Logic
The selection process follows a strict precedence chain to resolve which ProviderId becomes the effective provider for a command. The primary function resolveEffectiveProvider coordinates this resolution by checking explicit pins before falling back to quota-aware ranking.
Precedence Chain
The system resolves the provider ID using the following order of priority:
- Explicit Flag: The value provided via the
--providerCLI flag. - Environment Variable: The value set in the
SCOUTLINE_PROVIDERenvironment variable. - Routing Table: A per-capability provider list defined in
config.json. - Quota Ranking: Real-time ranking based on available capacity and success rates.
- Default: Falls back to
zaiif no other provider is resolved.
Sources: packages/scoutline/src/index.ts:182-185, packages/scoutline/src/providers/selection.ts:50-100
This diagram represents the logic used to determine which provider is used for a given request.
Sources: packages/scoutline/src/providers/selection.ts:133-195
Component Architecture
Registry and Catalog
The registry.ts file defines the static set of built-in providers. Each provider is represented by a ProviderDescriptor which includes metadata about required credentials and advertised capabilities.
The catalog.ts file maintains user-facing labels and determines which providers are "shared" (eligible for general search/read operations) versus "vertical" (specialized suppliers for scholarly work).
| Provider ID | Display Label | Capabilities (Example) |
|---|---|---|
zai | Z.AI | search, reader, repository-exploration |
tavily | Tavily | search, reader, crawl, map, research |
exa | Exa | search, reader, research |
arxiv | arXiv | science.search, science.get |
Sources: packages/scoutline/src/providers/registry.ts:5-50, packages/scoutline/src/providers/catalog.ts:27-56, packages/scoutline/src/index.ts:187-203
Quota-Aware Ranking
When no explicit pin exists and a quota snapshot is available, the system scores every eligible provider for the requested capability.
- Eligibility Filtering: The system excludes providers that are not configured (missing API keys) or do not advertise the specific capability.
- Tiered Ranking:
- Known Tier: Providers with fresh status in the snapshot.
- Unknown Tier: Providers missing from the snapshot or with stale data.
- Exhausted Tier: Providers explicitly marked with 0% remaining quota within the last 24 hours.
- Tie-breaking: In the event of equal scores, providers are selected in registry order to ensure stability.
Sources: packages/scoutline/src/providers/selection.ts:133-195, packages/scoutline/src/index.ts:1532-1560
Fan-out Routing
For the search and investigate commands, scoutline supports "Fan-out" routing. Instead of a single provider, the system can parallelize requests across multiple backends.
- Activation: Triggered when the
--providerflag contains a comma-separated list or the keywordall. - Deduplication: Results from multiple providers are merged and deduplicated using URL normalization.
- Reciprocal Rank Fusion (RRF): Merged results are ranked using the RRF algorithm by default to ensure the most relevant items across all sources appear first.
Sources: packages/scoutline/src/index.ts:207-212, packages/scoutline/src/index.ts:1071-1100
The sequence above illustrates how parallel provider requests are managed during a fan-out search.
Sources: packages/scoutline/src/index.ts:1050-1110
Implementation Interfaces
The system uses standard TypeScript types to define provider identities and their capabilities.
// From packages/scoutline/src/providers/types.ts
export type ProviderId =
| "zai" | "minimax" | "tavily" | "exa" | "brave"
| "firecrawl" | "parallel" | "perplexity" | "jina"
| "you" | "linkup" | "spider" | "bocha" | "searchapi"
| "kagi" | "arxiv" | "openalex" | "crossref"
| "pubmed" | "europepmc";
export interface ProviderDescriptor {
readonly id: ProviderId;
readonly credentialEnvVars: readonly string[];
isConfigured(env: NodeJS.ProcessEnv): boolean;
capabilities(): ReadonlySet<ProviderCapability>;
create(context: ProviderContext): ProviderAdapter;
}
Sources: packages/scoutline/src/providers/types.ts:11-20, packages/scoutline/src/providers/types.ts:40-46
Summary
Provider Selection & Routing provides the logic for determining which service provider executes a user's request. It transitions from strict user-defined pins to automated, quota-aware ranking. The system enables robust multi-provider strategies, including automatic fallback for unavailable providers and parallel fan-out for comprehensive search coverage. This architecture allows scoutline to remain provider-agnostic while maximizing the utility of different research APIs.
Sources: packages/scoutline/src/providers/selection.ts:1-25, packages/scoutline/src/index.ts:182-212