packages feed

llm-simple-0.1.0.1: src/LLM/Load/LoadGateways.hs

module LLM.Load.LoadGateways
  ( GatewayMap,
    loadGateways,
    loadGatewaysWithDotenv,
  )
where

import Configuration.Dotenv (defaultConfig, loadFile)
import Control.Exception (SomeException, catch)
import Control.Lens ((<&>))
import Data.Map qualified as Map
import Data.Maybe (catMaybes)
import Data.Text (Text)
import Data.Text qualified as T
import LLM.Core.Types (LLMGateway)
import LLM.Providers.Claude (claudeGateway)
import LLM.Providers.DeepSeek (deepSeekGateway)
import LLM.Providers.Gemini (geminiGateway)
import LLM.Providers.Ollama (ollamaGateway)
import LLM.Providers.OpenAI (openAIGateway)
import System.Environment (lookupEnv)

type GatewayMap = Map.Map Text LLMGateway

-- | Build a gateway map from the current process environment.
-- Does not read a @.env@ file; set variables yourself or use
-- 'loadGatewaysWithDotenv'.
loadGateways :: IO GatewayMap
loadGateways = loadGatewaysFromEnv

-- | Load @.env@ (if present) and then build a gateway map from the
-- environment. Convenience for local development; prefer explicit env
-- injection in production.
loadGatewaysWithDotenv :: IO GatewayMap
loadGatewaysWithDotenv = do
  loadFile defaultConfig `catch` \(_ :: SomeException) -> pure ()
  loadGatewaysFromEnv

loadGatewaysFromEnv :: IO GatewayMap
loadGatewaysFromEnv = do
  let ollama = Just ("ollama", ollamaGateway)
  openai <- lookupEnv "OPENAI_API_KEY" <&> fmap (("openai",) . openAIGateway . T.pack)
  claude <- lookupEnv "CLAUDE_API_KEY" <&> fmap (("claude",) . claudeGateway . T.pack)
  gemini <- lookupEnv "GEMINI_API_KEY" <&> fmap (("gemini",) . geminiGateway . T.pack)
  deepseek <- lookupEnv "DEEPSEEK_API_KEY" <&> fmap (("deepseek",) . deepSeekGateway . T.pack)
  pure $ Map.fromList $ catMaybes [openai, claude, gemini, deepseek, ollama]