refactor: move summarization model settings to notifications

- Remove Utility Model controls from Session Defaults and restore that section’s original scope.
- Add Zen-based Summarization Model selector to Notifications under AI Summarization.
- Keep config resolution aligned with zenModel-only utility behavior in useConfigStore and git API flow.
This commit is contained in:
Bohdan Triapitsyn
2026-02-24 16:19:39 +02:00
parent 100d6d33a1
commit 2f3209bd65
4 changed files with 150 additions and 213 deletions
@@ -12,9 +12,6 @@ import { useUIStore } from '@/stores/useUIStore';
import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';
import { getModifierLabel, cn } from '@/lib/utils';
const UTILITY_PROVIDER_ID = 'zen';
const UTILITY_PREFERRED_MODEL_ID = 'big-pickle';
const getDisplayModel = (
storedModel: string | undefined
): { providerId: string; modelId: string } => {
@@ -28,45 +25,6 @@ const getDisplayModel = (
return { providerId: '', modelId: '' };
};
const getUtilityDisplayModel = (
storedGitProviderId: string | undefined,
storedGitModelId: string | undefined,
zenModel: string | undefined,
providers: Array<{ id: string; models: Array<{ id: string }> }>
): { providerId: string; modelId: string } => {
if (storedGitProviderId && storedGitModelId) {
const provider = providers.find((p) => p.id === storedGitProviderId);
if (provider?.models.some((m) => m.id === storedGitModelId)) {
return { providerId: storedGitProviderId, modelId: storedGitModelId };
}
}
const utilityProvider = providers.find((p) => p.id === UTILITY_PROVIDER_ID);
if (zenModel && utilityProvider?.models.some((m) => m.id === zenModel)) {
return { providerId: UTILITY_PROVIDER_ID, modelId: zenModel };
}
const preferredUtilityModel = utilityProvider?.models.find((m) => m.id === UTILITY_PREFERRED_MODEL_ID);
if (preferredUtilityModel) {
return { providerId: UTILITY_PROVIDER_ID, modelId: preferredUtilityModel.id };
}
if (utilityProvider?.models.length) {
const randomIndex = Math.floor(Math.random() * utilityProvider.models.length);
const randomModel = utilityProvider.models[randomIndex];
if (randomModel?.id) {
return { providerId: UTILITY_PROVIDER_ID, modelId: randomModel.id };
}
}
const firstProvider = providers[0];
if (firstProvider?.models[0]) {
return { providerId: firstProvider.id, modelId: firstProvider.models[0].id };
}
return { providerId: '', modelId: '' };
};
export const DefaultsSettings: React.FC = () => {
const setProvider = useConfigStore((state) => state.setProvider);
const setModel = useConfigStore((state) => state.setModel);
@@ -77,12 +35,6 @@ export const DefaultsSettings: React.FC = () => {
const setSettingsDefaultAgent = useConfigStore((state) => state.setSettingsDefaultAgent);
const settingsAutoCreateWorktree = useConfigStore((state) => state.settingsAutoCreateWorktree);
const setSettingsAutoCreateWorktree = useConfigStore((state) => state.setSettingsAutoCreateWorktree);
const settingsZenModel = useConfigStore((state) => state.settingsZenModel);
const setSettingsZenModel = useConfigStore((state) => state.setSettingsZenModel);
const settingsGitProviderId = useConfigStore((state) => state.settingsGitProviderId);
const settingsGitModelId = useConfigStore((state) => state.settingsGitModelId);
const setSettingsGitProviderId = useConfigStore((state) => state.setSettingsGitProviderId);
const setSettingsGitModelId = useConfigStore((state) => state.setSettingsGitModelId);
const showDeletionDialog = useUIStore((state) => state.showDeletionDialog);
const setShowDeletionDialog = useUIStore((state) => state.setShowDeletionDialog);
const providers = useConfigStore((state) => state.providers);
@@ -93,9 +45,6 @@ export const DefaultsSettings: React.FC = () => {
const [isLoading, setIsLoading] = React.useState(true);
const parsedModel = React.useMemo(() => getDisplayModel(defaultModel), [defaultModel]);
const utilityDisplayModel = React.useMemo(() => {
return getUtilityDisplayModel(settingsGitProviderId, settingsGitModelId, settingsZenModel, providers);
}, [settingsGitProviderId, settingsGitModelId, settingsZenModel, providers]);
const isVSCode = React.useMemo(() => isVSCodeRuntime(), []);
React.useEffect(() => {
@@ -105,9 +54,6 @@ export const DefaultsSettings: React.FC = () => {
defaultModel?: string;
defaultVariant?: string;
defaultAgent?: string;
zenModel?: string;
gitProviderId?: string;
gitModelId?: string;
} | null = null;
if (!data) {
@@ -124,18 +70,6 @@ export const DefaultsSettings: React.FC = () => {
? ((settings as Record<string, unknown>).defaultVariant as string)
: undefined,
defaultAgent: typeof settings.defaultAgent === 'string' ? settings.defaultAgent : undefined,
zenModel:
typeof (settings as Record<string, unknown>).zenModel === 'string'
? ((settings as Record<string, unknown>).zenModel as string)
: undefined,
gitProviderId:
typeof (settings as Record<string, unknown>).gitProviderId === 'string'
? ((settings as Record<string, unknown>).gitProviderId as string)
: undefined,
gitModelId:
typeof (settings as Record<string, unknown>).gitModelId === 'string'
? ((settings as Record<string, unknown>).gitModelId as string)
: undefined,
};
}
} catch {
@@ -167,25 +101,10 @@ export const DefaultsSettings: React.FC = () => {
typeof data.defaultAgent === 'string' && data.defaultAgent.trim().length > 0
? data.defaultAgent.trim()
: undefined;
const zen =
typeof data.zenModel === 'string' && data.zenModel.trim().length > 0
? data.zenModel.trim()
: undefined;
const gitProviderId =
typeof data.gitProviderId === 'string' && data.gitProviderId.trim().length > 0
? data.gitProviderId.trim()
: undefined;
const gitModelId =
typeof data.gitModelId === 'string' && data.gitModelId.trim().length > 0
? data.gitModelId.trim()
: undefined;
if (model !== undefined) setDefaultModel(model);
if (variant !== undefined) setDefaultVariant(variant);
if (agent !== undefined) setDefaultAgent(agent);
if (zen !== undefined) setSettingsZenModel(zen);
if (gitProviderId !== undefined) setSettingsGitProviderId(gitProviderId);
if (gitModelId !== undefined) setSettingsGitModelId(gitModelId);
}
} catch (error) {
console.warn('Failed to load defaults settings:', error);
@@ -194,7 +113,7 @@ export const DefaultsSettings: React.FC = () => {
}
};
loadSettings();
}, [setSettingsGitModelId, setSettingsGitProviderId, setSettingsZenModel]);
}, []);
const handleModelChange = React.useCallback(
async (providerId: string, modelId: string) => {
@@ -303,26 +222,6 @@ export const DefaultsSettings: React.FC = () => {
[setSettingsAutoCreateWorktree]
);
const handleUtilityModelChange = React.useCallback(
async (providerId: string, modelId: string) => {
setSettingsGitProviderId(providerId);
setSettingsGitModelId(modelId);
if (providerId === UTILITY_PROVIDER_ID) {
setSettingsZenModel(modelId);
}
try {
await updateDesktopSettings({
gitProviderId: providerId,
gitModelId: modelId,
...(providerId === UTILITY_PROVIDER_ID ? { zenModel: modelId } : {}),
});
} catch (error) {
console.warn('Failed to save utility model setting:', error);
}
},
[setSettingsGitModelId, setSettingsGitProviderId, setSettingsZenModel]
);
if (isLoading) {
return null;
}
@@ -393,29 +292,6 @@ export const DefaultsSettings: React.FC = () => {
</div>
</div>
<div className="flex flex-col gap-2 py-1 sm:flex-row sm:items-center sm:gap-8">
<div className="flex min-w-0 flex-col sm:w-56 shrink-0">
<div className="flex items-center gap-2">
<span className="typography-ui-label text-foreground">Utility Model</span>
<Tooltip delayDuration={1000}>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
<TooltipContent sideOffset={8} className="max-w-xs">
The model used for lightweight background tasks like commit messages, PR descriptions, and summarization.
</TooltipContent>
</Tooltip>
</div>
</div>
<div className="flex min-w-0 flex-1 items-center gap-2 sm:w-fit sm:flex-initial">
<ModelSelector
providerId={utilityDisplayModel.providerId}
modelId={utilityDisplayModel.modelId}
onChange={handleUtilityModelChange}
/>
</div>
</div>
<div
className="group flex cursor-pointer items-center gap-2 py-1"
role="button"
@@ -1,8 +1,10 @@
import React from 'react';
import { RiRestartLine } from '@remixicon/react';
import { RiInformationLine, RiRestartLine } from '@remixicon/react';
import { useUIStore } from '@/stores/useUIStore';
import { useConfigStore } from '@/stores/useConfigStore';
import { isDesktopShell, isVSCodeRuntime } from '@/lib/desktop';
import { useDeviceInfo } from '@/lib/device';
import { updateDesktopSettings } from '@/lib/persistence';
import { Checkbox } from '@/components/ui/checkbox';
import { toast } from '@/components/ui';
import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';
@@ -10,6 +12,8 @@ import { GridLoader } from '@/components/ui/grid-loader';
import { Input } from '@/components/ui/input';
import { NumberInput } from '@/components/ui/number-input';
import { ButtonSmall } from '@/components/ui/button-small';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
const DEFAULT_NOTIFICATION_TEMPLATES = {
@@ -19,6 +23,10 @@ const DEFAULT_NOTIFICATION_TEMPLATES = {
subtask: { title: '{agent_name} is ready', message: '{model_name} completed the task' },
} as const;
const UTILITY_PROVIDER_ID = 'zen';
const UTILITY_PREFERRED_MODEL_ID = 'big-pickle';
const UTILITY_NOT_SELECTED_VALUE = '__not_selected__';
const DEFAULT_SUMMARY_THRESHOLD = 200;
const DEFAULT_SUMMARY_LENGTH = 100;
const DEFAULT_MAX_LAST_MESSAGE_LENGTH = 250;
@@ -50,11 +58,105 @@ export const NotificationSettings: React.FC = () => {
const setSummaryLength = useUIStore(state => state.setSummaryLength);
const maxLastMessageLength = useUIStore(state => state.maxLastMessageLength);
const setMaxLastMessageLength = useUIStore(state => state.setMaxLastMessageLength);
const providers = useConfigStore((state) => state.providers);
const settingsZenModel = useConfigStore((state) => state.settingsZenModel);
const setSettingsZenModel = useConfigStore((state) => state.setSettingsZenModel);
const [notificationPermission, setNotificationPermission] = React.useState<NotificationPermission>('default');
const [pushSupported, setPushSupported] = React.useState(false);
const [pushSubscribed, setPushSubscribed] = React.useState(false);
const [pushBusy, setPushBusy] = React.useState(false);
const [fetchedZenModels, setFetchedZenModels] = React.useState<Array<{ id: string; name: string }>>([]);
const providerZenModels = React.useMemo(() => {
const zenProvider = providers.find((provider) => provider.id === UTILITY_PROVIDER_ID);
const models = Array.isArray(zenProvider?.models) ? zenProvider.models : [];
return models
.map((model: Record<string, unknown>) => {
const id = typeof model.id === 'string' ? model.id.trim() : '';
if (!id) {
return null;
}
const name = typeof model.name === 'string' && model.name.trim().length > 0 ? model.name.trim() : id;
return { id, name };
})
.filter((model): model is { id: string; name: string } => model !== null);
}, [providers]);
React.useEffect(() => {
if (providerZenModels.length > 0) {
setFetchedZenModels([]);
return;
}
const controller = new AbortController();
void fetch('/api/zen/models', {
method: 'GET',
headers: { Accept: 'application/json' },
signal: controller.signal,
})
.then(async (response) => {
if (!response.ok) {
return [] as Array<{ id: string; name: string }>;
}
const payload = await response.json().catch(() => ({}));
const models = Array.isArray(payload?.models) ? payload.models : [];
return models
.map((entry: unknown) => {
const id = typeof (entry as { id?: unknown })?.id === 'string'
? (entry as { id: string }).id.trim()
: '';
if (!id) {
return null;
}
return { id, name: id };
})
.filter((entry: { id: string; name: string } | null): entry is { id: string; name: string } => entry !== null);
})
.then((models) => {
setFetchedZenModels(models);
})
.catch((error) => {
if (error?.name !== 'AbortError') {
console.warn('Failed to load zen utility models:', error);
}
});
return () => {
controller.abort();
};
}, [providerZenModels]);
const utilityModelOptions = React.useMemo(() => {
return providerZenModels.length > 0 ? providerZenModels : fetchedZenModels;
}, [fetchedZenModels, providerZenModels]);
const utilitySelectedModelId = React.useMemo(() => {
if (settingsZenModel && utilityModelOptions.some((model) => model.id === settingsZenModel)) {
return settingsZenModel;
}
if (utilityModelOptions.some((model) => model.id === UTILITY_PREFERRED_MODEL_ID)) {
return UTILITY_PREFERRED_MODEL_ID;
}
return utilityModelOptions[0]?.id ?? '';
}, [settingsZenModel, utilityModelOptions]);
const handleUtilityModelChange = React.useCallback(
async (value: string) => {
const modelId = value === UTILITY_NOT_SELECTED_VALUE ? undefined : value;
setSettingsZenModel(modelId);
try {
await updateDesktopSettings({
zenModel: modelId ?? '',
gitProviderId: '',
gitModelId: '',
});
} catch (error) {
console.warn('Failed to save utility model setting:', error);
}
},
[setSettingsZenModel]
);
React.useEffect(() => {
if (!isBrowser) {
@@ -648,6 +750,40 @@ export const NotificationSettings: React.FC = () => {
<span className="typography-ui-label text-foreground">Summarize Last Message</span>
</div>
<div className={cn("flex flex-col gap-2 py-1 sm:flex-row sm:items-center sm:gap-8")}>
<div className="flex min-w-0 flex-col sm:w-56 shrink-0">
<div className="flex items-center gap-2">
<span className="typography-ui-label text-foreground">Summarization Model</span>
<Tooltip delayDuration={1000}>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
<TooltipContent sideOffset={8} className="max-w-xs">
Used for notification and voice summaries.
</TooltipContent>
</Tooltip>
</div>
</div>
<div className="flex min-w-0 flex-1 items-center gap-2 sm:w-fit sm:flex-initial">
<Select
value={utilitySelectedModelId || UTILITY_NOT_SELECTED_VALUE}
onValueChange={handleUtilityModelChange}
>
<SelectTrigger className="w-fit min-w-[220px]">
<SelectValue placeholder="Not selected" />
</SelectTrigger>
<SelectContent>
<SelectItem value={UTILITY_NOT_SELECTED_VALUE}>Not selected</SelectItem>
{utilityModelOptions.map((model) => (
<SelectItem key={model.id} value={model.id}>
{model.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
{summarizeLastMessage ? (
<>
<div className="flex items-center gap-8 py-1.5 mt-1 border-t border-[var(--surface-subtle)]">
+2 -2
View File
@@ -116,7 +116,7 @@ export async function generateCommitMessage(
const generationSession = resolveSessionGenerationContext();
if (!generationSession) {
throw new Error('Select an active session for generation');
throw new Error('Select existing session for generation');
}
console.info('[git-generation][browser] request', {
@@ -205,7 +205,7 @@ export async function generatePullRequestDescription(
const startedAt = Date.now();
const generationSession = resolveSessionGenerationContext();
if (!generationSession) {
throw new Error('Select an active session for generation');
throw new Error('Select existing session for generation');
}
const commitLog = await getGitLog(directory, {
+10 -85
View File
@@ -28,8 +28,6 @@ interface OpenChamberDefaults {
autoCreateWorktree?: boolean;
gitmojiEnabled?: boolean;
zenModel?: string;
gitProviderId?: string;
gitModelId?: string;
}
const fetchOpenChamberDefaults = async (): Promise<OpenChamberDefaults> => {
@@ -46,8 +44,6 @@ const fetchOpenChamberDefaults = async (): Promise<OpenChamberDefaults> => {
const defaultAgent = typeof data?.defaultAgent === 'string' ? data.defaultAgent.trim() : '';
const gitmojiEnabled = typeof data?.gitmojiEnabled === 'boolean' ? data.gitmojiEnabled : undefined;
const zenModel = typeof data?.zenModel === 'string' ? data.zenModel.trim() : '';
const gitProviderId = typeof data?.gitProviderId === 'string' ? data.gitProviderId.trim() : '';
const gitModelId = typeof data?.gitModelId === 'string' ? data.gitModelId.trim() : '';
return {
defaultModel: defaultModel.length > 0 ? defaultModel : undefined,
@@ -56,8 +52,6 @@ const fetchOpenChamberDefaults = async (): Promise<OpenChamberDefaults> => {
autoCreateWorktree: typeof data?.autoCreateWorktree === 'boolean' ? data.autoCreateWorktree : undefined,
gitmojiEnabled,
zenModel: zenModel.length > 0 ? zenModel : undefined,
gitProviderId: gitProviderId.length > 0 ? gitProviderId : undefined,
gitModelId: gitModelId.length > 0 ? gitModelId : undefined,
};
}
} catch {
@@ -79,8 +73,6 @@ const fetchOpenChamberDefaults = async (): Promise<OpenChamberDefaults> => {
const defaultAgent = typeof data?.defaultAgent === 'string' ? data.defaultAgent.trim() : '';
const gitmojiEnabled = typeof data?.gitmojiEnabled === 'boolean' ? data.gitmojiEnabled : undefined;
const zenModel = typeof data?.zenModel === 'string' ? data.zenModel.trim() : '';
const gitProviderId = typeof data?.gitProviderId === 'string' ? data.gitProviderId.trim() : '';
const gitModelId = typeof data?.gitModelId === 'string' ? data.gitModelId.trim() : '';
return {
defaultModel: defaultModel.length > 0 ? defaultModel : undefined,
@@ -89,8 +81,6 @@ const fetchOpenChamberDefaults = async (): Promise<OpenChamberDefaults> => {
autoCreateWorktree: typeof data?.autoCreateWorktree === 'boolean' ? data.autoCreateWorktree : undefined,
gitmojiEnabled,
zenModel: zenModel.length > 0 ? zenModel : undefined,
gitProviderId: gitProviderId.length > 0 ? gitProviderId : undefined,
gitModelId: gitModelId.length > 0 ? gitModelId : undefined,
};
} catch {
return {};
@@ -139,17 +129,11 @@ const hasProviderModel = (
const resolveGitGenerationModelSelection = ({
providers,
settingsGitProviderId,
settingsGitModelId,
settingsZenModel,
}: {
providers: ProviderWithModelList[];
settingsGitProviderId?: string;
settingsGitModelId?: string;
settingsZenModel?: string;
}): GitModelSelection | null => {
const gitProviderId = normalizeOptionalString(settingsGitProviderId);
const gitModelId = normalizeOptionalString(settingsGitModelId);
const zenModel = normalizeOptionalString(settingsZenModel);
if (!Array.isArray(providers) || providers.length === 0) {
@@ -159,10 +143,6 @@ const resolveGitGenerationModelSelection = ({
return null;
}
if (gitProviderId && gitModelId && hasProviderModel(providers, gitProviderId, gitModelId)) {
return { providerId: gitProviderId, modelId: gitModelId };
}
if (zenModel && hasProviderModel(providers, GIT_UTILITY_PROVIDER_ID, zenModel)) {
return { providerId: GIT_UTILITY_PROVIDER_ID, modelId: zenModel };
}
@@ -180,12 +160,6 @@ const resolveGitGenerationModelSelection = ({
}
}
const firstProvider = providers.find((provider) => provider.models.length > 0);
const firstModelId = normalizeOptionalString(firstProvider?.models[0]?.id);
if (firstProvider?.id && firstModelId) {
return { providerId: firstProvider.id, modelId: firstModelId };
}
return null;
};
@@ -458,8 +432,6 @@ interface ConfigStore {
settingsAutoCreateWorktree: boolean;
settingsGitmojiEnabled: boolean;
settingsZenModel: string | undefined;
settingsGitProviderId: string | undefined;
settingsGitModelId: string | undefined;
// Voice provider preference ('browser', 'openai', or 'say' for macOS)
voiceProvider: 'browser' | 'openai' | 'say';
setVoiceProvider: (provider: 'browser' | 'openai' | 'say') => void;
@@ -509,8 +481,6 @@ interface ConfigStore {
setSettingsAutoCreateWorktree: (enabled: boolean) => void;
setSettingsGitmojiEnabled: (enabled: boolean) => void;
setSettingsZenModel: (model: string | undefined) => void;
setSettingsGitProviderId: (providerId: string | undefined) => void;
setSettingsGitModelId: (modelId: string | undefined) => void;
getResolvedGitGenerationModel: () => { providerId: string; modelId: string } | null;
saveAgentModelSelection: (agentName: string, providerId: string, modelId: string) => void;
getAgentModelSelection: (agentName: string) => { providerId: string; modelId: string } | null;
@@ -557,8 +527,6 @@ export const useConfigStore = create<ConfigStore>()(
settingsAutoCreateWorktree: false,
settingsGitmojiEnabled: false,
settingsZenModel: undefined,
settingsGitProviderId: undefined,
settingsGitModelId: undefined,
// Voice provider preference - load from localStorage or default to 'browser'
voiceProvider: (() => {
if (typeof window !== 'undefined') {
@@ -1100,35 +1068,23 @@ export const useConfigStore = create<ConfigStore>()(
? get().providers
: (get().directoryScoped[directoryKey]?.providers ?? []);
const existingGitProviderId = normalizeOptionalString(get().settingsGitProviderId);
const existingGitModelId = normalizeOptionalString(get().settingsGitModelId);
const existingZenModel = normalizeOptionalString(get().settingsZenModel);
const defaultGitProviderId = normalizeOptionalString(openChamberDefaults.gitProviderId);
const defaultGitModelId = normalizeOptionalString(openChamberDefaults.gitModelId);
const defaultZenModel = normalizeOptionalString(openChamberDefaults.zenModel);
const resolvedExistingGitSelection = resolveGitGenerationModelSelection({
providers,
settingsGitProviderId: existingGitProviderId,
settingsGitModelId: existingGitModelId,
settingsZenModel: existingZenModel,
});
const resolvedDefaultGitSelection = resolveGitGenerationModelSelection({
providers,
settingsGitProviderId: defaultGitProviderId,
settingsGitModelId: defaultGitModelId,
settingsZenModel: defaultZenModel,
});
const resolvedGitSelection = resolvedExistingGitSelection || resolvedDefaultGitSelection;
const resolvedGitProviderId = resolvedGitSelection?.providerId;
const resolvedGitModelId = resolvedGitSelection?.modelId;
const resolvedZenModel =
resolvedGitProviderId === GIT_UTILITY_PROVIDER_ID && resolvedGitModelId
? resolvedGitModelId
: (defaultZenModel || existingZenModel);
const resolvedZenModel = resolvedGitModelId || defaultZenModel || existingZenModel;
set((state) => {
const baseSnapshot: DirectoryScopedConfig = state.directoryScoped[directoryKey] ?? {
@@ -1155,8 +1111,6 @@ export const useConfigStore = create<ConfigStore>()(
settingsAutoCreateWorktree: openChamberDefaults.autoCreateWorktree ?? false,
settingsGitmojiEnabled: openChamberDefaults.gitmojiEnabled ?? false,
settingsZenModel: resolvedZenModel,
settingsGitProviderId: resolvedGitProviderId,
settingsGitModelId: resolvedGitModelId,
directoryScoped: {
...state.directoryScoped,
[directoryKey]: nextSnapshot,
@@ -1170,33 +1124,16 @@ export const useConfigStore = create<ConfigStore>()(
return nextState;
});
const shouldPersistResolvedGitSelection =
!!resolvedGitProviderId &&
!!resolvedGitModelId &&
(
defaultGitProviderId !== resolvedGitProviderId ||
defaultGitModelId !== resolvedGitModelId ||
(
resolvedGitProviderId === GIT_UTILITY_PROVIDER_ID &&
resolvedZenModel !== defaultZenModel
)
);
const shouldPersistResolvedZenModel =
!!resolvedZenModel &&
resolvedZenModel !== defaultZenModel;
if (shouldPersistResolvedGitSelection && resolvedGitProviderId && resolvedGitModelId) {
const gitSettingsUpdate: {
gitProviderId: string;
gitModelId: string;
zenModel?: string;
} = {
gitProviderId: resolvedGitProviderId,
gitModelId: resolvedGitModelId,
};
if (resolvedGitProviderId === GIT_UTILITY_PROVIDER_ID && resolvedZenModel) {
gitSettingsUpdate.zenModel = resolvedZenModel;
}
updateDesktopSettings(gitSettingsUpdate).catch(() => {
if (shouldPersistResolvedZenModel && resolvedZenModel) {
updateDesktopSettings({
zenModel: resolvedZenModel,
gitProviderId: '',
gitModelId: '',
}).catch(() => {
// Ignore errors - best effort cleanup
});
}
@@ -1616,20 +1553,10 @@ export const useConfigStore = create<ConfigStore>()(
set({ settingsZenModel: model });
},
setSettingsGitProviderId: (providerId: string | undefined) => {
set({ settingsGitProviderId: providerId });
},
setSettingsGitModelId: (modelId: string | undefined) => {
set({ settingsGitModelId: modelId });
},
getResolvedGitGenerationModel: () => {
const state = get();
return resolveGitGenerationModelSelection({
providers: state.providers,
settingsGitProviderId: state.settingsGitProviderId,
settingsGitModelId: state.settingsGitModelId,
settingsZenModel: state.settingsZenModel,
});
},
@@ -1844,8 +1771,6 @@ export const useConfigStore = create<ConfigStore>()(
settingsAutoCreateWorktree: state.settingsAutoCreateWorktree,
settingsGitmojiEnabled: state.settingsGitmojiEnabled,
settingsZenModel: state.settingsZenModel,
settingsGitProviderId: state.settingsGitProviderId,
settingsGitModelId: state.settingsGitModelId,
speechRate: state.speechRate,
speechPitch: state.speechPitch,
speechVolume: state.speechVolume,