@@ -102,7 +102,7 @@ interface IAppSettings {
102102 enableSkills ?: boolean // Skills system global toggle
103103 hooksNotifications ?: HooksNotificationsSettings // Hooks & notifications settings
104104 defaultModel ?: { providerId : string ; modelId : string } // Default model for new conversations
105- defaultVisionModel ?: { providerId : string ; modelId : string } // Default vision model for image tools
105+ defaultVisionModel ?: { providerId : string ; modelId : string } // Legacy vision model setting for migration only
106106 defaultProjectPath ?: string | null
107107 acpRegistryMigrationVersion ?: number
108108 unifiedAgentsMigrationVersion ?: number
@@ -153,6 +153,15 @@ const isModelSelection = (value: unknown): value is ModelSelection => {
153153 return typeof record . providerId === 'string' && typeof record . modelId === 'string'
154154}
155155
156+ const normalizeKnownModelId = ( modelId : string ) : string => {
157+ const normalizedModelId = modelId . trim ( ) . toLowerCase ( )
158+ return normalizedModelId . replace ( / ^ m o d e l s \/ / , '' )
159+ }
160+
161+ const normalizeKnownProviderId = ( providerId : string ) : string =>
162+ modelCapabilities . resolveProviderId ( providerId . trim ( ) . toLowerCase ( ) ) ||
163+ providerId . trim ( ) . toLowerCase ( )
164+
156165export const getAnthropicModelSelectionKeysToClear = (
157166 settings : Partial <
158167 Record <
@@ -362,6 +371,7 @@ export class ConfigPresenter implements IConfigPresenter {
362371 setAgentRepository ( agentRepository : AgentRepository ) : void {
363372 this . agentRepository = agentRepository
364373 this . initializeUnifiedAgents ( )
374+ this . migrateLegacyDefaultVisionModelToBuiltinAgent ( )
365375 }
366376
367377 private getAgentRepositoryOrThrow ( ) : AgentRepository {
@@ -396,6 +406,35 @@ export class ConfigPresenter implements IConfigPresenter {
396406 this . syncRegistryAgentsToRepository ( )
397407 }
398408
409+ private migrateLegacyDefaultVisionModelToBuiltinAgent ( ) : void {
410+ const legacySelection = this . store . get ( 'defaultVisionModel' ) as unknown
411+ if ( legacySelection === undefined ) {
412+ return
413+ }
414+
415+ const builtinVisionModel = this . getBuiltinDeepChatConfig ( ) . visionModel
416+
417+ if (
418+ isModelSelection ( legacySelection ) &&
419+ ( ! builtinVisionModel ?. providerId || ! builtinVisionModel ?. modelId )
420+ ) {
421+ const providerId = legacySelection . providerId . trim ( )
422+ const modelId = legacySelection . modelId . trim ( )
423+
424+ if ( providerId && modelId ) {
425+ this . updateBuiltinDeepChatConfig ( {
426+ visionModel : {
427+ providerId,
428+ modelId
429+ }
430+ } )
431+ }
432+ }
433+
434+ this . store . delete ( 'defaultVisionModel' )
435+ eventBus . sendToMain ( CONFIG_EVENTS . SETTING_CHANGED , 'defaultVisionModel' , undefined )
436+ }
437+
399438 private buildLegacyBuiltinDeepChatConfig ( ) : DeepChatAgentConfig {
400439 const defaultModel = this . store . get ( 'defaultModel' ) as ModelSelection | undefined
401440 const assistantModel = this . store . get ( 'assistantModel' ) as ModelSelection | undefined
@@ -760,7 +799,9 @@ export class ConfigPresenter implements IConfigPresenter {
760799 const keysToClear = getAnthropicModelSelectionKeysToClear ( {
761800 defaultModel : this . getSetting ( 'defaultModel' ) ,
762801 assistantModel : this . getSetting ( 'assistantModel' ) ,
763- defaultVisionModel : this . getSetting ( 'defaultVisionModel' ) ,
802+ defaultVisionModel : this . store . get ( 'defaultVisionModel' ) as
803+ | { providerId : string ; modelId : string }
804+ | undefined ,
764805 preferredModel : this . getSetting ( 'preferredModel' )
765806 } )
766807
@@ -780,9 +821,6 @@ export class ConfigPresenter implements IConfigPresenter {
780821 if ( key === 'assistantModel' ) {
781822 return this . getBuiltinDeepChatConfig ( ) . assistantModel as T | undefined
782823 }
783- if ( key === 'defaultVisionModel' ) {
784- return this . getDefaultVisionModel ( ) as T | undefined
785- }
786824 if ( key === 'default_system_prompt' ) {
787825 return this . getBuiltinDeepChatConfig ( ) . systemPrompt as T | undefined
788826 }
@@ -808,10 +846,6 @@ export class ConfigPresenter implements IConfigPresenter {
808846 eventBus . sendToMain ( CONFIG_EVENTS . SETTING_CHANGED , key , value )
809847 return
810848 }
811- if ( key === 'defaultVisionModel' ) {
812- this . setDefaultVisionModel ( value as { providerId : string ; modelId : string } | undefined )
813- return
814- }
815849 if ( key === 'default_system_prompt' ) {
816850 this . updateBuiltinDeepChatConfig ( {
817851 systemPrompt : typeof value === 'string' ? value : ''
@@ -1015,6 +1049,26 @@ export class ConfigPresenter implements IConfigPresenter {
10151049 return this . providerModelHelper . getCustomModels ( providerId )
10161050 }
10171051
1052+ isKnownModel ( providerId : string , modelId : string ) : boolean {
1053+ const normalizedProviderId = normalizeKnownProviderId ( providerId )
1054+ const normalizedModelId = normalizeKnownModelId ( modelId )
1055+
1056+ if ( ! normalizedProviderId || ! normalizedModelId ) {
1057+ return false
1058+ }
1059+
1060+ const hasKnownModel = ( models : Array < { id : string } > | undefined ) : boolean =>
1061+ Array . isArray ( models ) &&
1062+ models . some ( ( model ) => normalizeKnownModelId ( model . id ) === normalizedModelId )
1063+
1064+ return (
1065+ this . hasUserModelConfig ( normalizedModelId , normalizedProviderId ) ||
1066+ hasKnownModel ( this . getProviderModels ( normalizedProviderId ) ) ||
1067+ hasKnownModel ( this . getCustomModels ( normalizedProviderId ) ) ||
1068+ hasKnownModel ( this . getDbProviderModels ( normalizedProviderId ) )
1069+ )
1070+ }
1071+
10181072 setCustomModels ( providerId : string , models : MODEL_META [ ] ) : void {
10191073 this . providerModelHelper . setCustomModels ( providerId , models )
10201074 }
@@ -1688,6 +1742,18 @@ export class ConfigPresenter implements IConfigPresenter {
16881742 )
16891743 }
16901744
1745+ async agentSupportsCapability ( agentId : string , capability : 'vision' ) : Promise < boolean > {
1746+ if ( capability !== 'vision' ) {
1747+ return false
1748+ }
1749+
1750+ const agentConfig = await this . resolveDeepChatAgentConfig ( agentId )
1751+ const providerId = agentConfig . visionModel ?. providerId ?. trim ( )
1752+ const modelId = agentConfig . visionModel ?. modelId ?. trim ( )
1753+
1754+ return Boolean ( providerId && modelId && this . getModelConfig ( modelId , providerId ) ?. vision )
1755+ }
1756+
16911757 async createDeepChatAgent ( input : CreateDeepChatAgentInput ) : Promise < Agent > {
16921758 const created = this . getAgentRepositoryOrThrow ( ) . createDeepChatAgent ( input )
16931759 this . notifyAcpAgentsChanged ( )
@@ -2312,32 +2378,6 @@ export class ConfigPresenter implements IConfigPresenter {
23122378 eventBus . sendToMain ( CONFIG_EVENTS . SETTING_CHANGED , 'defaultModel' , model )
23132379 }
23142380
2315- getDefaultVisionModel ( ) : { providerId : string ; modelId : string } | undefined {
2316- const selection = this . getBuiltinDeepChatConfig ( ) . visionModel
2317- if ( selection ?. providerId && selection ?. modelId ) {
2318- return {
2319- providerId : selection . providerId ,
2320- modelId : selection . modelId
2321- }
2322- }
2323- return this . store . get ( 'defaultVisionModel' ) as
2324- | { providerId : string ; modelId : string }
2325- | undefined
2326- }
2327-
2328- setDefaultVisionModel ( model : { providerId : string ; modelId : string } | undefined ) : void {
2329- this . updateBuiltinDeepChatConfig ( {
2330- visionModel :
2331- model ?. providerId && model ?. modelId
2332- ? {
2333- providerId : model . providerId ,
2334- modelId : model . modelId
2335- }
2336- : null
2337- } )
2338- eventBus . sendToMain ( CONFIG_EVENTS . SETTING_CHANGED , 'defaultVisionModel' , model )
2339- }
2340-
23412381 getDefaultProjectPath ( ) : string | null {
23422382 const path = this . getSetting < string | null > ( 'defaultProjectPath' )
23432383 return path ?. trim ( ) ? path . trim ( ) : null
0 commit comments