feat: separated efficient agent mode (lite mode) for small language models
This commit is contained in:
@@ -23,6 +23,7 @@ import { KGConversationStorage } from '../core/io/KGConversationStorage';
|
||||
import { SAVED_CONVERSATION_VERSION, type SavedConversationDocument, type SavedConversationMeta } from '../types/conversationTypes';
|
||||
import type { Message } from '../agent/core/AgentState';
|
||||
import { showConfirm } from '../util/dialogUtil';
|
||||
import { getEffectiveAgentMode, getSystemPromptPathForAgentMode } from '../util/agentMode';
|
||||
|
||||
import type { ChatMessage } from '../types/projectTypes';
|
||||
|
||||
@@ -631,9 +632,9 @@ const ChatBox: React.FC<ChatBoxProps> = ({ isVisible }) => {
|
||||
// Log system prompt only for first message
|
||||
if (isFirstMessage) {
|
||||
try {
|
||||
const provider = AgentCore.instance().getLLMProvider();
|
||||
const agentMode = getEffectiveAgentMode(ConfigManager.instance());
|
||||
const systemPrompt = await SystemPrompts.getSystemPromptWithContext(
|
||||
provider?.getPreferredSystemPromptPath?.(),
|
||||
getSystemPromptPathForAgentMode(agentMode),
|
||||
);
|
||||
console.log('------------ SYSTEM ------------');
|
||||
console.log(systemPrompt);
|
||||
|
||||
@@ -14,6 +14,7 @@ const { localSeparatorModelCacheMock } = vi.hoisted(() => ({
|
||||
|
||||
const configState = new Map<string, unknown>([
|
||||
['general.language', 'auto'],
|
||||
['general.agent_mode', 'regular'],
|
||||
['general.llm_provider', 'local_browser'],
|
||||
['general.persist_api_keys_non_localhost', false],
|
||||
['general.auto_compact_threshold_percent', 90],
|
||||
@@ -107,6 +108,8 @@ describe('GeneralSettings', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
configState.set('general.language', 'auto');
|
||||
configState.set('general.agent_mode', 'regular');
|
||||
configState.set('general.llm_provider', 'local_browser');
|
||||
configState.set('general.local_browser.context_length', 65536);
|
||||
configState.set('general.auto_compact_threshold_percent', 90);
|
||||
configManagerMock.get.mockClear();
|
||||
@@ -196,6 +199,41 @@ describe('GeneralSettings', () => {
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders the music assistant section and initializes the agent mode selector', async () => {
|
||||
configState.set('general.llm_provider', 'openai');
|
||||
configState.set('general.agent_mode', 'efficient');
|
||||
|
||||
renderSettings();
|
||||
|
||||
expect(await screen.findByText('K.G.Studio Music Assistant')).toBeTruthy();
|
||||
const select = screen.getByLabelText('Agent Mode');
|
||||
expect((select as HTMLSelectElement).value).toBe('efficient');
|
||||
});
|
||||
|
||||
it('persists agent mode changes for non-local providers', async () => {
|
||||
configState.set('general.llm_provider', 'openai');
|
||||
|
||||
renderSettings();
|
||||
|
||||
const select = await screen.findByLabelText('Agent Mode');
|
||||
fireEvent.change(select, { target: { value: 'efficient' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(configManagerMock.set).toHaveBeenCalledWith('general.agent_mode', 'efficient');
|
||||
});
|
||||
});
|
||||
|
||||
it('disables the agent mode selector for the local browser provider and shows override help', async () => {
|
||||
configState.set('general.llm_provider', 'local_browser');
|
||||
configState.set('general.agent_mode', 'regular');
|
||||
|
||||
renderSettings();
|
||||
|
||||
const select = await screen.findByLabelText('Agent Mode');
|
||||
expect(select).toBeDisabled();
|
||||
expect(screen.getByText('Local LLM (Browser) always runs the assistant in Efficient Mode.')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders and persists local runtime download URLs', async () => {
|
||||
renderSettings();
|
||||
|
||||
|
||||
@@ -18,6 +18,13 @@ import {
|
||||
LOCAL_SEPARATOR_MODEL_CONFIGS,
|
||||
LOCAL_SEPARATOR_MODEL_IDS,
|
||||
} from '../../../util/local-separator/config';
|
||||
import {
|
||||
DEFAULT_AGENT_MODE,
|
||||
getEffectiveAgentMode,
|
||||
isAgentModeForcedByProvider,
|
||||
normalizeAgentMode,
|
||||
type AgentMode,
|
||||
} from '../../../util/agentMode';
|
||||
|
||||
const LANGUAGE_OPTION_LABELS: Record<Exclude<LanguageSetting, 'auto'>, string> = {
|
||||
en_us: 'English',
|
||||
@@ -29,6 +36,7 @@ const LANGUAGE_OPTION_LABELS: Record<Exclude<LanguageSetting, 'auto'>, string> =
|
||||
const GeneralSettings: React.FC = () => {
|
||||
const { t, setLanguageSetting } = useI18n();
|
||||
const [language, setLanguage] = useState<LanguageSetting>('auto');
|
||||
const [agentMode, setAgentMode] = useState<AgentMode>(DEFAULT_AGENT_MODE);
|
||||
const [llmProvider, setLlmProvider] = useState<string>(LOCAL_LLM_PROVIDER_KEY);
|
||||
const [openaiKey, setOpenaiKey] = useState<string>('');
|
||||
const [openaiModel, setOpenaiModel] = useState<string>('');
|
||||
@@ -103,6 +111,7 @@ const GeneralSettings: React.FC = () => {
|
||||
}
|
||||
|
||||
setLanguage(((configManager.get('general.language') as LanguageSetting | undefined) ?? 'auto'));
|
||||
setAgentMode(normalizeAgentMode(configManager.get('general.agent_mode')));
|
||||
setLlmProvider((configManager.get('general.llm_provider') as string) || LOCAL_LLM_PROVIDER_KEY);
|
||||
setOpenaiKey((configManager.get('general.openai.api_key') as string) || '');
|
||||
setOpenaiModel((configManager.get('general.openai.model') as string) || '');
|
||||
@@ -169,6 +178,16 @@ const GeneralSettings: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleAgentModeChange = async (value: AgentMode) => {
|
||||
setAgentMode(value);
|
||||
try {
|
||||
await configManager.set('general.agent_mode', value);
|
||||
console.log('Agent mode changed to:', value);
|
||||
} catch (error) {
|
||||
console.error('Failed to save agent mode:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLanguageChange = async (value: LanguageSetting) => {
|
||||
setLanguage(value);
|
||||
try {
|
||||
@@ -354,6 +373,8 @@ const GeneralSettings: React.FC = () => {
|
||||
|
||||
const localRuntimeMessage = localModelState.runtimeSupport.reason;
|
||||
const hasLocalRuntimeHardFailure = !localModelState.runtimeSupport.supported;
|
||||
const isAgentModeOverriddenByLocalProvider = isAgentModeForcedByProvider(llmProvider);
|
||||
const effectiveAgentMode = getEffectiveAgentMode(configManager);
|
||||
|
||||
// NOTE: Gemini and Claude are not supported yet due to CORS issues.
|
||||
return (
|
||||
@@ -444,6 +465,38 @@ const GeneralSettings: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settings-group">
|
||||
<h4>{t('settings.general.musicAssistant.section')}</h4>
|
||||
|
||||
<div className="settings-item">
|
||||
<label className="settings-label" htmlFor="general-agent-mode-select">
|
||||
{t('settings.general.musicAssistant.agentMode.label')}
|
||||
</label>
|
||||
<select
|
||||
id="general-agent-mode-select"
|
||||
className="settings-select"
|
||||
value={agentMode}
|
||||
onChange={(e) => void handleAgentModeChange(e.target.value as AgentMode)}
|
||||
disabled={isAgentModeOverriddenByLocalProvider}
|
||||
>
|
||||
<option value="regular">{t('settings.general.musicAssistant.agentMode.regular')}</option>
|
||||
<option value="efficient">{t('settings.general.musicAssistant.agentMode.efficient')}</option>
|
||||
</select>
|
||||
<div className="settings-help" style={{ fontSize: '12px', color: '#888', marginTop: '4px' }}>
|
||||
{isAgentModeOverriddenByLocalProvider
|
||||
? t('settings.general.musicAssistant.agentMode.localOverride')
|
||||
: t('settings.general.musicAssistant.agentMode.help')}
|
||||
</div>
|
||||
{effectiveAgentMode !== agentMode && (
|
||||
<div className="settings-help" style={{ fontSize: '12px', color: '#888', marginTop: '4px' }}>
|
||||
{t('settings.general.musicAssistant.agentMode.effectiveValue', {
|
||||
mode: t('settings.general.musicAssistant.agentMode.efficient'),
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settings-group">
|
||||
<h4>{LOCAL_LLM_DISPLAY_NAME} Local Runtime</h4>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user