managarten/services/mana-research/src/config.ts
Till JS 2bdb48bdd1 feat(research): add mana-research service — Phase 1 + 2
New Bun/Hono service on port 3068 that bundles many web-research providers
behind a unified interface for side-by-side comparison. All eval runs
persist in research.* (mana_platform) so quality can be reviewed later.

Providers (Phase 1+2):
  search:  searxng, duckduckgo, brave, tavily, exa, serper
  extract: readability (via mana-search), jina-reader, firecrawl

Endpoints:
  POST /v1/search, /v1/search/compare       — single + fan-out
  POST /v1/extract, /v1/extract/compare     — single + fan-out
  GET  /v1/runs, /v1/runs/:id               — history
  POST /v1/runs/:run/results/:id/rate       — manual eval
  GET  /v1/providers, /v1/providers/health  — catalog + readiness

Auto-routing: when `provider` is omitted, queries are classified via regex
(fast path, 0ms) with optional mana-llm fallback, then routed to the first
available provider for that query type (news → tavily, academic → exa,
semantic → exa, etc.).

Credits: server-key calls go through mana-credits reserve → commit/refund
so failed provider calls don't charge the user. BYO-keys supported via
research.provider_configs (UI arrives in Phase 4).

Cache: Redis with graceful degradation (1h TTL for search, 24h for
extract). Pay-per-use APIs only — no subscription-gated providers.

Docs: docs/plans/mana-research-service.md + docs/reports/web-research-capabilities.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:42:25 +02:00

68 lines
2 KiB
TypeScript

/**
* Application configuration loaded from environment variables.
*/
export interface Config {
port: number;
databaseUrl: string;
redisUrl: string;
manaAuthUrl: string;
manaLlmUrl: string;
manaCreditsUrl: string;
manaSearchUrl: string;
serviceKey: string;
cors: { origins: string[] };
cacheTtlSeconds: number;
providerKeys: {
brave?: string;
tavily?: string;
exa?: string;
serper?: string;
perplexity?: string;
anthropic?: string;
openai?: string;
googleGenai?: string;
jina?: string;
firecrawl?: string;
scrapingbee?: string;
};
}
export function loadConfig(): Config {
const requiredEnv = (key: string, fallback?: string): string => {
const value = process.env[key] || fallback;
if (!value) throw new Error(`Missing required env var: ${key}`);
return value;
};
return {
port: parseInt(process.env.PORT || '3068', 10),
databaseUrl: requiredEnv(
'DATABASE_URL',
'postgresql://mana:devpassword@localhost:5432/mana_platform'
),
redisUrl: process.env.REDIS_URL || 'redis://localhost:6379',
manaAuthUrl: requiredEnv('MANA_AUTH_URL', 'http://localhost:3001'),
manaLlmUrl: requiredEnv('MANA_LLM_URL', 'http://localhost:3025'),
manaCreditsUrl: requiredEnv('MANA_CREDITS_URL', 'http://localhost:3061'),
manaSearchUrl: requiredEnv('MANA_SEARCH_URL', 'http://localhost:3021'),
serviceKey: requiredEnv('MANA_SERVICE_KEY', 'dev-service-key'),
cors: {
origins: (process.env.CORS_ORIGINS || 'http://localhost:5173').split(','),
},
cacheTtlSeconds: parseInt(process.env.CACHE_TTL_SECONDS || '3600', 10),
providerKeys: {
brave: process.env.BRAVE_API_KEY,
tavily: process.env.TAVILY_API_KEY,
exa: process.env.EXA_API_KEY,
serper: process.env.SERPER_API_KEY,
perplexity: process.env.PERPLEXITY_API_KEY,
anthropic: process.env.ANTHROPIC_API_KEY,
openai: process.env.OPENAI_API_KEY,
googleGenai: process.env.GOOGLE_GENAI_API_KEY,
jina: process.env.JINA_API_KEY,
firecrawl: process.env.FIRECRAWL_API_KEY,
scrapingbee: process.env.SCRAPINGBEE_API_KEY,
},
};
}