@@ -14,98 +14,96 @@ import { AiProviderEnum } from '@openops/shared';
1414import fs from 'node:fs' ;
1515import path from 'node:path' ;
1616
17- interface AiSdkConfig {
18- package : string ;
17+ interface TypeSource {
1918 typeName : string ;
20- providerFile : string ;
2119 distPath ?: string ;
22- arrayName ?: string ;
2320 excludedModels ?: string [ ] ;
24- additionalArrays ?: Array < {
25- distPath : string ;
26- typeName : string ;
27- arrayName : string ;
28- excludedModels ? : string [ ] ;
29- } > ;
21+ }
22+
23+ interface AiSdkConfig {
24+ package : string ;
25+ providerFile : string ;
26+ typeSources : TypeSource [ ] ;
3027}
3128
3229export const AI_SDK_CONFIGS : Partial < Record < AiProviderEnum , AiSdkConfig > > = {
3330 [ AiProviderEnum . ANTHROPIC ] : {
3431 package : 'anthropic' ,
35- typeName : 'AnthropicMessagesModelId' ,
3632 providerFile : 'anthropic' ,
33+ typeSources : [ { typeName : 'AnthropicMessagesModelId' } ] ,
3734 } ,
3835 [ AiProviderEnum . CEREBRAS ] : {
3936 package : 'cerebras' ,
40- typeName : 'CerebrasChatModelId' ,
4137 providerFile : 'cerebras' ,
38+ typeSources : [ { typeName : 'CerebrasChatModelId' } ] ,
4239 } ,
4340 [ AiProviderEnum . COHERE ] : {
4441 package : 'cohere' ,
45- typeName : 'CohereChatModelId' ,
4642 providerFile : 'cohere' ,
43+ typeSources : [ { typeName : 'CohereChatModelId' } ] ,
4744 } ,
4845 [ AiProviderEnum . DEEPSEEK ] : {
4946 package : 'deepseek' ,
50- typeName : 'DeepSeekChatModelId' ,
5147 providerFile : 'deep-seek' ,
48+ typeSources : [ { typeName : 'DeepSeekChatModelId' } ] ,
5249 } ,
5350 [ AiProviderEnum . GOOGLE ] : {
5451 package : 'google' ,
55- typeName : 'GoogleGenerativeAIModelId' ,
5652 providerFile : 'google' ,
53+ typeSources : [ { typeName : 'GoogleGenerativeAIModelId' } ] ,
5754 } ,
5855 [ AiProviderEnum . GOOGLE_VERTEX ] : {
5956 package : 'google-vertex' ,
60- typeName : 'GoogleVertexModelId' ,
6157 providerFile : 'google-vertex' ,
62- excludedModels : [
63- 'gemini-1.0-pro' ,
64- 'gemini-1.0-pro-001' ,
65- 'gemini-1.0-pro-002' ,
66- 'gemini-1.0-pro-vision-001' ,
67- 'gemini-1.5-flash-001' ,
68- 'gemini-1.5-flash-002' ,
69- 'gemini-1.5-pro-001' ,
70- 'gemini-1.5-pro-002' ,
71- ] ,
72- additionalArrays : [
58+ typeSources : [
59+ {
60+ typeName : 'GoogleVertexModelId' ,
61+ excludedModels : [
62+ 'gemini-1.0-pro' ,
63+ 'gemini-1.0-pro-001' ,
64+ 'gemini-1.0-pro-002' ,
65+ 'gemini-1.0-pro-vision-001' ,
66+ 'gemini-1.5-flash-001' ,
67+ 'gemini-1.5-flash-002' ,
68+ 'gemini-1.5-pro-001' ,
69+ 'gemini-1.5-pro-002' ,
70+ ] ,
71+ } ,
7372 {
74- distPath : 'dist/anthropic/index.d.ts' ,
7573 typeName : 'GoogleVertexAnthropicMessagesModelId' ,
76- arrayName : 'googleVertexClaudeModels ' ,
74+ distPath : 'dist/anthropic/index.d.ts ' ,
7775 } ,
7876 ] ,
7977 } ,
8078 [ AiProviderEnum . GROQ ] : {
8179 package : 'groq' ,
82- typeName : 'GroqChatModelId' ,
8380 providerFile : 'groq' ,
81+ typeSources : [ { typeName : 'GroqChatModelId' } ] ,
8482 } ,
8583 [ AiProviderEnum . MISTRAL ] : {
8684 package : 'mistral' ,
87- typeName : 'MistralChatModelId' ,
8885 providerFile : 'mistral' ,
86+ typeSources : [ { typeName : 'MistralChatModelId' } ] ,
8987 } ,
9088 [ AiProviderEnum . OPENAI ] : {
9189 package : 'openai' ,
92- typeName : 'OpenAIChatModelId' ,
9390 providerFile : 'openai' ,
91+ typeSources : [ { typeName : 'OpenAIChatModelId' } ] ,
9492 } ,
9593 [ AiProviderEnum . PERPLEXITY ] : {
9694 package : 'perplexity' ,
97- typeName : 'PerplexityLanguageModelId' ,
9895 providerFile : 'perplexity' ,
96+ typeSources : [ { typeName : 'PerplexityLanguageModelId' } ] ,
9997 } ,
10098 [ AiProviderEnum . TOGETHER_AI ] : {
10199 package : 'togetherai' ,
102- typeName : 'TogetherAIChatModelId' ,
103100 providerFile : 'together-ai' ,
101+ typeSources : [ { typeName : 'TogetherAIChatModelId' } ] ,
104102 } ,
105103 [ AiProviderEnum . XAI ] : {
106104 package : 'xai' ,
107- typeName : 'XaiChatModelId' ,
108105 providerFile : 'xai' ,
106+ typeSources : [ { typeName : 'XaiChatModelId' } ] ,
109107 } ,
110108} ;
111109
@@ -127,10 +125,9 @@ const NON_CHAT_KEYWORDS = [
127125
128126async function fetchAiSdkModels (
129127 pkg : string ,
130- typeName : string ,
131- distPath = 'dist/index.d.ts' ,
132- excludedModels : string [ ] = [ ] ,
128+ source : TypeSource ,
133129) : Promise < string [ ] > {
130+ const distPath = source . distPath ?? 'dist/index.d.ts' ;
134131 const url = `https://unpkg.com/@ai-sdk/${ pkg } @latest/${ distPath } ` ;
135132 const response = await fetch ( url ) ;
136133 if ( ! response . ok ) {
@@ -140,31 +137,31 @@ async function fetchAiSdkModels(
140137 }
141138
142139 const dts = await response . text ( ) ;
143- const pattern = new RegExp ( `type\\s+${ typeName } \\s*=\\s*([^;]+);` , 's' ) ;
140+ const pattern = new RegExp (
141+ `type\\s+${ source . typeName } \\s*=\\s*([^;]+);` ,
142+ 's' ,
143+ ) ;
144144 const match = dts . match ( pattern ) ;
145145 if ( ! match ) {
146- throw new Error ( `Could not find type ${ typeName } in @ai-sdk/${ pkg } ` ) ;
146+ throw new Error ( `Could not find type ${ source . typeName } in @ai-sdk/${ pkg } ` ) ;
147147 }
148148
149+ const excluded = source . excludedModels ?? [ ] ;
149150 return [ ...match [ 1 ] . matchAll ( / ' ( [ ^ ' ] + ) ' / g) ]
150151 . map ( ( m ) => m [ 1 ] )
151152 . filter (
152153 ( id ) =>
153154 ! NON_CHAT_KEYWORDS . some ( ( kw ) => id . toLowerCase ( ) . includes ( kw ) ) &&
154- ! excludedModels . includes ( id ) ,
155- )
156- . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
155+ ! excluded . includes ( id ) ,
156+ ) ;
157157}
158158
159- function getCurrentModels ( providerFile : string , arrayName ?: string ) : string [ ] {
159+ function getCurrentModels ( providerFile : string ) : string [ ] {
160160 const filePath = path . join ( __dirname , 'providers' , `${ providerFile } .ts` ) ;
161161 if ( ! fs . existsSync ( filePath ) ) return [ ] ;
162162
163163 const content = fs . readFileSync ( filePath , 'utf-8' ) ;
164- const pattern = arrayName
165- ? new RegExp ( `const\\s+${ arrayName } \\s*=\\s*\\[([\\s\\S]*?)\\];` )
166- : / c o n s t \s + \w + M o d e l s \s * = \s * \[ ( [ \s \S ] * ?) \] ; / ;
167- const match = content . match ( pattern ) ;
164+ const match = content . match ( / c o n s t \s + \w + M o d e l s \s * = \s * \[ ( [ \s \S ] * ?) \] ; / ) ;
168165 if ( ! match ) return [ ] ;
169166
170167 return match [ 1 ]
@@ -174,69 +171,23 @@ function getCurrentModels(providerFile: string, arrayName?: string): string[] {
174171 . sort ( ) ;
175172}
176173
177- function updateProviderFile (
178- providerFile : string ,
179- models : string [ ] ,
180- arrayName ?: string ,
181- ) : void {
174+ function updateProviderFile ( providerFile : string , models : string [ ] ) : void {
182175 const filePath = path . join ( __dirname , 'providers' , `${ providerFile } .ts` ) ;
183176 const content = fs . readFileSync ( filePath , 'utf-8' ) ;
184- const pattern = arrayName
185- ? new RegExp ( `const\\s+(${ arrayName } )\\s*=\\s*\\[([\\s\\S]*?)\\];` )
186- : / c o n s t \s + ( \w + M o d e l s ) \s * = \s * \[ ( [ \s \S ] * ?) \] ; / ;
187- const match = content . match ( pattern ) ;
177+ const match = content . match ( / c o n s t \s + ( \w + M o d e l s ) \s * = \s * \[ ( [ \s \S ] * ?) \] ; / ) ;
188178 if ( ! match ) return ;
189179
190- const resolvedArrayName = match [ 1 ] ;
180+ const arrayName = match [ 1 ] ;
191181 const formattedModels = models . map ( ( model ) => ` '${ model } ',` ) . join ( '\n' ) ;
192- const newArray = `const ${ resolvedArrayName } = [\n${ formattedModels } \n];` ;
193- const updatedContent = content . replace ( pattern , newArray ) ;
182+ const newArray = `const ${ arrayName } = [\n${ formattedModels } \n];` ;
183+ const updatedContent = content . replace (
184+ / c o n s t \s + \w + M o d e l s \s * = \s * \[ ( [ \s \S ] * ?) \] ; / ,
185+ newArray ,
186+ ) ;
194187
195188 fs . writeFileSync ( filePath , updatedContent , 'utf-8' ) ;
196189}
197190
198- async function syncConfig (
199- label : string ,
200- pkg : string ,
201- typeName : string ,
202- providerFile : string ,
203- distPath : string | undefined ,
204- arrayName : string | undefined ,
205- excludedModels : string [ ] | undefined ,
206- shouldUpdate : boolean ,
207- ) : Promise < boolean > {
208- let latestModels : string [ ] ;
209- try {
210- latestModels = await fetchAiSdkModels (
211- pkg ,
212- typeName ,
213- distPath ,
214- excludedModels ,
215- ) ;
216- } catch ( error ) {
217- console . error ( `Skipping ${ label } : ${ ( error as Error ) . message } ` ) ;
218- return false ;
219- }
220-
221- const currentModels = getCurrentModels ( providerFile , arrayName ) ;
222- const added = latestModels . filter ( ( m ) => ! currentModels . includes ( m ) ) ;
223- const removed = currentModels . filter ( ( m ) => ! latestModels . includes ( m ) ) ;
224-
225- if ( added . length === 0 && removed . length === 0 ) {
226- return false ;
227- }
228-
229- console . log ( `${ label } :` ) ;
230- if ( added . length > 0 ) console . log ( ` +${ added . length } ` ) ;
231- if ( removed . length > 0 ) console . log ( ` -${ removed . length } ` ) ;
232-
233- if ( shouldUpdate ) {
234- updateProviderFile ( providerFile , latestModels , arrayName ) ;
235- }
236-
237- return true ;
238- }
239-
240191async function main ( ) {
241192 const shouldUpdate = process . argv . includes ( '--update' ) ;
242193
@@ -245,30 +196,36 @@ async function main() {
245196 for ( const [ provider , config ] of Object . entries ( AI_SDK_CONFIGS ) ) {
246197 if ( ! config ) continue ;
247198
248- const changed = await syncConfig (
249- provider ,
250- config . package ,
251- config . typeName ,
252- config . providerFile ,
253- config . distPath ,
254- config . arrayName ,
255- config . excludedModels ,
256- shouldUpdate ,
257- ) ;
258- if ( changed ) hasChanges = true ;
259-
260- for ( const extra of config . additionalArrays ?? [ ] ) {
261- const extraChanged = await syncConfig (
262- `${ provider } (${ extra . arrayName } )` ,
263- config . package ,
264- extra . typeName ,
265- config . providerFile ,
266- extra . distPath ,
267- extra . arrayName ,
268- extra . excludedModels ,
269- shouldUpdate ,
199+ let latestModels : string [ ] ;
200+ try {
201+ const results = await Promise . all (
202+ config . typeSources . map ( ( source ) =>
203+ fetchAiSdkModels ( config . package , source ) ,
204+ ) ,
205+ ) ;
206+ latestModels = [ ...new Set ( results . flat ( ) ) ] . sort ( ( a , b ) =>
207+ a . localeCompare ( b ) ,
270208 ) ;
271- if ( extraChanged ) hasChanges = true ;
209+ } catch ( error ) {
210+ console . error ( `Skipping ${ provider } : ${ ( error as Error ) . message } ` ) ;
211+ continue ;
212+ }
213+
214+ const currentModels = getCurrentModels ( config . providerFile ) ;
215+ const added = latestModels . filter ( ( m ) => ! currentModels . includes ( m ) ) ;
216+ const removed = currentModels . filter ( ( m ) => ! latestModels . includes ( m ) ) ;
217+
218+ if ( added . length === 0 && removed . length === 0 ) {
219+ continue ;
220+ }
221+
222+ hasChanges = true ;
223+ console . log ( `${ provider } :` ) ;
224+ if ( added . length > 0 ) console . log ( ` +${ added . length } ` ) ;
225+ if ( removed . length > 0 ) console . log ( ` -${ removed . length } ` ) ;
226+
227+ if ( shouldUpdate ) {
228+ updateProviderFile ( config . providerFile , latestModels ) ;
272229 }
273230 }
274231
0 commit comments