@@ -35,6 +35,31 @@ type OllamaModel = Omit<Model, "id"> & {
3535 limit : Model [ "limit" ] & { output ?: number } ;
3636} ;
3737
38+ type ComparableModel = Pick < Model ,
39+ | "name"
40+ | "attachment"
41+ | "reasoning"
42+ | "tool_call"
43+ | "knowledge"
44+ | "open_weights"
45+ | "modalities"
46+ > & {
47+ limit : Pick < Model [ "limit" ] , "context" > ;
48+ } ;
49+
50+ function normalizeForComparison ( model : Omit < Model , "id" > ) : ComparableModel {
51+ return {
52+ name : model . name ,
53+ attachment : model . attachment ,
54+ reasoning : model . reasoning ,
55+ tool_call : model . tool_call ,
56+ knowledge : model . knowledge ,
57+ open_weights : model . open_weights ,
58+ limit : { context : model . limit . context } ,
59+ modalities : model . modalities ,
60+ } ;
61+ }
62+
3863const OllamaTagsResponse = z . object ( {
3964 models : z . array (
4065 z . object ( {
@@ -137,20 +162,34 @@ for (const modelName of modelNames) {
137162 modelsData . push ( { name : modelName , data : showParsed . data } ) ;
138163}
139164
140- console . log ( `Fetched all models. Writing new files...` ) ;
165+ console . log ( `Fetched all models. Syncing files...` ) ;
166+
167+ const existingFiles = Array . from ( new Bun . Glob ( "*.toml" ) . scanSync ( modelsDir ) ) ;
168+ const existingModelNames = new Set ( existingFiles . map ( ( f ) => f . replace ( / \. t o m l $ / , "" ) ) ) ;
169+ const apiModelNames = new Set ( modelNames ) ;
170+
171+ let deleted = 0 ;
172+ for ( const existingName of existingModelNames ) {
173+ if ( ! apiModelNames . has ( existingName ) ) {
174+ const filePath = path . join ( modelsDir , modelFileName ( existingName ) ) ;
175+ await Bun . file ( filePath ) . delete ( ) ;
176+ console . log ( `Deleted: ${ modelFileName ( existingName ) } ` ) ;
177+ deleted ++ ;
178+ }
179+ }
141180
142181let created = 0 ;
182+ let skipped = 0 ;
143183for ( const { name, data } of modelsData ) {
144184 const fileName = modelFileName ( name ) ;
145185 const filePath = path . join ( modelsDir , fileName ) ;
146186
147- let existingData : Omit < Model , "id" > | null ;
187+ let existingData : Omit < Model , "id" > | null = null ;
148188 try {
149189 const existingToml = await Bun . file ( filePath ) . text ( ) ;
150190 existingData = Bun . TOML . parse ( existingToml ) as Omit < Model , "id" > ;
151191 } catch {
152192 // File doesn't exist
153- existingData = null ;
154193 }
155194
156195 const family = existingData ?. family ?? ( data . details . family as ModelFamily ) ;
@@ -179,9 +218,20 @@ for (const { name, data } of modelsData) {
179218 } ,
180219 } ;
181220
221+ if ( existingData ) {
222+ const normalizedExisting = normalizeForComparison ( existingData ) ;
223+ const normalizedIncoming = normalizeForComparison ( ollamaModel ) ;
224+
225+ if ( Bun . deepEquals ( normalizedExisting , normalizedIncoming ) ) {
226+ console . log ( `Skipped (no changes): ${ fileName } ` ) ;
227+ skipped ++ ;
228+ continue ;
229+ }
230+ }
231+
182232 await Bun . write ( filePath , generateToml ( name , ollamaModel ) ) ;
183233 console . log ( `Created: ${ fileName } ` ) ;
184234 created ++ ;
185235}
186236
187- console . log ( `\nDone. Created ${ created } ` ) ;
237+ console . log ( `\nDone. Created: ${ created } , Skipped: ${ skipped } , Deleted: ${ deleted } ` ) ;
0 commit comments