@@ -124,13 +124,15 @@ type GlobalStateKey =
124124 | "autoApprovalEnabled"
125125 | "customModes" // Array of custom modes
126126 | "unboundModelId"
127+ | "unboundModelInfo"
127128
128129export const GlobalFileNames = {
129130 apiConversationHistory : "api_conversation_history.json" ,
130131 uiMessages : "ui_messages.json" ,
131132 glamaModels : "glama_models.json" ,
132133 openRouterModels : "openrouter_models.json" ,
133134 mcpSettings : "cline_mcp_settings.json" ,
135+ unboundModels : "unbound_models.json" ,
134136}
135137
136138export class ClineProvider implements vscode . WebviewViewProvider {
@@ -529,6 +531,24 @@ export class ClineProvider implements vscode.WebviewViewProvider {
529531 }
530532 } )
531533
534+ this . readUnboundModels ( ) . then ( ( unboundModels ) => {
535+ if ( unboundModels ) {
536+ this . postMessageToWebview ( { type : "unboundModels" , unboundModels } )
537+ }
538+ } )
539+ this . refreshUnboundModels ( ) . then ( async ( unboundModels ) => {
540+ if ( unboundModels ) {
541+ const { apiConfiguration } = await this . getState ( )
542+ if ( apiConfiguration ?. unboundModelId ) {
543+ await this . updateGlobalState (
544+ "unboundModelInfo" ,
545+ unboundModels [ apiConfiguration . unboundModelId ] ,
546+ )
547+ await this . postStateToWebview ( )
548+ }
549+ }
550+ } )
551+
532552 this . configManager
533553 . listConfig ( )
534554 . then ( async ( listApiConfig ) => {
@@ -548,7 +568,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
548568 }
549569 }
550570
551- let currentConfigName = ( await this . getGlobalState ( "currentApiConfigName" ) ) as string
571+ const currentConfigName = ( await this . getGlobalState ( "currentApiConfigName" ) ) as string
552572
553573 if ( currentConfigName ) {
554574 if ( ! ( await this . configManager . hasConfig ( currentConfigName ) ) ) {
@@ -687,6 +707,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
687707 this . postMessageToWebview ( { type : "openAiModels" , openAiModels } )
688708 }
689709 break
710+ case "refreshUnboundModels" :
711+ await this . refreshUnboundModels ( )
712+ break
690713 case "openImage" :
691714 openImage ( message . text ! )
692715 break
@@ -1124,7 +1147,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
11241147 if ( message . text && message . apiConfiguration ) {
11251148 try {
11261149 await this . configManager . saveConfig ( message . text , message . apiConfiguration )
1127- let listApiConfig = await this . configManager . listConfig ( )
1150+ const listApiConfig = await this . configManager . listConfig ( )
11281151
11291152 await Promise . all ( [
11301153 this . updateGlobalState ( "listApiConfigMeta" , listApiConfig ) ,
@@ -1149,7 +1172,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
11491172 await this . configManager . saveConfig ( newName , message . apiConfiguration )
11501173 await this . configManager . deleteConfig ( oldName )
11511174
1152- let listApiConfig = await this . configManager . listConfig ( )
1175+ const listApiConfig = await this . configManager . listConfig ( )
11531176 const config = listApiConfig ?. find ( ( c ) => c . name === newName )
11541177
11551178 // Update listApiConfigMeta first to ensure UI has latest data
@@ -1207,7 +1230,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
12071230 await this . updateGlobalState ( "listApiConfigMeta" , listApiConfig )
12081231
12091232 // If this was the current config, switch to first available
1210- let currentApiConfigName = await this . getGlobalState ( "currentApiConfigName" )
1233+ const currentApiConfigName = await this . getGlobalState ( "currentApiConfigName" )
12111234 if ( message . text === currentApiConfigName && listApiConfig ?. [ 0 ] ?. name ) {
12121235 const apiConfig = await this . configManager . loadConfig ( listApiConfig [ 0 ] . name )
12131236 await Promise . all ( [
@@ -1227,7 +1250,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
12271250 break
12281251 case "getListApiConfiguration" :
12291252 try {
1230- let listApiConfig = await this . configManager . listConfig ( )
1253+ const listApiConfig = await this . configManager . listConfig ( )
12311254 await this . updateGlobalState ( "listApiConfigMeta" , listApiConfig )
12321255 this . postMessageToWebview ( { type : "listApiConfig" , listApiConfig } )
12331256 } catch ( error ) {
@@ -1267,7 +1290,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
12671290 this . outputChannel . appendLine (
12681291 `Failed to update timeout for ${ message . serverName } : ${ JSON . stringify ( error , Object . getOwnPropertyNames ( error ) , 2 ) } ` ,
12691292 )
1270- vscode . window . showErrorMessage ( ` Failed to update server timeout` )
1293+ vscode . window . showErrorMessage ( " Failed to update server timeout" )
12711294 }
12721295 }
12731296 break
@@ -1395,6 +1418,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
13951418 mistralApiKey,
13961419 unboundApiKey,
13971420 unboundModelId,
1421+ unboundModelInfo,
13981422 } = apiConfiguration
13991423 await this . updateGlobalState ( "apiProvider" , apiProvider )
14001424 await this . updateGlobalState ( "apiModelId" , apiModelId )
@@ -1435,6 +1459,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
14351459 await this . storeSecret ( "mistralApiKey" , mistralApiKey )
14361460 await this . storeSecret ( "unboundApiKey" , unboundApiKey )
14371461 await this . updateGlobalState ( "unboundModelId" , unboundModelId )
1462+ await this . updateGlobalState ( "unboundModelInfo" , unboundModelInfo )
14381463 if ( this . cline ) {
14391464 this . cline . api = buildApiHandler ( apiConfiguration )
14401465 }
@@ -1620,7 +1645,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
16201645 async refreshGlamaModels ( ) {
16211646 const glamaModelsFilePath = path . join ( await this . ensureCacheDirectoryExists ( ) , GlobalFileNames . glamaModels )
16221647
1623- let models : Record < string , ModelInfo > = { }
1648+ const models : Record < string , ModelInfo > = { }
16241649 try {
16251650 const response = await axios . get ( "https://glama.ai/api/gateway/v1/models" )
16261651 /*
@@ -1710,7 +1735,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
17101735 GlobalFileNames . openRouterModels ,
17111736 )
17121737
1713- let models : Record < string , ModelInfo > = { }
1738+ const models : Record < string , ModelInfo > = { }
17141739 try {
17151740 const response = await axios . get ( "https://openrouter.ai/api/v1/models" )
17161741 /*
@@ -1816,6 +1841,52 @@ export class ClineProvider implements vscode.WebviewViewProvider {
18161841 return models
18171842 }
18181843
1844+ async readUnboundModels ( ) : Promise < Record < string , ModelInfo > | undefined > {
1845+ const unboundModelsFilePath = path . join ( await this . ensureCacheDirectoryExists ( ) , GlobalFileNames . unboundModels )
1846+ const fileExists = await fileExistsAtPath ( unboundModelsFilePath )
1847+ if ( fileExists ) {
1848+ const fileContents = await fs . readFile ( unboundModelsFilePath , "utf8" )
1849+ return JSON . parse ( fileContents )
1850+ }
1851+ return undefined
1852+ }
1853+
1854+ async refreshUnboundModels ( ) {
1855+ const unboundModelsFilePath = path . join ( await this . ensureCacheDirectoryExists ( ) , GlobalFileNames . unboundModels )
1856+
1857+ const models : Record < string , ModelInfo > = { }
1858+ try {
1859+ const response = await axios . get ( "http://localhost:8787/models" )
1860+
1861+ if ( response . data ) {
1862+ const rawModels : Record < string , any > = response . data
1863+
1864+ for ( const [ modelId , model ] of Object . entries ( rawModels ) ) {
1865+ models [ modelId ] = {
1866+ maxTokens : model . maxTokens ? parseInt ( model . maxTokens ) : undefined ,
1867+ contextWindow : model . contextWindow ? parseInt ( model . contextWindow ) : 0 ,
1868+ supportsImages : model . supportsImages ?? false ,
1869+ supportsPromptCache : model . supportsPromptCaching ?? false ,
1870+ supportsComputerUse : model . supportsComputerUse ?? false ,
1871+ inputPrice : model . inputTokenPrice ? parseFloat ( model . inputTokenPrice ) : undefined ,
1872+ outputPrice : model . outputTokenPrice ? parseFloat ( model . outputTokenPrice ) : undefined ,
1873+ cacheWritesPrice : model . cacheWritePrice ? parseFloat ( model . cacheWritePrice ) : undefined ,
1874+ cacheReadsPrice : model . cacheReadPrice ? parseFloat ( model . cacheReadPrice ) : undefined ,
1875+ }
1876+ }
1877+ }
1878+ await fs . writeFile ( unboundModelsFilePath , JSON . stringify ( models ) )
1879+ this . outputChannel . appendLine ( `Unbound models fetched and saved: ${ JSON . stringify ( models , null , 2 ) } ` )
1880+ } catch ( error ) {
1881+ this . outputChannel . appendLine (
1882+ `Error fetching Unbound models: ${ JSON . stringify ( error , Object . getOwnPropertyNames ( error ) , 2 ) } ` ,
1883+ )
1884+ }
1885+
1886+ await this . postMessageToWebview ( { type : "unboundModels" , unboundModels : models } )
1887+ return models
1888+ }
1889+
18191890 // Task history
18201891
18211892 async getTaskWithId ( id : string ) : Promise < {
@@ -2104,6 +2175,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
21042175 experiments ,
21052176 unboundApiKey ,
21062177 unboundModelId ,
2178+ unboundModelInfo ,
21072179 ] = await Promise . all ( [
21082180 this . getGlobalState ( "apiProvider" ) as Promise < ApiProvider | undefined > ,
21092181 this . getGlobalState ( "apiModelId" ) as Promise < string | undefined > ,
@@ -2176,6 +2248,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
21762248 this . getGlobalState ( "experiments" ) as Promise < Record < ExperimentId , boolean > | undefined > ,
21772249 this . getSecret ( "unboundApiKey" ) as Promise < string | undefined > ,
21782250 this . getGlobalState ( "unboundModelId" ) as Promise < string | undefined > ,
2251+ this . getGlobalState ( "unboundModelInfo" ) as Promise < ModelInfo | undefined > ,
21792252 ] )
21802253
21812254 let apiProvider : ApiProvider
@@ -2233,6 +2306,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
22332306 vsCodeLmModelSelector,
22342307 unboundApiKey,
22352308 unboundModelId,
2309+ unboundModelInfo,
22362310 } ,
22372311 lastShownAnnouncementId,
22382312 customInstructions,
0 commit comments