Skip to main content
Glama
ollama-detector.ts5.92 kB
/** * Ollama Server Detection Utility * * Provides utilities to detect if Ollama server is running * and available for embedding generation. */ /** * Result of Ollama availability check */ export interface OllamaStatus { available: boolean; host: string; models?: string[]; error?: string; latencyMs?: number; } /** * Default Ollama host */ export const DEFAULT_OLLAMA_HOST = "http://localhost:11434"; /** * Check if Ollama server is available * * @param host - Ollama host URL (defaults to OLLAMA_HOST env or localhost:11434) * @param timeoutMs - Timeout in milliseconds (default: 2000) * @returns Promise resolving to OllamaStatus */ export async function checkOllamaAvailability( host?: string, timeoutMs: number = 2000 ): Promise<OllamaStatus> { const ollamaHost = host ?? process.env.OLLAMA_HOST ?? DEFAULT_OLLAMA_HOST; const startTime = Date.now(); try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); const response = await fetch(`${ollamaHost}/api/tags`, { method: "GET", signal: controller.signal, }); clearTimeout(timeoutId); if (!response.ok) { return { available: false, host: ollamaHost, error: `HTTP ${response.status}: ${response.statusText}`, latencyMs: Date.now() - startTime, }; } const data = (await response.json()) as { models?: Array<{ name: string }> }; const models = data.models?.map((m) => m.name) ?? []; return { available: true, host: ollamaHost, models, latencyMs: Date.now() - startTime, }; } catch (error) { const errorMessage = error instanceof Error ? error.name === "AbortError" ? `Connection timeout after ${timeoutMs}ms` : error.message : String(error); return { available: false, host: ollamaHost, error: errorMessage, latencyMs: Date.now() - startTime, }; } } /** * Check if a specific model is available in Ollama * * @param modelName - Name of the model to check * @param host - Ollama host URL * @returns Promise resolving to boolean */ export async function isModelAvailable(modelName: string, host?: string): Promise<boolean> { const status = await checkOllamaAvailability(host); if (!status.available || !status.models) { return false; } // Check for exact match or partial match (e.g., "nomic-embed-text" matches "nomic-embed-text:latest") return status.models.some((m) => m === modelName || m.startsWith(`${modelName}:`)); } /** * Cached Ollama availability status */ let cachedStatus: OllamaStatus | null = null; let cacheTimestamp: number = 0; const CACHE_TTL_MS = 30000; // 30 seconds /** * Get cached Ollama availability status * Caches result for 30 seconds to avoid repeated network calls * * @param host - Ollama host URL * @param forceRefresh - Force refresh the cache * @returns Promise resolving to OllamaStatus */ export async function getCachedOllamaStatus( host?: string, forceRefresh: boolean = false ): Promise<OllamaStatus> { const now = Date.now(); if (!forceRefresh && cachedStatus && now - cacheTimestamp < CACHE_TTL_MS) { return cachedStatus; } cachedStatus = await checkOllamaAvailability(host); cacheTimestamp = now; return cachedStatus; } /** * Clear the cached status (useful for testing) */ export function clearOllamaStatusCache(): void { cachedStatus = null; cacheTimestamp = 0; } /** * Check if we should use real Ollama or mock embeddings * * Decision logic: * 1. If USE_MOCK_EMBEDDINGS env is set to "true", always use mock * 2. If USE_REAL_OLLAMA env is set to "true", always try real Ollama * 3. Otherwise, check if Ollama is available and use it if so * * @param host - Ollama host URL * @returns Promise resolving to boolean (true = use real Ollama) */ export async function shouldUseRealOllama(host?: string): Promise<boolean> { // Explicit mock mode if (process.env.USE_MOCK_EMBEDDINGS === "true") { return false; } // Explicit real mode if (process.env.USE_REAL_OLLAMA === "true") { return true; } // Auto-detect const status = await getCachedOllamaStatus(host); return status.available; } /** * Get embedding model configuration based on availability * * @param preferredModel - Preferred model name * @param host - Ollama host URL * @returns Promise resolving to model configuration */ export async function getEmbeddingModelConfig( preferredModel: string = "nomic-embed-text", host?: string ): Promise<{ useRealOllama: boolean; model: string; host: string; reason: string; }> { const ollamaHost = host ?? process.env.OLLAMA_HOST ?? DEFAULT_OLLAMA_HOST; // Check explicit overrides if (process.env.USE_MOCK_EMBEDDINGS === "true") { return { useRealOllama: false, model: preferredModel, host: ollamaHost, reason: "USE_MOCK_EMBEDDINGS=true", }; } if (process.env.USE_REAL_OLLAMA === "true") { return { useRealOllama: true, model: preferredModel, host: ollamaHost, reason: "USE_REAL_OLLAMA=true", }; } // Auto-detect const status = await getCachedOllamaStatus(ollamaHost); if (!status.available) { return { useRealOllama: false, model: preferredModel, host: ollamaHost, reason: `Ollama not available: ${status.error}`, }; } // Check if preferred model is available const modelAvailable = await isModelAvailable(preferredModel, ollamaHost); if (!modelAvailable) { return { useRealOllama: false, model: preferredModel, host: ollamaHost, reason: `Model '${preferredModel}' not found in Ollama`, }; } return { useRealOllama: true, model: preferredModel, host: ollamaHost, reason: "Ollama available with requested model", }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ThoughtMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server