diff --git a/src/lattice.ts b/src/lattice.ts index 857a345..d207530 100644 --- a/src/lattice.ts +++ b/src/lattice.ts @@ -99,7 +99,7 @@ export function parseSections( ): Section[] { const tree = parse(content); const file = projectRoot - ? relative(projectRoot, filePath).replace(/\.md$/, '') + ? relative(projectRoot, filePath).replace(/\.md$/, '').replace(/\\/g, '/') : basename(filePath, '.md'); const sectionFilePath = projectRoot ? relative(projectRoot, filePath) @@ -619,7 +619,7 @@ export function extractRefs( ): Ref[] { const tree = parse(content); const file = projectRoot - ? relative(projectRoot, filePath).replace(/\.md$/, '') + ? relative(projectRoot, filePath).replace(/\.md$/, '').replace(/\\/g, '/') : basename(filePath, '.md'); const refs: Ref[] = []; diff --git a/src/search/provider.ts b/src/search/provider.ts index 16ee2b6..c838d72 100644 --- a/src/search/provider.ts +++ b/src/search/provider.ts @@ -6,6 +6,18 @@ export type EmbeddingProvider = { headers: (key: string) => Record; }; +// Known dimensions for common Ollama embedding models. +// Override with LAT_OLLAMA_DIMENSIONS for unlisted models. +const OLLAMA_KNOWN_DIMENSIONS: Record = { + 'nomic-embed-text': 768, + 'mxbai-embed-large': 1024, + 'all-minilm': 384, + 'snowflake-arctic-embed': 1024, + 'bge-large': 1024, + 'bge-base': 768, + 'bge-small': 384, +}; + const openai: EmbeddingProvider = { name: 'openai', apiBase: 'https://api.openai.com/v1', @@ -39,6 +51,25 @@ export function detectProvider(key: string): EmbeddingProvider { headers: () => ({ 'Content-Type': 'application/json' }), }; } + if (key.startsWith('ollama:')) { + const model = key.slice('ollama:'.length).trim(); + if (!model) + throw new Error( + 'ollama: key must include a model name, e.g. LAT_LLM_KEY=ollama:nomic-embed-text', + ); + const host = process.env.OLLAMA_HOST ?? 'http://localhost:11434'; + const dimOverride = process.env.LAT_OLLAMA_DIMENSIONS; + const dimensions = dimOverride + ? parseInt(dimOverride, 10) + : (OLLAMA_KNOWN_DIMENSIONS[model] ?? 768); + return { + name: 'ollama', + apiBase: `${host}/v1`, + model, + dimensions, + headers: () => ({ 'Content-Type': 'application/json' }), + }; + } if (key.startsWith('sk-ant-')) { throw new Error( "Anthropic doesn't offer an embedding model. Set LAT_LLM_KEY to an OpenAI (sk-...) or Vercel AI Gateway (vck_...) key.", @@ -47,6 +78,6 @@ export function detectProvider(key: string): EmbeddingProvider { if (key.startsWith('vck_')) return vercel; if (key.startsWith('sk-')) return openai; throw new Error( - `Unrecognized LAT_LLM_KEY prefix. Supported: OpenAI (sk-...), Vercel AI Gateway (vck_...).`, + `Unrecognized LAT_LLM_KEY prefix. Supported: OpenAI (sk-...), Vercel AI Gateway (vck_...), Ollama (ollama:).`, ); }