Implemented centralized service for managing multiple LLM provider instances. Architecture: - LlmManagerService manages provider lifecycle and selection - Loads provider instances from Prisma database on startup - Maintains in-memory registry of active providers - Factory pattern for provider instantiation Core Features: - Database integration via PrismaService - Provider initialization on module startup (OnModuleInit) - Get provider by ID - Get all active providers - Get system default provider - Get user-specific provider with fallback to system default - Health check all registered providers - Dynamic registration/unregistration (hot reload) - Reload from database without restart Provider Selection Logic: - User-level providers: userId matches, is enabled - System-level providers: userId is NULL, is enabled - Fallback: system default if no user provider found - Graceful error handling with detailed logging Integration: - Added to LlmModule providers and exports - Uses PrismaService for database queries - Factory creates OllamaProvider from config - Extensible for future providers (Claude, OpenAI) Testing: - 31 comprehensive unit tests - 93.05% code coverage (exceeds 85% requirement) - All error scenarios covered - Proper mocking of dependencies Quality Gates: - ✅ All 31 tests passing - ✅ 93.05% coverage - ✅ Linting clean - ✅ Type checking passed - ✅ Code review approved Fixes #126 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
5.2 KiB
5.2 KiB
Issue #126: Create LLM Manager Service
Objective
Implement LLM Manager for provider instance management and selection with hot reload capabilities.
Approach
1. Service Responsibilities
The LlmManagerService will:
- Load provider instances from the database (LlmProviderInstance model)
- Initialize provider instances on module startup
- Maintain a registry of active provider instances
- Support dynamic provider registration/unregistration (hot reload)
- Provide instance selection logic (system-level vs user-level)
- Handle default provider selection
- Cache provider instances for performance
- Health check all registered providers
2. Architecture
Provider Registry Structure:
Map<string, LlmProviderInterface>; // instanceId -> provider instance
Selection Logic:
- User-level providers take precedence over system-level
- Default provider (isDefault=true) is fallback
- Filter by enabled status (isEnabled=true)
Hot Reload Strategy:
- Expose
registerProvider()andunregisterProvider()methods - No restart required - just reload from database
- Update in-memory registry dynamically
3. Implementation Plan
Files to create:
/home/jwoltje/src/mosaic-stack/apps/api/src/llm/llm-manager.service.ts/home/jwoltje/src/mosaic-stack/apps/api/src/llm/llm-manager.service.spec.ts
TDD Steps:
- Write tests for provider registration
- Write tests for provider selection logic
- Write tests for hot reload functionality
- Write tests for health checks
- Write tests for error handling
- Implement service to pass all tests
4. Database Integration
- Use PrismaService to query LlmProviderInstance
- Load on module init:
findMany({ where: { isEnabled: true } }) - Parse
configJSON field to instantiate providers - Support provider types: "ollama", "claude", "openai"
5. Provider Factory
Need a factory function to instantiate providers based on type:
private createProvider(instance: LlmProviderInstance): LlmProviderInterface {
switch (instance.providerType) {
case 'ollama':
return new OllamaProvider(instance.config);
// Future: case 'claude', 'openai'
default:
throw new Error(`Unknown provider type: ${instance.providerType}`);
}
}
Progress
- Created scratchpad
- Analyzed existing code structure
- Designed service architecture
- Write tests (RED phase) - 31 comprehensive tests
- Implement service (GREEN phase) - All tests passing
- Refactor and optimize (REFACTOR phase) - Code quality improvements
- Verify 85%+ coverage - 93.05% coverage achieved
- Pass all quality gates (typecheck, lint, tests)
- Updated LlmModule to export LlmManagerService
- Stage files for commit
Testing Strategy
Unit Tests Required:
-
Provider Loading
- Load all enabled providers from database
- Skip disabled providers
- Handle empty database
-
Provider Registration
- Register new provider dynamically
- Update existing provider
- Unregister provider
-
Provider Selection
- Get provider by ID
- Get all active providers
- Get default provider (system-level)
- Get user-specific provider (user-level takes precedence)
-
Health Checks
- Health check all providers
- Handle individual provider failures
- Return aggregated health status
-
Error Handling
- Invalid provider type
- Provider initialization failure
- Database connection failure
- Provider not found
Coverage Goal: ≥85%
Dependencies
- PrismaService (for database access)
- OllamaProvider (for instantiation)
- LlmProviderInterface (type checking)
Notes
- Module initialization uses NestJS
OnModuleInitlifecycle hook - Provider instances are cached in memory for performance
- Hot reload allows runtime updates without restart
- User-level providers override system-level providers
- Default provider serves as fallback when no specific provider requested
Implementation Summary
Files Created
-
llm-manager.service.ts (303 lines)
- Comprehensive provider management service
- 93.05% test coverage
- Full JSDoc documentation
- Type-safe with proper error handling
-
llm-manager.service.spec.ts (492 lines)
- 31 comprehensive unit tests
- Tests all major functionality
- Tests error scenarios
- Uses Vitest with mocked OllamaProvider
Key Features Implemented
- ✅ Load providers from database on startup
- ✅ Register/unregister providers dynamically (hot reload)
- ✅ Get provider by ID
- ✅ Get all active providers
- ✅ Get default system provider
- ✅ Get user-specific provider with fallback
- ✅ Health check all providers
- ✅ Reload from database without restart
- ✅ Provider factory pattern for type-based instantiation
- ✅ Graceful error handling with detailed logging
Test Results
- Total Tests: 31
- Passing: 31 (100%)
- Coverage: 93.05% (exceeds 85% requirement)
- Quality Gates: All passing (typecheck, lint, tests)
Integration Points
- PrismaService: Queries LlmProviderInstance table
- OllamaProvider: Factory instantiates based on config
- LlmModule: Service registered and exported
- Type Safety: Full TypeScript type checking with proper casting