refactor: optimize settings change notifications and cleanup subscriptions

Remove unused dispose method and settings subscription from BaseAIClass. Update SettingsService to track which settings changed and notify subscribers with specific changed keys. Components now only react to relevant setting changes. Export RegisterAiProvider and call it when AI provider settings change to ensure provider is re-registered with new configuration.
This commit is contained in:
Andrew Beal 2026-05-26 18:51:08 +01:00
parent 23dbf5e5a2
commit 5fc1cfba60
6 changed files with 30 additions and 23 deletions

View file

@ -27,8 +27,6 @@ export abstract class BaseAIClass implements IAIClass {
protected readonly settingsService: SettingsService;
protected readonly streamingService: StreamingService;
private readonly settingsSubscription: object;
private _systemPrompt: string = "";
private _userInstruction: string = "";
private _agentType: AgentType = AgentType.Main;
@ -42,16 +40,9 @@ export abstract class BaseAIClass implements IAIClass {
this.settingsService = Resolve<SettingsService>(Services.SettingsService);
this.streamingService = Resolve<StreamingService>(Services.StreamingService);
this.settingsSubscription = this.settingsService.subscribeToSettingsChanged(() => {
this.apiKey = this.settingsService.getApiKeyForProvider(provider);
});
this.apiKey = this.settingsService.getApiKeyForProvider(provider);
}
public dispose(): void {
this.settingsService.unsubscribe(this.settingsSubscription);
}
public get currentProvider(): AIProvider {
return this.provider;
}

View file

@ -73,11 +73,13 @@
const diffClosedRef: EventRef = eventService.on(Event.DiffClosed, () => { inputMode = InputMode.Normal; focusInput(); });
const rateLimitCountdownRef: EventRef = eventService.on(Event.RateLimitCountdown, (delayMs: number) => { startCountdown(delayMs); });
const settingsSubscription: object = settingsService.subscribeToSettingsChanged(() => {
chatMode = settingsService.settings.chatMode;
editsAllowed = chatModeAllowsEdits(chatMode);
if (chatModeButton){
setIcon(chatModeButton, iconForChatMode(chatMode));
const settingsSubscription: object = settingsService.subscribeToSettingsChanged(changed => {
if (changed.includes("chatMode")) {
chatMode = settingsService.settings.chatMode;
editsAllowed = chatModeAllowsEdits(chatMode);
if (chatModeButton) {
setIcon(chatModeButton, iconForChatMode(chatMode));
}
}
});

View file

@ -12,7 +12,11 @@
const settingsService: SettingsService = Resolve<SettingsService>(Services.SettingsService);
const settingsSubscription: object = settingsService.subscribeToSettingsChanged(() => currentChatMode = settingsService.settings.chatMode);
const settingsSubscription: object = settingsService.subscribeToSettingsChanged(changed => {
if (changed.includes("chatMode")) {
currentChatMode = settingsService.settings.chatMode;
}
});
onDestroy(() => settingsService.unsubscribe(settingsSubscription));

View file

@ -102,7 +102,7 @@ export function RegisterDependencies() {
RegisterAiProvider();
}
function RegisterAiProvider() {
export function RegisterAiProvider() {
const settingsService = Resolve<SettingsService>(Services.SettingsService);
const provider = fromModel(settingsService.settings.model);

View file

@ -81,12 +81,15 @@ export interface IVaultkeeperAISettings {
hideDrawerElements: boolean;
}
type SettingKey = keyof IVaultkeeperAISettings;
type SettingsChangedCallback = ((changedKeys: SettingKey[]) => void) | ((changedKeys: SettingKey[]) => Promise<void>);
export class SettingsService {
public readonly settings: Readonly<IVaultkeeperAISettings>;
private readonly plugin: VaultkeeperAIPlugin;
private readonly subscribers: WeakMap<object, (() => void) | (() => Promise<void>)> = new WeakMap();
private readonly subscribers: WeakMap<object, SettingsChangedCallback> = new WeakMap();
private readonly subscriberRefs: Set<WeakRef<object>> = new Set();
private settingsSnapshot: string;
@ -98,7 +101,7 @@ export class SettingsService {
this.ensureValidModels();
}
public subscribeToSettingsChanged(callback: (() => void) | (() => Promise<void>)): object {
public subscribeToSettingsChanged(callback: SettingsChangedCallback): object {
const token = {};
this.subscribers.set(token, callback);
this.subscriberRefs.add(new WeakRef(token));
@ -150,17 +153,19 @@ export class SettingsService {
}
private async saveSettings() {
const oldSettings = JSON.parse(this.settingsSnapshot) as IVaultkeeperAISettings;
await this.plugin.saveData(this.settings);
const snapshot = JSON.stringify(this.settings);
if (this.settingsSnapshot !== snapshot) {
this.settingsSnapshot = snapshot;
const changedKeys = (Object.keys(this.settings) as SettingKey[])
.filter(key => JSON.stringify(this.settings[key]) !== JSON.stringify(oldSettings[key]));
if (changedKeys.length > 0) {
this.settingsSnapshot = JSON.stringify(this.settings);
for (const ref of this.subscriberRefs) {
const subscriber = ref.deref();
if (!subscriber) {
if (!subscriber) {
this.subscriberRefs.delete(ref);
continue;
}
await this.subscribers.get(subscriber)?.();
await this.subscribers.get(subscriber)?.(changedKeys);
}
}
}

View file

@ -11,6 +11,7 @@ import type { SettingsService } from "Services/SettingsService";
import { Services } from "Services/Services";
import { closePluginSettings } from "Helpers/Helpers";
import type { MemoriesService } from "Services/MemoriesService";
import { RegisterAiProvider } from "Services/ServiceRegistration";
export class VaultkeeperAISettingTab extends PluginSettingTab {
private readonly plugin: VaultkeeperAIPlugin;
@ -63,6 +64,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
}
this.updateFileDisclaimer();
await this.updateModelDropdowns();
RegisterAiProvider();
});
});
@ -87,6 +89,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
await this.settingsService.updateSettings(settings => {
settings.planningModel = value;
});
RegisterAiProvider();
});
});
@ -105,6 +108,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
await this.settingsService.updateSettings(settings => {
settings.quickActionModel = value;
});
RegisterAiProvider();
});
});
@ -120,6 +124,7 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
await this.settingsService.setApiKeyForProvider(fromModel(settings.model), value);
});
this.highlightApiKey();
RegisterAiProvider();
});
text.inputEl.type = "password";
this.apiKeyInputEl = text.inputEl;