mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 23:29:02 +02:00
242 lines
6.9 KiB
TypeScript
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);
|
|
}
|
|
|