feat: added local LLM context length option
This commit is contained in:
@@ -2,6 +2,7 @@ import { KGConfigStorage } from '../io/KGConfigStorage';
|
||||
import { CONFIG_UPGRADER_CONSTANTS } from '../../constants/coreConstants';
|
||||
import { upgradeConfigToV1 } from './upgradeConfigToV1';
|
||||
import { upgradeConfigToV2 } from './upgradeConfigToV2';
|
||||
import { upgradeConfigToV3 } from './upgradeConfigToV3';
|
||||
|
||||
/**
|
||||
* KGConfigUpgrader — Orchestrates app-level migrations (e.g., storage backend changes).
|
||||
@@ -38,6 +39,10 @@ export class KGConfigUpgrader {
|
||||
await upgradeConfigToV2();
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
await upgradeConfigToV3();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`No config upgrader found for version ${nextVersion}`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const configStore = new Map<string, { name: string; data: Record<string, unknown>; lastModified: number }>();
|
||||
|
||||
vi.mock('../io/KGConfigStorage', () => ({
|
||||
KGConfigStorage: {
|
||||
getInstance: () => ({
|
||||
getRaw: vi.fn(async (name: string) => configStore.get(name)?.data ?? null),
|
||||
saveRaw: vi.fn(async (name: string, data: Record<string, unknown>) => {
|
||||
configStore.set(name, { name, data, lastModified: Date.now() });
|
||||
}),
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
import { upgradeConfigToV3 } from './upgradeConfigToV3';
|
||||
|
||||
describe('upgradeConfigToV3', () => {
|
||||
beforeEach(() => {
|
||||
configStore.clear();
|
||||
});
|
||||
|
||||
it('adds the default local browser context length when missing', async () => {
|
||||
configStore.set('userConfig', {
|
||||
name: 'userConfig',
|
||||
data: {
|
||||
general: {
|
||||
llm_provider: 'local_browser',
|
||||
},
|
||||
},
|
||||
lastModified: Date.now(),
|
||||
});
|
||||
|
||||
await upgradeConfigToV3();
|
||||
|
||||
expect(
|
||||
((configStore.get('userConfig')?.data.general as Record<string, unknown>).local_browser as Record<string, unknown>).context_length,
|
||||
).toBe(32768);
|
||||
});
|
||||
|
||||
it.each([32768, 65536, 131072])('preserves existing context length %s', async (existingValue) => {
|
||||
configStore.set('userConfig', {
|
||||
name: 'userConfig',
|
||||
data: {
|
||||
general: {
|
||||
local_browser: {
|
||||
context_length: existingValue,
|
||||
},
|
||||
},
|
||||
},
|
||||
lastModified: Date.now(),
|
||||
});
|
||||
|
||||
await upgradeConfigToV3();
|
||||
|
||||
expect(
|
||||
((configStore.get('userConfig')?.data.general as Record<string, unknown>).local_browser as Record<string, unknown>).context_length,
|
||||
).toBe(existingValue);
|
||||
});
|
||||
|
||||
it('is a no-op when general is missing', async () => {
|
||||
configStore.set('userConfig', {
|
||||
name: 'userConfig',
|
||||
data: {},
|
||||
lastModified: Date.now(),
|
||||
});
|
||||
|
||||
await upgradeConfigToV3();
|
||||
|
||||
expect(configStore.get('userConfig')?.data).toEqual({});
|
||||
});
|
||||
|
||||
it('is a no-op when general is malformed', async () => {
|
||||
configStore.set('userConfig', {
|
||||
name: 'userConfig',
|
||||
data: {
|
||||
general: 'invalid',
|
||||
},
|
||||
lastModified: Date.now(),
|
||||
});
|
||||
|
||||
await upgradeConfigToV3();
|
||||
|
||||
expect(configStore.get('userConfig')?.data).toEqual({
|
||||
general: 'invalid',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { KGConfigStorage } from '../io/KGConfigStorage';
|
||||
import { LOCAL_LLM_DEFAULT_CONTEXT_LENGTH } from '../../util/localLLMConfig';
|
||||
|
||||
const CONFIG_KEY = 'userConfig';
|
||||
|
||||
export async function upgradeConfigToV3(): Promise<void> {
|
||||
const storage = KGConfigStorage.getInstance();
|
||||
const rawConfig = await storage.getRaw(CONFIG_KEY);
|
||||
if (!rawConfig || typeof rawConfig !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = rawConfig as Record<string, unknown>;
|
||||
const general = config.general;
|
||||
if (!general || typeof general !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
const generalRecord = general as Record<string, unknown>;
|
||||
const localBrowser = generalRecord.local_browser;
|
||||
|
||||
if (!localBrowser || typeof localBrowser !== 'object') {
|
||||
generalRecord.local_browser = { context_length: LOCAL_LLM_DEFAULT_CONTEXT_LENGTH };
|
||||
await storage.saveRaw(CONFIG_KEY, config);
|
||||
return;
|
||||
}
|
||||
|
||||
const localBrowserRecord = localBrowser as Record<string, unknown>;
|
||||
if ('context_length' in localBrowserRecord) {
|
||||
return;
|
||||
}
|
||||
|
||||
localBrowserRecord.context_length = LOCAL_LLM_DEFAULT_CONTEXT_LENGTH;
|
||||
await storage.saveRaw(CONFIG_KEY, config);
|
||||
}
|
||||
@@ -8,6 +8,9 @@ interface AppConfig {
|
||||
language: string;
|
||||
llm_provider: 'local_browser' | 'openai' | 'gemini' | 'claude' | 'claude_openrouter' | 'openai_compatible';
|
||||
persist_api_keys_non_localhost: boolean;
|
||||
local_browser: {
|
||||
context_length: 32768 | 65536 | 131072;
|
||||
};
|
||||
openai: {
|
||||
api_key: string;
|
||||
flex: boolean;
|
||||
@@ -208,6 +211,9 @@ export class ConfigManager {
|
||||
base_url: '',
|
||||
model: ''
|
||||
},
|
||||
local_browser: {
|
||||
context_length: 32768
|
||||
},
|
||||
soundfont: {
|
||||
base_url: 'https://cdn.jsdelivr.net/npm/soundfont-for-samplers/FluidR3_GM/'
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user