The Exa and Perplexity providers hard-coded request parameters that deployments should control while defaults are still unsettled. Exa gains searchType, numResults, and highlightsPerResult; Perplexity gains maxTokens (it previously sent none) and an optional searchRecency. Each follows the deepseek provider's shape: a defaulted Config field, a DEFAULT_* constant, and a positive-integer status() check for numeric limits. The call-level maxResults still flows through WebSearchRequest and wins over the configured default, keeping the seam layering intact. Addresses tianyicui's "make everything configurable" review comment.
69 lines
2.4 KiB
TypeScript
69 lines
2.4 KiB
TypeScript
/**
|
|
* `@deepseek-ai/dsh-web-search-exa`: registers an Exa-backed `WebSearchProvider`
|
|
* with `ctx.web`. A function/namespace plugin (NOT a default-export service):
|
|
* a search provider does not own the `ctx.web` key — it registers INTO the
|
|
* seam's provider registry, exactly as `@deepseek-ai/dsh-llm-deepseek`
|
|
* registers an adapter into `ctx.llm`. The key is owned by `@deepseek-ai/dsh-web`.
|
|
*
|
|
* @module @deepseek-ai/dsh-web-search-exa
|
|
*/
|
|
|
|
import type { Context } from 'cordis'
|
|
import z from 'schemastery'
|
|
import type {} from '@deepseek-ai/dsh-web'
|
|
import {
|
|
ExaSearchProvider,
|
|
EXA_DEFAULT_BASE_URL,
|
|
EXA_DEFAULT_HIGHLIGHTS_PER_RESULT,
|
|
EXA_DEFAULT_SEARCH_TYPE,
|
|
} from './provider.ts'
|
|
|
|
export {
|
|
EXA_DEFAULT_BASE_URL,
|
|
EXA_DEFAULT_HIGHLIGHTS_PER_RESULT,
|
|
EXA_DEFAULT_SEARCH_TYPE,
|
|
EXA_PROVIDER_ID,
|
|
ExaSearchProvider,
|
|
mapExaResponse,
|
|
mapExaResult,
|
|
} from './provider.ts'
|
|
export type { ExaSearchProviderOptions } from './provider.ts'
|
|
|
|
/** Cordis plugin name used by loader diagnostics. */
|
|
export const name = 'web-search-exa'
|
|
|
|
/** The web seam this provider registers into. */
|
|
export const inject = ['web']
|
|
|
|
export interface Config {
|
|
/** Exa API key. Falls back to `$EXA_API_KEY`. Empty → provider unavailable. */
|
|
apiKey?: string
|
|
/** Endpoint base; `/search` is appended. Defaults to the public API. */
|
|
baseURL?: string
|
|
/** Retrieval mode sent as Exa's `type`. Defaults to `auto`. */
|
|
searchType?: 'auto' | 'keyword' | 'neural'
|
|
/** Default result count when a request carries no `maxResults`. Omitted = none. */
|
|
numResults?: number
|
|
/** Highlight sentences requested per result. Defaults to 1. */
|
|
highlightsPerResult?: number
|
|
}
|
|
|
|
export const Config: z<Config> = z.object({
|
|
apiKey: z.string(),
|
|
baseURL: z.string(),
|
|
searchType: z.union(['auto', 'keyword', 'neural'] as const),
|
|
numResults: z.number().step(1).min(1),
|
|
highlightsPerResult: z.number().step(1).min(1),
|
|
})
|
|
|
|
/** Register the Exa search provider with `ctx.web`. */
|
|
export function apply(ctx: Context, config: Config): void {
|
|
ctx.web.registerSearchProvider(new ExaSearchProvider({
|
|
apiKey: config.apiKey ?? process.env.EXA_API_KEY ?? '',
|
|
baseURL: config.baseURL ?? EXA_DEFAULT_BASE_URL,
|
|
searchType: config.searchType ?? EXA_DEFAULT_SEARCH_TYPE,
|
|
highlightsPerResult: config.highlightsPerResult ?? EXA_DEFAULT_HIGHLIGHTS_PER_RESULT,
|
|
...config.numResults !== undefined ? { numResults: config.numResults } : {},
|
|
}))
|
|
}
|