mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
feat: add cached model settings per provider with automatic restoration
Preserve user's model preferences for each AI provider separately and restore them when switching between providers, preventing unwanted model resets during provider changes
This commit is contained in:
parent
d31c92b35c
commit
938837c9c1
8 changed files with 120 additions and 214 deletions
|
|
@ -14,7 +14,7 @@ import {
|
|||
modelMatchesProvider
|
||||
} from "Enums/ApiProvider";
|
||||
|
||||
const DEFAULT_SETTINGS: IVaultkeeperAISettings = {
|
||||
export const DEFAULT_SETTINGS: IVaultkeeperAISettings = {
|
||||
firstTimeStart: true,
|
||||
|
||||
chatMode: ChatMode.ReadOnly,
|
||||
|
|
@ -25,6 +25,25 @@ const DEFAULT_SETTINGS: IVaultkeeperAISettings = {
|
|||
planningModel: AIProviderModel.ClaudeOpus_4_8,
|
||||
quickActionModel: AIProviderModel.ClaudeHaiku_4_5,
|
||||
|
||||
cachedModelSettings: {
|
||||
[AIProvider.Claude]: {
|
||||
planningModel: DEFAULT_PLANNING_MODEL_BY_PROVIDER[AIProvider.Claude],
|
||||
quickActionModel: DEFAULT_QUICK_MODEL_BY_PROVIDER[AIProvider.Claude]
|
||||
},
|
||||
[AIProvider.OpenAI]: {
|
||||
planningModel: DEFAULT_PLANNING_MODEL_BY_PROVIDER[AIProvider.OpenAI],
|
||||
quickActionModel: DEFAULT_QUICK_MODEL_BY_PROVIDER[AIProvider.OpenAI]
|
||||
},
|
||||
[AIProvider.Gemini]: {
|
||||
planningModel: DEFAULT_PLANNING_MODEL_BY_PROVIDER[AIProvider.Gemini],
|
||||
quickActionModel: DEFAULT_QUICK_MODEL_BY_PROVIDER[AIProvider.Gemini]
|
||||
},
|
||||
[AIProvider.Mistral]: {
|
||||
planningModel: DEFAULT_PLANNING_MODEL_BY_PROVIDER[AIProvider.Mistral],
|
||||
quickActionModel: DEFAULT_QUICK_MODEL_BY_PROVIDER[AIProvider.Mistral]
|
||||
}
|
||||
},
|
||||
|
||||
apiKeys: {
|
||||
claude: "",
|
||||
openai: "",
|
||||
|
|
@ -59,6 +78,8 @@ export interface IVaultkeeperAISettings {
|
|||
planningModel: AIProviderModel;
|
||||
quickActionModel: AIProviderModel;
|
||||
|
||||
cachedModelSettings: Record<AIProvider, ProviderModelCache>;
|
||||
|
||||
apiKeys: {
|
||||
claude: string;
|
||||
openai: string;
|
||||
|
|
@ -82,6 +103,11 @@ export interface IVaultkeeperAISettings {
|
|||
hideDrawerElements: boolean;
|
||||
}
|
||||
|
||||
export interface ProviderModelCache {
|
||||
planningModel: AIProviderModel;
|
||||
quickActionModel: AIProviderModel;
|
||||
}
|
||||
|
||||
type SettingKey = keyof IVaultkeeperAISettings;
|
||||
type SettingsChangedCallback = ((changedKeys: SettingKey[]) => void) | ((changedKeys: SettingKey[]) => Promise<void>);
|
||||
|
||||
|
|
@ -99,7 +125,7 @@ export class SettingsService {
|
|||
this.plugin = Resolve<VaultkeeperAIPlugin>(Services.VaultkeeperAIPlugin);
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, loadedSettings);
|
||||
this.settingsSnapshot = JSON.stringify(this.settings);
|
||||
this.ensureValidModels();
|
||||
void this.ensureValidModels();
|
||||
}
|
||||
|
||||
public subscribeToSettingsChanged(callback: SettingsChangedCallback): object {
|
||||
|
|
@ -153,6 +179,34 @@ export class SettingsService {
|
|||
}
|
||||
}
|
||||
|
||||
public async ensureValidModels(): Promise<void> {
|
||||
await this.updateSettings(settings => {
|
||||
if (!isvalidProvider(settings.provider)) {
|
||||
settings.provider = DEFAULT_SETTINGS.provider;
|
||||
}
|
||||
|
||||
if (!isValidProviderModel(settings.model) || !modelMatchesProvider(settings.model, settings.provider)) {
|
||||
settings.model = DEFAULT_MODEL_BY_PROVIDER[settings.provider];
|
||||
}
|
||||
|
||||
if (!isValidProviderModel(settings.planningModel) || !modelMatchesProvider(settings.planningModel, settings.provider)) {
|
||||
settings.planningModel = DEFAULT_PLANNING_MODEL_BY_PROVIDER[settings.provider];
|
||||
}
|
||||
|
||||
if (!isValidProviderModel(settings.quickActionModel) || !modelMatchesProvider(settings.quickActionModel, settings.provider)) {
|
||||
settings.quickActionModel = DEFAULT_QUICK_MODEL_BY_PROVIDER[settings.provider];
|
||||
}
|
||||
|
||||
const cached = settings.cachedModelSettings[settings.provider];
|
||||
if (!isValidProviderModel(cached.planningModel) || !modelMatchesProvider(cached.planningModel, settings.provider)) {
|
||||
settings.cachedModelSettings[settings.provider].planningModel = DEFAULT_PLANNING_MODEL_BY_PROVIDER[settings.provider];
|
||||
}
|
||||
if (!isValidProviderModel(cached.quickActionModel) || !modelMatchesProvider(cached.quickActionModel, settings.provider)) {
|
||||
settings.cachedModelSettings[settings.provider].quickActionModel = DEFAULT_QUICK_MODEL_BY_PROVIDER[settings.provider];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async saveSettings() {
|
||||
const oldSettings = JSON.parse(this.settingsSnapshot) as IVaultkeeperAISettings;
|
||||
await this.plugin.saveData(this.settings);
|
||||
|
|
@ -171,26 +225,4 @@ export class SettingsService {
|
|||
}
|
||||
}
|
||||
|
||||
private ensureValidModels(): void {
|
||||
void this.updateSettings(settings => {
|
||||
let provider = settings.provider;
|
||||
|
||||
if (!isvalidProvider(provider)) {
|
||||
provider = DEFAULT_SETTINGS.provider;
|
||||
}
|
||||
|
||||
if (!isValidProviderModel(this.settings.model) || !modelMatchesProvider(this.settings.model, provider)) {
|
||||
settings.model = DEFAULT_MODEL_BY_PROVIDER[provider];
|
||||
}
|
||||
|
||||
if (!isValidProviderModel(this.settings.planningModel) || !modelMatchesProvider(this.settings.planningModel, provider)) {
|
||||
settings.planningModel = DEFAULT_PLANNING_MODEL_BY_PROVIDER[provider];
|
||||
}
|
||||
|
||||
if (!isValidProviderModel(this.settings.quickActionModel) || !modelMatchesProvider(this.settings.quickActionModel, provider)) {
|
||||
settings.quickActionModel = DEFAULT_QUICK_MODEL_BY_PROVIDER[provider];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
import { AIProvider, AIProviderModel, fromModel, isValidProviderModel } from "Enums/ApiProvider";
|
||||
import { AIProvider, AIProviderModel, DEFAULT_PLANNING_MODEL_BY_PROVIDER, DEFAULT_QUICK_MODEL_BY_PROVIDER, fromModel, isValidProviderModel } from "Enums/ApiProvider";
|
||||
import { Copy } from "Enums/Copy";
|
||||
import { Selector } from "Enums/Selector";
|
||||
import type VaultkeeperAIPlugin from "main";
|
||||
import { HelpModal } from "Modals/HelpModal";
|
||||
import { DropdownComponent, PluginSettingTab, Setting, ToggleComponent, setIcon, setTooltip } from "obsidian";
|
||||
import { Resolve } from "Services/DependencyService";
|
||||
import type { EventService } from "Services/EventService";
|
||||
import type { SettingsService } from "Services/SettingsService";
|
||||
import { Services } from "Services/Services";
|
||||
import { closePluginSettings } from "Helpers/Helpers";
|
||||
|
|
@ -16,7 +15,6 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
private readonly plugin: VaultkeeperAIPlugin;
|
||||
private readonly settingsService: SettingsService;
|
||||
private readonly memoriesService: MemoriesService;
|
||||
private readonly eventService: EventService;
|
||||
|
||||
private apiKeySetting: Setting | null = null;
|
||||
private apiKeyInputEl: HTMLInputElement | null = null;
|
||||
|
|
@ -34,7 +32,6 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
|
||||
this.settingsService = Resolve<SettingsService>(Services.SettingsService);
|
||||
this.memoriesService = Resolve<MemoriesService>(Services.MemoriesService);
|
||||
this.eventService = Resolve<EventService>(Services.EventService);
|
||||
}
|
||||
|
||||
public display() {
|
||||
|
|
@ -54,15 +51,23 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
return;
|
||||
}
|
||||
await this.settingsService.updateSettings(settings => {
|
||||
settings.model = value;
|
||||
settings.provider = fromModel(value);
|
||||
settings.model = value;
|
||||
const cached = settings.cachedModelSettings[settings.provider];
|
||||
if (cached.planningModel) {
|
||||
settings.planningModel = cached.planningModel;
|
||||
}
|
||||
if (cached.quickActionModel) {
|
||||
settings.quickActionModel = cached.quickActionModel;
|
||||
}
|
||||
});
|
||||
if (this.apiKeyInputEl) {
|
||||
this.apiKeyInputEl.value = this.settingsService.getApiKeyForCurrentModel();
|
||||
this.highlightApiKey();
|
||||
}
|
||||
this.updateFileDisclaimer();
|
||||
await this.settingsService.ensureValidModels();
|
||||
await this.updateModelDropdowns();
|
||||
this.updateFileDisclaimer();
|
||||
RegisterAiProvider();
|
||||
});
|
||||
});
|
||||
|
|
@ -87,6 +92,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
}
|
||||
await this.settingsService.updateSettings(settings => {
|
||||
settings.planningModel = value;
|
||||
settings.cachedModelSettings[settings.provider].planningModel = value;
|
||||
});
|
||||
RegisterAiProvider();
|
||||
});
|
||||
|
|
@ -106,6 +112,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
}
|
||||
await this.settingsService.updateSettings(settings => {
|
||||
settings.quickActionModel = value;
|
||||
settings.cachedModelSettings[settings.provider].quickActionModel = value;
|
||||
});
|
||||
RegisterAiProvider();
|
||||
});
|
||||
|
|
@ -378,7 +385,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
this.populateModelDropdown(this.planningModelDropdown, currentProvider);
|
||||
|
||||
if (planningProvider !== currentProvider) {
|
||||
settings.planningModel = settings.model;
|
||||
settings.planningModel = settings.cachedModelSettings[currentProvider].planningModel ?? DEFAULT_PLANNING_MODEL_BY_PROVIDER[currentProvider];
|
||||
}
|
||||
|
||||
this.planningModelDropdown.setValue(settings.planningModel);
|
||||
|
|
@ -390,7 +397,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
this.populateModelDropdown(this.quickActionModelDropdown);
|
||||
|
||||
if (quickActionProvider !== currentProvider) {
|
||||
settings.quickActionModel = settings.model;
|
||||
settings.quickActionModel = settings.cachedModelSettings[currentProvider].quickActionModel ?? DEFAULT_QUICK_MODEL_BY_PROVIDER[currentProvider];
|
||||
}
|
||||
|
||||
this.quickActionModelDropdown.setValue(settings.quickActionModel);
|
||||
|
|
|
|||
12
__tests__/Helpers/makeTestSettings.ts
Normal file
12
__tests__/Helpers/makeTestSettings.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { DEFAULT_SETTINGS, type IVaultkeeperAISettings } from 'Services/SettingsService';
|
||||
|
||||
/**
|
||||
* Builds a complete IVaultkeeperAISettings for tests, starting from the real
|
||||
* DEFAULT_SETTINGS so the mock can never drift from the production shape. Adding
|
||||
* a new required setting only requires updating DEFAULT_SETTINGS, not every test.
|
||||
*/
|
||||
export function makeTestSettings(
|
||||
overrides: Partial<IVaultkeeperAISettings> = {}
|
||||
): IVaultkeeperAISettings {
|
||||
return structuredClone({ ...DEFAULT_SETTINGS, ...overrides });
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
||||
import { SettingsService, type IVaultkeeperAISettings } from '../../Services/SettingsService';
|
||||
import { makeTestSettings } from '../Helpers/makeTestSettings';
|
||||
import { RegisterSingleton, DeregisterAllServices } from '../../Services/DependencyService';
|
||||
import { Services } from '../../Services/Services';
|
||||
import { AIProvider, AIProviderModel, fromModel } from '../../Enums/ApiProvider';
|
||||
import { ChatMode } from 'Enums/ChatMode';
|
||||
import { AIProvider, AIProviderModel } from '../../Enums/ApiProvider';
|
||||
|
||||
describe('SettingsService', () => {
|
||||
let settingsService: SettingsService;
|
||||
|
|
@ -90,30 +90,15 @@ describe('SettingsService', () => {
|
|||
|
||||
describe('getApiKeyForProvider', () => {
|
||||
beforeEach(() => {
|
||||
const loadedSettings: IVaultkeeperAISettings = {
|
||||
firstTimeStart: false,
|
||||
const loadedSettings = makeTestSettings({
|
||||
provider: AIProvider.Claude,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeOpus_4_8,
|
||||
apiKeys: {
|
||||
claude: 'claude-api-key',
|
||||
openai: 'openai-api-key',
|
||||
gemini: 'gemini-api-key', mistral: ''
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.ReadOnly
|
||||
};
|
||||
}
|
||||
});
|
||||
settingsService = new SettingsService(loadedSettings);
|
||||
});
|
||||
|
||||
|
|
@ -141,30 +126,15 @@ describe('SettingsService', () => {
|
|||
|
||||
describe('getApiKeyForCurrentModel', () => {
|
||||
it('should return Claude key when current model is Claude', () => {
|
||||
const loadedSettings: IVaultkeeperAISettings = {
|
||||
firstTimeStart: false,
|
||||
const loadedSettings = makeTestSettings({
|
||||
provider: AIProvider.Claude,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeOpus_4_8,
|
||||
apiKeys: {
|
||||
claude: 'claude-key',
|
||||
openai: 'openai-key',
|
||||
gemini: 'gemini-key', mistral: ''
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.ReadOnly
|
||||
};
|
||||
}
|
||||
});
|
||||
settingsService = new SettingsService(loadedSettings);
|
||||
|
||||
const key = settingsService.getApiKeyForCurrentModel();
|
||||
|
|
@ -172,30 +142,15 @@ describe('SettingsService', () => {
|
|||
});
|
||||
|
||||
it('should return OpenAI key when current model is GPT', () => {
|
||||
const loadedSettings: IVaultkeeperAISettings = {
|
||||
firstTimeStart: false,
|
||||
const loadedSettings = makeTestSettings({
|
||||
provider: AIProvider.OpenAI,
|
||||
model: AIProviderModel.GPT_5_4_Mini,
|
||||
planningModel: AIProviderModel.GPT_5_5,
|
||||
apiKeys: {
|
||||
claude: 'claude-key',
|
||||
openai: 'openai-key',
|
||||
gemini: 'gemini-key', mistral: ''
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.OpenAI,
|
||||
quickActionModel: AIProviderModel.GPT_5_4_Mini,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.ReadOnly
|
||||
};
|
||||
}
|
||||
});
|
||||
settingsService = new SettingsService(loadedSettings);
|
||||
|
||||
const key = settingsService.getApiKeyForCurrentModel();
|
||||
|
|
@ -203,30 +158,15 @@ describe('SettingsService', () => {
|
|||
});
|
||||
|
||||
it('should return Gemini key when current model is Gemini', () => {
|
||||
const loadedSettings: IVaultkeeperAISettings = {
|
||||
firstTimeStart: false,
|
||||
const loadedSettings = makeTestSettings({
|
||||
provider: AIProvider.Gemini,
|
||||
model: AIProviderModel.GeminiFlash_3_5_Flash,
|
||||
planningModel: AIProviderModel.GeminiPro_3_1_Preview,
|
||||
apiKeys: {
|
||||
claude: 'claude-key',
|
||||
openai: 'openai-key',
|
||||
gemini: 'gemini-key', mistral: ''
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Gemini,
|
||||
quickActionModel: AIProviderModel.GeminiFlash_3_5_Flash,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.ReadOnly
|
||||
};
|
||||
}
|
||||
});
|
||||
settingsService = new SettingsService(loadedSettings);
|
||||
|
||||
const key = settingsService.getApiKeyForCurrentModel();
|
||||
|
|
@ -262,30 +202,10 @@ describe('SettingsService', () => {
|
|||
|
||||
describe('setApiKeyForProvider', () => {
|
||||
beforeEach(() => {
|
||||
const loadedSettings: IVaultkeeperAISettings = {
|
||||
firstTimeStart: false,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeOpus_4_8,
|
||||
apiKeys: {
|
||||
claude: '',
|
||||
openai: '',
|
||||
gemini: '', mistral: ''
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
const loadedSettings = makeTestSettings({
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.ReadOnly
|
||||
};
|
||||
model: AIProviderModel.ClaudeSonnet_4_6
|
||||
});
|
||||
settingsService = new SettingsService(loadedSettings);
|
||||
});
|
||||
|
||||
|
|
@ -330,30 +250,17 @@ describe('SettingsService', () => {
|
|||
|
||||
describe('saveSettings', () => {
|
||||
beforeEach(() => {
|
||||
const loadedSettings: IVaultkeeperAISettings = {
|
||||
firstTimeStart: false,
|
||||
const loadedSettings = makeTestSettings({
|
||||
provider: AIProvider.Claude,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeOpus_4_8,
|
||||
apiKeys: {
|
||||
claude: 'test-key',
|
||||
openai: '',
|
||||
gemini: '', mistral: ''
|
||||
},
|
||||
exclusions: ['node_modules'],
|
||||
userInstruction: 'Be helpful',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.ReadOnly
|
||||
};
|
||||
userInstruction: 'Be helpful'
|
||||
});
|
||||
settingsService = new SettingsService(loadedSettings);
|
||||
mockPlugin.saveData.mockClear();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import { TFile, TFolder, TAbstractFile, MetadataCache, FileManager } from 'obsid
|
|||
import { VaultCacheService } from '../../Services/VaultCacheService';
|
||||
import { VaultService } from '../../Services/VaultService';
|
||||
import { SettingsService, type IVaultkeeperAISettings } from '../../Services/SettingsService';
|
||||
import { makeTestSettings } from '../Helpers/makeTestSettings';
|
||||
import { SanitiserService } from '../../Services/SanitiserService';
|
||||
import { RegisterSingleton, DeregisterAllServices } from '../../Services/DependencyService';
|
||||
import { Services } from '../../Services/Services';
|
||||
import { AIProvider, AIProviderModel } from '../../Enums/ApiProvider';
|
||||
import type VaultkeeperAIPlugin from '../../main';
|
||||
import { ChatMode } from '../../Enums/ChatMode';
|
||||
|
||||
|
|
@ -88,30 +88,17 @@ const mockPlugin = {
|
|||
registerEvent: vi.fn()
|
||||
} as unknown as VaultkeeperAIPlugin;
|
||||
|
||||
const mockSettings: IVaultkeeperAISettings = {
|
||||
const mockSettings: IVaultkeeperAISettings = makeTestSettings({
|
||||
firstTimeStart: false,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
apiKeys: {
|
||||
claude: 'test-claude-key',
|
||||
openai: 'test-openai-key',
|
||||
gemini: 'test-gemini-key', mistral: 'test-mistral-key'
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.Edit
|
||||
};
|
||||
});
|
||||
|
||||
let settingsService: SettingsService;
|
||||
let vaultService: VaultService;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { RegisterSingleton, DeregisterAllServices } from '../../Services/Depende
|
|||
import { Services } from '../../Services/Services';
|
||||
import { SanitiserService } from '../../Services/SanitiserService';
|
||||
import { SettingsService, type IVaultkeeperAISettings } from '../../Services/SettingsService';
|
||||
import { AIProvider, AIProviderModel } from '../../Enums/ApiProvider';
|
||||
import { makeTestSettings } from '../Helpers/makeTestSettings';
|
||||
import { Exception } from '../../Helpers/Exception';
|
||||
import * as PDFHelper from '../../Helpers/DocumentHelper';
|
||||
import type { IPageText } from '../../Types/SearchTypes';
|
||||
|
|
@ -48,30 +48,17 @@ const mockFileManager = {
|
|||
trashFile: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
|
||||
const mockSettings: IVaultkeeperAISettings = {
|
||||
const mockSettings: IVaultkeeperAISettings = makeTestSettings({
|
||||
firstTimeStart: false,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
apiKeys: {
|
||||
claude: 'test-claude-key',
|
||||
openai: 'test-openai-key',
|
||||
gemini: 'test-gemini-key', mistral: 'test-mistral-key'
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.Edit
|
||||
};
|
||||
});
|
||||
|
||||
const mockPlugin = {
|
||||
app: {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|||
import { TFile, TFolder, TAbstractFile, Vault, FileManager } from 'obsidian';
|
||||
import { VaultService } from '../../Services/VaultService';
|
||||
import { SettingsService, type IVaultkeeperAISettings } from '../../Services/SettingsService';
|
||||
import { makeTestSettings } from '../Helpers/makeTestSettings';
|
||||
import { SanitiserService } from '../../Services/SanitiserService';
|
||||
import { RegisterSingleton, DeregisterAllServices } from '../../Services/DependencyService';
|
||||
import { Services } from '../../Services/Services';
|
||||
import { AIProvider, AIProviderModel } from '../../Enums/ApiProvider';
|
||||
import type VaultkeeperAIPlugin from '../../main';
|
||||
import { ChatMode } from '../../Enums/ChatMode';
|
||||
|
||||
|
|
@ -50,30 +50,17 @@ const mockPlugin = {
|
|||
saveData: vi.fn().mockResolvedValue(undefined)
|
||||
} as unknown as VaultkeeperAIPlugin;
|
||||
|
||||
const mockSettings: IVaultkeeperAISettings = {
|
||||
const mockSettings: IVaultkeeperAISettings = makeTestSettings({
|
||||
firstTimeStart: false,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
apiKeys: {
|
||||
claude: 'test-claude-key',
|
||||
openai: 'test-openai-key',
|
||||
gemini: 'test-gemini-key', mistral: 'test-mistral-key'
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.Edit
|
||||
};
|
||||
});
|
||||
|
||||
let settingsService: SettingsService;
|
||||
let vaultService: VaultService;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { RegisterSingleton, DeregisterAllServices } from '../../Services/Depende
|
|||
import { Services } from '../../Services/Services';
|
||||
import { SanitiserService } from '../../Services/SanitiserService';
|
||||
import { SettingsService, type IVaultkeeperAISettings } from '../../Services/SettingsService';
|
||||
import { AIProvider, AIProviderModel } from '../../Enums/ApiProvider';
|
||||
import { makeTestSettings } from '../Helpers/makeTestSettings';
|
||||
import { Exception } from '../../Helpers/Exception';
|
||||
import { ChatMode } from '../../Enums/ChatMode';
|
||||
|
||||
|
|
@ -47,30 +47,17 @@ const mockFileManager = {
|
|||
};
|
||||
|
||||
// Create a mutable settings object that tests can modify
|
||||
const mockSettings: IVaultkeeperAISettings = {
|
||||
const mockSettings: IVaultkeeperAISettings = makeTestSettings({
|
||||
firstTimeStart: false,
|
||||
model: AIProviderModel.ClaudeSonnet_4_6,
|
||||
planningModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
apiKeys: {
|
||||
claude: 'test-claude-key',
|
||||
openai: 'test-openai-key',
|
||||
gemini: 'test-gemini-key', mistral: 'test-mistral-key'
|
||||
},
|
||||
exclusions: [],
|
||||
userInstruction: '',
|
||||
searchResultsLimit: 15,
|
||||
snippetSizeLimit: 300,
|
||||
enableMemories: false,
|
||||
allowUpdatingMemories: true,
|
||||
enableWebSearch: true,
|
||||
enableWebViewer: false,
|
||||
provider: AIProvider.Claude,
|
||||
quickActionModel: AIProviderModel.ClaudeSonnet_4_6,
|
||||
enableContextMenuActions: false,
|
||||
enableToolbarActions: false,
|
||||
hideDrawerElements: false,
|
||||
chatMode: ChatMode.Edit
|
||||
};
|
||||
});
|
||||
|
||||
const mockPlugin = {
|
||||
app: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue