index.ts 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. /**
  2. * Exa-backed `WebSearchProvider` plugin. It contributes to the `ctx.web`
  3. * registry without owning the service.
  4. *
  5. * @module @deepseek-ai/dsh-web-search-exa
  6. */
  7. import type { Context } from '@deepseek-ai/cordis'
  8. import { launchEnvironmentOf } from '@deepseek-ai/dsh-launch-environment'
  9. import z from '@deepseek-ai/schemastery'
  10. import type {} from '@deepseek-ai/dsh-web'
  11. import {
  12. ExaSearchProvider,
  13. EXA_DEFAULT_BASE_URL,
  14. EXA_DEFAULT_HIGHLIGHTS_PER_RESULT,
  15. EXA_DEFAULT_SEARCH_TYPE,
  16. } from './provider.ts'
  17. export {
  18. EXA_DEFAULT_BASE_URL,
  19. EXA_DEFAULT_HIGHLIGHTS_PER_RESULT,
  20. EXA_DEFAULT_SEARCH_TYPE,
  21. EXA_PROVIDER_ID,
  22. ExaSearchProvider,
  23. } from './provider.ts'
  24. export type { ExaSearchProviderOptions } from './provider.ts'
  25. /** Cordis plugin name used by loader diagnostics. */
  26. export const name = 'web-search-exa'
  27. /** The web seam this provider registers into. */
  28. export const inject = ['web']
  29. /** Plugin config (all optional — `apply` fills env-var and constant defaults). */
  30. export interface Config {
  31. /** Exa API key. Falls back to `$EXA_API_KEY`. Empty → provider unavailable. */
  32. apiKey?: string
  33. /** Endpoint base; `/search` is appended. Defaults to the public API. */
  34. baseURL?: string
  35. /** Retrieval mode sent as Exa's `type`. Defaults to `auto`. */
  36. searchType?: 'auto' | 'keyword' | 'neural'
  37. /** Default result count when a request carries no `maxResults`. Omitted = none. */
  38. numResults?: number
  39. /** Highlight sentences requested per result. Defaults to 1. */
  40. highlightsPerResult?: number
  41. }
  42. export const Config: z<Config> = z.object({
  43. apiKey: z.string(),
  44. baseURL: z.string(),
  45. searchType: z.union(['auto', 'keyword', 'neural'] as const),
  46. numResults: z.number().step(1).min(1),
  47. highlightsPerResult: z.number().step(1).min(1),
  48. })
  49. /** Register the Exa search provider with `ctx.web`. */
  50. export function apply(ctx: Context, config: Config): void {
  51. ctx.web.registerSearchProvider(new ExaSearchProvider({
  52. // Every environment layer may name this key: the product trusts the
  53. // project it is launched in, and the managed store is not involved here.
  54. apiKey: config.apiKey ?? launchEnvironmentOf(ctx).get('EXA_API_KEY')?.value ?? '',
  55. baseURL: config.baseURL ?? EXA_DEFAULT_BASE_URL,
  56. searchType: config.searchType ?? EXA_DEFAULT_SEARCH_TYPE,
  57. highlightsPerResult: config.highlightsPerResult ?? EXA_DEFAULT_HIGHLIGHTS_PER_RESULT,
  58. ...config.numResults !== undefined ? { numResults: config.numResults } : {},
  59. }))
  60. }