trilium/apps/server/src/services/llm/config/configuration_helpers.ts
2025-06-07 23:57:35 +00:00

242 lines
6.9 KiB
TypeScript

import optionService from '../../options.js';
import log from '../../log.js';
import type {
ProviderType,
ModelIdentifier,
ModelConfig,
} from '../interfaces/configuration_interfaces.js';
/**
* Helper functions for accessing AI configuration without string parsing
* Use these throughout the codebase instead of parsing strings directly
*/
/**
* Get the selected AI provider - always fresh from options
*/
export async function getSelectedProvider(): Promise<ProviderType | null> {
const providerOption = optionService.getOption('aiSelectedProvider');
return providerOption as ProviderType || null;
}
/**
* Parse a model identifier (handles "provider:model" format)
*/
export function parseModelIdentifier(modelString: string): ModelIdentifier {
if (!modelString) {
return {
modelId: '',
fullIdentifier: ''
};
}
const parts = modelString.split(':');
if (parts.length === 1) {
// No provider prefix, just model name
return {
modelId: modelString,
fullIdentifier: modelString
};
}
// Check if first part is a known provider
const potentialProvider = parts[0].toLowerCase();
const knownProviders: ProviderType[] = ['openai', 'anthropic', 'ollama'];
if (knownProviders.includes(potentialProvider as ProviderType)) {
// Provider prefix format
const provider = potentialProvider as ProviderType;
const modelId = parts.slice(1).join(':'); // Rejoin in case model has colons
return {
provider,
modelId,
fullIdentifier: modelString
};
}
// Not a provider prefix, treat whole string as model name
return {
modelId: modelString,
fullIdentifier: modelString
};
}
/**
* Create a model configuration from a model string
*/
export function createModelConfig(modelString: string, defaultProvider?: ProviderType): ModelConfig {
const identifier = parseModelIdentifier(modelString);
const provider = identifier.provider || defaultProvider || 'openai'; // fallback to openai if no provider specified
return {
provider,
modelId: identifier.modelId,
displayName: identifier.fullIdentifier
};
}
/**
* Get the default model for a specific provider - always fresh from options
*/
export async function getDefaultModelForProvider(provider: ProviderType): Promise<string | undefined> {
const optionKey = `${provider}DefaultModel` as const;
return optionService.getOption(optionKey) || undefined;
}
/**
* Get provider settings for a specific provider - always fresh from options
*/
export async function getProviderSettings(provider: ProviderType) {
switch (provider) {
case 'openai':
return {
apiKey: optionService.getOption('openaiApiKey'),
baseUrl: optionService.getOption('openaiBaseUrl'),
defaultModel: optionService.getOption('openaiDefaultModel')
};
case 'anthropic':
return {
apiKey: optionService.getOption('anthropicApiKey'),
baseUrl: optionService.getOption('anthropicBaseUrl'),
defaultModel: optionService.getOption('anthropicDefaultModel')
};
case 'ollama':
return {
baseUrl: optionService.getOption('ollamaBaseUrl'),
defaultModel: optionService.getOption('ollamaDefaultModel')
};
default:
return {};
}
}
/**
* Check if AI is enabled - always fresh from options
*/
export async function isAIEnabled(): Promise<boolean> {
return optionService.getOptionBool('aiEnabled');
}
/**
* Check if a provider has required configuration
*/
export async function isProviderConfigured(provider: ProviderType): Promise<boolean> {
const settings = await getProviderSettings(provider);
switch (provider) {
case 'openai':
return Boolean((settings as any)?.apiKey);
case 'anthropic':
return Boolean((settings as any)?.apiKey);
case 'ollama':
return Boolean((settings as any)?.baseUrl);
default:
return false;
}
}
/**
* Get the currently selected provider if it's available and configured
*/
export async function getAvailableSelectedProvider(): Promise<ProviderType | null> {
const selectedProvider = await getSelectedProvider();
if (!selectedProvider) {
return null; // No provider selected
}
if (await isProviderConfigured(selectedProvider)) {
return selectedProvider;
}
return null; // Selected provider is not properly configured
}
/**
* Validate the current AI configuration - simplified validation
*/
export async function validateConfiguration() {
const result = {
isValid: true,
errors: [] as string[],
warnings: [] as string[]
};
const aiEnabled = await isAIEnabled();
if (!aiEnabled) {
result.warnings.push('AI features are disabled');
return result;
}
const selectedProvider = await getSelectedProvider();
if (!selectedProvider) {
result.errors.push('No AI provider selected');
result.isValid = false;
return result;
}
// Validate provider-specific settings
const settings = await getProviderSettings(selectedProvider);
if (selectedProvider === 'openai' && !(settings as any)?.apiKey) {
result.warnings.push('OpenAI API key is not configured');
}
if (selectedProvider === 'anthropic' && !(settings as any)?.apiKey) {
result.warnings.push('Anthropic API key is not configured');
}
if (selectedProvider === 'ollama' && !(settings as any)?.baseUrl) {
result.warnings.push('Ollama base URL is not configured');
}
return result;
}
/**
* Clear cached configuration (no-op since we removed caching)
*/
export function clearConfigurationCache(): void {
// No caching anymore, so nothing to clear
}
/**
* Get a model configuration with validation that no defaults are assumed
*/
export async function getValidModelConfig(provider: ProviderType): Promise<{ model: string; provider: ProviderType } | null> {
const defaultModel = await getDefaultModelForProvider(provider);
if (!defaultModel) {
// No default model configured for this provider
return null;
}
const isConfigured = await isProviderConfigured(provider);
if (!isConfigured) {
// Provider is not properly configured
return null;
}
return {
model: defaultModel,
provider
};
}
/**
* Get the model configuration for the currently selected provider
*/
export async function getSelectedModelConfig(): Promise<{ model: string; provider: ProviderType } | null> {
const selectedProvider = await getSelectedProvider();
if (!selectedProvider) {
return null; // No provider selected
}
return await getValidModelConfig(selectedProvider);
}