Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
NORNICDB_NATIVE_EMBEDDINGS_PLAN.md20.1 kB
# NornicDB Native Embeddings Integration Plan (REVISED) **Version:** 1.1.0 **Date:** November 28, 2025 **Status:** Draft Implementation Plan - **APPROVED** --- ## Executive Summary Enable Mimir to leverage NornicDB's native embedding capabilities while maintaining 100% backwards compatibility with Neo4j deployments. When connected to NornicDB, Mimir will delegate embedding generation to the database while retaining only vision-language model calls for image descriptions. **VL providers are fully configurable and can reuse the default LLM provider.** --- ## 1. Database Provider Detection ### Detection Strategy **Location:** `src/managers/GraphManager.ts` (or new `src/config/database-provider.ts`) ```typescript enum DatabaseProvider { NEO4J = 'neo4j', NORNICDB = 'nornicdb' } class DatabaseProviderDetector { async detectProvider(uri: string): Promise<DatabaseProvider> { // Method 1: Check health endpoint for NornicDB signature const healthCheck = await fetch(`${httpUrl}/health`); const headers = healthCheck.headers.get('x-database-engine'); if (headers?.includes('nornicdb')) return DatabaseProvider.NORNICDB; // Method 2: Query for NornicDB-specific procedures const result = await session.run('CALL dbms.procedures() YIELD name WHERE name STARTS WITH "nornicdb." RETURN count(name) as count'); if (result.records[0].get('count') > 0) return DatabaseProvider.NORNICDB; // Default to Neo4j return DatabaseProvider.NEO4J; } } ``` **Environment Variable Override:** ```bash MIMIR_DATABASE_PROVIDER=nornicdb # or 'neo4j' (default: auto-detect) ``` --- ## 2. Vision Language Provider Configuration ### Flexible VL Provider Selection **Key Requirement:** VL provider should be independently configurable and can reuse existing LLM provider infrastructure. ### Configuration Hierarchy (Priority Order) ```typescript class VisionLanguageConfig { getVLProvider(): LLMConfig { // 1. Explicit VL-specific configuration (highest priority) if (process.env.MIMIR_EMBEDDINGS_VL_PROVIDER) { return { provider: process.env.MIMIR_EMBEDDINGS_VL_PROVIDER, apiUrl: process.env.MIMIR_EMBEDDINGS_VL_API, apiPath: process.env.MIMIR_EMBEDDINGS_VL_API_PATH, apiKey: process.env.MIMIR_EMBEDDINGS_VL_API_KEY, model: process.env.MIMIR_EMBEDDINGS_VL_MODEL, // ... other VL-specific settings }; } // 2. Reuse default LLM provider (fallback) return { provider: process.env.MIMIR_DEFAULT_PROVIDER, apiUrl: process.env.MIMIR_LLM_API, apiPath: process.env.MIMIR_LLM_API_PATH, apiKey: process.env.MIMIR_LLM_API_KEY, model: process.env.MIMIR_DEFAULT_MODEL, // Use default model for descriptions }; } } ``` ### Example Configurations **Example 1: Dedicated VL Model (Current Behavior)** ```bash # Use dedicated Qwen2.5-VL server MIMIR_EMBEDDINGS_VL_PROVIDER=llama.cpp MIMIR_EMBEDDINGS_VL_API=http://llama-vl-server-2b:8080 MIMIR_EMBEDDINGS_VL_MODEL=qwen2.5-vl ``` **Example 2: Reuse Default LLM (GPT-4V)** ```bash # No VL vars set - automatically uses default LLM MIMIR_DEFAULT_PROVIDER=openai MIMIR_LLM_API=https://api.openai.com MIMIR_DEFAULT_MODEL=gpt-4-vision-preview # VL-capable model ``` **Example 3: Reuse Copilot (Claude Sonnet 3.5 with Vision)** ```bash # No VL vars set - uses Copilot API with vision models MIMIR_DEFAULT_PROVIDER=copilot MIMIR_LLM_API=http://copilot-api:4141 MIMIR_DEFAULT_MODEL=claude-3.5-sonnet # Supports images ``` **Example 4: Mix and Match** ```bash # Use Copilot for chat, local Qwen for image descriptions MIMIR_DEFAULT_PROVIDER=copilot MIMIR_LLM_API=http://copilot-api:4141 MIMIR_DEFAULT_MODEL=gpt-4.1 # Override VL specifically MIMIR_EMBEDDINGS_VL_PROVIDER=llama.cpp MIMIR_EMBEDDINGS_VL_API=http://llama-vl-server:8080 MIMIR_EMBEDDINGS_VL_MODEL=qwen2.5-vl ``` --- ## 3. Embedding Strategy by Provider ### Architecture Changes **Create:** `src/services/EmbeddingStrategyFactory.ts` ```typescript interface EmbeddingStrategy { shouldGenerateEmbedding(contentType: string): boolean; generateEmbedding(content: string): Promise<number[] | null>; handleImageFile(imagePath: string): Promise<string>; // Returns description } class NornicDBStrategy implements EmbeddingStrategy { constructor( private vlService: VisionLanguageService // Reusable VL service ) {} shouldGenerateEmbedding(contentType: string): boolean { return false; // NornicDB handles all embeddings internally } async generateEmbedding(content: string): Promise<null> { return null; // No-op - database handles it } async handleImageFile(imagePath: string): Promise<string> { // Use configured VL provider (could be default LLM or dedicated VL) return await this.vlService.describeImage(imagePath); } } class Neo4jStrategy implements EmbeddingStrategy { constructor( private embeddingService: EmbeddingService, private vlService: VisionLanguageService ) {} shouldGenerateEmbedding(contentType: string): boolean { return this.config.MIMIR_EMBEDDINGS_ENABLED; // Existing logic } async generateEmbedding(content: string): Promise<number[]> { // Existing Mimir embedding generation logic return await this.embeddingService.embed(content); } async handleImageFile(imagePath: string): Promise<string> { // Use same VL service (unified interface) const description = await this.vlService.describeImage(imagePath); // Also generate embedding for Neo4j const embedding = await this.generateEmbedding(description); // Store embedding separately return description; } } ``` --- ## 4. VisionLanguageService Refactor ### Unified VL Service Interface **Location:** `src/services/VisionLanguageService.ts` ```typescript interface VLProviderConfig { provider: string; apiUrl: string; apiPath: string; apiKey: string; model: string; contextSize?: number; maxTokens?: number; temperature?: number; timeout?: number; } class VisionLanguageService { private config: VLProviderConfig; constructor() { // Load config with fallback to default LLM this.config = this.loadVLConfig(); } private loadVLConfig(): VLProviderConfig { // Priority 1: Explicit VL configuration if (process.env.MIMIR_EMBEDDINGS_VL_PROVIDER) { return { provider: process.env.MIMIR_EMBEDDINGS_VL_PROVIDER, apiUrl: process.env.MIMIR_EMBEDDINGS_VL_API!, apiPath: process.env.MIMIR_EMBEDDINGS_VL_API_PATH || '/v1/chat/completions', apiKey: process.env.MIMIR_EMBEDDINGS_VL_API_KEY || 'dummy-key', model: process.env.MIMIR_EMBEDDINGS_VL_MODEL!, contextSize: parseInt(process.env.MIMIR_EMBEDDINGS_VL_CONTEXT_SIZE || '131072'), maxTokens: parseInt(process.env.MIMIR_EMBEDDINGS_VL_MAX_TOKENS || '2048'), temperature: parseFloat(process.env.MIMIR_EMBEDDINGS_VL_TEMPERATURE || '0.7'), timeout: parseInt(process.env.MIMIR_EMBEDDINGS_VL_TIMEOUT || '180000'), }; } // Priority 2: Reuse default LLM provider return { provider: process.env.MIMIR_DEFAULT_PROVIDER || 'copilot', apiUrl: process.env.MIMIR_LLM_API!, apiPath: process.env.MIMIR_LLM_API_PATH || '/v1/chat/completions', apiKey: process.env.MIMIR_LLM_API_KEY || 'dummy-key', model: process.env.MIMIR_DEFAULT_MODEL || 'gpt-4.1', maxTokens: 2048, temperature: 0.7, timeout: 180000, }; } async describeImage(imagePath: string): Promise<string> { // Universal OpenAI-compatible image description const imageData = await this.loadImageAsBase64(imagePath); const response = await fetch(`${this.config.apiUrl}${this.config.apiPath}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.config.apiKey}`, }, body: JSON.stringify({ model: this.config.model, messages: [ { role: 'user', content: [ { type: 'text', text: 'Describe this image in detail. Focus on key visual elements, composition, style, and any text or notable features.' }, { type: 'image_url', image_url: { url: `data:image/jpeg;base64,${imageData}` } } ] } ], max_tokens: this.config.maxTokens, temperature: this.config.temperature, }), signal: AbortSignal.timeout(this.config.timeout), }); const result = await response.json(); return result.choices[0].message.content; } private async loadImageAsBase64(imagePath: string): Promise<string> { // Reuse existing image loading logic const buffer = await fs.readFile(imagePath); return buffer.toString('base64'); } } ``` --- ## 5. File Changes Required ### Core Files to Modify | File | Change Type | Description | |------|-------------|-------------| | `src/managers/GraphManager.ts` | **MODIFY** | Add provider detection, inject strategy | | `src/services/EmbeddingService.ts` | **MODIFY** | Wrap with strategy pattern | | `src/services/VisionLanguageService.ts` | **REFACTOR** | Unified VL provider with fallback to default LLM | | `src/indexing/FileIndexer.ts` | **MODIFY** | Use strategy for file indexing | | `src/indexing/DocumentParser.ts` | **MODIFY** | Conditionally generate embeddings | | `src/api/nodes-api.ts` | **MODIFY** | Don't accept embeddings when NornicDB | | `src/config/database-provider.ts` | **NEW** | Provider detection utility | | `src/config/vl-provider.ts` | **NEW** | VL provider config with LLM fallback | | `src/services/EmbeddingStrategyFactory.ts` | **NEW** | Strategy factory | --- ## 6. Implementation Phases ### Phase 1: Detection & Configuration (2-4 hours) - ✅ Implement database provider detection - ✅ Add `MIMIR_DATABASE_PROVIDER` env var - ✅ Create provider detection utility with health check + Cypher probe - ✅ Implement VL provider config with LLM fallback - ✅ Add logging for detected provider and VL config ### Phase 2: VL Service Refactor (3-4 hours) - ✅ Extract VL config loading logic - ✅ Implement fallback to default LLM provider - ✅ Test VL service with multiple provider types - ✅ Ensure OpenAI-compatible API format for all providers ### Phase 3: Strategy Pattern (4-6 hours) - ✅ Create `EmbeddingStrategy` interface - ✅ Implement `NornicDBStrategy` (no-op embeddings, VL only) - ✅ Implement `Neo4jStrategy` (existing logic + VL) - ✅ Create factory to select strategy based on provider - ✅ Inject both strategy and VL service into `GraphManager` ### Phase 4: Integration (6-8 hours) - ✅ Update `FileIndexer` to use strategy - ✅ Update `DocumentParser` to conditionally embed - ✅ Update node creation APIs to reject embeddings for NornicDB - ✅ Update MCP tools to use strategy - ✅ Ensure VL service is reusable across both strategies ### Phase 5: Testing & Validation (4-6 hours) - ✅ Test with Neo4j + dedicated VL model - ✅ Test with NornicDB + dedicated VL model - ✅ Test with NornicDB + default LLM (GPT-4V) - ✅ Test with NornicDB + Copilot (Claude Sonnet) - ✅ Test provider auto-detection - ✅ Integration tests for all configurations --- ## 7. Configuration Changes ### New Environment Variables ```bash # Database Provider (auto-detect by default) MIMIR_DATABASE_PROVIDER=auto # Options: auto, neo4j, nornicdb # NornicDB-specific settings (optional overrides) MIMIR_NORNICDB_SKIP_EMBEDDINGS=true # Default: true (use native) MIMIR_NORNICDB_VL_ONLY=true # Default: true (only VL calls) ``` ### VL Provider Configuration (Priority Order) **Option 1: Dedicated VL Provider (Explicit)** ```bash # Highest priority - explicit VL configuration MIMIR_EMBEDDINGS_VL_PROVIDER=llama.cpp MIMIR_EMBEDDINGS_VL_API=http://llama-vl-server-2b:8080 MIMIR_EMBEDDINGS_VL_API_PATH=/v1/chat/completions MIMIR_EMBEDDINGS_VL_API_KEY=dummy-key MIMIR_EMBEDDINGS_VL_MODEL=qwen2.5-vl MIMIR_EMBEDDINGS_VL_CONTEXT_SIZE=131072 MIMIR_EMBEDDINGS_VL_MAX_TOKENS=2048 MIMIR_EMBEDDINGS_VL_TEMPERATURE=0.7 MIMIR_EMBEDDINGS_VL_TIMEOUT=180000 ``` **Option 2: Reuse Default LLM (Automatic Fallback)** ```bash # When no VL vars are set, automatically use default LLM MIMIR_DEFAULT_PROVIDER=copilot # or 'openai', 'anthropic', etc. MIMIR_LLM_API=http://copilot-api:4141 MIMIR_LLM_API_PATH=/v1/chat/completions MIMIR_LLM_API_KEY=dummy-key MIMIR_DEFAULT_MODEL=gpt-4.1 # Must support vision API # No VL vars needed - will automatically use above config ``` **Option 3: Mix and Match** ```bash # Use different providers for chat vs image descriptions MIMIR_DEFAULT_PROVIDER=copilot MIMIR_LLM_API=http://copilot-api:4141 MIMIR_DEFAULT_MODEL=gpt-4.1 # Override for image descriptions only MIMIR_EMBEDDINGS_VL_PROVIDER=llama.cpp MIMIR_EMBEDDINGS_VL_API=http://llama-vl-server:8080 MIMIR_EMBEDDINGS_VL_MODEL=qwen2.5-vl ``` ### Existing Variables (No Breaking Changes) - All `MIMIR_EMBEDDINGS_*` variables still respected for Neo4j - All existing `MIMIR_EMBEDDINGS_VL_*` variables still work - New fallback behavior only when VL vars are not set - No breaking changes to existing deployments --- ## 8. Backwards Compatibility Checklist ### Neo4j Mode (Existing Behavior) - ✅ Embeddings generated by Mimir for text content - ✅ Embeddings generated for image descriptions - ✅ All existing env vars respected (`MIMIR_EMBEDDINGS_*`) - ✅ VL provider can be dedicated or reuse default LLM - ✅ File indexing with embeddings works as before - ✅ Vector search uses Mimir-generated embeddings - ✅ No breaking changes to MCP tools - ✅ No breaking changes to REST APIs ### NornicDB Mode (New Behavior) - ✅ No embedding generation by Mimir (delegated) - ✅ VL provider can be dedicated or reuse default LLM - ✅ VL model called for image descriptions (same interface) - ✅ Text descriptions stored in properties - ✅ NornicDB generates embeddings internally via async queue - ✅ Vector search uses NornicDB-generated embeddings - ✅ Same MCP tool interface (transparent to users) - ✅ Zero config needed if default LLM supports vision --- ## 9. Key Design Decisions ### Decision 1: Strategy Pattern Over Conditionals **Rationale:** Clean separation of concerns, testable, extensible for future providers ### Decision 2: Auto-Detection with Override **Rationale:** Zero-config for most users, manual override for edge cases ### Decision 3: VL Service Reusability **Rationale:** - Single VL service used by both strategies - Fallback to default LLM eliminates need for dedicated VL server - OpenAI-compatible API makes all providers interchangeable - Users can choose cost/performance tradeoffs easily ### Decision 4: Configuration Hierarchy **Rationale:** - Explicit VL config takes precedence (power users) - Automatic LLM fallback for simplicity (most users) - Mix-and-match for optimization scenarios - Zero breaking changes to existing setups ### Decision 5: No API Changes **Rationale:** MCP tools and REST APIs remain unchanged - provider selection is internal --- ## 10. Code Reusability Matrix | Component | Neo4j Strategy | NornicDB Strategy | Reusability | |-----------|----------------|-------------------|-------------| | **VL Service** | ✅ Uses | ✅ Uses | 100% shared | | **VL Config Loading** | ✅ Uses | ✅ Uses | 100% shared | | **Image Base64 Encoding** | ✅ Uses | ✅ Uses | 100% shared | | **OpenAI API Client** | ✅ Uses | ✅ Uses | 100% shared | | **Embedding Service** | ✅ Uses | ❌ Skips | Strategy-specific | | **Embedding Config** | ✅ Uses | ❌ Ignored | Strategy-specific | **Reuse Score: 80%** - VL logic fully shared, only embedding generation differs --- ## 11. Testing Strategy ### Unit Tests - Provider detection (mock health endpoints) - Strategy selection (factory tests) - VL config loading (with/without explicit config) - VL service (multiple provider types) - Neo4j strategy (existing behavior) - NornicDB strategy (no-op embeddings) ### Integration Tests - **Neo4j + Mimir embeddings + dedicated VL** (existing) - **Neo4j + Mimir embeddings + default LLM VL** (new) - **NornicDB + native embeddings + dedicated VL** (new) - **NornicDB + native embeddings + default LLM VL** (new) - **NornicDB + native embeddings + Copilot VL** (new) - **Image indexing** (all configurations) - **Vector search** (both providers) - **Provider auto-detection** (both databases) ### Manual Testing Checklist - [ ] Deploy with Neo4j + Qwen VL, verify Mimir embeddings - [ ] Deploy with Neo4j + GPT-4V (default LLM), verify embeddings - [ ] Deploy with NornicDB + Qwen VL, verify no Mimir embeddings - [ ] Deploy with NornicDB + GPT-4V (default LLM), verify descriptions - [ ] Deploy with NornicDB + Claude Sonnet (Copilot), verify descriptions - [ ] Index images with all configurations - [ ] Query vector search with both providers - [ ] Switch providers without config changes (auto-detect) --- ## 12. Example Deployment Configurations ### Minimal Setup (NornicDB + Copilot) ```bash # Only 3 variables needed! NEO4J_URI=bolt://nornicdb:7687 MIMIR_DEFAULT_PROVIDER=copilot MIMIR_LLM_API=http://copilot-api:4141 # Auto-detects NornicDB # Uses Copilot for both chat AND image descriptions # No dedicated VL server needed ``` ### High Performance (NornicDB + Dedicated VL) ```bash NEO4J_URI=bolt://nornicdb:7687 MIMIR_DEFAULT_PROVIDER=copilot MIMIR_LLM_API=http://copilot-api:4141 # Dedicated local VL model for fast image processing MIMIR_EMBEDDINGS_VL_PROVIDER=llama.cpp MIMIR_EMBEDDINGS_VL_API=http://llama-vl-server:8080 MIMIR_EMBEDDINGS_VL_MODEL=qwen2.5-vl ``` ### Cost Optimized (NornicDB + GPT-4V) ```bash NEO4J_URI=bolt://nornicdb:7687 MIMIR_DEFAULT_PROVIDER=openai MIMIR_LLM_API=https://api.openai.com MIMIR_DEFAULT_MODEL=gpt-4-vision-preview # Uses GPT-4V for both chat and images # No local models needed # Pay per use ``` ### Backwards Compatible (Neo4j + Everything) ```bash NEO4J_URI=bolt://neo4j:7687 MIMIR_EMBEDDINGS_ENABLED=true MIMIR_EMBEDDINGS_API=http://llama-server:8080 MIMIR_EMBEDDINGS_MODEL=mxbai-embed-large # Dedicated VL as before MIMIR_EMBEDDINGS_VL_PROVIDER=llama.cpp MIMIR_EMBEDDINGS_VL_API=http://llama-vl-server:8080 MIMIR_EMBEDDINGS_VL_MODEL=qwen2.5-vl # Everything works exactly as before ``` --- ## 13. Success Metrics - ✅ **Zero breaking changes** for Neo4j users - ✅ **Zero embedding calls** when using NornicDB (except VL) - ✅ **VL provider reusability** - can use default LLM - ✅ **Configuration simplicity** - 80% of users need no VL vars - ✅ **Auto-detection accuracy** >99% - ✅ **Performance improvement** with NornicDB (no embedding overhead) - ✅ **Same MCP tool API** for both providers - ✅ **All existing tests pass** with Neo4j - ✅ **New tests pass** with NornicDB --- ## 14. Risk Mitigation | Risk | Impact | Mitigation | |------|--------|------------| | Auto-detection fails | High | Manual override via env var | | Breaking Neo4j users | Critical | Comprehensive test suite + canary deployment | | VL service coupling | Medium | Separate service interface | | Performance regression | Medium | Benchmark both providers | | Config complexity | Medium | Clear fallback hierarchy + docs | --- **Estimated Total Effort:** 19-28 hours (added 3-4 hours for VL refactor) **Priority:** High (enables NornicDB native features + simplifies configuration) **Dependencies:** None (self-contained changes) **Next Steps:** 1. ✅ Review revised plan 2. ✅ Approve plan 3. ⏳ Begin Phase 1 implementation 4. ⏳ Create feature branch `feature/nornicdb-native-embeddings` 5. ⏳ Implement provider detection 6. ⏳ Implement VL service refactor 7. ⏳ Implement strategy pattern 8. ⏳ Integration and testing 9. ⏳ Documentation updates 10. ⏳ Merge and release --- **Document Status:** ✅ Saved to repository **Location:** `docs/architecture/NORNICDB_NATIVE_EMBEDDINGS_PLAN.md` **Last Updated:** November 28, 2025

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/orneryd/Mimir'

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